예제 #1
0
    def _createStages(self):
        ''' Initialize each of the stages and all of their subcomponents. '''
        stageDicts = self._getStageSubDicts()

        # If we're initializing a dropped stage, figure out which one
        if self.stage != None:
            stageNumbers = []
            stageNumberSet = set()
            for stageDict in stageDicts:
                stageNumber = self.rocketDictReader.getFloat(stageDict + ".stageNumber")
                stageNumbers.append(stageNumber)
                stageNumberSet.add(stageNumber)
            
            if len(stageNumbers) != len(stageNumberSet):
                raise ValueError("For multi-stage rockets, each stage must have a unique stage number. Set the Rocket.StageName.stageNumber value for each stage. 0 for first stage, 1 for second, etc...")
            
            stageNumbers.sort()
            stageToInitialize = stageNumbers[self.stage]

        # Initialize Stage(s)
        initializingAllStages = (self.stage == None)
        for stageDictionary in stageDicts:
            stageDictReader = SubDictReader(stageDictionary, self.simDefinition)
            stageNumber = stageDictReader.getFloat("stageNumber")

            if initializingAllStages or stageNumber == stageToInitialize:
                newStage = Stage(stageDictReader, self)
                self.stages.append(newStage)

                if newStage.name not in self.__dict__: # Avoid clobbering existing info
                    setattr(self, newStage.name, newStage) # Make stage available as rocket.stageName
예제 #2
0
def integratorFactory(integrationMethod="Euler", simDefinition=None, discardedTimeStepCallback=None):
    ''' 
        Returns a callable integrator object

        Inputs:
            * integrationMethod: (str) Name of integration method: Examples = "Euler", "RK4", "RK23Adaptive", and "RK45Adaptive"
            * simDefinition: (`MAPLEAF.IO.SimDefinition`) for adaptive integration, provide a simdefinition file with time step adaptation parameters
            * discardedTimeStepCallback: (1-argument function reference) for adaptive integration, this function (if provided) is called when a time step is computed,
                but then discarded and re-computed with a smaller timestep to remain below the max estimated error threshold. Used by MAPLEAF to remove
                force calculation logs from those discarded time steps
    '''
    if "Adapt" in integrationMethod:
        if simDefinition == None:
            raise ValueError("SimDefinition object required to initialize adaptive integrator")

        from MAPLEAF.IO import SubDictReader
        adaptDictReader = SubDictReader("SimControl.TimeStepAdaptation", simDefinition)

        # Adaptive Integration
        controller = adaptDictReader.getString("controller")
        if controller == "PID":
            PIDCoeffs = [ float(x) for x in adaptDictReader.getString("PID.coefficients").split() ]
            safetyFactor = None
        elif controller == "elementary":
            safetyFactor = adaptDictReader.getFloat("Elementary.safetyFactor")
            PIDCoeffs = None

        targetError = adaptDictReader.getFloat("targetError")
        minFactor = adaptDictReader.getFloat("minFactor")
        maxFactor = adaptDictReader.getFloat("maxFactor")
        maxTimeStep = adaptDictReader.getFloat("maxTimeStep")
        minTimeStep = adaptDictReader.getFloat("minTimeStep")
        
        return AdaptiveIntegrator(
            method=integrationMethod, 
            controller=controller, 
            targetError=targetError, 
            maxMinSafetyFactors=[maxFactor, minFactor, safetyFactor], 
            PIDCoeffs=PIDCoeffs, 
            maxTimeStep=maxTimeStep, 
            minTimeStep=minTimeStep, 
            discardedTimeStepCallback=discardedTimeStepCallback
        )
    
    else:
        # Constant time step integrator
        return ClassicalIntegrator(method=integrationMethod)
예제 #3
0
    def __init__(self, simDefinition=None, silent=False):
        ''' Sets up the Wind, Atmospheric, and Earth models requested in the Sim Definition file '''
        self.launchRail = None

        if simDefinition != None:
            # Whenever we're running a real simulation, should always end up here
            envDictReader = SubDictReader("Environment", simDefinition)

            self.meanWindModel = meanWindModelFactory(envDictReader, silent=silent)
            self.turbulenceModel = turbulenceModelFactory(envDictReader, silent=silent)
            self.atmosphericModel = atmosphericModelFactory(envDictReader=envDictReader)
            self.earthModel = earthModelFactory(envDictReader)

            self.launchSiteElevation = envDictReader.tryGetFloat("LaunchSite.elevation")
            self.launchSiteLatitude = envDictReader.tryGetFloat("LaunchSite.latitude")
            self.launchSiteLongitude = envDictReader.tryGetFloat("LaunchSite.longitude")

            # Check if being launched from a launch rail
            launchRailLength = envDictReader.getFloat("LaunchSite.railLength")
            
            if launchRailLength > 0:
                # Initialize a launch rail, aligned with the rocket's initial direction
                initialRocketPosition_towerFrame = envDictReader.getVector("Rocket.position")

                # Check whether precise initial orientation has been specified
                rotationAxis = envDictReader.tryGetVector("Rocket.rotationAxis", defaultValue=None)
                if rotationAxis != None:
                    rotationAngle = math.radians(envDictReader.getFloat("Rocket.rotationAngle"))
                    initOrientation = Quaternion(rotationAxis, rotationAngle)
                else:
                    # Calculate initial orientation quaternion in launch tower frame
                    rotationAxis = envDictReader.tryGetVector("Rocket.rotationAxis", defaultValue=None)
                    if rotationAxis != None:
                        rotationAngle = math.radians(self.rocketDictReader.getFloat("Rocket.rotationAngle"))
                        initOrientation = Quaternion(rotationAxis, rotationAngle)
                    else:
                        # Calculate initial orientation quaternion in launch tower frame
                        initialDirection = envDictReader.getVector("Rocket.initialDirection").normalize()
                        angleFromVertical = Vector(0,0,1).angle(initialDirection)
                        rotationAxis = Vector(0,0,1).crossProduct(initialDirection)
                        initOrientation = Quaternion(rotationAxis, angleFromVertical)

                    # TODO: Get from rocket, or calculate the same way - so that it works with rotationAxis + Angle
                    initialDirection = envDictReader.getVector("Rocket.initialDirection").normalize()
                    angleFromVertical = Vector(0,0,1).angle(initialDirection)
                    rotationAxis = Vector(0,0,1).crossProduct(initialDirection)
                    initOrientation = Quaternion(rotationAxis, angleFromVertical)

                initPosition_seaLevelENUFrame = initialRocketPosition_towerFrame + Vector(0, 0, self.launchSiteElevation)
                launchTowerState_local = RigidBodyState(position=initPosition_seaLevelENUFrame, orientation=initOrientation)
                launchTowerState_global = self.earthModel.convertIntoGlobalFrame(launchTowerState_local, self.launchSiteLatitude, self.launchSiteLongitude)
                towerDirection_global = launchTowerState_global.orientation.rotate(Vector(0, 0, 1))                
                self.launchRail = LaunchRail(launchTowerState_global.position, towerDirection_global, launchRailLength, earthRotationRate=self.earthModel.rotationRate)
                
        else:
            # Construct default environment from default parameters when no sim definition is passed in
            # Need additional default value here in case a SimDefinition is not passed in (otherwise SimDefinition takes care of default values)
            self.meanWindModel = meanWindModelFactory()
            self.turbulenceModel = None
            self.atmosphericModel = atmosphericModelFactory()
            self.earthModel = earthModelFactory()

            self.launchSiteElevation = float(defaultConfigValues["Environment.LaunchSite.elevation"])
            self.launchSiteLatitude = float(defaultConfigValues["Environment.LaunchSite.latitude"])
            self.launchSiteLongitude = float(defaultConfigValues["Environment.LaunchSite.longitude"])