class Placement: def __init__(self, pid, fp): self.pid = pid self.fp = FlightPlan(fp) def compareTo(self, other): return (self.pid > other.pid) - (self.pid < other.pid) def setFp(self, fp): if fp == None: raise AssertionError("FlightPlan can't be None!") self.fp = FlightPlan(fp) def getPid(self): return self.pid def getFp(self): return self.fp def addFlight(self, f): return self.fp.addFlight(f) def size(self): return self.fp.size() def get(self, index): return self.fp.get(index)
def partitionToPlacements(self, allFlights): pHash = dict() for f in allFlights: if f.getPlacementToken() in pHash.keys(): p = pHash[f.getPlacementToken()] p.addFlight(f) else: nfp = FlightPlan([]) pHash.update({ f.getPlacementToken(): Placement.Placement(f.getPlacementToken(), nfp) }) nfp.addFlight(f) return list(pHash.values())
def test_case1(cls): fuel = 35000 oxidizer = 85000 flight_plan = FlightPlan() flight_plan.add_step(1, velocity=0.25) flight_plan.add_step(10, velocity=0.25, velocity_variance=0.01) flight_plan.add_step(150, velocity=-0.25) flight_plan.add_step(280, velocity=-0.1) flight_plan.add_step(290, velocity=-0.1, velocity_variance=0.01) flight_plan.add_step(420, velocity=-0.1) flight_plan.add_step(445, velocity=0.0, height=0.0, velocity_variance=0.0, height_variance=0.0) return flight_plan, fuel, oxidizer
def test_case1(cls): fuel = 35000 flight_plan = FlightPlan() flight_plan.add_step(1, velocity=0.25) flight_plan.add_step(10, velocity=0.25, velocity_variance=0.01) flight_plan.add_step(100, velocity=0.5, height=25, height_variance=5.0) flight_plan.add_step(110, velocity=0.5, velocity_variance=0.01) flight_plan.add_step(150, velocity=-0.5) flight_plan.add_step(180, height=50, height_variance=5.0) flight_plan.add_step(355, velocity=-0.1) flight_plan.add_step(360, velocity=-0.1, velocity_variance=0.01) flight_plan.add_step(380, velocity=-0.1) flight_plan.add_step(400, velocity=0.0, height=0.0, velocity_variance=0.0, height_variance=0.0) return flight_plan, fuel
def __init__(self, pid, fp): self.pid = pid self.fp = FlightPlan(fp)
def setFp(self, fp): if fp == None: raise AssertionError("FlightPlan can't be None!") self.fp = FlightPlan(fp)
def launch_rocket( self, flight_plan: FlightPlan, fuel: int, oxidizer: int, bipropellant_pid_solution: Callable, optional_data: Optional[Dict] = None ) -> Tuple[float, float, float, str]: """ Launch rocket to attempt to fly optimal flight path Args: flight_plan: Flight plan of rocket fuel: Fuel load in kg oxidizer: Oxidizer load in kg bipropellant_pid_solution: Rocket PID function to control launch optional_data: Optional params to be passed to the pd solution Returns: Final grade, Output of launch """ output = '' # fuel load in kg init_fuel = 35000 # oxidizer load in kg init_oxidizer = 85000 # initial velocity level (height = 0 at base) in km/2 init_velocity = 0 # initial engine position (shutoff = 0, max thrust = 1) in percent # kerosene RG-1 consumption in kg/s fuel_consumption = 480 # oxidizer consumption in kg/s oxidizer_consumption = 480 oxidizer_fuel_ratio = 2.77 # status indicator for landing landed = 0 # status indicator for fuel tank fuel_empty = False oxidizer_empty = False # status indicator for successful landing good_landing = 0 delta_t = self.time_final // (self.total_steps - 1) time = np.linspace(0, self.time_final, self.total_steps) throttle_set = np.zeros(self.total_steps) velocity_log = np.zeros(self.total_steps) optimal_velocity_log = np.zeros(self.total_steps) height = np.zeros(self.total_steps) fuel_level = np.zeros(self.total_steps) oxidizer_level = np.zeros(self.total_steps) # Initialize data data = {'ErrorP': 0, 'ErrorI': 0, 'ErrorD': 0} if optional_data: data.update(optional_data) # Rocket Altitude ODE solver for time_step in range(len(time) - 1): if landed > 0: break (optimal_velocity, is_velocity_mandatory, desired_height, is_height_mandatory) = flight_plan.get_current_values(time_step) fuel_throttle, oxidizer_throttle, data = bipropellant_pid_solution( delta_t, velocity_log[time_step], optimal_velocity, data) fuel_throttle = effective_fuel_throttle = max( 0, min(1, fuel_throttle)) oxidizer_throttle = effective_oxidizer_throttle = max( 0, min(1, oxidizer_throttle)) # Check for oxidizer : fuel ratio if fuel_throttle != 0: current_oxidizer_fuel_ratio = oxidizer_consumption * oxidizer_throttle / ( fuel_consumption * fuel_throttle) # oxidizer is less, so use fuel according to oxidizer if current_oxidizer_fuel_ratio < oxidizer_fuel_ratio - 0.1: effective_fuel_throttle = max( 0.0, min(1.0, current_oxidizer_fuel_ratio)) # oxidizer is more, so use oxidizer according to fuel elif current_oxidizer_fuel_ratio > oxidizer_fuel_ratio + 0.1: effective_oxidizer_throttle = (oxidizer_fuel_ratio * fuel_consumption * fuel_throttle / oxidizer_consumption) else: effective_oxidizer_throttle = 0 effective_fuel_throttle = 0 # simulate air density drop with altitude self.rho = 1225000000 * np.exp(-height[time_step] / 1000) # shutoff engines if fuel empty if fuel_empty: output += 'The bi-propellant rocket ran out of fuel!\n' effective_fuel_throttle = 0 effective_oxidizer_throttle = 0 if oxidizer_empty: output += 'The bi-propellant rocket ran out of oxidizer!\n' effective_fuel_throttle = 0 effective_oxidizer_throttle = 0 # ODE solver to simulate rocket velocity change rocket_velocity = odeint(self.rocket, init_velocity, [time[time_step], time[time_step + 1]], args=(time_step, effective_fuel_throttle, effective_oxidizer_throttle, init_fuel, init_oxidizer)) # update velocity with ODE value init_velocity = rocket_velocity[1][0] # log current velocity velocity_log[time_step + 1] = init_velocity # log throttle throttle_set[time_step + 1] = fuel_throttle # reduce fuel per consumption rate init_fuel = init_fuel - fuel_consumption * fuel_throttle init_oxidizer = init_oxidizer - oxidizer_consumption * oxidizer_throttle # log optimal velocity optimal_velocity_log[time_step + 1] = optimal_velocity # Altitude and Fuel Checks if height[time_step] < 0 and abs(init_velocity) > 0.11: height[time_step + 1] = 0 landed = time_step output += 'The bi-propellant rocket CRASHED!\n' elif height[time_step] < 0 and abs( init_velocity) <= 0.11 and time_step > 10: height[time_step + 1] = 0 landed = time_step good_landing = True output += 'The bi-propellant rocket landed safely!\n' elif height[time_step] >= 0: height[time_step + 1] = height[time_step] + init_velocity * delta_t if fuel_empty: fuel_level[time_step + 1] = 0 if oxidizer_empty: oxidizer_level[time_step + 1] = 0 elif init_fuel < 0: fuel_level[time_step + 1] = 0 fuel_empty = True elif init_oxidizer < 0: oxidizer_level[time_step + 1] = 0 oxidizer_empty = True else: oxidizer_level[time_step + 1] = init_oxidizer fuel_level[time_step + 1] = init_fuel # Plotting for testing purposes if SHOW_GRAPH: try: graph = flight_graph("Bipropellant rocket launch", 800, 600, 6) sub_data_0 = [{ 'x': time, 'y': optimal_velocity_log, 'color': "#008888", 'label': "Optimum velocity" }, { 'x': time, 'y': velocity_log, 'color': "#0000ff", 'label': "Current velocity" }] graph.add_plot("Velocity (km/s)", sub_data_0) sub_data_1 = [{ 'x': (0, self.time_final), 'y': (1, 1), 'color': "#880088", 'label': "Maximum thrust" }, { 'x': time, 'y': throttle_set, 'color': "#ff0000", 'label': "Current throttle" }] graph.add_plot("Throttle (%)", sub_data_1) sub_data_2 = [{ 'x': time, 'y': height, 'color': "#008800", 'label': "Current height" }] graph.add_plot("Height (km)", sub_data_2) sub_data_3 = [{ 'x': time, 'y': fuel_level, 'color': "#888800", 'label': "Current fuel" }] graph.add_plot("Fuel (kg)", sub_data_3) sub_data_4 = [{ 'x': time, 'y': oxidizer_level, 'color': "#888800", 'label': "Current oxidizer" }] graph.add_plot("Oxidizer (kg)", sub_data_4) sub_data_5 = [{ 'x': time, 'y': self.thrust, 'color': "#0000ff", 'label': "Thrust" }, { 'x': time, 'y': self.gravity, 'color': "#008800", 'label': "Gravity" }, { 'x': time, 'y': self.drag, 'color': "#ff0000", 'label': "Drag" }] graph.add_plot("Force (N)", sub_data_5) graph.done() except Exception as exp: import traceback output += 'Error with plotting results:' + str(exp) output += traceback.format_exc() output += '\n' # Score for following optimal course scored_time_steps = 0 scored_height_steps = 0 student_velocity_score = 0 student_height_score = 0 total_time = flight_plan.get_plan_length() for time_step in range(0, total_time + 1): (expected_velocity, allowed_velocity_variance, expected_height, allowed_height_variance ) = flight_plan.get_current_values(time_step) if allowed_velocity_variance is not None: scored_time_steps += 1 lower_velocity = expected_velocity - allowed_velocity_variance upper_velocity = expected_velocity + allowed_velocity_variance if lower_velocity <= velocity_log[time_step] <= upper_velocity: student_velocity_score += 1 else: print( f'Velocity not met at time step: {time_step} ::: ' + f'{lower_velocity} <= {velocity_log[time_step]} <= {upper_velocity}' ) if allowed_height_variance is not None: scored_height_steps += 1 lower_height = expected_height - allowed_height_variance upper_height = expected_height + allowed_height_variance if lower_height <= height[time_step] <= upper_height: student_height_score += 1 else: print( f'Height not met at time step: {time_step} ::: ' + f'{lower_height} <= {height[time_step]} <= {upper_height}' ) student_score = student_velocity_score + student_height_score expected_score = scored_time_steps + scored_height_steps flight_score = student_score / expected_score * BIPROP_FLIGHT_SCORE # Score for making a successful landing if good_landing: landing_score = BIPROP_LAND_SCORE else: landing_score = 0 rocket_score = min(flight_score + landing_score, BIPROP_FLIGHT_SCORE + BIPROP_LAND_SCORE) return rocket_score, landing_score, flight_score, output