//------------------------------------------------------------------------------ bool FiniteBurn::SetStringParameter(const Integer id, const std::string &value, const Integer index) { if (id == FUEL_TANK) return true; // just to ignore Integer count; if (id == THRUSTER) { count = thrusterNames.size(); if (index > count) throw BurnException("Attempting to write thruster " + value + " past the allowed range for FiniteBurn " + instanceName); if (find(thrusterNames.begin(), thrusterNames.end(), value) != thrusterNames.end()) { if (thrusterNames[index] == value) return true; throw BurnException("Thruster " + value + " already set for FiniteBurn " + instanceName); } if (index == count) thrusterNames.push_back(value); else thrusterNames[index] = value; isInitialized = false; return true; } return Burn::SetStringParameter(id, value, index); }
//------------------------------------------------------------------------------ bool Burn::Initialize() { #ifdef DEBUG_BURN_INIT MessageInterface::ShowMessage ("Burn::Initialize() <%p>'%s' entered, spacecraft=<%p>\n", this, GetName().c_str(), spacecraft); #endif bool retval = GmatBase::Initialize(); if (retval) { if ((!solarSystem)) throw BurnException("Unable to initialize the burn object \"" + instanceName + "\"; the SolarSystem was not set."); j2000Body = solarSystem->GetBody(j2000BodyName); if (!localOrigin) localOrigin = solarSystem->GetBody(localOriginName); if ((!localOrigin) || (!j2000Body)) throw BurnException("Unable to initialize the burn object " + instanceName + "; either " + j2000BodyName + " or " + localOriginName + " was not set for the burn."); } // delete old local coordinate system if (usingLocalCoordSys && localCoordSystem != NULL) { #ifdef DEBUG_MEMORY MemoryTracker::Instance()->Remove (localCoordSystem, "localCoordSystem", "Burn::Initialize()", "deleting localCoordSystem"); #endif delete localCoordSystem; localCoordSystem = NULL; } // If spacecraft is available, create new local coordinate system if (usingLocalCoordSys && spacecraft != NULL) localCoordSystem = CreateLocalCoordinateSystem(); if (usingLocalCoordSys && localCoordSystem == NULL) retval = false; #ifdef DEBUG_BURN_INIT MessageInterface::ShowMessage ("Burn::Initialize() <%p>'%s' returning %d, localCoordSystem=<%p>\n", this, GetName().c_str(), retval, localCoordSystem); #endif // hasFired = false; // do I want this here? return retval; }
//------------------------------------------------------------------------------ bool ImpulsiveBurn::Validate() { if (decrementMass) { if (tankNames.empty()) { throw BurnException("The ImpulsiveBurn \"" + instanceName + "\" is set to deplete mass, but no tank is identified as the " "mass source for mass depletion. Please specify a fuel tank " "on the panel or by using the scripting\n " + instanceName + ".Tank = {<tankName>};"); } } return Burn::Validate(); }
//------------------------------------------------------------------------------ bool Burn::SetStringParameter(const Integer id, const std::string &value) { #ifdef DEBUG_BURN_SET MessageInterface::ShowMessage ("Burn::SetStringParameter() this=<%p> '%s', id=%d, value='%s'\n", this, GetName().c_str(), id, value.c_str()); #endif switch (id) { case COORDINATESYSTEM: coordSystemName = value; if (coordSystemName == "Local") usingLocalCoordSys = true; else usingLocalCoordSys = false; return true; case BURNORIGIN: localOriginName = value; #ifdef DEBUG_BURN_SET MessageInterface::ShowMessage ("Burn::SetStringParameter() exiting, localOriginName set to '%s'\n", value.c_str()); #endif return true; case BURNAXES: { localAxesName = value; // Do we need to determine Local CS here? // Yes, old ImpulsiveBurn script doesn't have CoordinateSystem field, // so Axes should be used to determine Local CS or not if (find(localAxesLabels.begin(), localAxesLabels.end(), localAxesName) != localAxesLabels.end()) { #ifdef DEBUG_BURN_SET MessageInterface::ShowMessage (" Local axes '%s' found, so setting coordSystemName to Local\n", localAxesName.c_str()); #endif if (usingLocalCoordSys) coordSystemName = "Local"; } else { // write one warning per GMAT session static bool firstTimeWarning = true; std::string framelist = localAxesLabels[0]; for (UnsignedInt n = 1; n < localAxesLabels.size(); ++n) framelist += ", " + localAxesLabels[n]; std::string msg = "The value of \"" + value + "\" for field \"Axes\"" " on object \"" + instanceName + "\" is not an allowed value.\n" "The allowed values are: [ " + framelist + " ]. "; if (firstTimeWarning) { firstTimeWarning = false; if (value == "Inertial") MessageInterface::ShowMessage("*** WARNING *** " + msg + "\n"); else throw BurnException(msg); } if (value == "Inertial") { coordSystemName = "EarthMJ2000Eq"; usingLocalCoordSys = false; } else throw BurnException(msg); } return true; } case VECTORFORMAT: // deprecated vectorFormat = value; return true; default: break; } return GmatBase::SetStringParameter(id, value); }
//------------------------------------------------------------------------------ // void ConvertDeltaVToInertial(Real *dv, Real *dvInertial, Real epoch) //------------------------------------------------------------------------------ void Burn::ConvertDeltaVToInertial(Real *dv, Real *dvInertial, Real epoch) { #ifdef DEBUG_BURN_CONVERT MessageInterface::ShowMessage ("Burn::ConvertDeltaVToInertial(), usingLocalCoordSys=%d, coordSystemName='%s', " "coordSystem=<%p>'%s'\n", usingLocalCoordSys, coordSystemName.c_str(), coordSystem, coordSystem ? coordSystem->GetName().c_str() : "NULL"); #endif if (usingLocalCoordSys && localCoordSystem == NULL) { throw BurnException ("Unable to convert burn elements to Inertial, the local Coordinate " "System has not been created"); } else if (!usingLocalCoordSys && coordSystem == NULL) { throw BurnException ("Unable to convert burn elements to Inertial, the Coordinate " "System has not been set"); } Real inDeltaV[6], outDeltaV[6]; for (Integer i=0; i<3; i++) inDeltaV[i] = dv[i]; for (Integer i=3; i<6; i++) inDeltaV[i] = 0.0; // if not using local CS, use ref CoordinateSystem if (!usingLocalCoordSys) { // Now rotate to MJ2000Eq axes, we don't want to translate so // set coincident to true coordSystem->ToBaseSystem(epoch, inDeltaV, outDeltaV, true); // @todo - need ToMJ2000Eq here? #ifdef DEBUG_BURN_CONVERT_ROTMAT Rmatrix33 rotMat = coordSystem->GetLastRotationMatrix(); MessageInterface::ShowMessage ("rotMat=\n%s\n", rotMat.ToString(16, 20).c_str()); #endif dvInertial[0] = outDeltaV[0]; dvInertial[1] = outDeltaV[1]; dvInertial[2] = outDeltaV[2]; } else { // if MJ2000Eq axes rotation matrix is always identity matrix if (isMJ2000EqAxes) { dvInertial[0] = dv[0]; dvInertial[1] = dv[1]; dvInertial[2] = dv[2]; } else if (isSpacecraftBodyAxes) { Rvector3 inDeltaV(dv[0], dv[1], dv[2]); Rvector3 outDeltaV; // Get attitude matrix from Spacecraft and transpose since // attitude matrix from spacecraft gives rotation matrix from // inertial to body Rmatrix33 inertialToBody = spacecraft->GetAttitude(epoch); Rmatrix33 rotMat = inertialToBody.Transpose(); #ifdef DEBUG_BURN_CONVERT_ROTMAT MessageInterface::ShowMessage ("for local Spacecraft body ----- rotMat=\n%s\n", rotMat.ToString(16, 20).c_str()); #endif outDeltaV = inDeltaV * rotMat; for (Integer i=0; i<3; i++) dvInertial[i] = outDeltaV[i]; } else { // // Now rotate to MJ2000Eq axes // localCoordSystem->ToMJ2000Eq(epoch, inDeltaV, outDeltaV, true); // Now rotate to base system axes localCoordSystem->ToBaseSystem(epoch, inDeltaV, outDeltaV, true); // @todo - need ToMJ2000Eq here? dvInertial[0] = outDeltaV[0]; dvInertial[1] = outDeltaV[1]; dvInertial[2] = outDeltaV[2]; } } #ifdef DEBUG_BURN_CONVERT MessageInterface::ShowMessage ("Burn::ConvertDeltaVToInertial() returning\n" " dv = %f %f %f\n dvInertial = %f %f %f\n", dv[0], dv[1], dv[2], dvInertial[0], dvInertial[1], dvInertial[2]); #endif }
//------------------------------------------------------------------------------ // CoordinateSystem* CreateLocalCoordinateSystem() //------------------------------------------------------------------------------ CoordinateSystem* Burn::CreateLocalCoordinateSystem() { #ifdef DEBUG_BURN_INIT MessageInterface::ShowMessage ("Burn::CreateLocalCoordinateSystem() '%s' entered, usingLocalCoordSys=%d, " "spacecraft=<%p>, solarSystem=<%p>\n", GetName().c_str(), usingLocalCoordSys, spacecraft, solarSystem); #endif // Why solarSystem gets NULL when running MMS script? // Added a check here for now (LOJ: 2009.04.22) if (solarSystem == NULL) { #ifdef DEBUG_BURN_INIT MessageInterface::ShowMessage ("*** WARNING *** Burn::CreateLocalCoordinateSystem() Unable to create local " "coordiante system, SolarSystem is NULL\n"); #endif throw BurnException ("*** WARNING *** Burn::CreateLocalCoordinateSystem() Unable to create " "local coordiante system, SolarSystem is NULL\n"); } CoordinateSystem *localCS = NULL; // If coordinate system being used is local, then create if (usingLocalCoordSys) { if (spacecraft == NULL) { // Since spacecraft is set later, just return NULL for now #ifdef DEBUG_BURN_INIT MessageInterface::ShowMessage ("Burn::CreateLocalCoordinateSystem() spacecraft is not set so, " "returning NULL\n"); #endif return NULL; //throw BurnException("Unable to initialize the Burn object " + // instanceName + " " + satName + " was not set for the burn."); } // Call CoordinateSystem static method to create a local coordinate system localOrigin = solarSystem->GetBody(localOriginName); localCS = CoordinateSystem::CreateLocalCoordinateSystem ("Local", localAxesName, spacecraft, localOrigin, spacecraft, j2000Body, solarSystem); if (localCS == NULL) return NULL; if (localAxesName == "MJ2000Eq") isMJ2000EqAxes = true; else if (localAxesName == "SpacecraftBody") isSpacecraftBodyAxes = true; } else { // If not using local cooordinate system, then it is using configured CS and // it should have been set by this time if (coordSystem) { throw BurnException ("Unable to initialize the Burn object " + instanceName + " " + coordSystemName + " was not set for the burn."); } localCS = coordSystem; } #ifdef DEBUG_BURN_INIT MessageInterface::ShowMessage ("Burn::CreateLocalCoordinateSystem() returning <%p>\n", localCS); #endif return localCS; }
//------------------------------------------------------------------------------ bool ImpulsiveBurn::Fire(Real *burnData, Real epoch, bool backwards) { #ifdef DEBUG_IMPBURN_FIRE MessageInterface::ShowMessage ("ImpulsiveBurn::Fire() <%p>'%s' entered\n", this, instanceName.c_str()); MessageInterface::ShowMessage (" deltaV: %18le %18le %18le\n", deltaV[0], deltaV[1], deltaV[2]); #endif #ifdef DEBUG_IMPBURN_FIRE MessageInterface::ShowMessage (" usingLocalCoordSys=%d, spacecraft=<%p>, " "localCoordSystem=<%p>\n", usingLocalCoordSys, spacecraft, localCoordSystem); #endif // By this time, the spacecraft should have been set if (usingLocalCoordSys && spacecraft == NULL) throw BurnException ("Unable to initialize the ImpulsiveBurn object " + instanceName + " " + satName + " was not set for the burn."); if (!isInitialized || localCoordSystem == NULL) { if (Initialize()) isInitialized = true; } if (epoch == GmatTimeConstants::MJD_OF_J2000) epoch = spacecraft->GetRealParameter("A1Epoch"); Real *satState = spacecraft->GetState().GetState(); // Update tank of the spacecraft if (decrementMass) SetTankFromSpacecraft(); #ifdef DEBUG_IMPBURN_FIRE MessageInterface::ShowMessage (" Maneuvering spacecraft %s\n", spacecraft->GetName().c_str()); MessageInterface::ShowMessage (" Position for burn: %18le %18le %18le\n", satState[0], satState[1], satState[2]); MessageInterface::ShowMessage (" Velocity before burn: %18le %18le %18le\n", satState[3], satState[4], satState[5]); #endif // The returned vector here is not rotated correctly because one of the bodies is not centered correctly ConvertDeltaVToInertial(deltaV, deltaVInertial, epoch); if (backwards) { // theDv is the burn we will apply, in the burn frame Real theV[3], trialBurn[3], endState[3]; theV[0] = satState[3]; theV[1] = satState[4]; theV[2] = satState[5]; // Seed the burn to be applied trialBurn[0] = -deltaVInertial[0]; trialBurn[1] = -deltaVInertial[1]; trialBurn[2] = -deltaVInertial[2]; // ConvertDeltaVToInertial(theDv, trialBurn, epoch); Real eps = 0.0, mag, tbMag; Integer count = 0; mag = sqrt(deltaV[0]*deltaV[0] + deltaV[1]*deltaV[1] + deltaV[2]*deltaV[2]); #ifdef DEBUG_BACKPROP MessageInterface::ShowMessage("BackProp Seed dv: [%lf %lf %lf]\n", trialBurn[0], trialBurn[1], trialBurn[2]); #endif // For BackProp, iterate the coordinate system conversion do { if (eps != 0.0) // After the first pass through... { // Reset spacecraft V satState[3] = theV[0]; satState[4] = theV[1]; satState[5] = theV[2]; // Calc how different achieved was from desired trialBurn[0] += satState[3] - endState[0]; trialBurn[1] += satState[4] - endState[1]; trialBurn[2] += satState[5] - endState[2]; // Apply dV with right mag in the adjusted direction tbMag = sqrt(trialBurn[0]*trialBurn[0] + trialBurn[1]*trialBurn[1] + trialBurn[2]*trialBurn[2]); trialBurn[0] *= mag/tbMag; trialBurn[1] *= mag/tbMag; trialBurn[2] *= mag/tbMag; } #ifdef DEBUG_BACKPROP MessageInterface::ShowMessage("%d dv: [%lf %lf %lf]\n", count, trialBurn[0], trialBurn[1], trialBurn[2]); #endif satState[3] += trialBurn[0]; satState[4] += trialBurn[1]; satState[5] += trialBurn[2]; // Now apply the forward burn ConvertDeltaVToInertial(deltaV, deltaVInertial, epoch); endState[0] = satState[3] + deltaVInertial[0]; endState[1] = satState[4] + deltaVInertial[1]; endState[2] = satState[5] + deltaVInertial[2]; // and see how different it is from the starting velocity eps = fabs(theV[0] - endState[0]) + fabs(theV[1] - endState[1]) + fabs(theV[2] - endState[2]); ++count; #ifdef DEBUG_BACKPROP MessageInterface::ShowMessage("%d: eps = %le\n", count, eps); #endif } while ((eps > BACKPROP_PRECISION) && (count < BACKPROP_ITERATIONS)); if (count == BACKPROP_ITERATIONS) { MessageInterface::ShowMessage("Warning!!! Maneuver BackProp did not " "converge to a solution that inverts the forward maneuver in " "direction,\nso the raw maneuver has been applied for the " "ImpulsiveBurn %s\n", instanceName.c_str()); satState[3] = theV[0] - deltaVInertial[0]; satState[4] = theV[1] - deltaVInertial[1]; satState[5] = theV[2] - deltaVInertial[2]; } } else { #ifdef DEBUG_BACKPROP MessageInterface::ShowMessage("FrwdProp used dv: [%lf %lf %lf]\n", deltaVInertial[0], deltaVInertial[1], deltaVInertial[2]); #endif satState[3] += deltaVInertial[0]; satState[4] += deltaVInertial[1]; satState[5] += deltaVInertial[2]; } #ifdef DEBUG_IMPBURN_FIRE MessageInterface::ShowMessage (" Velocity after burn: %18le %18le %18le\n", satState[3], satState[4], satState[5]); MessageInterface::ShowMessage (" %s tank mass computation\n", decrementMass ? "Continue with " : "Skipping"); #endif if (decrementMass) DecrementMass(backwards); #ifdef DEBUG_IMPBURN_FIRE MessageInterface::ShowMessage("ImpulsiveBurn::Fire() returning true\n"); #endif hasFired = true; epochAtLastFire = epoch; return true; }
//------------------------------------------------------------------------------ // void DecrementMass() //------------------------------------------------------------------------------ void ImpulsiveBurn::DecrementMass(bool backwards) { #ifdef DEBUG_IMPBURN_DECMASS MessageInterface::ShowMessage ("ImpulsiveBurn::DecrementMass() <%p>'%s' entered. There are %d tank(s)\n", this, instanceName.c_str(), tankMap.size()); #endif totalTankMass = spacecraft->GetRealParameter("TotalMass"); #ifdef DEBUG_IMPBURN_DECMASS MessageInterface::ShowMessage (" Now decrementing mass\n before maneuver totalTankMass = %f\n", totalTankMass); #endif Real dv = sqrt( deltaV[0]*deltaV[0] + deltaV[1]*deltaV[1] + deltaV[2]*deltaV[2]); if (!backwards) deltaTankMass = totalTankMass * (exp(-dv * 1000/(isp * gravityAccel)) - 1.0); else deltaTankMass = totalTankMass * (exp(dv * 1000/(isp * gravityAccel)) - 1.0); #ifdef DEBUG_IMPBURN_DECMASS MessageInterface::ShowMessage (" after maneuver deltaTankMass = %f\n", deltaTankMass); #endif totalTankMass = totalTankMass + deltaTankMass; #ifdef DEBUG_IMPBURN_DECMASS MessageInterface::ShowMessage (" after maneuver totalTankMass = %f\n", totalTankMass); #endif // Update tank mass if (!tankMap.empty()) { if (tankMap.size() > 1) throw BurnException("The ImpulsiveBorn object " + instanceName + " is configured to draw mass from multiple tanks, but only one " "tank is supported in the current implementation."); // This code is set up to draw from multiple tanks, but the amount drawn // is not calculated to draw proportionally. Instead, it reduces each // tank by deltaTankMass. We need to check this code before enabling // mass reduction from multiple tanks in a single impulsive burn. for (ObjectMap::iterator tankPos = tankMap.begin(); tankPos != tankMap.end(); ++tankPos) { GmatBase *currTank = tankPos->second; #ifdef DEBUG_IMPBURN_DECMASS MessageInterface::ShowMessage (" Decrementing tank mass for <%p>'%s'\n", currTank, (tankPos->first).c_str()); #endif Integer paramID = currTank->GetParameterID("FuelMass"); Real oldTankMass = currTank->GetRealParameter(paramID); Real currTankMass = oldTankMass + deltaTankMass; #ifdef DEBUG_IMPBURN_DECMASS MessageInterface::ShowMessage (" it was %f, it is now %f\n", oldTankMass, currTankMass); #endif //@todo What should we do if decremented tank mass is below zero? currTank->SetRealParameter(paramID, currTankMass); } } else throw BurnException("Impulsive Burn " + instanceName + " is set to decrement mass from a tank named " + tankNames[0] + ", but the Spacecraft " + spacecraft->GetName() + " does not have the selected fuel tank."); #ifdef DEBUG_IMPBURN_DECMASS MessageInterface::ShowMessage ("ImpulsiveBurn::DecrementMass() <%p>'%s' returning\n", this, GetName().c_str()); #endif }
//------------------------------------------------------------------------------ // bool SetTankFromSpacecraft() //------------------------------------------------------------------------------ bool ImpulsiveBurn::SetTankFromSpacecraft() { #ifdef DEBUG_IMPBURN_SET MessageInterface::ShowMessage ("ImpulsiveBurn::SetTankFromSpacecraft() entered, spacecraft=<%p>'%s'\n", spacecraft, spacecraft ? spacecraft->GetName().c_str() : "NULL"); MessageInterface::ShowMessage(" tankNames.size()=%d\n", tankNames.size()); #endif if (spacecraft == NULL) return false; if (tankNames.empty()) throw BurnException("ImpulsiveBurn::Initialize() " + instanceName + " has no associated tank"); ObjectArray tankArray = spacecraft->GetRefObjectArray(Gmat::FUEL_TANK); #ifdef DEBUG_IMPBURN_SET MessageInterface::ShowMessage (" spacecraft tankArray.size()=%d\n", tankArray.size()); #endif if (!tankNames.empty() && !tankArray.empty()) { ObjectArray::iterator scTank = tankArray.begin(); // Find the tank on the spacecraft for (StringArray::iterator tankName = tankNames.begin(); tankName != tankNames.end(); ++tankName) { while (scTank != tankArray.end()) { #ifdef DEBUG_IMPBURN_SET MessageInterface::ShowMessage (" The tank '%s' associated with spacecraft is <%p>'%s'\n", (*tankName).c_str(), (*scTank), (*scTank) ? (*scTank)->GetName().c_str() : "NULL"); #endif // Just in case, check for NULL tank pointer if (*scTank == NULL) continue; // Assign the tank if ((*scTank)->GetName() == *tankName) { tankMap[*tankName] = (*scTank); #ifdef DEBUG_IMPBURN_SET MessageInterface::ShowMessage (" Assigned <%p>'%s' to tankMap\n", *scTank, (*tankName).c_str()); #endif } ++scTank; } } if (tankNames.size() != tankMap.size()) throw BurnException("The impulsive burn " + instanceName + " could not find the fuel tank needed to deplete mass; please " "attach the tank to the spacecraft " + spacecraft->GetName() + " or turn off mass depletion."); } #ifdef DEBUG_IMPBURN_SET MessageInterface::ShowMessage ("ImpulsiveBurn::SetTankFromSpacecraft() returning true\n"); #endif return true; }
//------------------------------------------------------------------------------ bool ImpulsiveBurn::Fire(Real *burnData, Real epoch) { #ifdef DEBUG_IMPBURN_FIRE MessageInterface::ShowMessage (wxT("ImpulsiveBurn::Fire() <%p>'%s' entered\n"), this, instanceName.c_str()); MessageInterface::ShowMessage (wxT(" deltaV: %18le %18le %18le\n"), deltaV[0], deltaV[1], deltaV[2]); #endif #ifdef DEBUG_IMPBURN_FIRE MessageInterface::ShowMessage (wxT(" usingLocalCoordSys=%d, spacecraft=<%p>, initialized=%d, ") wxT("localCoordSystem=<%p>\n"), usingLocalCoordSys, spacecraft, initialized, localCoordSystem); #endif // By this time, the spacecraft should have been set if (usingLocalCoordSys && spacecraft == NULL) throw BurnException (wxT("Unable to initialize the ImpulsiveBurn object ") + instanceName + wxT(" ") + satName + wxT(" was not set for the burn.")); if (!initialized || localCoordSystem == NULL) { if (Initialize()) initialized = true; } if (epoch == GmatTimeConstants::MJD_OF_J2000) epoch = spacecraft->GetRealParameter(wxT("A1Epoch")); Real *satState = spacecraft->GetState().GetState(); // Update tank of the spacecraft if (decrementMass) SetTankFromSpacecraft(); #ifdef DEBUG_IMPBURN_FIRE MessageInterface::ShowMessage (wxT(" Maneuvering spacecraft %s\n"), spacecraft->GetName().c_str()); MessageInterface::ShowMessage (wxT(" Position for burn: %18le %18le %18le\n"), satState[0], satState[1], satState[2]); MessageInterface::ShowMessage (wxT(" Velocity before burn: %18le %18le %18le\n"), satState[3], satState[4], satState[5]); #endif // The returned vector here is not rotated correctly because one of the bodies is not centered correctly ConvertDeltaVToInertial(deltaV, deltaVInertial, epoch); satState[3] += deltaVInertial[0]; satState[4] += deltaVInertial[1]; satState[5] += deltaVInertial[2]; #ifdef DEBUG_IMPBURN_FIRE MessageInterface::ShowMessage (wxT(" Velocity after burn: %18le %18le %18le\n"), satState[3], satState[4], satState[5]); MessageInterface::ShowMessage (wxT(" %s tank mass computation\n"), decrementMass ? wxT("Continue with ") : wxT("Skipping")); #endif if (decrementMass) DecrementMass(); #ifdef DEBUG_IMPBURN_FIRE MessageInterface::ShowMessage(wxT("ImpulsiveBurn::Fire() returning true\n")); #endif return true; }
//------------------------------------------------------------------------------ // bool SetThrustersFromSpacecraft() //------------------------------------------------------------------------------ bool FiniteBurn::SetThrustersFromSpacecraft() { #ifdef DEBUG_FINITEBURN_SET MessageInterface::ShowMessage ("FiniteBurn::SetThrustersFromSpacecraft() entered, spacecraft=<%p>'%s'\n", spacecraft, spacecraft ? spacecraft->GetName().c_str() : "NULL"); MessageInterface::ShowMessage(" thrusterNames.size()=%d\n", thrusterNames.size()); #endif // Get thrusters and tanks associated to spacecraft ObjectArray thrusterArray = spacecraft->GetRefObjectArray(Gmat::THRUSTER); ObjectArray tankArray = spacecraft->GetRefObjectArray(Gmat::FUEL_TANK); // Look up the thruster(s) for (ObjectArray::iterator th = thrusterArray.begin(); th != thrusterArray.end(); ++th) { for (StringArray::iterator thName = thrusterNames.begin(); thName != thrusterNames.end(); ++thName) { // Only act on thrusters assigned to this burn if ((*th)->GetName() == *thName) { Integer paramId = (*th)->GetParameterID("Tank"); StringArray tankNames = (*th)->GetStringArrayParameter(paramId); // Setup the tankNames (*th)->TakeAction("ClearTankNames"); // Loop through each tank for the burn for (StringArray::iterator tankName = tankNames.begin(); tankName != tankNames.end(); ++tankName) { ObjectArray::iterator tnk = tankArray.begin(); // Find the tank on the spacecraft while (tnk != tankArray.end()) { if ((*tnk)->GetName() == *tankName) { // Make the assignment (*th)->SetStringParameter("Tank", *tankName); (*th)->SetRefObject(*tnk, (*tnk)->GetType(), (*tnk)->GetName()); break; } // Not found; keep looking ++tnk; if (tnk == tankArray.end()) throw BurnException ("FiniteBurn::Initialize() cannot find tank " + (*tankName) + " for burn " + instanceName); } } } } } #ifdef DEBUG_FINITEBURN_SET MessageInterface::ShowMessage ("FiniteBurn::SetThrustersFromSpacecraft() returning true\n"); #endif return true; }
//------------------------------------------------------------------------------ bool FiniteBurn::Fire(Real *burnData, Real epoch) { #ifdef DEBUG_FINITEBURN_FIRE MessageInterface::ShowMessage ("FiniteBurn::Fire() this<%p>'%s' entered, epoch=%f, spacecraft=<%p>'%s'\n", this, instanceName.c_str(), epoch, spacecraft, spacecraft ? spacecraft->GetName().c_str() : "NULL"); #endif if (isInitialized == false) Initialize(); if (!spacecraft) throw BurnException("Maneuver initial state undefined (No spacecraft?)"); // Accumulate the individual accelerations from the thrusters Real dm = 0.0, tMass, tOverM, *dir, norm; deltaV[0] = deltaV[1] = deltaV[2] = 0.0; Thruster *current; tMass = spacecraft->GetRealParameter("TotalMass"); #ifdef DEBUG_BURN_ORIGIN Real *satState = spacecraft->GetState().GetState(); MessageInterface::ShowMessage ("FiniteBurn Vectors:\n " "Sat = [%.15f %.15f %.15f %.15f %.15f %.15f]\n " "Frame = [%.15f %.15f %.15f\n " " %.15f %.15f %.15f\n " " %.15f %.15f %.15f]\n\n", satState[0], satState[1], satState[2], satState[3], satState[4], satState[5], frameBasis[0][0], frameBasis[0][1], frameBasis[0][2], frameBasis[1][0], frameBasis[1][1], frameBasis[1][2], frameBasis[2][0], frameBasis[2][1], frameBasis[2][2]); #endif for (StringArray::iterator i = thrusterNames.begin(); i != thrusterNames.end(); ++i) { #ifdef DEBUG_FINITE_BURN MessageInterface::ShowMessage (" Accessing thruster '%s' from spacecraft <%p>'%s'\n", (*i).c_str(), spacecraft, spacecraft->GetName().c_str()); #endif current = (Thruster *)spacecraft->GetRefObject(Gmat::THRUSTER, *i); if (!current) throw BurnException("FiniteBurn::Fire requires thruster named \"" + (*i) + "\" on spacecraft " + spacecraft->GetName()); // Save current thruster so that GetRefObject() can return it (LOJ: 2009.08.28) thrusterMap[current->GetName()] = current; // FiniteBurn class is friend of Thruster class, so we can access // member data directly current->ComputeInertialDirection(epoch); dir = current->inertialDirection; norm = sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]); #ifdef DEBUG_FINITE_BURN MessageInterface::ShowMessage (" Thruster Direction: %.15f %.15f %.15f\n" " norm: %.15f\n", dir[0], dir[1], dir[2], norm); #endif if (norm == 0.0) throw BurnException("FiniteBurn::Fire thruster " + (*i) + " on spacecraft " + spacecraft->GetName() + " has no direction."); dm += current->CalculateMassFlow(); //tOverM = current->thrust / (tMass * norm * 1000.0); //old code tOverM = current->thrust * current->thrustScaleFactor * current->dutyCycle / (tMass * norm * 1000.0); deltaV[0] += dir[0] * tOverM; deltaV[1] += dir[1] * tOverM; deltaV[2] += dir[2] * tOverM; #ifdef DEBUG_FINITE_BURN MessageInterface::ShowMessage(" Thruster %s = %s details:\n", (*i).c_str(), current->GetName().c_str()); MessageInterface::ShowMessage( " thrust = %.15f\n" " dM = %.15e\n Mass = %.15f\n" " TSF = %.15f\n |Acc| = %.15e\n " "Acc = [%.15e %.15e %.15e]\n", current->thrust, dm, tMass, current->thrustScaleFactor, tOverM, deltaV[0], deltaV[1], deltaV[2]); #endif } // Build the acceleration burnData[0] = deltaV[0]*frameBasis[0][0] + deltaV[1]*frameBasis[0][1] + deltaV[2]*frameBasis[0][2]; burnData[1] = deltaV[0]*frameBasis[1][0] + deltaV[1]*frameBasis[1][1] + deltaV[2]*frameBasis[1][2]; burnData[2] = deltaV[0]*frameBasis[2][0] + deltaV[1]*frameBasis[2][1] + deltaV[2]*frameBasis[2][2]; burnData[3] = dm; #ifdef DEBUG_FINITEBURN_FIRE MessageInterface::ShowMessage( "FiniteBurn::Fire() this<%p>'%s' returning\n" " Acceleration: %.15e %.15e %.15e dm: %.15e\n", this, GetName().c_str(), burnData[0], burnData[1], burnData[2], dm); #endif hasFired = true; epochAtLastFire = epoch; return true; }