Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/openconcept.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ jobs:
os: ["ubuntu-latest", "windows-latest", "macos-latest"]
dep-versions: ["oldest", "latest"]
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Set versions to test here ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PYTHON_VERSION_OLDEST: ['3.8']
PYTHON_VERSION_LATEST: ['3.11']
PYTHON_VERSION_OLDEST: ['3.11']
PYTHON_VERSION_LATEST: ['3.13']
PIP_VERSION_OLDEST: ['23.0.1'] # pip>=23.1 cannot build the oldest OpenMDAO
SETUPTOOLS_VERSION_OLDEST: ['66.0.0'] # setuptools >= 67.0.0 can't build the oldest OpenMDAO
NUMPY_VERSION_OLDEST: ['1.21'] # latest is most recent on PyPI
SCIPY_VERSION_OLDEST: ['1.7.0'] # latest is most recent on PyPI
NUMPY_VERSION_OLDEST: ['1.25'] # latest is most recent on PyPI
SCIPY_VERSION_OLDEST: ['1.11.0'] # latest is most recent on PyPI
OPENMDAO_VERSION_OLDEST: ['3.21'] # latest is most recent on PyPI
fail-fast: false
env:
Expand Down
21 changes: 15 additions & 6 deletions openconcept/aerodynamics/drag_jet_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,14 @@ def compute(self, inputs, outputs):
# Reynolds number
Re = inputs["fltcond|Utrue"] * inputs["L"] / visc_kin

# During Newton iterations, Utrue can temporarily go negative, making Re
# negative and causing log(negative) = NaN. Apply abs only for the real part so
# complex-step derivative checking still propagates the imaginary part correctly.
if np.isrealobj(Re):
Re = np.abs(Re)
else:
Re = np.where(np.real(Re) < 0, -Re, Re)

# Skin friction coefficient assuming fully turbulent
Cf = 0.523 / np.log(0.06 * Re) ** 2 # explicit fit of Spalding

Expand All @@ -603,14 +611,15 @@ def compute_partials(self, inputs, J):
dvkin_dT = dvdyn_dT / inputs["fltcond|rho"]
dvkin_drho = -visc_dyn / inputs["fltcond|rho"] ** 2

# Reynolds number
# Reynolds number (absolute value of velocity to handle negative Utrue during Newton iterations)
U = inputs["fltcond|Utrue"]
absU = np.abs(U)
L = inputs["L"]
Re = U * L / visc_kin
dRe_dT = -U * L / visc_kin**2 * dvkin_dT
dRe_drho = -U * L / visc_kin**2 * dvkin_drho
dRe_dU = L / visc_kin
dRe_dL = U / visc_kin
Re = absU * L / visc_kin
dRe_dT = -absU * L / visc_kin**2 * dvkin_dT
dRe_drho = -absU * L / visc_kin**2 * dvkin_drho
dRe_dU = np.sign(U) * L / visc_kin
dRe_dL = absU / visc_kin

# Skin friction coefficient assuming fully turbulent
Cf = 0.523 / np.log(0.06 * Re) ** 2 # explicit fit of Spalding
Expand Down
25 changes: 23 additions & 2 deletions openconcept/examples/HybridTwin_thermal.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,13 @@ def setup(self):
# any control variables other than throttle and braking need to be defined here
controls = self.add_subsystem("controls", IndepVarComp(), promotes_outputs=["*"])
controls.add_output("proprpm", val=np.ones((nn,)) * 2000, units="rpm")
controls.add_output("ac|propulsion|thermal|hx|mdot_coolant", val=0.1 * np.ones((nn,)), units="kg/s")
# mdot_coolant is a per-phase control vector of shape (nn,), where nn differs between
# phases (e.g. nn=11 for climb/cruise/descent, nn=1 for engineoutclimb). If this were
# promoted under its ac|propulsion|* name, all phases would expose the same promoted name
# at the parent analysis level with different shapes, which OpenMDAO 3.43+ rejects.
# Instead, give it a local name and wire it into the propulsion model via an explicit
# connect() below, keeping it entirely within this group's scope.
controls.add_output("phase_hx_mdot_coolant", val=0.1 * np.ones((nn,)), units="kg/s")

# assume TO happens on battery backup
if flight_phase in ["climb", "cruise", "descent"]:
Expand All @@ -76,9 +82,23 @@ def setup(self):
)

propulsion_promotes_outputs = ["fuel_flow", "thrust", "ac|propulsion|thermal|duct|area_nozzle"]
# Explicitly list ac|propulsion|* inputs except mdot_coolant, which has a per-phase
# (nn,) shape and is connected directly below to avoid analysis-level shape conflicts.
propulsion_promotes_inputs = [
"fltcond|*",
"ac|propulsion|*",
"ac|propulsion|battery|specific_energy",
"ac|propulsion|engine|rating",
"ac|propulsion|generator|rating",
"ac|propulsion|motor|rating",
"ac|propulsion|propeller|diameter",
"ac|propulsion|thermal|hx|channel_height",
"ac|propulsion|thermal|hx|channel_length",
"ac|propulsion|thermal|hx|channel_width",
"ac|propulsion|thermal|hx|coolant_mass",
"ac|propulsion|thermal|hx|n_long_cold",
"ac|propulsion|thermal|hx|n_parallel",
"ac|propulsion|thermal|hx|n_tall",
"ac|propulsion|thermal|hx|n_wide_cold",
"throttle",
"propulsor_active",
"ac|weights*",
Expand All @@ -93,6 +113,7 @@ def setup(self):
)
self.connect("proprpm", ["propmodel.prop1.rpm", "propmodel.prop2.rpm"])
self.connect("hybrid_factor.vec", "propmodel.hybrid_split.power_split_fraction")
self.connect("phase_hx_mdot_coolant", "propmodel.ac|propulsion|thermal|hx|mdot_coolant")

# use a different drag coefficient for takeoff versus cruise
if flight_phase not in ["v0v1", "v1v0", "v1vr", "rotate"]:
Expand Down
2 changes: 1 addition & 1 deletion openconcept/examples/tests/test_example_aircraft.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def test_values_hybridtwin(self):
assert_near_equal(prob.get_val("rotate.range_final", units="ft"), 4383.871458066499, tolerance=1e-5)
assert_near_equal(prob.get_val("engineoutclimb.gamma", units="deg"), 1.7659046316724112, tolerance=1e-5)
assert_near_equal(prob.get_val("descent.fuel_used_final", units="lb"), 854.8937776195904, tolerance=1e-5)
assert_near_equal(prob.get_val("descent.propmodel.batt1.SOC_final", units=None), -0.00030626412, tolerance=1e-5)
assert_near_equal(prob.get_val("descent.propmodel.batt1.SOC_final", units=None), -0.00030626412, tolerance=5e-5)


class KingAirTestCase(unittest.TestCase):
Expand Down
2 changes: 1 addition & 1 deletion openconcept/propulsion/tests/test_N3.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def test_defaults(self):

assert_near_equal(p.get_val("thrust", units="lbf"), 6902.32371562 * np.ones(1), tolerance=1e-6)
assert_near_equal(p.get_val("fuel_flow", units="kg/s"), 0.35176628 * np.ones(1), tolerance=1e-6)
assert_near_equal(p.get_val("surge_margin"), 18.42447377 * np.ones(1), tolerance=1e-6)
assert_near_equal(p.get_val("surge_margin"), 18.42447377 * np.ones(1), tolerance=5e-6)

def test_vectorized(self):
nn = 5
Expand Down
2 changes: 1 addition & 1 deletion openconcept/thermal/hose.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def compute_partials(self, inputs, J):
fake_inputs = dict()
# make a perturbable, complex copy of the inputs
for inp in cs_inp_list:
fake_inputs[inp] = inputs[inp].astype(np.complex_, copy=True)
fake_inputs[inp] = inputs[inp].astype(np.complex128, copy=True)

for inp in cs_inp_list:
arr_to_restore = fake_inputs[inp].copy()
Expand Down
2 changes: 1 addition & 1 deletion openconcept/utilities/math/add_subtract_comp.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ def compute(self, inputs, outputs):
shape = (vec_out_size, length)

if self.under_complex_step:
temp = np.zeros(shape, dtype=np.complex_)
temp = np.zeros(shape, dtype=np.complex128)
else:
temp = np.zeros(shape)

Expand Down
4 changes: 2 additions & 2 deletions openconcept/utilities/math/combine_split_comp.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,13 @@ def compute(self, inputs, outputs):
input_names = [input_names]

if self.under_complex_step:
dtype = np.complex_
dtype = np.complex128
else:
dtype = np.float64
if length == 1:
temp = np.array([], dtype=dtype)
else:
temp = np.empty([0, length], dtype=np.dtype)
temp = np.empty([0, length], dtype=dtype)

for input_name in input_names:
temp = np.concatenate((temp, inputs[input_name]))
Expand Down
2 changes: 1 addition & 1 deletion openconcept/utilities/math/multiply_divide_comp.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ def compute(self, inputs, outputs):
shape = (vec_out_size, length)

if self.under_complex_step:
temp = np.ones(shape, dtype=np.complex_)
temp = np.ones(shape, dtype=np.complex128)
else:
temp = np.ones(shape)

Expand Down
66 changes: 33 additions & 33 deletions openconcept/weights/weights_turboprop.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,22 @@ def setup(self):
def compute(self, inputs, outputs):
n_ult = self.options["n_ult"]
# USAF method, Roskam PVC5pg68eq5.4
# W_wing_USAF = 96.948*((inputs['ac|weights|MTOW']*n_ult/1e5)**0.65 * (inputs['ac|geom|wing|AR']/math.cos(inputs['ac|geom|wing|c4sweep']))**0.57 * (inputs['ac|geom|wing|S_ref']/100)**0.61 * ((1+inputs['ac|geom|wing|taper'])/2/inputs['ac|geom|wing|toverc'])**0.36 * (1+inputs['V_H']/500)**0.5)**0.993
# W_wing_USAF = 96.948*((inputs['ac|weights|MTOW']*n_ult/1e5)**0.65 * (inputs['ac|geom|wing|AR']/np.cos(inputs['ac|geom|wing|c4sweep']))**0.57 * (inputs['ac|geom|wing|S_ref']/100)**0.61 * ((1+inputs['ac|geom|wing|taper'])/2/inputs['ac|geom|wing|toverc'])**0.36 * (1+inputs['V_H']/500)**0.5)**0.993
# Torenbeek, Roskam PVC5p68eq5.5
# b = math.sqrt(inputs['ac|geom|wing|S_ref']*inputs['ac|geom|wing|AR'])
# b = np.sqrt(inputs['ac|geom|wing|S_ref']*inputs['ac|geom|wing|AR'])
# root_chord = 2*inputs['ac|geom|wing|S_ref']/b/(1+inputs['ac|geom|wing|taper'])
# tr = root_chord * inputs['ac|geom|wing|toverc']
# c2sweep_wing = inputs['ac|geom|wing|c4sweep'] # a hack for now
# W_wing_Torenbeek = 0.00125*inputs['ac|weights|MTOW'] * (b/math.cos(c2sweep_wing))**0.75 * (1+ (6.3*math.cos(c2sweep_wing)/b)**0.5) * n_ult**0.55 * (b*inputs['ac|geom|wing|S_ref']/tr/inputs['ac|weights|MTOW']/math.cos(c2sweep_wing))**0.30
# W_wing_Torenbeek = 0.00125*inputs['ac|weights|MTOW'] * (b/np.cos(c2sweep_wing))**0.75 * (1+ (6.3*np.cos(c2sweep_wing)/b)**0.5) * n_ult**0.55 * (b*inputs['ac|geom|wing|S_ref']/tr/inputs['ac|weights|MTOW']/np.cos(c2sweep_wing))**0.30

W_wing_Raymer = (
0.036
* inputs["ac|geom|wing|S_ref"] ** 0.758
* inputs["ac|weights|W_fuel_max"] ** 0.0035
* (inputs["ac|geom|wing|AR"] / math.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* (inputs["ac|geom|wing|AR"] / np.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* inputs["ac|q_cruise"] ** 0.006
* inputs["ac|geom|wing|taper"] ** 0.04
* (100 * inputs["ac|geom|wing|toverc"] / math.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (100 * inputs["ac|geom|wing|toverc"] / np.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (n_ult * inputs["ac|weights|MTOW"]) ** 0.49
)

Expand All @@ -66,10 +66,10 @@ def compute_partials(self, inputs, J):
0.036
* inputs["ac|geom|wing|S_ref"] ** 0.758
* inputs["ac|weights|W_fuel_max"] ** 0.0035
* (inputs["ac|geom|wing|AR"] / math.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* (inputs["ac|geom|wing|AR"] / np.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* inputs["ac|q_cruise"] ** 0.006
* inputs["ac|geom|wing|taper"] ** 0.04
* (100 * inputs["ac|geom|wing|toverc"] / math.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (100 * inputs["ac|geom|wing|toverc"] / np.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (n_ult * inputs["ac|weights|MTOW"]) ** (0.49 - 1)
* n_ult
* 0.49
Expand All @@ -79,33 +79,33 @@ def compute_partials(self, inputs, J):
* inputs["ac|geom|wing|S_ref"] ** 0.758
* 0.0035
* inputs["ac|weights|W_fuel_max"] ** (0.0035 - 1)
* (inputs["ac|geom|wing|AR"] / math.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* (inputs["ac|geom|wing|AR"] / np.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* inputs["ac|q_cruise"] ** 0.006
* inputs["ac|geom|wing|taper"] ** 0.04
* (100 * inputs["ac|geom|wing|toverc"] / math.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (100 * inputs["ac|geom|wing|toverc"] / np.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (n_ult * inputs["ac|weights|MTOW"]) ** 0.49
)
J["W_wing", "ac|geom|wing|S_ref"] = (
0.036
* inputs["ac|geom|wing|S_ref"] ** (0.758 - 1)
* 0.758
* inputs["ac|weights|W_fuel_max"] ** 0.0035
* (inputs["ac|geom|wing|AR"] / math.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* (inputs["ac|geom|wing|AR"] / np.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* inputs["ac|q_cruise"] ** 0.006
* inputs["ac|geom|wing|taper"] ** 0.04
* (100 * inputs["ac|geom|wing|toverc"] / math.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (100 * inputs["ac|geom|wing|toverc"] / np.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (n_ult * inputs["ac|weights|MTOW"]) ** 0.49
)
J["W_wing", "ac|geom|wing|AR"] = (
0.036
* inputs["ac|geom|wing|S_ref"] ** 0.758
* inputs["ac|weights|W_fuel_max"] ** 0.0035
* 0.6
* (inputs["ac|geom|wing|AR"] / math.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** (0.6 - 1)
/ math.cos(inputs["ac|geom|wing|c4sweep"]) ** 2
* (inputs["ac|geom|wing|AR"] / np.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** (0.6 - 1)
/ np.cos(inputs["ac|geom|wing|c4sweep"]) ** 2
* inputs["ac|q_cruise"] ** 0.006
* inputs["ac|geom|wing|taper"] ** 0.04
* (100 * inputs["ac|geom|wing|toverc"] / math.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (100 * inputs["ac|geom|wing|toverc"] / np.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (n_ult * inputs["ac|weights|MTOW"]) ** 0.49
)
c4const = (
Expand All @@ -116,55 +116,55 @@ def compute_partials(self, inputs, J):
* inputs["ac|geom|wing|taper"] ** 0.04
* (n_ult * inputs["ac|weights|MTOW"]) ** 0.49
)
c4multa = (inputs["ac|geom|wing|AR"] / math.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
c4multb = (100 * inputs["ac|geom|wing|toverc"] / math.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
c4multa = (inputs["ac|geom|wing|AR"] / np.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
c4multb = (100 * inputs["ac|geom|wing|toverc"] / np.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
dc4multa = (
0.6
* (inputs["ac|geom|wing|AR"] / math.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** (0.6 - 1)
* (-2 * inputs["ac|geom|wing|AR"] / math.cos(inputs["ac|geom|wing|c4sweep"]) ** 3)
* (-math.sin(inputs["ac|geom|wing|c4sweep"]))
* (inputs["ac|geom|wing|AR"] / np.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** (0.6 - 1)
* (-2 * inputs["ac|geom|wing|AR"] / np.cos(inputs["ac|geom|wing|c4sweep"]) ** 3)
* (-np.sin(inputs["ac|geom|wing|c4sweep"]))
)
dc4multb = (
-0.3
* (100 * inputs["ac|geom|wing|toverc"] / math.cos(inputs["ac|geom|wing|c4sweep"])) ** (-0.3 - 1)
* (100 * inputs["ac|geom|wing|toverc"] / np.cos(inputs["ac|geom|wing|c4sweep"])) ** (-0.3 - 1)
* -100
* inputs["ac|geom|wing|toverc"]
/ math.cos(inputs["ac|geom|wing|c4sweep"]) ** 2
* (-math.sin(inputs["ac|geom|wing|c4sweep"]))
/ np.cos(inputs["ac|geom|wing|c4sweep"]) ** 2
* (-np.sin(inputs["ac|geom|wing|c4sweep"]))
)
J["W_wing", "ac|geom|wing|c4sweep"] = c4const * (c4multa * dc4multb + c4multb * dc4multa)
J["W_wing", "ac|geom|wing|taper"] = (
0.036
* inputs["ac|geom|wing|S_ref"] ** 0.758
* inputs["ac|weights|W_fuel_max"] ** 0.0035
* (inputs["ac|geom|wing|AR"] / math.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* (inputs["ac|geom|wing|AR"] / np.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* inputs["ac|q_cruise"] ** 0.006
* 0.04
* inputs["ac|geom|wing|taper"] ** (0.04 - 1)
* (100 * inputs["ac|geom|wing|toverc"] / math.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (100 * inputs["ac|geom|wing|toverc"] / np.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (n_ult * inputs["ac|weights|MTOW"]) ** 0.49
)
J["W_wing", "ac|geom|wing|toverc"] = (
0.036
* inputs["ac|geom|wing|S_ref"] ** 0.758
* inputs["ac|weights|W_fuel_max"] ** 0.0035
* (inputs["ac|geom|wing|AR"] / math.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* (inputs["ac|geom|wing|AR"] / np.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* inputs["ac|q_cruise"] ** 0.006
* inputs["ac|geom|wing|taper"] ** 0.04
* -0.3
* (100 * inputs["ac|geom|wing|toverc"] / math.cos(inputs["ac|geom|wing|c4sweep"])) ** (-0.3 - 1)
* (100 / math.cos(inputs["ac|geom|wing|c4sweep"]))
* (100 * inputs["ac|geom|wing|toverc"] / np.cos(inputs["ac|geom|wing|c4sweep"])) ** (-0.3 - 1)
* (100 / np.cos(inputs["ac|geom|wing|c4sweep"]))
* (n_ult * inputs["ac|weights|MTOW"]) ** 0.49
)
J["W_wing", "ac|q_cruise"] = (
0.036
* inputs["ac|geom|wing|S_ref"] ** 0.758
* inputs["ac|weights|W_fuel_max"] ** 0.0035
* (inputs["ac|geom|wing|AR"] / math.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* (inputs["ac|geom|wing|AR"] / np.cos(inputs["ac|geom|wing|c4sweep"]) ** 2) ** 0.6
* 0.006
* inputs["ac|q_cruise"] ** (0.006 - 1)
* inputs["ac|geom|wing|taper"] ** 0.04
* (100 * inputs["ac|geom|wing|toverc"] / math.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (100 * inputs["ac|geom|wing|toverc"] / np.cos(inputs["ac|geom|wing|c4sweep"])) ** -0.3
* (n_ult * inputs["ac|weights|MTOW"]) ** 0.49
)

Expand Down Expand Up @@ -196,8 +196,8 @@ def setup(self):
def compute(self, inputs, outputs):
n_ult = self.options["n_ult"]
# USAF method, Roskam PVC5pg72eq5.14/15
# bh = math.sqrt(inputs['ac|geom|hstab|S_ref']*inputs['AR_h'])
# bv = math.sqrt(inputs['ac|geom|vstab|S_ref']*inputs['AR_v'])
# bh = np.sqrt(inputs['ac|geom|hstab|S_ref']*inputs['AR_h'])
# bv = np.sqrt(inputs['ac|geom|vstab|S_ref']*inputs['AR_v'])
# # Wh = 127 * ((inputs['ac|weights|MTOW']*n_ult/1e5)**0.87 * (inputs['ac|geom|hstab|S_ref']/100)**1.2 * 0.289*(inputs['ac|geom|hstab|c4_to_wing_c4']/10)**0.483 * (bh/inputs['troot_h'])**0.5)**0.458
# # #Wh_raymer = 0.016 * (n_ult*inputs['ac|weights|MTOW'])**0.414 * inputs['ac|q_cruise']**0.168 * inputs['ac|geom|hstab|S_ref']**0.896 * (100 * 0.18)**-0.12 * (inputs['AR_h'])**0.043 * 0.7**-0.02
# # Wv = 98.5 * ((inputs['ac|weights|MTOW']*n_ult/1e5)**0.87 * (inputs['ac|geom|vstab|S_ref']/100)**1.2 * 0.289 * (bv/inputs['troot_v'])**0.5)**0.458
Expand Down Expand Up @@ -552,7 +552,7 @@ def setup(self):
self.declare_partials(["W_equipment"], ["*"])

def compute(self, inputs, outputs):
b = math.sqrt(inputs["ac|geom|wing|S_ref"] * inputs["ac|geom|wing|AR"])
b = np.sqrt(inputs["ac|geom|wing|S_ref"] * inputs["ac|geom|wing|AR"])

# Flight control system (unpowered)
# Roskam PVC7p98eq7.2
Expand All @@ -579,7 +579,7 @@ def compute(self, inputs, outputs):
outputs["W_equipment"] = Wfc_Torenbeek + Welec + Wavionics + Wapi + Woxygen + Wfur + Wpaint + Whydraulics

def compute_partials(self, inputs, J):
b = math.sqrt(inputs["ac|geom|wing|S_ref"] * inputs["ac|geom|wing|AR"])
b = np.sqrt(inputs["ac|geom|wing|S_ref"] * inputs["ac|geom|wing|AR"])
Wavionics = 2.117 * (np.array([110])) ** 0.933
J["W_equipment", "ac|weights|MTOW"] = (
0.23 * inputs["ac|weights|MTOW"] ** (0.666 - 1) * 0.666
Expand Down
Loading
Loading