def __init__(self, gm, r, alt, rp, t, sc): """Initializes `TwoDimLLO2HEOGuess` class. """ dep = TwoDimOrb(gm, a=(r + alt), e=0) arr = TwoDimOrb(gm, T=t, rp=rp) TwoDimHEOGuess.__init__(self, gm, r, dep, arr, sc) self.pow = PowConstRadius(gm, dep.a, dep.vp, self.ht.transfer.vp, sc.m0, sc.T_max, sc.Isp) self.pow.compute_final_time_states() self.tf = self.pow.tf + self.ht.tof self.insertion_burn = None
def __init__(self, gm, dep, arr): """Initializes `HohmannTransfer` class. """ self.GM = gm self.depOrb = dep self.arrOrb = arr if self.depOrb.a < self.arrOrb.a: # ascent self.ra = self.arrOrb.ra self.rp = self.depOrb.rp else: # descent self.ra = self.depOrb.ra self.rp = self.arrOrb.rp self.transfer = TwoDimOrb(self.GM, ra=self.ra, rp=self.rp) self.tof = self.transfer.T / 2 if self.depOrb.a < self.arrOrb.a: # ascent self.dvp = self.transfer.vp - self.depOrb.vp self.dva = self.arrOrb.va - self.transfer.va else: # descent self.dva = self.depOrb.va - self.transfer.va self.dvp = self.transfer.vp - self.arrOrb.vp self.r = self.theta = self.u = self.v = None self.states = self.controls = None
def compute_energy_mprop(self, r, u, v, m_coast): """Computes the specific energy of the spacecraft on the ballistic arc and the total propellant mass including the final insertion burn. Parameters ---------- r : float Radius at the end of the first powered phase [m] u : float Radial velocity at the end of the first powered phase [m/s] v : float Tangential velocity at the end of the first powered phase [m/s] m_coast : float Spacecraft mass on the ballistic arc [kg] Returns ------- en : float Specific energy of the spacecraft on the ballistic arc [m/s] m_prop : float Total propellant mass including the final insertion burn [kg] """ en = TwoDimOrb.polar2energy( self.body.GM, r, u, v) # specific energy on ballistic arc [m^2/s^2] va = (2 * (en + self.body.GM / self.nlp.guess.ht.arrOrb.ra) )**0.5 # ballistic arc apoapsis velocity [m/s] dva = self.guess.ht.arrOrb.va - va # apoapsis dv [m/s] m_prop = self.sc.m0 - ImpulsiveBurn.tsiolkovsky_mf( m_coast, dva, self.sc.Isp) # total propellant mass [kg] return en, m_prop
def __init__(self, body, db, case_id='final', db_exp=None, scaled=False): Reader.__init__(self, db, case_id=case_id, db_exp=db_exp) self.body = body if scaled: self.gm_res = 1.0 self.rm_res = 1.0 self.states_scalers = None else: self.gm_res = body.GM self.rm_res = body.R self.states_scalers = np.array( [body.R, 1.0, body.vc, body.vc, 1.0]) self.phase_name = [] for s in ['dep', 'coast', 'arr']: ph_name = '.'.join(['traj', s, 'timeseries']) self.phase_name.append(ph_name) self.tof, self.time, self.states, self.controls = self.get_time_series( self.case) if db_exp is not None: self.tof_exp, self.time_exp, self.states_exp, self.controls_exp = self.get_time_series( self.case_exp) else: self.tof_exp = self.time_exp = self.states_exp = self.controls_exp = None self.coe_inj = TwoDimOrb.polar2coe(self.gm_res, self.states[-1][-1, 0], self.states[-1][-1, 2], self.states[-1][-1, 3])
def __init__(self, gm, r, alt, rp, t, sc): """Initializes `TwoDimHEO2LLOGuess` class. """ arr = TwoDimOrb(gm, a=(r + alt), e=0) dep = TwoDimOrb(gm, T=t, rp=rp) TwoDimGuess.__init__(self, gm, r, dep, arr, sc) self.deorbit_burn = ImpulsiveBurn(sc, self.ht.dva) self.pow = PowConstRadius(gm, arr.a, self.ht.transfer.vp, arr.vp, self.deorbit_burn.mf, sc.T_max, sc.Isp, t0=self.ht.tof) self.pow.compute_final_time_states() self.tf = self.pow.tf
def compute_solution(self, nb=200): """Retrieves the optimization results and computes the spacecraft states along the ballistic arc as well as the final insertion burn. Parameters ---------- nb : int, optional Number of points in which the spacecraft states along the ballistic arc are computed. Default is ``200`` """ # states and COEs at the end of the departure burn states_end = self.states[-1] a, e, h, ta = TwoDimOrb.polar2coe(self.gm_res, states_end[0], states_end[2], states_end[3]) # coasting orbit in dimensional units if np.isclose(self.gm_res, 1.0): self.transfer = TwoDimOrb(self.body.GM, a=a * self.body.R, e=e) else: self.transfer = TwoDimOrb(self.body.GM, a=a, e=e) # finite dV at departure [m/s] self.dv_dep = ImpulsiveBurn.tsiolkovsky_dv(self.sc.m0, states_end[-1], self.sc.Isp) # impulsive dV at arrival [m/s] sc = deepcopy(self.sc) sc.m0 = states_end[-1] self.insertion_burn = ImpulsiveBurn( sc, self.guess.ht.arrOrb.va - self.transfer.va) # time and states along transfer orbit t, states = TwoDimOrb.propagate(self.gm_res, a, e, ta, np.pi, nb) # adjust time t_pow_end = self.time[-1, -1] t_coast_start = t[0, 0] t_coast_end = t[-1, 0] tof_coast = t_coast_end - t_coast_start self.tof = [self.tof, tof_coast] self.time = [self.time, (t - t_coast_start) + t_pow_end] # add mass m = np.vstack((states_end[-1] * np.ones( (len(t) - 1, 1)), [self.insertion_burn.mf])) states = np.hstack((states, m)) # stack states and controls self.states = [self.states, states] self.controls = [self.controls, np.zeros((len(t), 2))] self.controls[-1][-1, 0] = self.controls[0][0, 0] # adjust theta dtheta = ta - self.states[0][-1, 1] self.states[0][:, 1] = self.states[0][:, 1] + dtheta if self.states_exp is not None: self.states_exp[:, 1] = self.states_exp[:, 1] + dtheta
def __init__(self, gm, r, alt, sc): """Initializes `TwoDimAscGuess` class. """ dep = TwoDimOrb(gm, a=r, e=0) arr = TwoDimOrb(gm, a=(r + alt), e=0) TwoDimGuess.__init__(self, gm, r, dep, arr, sc) self.pow1 = PowConstRadius(gm, r, 0.0, self.ht.transfer.vp, sc.m0, sc.T_max, sc.Isp) self.pow1.compute_final_time_states() self.pow2 = PowConstRadius(gm, (r + alt), self.ht.transfer.va, self.ht.arrOrb.va, self.pow1.mf, sc.T_max, sc.Isp, t0=(self.pow1.tf + self.ht.tof), theta0=(self.pow1.thetaf + np.pi)) self.pow2.compute_final_time_states() self.tf = self.pow2.tf
def __init__(self, gm, r, alt, rp, t, sc): dep = TwoDimOrb(gm, a=(r + alt), e=0) arr = TwoDimOrb(gm, T=t, rp=rp) TwoDimGuess.__init__(self, gm, r, dep, arr, sc) self.pow1 = PowConstRadius(gm, (r + alt), dep.vp, self.ht.transfer.vp, sc.m0, sc.T_max, sc.Isp) self.pow1.compute_final_time_states() self.pow2 = PowConstRadius(gm, arr.ra, self.ht.transfer.va, arr.va, self.pow1.mf, sc.T_max, sc.Isp, t0=(self.pow1.tf + self.ht.tof), theta0=(self.pow1.thetaf + np.pi)) self.pow2.compute_final_time_states() self.tf = self.pow2.tf
def get_solutions(self, explicit=True, scaled=False): """Access the simulation solution. Parameters ---------- explicit : bool Computes also the explicit simulation. Default is ``True`` scaled : bool Scales the simulation results. Default is ``False`` """ TwoDimAnalyzer.get_solutions(self, explicit=explicit, scaled=scaled) coe = TwoDimOrb.polar2coe(self.gm_res, self.states[0][-1, 0], self.states[0][-1, 2], self.states[0][-1, 3]) self.transfer = TwoDimOrb(self.body.GM, a=coe[0] * self.body.R / self.rm_res, e=coe[1]) for i in [0, 2]: self.dv.append( self.sc.Isp * g0 * np.log(self.states[i][0, -1] / self.states[i][-1, -1]))
def plot(self): """Plots the states and controls resulting from the simulation and the ones from the explicit computation in time. The semi-major axis and the eccentricity of the HEO are also displayed. """ coe_inj = TwoDimOrb.polar2coe(self.gm_res, self.states[-1][-1, 0], self.states[-1][-1, 2], self.states[-1][-1, 3]) dtheta = coe_inj[-1] - self.states[-1][-1, 1] sol_plot = TwoDimMultiPhaseSolPlot(self.rm_res, self.time, self.states, self.controls, self.time_exp, self.states_exp, a=self.nlp.guess.ht.arrOrb.a * (self.rm_res / self.body.R), e=self.nlp.guess.ht.arrOrb.e, dtheta=dtheta) sol_plot.plot()
class TwoDim3PhasesLLO2HEOAnalyzer(TwoDimMultiPhasesLLO2HEOAnalyzer): """Analyzer class defines the methods to analyze the results of a two dimensional 3 phases LLO to HEO simulation. It gives the results of an optimal trajectory from a Low Lunar Orbit of chosen altitude to an High Elliptical Orbit which can represent a transposition of an Halo orbit in 2D. The trajectory is modeled as the succession of three different phases: a first powered phase for departure, a coasting arch and a final powered phase for the injection. Parameters ---------- body : Primary Instance of `Primary` class describing the central attracting body sc : Spacecraft Instance of `Spacecraft` class describing the spacecraft characteristics alt : float alt : float Value of the initial LLO altitude [m] rp : float Value for the target HEO periselene radius [m] t : float Value for the guessed trajectory time of flight [s] t_bounds : float Value for the time of flight bounds [-] method : str NLP transcription method nb_seg : int Number of segments for the transcription order : int Transcription order solver : str NLP solver snopt_opts : dict Sets some SNOPT's options. Default is ``None`` rec_file : str Directory path for the solution recording file. Default is ``None`` check_partials : bool Checking of partial derivatives. Default is ``False`` Attributes ---------- body : Primary Instance of `Primary` class describing the central attracting body sc : Spacecraft Instance of `Spacecraft` class describing the spacecraft characteristics phase_name : str Describes the phase name in case of multi-phase trajectories. Can be ``dep``, ``coast`` or ``arr``. nlp : NLP Instance of `NLP` object describing the type of Non Linear Problem solver used tof : float Value of the time of flight resulting by the simulation [s] tof_exp : float Value of the time of flight of the explicit simulation [s] err : float Value of the error between the optimized simulation results and the explicit simulation results rm_res : float Value of the central body radius [-] or [m] states_scalers : ndarray Reference values of the states with which perform the scaling controls_scalers : ndarray Reference values of the controls with which perform the scaling """ def __init__(self, body, sc, alt, rp, t, t_bounds, method, nb_seg, order, solver, snopt_opts=None, rec_file=None, check_partials=False): """Initializes the `TwoDim3PhasesLLO2HEOAnalyzer` class variables. """ TwoDimMultiPhasesLLO2HEOAnalyzer.__init__(self, body, sc) self.phase_name = ('dep', 'coast', 'arr') self.nlp = TwoDim3PhasesLLO2HEONLP(body, sc, alt, rp, t, (-np.pi / 2, np.pi / 2), t_bounds, method, nb_seg, order, solver, self.phase_name, snopt_opts=snopt_opts, rec_file=rec_file, check_partials=check_partials) def get_time_series(self, p, scaled=False): """Access the time series of the problem. Parameters ---------- p : Problem Instance of `Problem` class scaled : bool Scales the simulation results Returns ------- tof : float Time of flight resulting from the optimized simulation phase [-] or [s] t : ndarray Time of flight time series for the optimized simulation phase [-] or [s] states : ndarray States time series for the optimized simulation phase controls : ndarray Controls time series for the optimized simulation phase """ tof = [] t = [] states = [] controls = [] for i in range(3): tofi, ti, si, ci = self.get_time_series_phase( p, self.nlp.phase_name[i], scaled=scaled) tof.append(tofi) t.append(ti) states.append(si) controls.append(ci) return tof, t, states, controls def get_solutions(self, explicit=True, scaled=False): """Access the simulation solution. Parameters ---------- explicit : bool Computes also the explicit simulation. Default is ``True`` scaled : bool Scales the simulation results. Default is ``False`` """ TwoDimAnalyzer.get_solutions(self, explicit=explicit, scaled=scaled) coe = TwoDimOrb.polar2coe(self.gm_res, self.states[0][-1, 0], self.states[0][-1, 2], self.states[0][-1, 3]) self.transfer = TwoDimOrb(self.body.GM, a=coe[0] * self.body.R / self.rm_res, e=coe[1]) for i in [0, 2]: self.dv.append( self.sc.Isp * g0 * np.log(self.states[i][0, -1] / self.states[i][-1, -1])) def __str__(self): """Prints info on the `TwoDim3PhasesLLO2HEOAnalyzer`. Returns ------- s : str Info on `TwoDim3PhasesLLO2HEOAnalyzer` """ if np.isclose(self.gm_res, 1.0): time_scaler = self.body.tc else: time_scaler = 1.0 lines = [ '\n{:^50s}'.format('2D Transfer trajectory from LLO to HEO:'), self.nlp.guess.__str__(), '\n{:^50s}'.format('Coasting orbit:'), self.transfer.__str__(), '\n{:^50s}'.format('Optimal transfer:'), '\n{:<25s}{:>20.6f}{:>5s}'.format( 'Propellant fraction:', 1 - self.states[-1][-1, -1] / self.sc.m0, ''), '{:<25s}{:>20.6f}{:>5s}'.format( 'Time of flight:', sum(self.tof) * time_scaler / 86400, 'days'), '\n{:^50s}'.format('Departure burn:'), '\n{:<25s}{:>20.6f}{:>5s}'.format('Impulsive dV:', self.nlp.guess.pow1.dv_inf, 'm/s'), '{:<25s}{:>20.6f}{:>5s}'.format('Finite dV:', self.dv[0], 'm/s'), '{:<25s}{:>20.6f}{:>5s}'.format('Burn time:', self.tof[0] * time_scaler, 's'), '{:<25s}{:>20.6f}{:>5s}'.format( 'Propellant fraction:', 1 - self.states[0][-1, -1] / self.sc.m0, ''), '\n{:^50s}'.format('Injection burn:'), '\n{:<25s}{:>20.6f}{:>5s}'.format('Impulsive dV:', self.nlp.guess.pow2.dv_inf, 'm/s'), '{:<25s}{:>20.6f}{:>5s}'.format('Finite dV:', self.dv[-1], 'm/s'), '{:<25s}{:>20.6f}{:>5s}'.format('Burn time:', self.tof[-1] * time_scaler, 's'), '{:<25s}{:>20.6f}{:>5s}'.format( 'Propellant fraction:', 1 - self.states[-1][-1, -1] / self.states[-1][0, -1], ''), TwoDimAnalyzer.__str__(self) ] s = '\n'.join(lines) return s
class TwoDimLLO2ApoAnalyzer(TwoDimAscAnalyzer): """TwoDimLLO2HEOAnalyzer class defines the methods to analyze the results of a two dimensional simulation from a Low Lunar Orbit to an Highly Elliptical Orbit. The Highly Elliptical Orbit is chosen as first planar approximation of a three-dimensional Near Rectilinear Halo Orbit. The optimal control problem is solved for a single phase trajectory performed at constant thrust that injects the spacecraft from the Low Lunar Orbit to an intermediate transfer trajectory whose aposelene radius coincides with the one of the target Highly Elliptical Orbit. The final insertion manoeuvre is then modelled as an ideal impulsive burn due to its limited dV magnitude. Parameters ---------- body : Primary Instance of `Primary` class describing the central attracting body sc : Spacecraft Instance of `Spacecraft` class describing the spacecraft characteristics alt : float Value of the final orbit altitude [m] rp : float Value for the target HEO periselene radius [m] t : float Value for the target HEO period [s] t_bounds : float Value for the time of flight bounds [-] method : str NLP transcription method nb_seg : int Number of segments for the transcription order : int Transcription order solver : str NLP solver snopt_opts : dict Sets some SNOPT's options. Default is ``None`` rec_file : str Directory path for the solution recording file. Default is ``None`` check_partials : bool Checking of partial derivatives. Default is ``False`` Attributes ---------- body : Primary Instance of `Primary` class describing the central attracting body sc : Spacecraft Instance of `Spacecraft` class describing the spacecraft characteristics phase_name : str Describes the phase name in case of multi-phase trajectories nlp : NLP Instance of `NLP` object describing the type of Non Linear Problem solver used tof : float Value of the time of flight resulting by the simulation [s] tof_exp : float Value of the time of flight of the explicit simulation [s] err : float Value of the error between the optimized simulation results and the explicit simulation results rm_res : float Value of the central body radius [- or m] states_scalers = ndarray Reference values of the states with which perform the scaling controls_scalers : ndarray Reference values of the controls with which perform the scaling alt : float Value of the final orbit altitude [m] phase_name : str Name assigned to the problem phase transfer : HohmannTransfer Instance of `HohmannTransfer` computing the keplerian parameters of the transfer orbit insertion_burn : ImpulsiveBurn Instance of `ImpulsiveBurn` defining the delta v required for an impulsive burn dv_dep : float Delta v required for a manoeuvre [m/s] """ def __init__(self, body, sc, alt, rp, t, t_bounds, method, nb_seg, order, solver, snopt_opts=None, rec_file=None, check_partials=False): """Initializes the `TwoDimLLO2ApoAnalyzer` class variables. """ TwoDimAscAnalyzer.__init__(self, body, sc, alt) self.nlp = TwoDimLLO2ApoNLP(body, sc, alt, rp, t, (-np.pi / 2, np.pi / 2), t_bounds, method, nb_seg, order, solver, self.phase_name, snopt_opts=snopt_opts, rec_file=rec_file, check_partials=check_partials) self.transfer = self.insertion_burn = self.dv_dep = None self.guess = self.nlp.guess # save the initial initial guess at analyzer level def compute_solution(self, nb=200): """Retrieves the optimization results and computes the spacecraft states along the ballistic arc as well as the final insertion burn. Parameters ---------- nb : int, optional Number of points in which the spacecraft states along the ballistic arc are computed. Default is ``200`` """ # states and COEs at the end of the departure burn states_end = self.states[-1] a, e, h, ta = TwoDimOrb.polar2coe(self.gm_res, states_end[0], states_end[2], states_end[3]) # coasting orbit in dimensional units if np.isclose(self.gm_res, 1.0): self.transfer = TwoDimOrb(self.body.GM, a=a * self.body.R, e=e) else: self.transfer = TwoDimOrb(self.body.GM, a=a, e=e) # finite dV at departure [m/s] self.dv_dep = ImpulsiveBurn.tsiolkovsky_dv(self.sc.m0, states_end[-1], self.sc.Isp) # impulsive dV at arrival [m/s] sc = deepcopy(self.sc) sc.m0 = states_end[-1] self.insertion_burn = ImpulsiveBurn( sc, self.guess.ht.arrOrb.va - self.transfer.va) # time and states along transfer orbit t, states = TwoDimOrb.propagate(self.gm_res, a, e, ta, np.pi, nb) # adjust time t_pow_end = self.time[-1, -1] t_coast_start = t[0, 0] t_coast_end = t[-1, 0] tof_coast = t_coast_end - t_coast_start self.tof = [self.tof, tof_coast] self.time = [self.time, (t - t_coast_start) + t_pow_end] # add mass m = np.vstack((states_end[-1] * np.ones( (len(t) - 1, 1)), [self.insertion_burn.mf])) states = np.hstack((states, m)) # stack states and controls self.states = [self.states, states] self.controls = [self.controls, np.zeros((len(t), 2))] self.controls[-1][-1, 0] = self.controls[0][0, 0] # adjust theta dtheta = ta - self.states[0][-1, 1] self.states[0][:, 1] = self.states[0][:, 1] + dtheta if self.states_exp is not None: self.states_exp[:, 1] = self.states_exp[:, 1] + dtheta def get_solutions(self, explicit=True, scaled=False, nb=200): """Access the simulation solution. Parameters ---------- explicit : bool Computes also the explicit simulation. Default is ``True`` scaled : bool Scales the simulation results. Default is ``False`` nb : int Number of points where the coasting arch is computed """ TwoDimAscAnalyzer.get_solutions(self, explicit=explicit, scaled=scaled) self.compute_solution(nb=nb) def plot(self): """Plots the states and controls resulting from the simulation and the ones from the explicit computation in time. The semi-major axis and the eccentricity of the HEO are also displayed. """ states_plot = TwoDimStatesTimeSeries(self.rm_res, self.time[0], self.states[0], self.time_exp, self.states_exp) if np.isclose(self.rm_res, 1.0): controls_plot = TwoDimControlsTimeSeries(self.time[0], self.controls[0], units=('-', '-'), threshold=None) else: controls_plot = TwoDimControlsTimeSeries(self.time[0], self.controls[0], threshold=None) sol_plot = TwoDimMultiPhaseSolPlot(self.rm_res, self.time, self.states, self.controls, self.time_exp, self.states_exp, a=self.guess.ht.arrOrb.a * (self.rm_res / self.body.R), e=self.guess.ht.arrOrb.e) states_plot.plot() controls_plot.plot() sol_plot.plot() def __str__(self): """Prints info on the `TwoDimLLO2ApoAnalyzer`. Returns ------- s : str Info on `TwoDimLLO2ApoAnalyzer` """ if np.isclose(self.gm_res, 1.0): time_scaler = self.body.tc else: time_scaler = 1.0 lines = [ '\n{:^50s}'.format('2D Transfer trajectory from LLO to HEO:'), self.guess.__str__(), '\n{:^50s}'.format('Optimal coasting phase:'), self.transfer.__str__(), '\n{:^50s}'.format('Optimal powered phases:'), '\n{:<25s}{:>20.6f}{:>5s}'.format( 'Propellant fraction:', 1 - self.insertion_burn.mf / self.sc.m0, ''), '{:<25s}{:>20.6f}{:>5s}'.format( 'Time of flight:', sum(self.tof) * time_scaler / 86400, 'days'), '\n{:^50s}'.format('Departure burn:'), '\n{:<25s}{:>20.6f}{:>5s}'.format('Impulsive dV:', self.guess.pow.dv_inf, 'm/s'), '{:<25s}{:>20.6f}{:>5s}'.format('Finite dV:', self.dv_dep, 'm/s'), '{:<25s}{:>20.6f}{:>5s}'.format('Burn time:', self.tof[0] * time_scaler, 's'), '{:<25s}{:>20.6f}{:>5s}'.format( 'Propellant fraction:', 1 - self.states[0][-1, -1] / self.sc.m0, ''), '\n{:^50s}'.format('Injection burn:'), '\n{:<25s}{:>20.6f}{:>5s}'.format('Impulsive dV:', self.insertion_burn.dv, 'm/s'), '{:<25s}{:>20.6f}{:>5s}'.format( 'Propellant fraction:', self.insertion_burn.dm / self.sc.m0, ''), TwoDimAnalyzer.__str__(self) ] s = '\n'.join(lines) return s
def sampling(self, body, isp_lim, twr_lim, alt, alt_p, alt_switch, theta, tof, t_bounds, method, nb_seg, order, solver, nb_samp, samp_method='lhs', criterion='m', snopt_opts=None): """Compute a new set of training data starting from a given sampling grid. Parameters ---------- body : Primary Central attracting body isp_lim : iterable Specific impulse lower and upper limits [s] twr_lim : iterable Thrust/weight ratio lower and upper limits [-] alt : float Orbit altitude [m] alt_p : float Periapsis altitude where the final powered descent is initiated [m] alt_switch : float Altitude at which the final vertical descent is triggered [m] theta : float Guessed spawn angle [rad] tof : iterable Guessed time of flight for the two phases [s] t_bounds : iterable Time of flight lower and upper bounds expressed as fraction of `tof` 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 iterable Number of segments in which each phase is discretized order : int or iterable Transcription order within each phase, must be odd solver : str NLP solver, must be supported by OpenMDAO nb_samp : iterable Total number of sampling points samp_method : str, optional Sampling scheme, ``lhs`` for Latin Hypercube Sampling or ``full`` for Full-Factorial Sampling. Default is ``lhs`` criterion : str, optional Criterion used to construct the LHS design among ``center``, ``maximin``, ``centermaximin``, ``correlation``, ``c``, ``m``, ``cm``, ``corr``, ``ese``. ``c``, ``m``, ``cm`` and ``corr`` are abbreviations of ``center``, ``maximin``, ``centermaximin`` and ``correlation``, ``respectively``. Default is ``m`` snopt_opts : dict or None, optional SNOPT optional settings expressed as key-value pairs. Default is None """ self.compute_grid(isp_lim, twr_lim, nb_samp, samp_method=samp_method, criterion=criterion) ht = HohmannTransfer(body.GM, TwoDimOrb(body.GM, a=(body.R + alt), e=0.0), TwoDimOrb(body.GM, a=(body.R + alt_p), e=0.0)) for i in range(nb_samp): sc = Spacecraft(self.x_samp[i, 0], self.x_samp[i, 1], g=body.g) deorbit_burn = ImpulsiveBurn(sc, ht.dva) nlp = TwoDimDescTwoPhasesNLP(body, deorbit_burn.sc, alt, alt_switch, ht.transfer.vp, theta, (0.0, np.pi), tof, t_bounds, method, nb_seg, order, solver, ('free', 'vertical'), snopt_opts=snopt_opts) self.m_prop[i, 0], self.failures[i, 0] = self.solve(nlp, i)
def solve(body, sc, alt, t_bounds, method, nb_seg, order, solver, snopt_opts=None, u_bound=None, **kwargs): """Solve the NLP for the i-th `twr` and k-th `Isp` values. Parameters ---------- body : Primary Central attracting body sc : Spacecraft Spacecraft object characterized by the i-th `twr` and k-th `Isp` values alt : float Orbit altitude [m] t_bounds : iterable Time of flight lower and upper bounds expressed as fraction of `tof` 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 Number of segments in which the phase is discretized order : int Transcription order within the 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. Default is None u_bound : str, optional Specify the bounds on the radial velocity along the transfer as ``lower``, ``upper`` or ``None``. Default is ``None`` Other Parameters ---------------- alt_p : float Periapsis altitude where the final powered descent is initiated [m] theta : float Guessed spawn angle [rad] tof : float Guessed time of flight [s] Returns ------- m_prop : float Propellant fraction [-] f : bool Failure status """ if 'alt_p' in kwargs: alt_p = kwargs['alt_p'] else: alt_p = alt dep = TwoDimOrb(body.GM, a=(body.R + alt), e=0.0) arr = TwoDimOrb(body.GM, a=(body.R + alt_p), e=0.0) ht = HohmannTransfer(body.GM, dep, arr) deorbit_burn = ImpulsiveBurn(sc, ht.dva) nlp = TwoDimDescConstNLP(body, deorbit_burn.sc, alt_p, ht.transfer.vp, kwargs['theta'], (0.0, 1.5 * np.pi), kwargs['tof'], t_bounds, method, nb_seg, order, solver, 'powered', snopt_opts=snopt_opts, u_bound=u_bound) f = nlp.p.run_driver() nlp.cleanup() m_prop = 1. - nlp.p.get_val(nlp.phase_name + '.timeseries.states:m')[-1, -1] return m_prop, f