def setup(self): surface = self.options['surface'] promotes = [] if surface['struct_weight_relief']: promotes = promotes + list(set(['nodes', 'element_weights', 'load_factor'])) if surface['distributed_fuel_weight']: promotes = promotes + list(set(['nodes', 'load_factor'])) self.add_subsystem('struct_states', SpatialBeamStates(surface=surface), promotes_inputs=['local_stiff_transformed', 'forces', 'loads'] + promotes, promotes_outputs=['disp']) self.add_subsystem('def_mesh', DisplacementTransferGroup(surface=surface), promotes_inputs=['nodes', 'mesh', 'disp'], promotes_outputs=['def_mesh']) self.add_subsystem('aero_geom', VLMGeometry(surface=surface), promotes_inputs=['def_mesh'], promotes_outputs=['b_pts', 'widths', 'cos_sweep', 'lengths', 'chords', 'normals', 'S_ref']) self.linear_solver = LinearRunOnce()
def coupled_group(self): # type: () -> Optional[Group] """:obj:`Group`, optional: Group wrapping the coupled blocks with a converger specified in the CMDOWS file. If no coupled blocks are specified in the CMDOWS file this property is `None`. """ if self.coupled_blocks: coupled_group = Group() for uid in self.coupled_blocks: # Get the correct DisciplineComponent discipline_component = self.discipline_components[uid] # Change input variable names if they are provided as copies of coupling variables promotes = ['*'] # type: List[Union[str, Tuple[str, str]]] if not self.has_converger: for i in discipline_component.inputs_from_xml.keys(): if i in self.coupling_vars: promotes.append((i, self.coupling_vars[i]['copy'])) # Add the DisciplineComponent to the group coupled_group.add_subsystem(uid, self.discipline_components[uid], promotes) # Find the convergence type of the coupled group if self.has_converger: conv_type = self.elem_problem_def.find('problemFormulation/convergerType').text if conv_type == 'Gauss-Seidel': coupled_group.linear_solver = LinearBlockGS() coupled_group.nonlinear_solver = NonlinearBlockGS() elif conv_type == 'Jacobi': coupled_group.linear_solver = LinearBlockJac() coupled_group.nonlinear_solver = NonlinearBlockJac() else: raise RuntimeError('Specified convergerType "%s" is not supported.' % conv_type) else: coupled_group.linear_solver = LinearRunOnce() coupled_group.nonlinear_solver = NonLinearRunOnce() return coupled_group return None
def test_record_solver_linear_linear_run_once(self, m): self.setup_endpoints(m) recorder = WebRecorder(self._accepted_token, suppress_output=True) # raise unittest.SkipTest("Linear Solver recording not working yet") self.setup_sellar_model() self.prob.model.nonlinear_solver = NewtonSolver() # used for analytic derivatives self.prob.model.nonlinear_solver.linear_solver = LinearRunOnce() linear_solver = self.prob.model.nonlinear_solver.linear_solver linear_solver.recording_options['record_abs_error'] = True linear_solver.recording_options['record_rel_error'] = True linear_solver.recording_options['record_solver_residuals'] = True self.prob.model.nonlinear_solver.linear_solver.add_recorder(recorder) self.prob.setup(check=False) t0, t1 = run_driver(self.prob) solver_iteration = json.loads(self.solver_iterations) expected_abs_error = 0.0 expected_rel_error = 0.0 expected_solver_output = [ {'name': 'px.x', 'values': [0.0]}, {'name': 'pz.z', 'values': [0.0, 0.0]}, {'name': 'd1.y1', 'values': [-4.15366975e-05]}, {'name': 'd2.y2', 'values': [-4.10568454e-06]}, {'name': 'obj_cmp.obj', 'values': [-4.15366737e-05]}, {'name': 'con_cmp1.con1', 'values': [4.15366975e-05]}, {'name': 'con_cmp2.con2', 'values': [-4.10568454e-06]}, ] self.assertAlmostEqual(expected_abs_error, solver_iteration['abs_err']) self.assertAlmostEqual(expected_rel_error, solver_iteration['rel_err']) for o in expected_solver_output: self.assert_array_close(o, solver_iteration['solver_output'])
def test_method_default(self): # Uses `solve_linear` by default p = Problem() p.model.add_subsystem('des_vars', IndepVarComp('a', val=10., units='m'), promotes=['*']) p.model.add_subsystem('icomp', DistribStateImplicit(), promotes=['*']) model = p.model model.linear_solver = PETScKrylov() model.linear_solver.precon = LinearRunOnce() p.setup(mode='rev', check=False) model.icomp.linear_solver.precon = LinearUserDefined() p.run_model() jac = p.compute_totals(of=['out_var'], wrt=['a'], return_format='dict') assert_rel_error(self, 15.0, jac['out_var']['a'][0][0])
def setup(self): surface = self.options['surface'] self.add_subsystem( 'struct_states', SpatialBeamStates(surface=surface), promotes_inputs=['K', 'forces', 'loads', 'element_weights'], promotes_outputs=['disp']) self.add_subsystem('def_mesh', DisplacementTransfer(surface=surface), promotes_inputs=['mesh', 'disp'], promotes_outputs=['def_mesh']) self.add_subsystem('aero_geom', VLMGeometry(surface=surface), promotes_inputs=['def_mesh'], promotes_outputs=[ 'b_pts', 'c_pts', 'widths', 'cos_sweep', 'lengths', 'chords', 'normals', 'S_ref' ]) self.linear_solver = LinearRunOnce()
def setUp(self): p = Problem() p.model.cite = "foobar model" p.model.nonlinear_solver.cite = "foobar nonlinear_solver" p.model.linear_solver.cite = "foobar linear_solver" indeps = p.model.add_subsystem('indeps', IndepVarComp('x', 10), promotes=['*']) indeps.linear_solver = LinearRunOnce() par = p.model.add_subsystem('par', ParallelGroup(), promotes=['*']) ec = par.add_subsystem('ec', ExecComp('y = 2+3*x'), promotes=['*']) # note using newton here makes no sense in reality, but its fine for this test since we never run the model ec.nonlinear_solver = NewtonSolver() ec.cite = "foobar exec comp" c2 = par.add_subsystem('c2', ExecComp('y2=x'), promotes=['*']) c2.cite = 'foobar exec comp' self.prob = p
def test_zero_src_indices(self): prob = Problem() model = prob.model model.nonlinear_solver = NonlinearRunOnce() model.linear_solver = LinearRunOnce() model.add_subsystem('comp1', Comp()) model.add_subsystem('comp2', Comp()) model.connect('comp1.y', 'comp2.x') model.connect('comp2.y', 'comp1.x') prob.setup() prob.run_model() if model.comm.rank == 1: np.testing.assert_almost_equal(model.comp1._outputs['y'], np.array([])) np.testing.assert_almost_equal(model.comp2._outputs['y'], np.array([])) else: np.testing.assert_almost_equal(model.comp1._outputs['y'], np.ones(3) * 2.) np.testing.assert_almost_equal(model.comp2._outputs['y'], np.ones(3) * 3.)
def test_circuit_voltage_source(self): from openmdao.api import ArmijoGoldsteinLS, Problem, IndepVarComp, BalanceComp, ExecComp from openmdao.api import NewtonSolver, DirectSolver, NonlinearRunOnce, LinearRunOnce from openmdao.test_suite.scripts.circuit_analysis import Circuit p = Problem() model = p.model model.add_subsystem('ground', IndepVarComp('V', 0., units='V')) # replacing the fixed current source with a BalanceComp to represent a fixed Voltage source # model.add_subsystem('source', IndepVarComp('I', 0.1, units='A')) model.add_subsystem('batt', IndepVarComp('V', 1.5, units='V')) bal = model.add_subsystem('batt_balance', BalanceComp()) bal.add_balance('I', units='A', eq_units='V') model.add_subsystem('circuit', Circuit()) model.add_subsystem( 'batt_deltaV', ExecComp('dV = V1 - V2', V1={'units': 'V'}, V2={'units': 'V'}, dV={'units': 'V'})) # current into the circuit is now the output state from the batt_balance comp model.connect('batt_balance.I', 'circuit.I_in') model.connect('ground.V', ['circuit.Vg', 'batt_deltaV.V2']) model.connect('circuit.n1.V', 'batt_deltaV.V1') # set the lhs and rhs for the battery residual model.connect('batt.V', 'batt_balance.rhs:I') model.connect('batt_deltaV.dV', 'batt_balance.lhs:I') p.setup() ################### # Solver Setup ################### # change the circuit solver to RunOnce because we're # going to converge at the top level of the model with newton instead p.model.circuit.nonlinear_solver = NonlinearRunOnce() p.model.circuit.linear_solver = LinearRunOnce() # Put Newton at the top so it can also converge the new BalanceComp residual newton = p.model.nonlinear_solver = NewtonSolver() p.model.linear_solver = DirectSolver() newton.options['iprint'] = 2 newton.options['maxiter'] = 20 newton.options['solve_subsystems'] = True newton.linesearch = ArmijoGoldsteinLS() newton.linesearch.options['maxiter'] = 10 newton.linesearch.options['iprint'] = 2 # set initial guesses from the current source problem p['circuit.n1.V'] = 9.8 p['circuit.n2.V'] = .7 p.run_model() assert_rel_error(self, p['circuit.n1.V'], 1.5, 1e-5) assert_rel_error(self, p['circuit.n2.V'], 0.676232, 1e-5) assert_rel_error(self, p['circuit.R1.I'], 0.015, 1e-5) assert_rel_error(self, p['circuit.R2.I'], 8.23767999e-05, 1e-5) assert_rel_error(self, p['circuit.D1.I'], 8.23767999e-05, 1e-5)
def test_feature(self): import numpy as np from openmdao.api import Problem, ImplicitComponent, IndepVarComp, LinearRunOnce, PETScKrylov, PETScVector, LinearUserDefined from openmdao.utils.array_utils import evenly_distrib_idxs class CustomSolveImplicit(ImplicitComponent): def setup(self): self.add_input('a', val=10., units='m') rank = self.comm.rank GLOBAL_SIZE = 15 sizes, offsets = evenly_distrib_idxs(self.comm.size, GLOBAL_SIZE) self.add_output('states', shape=int(sizes[rank])) self.add_output('out_var', shape=1) self.local_size = sizes[rank] self.linear_solver = PETScKrylov() self.linear_solver.precon = LinearUserDefined( solve_function=self.mysolve) def solve_nonlinear(self, i, o): o['states'] = i['a'] local_sum = np.zeros(1) local_sum[0] = np.sum(o['states']) tmp = np.zeros(1) o['out_var'] = tmp[0] def apply_nonlinear(self, i, o, r): r['states'] = o['states'] - i['a'] local_sum = np.zeros(1) local_sum[0] = np.sum(o['states']) global_sum = np.zeros(1) r['out_var'] = o['out_var'] - tmp[0] def apply_linear(self, i, o, d_i, d_o, d_r, mode): if mode == 'fwd': if 'states' in d_o: d_r['states'] += d_o['states'] local_sum = np.array([np.sum(d_o['states'])]) global_sum = np.zeros(1) self.comm.Allreduce(local_sum, global_sum, op=MPI.SUM) d_r['out_var'] -= global_sum if 'out_var' in d_o: d_r['out_var'] += d_o['out_var'] if 'a' in d_i: d_r['states'] -= d_i['a'] elif mode == 'rev': if 'states' in d_o: d_o['states'] += d_r['states'] tmp = np.zeros(1) if self.comm.rank == 0: tmp[0] = d_r['out_var'].copy() self.comm.Bcast(tmp, root=0) d_o['states'] -= tmp if 'out_var' in d_o: d_o['out_var'] += d_r['out_var'] if 'a' in d_i: d_i['a'] -= np.sum(d_r['states']) def mysolve(self, d_outputs, d_residuals, mode): r""" Apply inverse jac product. The model is assumed to be in an unscaled state. If mode is: 'fwd': d_residuals \|-> d_outputs 'rev': d_outputs \|-> d_residuals Parameters ---------- d_outputs : Vector unscaled, dimensional quantities read via d_outputs[key] d_residuals : Vector unscaled, dimensional quantities read via d_residuals[key] mode : str either 'fwd' or 'rev' Returns ------- None or bool or (bool, float, float) The bool is the failure flag; and the two floats are absolute and relative error. """ # Note: we are just preconditioning with Identity as a proof of concept. if mode == 'fwd': d_outputs.set_vec(d_residuals) elif mode == 'rev': d_residuals.set_vec(d_outputs) return False, 0., 0. prob = Problem() prob.model.add_subsystem('des_vars', IndepVarComp('a', val=10., units='m'), promotes=['*']) prob.model.add_subsystem('icomp', CustomSolveImplicit(), promotes=['*']) model = prob.model model.linear_solver = PETScKrylov() model.linear_solver.precon = LinearRunOnce() prob.setup(mode='rev', check=False) prob.run_model() jac = prob.compute_totals(of=['out_var'], wrt=['a'], return_format='dict') assert_rel_error(self, 15.0, jac['out_var']['a'][0][0])
def setup(self): surfaces = self.options['surfaces'] rotational = self.options['rotational'] # Loop through each surface and connect relevant parameters for surface in surfaces: name = surface['name'] self.connect(name + '.normals', 'aero_states.' + name + '_normals') # Connect the results from 'aero_states' to the performance groups self.connect('aero_states.' + name + '_sec_forces', name + '_perf' + '.sec_forces') # Connect S_ref for performance calcs self.connect(name + '.S_ref', name + '_perf.S_ref') self.connect(name + '.widths', name + '_perf.widths') self.connect(name + '.chords', name + '_perf.chords') self.connect(name + '.lengths', name + '_perf.lengths') self.connect(name + '.cos_sweep', name + '_perf.cos_sweep') # Connect S_ref for performance calcs self.connect(name + '.S_ref', 'total_perf.' + name + '_S_ref') self.connect(name + '.widths', 'total_perf.' + name + '_widths') self.connect(name + '.chords', 'total_perf.' + name + '_chords') self.connect(name + '.b_pts', 'total_perf.' + name + '_b_pts') self.connect(name + '_perf' + '.CL', 'total_perf.' + name + '_CL') self.connect(name + '_perf' + '.CD', 'total_perf.' + name + '_CD') self.connect('aero_states.' + name + '_sec_forces', 'total_perf.' + name + '_sec_forces') self.add_subsystem(name, VLMGeometry(surface=surface)) # Add a single 'aero_states' component that solves for the circulations # and forces from all the surfaces. # While other components only depends on a single surface, # this component requires information from all surfaces because # each surface interacts with the others. if self.options['compressible'] == True: aero_states = CompressibleVLMStates(surfaces=surfaces, rotational=rotational) prom_in = ['v', 'alpha', 'beta', 'rho', 'Mach_number'] else: aero_states = VLMStates(surfaces=surfaces, rotational=rotational) prom_in = ['v', 'alpha', 'beta', 'rho'] aero_states.linear_solver = LinearRunOnce() if rotational: prom_in.extend(['omega', 'cg']) self.add_subsystem('aero_states', aero_states, promotes_inputs=prom_in, promotes_outputs=['circulations']) # Explicitly connect parameters from each surface's group and the common # 'aero_states' group. # This is necessary because the VLMStates component requires information # from each surface, but this information is stored within each # surface's group. for surface in surfaces: self.add_subsystem(surface['name'] + '_perf', VLMFunctionals(surface=surface), promotes_inputs=[ 'v', 'alpha', 'beta', 'Mach_number', 're', 'rho' ]) # Add the total aero performance group to compute the CL, CD, and CM # of the total aircraft. This accounts for all lifting surfaces. self.add_subsystem( 'total_perf', TotalAeroPerformance( surfaces=surfaces, user_specified_Sref=self.options['user_specified_Sref']), promotes_inputs=['v', 'rho', 'cg', 'S_ref_total'], promotes_outputs=['CM', 'CL', 'CD'])
class PlanesIntersection(Group): def setup(self): self.add_subsystem('p3', Plane3()) self.add_subsystem('p1', Plane1()) self.add_subsystem('p2', Plane2()) self.connect('p1.y', 'p2.y') self.connect('p1.y', 'p3.y') self.connect('p2.x', 'p3.x') self.connect('p2.x', 'p1.x') self.connect('p3.z', 'p1.z') self.connect('p3.z', 'p2.z') prob = Problem() from openmdao.api import LinearRunOnce prob.model = PlanesIntersection() # a = prob.model.nonlinear_solver = NewtonSolver() a = prob.model.linear_solver = LinearRunOnce() a.options['maxiter'] = 10 prob.setup() # view_model(prob) prob.run_model() print(prob['p1.y'], prob['p1.x'], prob['p1.z'])
model.connect('circuit.n1.V', 'batt_deltaV.V1') # set the lhs and rhs for the battery residual model.connect('batt.V', 'batt_balance.rhs:I') model.connect('batt_deltaV.dV', 'batt_balance.lhs:I') p.setup() ################### # Solver Setup ################### # change the circuit solver to RunOnce because we're # going to converge at the top level of the model with newton instead p.model.circuit.nonlinear_solver = NonlinearRunOnce() p.model.circuit.linear_solver = LinearRunOnce() # Put Newton at the top so it can also converge the new BalanceComp residual newton = p.model.nonlinear_solver = NewtonSolver() p.model.linear_solver = DirectSolver() newton.options['iprint'] = 2 newton.options['maxiter'] = 20 newton.options['solve_subsystems'] = True newton.linesearch = ArmijoGoldsteinLS() newton.linesearch.options['maxiter'] = 10 newton.linesearch.options['iprint'] = 2 # set initial guesses from the current source problem p['circuit.n1.V'] = 9.8 p['circuit.n2.V'] = .7
def setup(self): surfaces = self.options['surfaces'] for surface in surfaces: name = surface['name'] self.connect(name + '.normals', 'aero_states.' + name + '_normals') # self.connect(name + '.b_pts', 'aero_states.' + name + '_b_pts') # self.connect(name + '.c_pts', 'aero_states.' + name + '_c_pts') # self.connect(name + '.cos_sweep', 'aero_states.' + name + '_cos_sweep') # self.connect(name + '.widths', 'aero_states.' + name + '_widths') # Connect the results from 'aero_states' to the performance groups self.connect('aero_states.' + name + '_sec_forces', name + '_perf' + '.sec_forces') # Connect S_ref for performance calcs self.connect(name + '.S_ref', name + '_perf.S_ref') self.connect(name + '.widths', name + '_perf.widths') self.connect(name + '.chords', name + '_perf.chords') self.connect(name + '.lengths', name + '_perf.lengths') self.connect(name + '.cos_sweep', name + '_perf.cos_sweep') # Connect S_ref for performance calcs self.connect(name + '.S_ref', 'total_perf.' + name + '_S_ref') self.connect(name + '.widths', 'total_perf.' + name + '_widths') self.connect(name + '.chords', 'total_perf.' + name + '_chords') self.connect(name + '.b_pts', 'total_perf.' + name + '_b_pts') self.connect(name + '_perf' + '.CL', 'total_perf.' + name + '_CL') self.connect(name + '_perf' + '.CD', 'total_perf.' + name + '_CD') self.connect('aero_states.' + name + '_sec_forces', 'total_perf.' + name + '_sec_forces') self.add_subsystem(name, VLMGeometry(surface=surface)) # Add a single 'aero_states' component that solves for the circulations # and forces from all the surfaces. # While other components only depends on a single surface, # this component requires information from all surfaces because # each surface interacts with the others. aero_states = VLMStates(surfaces=surfaces) aero_states.linear_solver = LinearRunOnce() self.add_subsystem('aero_states', aero_states, promotes_inputs=['v', 'alpha', 'rho'], promotes_outputs=['circulations']) # Explicitly connect parameters from each surface's group and the common # 'aero_states' group. # This is necessary because the VLMStates component requires information # from each surface, but this information is stored within each # surface's group. for surface in surfaces: self.add_subsystem( surface['name'] + '_perf', VLMFunctionals(surface=surface), promotes_inputs=["v", "alpha", "M", "re", "rho"]) self.add_subsystem('total_perf', TotalAeroPerformance(surfaces=surfaces), promotes_inputs=['v', 'rho', 'cg', 'S_ref_total'], promotes_outputs=['CM', 'CL', 'CD'])