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
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)
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"])