Skip to content

Latest commit

 

History

History
379 lines (318 loc) · 14 KB

File metadata and controls

379 lines (318 loc) · 14 KB

Aeroshell

Default ValuesQuantityUnitsVariable Name
MassMass
AreaArea
Lift CoefficientLiftCoefficient
Drag CoefficientDragCoefficient
from openmdao.api import ExplicitComponent
import numpy as np
class AeroShell(ExplicitComponent):
    """Aeroshell of the pod"""
    <<AeroShell_initialize>>
    <<AeroShell_setup>>
    <<AeroShell_compute>>
    <<AeroShell_compute_partials>>

initialize

def initialize(self):
   """Declare options"""

    # Need to convert this to an input at some point
    self.options.declare('Mass', 
                         default=1.,
                         types=np.ScalarType,
                         desc='Mass of the HyperJackets Pod')
                         
    # The following properties need to be made more accurate ASAP.
    # These should not exist like this

    self.options.declare('Area'
                         default=1.
                         types=np.ScalarType,
                         desc='Pod Lift Area')

    self.options.declare('LiftCoefficient'
                         default=1.
                         types=np.ScalarType,
                         desc='Lift Coefficient of Pod')

    self.options.declare('DragCoefficient'
                         default=1.
                         types=np.ScalarType,
                         desc='Drag Coefficient of Pod')

setup

def setup(self):
   """Declare inputs and outputs"""

    # Inputs
    self.add_input('AirDensity', 
                   0.5,
                   desc="Air Density around the aeroshell")
    self.add_input('Velocity', 
                   0,
                   desc="Speed of the aeroshell (and of the pod)")

    # Outputs
    self.add_output('Lift', 0.0,
                    units="kg*m/s^2",
                    desc="Lifting force due to the aeroshell")
    self.add_output('Drag', 0.0, 
                    units="kg*m/s^2",
                    desc="Drag force due to the aeroshell")

    # Independence
    self.declare_partials('Lift',
                          'DragCoefficient',
                          dependent=False)
    self.declare_partials('Drag',
                          'LiftCoefficient',
                          dependent=False)

compute

def compute(self, inputs, outputs):
    """Compute outputs"""

    # Properties of the tube
    rho = inputs['AirDensity']

    # Aerodynamic Coefficients
    c_l = self.options['LiftCoefficient']
    c_d = self.options['DragCoefficient']

    # Properties of the pod
    area = self.options['Area']
    vel = inputs['Velocity']

    lift = - 0.5*rho*c_l*area*vel*vel
    drag = 0.5*rho*c_d*area*vel*vel

    outputs['Lift'] = lift
    outputs['Drag'] = drag

compute partials

def compute_partials(self, inputs, partials):
    """ Computation of partial derivatives."""

    c_l = self.options["LiftCoefficient"]
    c_d = self.options["DragCoefficient"]
    area = self.options["Area"]
    vel = inputs["Velocity"]
    rho = inputs["AirDensity"]

    partials['Lift', 'AirDensity'] = -0.5*c_l*area*vel*vel
    partials['Lift', 'Velocity'] = - c_l*area*rho*vel

Wheels

from openmdao.api import ExplicitComponent

<<Wheels_wheelRotationalStress>>
class Wheel(ExplicitComponent):
    """ Wheel Material """
    <<Wheel_initialize>>
    <<Wheel_setup>>
    <<Wheel_compute>>

initialize

def initialize(self):
   """Declare options"""

    # Material Properties
    self.options.declare('Density', 
                         default=1.,
                         types=np.ScalarType,
                         desc='Density of the wheel material')
    self.options.declare('PoissonsRatio',
                         default=1.
                         types=np.ScalarType,
                         desc="Poisson's Ratio for the wheel material")
    self.options.declare('FrictionCoefficient',
                         default=1,
                         types=np.ScalarType,
                         desc="Friction Coefficient of the wheel material")
    self.options.declare('YieldCircumferentialStress',
                         default=1,
                         types=np.ScalarType,
                         desc="Max Circumferential Stress")
    self.options.declare('YieldRadialStress',
                         default=1,
                         types=np.ScalarType,
                         desc="Max Radial Stress")

    # Engineering Properties
    self.options.declare('FactorOfSafety',
                         default=1,
                         types=np.ScalarType,
                         desc="Factor of Safety for the wheels")
    self.options.declare('ThicknessDistribution_Inner',
                         default=np.ones(20),
                         types=np.ndarray,
                         desc="Thickness Distribution of the Inner Surface")
    self.options.declare('ThicknessDistribution_Outer',
                         default=np.ones(20),
                         types=np.ndarray,
                         desc="Thickness Distribution of the Inner Surface")

    # Wheel Properties
    self.options.declare('InnerRadius',
                         default=1.,
                         types=np.ScalarType,
                         desc="Inner Radius of the wheel")
    self.options.declare('OuterRadius',
                         default=1.,
                         types=np.ScalarType,
                         desc="Outer Radius of the wheel")
    self.options.declare("Multiplicity",
                         default=4.,
                         types=np.ScalarType,
                         desc="Number of wheels used on pod")

setup

def setup(self):
    """Declare inputs and outputs"""

    # Inputs
    self.add_input('NormalForce',
                   0.5,
                   desc="Normal Force applied on wheels due to weight of the pod")
    self.add_input('Velocity',
                   0.5,
                   desc="Velocity of the pod")
    self.add_input('RevolutionsPerMinute',
                   0.5,
                   desc="Revolutions per minute of the wheel")

    # Output
    self.add_output('FrictionForce',
                    0.5,
                    desc="FrictionForce applied to the wheels of the car")

    # Output Stresses experienced by the wheel
    self.add_output('MaximumCircumferentialStress',
                   0.5,
                   desc="Circumferential Stress experienced due to rotation")
    self.add_output('MaximumRadialStress',
                   0.5,
                   desc="Radial Stress experienced due to rotation")

    # Independence
    self.declare_partials('CircumferentialStress',
                          'NormalForce',
                          dependent=False)
    self.declare_partials('RadialStress',
                          'NormalForce',
                          dependent=False)

compute

def compute(self, inputs, outputs):
    """Compute outputs"""

    # Material Properties of the wheel
    density = self.options["Density"]
    m = self.options["PoissonsRatio"]
    c_f = self.options["FrictionCoefficient"]
    circumferential_max = self.options["YieldCircumferentialStress"]
    radial_max = self.options["YieldRadialStress"]

    # Wheel Properties
    r1 = self.options["InnerRadius"]
    r2 = self.options["OuterRadius"]
    multiplicity = self.options["Multiplicity"]

    # Pod Properties
    vel = inputs["Velocity"]
    normal_force = inputs["NormalForce"]

    # Engineering Properties
    factor_of_safety = self.options["FactorOfSafety"]
    inner_thickness = self.options["ThicknessDistribution_Inner"]
    outer_thickness = self.options["ThicknessDistribution_Outer"]

    # Circumferential & Radial Stresses
    if r1 is 0:
        # We're dealing with a solid disc
        # Both stress are max at r = 0
        # Circumferential Stress & Radial Stress
        c_stress, r_stress = wheelRotationalStress(radius = 0,    
                                                   innerRadius = r1,           
                                                   outerRadius = r2,
                                                   omega = omega,
                                                   poissonsRatio = m,
                                                   density = density):
   else:
        # We're dealing with a hollow disc
        # Both stress are max at r = (r1 * r2) ** (0.5)
        # Circumferential Stress & Radial Stress
        c_stress, r_stress = wheelRotationalStress(radius = (r1*r2)**(0.5),    
                                                   innerRadius = r1,           
                                                   outerRadius = r2,
                                                   omega = omega,
                                                   poissonsRatio = m,
                                                   density = density):
   
    if c_stress > circumferential_max:
        failure = "Due to stress above yield circumferential stress"
        raise WheelFailure(failure)
    elif c_stress >  circumferential_max / factor_of_safety:
        failure = "Circumferential stress is past allowable "
        raise WheelFailure(failure)
        
    else:
        outputs["CircumferentialStress"] = c_stress
        
    if r_stress > radial_max:
        raise WheelFailure("Your wheels have ripped apart due to radial stress")
    elif r_stress >  radial_max / factor_of_safety:
        raise WheelFailure("Your radial stress is past the allowable stress")
    else:
        outputs["RadialStress"] = r_stress

    # RevolutionsPerMinute

    # FrictionForce

Rotational Stress

def wheelRotationalStress(radius = 0,         # Desired Radius
                          innerRadius = 0,     # Inner Radius of the wheel
                          outerRadius = 1,     # Outer Radius of the wheel
                          omega = 1,           # Rotational Velocity of the wheel
                          poissonsRatio = 1,   # Poisson's Ratio. Denoted by 1/m
                          density = 1):        # Density of the material
       
    if innerRadius is 0:
        # We're dealing with a solid disc
        C_1 = (3 + poissonsRatio)*(1/4)
        C_1 *= (density*(omega**2)*(outerRadius**2))
        C_2 = 0
    else:
        # We're dealing with a hollow disc
        C_1 = (3 + poissonsRatio)*(1/4)
        C_1 *= (density*(omega**2)*(innerRadius**2 + outerRadius**2))
        C_2 = (3 + poissonsRatio)*(1/8)
        C_2 *= (density*(omega**2)*(innerRadius**2)*(outerRadius**2))

    sigma_radial = C_1/2 + C_2/(radius**2)
    sigma_radial -= (3 + poissonsRatio)*(1/8)*(density*(omega**2)*(radius**2))
    sigma_circum = C_1/2 - C_2/(radius**2) 
    sigma_circum -= (1 + 3*poissonsRatio)*(1/8)*(density*(omega**2)*(radius**2))

    return sigma_radial, sigma_circum

Motor

from openmdao.api import ExplicitComponent

class Motor(ExplicitComponent):
    """ Wheel Material """
    <<Motor_initialize>>
    <<Motor_setup>>
    <<Motor_compute>>

initialize

def initialize(self):
   """Declare options"""

    # "Maximum" Properties
    self.options.declare('MaxTorque_Continuous', 
                         default=1.,
                         types=np.ScalarType,
                         desc='Maximum Continuous Torque provided by the motor')
    self.options.declare('MaxRPM_Continuous', 
                         default=1.,
                         types=np.ScalarType,
                         desc='Maximum RPM allowable by the motor')
                         
    # Engineering Properties
    self.options.declare('Mass',
                         default=1.,
                         types=np.ScalarType,
                         desc="Mass of one motor")
    self.options.declare('TransmissionEfficiency',
                         default=1.,
                         types=np.ScalarType,
                         desc="Transmission Efficiency of the Engine")

setup

compute