class NLP: """NLP class transcribes a continuous-time optimal control problem in trajectory optimization into a Non Linear Programming Problem (NLP) using the OpenMDAO and dymos libraries. Parameters ---------- body : Primary Instance of `Primary` class representing the central attracting body sc : Spacecraft Instance of `Spacecraft` class representing the spacecraft method : str Transcription method used to discretize the continuous time trajectory into a finite set of nodes, allowed ``gauss-lobatto``, ``radau-ps`` and ``runge-kutta`` nb_seg : int or tuple Number of segments in which each phase is discretized order : int or tuple Transcription order within each phase, must be odd solver : str NLP solver, must be supported by OpenMDAO snopt_opts : dict or None, optional SNOPT optional settings expressed as key-value pairs. Refer to the SNOPT User Guide [1]_ for more details. Default is None rec_file : str or None, optional Name of the file in which the computed solution is recorded or None. Default is None Attributes ---------- body : Primary Instance of `Primary` class representing the central attracting body sc : Spacecraft Instance of `Spacecraft` class representing the spacecraft method : str Transcription method used to discretize the continuous time trajectory into a finite set of nodes, allowed ``gauss-lobatto``, ``radau-ps`` and ``runge-kutta`` nb_seg : int or tuple Number of segments in which each phase is discretized order : int or tuple Transcription order within each phase, must be odd solver : str NLP solver, must be supported by OpenMDAO snopt_opts : dict or None SNOPT optional settings expressed as key-value pairs. Refer to the SNOPT User Guide [1]_ for more details. rec_file : str or None Name of the file in which the computed solution is recorded or None p : Problem OpenMDAO `Problem` class instance representing the NLP trajectory : Trajectory Dymos `Trajectory` class instance representing the spacecraft trajectory p_exp : Problem OpenMDAO `Problem` class instance representing the explicitly simulated trajectory References ---------- .. [1] Gill, Philip E., et al. User’s Guide for SNOPT Version 7.7: Software for Large-Scale Nonlinear Programming, Feb. 2019, p. 126. """ def __init__(self, body, sc, method, nb_seg, order, solver, snopt_opts=None, rec_file=None): """Initializes NLP class. """ # input parameters self.body = body self.sc = sc self.method = method self.nb_seg = nb_seg self.order = order self.solver = solver if self.solver == 'SNOPT': self.snopt_opts = snopt_opts else: self.snopt_opts = None self.rec_file = rec_file # Problem object self.p = Problem(model=Group()) # Problem Driver self.p.driver = pyOptSparseDriver() self.p.driver.options['optimizer'] = self.solver self.p.driver.options['print_results'] = False self.p.driver.options['dynamic_derivs_sparsity'] = True if self.snopt_opts is not None: for k in self.snopt_opts.keys(): self.p.driver.opt_settings[k] = self.snopt_opts[k] self.p.driver.declare_coloring(show_summary=True, show_sparsity=False) # Problem Recorder if rec_file is not None: recorder = SqliteRecorder(rec_file) opts = ['record_objectives', 'record_constraints', 'record_desvars'] self.p.add_recorder(recorder) for opt in opts: self.p.recording_options[opt] = False self.p.recording_options['excludes'] = rec_excludes self.rec_file = rec_file # Trajectory object self.trajectory = self.p.model.add_subsystem('traj', Trajectory()) # Problem object for explicit simulation self.p_exp = None def setup(self): """Set up the Jacobian type, linear solver and derivatives type. """ self.p.model.options['assembled_jac_type'] = 'csc' self.p.model.linear_solver = DirectSolver() self.p.setup(check=True, force_alloc_complex=True, derivatives=True) def exp_sim(self, rec_file=None): """Explicitly simulate the implicitly obtained optimal solution using Scipy `solve_ivp` method. """ if rec_file is not None: self.p_exp = self.trajectory.simulate(atol=1e-12, rtol=1e-12, record_file=rec_file) else: self.p_exp = self.trajectory.simulate(atol=1e-12, rtol=1e-12) self.cleanup() def cleanup(self): """Clean up resources. """ self.trajectory.cleanup() self.p.driver.cleanup() self.p.cleanup() def __str__(self): """Prints info on the NLP. Returns ------- s : str Info on the NLP """ lines = ['\n{:^40s}'.format('NLP characteristics:'), '\n{:<25s}{:<15s}'.format('Solver:', self.solver), '{:<25s}{:<15s}'.format('Transcription method:', str(self.method)), '{:<25s}{:<15s}'.format('Number of segments:', str(self.nb_seg)), '{:<25s}{:<15s}'.format('Transcription order:', str(self.order))] s = '\n'.join(lines) return s
def test_recording_remote_voi(self): # Create a parallel model model = Group() model.add_subsystem('par', ParallelGroup()) model.par.add_subsystem('G1', Mygroup()) model.par.add_subsystem('G2', Mygroup()) model.connect('par.G1.y', 'Obj.y1') model.connect('par.G2.y', 'Obj.y2') model.add_subsystem('Obj', ExecComp('obj=y1+y2')) model.add_objective('Obj.obj') # Configure driver to record VOIs on both procs driver = ScipyOptimizeDriver(disp=False) driver.recording_options['record_desvars'] = True driver.recording_options['record_responses'] = True driver.recording_options['record_objectives'] = True driver.recording_options['record_constraints'] = True driver.recording_options['includes'] = ['par.G1.y', 'par.G2.y'] driver.add_recorder(self.recorder) # Create problem and run driver prob = Problem(model, driver) prob.add_recorder(self.recorder) prob.setup() t0, t1 = run_driver(prob) prob.record_iteration('final') t2 = time() prob.cleanup() # Since the test will compare the last case recorded, just check the # current values in the problem. This next section is about getting those values # These involve collective gathers so all ranks need to run this expected_outputs = driver.get_design_var_values() expected_outputs.update(driver.get_objective_values()) expected_outputs.update(driver.get_constraint_values()) # includes for outputs are specified as promoted names but we need absolute names prom2abs = model._var_allprocs_prom2abs_list['output'] abs_includes = [prom2abs[n][0] for n in prob.driver.recording_options['includes']] # Absolute path names of includes on this rank rrank = model.comm.rank rowned = model._owning_rank local_includes = [n for n in abs_includes if rrank == rowned[n]] # Get values for all vars on this rank inputs, outputs, residuals = model.get_nonlinear_vectors() # Get values for includes on this rank local_vars = {n: outputs[n] for n in local_includes} # Gather values for includes on all ranks all_vars = model.comm.gather(local_vars, root=0) if prob.comm.rank == 0: # Only on rank 0 do we have all the values. The all_vars variable is a list of # dicts from all ranks 0,1,... In this case, just ranks 0 and 1 dct = all_vars[-1] for d in all_vars[:-1]: dct.update(d) expected_includes = { 'par.G1.Cy.y': dct['par.G1.Cy.y'], 'par.G2.Cy.y': dct['par.G2.Cy.y'], } expected_outputs.update(expected_includes) coordinate = [0, 'ScipyOptimize_SLSQP', (driver.iter_count-1,)] expected_data = ((coordinate, (t0, t1), expected_outputs, None),) assertDriverIterDataRecorded(self, expected_data, self.eps) expected_data = (('final', (t1, t2), expected_outputs),) assertProblemDataRecorded(self, expected_data, self.eps)
def test_recording_remote_voi(self): # Create a parallel model model = Group() model.add_subsystem('par', ParallelGroup()) model.par.add_subsystem('G1', Mygroup()) model.par.add_subsystem('G2', Mygroup()) model.connect('par.G1.y', 'Obj.y1') model.connect('par.G2.y', 'Obj.y2') model.add_subsystem('Obj', ExecComp('obj=y1+y2')) model.add_objective('Obj.obj') # Configure driver to record VOIs on both procs driver = ScipyOptimizeDriver(disp=False) driver.recording_options['record_desvars'] = True driver.recording_options['record_responses'] = True driver.recording_options['record_objectives'] = True driver.recording_options['record_constraints'] = True driver.recording_options['includes'] = ['par.G1.y', 'par.G2.y'] driver.add_recorder(self.recorder) # Create problem and run driver prob = Problem(model, driver) prob.add_recorder(self.recorder) prob.setup() t0, t1 = run_driver(prob) prob.record_iteration('final') t2 = time() prob.cleanup() # Since the test will compare the last case recorded, just check the # current values in the problem. This next section is about getting those values # These involve collective gathers so all ranks need to run this expected_outputs = driver.get_design_var_values() expected_outputs.update(driver.get_objective_values()) expected_outputs.update(driver.get_constraint_values()) # includes for outputs are specified as promoted names but we need absolute names prom2abs = model._var_allprocs_prom2abs_list['output'] abs_includes = [ prom2abs[n][0] for n in prob.driver.recording_options['includes'] ] # Absolute path names of includes on this rank rrank = model.comm.rank rowned = model._owning_rank local_includes = [n for n in abs_includes if rrank == rowned[n]] # Get values for all vars on this rank inputs, outputs, residuals = model.get_nonlinear_vectors() # Get values for includes on this rank local_vars = {n: outputs[n] for n in local_includes} # Gather values for includes on all ranks all_vars = model.comm.gather(local_vars, root=0) if prob.comm.rank == 0: # Only on rank 0 do we have all the values. The all_vars variable is a list of # dicts from all ranks 0,1,... In this case, just ranks 0 and 1 dct = all_vars[-1] for d in all_vars[:-1]: dct.update(d) expected_includes = { 'par.G1.Cy.y': dct['par.G1.Cy.y'], 'par.G2.Cy.y': dct['par.G2.Cy.y'], } expected_outputs.update(expected_includes) coordinate = [0, 'ScipyOptimize_SLSQP', (driver.iter_count - 1, )] expected_data = ((coordinate, (t0, t1), expected_outputs, None), ) assertDriverIterDataRecorded(self, expected_data, self.eps) expected_data = (('final', (t1, t2), expected_outputs), ) assertProblemDataRecorded(self, expected_data, self.eps)
#Optimization Set-Up p.driver = ScipyOptimizeDriver() p.driver.options['optimizer'] = 'SLSQP' # p.driver.options['optimizer'] = 'COBYLA' p.driver.options model.linear_solver = DirectSolver(iprint=2) # model.add_design_var('eta_sa', lower = 0.01, upper=1) model.add_design_var('M_ps', lower=0.01, upper=100) model.add_constraint('con1',) model.add_objective('t_tot') #Case Recorder Setting recorder = SqliteRecorder('test.sql') p.driver.add_recorder(recorder) p.add_recorder(recorder) #Set-up and Run p.setup() p.set_solver_print(2) p.run_driver() # view_model(p) p.record_iteration('final') p.cleanup() cr = CaseReader('test.sql') drivercases = cr.list_cases('driver') case = cr.get_case(drivercases[0]) print(sorted(case.outputs.keys())) print('P_req',['P_req'])