def set_boundary_cond(self, BC): """Setter for attribute BC. Args: BC (utils.BoundaryConditions): constraints for two-point boundary value problem. """ self.BC = utils.BoundaryConditions(BC.nu0, BC.nuf, BC.x0, BC.xf) self.plotter.set_boundary_cond(BC)
def run(self, BC): """Wrapper for all solving strategies (analytical, numerical and both). Args: BC (utils.BoundaryConditions): constraints for two-point boundary value problem. Returns: (utils.ControlLaw): optimal control law. """ if BC.half_dim == 1 and self.prop_ana: # out-of-plane analytical solving if self.dyn.mu != 0 and self.dyn.ecc == 0. and ( self.dyn.Li == 1 or self.dyn.Li == 2 or self.dyn.Li == 3): # special case of circular out-of-plane L1, 2 or 3 where analytical solution can be obtained from # 2-body solution by rescaling anomaly return self._circular_oop_L123(BC) else: # out-of-plane for elliptical 2-body problem or elliptical 3-body around L4 and 5 or circular around L1, 2 and 3 z = self.dyn.compute_rhs(BC, analytical=self.prop_ana) (nus, DVs, lamb) = solver_ana(z, self.dyn.ecc, self.dyn.mean_motion, BC.nu0, BC.nuf) return utils.ControlLaw(BC.half_dim, nus, DVs, lamb) elif (BC.half_dim == 3) and ( self.p == 1 ): # merge analytical and numerical solutions in the case of complete # dynamics with the 1-norm x0_ip, x0_oop = unstack_state(BC.x0) xf_ip, xf_oop = unstack_state(BC.xf) BC_oop = utils.BoundaryConditions(BC.nu0, BC.nuf, x0_oop, xf_oop) CL_oop = self.run(BC_oop) BC_ip = utils.BoundaryConditions(BC.nu0, BC.nuf, x0_ip, xf_ip) CL_ip = self.run(BC_ip) return utils.merge_control(CL_ip, CL_oop) else: # numerical solving return self.indirect_num(BC)
def __init__(self, indirect, p, plr): """Constructor for class master. Args: indirect (bool): set to True for indirect approach and False for direct one. p (int): type of norm to be minimized. plr (plotter.Plotter): plotter object for plotting. """ self.BC = utils.BoundaryConditions(plr.BC.nu0, plr.BC.nuf, plr.BC.x0, plr.BC.xf) self.plotter = plotter.Plotter(plr.dyn, plr.BC, plr.p, plr.anomaly, plr.linearized, plr.analytical) self.CL = utils.NoControl(self.BC.half_dim) if indirect: self._solver = indirect_solver.IndirectSolver( self.plotter.dyn, p, plr.analytical) else: # direct approach chosen self._solver = direct_solver.DirectSolver(self.plotter.dyn, p, plr.analytical)
def __init__(self, dyn, BC, p, anomaly, linearized, analytical, CL=None): """Constructor for class plotter. Args: dyn (dynamical_system.DynamicalSystem): dynamics to be used for two-boundary value problem. BC (utils.BoundaryConditions): constraints for two-point boundary value problem. p (int): type of norm for control law to be plotted. anomaly (bool): set to True if independent variable is the true anomaly and to False if it is time. linearized (bool): set to True to plot linearized dynamics, False otherwise analytical (bool): set to True to propagate the state vector analytically if possible, False otherwise CL (utils.ControlLaw): control law to be simulated. """ self.p = p self._q = indirect_num.dual_to_primal_norm_type(p) self.dyn = dynamical_system.DynamicalSystem(dyn.mu, dyn.ecc, dyn.period, dyn.sma, dyn.Li) self.BC = utils.BoundaryConditions(BC.nu0, BC.nuf, BC.x0, BC.xf) if CL is None: self.CL = utils.NoControl(BC.half_dim) self.linearized = linearized self.anomaly = anomaly if analytical and dyn.mu != 0. and dyn.ecc != 0. and ( dyn.Li == 1 or dyn.Li == 2 or dyn.Li == 3 or BC.half_dim > 1): print( 'WARNING: propagation type within plotter changed to numerical' ) self.analytical = False else: # propagation has to be numerical for elliptical out-of-plane L1, 2 or 3 or elliptical in-plane of any LP self.analytical = analytical self._nb = plot_params["mesh_plot"] self._nus = None self._times = None self._pts = None self._compute_points() self._states = None
def _circular_oop_L123(self, BC): """Function computing the optimal control law analytically in the special case of out-of-plane dynamics in the circular L1, 2 or 3. Args: BC (utils.BoundaryConditions): constraints for two-point boundary value problem. Returns: (utils.ControlLaw): analytical optimal control law. """ # getting scaling factor for time puls = orbital_mechanics.puls_oop_LP(self.dyn.x_eq_normalized, self.dyn.mu) # scaling inputs BC_rescaled = utils.BoundaryConditions(BC.nu0 * puls, BC.nuf * puls, BC.x0, BC.xf) dyn_rescaled = dynamical_system.DynamicalSystem( 0., 0., self.dyn.period / puls, self.dyn.sma) z_rescaled = dyn_rescaled.compute_rhs(BC_rescaled, analytical=True) # 'classic' call to numerical solver (nus, DVs, lamb) = solver_ana(z_rescaled, 0., dyn_rescaled.mean_motion, BC_rescaled.nu0, BC_rescaled.nuf) factor = linalg.norm(self.dyn.compute_rhs( BC, analytical=True)) / linalg.norm(z_rescaled) # un-scaling for k in range(0, len(nus)): nus[k] /= puls for k in range(0, len(lamb)): lamb[k] /= factor return utils.ControlLaw(BC.half_dim, nus, DVs, lamb)
) # 3-body restricted dynamics is linearized around Earth-Moon Lagrange Point 4 hd = 3 # half-dimension of state vector (1 for out-of-plane dynamics only, 2 for in-plane only and 3 for complete) x0 = numpy.zeros(hd * 2) xf = numpy.zeros(hd * 2) for i in range(0, len(x0)): if i < hd: x0[i] = (-1.0 + 2.0 * random.random()) * 1.0e3 xf[i] = (-1.0 + 2.0 * random.random()) * 1.0e3 else: x0[i] = (-1.0 + 2.0 * random.random()) * 1.0e3 * math.pi / dyn.period xf[i] = (-1.0 + 2.0 * random.random()) * 1.0e3 * math.pi / dyn.period p = 2 # norm for minimization (1 or 2) BC = utils.BoundaryConditions(nu0, nuf, x0, xf) plr = plotter.Plotter(dyn, BC, p, anomaly=True, linearized=True, analytical=True) master = master.Master(indirect=True, p=p, plr=plr) t1 = time.time() master.solve() print("Time elapsed with indirect approach: " + str(time.time() - t1) + " s") master.plot() master.write_boundary_cond("boundary_conditions_compa_approach.txt") master.write_control_law("control_law_indirect.txt")
def compute_rhs(self, BC, analytical): """Function that computes right-hand side of moment equation. Args: BC (utils.BoundaryConditions): constraints for two-point boundary value problem. analytical (bool): set to true for analytical propagation of motion, false for integration. Returns: u (numpy.array): right-hand side of moment equation. """ factor = 1.0 - self.ecc * self.ecc multiplier = self.mean_motion / math.sqrt(factor * factor * factor) x1 = self.transformation(BC.x0, BC.nu0) x2 = self.transformation(BC.xf, BC.nuf) if analytical: u = numpy.zeros(2 * BC.half_dim) if BC.half_dim == 1: if (self.mu != 0.) and (self.Li == 1 or self.Li == 2 or self.Li == 3): if self.ecc == 0.: u += phi_harmo( -BC.nuf, puls_oop_LP(self.x_eq_normalized, self.mu)).dot(x2) u -= phi_harmo( -BC.nu0, puls_oop_LP(self.x_eq_normalized, self.mu)).dot(x1) else: print( 'compute_rhs: analytical 3-body elliptical out-of-plane near L1, 2 and 3 not coded yet' ) else: # out-of-plane elliptical 2-body problem or 3-body near L4 and 5 u += phi_harmo(-BC.nuf, 1.0).dot(x2) u -= phi_harmo(-BC.nu0, 1.0).dot(x1) u[0] *= multiplier u[1] *= multiplier elif BC.half_dim == 2: if self.mu == 0.: if self.ecc == 0.: u += exp_HCW(-BC.nuf).dot(x2) u -= exp_HCW(-BC.nu0).dot(x1) else: # elliptical case M = phi_YA(self.ecc, self.mean_motion, 0., BC.nuf) u += linalg.inv(M).dot(x2) M = phi_YA(self.ecc, self.mean_motion, 0., BC.nu0) u -= linalg.inv(M).dot(x1) for i in range(0, len(u)): u[i] *= multiplier else: # in-plane restricted 3-body problem if self.ecc == 0.: if (self.Li == 1) or (self.Li == 2) or (self.Li == 3): u += self.exp_LP123(-BC.nuf).dot(x2) u -= self.exp_LP123(-BC.nu0).dot(x1) elif self.Li == 4: u += self.exp_LP45(-BC.nuf, 1. - 2. * self.mu).dot(x2) u -= self.exp_LP45(-BC.nu0, 1. - 2. * self.mu).dot(x1) else: # Li = 5 u += self.exp_LP45(-BC.nuf, -1. + 2. * self.mu).dot(x2) u -= self.exp_LP45(-BC.nu0, -1. + 2. * self.mu).dot(x1) else: # elliptical case print( 'compute_rhs: analytical elliptical 3-body problem in-plane dynamics case not coded yet' ) for i in range(0, len(u)): u[i] *= multiplier else: # complete dynamics x0_ip, x0_oop = utils.unstack_state(BC.x0) xf_ip, xf_oop = utils.unstack_state(BC.xf) BC_ip = utils.BoundaryConditions(BC.nu0, BC.nuf, x0_ip, xf_ip) BC_oop = utils.BoundaryConditions(BC.nu0, BC.nuf, x0_oop, xf_oop) z_oop = self.compute_rhs(BC_oop, analytical=True) z_ip = self.compute_rhs(BC_ip, analytical=True) u = utils.stack_state(z_ip, z_oop) else: # numerical integration matrices = self.integrate_phi_inv([BC.nu0, BC.nuf], BC.half_dim) IC_matrix = matrices[0] FC_matrix = matrices[-1] u = (FC_matrix.dot(x2) - IC_matrix.dot(x1)) * multiplier return u