Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a balanced field length example #533

Merged
merged 29 commits into from
Feb 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f9f51ac
balaneced field files
robfalck Jan 25, 2021
208c369
Merge branch 'master' of https://github.com/OpenMDAO/dymos into balan…
robfalck Jan 26, 2021
299ca97
balanced field case converges with ipopt but cleanup is needed
robfalck Jan 29, 2021
50d48d6
cs part 1
robfalck Feb 1, 2021
8885225
stall speed comp now computes weight itself
robfalck Feb 1, 2021
1115275
lift coef now computed in aero forces comp
robfalck Feb 1, 2021
c91e0da
removed stall speed comp
robfalck Feb 1, 2021
6bf8ae6
just need to get rid of groundroll dynamics
robfalck Feb 1, 2021
ea465bb
groundroll is a group with a single comp now
robfalck Feb 1, 2021
4ee4249
v_dot computed in aero_forces_comp is being problematic
robfalck Feb 1, 2021
12e4068
ground roll ODE is now successfully a single component
robfalck Feb 1, 2021
cbeaf72
climb now using a single-component ODE
robfalck Feb 1, 2021
491df3b
removed unnecessary files
robfalck Feb 1, 2021
fabe873
moved most parameters to the trajectory level, but restarts with traj…
robfalck Feb 1, 2021
8d5344a
trajectory simulation now records inputs to capture parameter values
robfalck Feb 1, 2021
743705d
case cleaned up, but no docs yet. possible bug in some traj parameter…
robfalck Feb 1, 2021
e1e4d5c
balanced field ODEs now share common functions
robfalck Feb 2, 2021
18d9d81
Added new test case to verify that default "val" for states, controls…
robfalck Feb 2, 2021
4a4fb97
conform sticking default value for parameter
robfalck Feb 2, 2021
9ed5a26
pep8 cleanup
robfalck Feb 2, 2021
674164c
added utility function to reshape default values to the proper shape
robfalck Feb 2, 2021
ee9740a
cleanup
robfalck Feb 3, 2021
3668cb3
plot added for the docs
robfalck Feb 3, 2021
e285d1b
added documentation of balanced field problem
robfalck Feb 4, 2021
f5cb996
pep8
robfalck Feb 4, 2021
57f29f3
simplified ODEs per code review, and updated docs to reflect the change
robfalck Feb 5, 2021
1a4e9c8
doc update
robfalck Feb 5, 2021
e7401d5
Fixed reference to old ODE
robfalck Feb 5, 2021
7263cb8
one more minor typo
robfalck Feb 5, 2021
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
Empty file.
122 changes: 122 additions & 0 deletions dymos/examples/balanced_field/balanced_field_ode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import numpy as np
import openmdao.api as om


class BalancedFieldODEComp(om.ExplicitComponent):
"""
The ODE System for an aircraft takeoff climb.
Computes the rates for states v (true airspeed) gam (flight path angle) r (range) and h (altitude).
References
----------
.. [1] Raymer, Daniel. Aircraft design: a conceptual approach. American Institute of
Aeronautics and Astronautics, Inc., 2012.
"""
def initialize(self):
self.options.declare('num_nodes', types=int)
self.options.declare('g', types=(float, int), default=9.80665, desc='gravitational acceleration (m/s**2)')
self.options.declare('mode', values=('runway', 'climb'), desc='mode of operation (ground roll or flight)')

def setup(self):
nn = self.options['num_nodes']

# Scalar (constant) inputs
self.add_input('rho', val=1.225, desc='atmospheric density at runway', units='kg/m**3')
self.add_input('S', val=124.7, desc='aerodynamic reference area', units='m**2')
self.add_input('CD0', val=0.03, desc='zero-lift drag coefficient', units=None)
self.add_input('CL0', val=0.5, desc='zero-alpha lift coefficient', units=None)
self.add_input('CL_max', val=2.0, desc='maximum lift coefficient for linear fit', units=None)
self.add_input('alpha_max', val=np.radians(10), desc='angle of attack at CL_max', units='rad')
self.add_input('h_w', val=1.0, desc='height of the wing above the CG', units='m')
self.add_input('AR', val=9.45, desc='wing aspect ratio', units=None)
self.add_input('e', val=0.801, desc='Oswald span efficiency factor', units=None)
self.add_input('span', val=35.7, desc='Wingspan', units='m')
self.add_input('T', val=1.0, desc='thrust', units='N')

# Dynamic inputs (can assume a different value at every node)
self.add_input('m', shape=(nn,), desc='aircraft mass', units='kg')
self.add_input('v', shape=(nn,), desc='aircraft true airspeed', units='m/s')
self.add_input('h', shape=(nn,), desc='altitude', units='m')
self.add_input('alpha', shape=(nn,), desc='angle of attack', units='rad')

# Outputs
self.add_output('CL', shape=(nn,), desc='lift coefficient', units=None)
self.add_output('q', shape=(nn,), desc='dynamic pressure', units='Pa')
self.add_output('L', shape=(nn,), desc='lift force', units='N')
self.add_output('D', shape=(nn,), desc='drag force', units='N')
self.add_output('K', val=np.ones(nn), desc='drag-due-to-lift factor', units=None)
self.add_output('F_r', shape=(nn,), desc='runway normal force', units='N')
self.add_output('v_dot', shape=(nn,), desc='rate of change of speed', units='m/s**2',
tags=['state_rate_source:v'])
self.add_output('r_dot', shape=(nn,), desc='rate of change of range', units='m/s',
tags=['state_rate_source:r'])
self.add_output('W', shape=(nn,), desc='aircraft weight', units='N')
self.add_output('v_stall', shape=(nn,), desc='stall speed', units='m/s')
self.add_output('v_over_v_stall', shape=(nn,), desc='stall speed ratio', units=None)

# Mode-dependent IO
if self.options['mode'] == 'runway':
self.add_input('mu_r', val=0.05, desc='runway friction coefficient', units=None)
else:
self.add_input('gam', shape=(nn,), desc='flight path angle', units='rad')
self.add_output('gam_dot', shape=(nn,), desc='rate of change of flight path angle',
units='rad/s', tags=['state_rate_source:gam'])
self.add_output('h_dot', shape=(nn,), desc='rate of change of altitude', units='m/s',
tags=['state_rate_source:h'])

self.declare_coloring(wrt='*', method='cs')

def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
g = self.options['g']

# Compute factor k to include ground effect on lift
rho = inputs['rho']
v = inputs['v']
S = inputs['S']
CD0 = inputs['CD0']
m = inputs['m']
T = inputs['T']
h = inputs['h']
h_w = inputs['h_w']
span = inputs['span']
AR = inputs['AR']
CL0 = inputs['CL0']
alpha = inputs['alpha']
alpha_max = inputs['alpha_max']
CL_max = inputs['CL_max']
e = inputs['e']

outputs['W'] = W = m * g
outputs['v_stall'] = v_stall = np.sqrt(2 * W / rho / S / CL_max)
outputs['v_over_v_stall'] = v / v_stall

outputs['CL'] = CL = CL0 + (alpha / alpha_max) * (CL_max - CL0)
K_nom = 1.0 / (np.pi * AR * e)
b = span / 2.0
fact = ((h + h_w) / b) ** 1.5
outputs['K'] = K = K_nom * 33 * fact / (1.0 + 33 * fact)

outputs['q'] = q = 0.5 * rho * v ** 2
outputs['L'] = L = q * S * CL
outputs['D'] = D = q * S * (CD0 + K * CL ** 2)

# Compute the downward force on the landing gear
calpha = np.cos(alpha)
salpha = np.sin(alpha)

# Runway normal force
outputs['F_r'] = F_r = m * g - L * calpha - T * salpha

# Compute the dynamics
if self.options['mode'] == 'climb':
gam = inputs['gam']
cgam = np.cos(gam)
sgam = np.sin(gam)
outputs['v_dot'] = (T * calpha - D) / m - g * sgam
outputs['gam_dot'] = (T * salpha + L) / (m * v) - (g / v) * cgam
outputs['h_dot'] = v * sgam
outputs['r_dot'] = v * cgam
else:
outputs['v_dot'] = (T * calpha - D - F_r * inputs['mu_r']) / m
outputs['r_dot'] = v
Empty file.
Loading