Setting and Getting Component Variables¶
You will both set and get the values in the dimensional and unscaled form via the Problem class. If you have promoted both inputs and outputs to the same name, then the output takes precedence and it determines the units you should work in.
Outputs and Independent Variables¶
To set or get the output variable, you reference it by its promoted name. In the regular Sellar problem, all the variables have been promoted to the top of the model. So to get the value of the “y1” output defined in the SellarDis1WithDerivatives component, you would do the following:
from openmdao.api import Problem, NonlinearBlockGS
from openmdao.test_suite.components.sellar import SellarDerivatives
prob = Problem()
prob.model = SellarDerivatives()
prob.model.nonlinear_solver = NonlinearBlockGS()
prob.setup()
prob['x'] = 2.75
prob.run_model()
NL: NLBGS Converged in 7 iterations
print(prob['x'])
[ 2.75]
print(prob['y1'])
[ 27.30491784]
You use the same syntax when working with the independent variables of your problem. Independent variables hold values set by a user or are used as design variables by a Driver. OpenMDAO requires that every variable must have an ultimate source, even independent variables. We accomplish this by defining independent variables as outputs of a special component, IndepVarComp, that does not have any inputs. For example, consider our paraboloid tutorial problem problem which has two independent variables: x and y.
These would be defined and set as follows:
from openmdao.api import Problem, Group, IndepVarComp
from openmdao.test_suite.components.paraboloid import Paraboloid
prob = Problem()
model = prob.model = Group()
model.add_subsystem('p1', IndepVarComp('x', 0.0), promotes=['x'])
model.add_subsystem('p2', IndepVarComp('y', 0.0), promotes=['y'])
model.add_subsystem('comp', Paraboloid(), promotes=['x', 'y', 'f_xy'])
prob.setup()
prob['x'] = 2.
prob['y'] = 10.
prob.run_model()
print(prob['f_xy'])
[ 214.]
As we said above, outputs are always referenced via their promoted name. So if you built the Sellar problem using connections (see SellarDerivativesConnected), instead of promoting everything, then you would access the variables like this:
from openmdao.api import Problem, NonlinearBlockGS
from openmdao.test_suite.components.sellar import SellarDerivativesConnected
prob = Problem()
prob.model = SellarDerivativesConnected()
prob.model.nonlinear_solver = NonlinearBlockGS()
prob.setup()
prob['px.x'] = 2.75
prob.run_model()
NL: NLBGS Converged in 7 iterations
print(prob['px.x'])
[ 2.75]
print(prob['d1.y1'])
[ 27.30491784]
Working with Array Variables¶
When you have an array variable, for convenience we allow you to set the value with any properly-sized array, list, or tuple. In other words, the shape of the list has to match the shape of the actual data.
import numpy as np
from openmdao.api import Problem, NonlinearBlockGS
from openmdao.test_suite.components.sellar import SellarDerivatives
prob = Problem()
prob.model = SellarDerivatives()
prob.model.nonlinear_solver = NonlinearBlockGS()
prob.setup()
# default value from the class definition
print(prob['x'])
[ 1.]
prob['x'] = 2.75
print(prob['x'])
2.75
# default value from the class definition
print(prob['z'])
[ 5. 2.]
prob['z'] = [1.5, 1.5] # for convenience we convert the list to an array.
print(prob['z'])
[1.5, 1.5]
prob.run_model()
NL: NLBGS Converged in 8 iterations
print(prob['y1'])
[ 5.43379017]
print(prob['y2'])
[ 5.33104916]
prob['z'] = np.array([2.5, 2.5])
print(prob['z'])
[ 2.5 2.5]
prob.run_model()
NL: NLBGS Converged in 8 iterations
print(prob['y1'])
[ 9.8716174]
print(prob['y2'])
[ 8.14191302]
import numpy as np
from openmdao.api import Problem, IndepVarComp, Group
prob = Problem(model=Group())
model = prob.model
model.add_subsystem(name='indeps',
subsys=IndepVarComp(name='X_c', shape=(3, 1)))
prob.setup()
new_val = -5*np.ones((3, 1))
prob['indeps.X_c'] = new_val
prob.final_setup()
print(prob['indeps.X_c'])
[[-5.] [-5.] [-5.]]
new_val = 2.5*np.ones(3)
prob['indeps.X_c'][:, 0] = new_val
prob.final_setup()
print(prob['indeps.X_c'])
[[ 2.5] [ 2.5] [ 2.5]]
print(prob['indeps.X_c'][:, 0])
[ 2.5 2.5 2.5]
Residuals¶
If you want to look at the residual values associated with any particular output variable, you will reference them using the same naming conventions the outputs. Also like outputs, you will be given the residuals in the unscaled dimensional form.
from openmdao.api import Problem, NonlinearBlockGS
from openmdao.test_suite.components.sellar import SellarDerivatives
prob = Problem()
prob.model = SellarDerivatives()
prob.model.nonlinear_solver = NonlinearBlockGS()
prob.setup()
prob['z'] = [1.5, 1.5] # for convenience we convert the list to an array.
prob.run_model()
NL: NLBGS Converged in 8 iterations
inputs, outputs, residuals = prob.model.get_nonlinear_vectors()
print(residuals['y1'])
[ 7.66033903e-10]
print(residuals['y2'])
[ 0.]
Inputs¶
Note
99.9% of the time, you don’t want to work with input variables. Instead you probably want to use the associated output variable. But if you really, really want to, this is how you do it.
To set or get the and input variable, you reference it by its absolute path name. The full path name is necessary, because you could have an output (source) variable in units of meters, and then two connected inputs (targets) in units of millimeters and centimeters, respectively. Hence you need a specific path to reference each of the two different inputs separately to get the value in that input’s units.
from openmdao.api import Problem, NonlinearBlockGS
from openmdao.test_suite.components.sellar import SellarDerivatives
prob = Problem()
prob.model = SellarDerivatives()
prob.model.nonlinear_solver = NonlinearBlockGS()
prob.setup()
prob['x'] = 2.75
prob.run_model()
NL: NLBGS Converged in 7 iterations
print(prob['x'])
[ 2.75]
# the output variable, referenced by the promoted name
print(prob['y1'])
[ 27.30491784]
# the connected input variable, referenced by the absolute path
print(prob['d2.y1'])
[ 27.30491784]
Specifying Units¶
You can also set an input or request the valuable of any variable in a different unit than the one it is declared in, and OpenMDAO will peform the conversion for you. This is done with the Problem methods get_val and set_val.
from openmdao.api import Problem, ExecComp
prob = Problem()
comp = prob.model.add_subsystem('comp', ExecComp('y=x+1.', x={'value': 100.0, 'units': 'cm'},
y={'units': 'm'}))
prob.setup()
prob.run_model()
print(prob.get_val('comp.x'))
[ 100.]
print(prob.get_val('comp.x', 'm'))
[ 1.]
prob.set_val('comp.x', 10.0, 'mm')
print(prob.get_val('comp.x'))
[ 1.]
print(prob.get_val('comp.x', 'm'))
[ 0.01]
When dealing with arrays, you can set or get specific indices or index ranges by adding the “index” argument to the calls:
from openmdao.api import Problem, ExecComp
prob = Problem()
comp = prob.model.add_subsystem('comp', ExecComp('y=x+1.', x={'value': np.array([100.0, 33.3]), 'units': 'cm'},
y={'shape': (2, ), 'units': 'm'}))
prob.setup()
prob.run_model()
print(prob.get_val('comp.x'))
[ 100. 33.3]
print(prob.get_val('comp.x', 'm'))
[ 1. 0.333]
print(prob.get_val('comp.x', 'km', indices=[0]))
[ 0.001]
prob.set_val('comp.x', 10.0, 'mm')
print(prob.get_val('comp.x'))
[ 1. 1.]
print(prob.get_val('comp.x', 'm', indices=0))
0.01
prob.set_val('comp.x', 50.0, 'mm', indices=[1])
print(prob.get_val('comp.x'))
[ 1. 5.]
print(prob.get_val('comp.x', 'm', indices=1))
0.05