text: # Sweep to evaluate the sensitivity of each design to number of rotors
  
  import os
  import sys
  
  sys.path.append(os.path.abspath(os.path.dirname(__file__) + "/../../models"))
  
  import numpy as np
  from gpkit import Model, ureg
  from matplotlib import pyplot as plt
  from copy import deepcopy
  from aircraft_models import OnDemandAircraft
  from mission_models import (
      OnDemandSizingMission,
      OnDemandRevenueMission,
      OnDemandDeadheadMission,
  )
  from cost_models import OnDemandMissionCost
  from study_input_data import generic_data, configs
  from noise_models import vortex_noise
  
  config = deepcopy(configs)
  
  # Optimize remaining configurations
  for config in configs:
  
      print("Solving configuration: " + config)
  
      c = configs[config]
  
      # Parameter of interest
      if (config == "Helicopter") or (config == "Coaxial heli"):
          N_values = np.array([1, 2])
      elif (config == "Compound heli") or (config == "Autogyro"):
          N_values = np.array([1, 2])
      elif (
          (config == "Tilt wing")
          or (config == "Tilt rotor")
          or (config == "Lift + cruise")
          or (config == "Multirotor")
      ):
          N_values = np.linspace(2, 16, 8)
      elif config == "Tilt duct":
          N_values = np.linspace(20, 40, 11)
  
      configs[config]["N_values"] = N_values
      configs[config]["TOGW"] = np.zeros(np.size(N_values))
      configs[config]["W_{battery}"] = np.zeros(np.size(N_values))
      configs[config]["cost_per_trip_per_passenger"] = np.zeros(np.size(N_values))
      configs[config]["f_{peak}"] = np.zeros(np.size(N_values))
      configs[config]["SPL_A"] = np.zeros(np.size(N_values))
  
      for i, N in enumerate(N_values):
  
          problem_subDict = {}
  
          Aircraft = OnDemandAircraft()
          Aircraft = Aircraft.standard_substitutions(
              autonomousEnabled=generic_data["autonomousEnabled"],
          )
          problem_subDict.update(
              {
                  Aircraft.L_D_cruise: c["L/D"],  # estimated L/D in cruise
                  Aircraft.eta_cruise: generic_data[
                      "\eta_{cruise}"
                  ],  # propulsive efficiency in cruise
                  Aircraft.tailRotor_power_fraction_hover: c[
                      "tailRotor_power_fraction_hover"
                  ],
                  Aircraft.tailRotor_power_fraction_levelFlight: c[
                      "tailRotor_power_fraction_levelFlight"
                  ],
                  Aircraft.cost_per_weight: generic_data[
                      "vehicle_cost_per_weight"
                  ],  # vehicle cost per unit empty weight
                  Aircraft.battery.C_m: generic_data["C_m"],  # battery energy density
                  Aircraft.battery.cost_per_C: generic_data[
                      "battery_cost_per_C"
                  ],  # battery cost per unit energy capacity
                  Aircraft.rotors.N: N,  # number of rotors
                  Aircraft.rotors.Cl_mean_max: c[
                      "Cl_{mean_{max}}"
                  ],  # maximum allowed mean lift coefficient
                  Aircraft.structure.weight_fraction: c[
                      "weight_fraction"
                  ],  # empty weight fraction
                  Aircraft.electricalSystem.eta: generic_data[
                      "\eta_{electric}"
                  ],  # electrical system efficiency
              }
          )
  
          SizingMission = OnDemandSizingMission(
              Aircraft,
              mission_type=generic_data["sizing_mission"]["type"],
              reserve_type=generic_data["reserve_type"],
          )
          problem_subDict.update(
              {
                  SizingMission.mission_range: generic_data["sizing_mission"][
                      "range"
                  ],  # mission range
                  SizingMission.V_cruise: c["V_{cruise}"],  # cruising speed
                  SizingMission.t_hover: generic_data["sizing_mission"][
                      "t_{hover}"
                  ],  # hover time
                  SizingMission.T_A: c["T/A"],  # disk loading
                  SizingMission.passengers.N_passengers: generic_data["sizing_mission"][
                      "N_{passengers}"
                  ],  # Number of passengers
              }
          )
  
          RevenueMission = OnDemandRevenueMission(
              Aircraft, mission_type=generic_data["revenue_mission"]["type"]
          )
          problem_subDict.update(
              {
                  RevenueMission.mission_range: generic_data["revenue_mission"][
                      "range"
                  ],  # mission range
                  RevenueMission.V_cruise: c["V_{cruise}"],  # cruising speed
                  RevenueMission.t_hover: generic_data["revenue_mission"][
                      "t_{hover}"
                  ],  # hover time
                  RevenueMission.passengers.N_passengers: generic_data["revenue_mission"][
                      "N_{passengers}"
                  ],  # Number of passengers
                  RevenueMission.time_on_ground.charger_power: generic_data[
                      "charger_power"
                  ],  # Charger power
              }
          )
  
          DeadheadMission = OnDemandDeadheadMission(
              Aircraft, mission_type=generic_data["deadhead_mission"]["type"]
          )
          problem_subDict.update(
              {
                  DeadheadMission.mission_range: generic_data["deadhead_mission"][
                      "range"
                  ],  # mission range
                  DeadheadMission.V_cruise: c["V_{cruise}"],  # cruising speed
                  DeadheadMission.t_hover: generic_data["deadhead_mission"][
                      "t_{hover}"
                  ],  # hover time
                  DeadheadMission.passengers.N_passengers: generic_data[
                      "deadhead_mission"
                  ][
                      "N_{passengers}"
                  ],  # Number of passengers
                  DeadheadMission.time_on_ground.charger_power: generic_data[
                      "charger_power"
                  ],  # Charger power
              }
          )
  
          MissionCost = OnDemandMissionCost(Aircraft, RevenueMission, DeadheadMission)
          problem_subDict.update(
              {
                  MissionCost.revenue_mission_costs.operating_expenses.pilot_cost.wrap_rate: generic_data[
                      "pilot_wrap_rate"
                  ],  # pilot wrap rate
                  MissionCost.revenue_mission_costs.operating_expenses.maintenance_cost.wrap_rate: generic_data[
                      "mechanic_wrap_rate"
                  ],  # mechanic wrap rate
                  MissionCost.revenue_mission_costs.operating_expenses.maintenance_cost.MMH_FH: generic_data[
                      "MMH_FH"
                  ],  # maintenance man-hours per flight hour
                  MissionCost.deadhead_mission_costs.operating_expenses.pilot_cost.wrap_rate: generic_data[
                      "pilot_wrap_rate"
                  ],  # pilot wrap rate
                  MissionCost.deadhead_mission_costs.operating_expenses.maintenance_cost.wrap_rate: generic_data[
                      "mechanic_wrap_rate"
                  ],  # mechanic wrap rate
                  MissionCost.deadhead_mission_costs.operating_expenses.maintenance_cost.MMH_FH: generic_data[
                      "MMH_FH"
                  ],  # maintenance man-hours per flight hour
                  MissionCost.deadhead_ratio: generic_data[
                      "deadhead_ratio"
                  ],  # deadhead ratio
              }
          )
  
          problem = Model(
              MissionCost["cost_per_trip"],
              [Aircraft, SizingMission, RevenueMission, DeadheadMission, MissionCost],
          )
          problem.substitutions.update(problem_subDict)
          solution = problem.solve(verbosity=0)
          configs[config]["solution"] = solution
  
          configs[config]["TOGW"][i] = (
              solution("TOGW_OnDemandAircraft").to(ureg.lbf).magnitude
          )
          configs[config]["W_{battery}"][i] = (
              solution("W_OnDemandAircraft/Battery").to(ureg.lbf).magnitude
          )
          configs[config]["cost_per_trip_per_passenger"][i] = solution(
              "cost_per_trip_per_passenger_OnDemandMissionCost"
          )
  
          # Noise computations
          T_perRotor = solution("T_perRotor_OnDemandSizingMission")[0]
          Q_perRotor = solution("Q_perRotor_OnDemandSizingMission")[0]
          R = solution("R")
          VT = solution("VT_OnDemandSizingMission")[0]
          s = solution("s")
          Cl_mean = solution("Cl_{mean_{max}}")
          N = solution("N")
  
          B = generic_data["B"]
          delta_S = generic_data["delta_S"]
  
          # A-weighted
          f_peak, SPL, spectrum = vortex_noise(
              T_perRotor=T_perRotor,
              R=R,
              VT=VT,
              s=s,
              Cl_mean=Cl_mean,
              N=N,
              B=B,
              delta_S=delta_S,
              h=0 * ureg.ft,
              t_c=0.12,
              St=0.28,
              weighting="A",
          )
  
          configs[config]["SPL_A"][i] = SPL
          configs[config]["f_{peak}"][i] = f_peak.to(ureg.turn / ureg.s).magnitude
  
      configs[config]["TOGW"] = configs[config]["TOGW"] * ureg.lbf
      configs[config]["W_{battery}"] = configs[config]["W_{battery}"] * ureg.lbf
      configs[config]["f_{peak}"] = configs[config]["f_{peak}"] * ureg.turn / ureg.s
  
  
  # Plotting commands
  plt.ion()
  fig1 = plt.figure(figsize=(12, 12), dpi=80)
  plt.rc("axes", axisbelow=True)
  plt.show()
  
  style = {}
  style["linestyle"] = ["-", "-", "-", "-", "--", "--", "--", "--"]
  style["marker"] = ["s", "o", "^", "v", "s", "o", "^", "v"]
  style["fillstyle"] = ["full", "full", "full", "full", "none", "none", "none", "none"]
  style["markersize"] = 10
  
  # Maximum takeoff weight
  plt.subplot(2, 2, 1)
  for i, config in enumerate(configs):
      c = configs[config]
      plt.plot(
          c["N_values"],
          c["TOGW"].to(ureg.lbf).magnitude,
          color="black",
          linewidth=1.5,
          linestyle=style["linestyle"][i],
          marker=style["marker"][i],
          fillstyle=style["fillstyle"][i],
          markersize=style["markersize"],
          label=config,
      )
  plt.grid()
  [ymin, ymax] = plt.gca().get_ylim()
  plt.ylim(ymin=0, ymax=1.1 * ymax)
  plt.xticks(fontsize=12)
  plt.yticks(fontsize=12)
  plt.xlabel("Number of rotors", fontsize=16)
  plt.ylabel("Weight (lbf)", fontsize=16)
  plt.title("Takeoff Gross Weight", fontsize=20)
  plt.legend(numpoints=1, loc="lower right", fontsize=12, framealpha=1)
  
  
  # Trip cost per passenger
  plt.subplot(2, 2, 2)
  for i, config in enumerate(configs):
      c = configs[config]
      plt.plot(
          c["N_values"],
          c["cost_per_trip_per_passenger"],
          color="black",
          linewidth=1.5,
          linestyle=style["linestyle"][i],
          marker=style["marker"][i],
          fillstyle=style["fillstyle"][i],
          markersize=style["markersize"],
          label=config,
      )
  plt.grid()
  axes = plt.gca()
  [ymin, ymax] = axes.get_ylim()
  plt.ylim(ymin=0, ymax=1.1 * ymax)
  plt.xticks(fontsize=12)
  plt.yticks(fontsize=12)
  plt.xlabel("Number of rotors", fontsize=16)
  plt.ylabel("Cost ($US)", fontsize=16)
  plt.title("Cost per Trip, per Passenger", fontsize=20)
  plt.legend(numpoints=1, loc="lower right", fontsize=12, framealpha=1)
  
  
  # Vortex-noise peak frequency
  plt.subplot(2, 2, 3)
  for i, config in enumerate(configs):
      c = configs[config]
      plt.plot(
          c["N_values"],
          c["f_{peak}"].to(ureg.turn / ureg.s).magnitude,
          color="black",
          linewidth=1.5,
          linestyle=style["linestyle"][i],
          marker=style["marker"][i],
          fillstyle=style["fillstyle"][i],
          markersize=style["markersize"],
          label=config,
      )
  plt.grid()
  plt.yscale("log", nonposy="clip")
  plt.ylim(ymin=1e2, ymax=1e4)
  plt.xticks(fontsize=12)
  plt.yticks(fontsize=12)
  plt.xlabel("Number of rotors", fontsize=16)
  plt.ylabel("Peak Frequency (Hz)", fontsize=16)
  plt.title("Vortex-Noise Peak Frequency", fontsize=20)
  plt.legend(numpoints=1, loc="lower right", fontsize=12, framealpha=1)
  
  
  # Sound pressure level (in hover)
  plt.subplot(2, 2, 4)
  for i, config in enumerate(configs):
      c = configs[config]
      plt.plot(
          c["N_values"],
          c["SPL_A"],
          color="black",
          linewidth=1.5,
          linestyle=style["linestyle"][i],
          marker=style["marker"][i],
          fillstyle=style["fillstyle"][i],
          markersize=style["markersize"],
          label=config,
      )
  plt.grid()
  plt.xticks(fontsize=12)
  plt.yticks(fontsize=12)
  plt.xlabel("Number of rotors", fontsize=16)
  plt.ylabel("SPL (dBA)", fontsize=16)
  plt.title("Sound Pressure Level in Hover", fontsize=20)
  plt.legend(numpoints=1, loc="lower right", fontsize=12, framealpha=1)
  
  
  if (
      generic_data["reserve_type"] == "FAA_aircraft"
      or generic_data["reserve_type"] == "FAA_heli"
  ):
      num = solution("t_{loiter}_OnDemandSizingMission").to(ureg.minute).magnitude
      if generic_data["reserve_type"] == "FAA_aircraft":
          reserve_type_string = "FAA aircraft VFR (%0.0f-minute loiter time)" % num
      elif generic_data["reserve_type"] == "FAA_heli":
          reserve_type_string = "FAA helicopter VFR (%0.0f-minute loiter time)" % num
  elif generic_data["reserve_type"] == "Uber":
      num = (
          solution["constants"]["R_{divert}_OnDemandSizingMission"]
          .to(ureg.nautical_mile)
          .magnitude
      )
      reserve_type_string = " (%0.0f-nm diversion distance)" % num
  
  if generic_data["autonomousEnabled"]:
      autonomy_string = "autonomy enabled"
  else:
      autonomy_string = "pilot required"
  
  title_str = (
      "Aircraft parameters: battery energy density = %0.0f Wh/kg; %0.0f rotor blades; %s\n"
      % (generic_data["C_m"].to(ureg.Wh / ureg.kg).magnitude, B, autonomy_string)
      + "Sizing mission (%s): range = %0.0f nmi; %0.0f passengers; %0.0fs hover time; reserve type = "
      % (
          generic_data["sizing_mission"]["type"],
          generic_data["sizing_mission"]["range"].to(ureg.nautical_mile).magnitude,
          generic_data["sizing_mission"]["N_{passengers}"],
          generic_data["sizing_mission"]["t_{hover}"].to(ureg.s).magnitude,
      )
      + reserve_type_string
      + "\n"
      + "Revenue mission (%s): range = %0.0f nmi; %0.1f passengers; %0.0fs hover time; no reserve; charger power = %0.0f kW\n"
      % (
          generic_data["revenue_mission"]["type"],
          generic_data["revenue_mission"]["range"].to(ureg.nautical_mile).magnitude,
          generic_data["revenue_mission"]["N_{passengers}"],
          generic_data["revenue_mission"]["t_{hover}"].to(ureg.s).magnitude,
          generic_data["charger_power"].to(ureg.kW).magnitude,
      )
      + "Deadhead mission (%s): range = %0.0f nmi; %0.1f passengers; %0.0fs hover time; no reserve; deadhead ratio = %0.1f"
      % (
          generic_data["deadhead_mission"]["type"],
          generic_data["deadhead_mission"]["range"].to(ureg.nautical_mile).magnitude,
          generic_data["deadhead_mission"]["N_{passengers}"],
          generic_data["deadhead_mission"]["t_{hover}"].to(ureg.s).magnitude,
          generic_data["deadhead_ratio"],
      )
  )
  
  plt.suptitle(title_str, fontsize=13.0)
  plt.tight_layout()
  plt.subplots_adjust(left=0.07, right=0.98, bottom=0.05, top=0.87)
  plt.savefig("number_of_rotors_plot_01.pdf")
  