def changeReferenceFrame(): # From Howard Curtis: pg218 # For a given earth orbit, the elements are h 1⁄4 80,000 km 2 /s, e 1⁄4 1.4, i 1⁄4 30 , U 1⁄4 40 , u 1⁄4 60 , and q 1⁄4 30 . # Using Algorithm 4.5, find the state vectors r and v in the geocentric equatorial frame. h = 80000 * 1e6 #m^2/s e = 1.4 i = AL_BF.deg2rad(30) RAAN = AL_BF.deg2rad(40) omega = AL_BF.deg2rad(60) theta = AL_BF.deg2rad(30) # rv in perifocal r_norm = h**2/Cts.mu_E_m / (1+e*np.cos(theta)) r = r_norm* np.array([np.cos(theta), np.sin(theta),0]) v = Cts.mu_E_m / h * np.array([-np.sin(theta), e+ np.cos(theta),0]) print(r, v) # Validated # r, v in geocentric Frame1 = AL_Eph.FramesOfReference([omega, i, RAAN], 'perif') r2 = Frame1.transform(r, 'helioc') v2 = Frame1.transform(v, 'helioc') print(r2, v2) # Validated # Back to perifocal r3 = Frame1.transform(r2, 'perif') v3 = Frame1.transform(v2, 'perif') print(r3, v3) # Validated: same as initial
def objFunction(self, Error, m_fuel=False, typeError='vec'): if typeError == 'vec': fc1 = np.linalg.norm(Error[0:3] / AL_BF.AU) # Normalize with AU fc2 = np.linalg.norm(Error[3:] / AL_BF.AU * AL_BF.year2sec(1)) fc1_SI = np.linalg.norm(Error[0:3]) fc2_SI = np.linalg.norm(Error[3:]) else: fc1 = Error[0] / AL_BF.AU fc2 = Error[1] / AL_BF.AU * AL_BF.year2sec(1) fc1_SI = fc1 fc2_SI = fc2 self.Epnorm_norm = fc1 self.Evnorm_norm = fc2 self.Epnorm = fc1_SI self.Evnorm = fc2_SI factor_pos = CONF['FEASIB']['factor_pos'] factor_vel = CONF['FEASIB']['factor_vel'] factor_mass = CONF['FEASIB']['factor_mass'] # if CONF['FEASIB']['log'] == 1: # fc1 = np.log10(fc1) # fc2 = np.log10(fc2) # factor_pos = np.log10(factor_pos) # factor_vel = np.log10(factor_vel) # print('------------------------') # print(m_fuel, Error) # print(fc1, fc2) if type(m_fuel) == bool: value = fc1 * factor_pos + \ fc2 * factor_vel else: fc0 = m_fuel / self.Spacecraft.m_dry # else: res = [fc0, fc1, fc2] res2 = [fc0, fc1_SI, fc2_SI] # print(res) # print('###################') # print(fc1,factor_pos*fc1) # print(fc2, factor_vel*fc2) # print(fc0, factor_mass*fc0) # print(res) value = res[0]* factor_mass +\ res[1]* factor_pos + \ res[2]* factor_vel # Has to be in AU for the coeff to work in balance return value
def test_convertAngleForm(): vector0 = np.array([90,0,0]) vector1 = AL_BF.convert3dvector(vector0, "cartesian") print(vector1) # validated vector0 = np.array([90,90,90]) vector1 = AL_BF.convert3dvector(vector0, "cartesian") print(vector1) # validated vector0 = np.array([155, 0.78, 0.61]) vector1 = AL_BF.convert3dvector(vector0, "polar") print(vector1) # validated print(np.arcsin(-0.7071067811865475)) vector0 = np.array([-90,-90,-90]) vector1 = AL_BF.convert3dvector(vector0, "cartesian") print(vector1*AL_BF.rad2deg(1))
def to_helioc(r, vx, vy): v_body = np.array([vx, vy, 0]) # Convert to heliocentric angle = np.arctan2(r[1], r[0]) v_h = AL_BF.rot_matrix(v_body, angle, 'z') return v_h
def plot_tvsT(self): t = np.linspace(self.t0, self.t0 + AL_BF.sec2days(self.t_t), num=self.Nimp + 2) deltaV_i = [ np.linalg.norm(self.DeltaV_list[i, :]) * self.DeltaV_max for i in range(len(self.DeltaV_list[:, 0])) ] deltaV = np.zeros(self.Nimp + 2) deltaV[1:-1] = deltaV_i fig, ax = plt.subplots() plt.plot(t, deltaV, 'o-', color='k') plt.title("Epoch vs Delta V") plt.ylabel("Delta V (m/s)") plt.xlabel("JD0 (days)") plt.grid(alpha=0.5) # AL_Plot.set_axes_equal(ax) dpi = 200 layoutSave = 'tight' plt.savefig('OptSol/tvsT.png', dpi=dpi, bbox_inches=layoutSave) plt.show()
def propagateLambert(): ### Using ephemeris # Lambert trajectory obtain terminal velocity vectors date0 = np.array([27,1,2016,0]) t_0 = AL_Eph.DateConv(date0,'calendar') #To JD transfertime = 250 # Create bodies sun = AL_2BP.Body('sun', 'yellow', mu = Cts.mu_S_m) earth = AL_2BP.Body('earth', 'blue', mu = Cts.mu_E_m) mars = AL_2BP.Body('mars', 'red', mu = Cts.mu_M_m) # Calculate trajectory of the bodies based on ephem earthephem = pk.planet.jpl_lp('earth') marsephem = pk.planet.jpl_lp('mars') r_E, v_E = earthephem.eph(t_0.JD_0) r_M, v_M = marsephem.eph(t_0.JD_0 + transfertime) orbit_E = AL_2BP.BodyOrbit(np.append(r_E, v_E), 'Cartesian', sun) earth.addOrbit(orbit_E) orbit_M = AL_2BP.BodyOrbit(np.append(r_M, v_M), 'Cartesian', sun) mars.addOrbit(orbit_M) # Create transfer in the first moment lambert = AL_TR.Lambert(np.array(r_E), np.array(r_M), AL_BF.days2sec(transfertime), sun.mu) v_0, v_f = lambert.TerminalVelVect() print(v_0) # Propagate orbit_sp = AL_2BP.BodyOrbit(np.append(r_E, v_0), 'Cartesian', sun) x = orbit_sp.Propagation(AL_BF.days2sec(transfertime), 'Cartesian') # Coordinates after propagation r0 = np.array(r_E) rf = np.array(r_M) print('Mars', r_M, 'Propagation', x, 'Error', abs(rf - x[0:3])) # Almost zero fig = plt.figure() ax = fig.gca(projection = '3d') ax.scatter(0,0,0, color = 'yellow', s = 100) ax.scatter(r0[0],r0[1],r0[2], color = 'blue') ax.scatter(rf[0],rf[1],rf[2], color = 'red') ax.scatter(x[0], x[1], x[2], color = 'green') AL_Plot.set_axes_equal(ax) plt.show() # Validated
def findValidLambert(): SF = CONFIG.SimsFlan_config() earthephem = pk.planet.jpl_lp('earth') marsephem = pk.planet.jpl_lp('mars') counter = 0 valid = False while valid == False: decv = np.zeros(len(SF.bnds)) for i in range(6,8): decv[i] = np.random.uniform(low = SF.bnds[i][0], \ high = SF.bnds[i][1], size = 1) r_E, v_E = earthephem.eph(decv[6]) r_M, v_M = marsephem.eph(decv[6] + AL_BF.sec2days(decv[7]) ) # Create transfer in the first moment nrevs = 2 l = pk.lambert_problem(r1 = r_E, r2 = r_M, tof = decv[7], \ cw = False, mu = Cts.mu_S_m, max_revs=nrevs) v1 = np.array(l.get_v1()) v2 = np.array(l.get_v2()) v_i_prev = 1e12 # Excessive random value for rev in range(len(v1)): v_i = np.linalg.norm(v1[rev] - np.array(v_E)) # Relative velocities for the bounds v_i2 = np.linalg.norm(v2[rev] - np.array(v_M)) # Change to polar for the bounds if v_i >= SF.bnds[0][0] and v_i <= SF.bnds[0][1] and \ v_i2 >= SF.bnds[3][0] and v_i2 <= SF.bnds[3][1]: print('decv') print(v1[rev]-v_E,v2[rev]-v_M) decv[0:3] = AL_BF.convert3dvector(v1[rev]-v_E, "cartesian") decv[3:6] = AL_BF.convert3dvector(v2[rev]-v_M, "cartesian") print(decv[0:6]) valid = True print('rev', rev, v1[rev], v2[rev]) counter += 1 print(counter) return decv, l
def propagateSimsFlanagan(): "Test the propagation of SimsFlanagan back and forth using the velocities from Lambert" ### Using ephemeris # Lambert trajectory obtain terminal velocity vectors SF = CONFIG.SimsFlan_config() # Create bodies sun = AL_2BP.Body('sun', 'yellow', mu = Cts.mu_S_m) earth = AL_2BP.Body('earth', 'blue', mu = Cts.mu_E_m) mars = AL_2BP.Body('mars', 'red', mu = Cts.mu_M_m) # Calculate trajectory of the bodies based on ephem earthephem = pk.planet.jpl_lp('earth') marsephem = pk.planet.jpl_lp('mars') decv, l = findValidLambert() print(decv) Fit = Fitness(Nimp = SF.Nimp) Fit.calculateFitness(decv) Fit.printResult() # We plot mpl.rcParams['legend.fontsize'] = 10 # Create the figure and axis fig = plt.figure(figsize = (16,5)) ax1 = fig.add_subplot(1, 3, 1, projection='3d') ax1.scatter([0], [0], [0], color=['y']) ax2 = fig.add_subplot(1, 3, 2, projection='3d') ax2.scatter([0], [0], [0], color=['y']) ax2.view_init(90, 0) ax3 = fig.add_subplot(1, 3, 3, projection='3d') ax3.scatter([0], [0], [0], color=['y']) ax3.view_init(0,0) t1 = SF.t0.JD t2 = t1 + AL_BF.sec2days(decv[7]) for ax in [ax1, ax2, ax3]: # Plot the planet orbits # plot_planet(earth, t0=t1, color=(0.8, 0.8, 1), legend=True, units=AU, axes=ax) # plot_planet(mars, t0=t2, color=(0.8, 0.8, 1), legend=True, units=AU, axes=ax) # Plot the Lambert solutions axis = plot_lambert(l, color='b', legend=True, units=AU, axes=ax) # axis = plot_lambert(l, sol=1, color='g', legend=True, units=AU, axes=ax) # axis = plot_lambert(l, sol=2, color='g', legend=True, units=AU, axes=ax) plt.show()
def propagateSimsFlanaganForward(): "Test the propagation of SimsFlanagan forward using the velocities from Lambert" ### Using ephemeris # Lambert trajectory obtain terminal velocity vectors SF = CONFIG.SimsFlan_config() # Create bodies sun = AL_2BP.Body('sun', 'yellow', mu = Cts.mu_S_m) earth = AL_2BP.Body('earth', 'blue', mu = Cts.mu_E_m) mars = AL_2BP.Body('mars', 'red', mu = Cts.mu_M_m) # Calculate trajectory of the bodies based on ephem earthephem = pk.planet.jpl_lp('earth') marsephem = pk.planet.jpl_lp('mars') decv, l = findValidLambert() print(decv) r_M, v_M = marsephem.eph(decv[6] + AL_BF.sec2days(decv[7]) ) Fit = Propagate(Nimp = SF.Nimp) Fit.prop(decv, plot = True) print("Final", Fit.rv_final) print("Theoretical final", r_M, AL_BF.convert3dvector(decv[3:6], "polar")+v_M)
def __init__(self, *args, **kwargs): #Constants used Cts = AL_BF.ConstantsBook() #Constants for planets # Define bodies involved self.Spacecraft = AL_2BP.Spacecraft() self.earthephem = pk.planet.jpl_lp('earth') self.marsephem = pk.planet.jpl_lp('mars') self.jupiterephem = pk.planet.jpl_lp('jupiter') self.venusephem = pk.planet.jpl_lp('venus') self.sun = AL_2BP.Body('Sun', 'yellow', mu=Cts.mu_S_m) self.earth = AL_2BP.Body('Earth', 'blue', mu=Cts.mu_E_m) self.mars = AL_2BP.Body('Mars', 'red', mu=Cts.mu_M_m) self.jupiter = AL_2BP.Body('Jupiter', 'green', mu=Cts.mu_J_m) self.venus = AL_2BP.Body('Venus', 'brown', mu=Cts.mu_V_m) departure = kwargs.get('departure', "Earth") arrival = kwargs.get('arrival', "Mars") if departure == 'Earth': self.departure = self.earth self.departureephem = self.earthephem elif departure == 'Mars': self.departure = self.mars self.departureephem = self.marsephem if arrival == 'Mars': self.arrival = self.mars self.arrivalephem = self.marsephem elif arrival == 'Jupiter': self.arrival = self.jupiter self.arrivalephem = self.jupiterephem elif arrival == 'Venus': self.arrival = self.venus self.arrivalephem = self.venusephem elif arrival == 'Earth': self.arrival = self.earth self.arrivalephem = self.earthephem # Settings self.color = ['blue', 'green', 'black', 'red', 'yellow', 'orange'] # Choose odd number to compare easily in middle point self.Nimp = kwargs.get('Nimp', 11)
def EvolAlgorithm_cons(f, bounds, *args, **kwargs): """ EvolAlgorithm: evolutionary algorithm INPUTS: f: function to be analyzed x: decision variables bounds: bounds of x to initialize the random function x_add: additional parameters for the function. As a vector ind: number of individuals. cuts: number of cuts to the variable tol: tolerance for convergence max_iter: maximum number of iterations (generations) max_iter_success elitism: percentage of population elitism mut: mutation rate immig: migration rate (new individuals) cons: list of functions to constrain a function. Function should return a vector. return[0] = 0 if unfeasible, return[1] returns penalty """ x_add = kwargs.get('x_add', False) ind = kwargs.get('ind', 100) cuts = kwargs.get('cuts', 1) tol = kwargs.get('tol', 1e-4) max_iter = kwargs.get('max_iter', 1e3) max_iter_success = kwargs.get('max_iter_success', 1e2) elitism = kwargs.get('elitism', 0.1) mut = kwargs.get('mutation', 0.01) immig = kwargs.get('immig', 0.01) cons = kwargs.get('cons', None) ############################################### ###### GENERATION OF INITIAL POPULATION ####### ############################################### pop_0 = np.zeros([ind, len(bounds) + 1]) for i in range(len(bounds)): pop_0[:, i + 1] = np.random.rand(ind) * (bounds[i][1] - bounds[i][0]) + bounds[i][0] ############################################### ###### FITNESS EVALUATION ####### ############################################### if x_add == False: # No additional arguments needed for i in range(ind): pop_0[i, 0] = f(pop_0[i, 1:]) else: for i in range(ind): pop_0[i, 0] = f(pop_0[i, 1:], x_add) for j in range(ind): for i in range(len(cons)): feas = cons[i](pop_0[j, 1:]) # evaluate constraint function if feas[0] == 0: # it is unfeasible pop_0[:, 0] += feas[1] # Add penalty to unfeasible ones Sol = pop_0[pop_0[:, 0].argsort()] minVal = min(Sol[:, 0]) x_minVal = Sol[0, :] ############################################### ###### NEXT GENERATION ####### ############################################### noImprove = 0 counter = 0 lastMin = minVal Best = np.zeros([max_iter + 1, len(bounds) + 1]) while noImprove <= max_iter_success and counter <= max_iter: ############################################### #Generate descendents #Elitism ind_elit = int(round(elitism * ind)) children = np.zeros(np.shape(pop_0)) children[:, 1:] = Sol[:, 1:] #Separate into the number of parents pop = np.zeros(np.shape(pop_0)) pop[:ind_elit, :] = children[:ind_elit, :] #Keep best ones np.random.shuffle(children[:, :]) #shuffle the others for j in range((len(children) - ind_elit) // 2): if len(bounds) == 2: cut = 1 else: cut = np.random.randint(1, len(bounds) - 1) pop[ind_elit + 2 * j, 1:] = np.concatenate( (children[2 * j, 1:cut + 1], children[2 * j + 1, cut + 1:]), axis=0) pop[ind_elit + 2 * j + 1, 1:] = np.concatenate( (children[2 * j + 1, 1:cut + 1], children[2 * j, cut + 1:]), axis=0) if (len(children) - ind_elit) % 2 != 0: pop[-1, :] = children[-ind_elit, :] #Mutation for i in range(ind): for j in range(len(bounds)): if np.random.rand(1) < mut: #probability of mut pop[i, j + 1] = np.random.rand(1) * (bounds[j][1] - bounds[j][0]) + bounds[j][0] #Immigration ind_immig = int(round(immig * ind)) for i in range(len(bounds)): pop[-ind_immig:, i + 1] = np.random.rand(ind_immig) * (bounds[i][1] - bounds[i][0]) + bounds[i][0] ############################################### # Fitness if x_add == False: # No additional arguments needed for i in range(ind): pop[i, 0] = f(pop[i, 1:]) else: for i in range(ind): pop[i, 0] = f(pop[i, 1:], x_add) for j in range(ind): for i in range(len(cons)): feas = cons[i](pop[j, 1:]) # evaluate constraint function if feas[0] == 0: # it is unfeasible pop[:, 0] += feas[1] # Add penalty to unfeasible ones Sol = pop[pop[:, 0].argsort()] minVal = min(Sol[:, 0]) ############################################### #Check convergence if minVal >= lastMin: noImprove += 1 else: lastMin = minVal x_minVal = Sol[0, 1:] noImprove = 0 Best[counter, :] = Sol[0, :] print(counter, "Minimum: ", minVal) counter += 1 #Count generations if counter % 20 == 0: AL_BF.writeData(x_minVal, 'w', 'SolutionEA.txt') # print(counter) print("minimum:", lastMin) print("Iterations:", counter) print("Iterations with no improvement:", noImprove) return x_minVal, lastMin
def EvolAlgorithm_integerinput(f, bounds, *args, **kwargs): """ EvolAlgorithm_integerinput: evolutionary algorithm, some inputs will be fixed to integers if decided INPUTS: f: function to be analyzed x: decision variables bounds: bounds of x to initialize the random function x_add: additional parameters for the function. As a vector ind: number of individuals. cuts: number of cuts to the variable tol: tolerance for convergence max_iter: maximum number of iterations (generations) max_iter_success elitism: percentage of population elitism bulk_fitness: if True, the data has to be passed to the function all at once as a matrix with each row being an individual int_input: force some inputs to be integers. Vector with zero (not integer) or one if integer """ x_add = kwargs.get('x_add', False) ind = kwargs.get('ind', 100) cuts = kwargs.get('cuts', 1) tol = kwargs.get('tol', 1e-4) max_iter = kwargs.get('max_iter', 1e3) max_iter_success = kwargs.get('max_iter_success', 1e2) elitism = kwargs.get('elitism', 0.1) mut = kwargs.get('mutation', 0.01) bulk = kwargs.get('bulk_fitness', False) int_input = kwargs.get('int_input', np.zeros(len(bounds))) def f_evaluate(pop_0): if bulk == True: if x_add == False: pop_0[:, 0] = f(pop_0[:, 1:]) else: pop_0[:, 0] = f(pop_0[:, 1:], x_add) else: if x_add == False: # No additional arguments needed for i in range(ind): pop_0[i, 0] = f(pop_0[i, 1:]) else: for i in range(ind): pop_0[i, 0] = f(pop_0[i, 1:], x_add) return pop_0 ############################################### ###### GENERATION OF INITIAL POPULATION ####### ############################################### pop_0 = np.zeros([ind, len(bounds) + 1]) for i in range(len(bounds)): pop_0[:, i + 1] = np.random.uniform(low=bounds[i][0], high=bounds[i][1], size=ind) if int_input[i] != 0: # Force it to be an integer pop_0[:, i + 1] = [int(pop_0[indx, i + 1]) for indx in range(ind)] print(pop_0) ############################################### ###### FITNESS EVALUATION ####### ############################################### pop_0 = f_evaluate(pop_0) Sol = pop_0[pop_0[:, 0].argsort()] minVal = min(Sol[:, 0]) x_minVal = Sol[0, :] ############################################### ###### NEXT GENERATION ####### ############################################### noImprove = 0 counter = 0 lastMin = minVal Best = np.zeros([max_iter + 1, len(bounds) + 1]) while noImprove <= max_iter_success and counter <= max_iter: ############################################### #Generate descendents #Elitism ind_elit = int(round(elitism * ind)) children = np.zeros(np.shape(pop_0)) children[:, 1:] = Sol[:, 1:] #Separate into the number of parents pop = np.zeros(np.shape(pop_0)) pop[:ind_elit, :] = children[:ind_elit, :] #Keep best ones np.random.shuffle(children[:, :]) #shuffle the others for j in range((len(children) - ind_elit) // 2): if len(bounds) == 2: cut = 1 else: cut = np.random.randint(1, len(bounds) - 1) pop[ind_elit + 2 * j, 1:] = np.concatenate( (children[2 * j, 1:cut + 1], children[2 * j + 1, cut + 1:]), axis=0) pop[ind_elit + 2 * j + 1, 1:] = np.concatenate( (children[2 * j + 1, 1:cut + 1], children[2 * j, cut + 1:]), axis=0) if (len(children) - ind_elit) % 2 != 0: pop[-1, :] = children[-ind_elit, :] #Mutation for i in range(ind): for j in range(len(bounds)): if np.random.rand(1) < mut: #probability of mut pop[i, j + 1] = np.random.rand(1) * (bounds[j][1] - bounds[j][0]) + bounds[j][0] if int_input[i] != 0: # Force to be an int pop[i, j + 1] = int(pop[i, j + 1]) ############################################### # Fitness pop = f_evaluate(pop) Sol = pop[pop[:, 0].argsort()] minVal = min(Sol[:, 0]) ############################################### #Check convergence if minVal >= lastMin: noImprove += 1 # elif abs(lastMin-minVal)/lastMin > tol: # noImprove += 1 else: # print('here') lastMin = minVal x_minVal = Sol[0, 1:] noImprove = 0 Best[counter, :] = Sol[0, :] print(counter, "Minimum: ", minVal) counter += 1 #Count generations if counter % 20 == 0: AL_BF.writeData(x_minVal, 'w', 'SolutionEA.txt') # print(counter) print("minimum:", lastMin) print("Iterations:", counter) print("Iterations with no improvement:", noImprove) return x_minVal, lastMin
def test_convertRange(): angle = -3.02 print(AL_BF.convertRange(angle, 'deg', 0, 360))
def test_Exposin(): # Verify with example print("VERIFICATION") r1 = 1 r2 = 5 psi = np.pi/2 k2 = 1/4 # eSin = AL_Sh.shapingMethod(sun.mu / Cts.AU_m**3) # gammaOptim_v = eSin.start(r1, r2, psi, 365*1.5, k2) # verified # Ni = 1 # print(gammaOptim_v) # eSin.plot_sphere(r1, r2, psi, gammaOptim_v[Ni], Ni) # verified # Real life case sun = AL_2BP.Body('sun', 'yellow', mu = Cts.mu_S_m) earth = AL_2BP.Body('earth', 'blue', mu = Cts.mu_E_m) mars = AL_2BP.Body('mars', 'red', mu = Cts.mu_M_m) # Calculate trajectory of the bodies based on ephem earthephem = pk.planet.jpl_lp('earth') marsephem = pk.planet.jpl_lp('mars') date0 = np.array([27,1,2018,0]) t0 = AL_Eph.DateConv(date0,'calendar') #To JD t_t = 350 r_E, v_E = earthephem.eph( t0.JD_0 ) r_M, v_M = marsephem.eph(t0.JD_0+ t_t ) r_1 = r_E r_2 = r_M r_1_norm = np.linalg.norm( r_1 ) r_2_norm = np.linalg.norm( r_2 ) dot = np.dot(r_1[0:2], r_2[0:2]) # dot product between [x1, y1] and [x2, y2] det = r_1[0]*r_2[1] - r_2[0]*r_1[1] # determinant psi = np.arctan2(det, dot) psi = AL_BF.convertRange(psi, 'rad', 0 ,2*np.pi) k2 = 1/12 eSin = AL_Sh.shapingMethod(sun.mu / AL_BF.AU**3) gammaOptim_v = eSin.calculategamma1(r_1_norm / AL_BF.AU, r_2_norm / AL_BF.AU, psi, \ t_t, k2, plot = False) Ni = 1 eSin.calculateExposin(Ni, gammaOptim_v[Ni],r_1_norm / AL_BF.AU, r_2_norm / AL_BF.AU, psi ) eSin.plot_sphere(r_1_norm / AL_BF.AU, r_2_norm / AL_BF.AU, psi) v1, v2 = eSin.terminalVel(r_1_norm / AL_BF.AU, r_2_norm / AL_BF.AU, psi) t, a_T = eSin.calculateThrustProfile(r_1_norm / AL_BF.AU, r_2_norm / AL_BF.AU, psi) # print('a', a_T*AL_BF.AU) print("body coord", v1, v2) # print(v1[0]*Cts.AU_m, v1[1], v2[0]*Cts.AU_m, v2[1]) # To heliocentric coordinates (2d approximation) def to_helioc(r, vx, vy): v_body = np.array([vx, vy, 0]) # Convert to heliocentric angle = np.arctan2(r[1], r[0]) v_h = AL_BF.rot_matrix(v_body, angle, 'z') return v_h v_1 = to_helioc(r_1, v1[0]*AL_BF.AU, v1[1]*AL_BF.AU) v_2 = to_helioc(r_2, v2[0]*AL_BF.AU, v2[1]*AL_BF.AU) # def to_helioc(r, v, gamma): # v_body = np.array([v*np.sin(gamma), \ # v*np.cos(gamma),\ # 0]) # # Convert to heliocentric # angle = np.arctan2(r[1], r[0]) # v_h = AL_BF.rot_matrix(v_body, angle, 'z') # return v_h # v_1 = to_helioc(r_1, v1[0]*Cts.AU_m, v1[1]) # v_2 = to_helioc(r_2, v2[0]*Cts.AU_m, v2[1]) print("Helioc vel", v_1, v_2) print("with respect to body ", v_1-v_E, v_2-v_M) v_1_E = np.linalg.norm(v_1-v_E) v_2_M = np.linalg.norm(v_2-v_M) print("Final vel", v_1_E, v_2_M) ################################################3 # Propagate with terminal velocity vectors SF = CONFIG.SimsFlan_config() Fit = Fitness(Nimp = SF.Nimp) decv = np.zeros(len(SF.bnds)) decv[6] = t0.JD_0 decv[7] = AL_BF.days2sec(t_t) decv[0:3] = AL_BF.convert3dvector(v_1-v_E,'cartesian') decv[3:6] = AL_BF.convert3dvector(v_2- v_M,'cartesian') print('decv', decv[0:9]) for i in range(SF.Nimp): # Acceleration on segment is average of extreme accelerations t_i = AL_BF.days2sec(t_t) / (SF.Nimp+1) *i t_i1 = AL_BF.days2sec(t_t) / (SF.Nimp+1) *(i+1) #find acceleration at a certain time a_i = eSin.accelerationAtTime(t_i) a_i1 = eSin.accelerationAtTime(t_i1) a = (a_i+a_i1)/2 # find the acceleration at a certain time print("a", a_i, a_i1, a) deltav_i = AL_BF.days2sec(t_t) / (SF.Nimp+1) * a*AL_BF.AU print(deltav_i) decv[8+3*i] = deltav_i /100 decv[8+3*i+1] = 0 decv[8+3*i+2] = 0 Fit.calculateFeasibility(decv, plot = True, thrust = 'tangential') Fit.printResult()
def adaptDecisionVector(self, DecV, optMode=True): """ adaptDecisionVector: modify decision vector to input in the problem """ self.DecV = DecV v0 = np.array(DecV[0:3]) # vector, [magnitude, angle, angle] vf = np.array(DecV[3:6]) # vector, [magnitude, angle, angle] self.t0, self.t_t = DecV[6:8] # Delta V if optMode == True: DeltaV_list = np.array(DecV[8:]).reshape( -1, 3) # make a Nimp x 3 matrix else: DeltaV_list = DecV[8:][0] ######################################################################## # INITIAL CALCULATION OF VARIABLES ######################################################################## # Modify from magnitude angle angle to cartesian self.DeltaV_list = np.zeros(np.shape(DeltaV_list)) DeltaV_sum = np.zeros(len( self.DeltaV_list)) # Magnitude of the impulses for i in range(len(self.DeltaV_list)): self.DeltaV_list[i, :] = AL_BF.convert3dvector( DeltaV_list[i, :], "polar") DeltaV_sum[i] = np.linalg.norm(self.DeltaV_list[i]) # Write velocity as x,y,z vector v0_cart = AL_BF.convert3dvector(v0, "polar") vf_cart = AL_BF.convert3dvector(vf, "polar") # Sum of all the Delta V = DeltaV max * sum Delta V_list # Assumption: the DeltaV_max is calculated as if mass is constant and # equal to the dry mass as it is the largest contribution. This means # that the DelaV_max is actually smaller than it will be obtained in this # problem # = Thrust for segment self.DeltaV_max = self.Spacecraft.T / self.Spacecraft.m_dry * \ self.t_t / (self.Nimp + 1) # Total DeltaV DeltaV_total = sum(DeltaV_sum) * self.DeltaV_max #Calculate total mass of fuel for the given impulses self.m0 = \ self.Spacecraft.MassChangeInverse(self.Spacecraft.m_dry, DeltaV_total) self.m_fuel = self.m0 - self.Spacecraft.m_dry # Times and ephemeris # t_0 = AL_Eph.DateConv(self.date0,'calendar') #To JD self.t_1 = AL_Eph.DateConv(self.t0 + AL_BF.sec2days(self.t_t), 'JD_0') self.r_p0, self.v_p0 = self.departureephem.eph(self.t0) self.r_p1, self.v_p1 = self.arrivalephem.eph(self.t_1.JD_0) # Change from relative to heliocentric velocity self.v0 = v0_cart + self.v_p0 self.vf = vf_cart + self.v_p1 # Create state vector for initial and final point self.SV_0 = np.append(self.r_p0, self.v0) self.SV_f = np.append(self.r_p1, self.vf) # - to propagate backwards self.SV_f_corrected = np.append(self.r_p1, -self.vf) # - to propagate backwards
def validateSimsFlanagan(): SF = CONFIG.SimsFlan_config() # Create bodies sun = AL_2BP.Body('sun', 'yellow', mu = Cts.mu_S_m) earth = AL_2BP.Body('earth', 'blue', mu = Cts.mu_E_m) mars = AL_2BP.Body('mars', 'red', mu = Cts.mu_M_m) Spacecraft = AL_2BP.Spacecraft( ) # Calculate trajectory of the bodies based on ephem earthephem = pk.planet.jpl_lp('earth') marsephem = pk.planet.jpl_lp('mars') # Create a random decision vector DecV = np.zeros(len(SF.bnds)) samples_rand = 1 np.random.seed(1) for decv in range(len(SF.bnds)): DecV[decv] = np.random.rand(samples_rand) * (SF.bnds[decv][1]-SF.bnds[decv][0]) + SF.bnds[decv][0] DecV[8:] = np.zeros(3*SF.Nimp) Fit = Fitness(Nimp = 21) Fit.adaptDecisionVector(DecV) r = Fit.r_p0 r2 = Fit.r_p1 v = Fit.v0 v2 = Fit.vf imp = Fit.DeltaV_list.flatten() # imp = (0,0,0,0,0,0,0,0,0,0,0,0) m0 = Fit.m0 # Pykep Sims-Flanagan start = pk.epoch(DecV[6]) end = pk.epoch(DecV[6] + AL_BF.sec2days(DecV[7]) ) sc = pk.sims_flanagan.spacecraft(m0, Spacecraft.T, Spacecraft.Isp) x0 = pk.sims_flanagan.sc_state(r,v,sc.mass) xe = pk.sims_flanagan.sc_state(r2,v2,sc.mass) l = pk.sims_flanagan.leg(start, x0, imp, end, xe, sc,pk.MU_SUN) ceq = l.mismatch_constraints() c = l.throttles_constraints() times,r,v,m = l.get_states() r_vec = np.zeros((len(r),3)) for i in range(len(r)): r_vec[i, :] = r[i] plt.scatter(r[i][0], r[i][1], color = 'black') if i == 0: plt.scatter(r[i][0], r[i][1], color = 'blue') elif i == len(r)-1: plt.scatter(r[i][0], r[i][1], color = 'red') elif i == len(r)//2+1: plt.scatter(r[i][0], r[i][1], color = 'orange') elif i == len(r)//2: plt.scatter(r[i][0], r[i][1], color = 'green') # plt.show() # plt.plot(r_vec[:,0], r_vec[:,1]) plt.grid() print("State middle point") print(r[len(r)//2], v[len(r)//2]) print(r[len(r)//2+1], v[len(r)//2+1]) print("Mismatch middle point") mis_r = -(np.array(r[len(r)//2]) - np.array(r[len(r)//2+1])) mis_v = -(np.array(v[len(r)//2] )- np.array(v[len(r)//2+1])) print(mis_r, mis_v) mis = np.append(mis_r, mis_v) Fit = Fitness(Nimp = SF.Nimp) Fit.calculateFitness(DecV, plot=True) cep2 = Fit.Error # print(Fit.SV_0, Fit.SV_f) for i in range(6): print(i, ceq[i], '%.4E'%cep2[i], '%.4E'%mis[i])
from FitnessFunction import Fitness import AstroLibraries.AstroLib_Basic as AL_BF from AstroLibraries import AstroLib_2BP as AL_2BP from AstroLibraries import AstroLib_Ephem as AL_Eph from AstroLibraries import AstroLib_Plots as AL_Plot from AstroLibraries import AstroLib_Trajectories as AL_TR from AstroLibraries import AstroLib_ShapingMethod as AL_Sh import LoadConfigFiles as CONFIG # # In[] # ############################################## # ############# VALIDATION ##################### # ############################################## Cts = AL_BF.ConstantsBook() def pykepephem(): # earth = pk.planet.jpl_lp('earth') # marsephem = pk.planet.jpl_lp('mars') earth = pk.planet.jpl_lp('earth') K_0 = earth.eph(0) # print(K_0) earth.mu_central_body print(earth.mu_self) elem = earth.osculating_elements(pk.epoch(2345.3, 'mjd2000')) print(elem) print(np.array(elem))
def MonotonicBasinHopping(f, x, take_step, *args, **kwargs): """ Step for jump is small, as minimum cluster together. Jump from current min until n_no improve reaches the lim, then the jump is random again. """ niter = kwargs.get('niter', 100) niter_success = kwargs.get('niter_success', 50) niter_local = kwargs.get('niter_local', 50) bnds = kwargs.get('bnds', None) cons = kwargs.get('cons', 0) jumpMagnitude_default = kwargs.get( 'jumpMagnitude', 0.1) # Small jumps to search around the minimum tolLocal = kwargs.get('tolLocal', 1e2) tolGlobal = kwargs.get('tolGobal', 1e-5) n_itercounter = 1 n_noimprove = 0 Best = x bestMin = f(x) previousMin = f(x) jumpMagnitude = jumpMagnitude_default while n_itercounter < niter: n_itercounter += 1 # Change decision vector to find one within the bounds feasible = False while feasible == False and bnds != None: x_test = take_step.call(x, jumpMagnitude) feasible = check_feasibility(x_test, bnds) # if feasible == True: # feasible = check_constraints(x, cons) # Local optimization # solutionLocal = spy.minimize(f, x, method = 'COBYLA', constraints = cons, options = {'maxiter': niter_local} ) if type(cons) == int: solutionLocal = spy.minimize(f, x_test, method = 'SLSQP', \ tol = tolLocal, bounds = bnds, options = {'maxiter': niter_local} ) else: solutionLocal = spy.minimize(f, x_test, method = 'SLSQP', \ tol = tolLocal, bounds = bnds, options = {'maxiter': niter_local},\ constraints = cons ) currentMin = f(solutionLocal.x) feasible = check_feasibility(solutionLocal.x, bnds) # if feasible == True: # jump from current point even if it is not optimum # x = solutionLocal.x # Check te current point from which to jump: after doing a long jump or # when the solution is improved if jumpMagnitude == 1 or currentMin < previousMin: x = solutionLocal.x # Check improvement if currentMin < bestMin and feasible == True: # Improvement Best = x bestMin = currentMin accepted = True # If the improvement is not large, assume it is not improvement if (previousMin - currentMin) < tolGlobal: n_noimprove += 1 else: n_noimprove = 0 jumpMagnitude = jumpMagnitude_default elif n_noimprove == niter_success: # Not much improvement accepted = False jumpMagnitude = 1 n_noimprove = 0 # Restart count so that it performs jumps around a point else: accepted = False jumpMagnitude = jumpMagnitude_default n_noimprove += 1 previousMin = currentMin # Save results every 5 iter if n_itercounter % 20 == 0: AL_BF.writeData(Best, 'w', 'SolutionMBH_self.txt') print("iter", n_itercounter) print("Current min vs best one", currentMin, bestMin) print_fun(f, x, accepted) # Print solution # print_sol(Best, bestMin, n_itercounter, niter_success) return Best, bestMin
def MonotonicBasinHopping_batch(f, x, take_step, *args, **kwargs): """ Step for jump is small, as minimum cluster together. Jump from current min until n_no improve reaches the lim, then the jump is random again. """ f_batch = kwargs.get('f_batch', False) # Function allows for batch eval f_opt = kwargs.get('f_opt', None) # function to optimze locally nind = kwargs.get('nind', 100) niter = kwargs.get('niter', 100) niter_success = kwargs.get('niter_success', 50) bnds = kwargs.get('bnds', None) jumpMagnitude_default = kwargs.get( 'jumpMagnitude', 0.1) # Small jumps to search around the minimum tolGlobal = kwargs.get('tolGobal', 1e-5) niter_local = kwargs.get('niter_local', 50) tolLocal = kwargs.get('tolLocal', 1e2) n_itercounter = 1 n_noimprove = np.zeros((nind)) Best = x bestMin = seqEval(f, x) previousMin = seqEval(f, x) jumpMagnitude = np.ones((nind)) * jumpMagnitude_default accepted = np.zeros((nind)) feasibility = np.zeros((nind)) while n_itercounter < niter: n_itercounter += 1 # Change decision vector to find one within the bounds x_test = np.zeros(np.shape(x)) for ind in range(nind): feasible = False while feasible == False and bnds != None: x_test[ind] = take_step.call(x[ind], jumpMagnitude[ind]) feasible = check_feasibility(x_test[ind], bnds) # Local optimization if f_opt != None: currentMin = f_opt(x_test) solutionLocal = x_test else: currentMin = np.zeros((nind)) solutionLocal = np.zeros(np.shape(x)) for ind in range(nind): solLocal = spy.minimize(f, x_test[ind], method = 'SLSQP', \ tol = tolLocal, bounds = bnds, options = {'maxiter': niter_local} ) solutionLocal[ind] = solLocal.x feasibility[ind] = check_feasibility(solLocal.x, bnds) if feasibility[ind] == False: print("Warning: Point out of limits") currentMin = seqEval(f, solutionLocal) for ind in range(nind): # Check te current point from which to jump: after doing a long jump or # when the solution is improved if jumpMagnitude[ind] == 1 or currentMin[ind] < previousMin[ind]: x[ind] = solutionLocal[ind] # Check improvement if currentMin[ind] < bestMin[ind] and feasibility[ ind] == True: # Improvement Best[ind] = x[ind] bestMin[ind] = currentMin[ind] accepted[ind] = True # If the improvement is not large, assume it is not improvement if (previousMin[ind] - currentMin[ind]) < tolGlobal: n_noimprove[ind] += 1 else: n_noimprove[ind] = 0 jumpMagnitude[ind] = jumpMagnitude_default elif n_noimprove[ind] == niter_success: # Go to a bigger jump accepted[ind] = False jumpMagnitude[ind] = 1 n_noimprove[ ind] = 0 # Restart count so that it performs jumps around a point else: accepted[ind] = False jumpMagnitude[ind] = jumpMagnitude_default n_noimprove[ind] += 1 previousMin[ind] = currentMin[ind] # Save results every 5 iter if n_itercounter % 20 == 0: AL_BF.writeData(Best, 'w', './OptSol/allMBH_batch.txt') print("iter", n_itercounter) print("Current min vs best one", min(currentMin), min(bestMin)) print_fun(min(currentMin), min(bestMin), np.count_nonzero(accepted == True)) # Print solution # print_sol(Best, bestMin, n_itercounter, niter_success) return Best, bestMin
def DecV2inputV(self, typeinputs, newDecV=0): if type(newDecV) != int: self.adaptDecisionVector(newDecV) inputs = np.zeros(8) inputs[0] = self.t_t inputs[1] = self.m0 if typeinputs == "deltakeplerian": # Elements of the spacecraft earth_elem = AL_2BP.BodyOrbit(self.SV_0, "Cartesian", self.sun) elem_0 = earth_elem.KeplerElem mars_elem = AL_2BP.BodyOrbit(self.SV_f, "Cartesian", self.sun) elem_f = mars_elem.KeplerElem K_0 = np.array(elem_0) K_f = np.array(elem_f) # Mean anomaly to true anomaly K_0[-1] = AL_2BP.Kepler(K_0[-1], K_0[1], 'Mean')[0] K_f[-1] = AL_2BP.Kepler(K_f[-1], K_f[1], 'Mean')[0] inputs[2:] = K_f - K_0 inputs[2] = abs(inputs[2]) # absolute value inputs[3] = abs(inputs[3]) # absolute value inputs[4] = np.cos(inputs[4]) # cosine labels = [ r'$t_t$', r'$m_0$', r'$\vert \Delta a \vert$', r'$\vert \Delta e \vert$', r'$cos( \Delta i) $', r'$ \Delta \Omega$', r'$ \Delta \omega$', r'$ \Delta \theta$' ] elif typeinputs == "deltakeplerian_planet": t_1 = self.t0 + AL_BF.sec2days(self.t_t) # Elements of the planets elem_0 = self.departureephem.osculating_elements( pk.epoch(self.t0, 'mjd2000')) elem_f = self.arrivalephem.osculating_elements( pk.epoch(t_1, 'mjd2000')) K_0 = np.array(elem_0) K_f = np.array(elem_f) # Mean anomaly to true anomaly K_0[-1] = AL_2BP.Kepler(K_0[-1], K_0[1], 'Mean')[0] K_f[-1] = AL_2BP.Kepler(K_f[-1], K_f[1], 'Mean')[0] inputs[2:] = K_f - K_0 inputs[2] = abs(inputs[2]) # absolute value inputs[3] = abs(inputs[3]) # absolute value inputs[4] = np.cos(inputs[4]) # cosine labels = [ r'$t_t$', r'$m_0$', r'$\vert \Delta a \vert$', r'$\vert \Delta e \vert$', r'$cos( \Delta i) $', r'$ \Delta \Omega$', r'$ \Delta \omega$', r'$ \Delta \theta$' ] elif typeinputs == "cartesian": delta_r = np.array(self.SV_f[0:3]) - np.array(self.SV_0[0:3]) delta_v = np.array(self.SV_f[3:]) - np.array(self.SV_0[3:]) inputs[2:5] = np.abs(delta_r) inputs[5:] = np.abs(delta_v) labels = [ r'$t_t$', r'$m_0$', r'$\vert \Delta x \vert$', r'$\vert \Delta y \vert$', r'$\vert \Delta z \vert$', r'$\vert \Delta v_x \vert$', r'$\vert \Delta v_y \vert$', r'$\vert \Delta v_z \vert$' ] return inputs, labels