diff --git a/src/FDM/JSBSim/FGFDMExec.cpp b/src/FDM/JSBSim/FGFDMExec.cpp index 227c0267f..685122381 100644 --- a/src/FDM/JSBSim/FGFDMExec.cpp +++ b/src/FDM/JSBSim/FGFDMExec.cpp @@ -94,7 +94,8 @@ void checkTied ( FGPropertyManager *node ) for (int i=0; igetChild(i)->nChildren() ) { checkTied( (FGPropertyManager*)node->getChild(i) ); - } else if ( node->getChild(i)->isTied() ) { + } + if ( node->getChild(i)->isTied() ) { name = ((FGPropertyManager*)node->getChild(i))->GetFullyQualifiedName(); node->Untie(name); } @@ -108,7 +109,6 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root) { Frame = 0; - FirstModel = 0; Error = 0; GroundCallback = 0; State = 0; @@ -221,30 +221,11 @@ bool FGFDMExec::Allocate(void) // class needs valid pointers to the above // model classes - // Initialize models so they can communicate with each other - - Atmosphere->InitModel(); - FCS->InitModel(); - Propulsion->InitModel(); - MassBalance->InitModel(); - Aerodynamics->InitModel(); - Inertial->InitModel(); - GroundReactions->InitModel(); - ExternalReactions->InitModel(); - BuoyantForces->InitModel(); - Aircraft->InitModel(); - Propagate->InitModel(); - Auxiliary->InitModel(); - Input->InitModel(); - - IC = new FGInitialCondition(this); - // Schedule a model. The second arg (the integer) is the pass number. For - // instance, the atmosphere model could get executed every fifth pass it is called - // by the executive. IC and Trim objects are NOT scheduled. - + // instance, the atmosphere model could get executed every fifth pass it is called. + Schedule(Input, 1); - Schedule(Atmosphere, 1); + Schedule(Atmosphere, 30); Schedule(FCS, 1); Schedule(Propulsion, 1); Schedule(MassBalance, 1); @@ -257,6 +238,13 @@ bool FGFDMExec::Allocate(void) Schedule(Propagate, 1); Schedule(Auxiliary, 1); + // Initialize models so they can communicate with each other + + vector ::iterator it; + for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel(); + + IC = new FGInitialCondition(this); + modelLoaded = false; return result; @@ -290,7 +278,6 @@ bool FGFDMExec::DeAllocate(void) delete GroundCallback; - FirstModel = 0L; Error = 0; State = 0; @@ -309,35 +296,18 @@ bool FGFDMExec::DeAllocate(void) Auxiliary = 0; Script = 0; + Models.clear(); + modelLoaded = false; return modelLoaded; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -int FGFDMExec::Schedule(FGModel* model, int rate) +void FGFDMExec::Schedule(FGModel* model, int rate) { - FGModel* model_iterator; - - model_iterator = FirstModel; - - if (model_iterator == 0L) { // this is the first model - - FirstModel = model; - FirstModel->NextModel = 0L; - FirstModel->SetRate(rate); - - } else { // subsequent model - - while (model_iterator->NextModel != 0L) { - model_iterator = model_iterator->NextModel; - } - model_iterator->NextModel = model; - model_iterator->NextModel->SetRate(rate); - - } - - return 0; + model->SetRate(rate); + Models.push_back(model); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -345,10 +315,6 @@ int FGFDMExec::Schedule(FGModel* model, int rate) bool FGFDMExec::Run(void) { bool success=true; - FGModel* model_iterator; - - model_iterator = FirstModel; - if (model_iterator == 0L) return false; Debug(2); @@ -357,14 +323,11 @@ bool FGFDMExec::Run(void) ChildFDMList[i]->Run(); } - // returns true if success - // false if complete + // returns true if success, false if complete if (Script != 0 && !State->IntegrationSuspended()) success = Script->RunScript(); - while (model_iterator != 0L) { - model_iterator->Run(); - model_iterator = model_iterator->NextModel; - } + vector ::iterator it; + for (it = Models.begin(); it != Models.end(); ++it) (*it)->Run(); Frame++; if (!Holding()) State->IncrTime(); @@ -406,15 +369,10 @@ void FGFDMExec::ResetToInitialConditions(int mode) void FGFDMExec::ResetToInitialConditions(void) { - FGModel* model_iterator; + if (Constructing) return; - model_iterator = FirstModel; - if (model_iterator == 0L || Constructing) return; - - while (model_iterator != 0L) { - model_iterator->InitModel(); - model_iterator = model_iterator->NextModel; - } + vector ::iterator it; + for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel(); RunIC(); if (Script) Script->ResetEvents(); diff --git a/src/FDM/JSBSim/FGFDMExec.h b/src/FDM/JSBSim/FGFDMExec.h index 5e1ee0719..c1fbbb8ef 100644 --- a/src/FDM/JSBSim/FGFDMExec.h +++ b/src/FDM/JSBSim/FGFDMExec.h @@ -222,7 +222,7 @@ public: @param model A pointer to the model being scheduled. @param rate The rate at which to execute the model as described above. @return Currently returns 0 always. */ - int Schedule(FGModel* model, int rate); + void Schedule(FGModel* model, int rate); /** This function executes each scheduled model in succession. @return true if successful, false if sim should be ended */ @@ -488,7 +488,6 @@ private: static FGPropertyManager *master; - FGModel* FirstModel; FGGroundCallback* GroundCallback; FGState* State; FGAtmosphere* Atmosphere; @@ -514,6 +513,7 @@ private: vector PropertyCatalog; vector Outputs; vector ChildFDMList; + vector Models; bool ReadFileHeader(Element*); bool ReadChild(Element*); diff --git a/src/FDM/JSBSim/math/FGFunction.cpp b/src/FDM/JSBSim/math/FGFunction.cpp index 1db1e6aec..e45e6d9aa 100755 --- a/src/FDM/JSBSim/math/FGFunction.cpp +++ b/src/FDM/JSBSim/math/FGFunction.cpp @@ -31,6 +31,7 @@ INCLUDES #include #include #include +#include #include "FGFunction.h" #include "FGTable.h" #include "FGPropertyValue.h" @@ -56,6 +57,7 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr string operation, property_name; cached = false; cachedValue = -HUGE_VAL; + invlog2val = 1.0/log10(2.0); property_string = "property"; value_string = "value"; @@ -72,6 +74,9 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr quotient_string = "quotient"; pow_string = "pow"; exp_string = "exp"; + log2_string = "log2"; + ln_string = "ln"; + log10_string = "log10"; abs_string = "abs"; sin_string = "sin"; cos_string = "cos"; @@ -103,6 +108,12 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr Type = eQuotient; } else if (operation == pow_string) { Type = ePow; + } else if (operation == log2_string) { + Type = eLog2; + } else if (operation == ln_string) { + Type = eLn; + } else if (operation == log10_string) { + Type = eLog10; } else if (operation == abs_string) { Type = eAbs; } else if (operation == sin_string) { @@ -174,6 +185,9 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr operation == quotient_string || operation == pow_string || operation == exp_string || + operation == log2_string || + operation == ln_string || + operation == log10_string || operation == abs_string || operation == sin_string || operation == cos_string || @@ -259,6 +273,18 @@ double FGFunction::GetValue(void) const case eExp: temp = exp(temp); break; + case eLog2: + if (temp > 0.00) temp = log10(temp)*invlog2val; + else temp = -HUGE_VAL; + break; + case eLn: + if (temp > 0.00) temp = log(temp); + else temp = -HUGE_VAL; + break; + case eLog10: + if (temp > 0.00) temp = log10(temp); + else temp = -HUGE_VAL; + break; case eAbs: temp = fabs(temp); break; @@ -335,7 +361,12 @@ string FGFunction::GetValueAsString(void) const void FGFunction::bind(void) { if ( !Name.empty() ) { - string tmp = PropertyManager->mkPropertyName(Prefix + Name, false); // Allow upper case + string tmp; + if (Prefix.empty()) + tmp = PropertyManager->mkPropertyName(Name, false); // Allow upper case + else + tmp = PropertyManager->mkPropertyName(Prefix + "/" + Name, false); // Allow upper case + PropertyManager->Tie( tmp, this, &FGFunction::GetValue); } } diff --git a/src/FDM/JSBSim/math/FGFunction.h b/src/FDM/JSBSim/math/FGFunction.h index 4c67ba46e..d122ffe20 100755 --- a/src/FDM/JSBSim/math/FGFunction.h +++ b/src/FDM/JSBSim/math/FGFunction.h @@ -70,6 +70,9 @@ A function definition consists of an operation, a value, a table, or a property - quotient (takes 2 args) - pow (takes 2 args) - exp (takes 2 args) +- log2 (takes 1 arg) +- ln (takes 1 arg) +- log10 (takes 1 arg) - abs (takes n args) - sin (takes 1 arg) - cos (takes 1 arg) @@ -193,6 +196,7 @@ private: std::vector Parameters; FGPropertyManager* const PropertyManager; bool cached; + double invlog2val; std::string Prefix; std::string description_string; std::string property_string; @@ -208,6 +212,9 @@ private: std::string quotient_string; std::string pow_string; std::string exp_string; + std::string log2_string; + std::string ln_string; + std::string log10_string; std::string abs_string; std::string sin_string; std::string cos_string; @@ -226,7 +233,7 @@ private: double cachedValue; enum functionType {eTopLevel=0, eProduct, eDifference, eSum, eQuotient, ePow, eExp, eAbs, eSin, eCos, eTan, eASin, eACos, eATan, eATan2, - eMin, eMax, eAvg, eFrac, eInteger, eMod, eRandom} Type; + eMin, eMax, eAvg, eFrac, eInteger, eMod, eRandom, eLog2, eLn, eLog10} Type; std::string Name; void bind(void); void Debug(int from); diff --git a/src/FDM/JSBSim/math/FGMatrix33.cpp b/src/FDM/JSBSim/math/FGMatrix33.cpp index 8f27e88a5..5eccfdfce 100644 --- a/src/FDM/JSBSim/math/FGMatrix33.cpp +++ b/src/FDM/JSBSim/math/FGMatrix33.cpp @@ -39,6 +39,8 @@ INCLUDES #include "FGMatrix33.h" #include "FGColumnVector3.h" +#include +#include #include @@ -65,6 +67,23 @@ FGMatrix33::FGMatrix33(void) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +string FGMatrix33::Dump(const string& delimiter) const +{ + ostringstream buffer; + buffer << std::setw(18) << std::setprecision(16) << Entry(1,1) << delimiter; + buffer << std::setw(18) << std::setprecision(16) << Entry(1,2) << delimiter; + buffer << std::setw(18) << std::setprecision(16) << Entry(1,3) << delimiter; + buffer << std::setw(18) << std::setprecision(16) << Entry(2,1) << delimiter; + buffer << std::setw(18) << std::setprecision(16) << Entry(2,2) << delimiter; + buffer << std::setw(18) << std::setprecision(16) << Entry(2,3) << delimiter; + buffer << std::setw(18) << std::setprecision(16) << Entry(3,1) << delimiter; + buffer << std::setw(18) << std::setprecision(16) << Entry(3,2) << delimiter; + buffer << std::setw(18) << std::setprecision(16) << Entry(3,3); + return buffer.str(); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + ostream& operator<<(ostream& os, const FGMatrix33& M) { for (unsigned int i=1; i<=M.Rows(); i++) { diff --git a/src/FDM/JSBSim/math/FGMatrix33.h b/src/FDM/JSBSim/math/FGMatrix33.h index a31e05d88..d07687ea9 100644 --- a/src/FDM/JSBSim/math/FGMatrix33.h +++ b/src/FDM/JSBSim/math/FGMatrix33.h @@ -158,6 +158,11 @@ public: */ ~FGMatrix33(void) { Debug(1); } + /** Prints the contents of the matrix. + @param delimeter the item separator (tab or comma) + @return a string with the delimeter-separated contents of the matrix */ + std::string Dump(const std::string& delimeter) const; + /** Read access the entries of the matrix. @param row Row index. @param col Column index. diff --git a/src/FDM/JSBSim/models/FGAerodynamics.cpp b/src/FDM/JSBSim/models/FGAerodynamics.cpp index 5083bf7bc..ab2381ce4 100644 --- a/src/FDM/JSBSim/models/FGAerodynamics.cpp +++ b/src/FDM/JSBSim/models/FGAerodynamics.cpp @@ -108,9 +108,6 @@ FGAerodynamics::~FGAerodynamics() delete[] Coeff; - for (i=0; iHolding()) return false; // if paused don't execute + RunPreFunctions(); + // calculate some oft-used quantities for speed twovel = 2*Auxiliary->GetVt(); @@ -173,13 +172,6 @@ bool FGAerodynamics::Run(void) vFw.InitMatrix(); vFnative.InitMatrix(); - // Tell the variable functions to cache their values, so while the aerodynamic - // functions are being calculated for each axis, these functions do not get - // calculated each time, but instead use the values that have already - // been calculated for this frame. - - for (i=0; icacheValue(true); - for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) { for (ctr=0; ctr < Coeff[axis_ctr].size(); ctr++) { vFnative(axis_ctr+1) += Coeff[axis_ctr][ctr]->GetValue(); @@ -233,6 +225,8 @@ bool FGAerodynamics::Run(void) } } + RunPostFunctions(); + return false; } @@ -324,7 +318,7 @@ bool FGAerodynamics::Load(Element *element) document = element; } - FGModel::Load(element); // Perform base class Load + FGModel::Load(element); // Perform base class Pre-Load DetermineAxisSystem(); // Detemine if Lift/Side/Drag, etc. is used. @@ -349,12 +343,6 @@ bool FGAerodynamics::Load(Element *element) AeroRPShift = new FGFunction(PropertyManager, function_element); } - function_element = document->FindElement("function"); - while (function_element) { - variables.push_back( new FGFunction(PropertyManager, function_element) ); - function_element = document->FindNextElement("function"); - } - axis_element = document->FindElement("axis"); while (axis_element) { CoeffArray ca; @@ -368,6 +356,8 @@ bool FGAerodynamics::Load(Element *element) axis_element = document->FindNextElement("axis"); } + FGModel::PostLoad(element); // Perform base class Post-Load + return true; } @@ -427,15 +417,6 @@ string FGAerodynamics::GetCoefficientStrings(const string& delimeter) const bool firstime = true; unsigned int axis, sd; - for (sd = 0; sd < variables.size(); sd++) { - if (firstime) { - firstime = false; - } else { - CoeffStrings += delimeter; - } - CoeffStrings += variables[sd]->GetName(); - } - for (axis = 0; axis < 6; axis++) { for (sd = 0; sd < Coeff[axis].size(); sd++) { if (firstime) { @@ -455,12 +436,6 @@ string FGAerodynamics::GetCoefficientValues(const string& delimeter) const { ostringstream buf; - buf.precision(6); - for (unsigned int sd = 0; sd < variables.size(); sd++) { - if (buf.tellp() > 0) buf << delimeter; - buf << setw(9) << variables[sd]->GetValue(); - } - for (unsigned int axis = 0; axis < 6; axis++) { for (unsigned int sd = 0; sd < Coeff[axis].size(); sd++) { if (buf.tellp() > 0) buf << delimeter; diff --git a/src/FDM/JSBSim/models/FGAircraft.cpp b/src/FDM/JSBSim/models/FGAircraft.cpp index 83a1bf177..75f9fba59 100644 --- a/src/FDM/JSBSim/models/FGAircraft.cpp +++ b/src/FDM/JSBSim/models/FGAircraft.cpp @@ -114,6 +114,8 @@ bool FGAircraft::Run(void) if (FGModel::Run()) return true; if (FDMExec->Holding()) return false; + RunPreFunctions(); + vForces.InitMatrix(); if (!HoldDown) { vForces += Aerodynamics->GetForces(); @@ -139,6 +141,8 @@ bool FGAircraft::Run(void) vNwcg = Aerodynamics->GetTb2w() * vNcg; vNwcg(3) = -1*vNwcg(3) + 1; + RunPostFunctions(); + return false; } @@ -199,6 +203,8 @@ bool FGAircraft::Load(Element* el) } } + FGModel::PostLoad(el); + Debug(2); return true; diff --git a/src/FDM/JSBSim/models/FGAtmosphere.cpp b/src/FDM/JSBSim/models/FGAtmosphere.cpp index c21e45cbc..8acb17c1b 100644 --- a/src/FDM/JSBSim/models/FGAtmosphere.cpp +++ b/src/FDM/JSBSim/models/FGAtmosphere.cpp @@ -139,6 +139,8 @@ bool FGAtmosphere::Run(void) if (FGModel::Run()) return true; if (FDMExec->Holding()) return false; + RunPreFunctions(); + T_dev = 0.0; h = Propagate->GetAltitudeASL(); @@ -149,6 +151,8 @@ bool FGAtmosphere::Run(void) CalculateDerived(); } + RunPostFunctions(); + Debug(2); return false; } diff --git a/src/FDM/JSBSim/models/FGAuxiliary.cpp b/src/FDM/JSBSim/models/FGAuxiliary.cpp index d8a8d77c0..815a1b400 100755 --- a/src/FDM/JSBSim/models/FGAuxiliary.cpp +++ b/src/FDM/JSBSim/models/FGAuxiliary.cpp @@ -142,6 +142,8 @@ bool FGAuxiliary::Run() if (FGModel::Run()) return true; // return true if error returned from base class if (FDMExec->Holding()) return false; + RunPreFunctions(); + const FGColumnVector3& vPQR = Propagate->GetPQR(); const FGColumnVector3& vUVW = Propagate->GetUVW(); const FGColumnVector3& vUVWdot = Propagate->GetUVWdot(); @@ -290,6 +292,8 @@ bool FGAuxiliary::Run() CalculateRelativePosition(); + RunPostFunctions(); + return false; } diff --git a/src/FDM/JSBSim/models/FGBuoyantForces.cpp b/src/FDM/JSBSim/models/FGBuoyantForces.cpp index 44ecd6595..49d9cb2e5 100644 --- a/src/FDM/JSBSim/models/FGBuoyantForces.cpp +++ b/src/FDM/JSBSim/models/FGBuoyantForces.cpp @@ -95,6 +95,8 @@ bool FGBuoyantForces::Run(void) if (FDMExec->Holding()) return false; // if paused don't execute if (NoneDefined) return true; + RunPreFunctions(); + vTotalForces.InitMatrix(); vTotalMoments.InitMatrix(); @@ -104,6 +106,8 @@ bool FGBuoyantForces::Run(void) vTotalMoments += Cells[i]->GetMoments(); } + RunPostFunctions(); + return false; } @@ -135,6 +139,8 @@ bool FGBuoyantForces::Load(Element *element) gas_cell_element = document->FindNextElement("gas_cell"); } + FGModel::PostLoad(element); + return true; } diff --git a/src/FDM/JSBSim/models/FGExternalReactions.cpp b/src/FDM/JSBSim/models/FGExternalReactions.cpp index 58a334364..a9b6ee275 100755 --- a/src/FDM/JSBSim/models/FGExternalReactions.cpp +++ b/src/FDM/JSBSim/models/FGExternalReactions.cpp @@ -85,6 +85,8 @@ bool FGExternalReactions::Load(Element* el) force_element = el->FindNextElement("force"); } + FGModel::PostLoad(el); + return true; } @@ -115,6 +117,8 @@ bool FGExternalReactions::Run() if (FDMExec->Holding()) return false; // if paused don't execute if (NoneDefined) return true; + RunPreFunctions(); + vTotalForces.InitMatrix(); vTotalMoments.InitMatrix(); @@ -123,6 +127,8 @@ bool FGExternalReactions::Run() vTotalMoments += Forces[i]->GetMoments(); } + RunPostFunctions(); + return false; } diff --git a/src/FDM/JSBSim/models/FGFCS.cpp b/src/FDM/JSBSim/models/FGFCS.cpp index 3ee958110..477890295 100644 --- a/src/FDM/JSBSim/models/FGFCS.cpp +++ b/src/FDM/JSBSim/models/FGFCS.cpp @@ -198,6 +198,8 @@ bool FGFCS::Run(void) if (FGModel::Run()) return true; // fast exit if nothing to do if (FDMExec->Holding()) return false; + RunPreFunctions(); + for (i=0; iRun(); + RunPostFunctions(); + return false; } diff --git a/src/FDM/JSBSim/models/FGGroundReactions.cpp b/src/FDM/JSBSim/models/FGGroundReactions.cpp index 4de1c1960..c8afc723b 100644 --- a/src/FDM/JSBSim/models/FGGroundReactions.cpp +++ b/src/FDM/JSBSim/models/FGGroundReactions.cpp @@ -89,6 +89,8 @@ bool FGGroundReactions::Run(void) if (FGModel::Run()) return true; if (FDMExec->Holding()) return false; + RunPreFunctions(); + vForces.InitMatrix(); vMoments.InitMatrix(); @@ -102,6 +104,8 @@ bool FGGroundReactions::Run(void) vMoments += lGear[i]->GetMoments(); } + RunPostFunctions(); + return false; } @@ -138,6 +142,8 @@ bool FGGroundReactions::Load(Element* el) for (unsigned int i=0; ibind(); + FGModel::PostLoad(el); + return true; } @@ -185,7 +191,7 @@ string FGGroundReactions::GetGroundReactionValues(string delimeter) for (unsigned int i=0;iIsBogey()) { FGLGear *gear = lGear[i]; - buf << (gear->GetWOW() ? "1, " : "0, ") + buf << (gear->GetWOW() ? "1" : "0") << delimeter << setprecision(5) << gear->GetCompLen() << delimeter << setprecision(6) << gear->GetCompVel() << delimeter << setprecision(10) << gear->GetCompForce() << delimeter diff --git a/src/FDM/JSBSim/models/FGInertial.cpp b/src/FDM/JSBSim/models/FGInertial.cpp index 9bff3f6e8..4ff657a51 100644 --- a/src/FDM/JSBSim/models/FGInertial.cpp +++ b/src/FDM/JSBSim/models/FGInertial.cpp @@ -114,11 +114,15 @@ bool FGInertial::Run(void) if (FGModel::Run()) return true; if (FDMExec->Holding()) return false; + RunPreFunctions(); + // Gravitation accel double r = Propagate->GetRadius(); gAccel = GetGAccel(r); earthPosAngle += State->Getdt()*RotationRate; + RunPostFunctions(); + return false; } diff --git a/src/FDM/JSBSim/models/FGInput.cpp b/src/FDM/JSBSim/models/FGInput.cpp index 6ba43df4e..dd124efa0 100755 --- a/src/FDM/JSBSim/models/FGInput.cpp +++ b/src/FDM/JSBSim/models/FGInput.cpp @@ -105,6 +105,8 @@ bool FGInput::Run(void) // return false if no error // This model DOES execute if "Exec->Holding" + RunPreFunctions(); + data = socket->Receive(); // get socket transmission if present if (data.size() > 0) { @@ -213,6 +215,8 @@ bool FGInput::Run(void) } } + RunPostFunctions(); + return false; } diff --git a/src/FDM/JSBSim/models/FGMassBalance.cpp b/src/FDM/JSBSim/models/FGMassBalance.cpp index c866fa40a..7b6752a3e 100644 --- a/src/FDM/JSBSim/models/FGMassBalance.cpp +++ b/src/FDM/JSBSim/models/FGMassBalance.cpp @@ -152,6 +152,8 @@ bool FGMassBalance::Load(Element* el) Mass = lbtoslug*Weight; + FGModel::PostLoad(el); + Debug(2); return true; } @@ -166,6 +168,8 @@ bool FGMassBalance::Run(void) if (FGModel::Run()) return true; if (FDMExec->Holding()) return false; + RunPreFunctions(); + double ChildFDMWeight = 0.0; for (int fdm=0; fdmGetFDMCount(); fdm++) { if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight(); @@ -226,6 +230,8 @@ bool FGMassBalance::Run(void) k2, k4, k5, k3, k5, k6 ); + RunPostFunctions(); + Debug(0); return false; diff --git a/src/FDM/JSBSim/models/FGModel.cpp b/src/FDM/JSBSim/models/FGModel.cpp index 3a16f493a..2e2b8357e 100644 --- a/src/FDM/JSBSim/models/FGModel.cpp +++ b/src/FDM/JSBSim/models/FGModel.cpp @@ -105,6 +105,9 @@ FGModel::~FGModel() for (unsigned int i=0; iFindElement("property"); - if (property_element && debug_lvl > 0) cout << endl << " Declared properties" << endl << endl; + if (property_element && debug_lvl > 0) cout << endl << " Declared properties" + << endl << endl; while (property_element) { interface_property_string = property_element->GetDataLine(); if (PropertyManager->HasNode(interface_property_string)) { - cerr << " Property " << interface_property_string << " is already defined." << endl; + cerr << " Property " << interface_property_string + << " is already defined." << endl; } else { double value=0.0; if ( ! property_element->GetAttributeValue("value").empty()) @@ -162,23 +166,82 @@ bool FGModel::Load(Element* el) interface_properties.push_back(new double(value)); PropertyManager->Tie(interface_property_string, interface_properties.back()); if (debug_lvl > 0) - cout << " " << interface_property_string << " (initial value: " << value << ")" << endl; + cout << " " << interface_property_string << " (initial value: " + << value << ")" << endl << endl; } property_element = el->FindNextElement("property"); } + // End of interface property loading logic + + // Load model pre-functions, if any + + Element *function = el->FindElement("function"); + while (function) { + if (function->GetAttributeValue("type") == "pre") { + PreFunctions.push_back(new FGFunction(PropertyManager, function)); + } else if (function->GetAttributeValue("type").empty()) { // Assume pre-function + string funcname = function->GetAttributeValue("name"); + PreFunctions.push_back(new FGFunction(PropertyManager, function)); + } + function = el->FindNextElement("function"); + } + return true; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +void FGModel::PostLoad(Element* el) +{ + // Load model post-functions, if any + + Element *function = el->FindElement("function"); + while (function) { + if (function->GetAttributeValue("type") == "post") { + PostFunctions.push_back(new FGFunction(PropertyManager, function)); + } + function = el->FindNextElement("function"); + } +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// Tell the Functions to cache values, so when the function values +// are being used in the model, the functions do not get +// calculated each time, but instead use the values that have already +// been calculated for this frame. + +void FGModel::RunPreFunctions(void) +{ + vector ::iterator it; + for (it = PreFunctions.begin(); it != PreFunctions.end(); it++) + (*it)->GetValue(); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// Tell the Functions to cache values, so when the function values +// are being used in the model, the functions do not get +// calculated each time, but instead use the values that have already +// been calculated for this frame. + +void FGModel::RunPostFunctions(void) +{ + vector ::iterator it; + for (it = PostFunctions.begin(); it != PostFunctions.end(); it++) + (*it)->GetValue(); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + bool FGModel::Run() { if (debug_lvl & 4) cout << "Entering Run() for model " << Name << endl; - if (exe_ctr++ >= rate) exe_ctr = 1; + if (rate == 1) return false; // Fast exit if nothing to do - if (exe_ctr == 1) return false; + if (exe_ctr >= rate) exe_ctr = 1; + + if (exe_ctr++ == 1) return false; else return true; } diff --git a/src/FDM/JSBSim/models/FGModel.h b/src/FDM/JSBSim/models/FGModel.h index bfba0af48..5907328f9 100644 --- a/src/FDM/JSBSim/models/FGModel.h +++ b/src/FDM/JSBSim/models/FGModel.h @@ -39,6 +39,7 @@ INCLUDES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ #include "FGJSBBase.h" +#include "math/FGFunction.h" #include #include @@ -93,11 +94,6 @@ public: /// Destructor ~FGModel(); - /** Loads this model. - @param el a pointer to the element - @return true if model is successfully loaded*/ - virtual bool Load(Element* el); - FGModel* NextModel; std::string Name; @@ -116,6 +112,16 @@ protected: int exe_ctr; int rate; + void RunPreFunctions(void); + void RunPostFunctions(void); + + /** Loads this model. + @param el a pointer to the element + @return true if model is successfully loaded*/ + virtual bool Load(Element* el); + + void PostLoad(Element* el); + virtual void Debug(int from); FGFDMExec* FDMExec; @@ -133,6 +139,8 @@ protected: FGPropagate* Propagate; FGAuxiliary* Auxiliary; FGPropertyManager* PropertyManager; + std::vector PreFunctions; + std::vector PostFunctions; std::vector interface_properties; }; diff --git a/src/FDM/JSBSim/models/FGOutput.cpp b/src/FDM/JSBSim/models/FGOutput.cpp index 2e509ff63..e358ce028 100644 --- a/src/FDM/JSBSim/models/FGOutput.cpp +++ b/src/FDM/JSBSim/models/FGOutput.cpp @@ -188,6 +188,7 @@ bool FGOutput::Run(void) if (FGModel::Run()) return true; if (enabled && !State->IntegrationSuspended()&& !FDMExec->Holding()) { + RunPreFunctions(); if (Type == otSocket) { SocketOutput(); } else if (Type == otFlightGear) { @@ -201,6 +202,7 @@ bool FGOutput::Run(void) } else { // Not a valid type of output } + RunPostFunctions(); } return false; } @@ -396,22 +398,22 @@ void FGOutput::DelimitedOutput(const string& fname) } if (SubSystems & ssForces) { outstream << delimeter; - outstream << Aerodynamics->GetvFw() << delimeter; + outstream << Aerodynamics->GetvFw().Dump(delimeter) << delimeter; outstream << Aerodynamics->GetLoD() << delimeter; - outstream << Aerodynamics->GetForces() << delimeter; - outstream << Propulsion->GetForces() << delimeter; - outstream << GroundReactions->GetForces() << delimeter; - outstream << ExternalReactions->GetForces() << delimeter; - outstream << BuoyantForces->GetForces() << delimeter; + outstream << Aerodynamics->GetForces().Dump(delimeter) << delimeter; + outstream << Propulsion->GetForces().Dump(delimeter) << delimeter; + outstream << GroundReactions->GetForces().Dump(delimeter) << delimeter; + outstream << ExternalReactions->GetForces().Dump(delimeter) << delimeter; + outstream << BuoyantForces->GetForces().Dump(delimeter) << delimeter; outstream << Aircraft->GetForces().Dump(delimeter); } if (SubSystems & ssMoments) { outstream << delimeter; - outstream << Aerodynamics->GetMoments() << delimeter; - outstream << Propulsion->GetMoments() << delimeter; - outstream << GroundReactions->GetMoments() << delimeter; - outstream << ExternalReactions->GetMoments() << delimeter; - outstream << BuoyantForces->GetMoments() << delimeter; + outstream << Aerodynamics->GetMoments().Dump(delimeter) << delimeter; + outstream << Propulsion->GetMoments().Dump(delimeter) << delimeter; + outstream << GroundReactions->GetMoments().Dump(delimeter) << delimeter; + outstream << ExternalReactions->GetMoments().Dump(delimeter) << delimeter; + outstream << BuoyantForces->GetMoments().Dump(delimeter) << delimeter; outstream << Aircraft->GetMoments().Dump(delimeter); } if (SubSystems & ssAtmosphere) { @@ -428,9 +430,9 @@ void FGOutput::DelimitedOutput(const string& fname) } if (SubSystems & ssMassProps) { outstream << delimeter; - outstream << MassBalance->GetJ() << delimeter; + outstream << MassBalance->GetJ().Dump(delimeter) << delimeter; outstream << MassBalance->GetMass() << delimeter; - outstream << MassBalance->GetXYZcg(); + outstream << MassBalance->GetXYZcg().Dump(delimeter); } if (SubSystems & ssPropagate) { outstream.precision(14); diff --git a/src/FDM/JSBSim/models/FGPropagate.cpp b/src/FDM/JSBSim/models/FGPropagate.cpp index f2a1251fc..9bd502898 100644 --- a/src/FDM/JSBSim/models/FGPropagate.cpp +++ b/src/FDM/JSBSim/models/FGPropagate.cpp @@ -233,6 +233,8 @@ bool FGPropagate::Run(void) if (FGModel::Run()) return true; // Fast return if we have nothing to do ... if (FDMExec->Holding()) return false; + RunPreFunctions(); + RecomputeLocalTerrainRadius(); // Calculate current aircraft radius from center of planet @@ -344,6 +346,8 @@ bool FGPropagate::Run(void) last2_vLocationDot = last_vLocationDot; last_vLocationDot = vLocationDot; + RunPreFunctions(); + Debug(2); return false; } diff --git a/src/FDM/JSBSim/models/FGPropulsion.cpp b/src/FDM/JSBSim/models/FGPropulsion.cpp index b6e6c14ea..e71dfeaf0 100644 --- a/src/FDM/JSBSim/models/FGPropulsion.cpp +++ b/src/FDM/JSBSim/models/FGPropulsion.cpp @@ -147,6 +147,8 @@ bool FGPropulsion::Run(void) if (FGModel::Run()) return true; if (FDMExec->Holding()) return false; + RunPreFunctions(); + double dt = State->Getdt(); vForces.InitMatrix(); @@ -169,6 +171,8 @@ bool FGPropulsion::Run(void) if (refuel) DoRefuel( dt * rate ); if (dump) DumpFuel( dt * rate ); + RunPostFunctions(); + return false; } @@ -333,6 +337,7 @@ bool FGPropulsion::Load(Element* el) if (el->FindElement("dump-rate")) DumpRate = el->FindElementValueAsNumberConvertTo("dump-rate", "LBS/MIN"); + FGModel::PostLoad(el); return true; } diff --git a/src/FDM/JSBSim/models/atmosphere/FGMSIS.cpp b/src/FDM/JSBSim/models/atmosphere/FGMSIS.cpp index 032858101..bd2a0abb8 100755 --- a/src/FDM/JSBSim/models/atmosphere/FGMSIS.cpp +++ b/src/FDM/JSBSim/models/atmosphere/FGMSIS.cpp @@ -148,6 +148,8 @@ bool MSIS::Run(void) if (FGModel::Run()) return true; if (FDMExec->Holding()) return false; + RunPreFunctions(); + //do temp, pressure, and density first if (!useExternal) { // get sea-level values @@ -180,6 +182,8 @@ bool MSIS::Run(void) CalculateDerived(); + RunPostFunctions(); + Debug(2); return false; diff --git a/src/FDM/JSBSim/models/propulsion/FGEngine.cpp b/src/FDM/JSBSim/models/propulsion/FGEngine.cpp index 4c98cd3d1..b95837b04 100644 --- a/src/FDM/JSBSim/models/propulsion/FGEngine.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGEngine.cpp @@ -74,6 +74,7 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number) SLFuelFlowMax = 0.0; MaxThrottle = 1.0; MinThrottle = 0.0; + FuelDensity = 6.0; unsigned int i; ResetToIC(); // initialize dynamic terms @@ -122,7 +123,9 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number) if (local_element) { while (local_element) { int tankID = (int)local_element->GetDataAsNumber(); - AddFeedTank( tankID , Propulsion->GetTank(tankID)->GetPriority()); + FGTank* tank = Propulsion->GetTank(tankID); + AddFeedTank( tankID , tank->GetPriority()); + FuelDensity = tank->GetDensity(); local_element = engine_element->GetParent()->FindNextElement("feed"); } } else { @@ -139,6 +142,8 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number) property_name = base_property_name + "/fuel-flow-rate-pps"; PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetFuelFlowRate); + //cout << "Engine[" << EngineNumber << "] using fuel density: " << FuelDensity << endl; + Debug(0); } diff --git a/src/FDM/JSBSim/models/propulsion/FGEngine.h b/src/FDM/JSBSim/models/propulsion/FGEngine.h index 4876f571f..c758d3bc7 100644 --- a/src/FDM/JSBSim/models/propulsion/FGEngine.h +++ b/src/FDM/JSBSim/models/propulsion/FGEngine.h @@ -113,8 +113,7 @@ CLASS DOCUMENTATION @endcode
     NOTES:
-	Engines feed from all tanks equally.
-
+	
 	Not all thruster types can be matched with a given engine type.  See the class
 	documentation for engine and thruster classes.
 
@@ -226,6 +225,7 @@ protected: double FuelFlow_gph; double FuelFlow_pph; + double FuelDensity; FGFDMExec* FDMExec; FGState* State; diff --git a/src/FDM/JSBSim/models/propulsion/FGRocket.cpp b/src/FDM/JSBSim/models/propulsion/FGRocket.cpp index eab01be15..85b0fd57f 100644 --- a/src/FDM/JSBSim/models/propulsion/FGRocket.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGRocket.cpp @@ -71,6 +71,8 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number) SLOxiFlowMax = 0.0; BuildupTime = 0.0; It = 0.0; + ThrustVariation = 0.0; + TotalIspVariation = 0.0; // Defaults MinThrottle = 0.0; @@ -89,9 +91,19 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number) if (el->FindElement("sloxiflowmax")) SLOxiFlowMax = el->FindElementValueAsNumberConvertTo("sloxiflowmax", "LBS/SEC"); + // If there is a thrust table element, this is a solid propellant engine. thrust_table_element = el->FindElement("thrust_table"); if (thrust_table_element) { ThrustTable = new FGTable(PropertyManager, thrust_table_element); + Element* variation_element = el->FindElement("variation"); + if (variation_element) { + if (variation_element->FindElement("thrust")) { + ThrustVariation = variation_element->FindElementValueAsNumber("thrust"); + } + if (variation_element->FindElement("total_isp")) { + TotalIspVariation = variation_element->FindElementValueAsNumber("total_isp"); + } + } } bindmodel(); @@ -138,7 +150,9 @@ double FGRocket::Calculate(void) } } - VacThrust = ThrustTable->GetValue(TotalEngineFuelBurned); + VacThrust = ThrustTable->GetValue(TotalEngineFuelBurned) + * (ThrustVariation + 1) + * (TotalIspVariation + 1); if (BurnTime <= BuildupTime && BuildupTime > 0.0) { VacThrust *= sin((BurnTime/BuildupTime)*M_PI/2.0); // VacThrust *= (1-cos((BurnTime/BuildupTime)*M_PI))/2.0; // 1 - cos approach @@ -241,6 +255,11 @@ void FGRocket::ConsumeFuel(void) } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// +// The FuelFlowRate can be affected by the TotalIspVariation value (settable +// in a config file or via properties). The TotalIspVariation parameter affects +// thrust, but the thrust determines fuel flow rate, so it must be adjusted +// for Total Isp Variation. double FGRocket::CalcFuelNeed(void) { @@ -248,6 +267,7 @@ double FGRocket::CalcFuelNeed(void) if (ThrustTable != 0L) { // Thrust table given - infers solid fuel FuelFlowRate = VacThrust/Isp; // This calculates wdot (weight flow rate in lbs/sec) + FuelFlowRate /= (1 + TotalIspVariation); } else { FuelFlowRate = SLFuelFlowMax*PctPower; } @@ -290,7 +310,7 @@ string FGRocket::GetEngineValues(const string& delimiter) } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -// This funciton should tie properties to rocket engine specific properties +// This function should tie properties to rocket engine specific properties // that are not bound in the base class (FGEngine) code. // void FGRocket::bindmodel() @@ -300,10 +320,20 @@ void FGRocket::bindmodel() property_name = base_property_name + "/total-impulse"; PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetTotalImpulse); - property_name = base_property_name + "/oxi-flow-rate-pps"; - PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetOxiFlowRate); property_name = base_property_name + "/vacuum-thrust_lbs"; PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetVacThrust); + + if (ThrustTable) { // Solid rocket motor + property_name = base_property_name + "/thrust-variation_pct"; + PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetThrustVariation, + &FGRocket::SetThrustVariation); + property_name = base_property_name + "/total-isp-variation_pct"; + PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetTotalIspVariation, + &FGRocket::SetTotalIspVariation); + } else { // Liquid rocket motor + property_name = base_property_name + "/oxi-flow-rate-pps"; + PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetOxiFlowRate); + } } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/FDM/JSBSim/models/propulsion/FGRocket.h b/src/FDM/JSBSim/models/propulsion/FGRocket.h index b2cb76f4e..4ff539572 100644 --- a/src/FDM/JSBSim/models/propulsion/FGRocket.h +++ b/src/FDM/JSBSim/models/propulsion/FGRocket.h @@ -162,6 +162,32 @@ public: std::string GetEngineLabels(const std::string& delimiter); std::string GetEngineValues(const std::string& delimiter); + /** Sets the thrust variation for a solid rocket engine. + Solid propellant rocket motor thrust characteristics are typically + defined at 70 degrees F temperature. At any other temperature, + performance will be different. Warmer propellant grain will + burn quicker and at higher thrust. Total motor impulse is + not changed for change in thrust. + @param var the variation in percent. That is, a 2 percent + variation would be specified as 0.02. A positive 2% variation + in thrust would increase the thrust by 2%, and shorten the burn time. */ + void SetThrustVariation(double var) {ThrustVariation = var;} + + /** Sets the variation in total motor energy. + The total energy present in a solid rocket motor can be modified + (such as might happen with manufacturing variations) by setting + the total Isp variation. + @param var the variation in percent. That is, a 2 percent + variation would be specified as 0.02. This variation will + affect the total thrust, but not the burn time.*/ + void SetTotalIspVariation(double var) {TotalIspVariation = var;} + + /** Returns the thrust variation, if any. */ + double GetThrustVariation(void) const {return ThrustVariation;} + + /** Returns the Total Isp variation, if any. */ + double GetTotalIspVariation(void) const {return TotalIspVariation;} + private: /** Reduces the fuel in the active tanks by the amount required. This function should be called from within the @@ -192,6 +218,8 @@ private: double It; double MxR; // Mixture Ratio double BurnTime; + double ThrustVariation; + double TotalIspVariation; double VacThrust; double previousFuelNeedPerTank; double previousOxiNeedPerTank; diff --git a/src/FDM/JSBSim/models/propulsion/FGTank.cpp b/src/FDM/JSBSim/models/propulsion/FGTank.cpp index dced188c5..f05831b73 100644 --- a/src/FDM/JSBSim/models/propulsion/FGTank.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGTank.cpp @@ -58,7 +58,7 @@ CLASS IMPLEMENTATION FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number) : TankNumber(tank_number), Exec(exec) { - string token; + string token, strFuelName; Element* element; Element* element_Grain; Area = 1.0; @@ -102,6 +102,9 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number) InitialPriority = Priority = el->FindElementValueAsNumber("priority"); if (el->FindElement("density")) Density = el->FindElementValueAsNumberConvertTo("density", "LBS/GAL"); + if (el->FindElement("type")) + strFuelName = el->FindElementValue("type"); + SetPriority( InitialPriority ); // this will also set the Selected flag @@ -162,6 +165,9 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number) if (Temperature != -9999.0) InitialTemperature = Temperature = FahrenheitToCelsius(Temperature); Area = 40.0 * pow(Capacity/1975, 0.666666667); + // A named fuel type will override a previous density value + if (!strFuelName.empty()) Density = ProcessFuelName(strFuelName); + Debug(0); } @@ -313,6 +319,43 @@ void FGTank::CalculateInertias(void) } +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +double FGTank::ProcessFuelName(std::string const& name) +{ + if (name == "AVGAS") return 6.02; + else if (name == "JET-A") return 6.74; + else if (name == "JET-A1") return 6.74; + else if (name == "JET-B") return 6.48; + else if (name == "JP-1") return 6.76; + else if (name == "JP-2") return 6.38; + else if (name == "JP-3") return 6.34; + else if (name == "JP-4") return 6.48; + else if (name == "JP-5") return 6.81; + else if (name == "JP-6") return 6.55; + else if (name == "JP-7") return 6.61; + else if (name == "JP-8") return 6.66; + else if (name == "JP-8+100") return 6.66; + //else if (name == "JP-9") return 6.74; + //else if (name == "JPTS") return 6.74; + else if (name == "RP-1") return 6.73; + else if (name == "T-1") return 6.88; + else if (name == "ETHANOL") return 6.58; + else if (name == "HYDRAZINE")return 8.61; + else if (name == "F-34") return 6.66; + else if (name == "F-35") return 6.74; + else if (name == "F-40") return 6.48; + else if (name == "F-44") return 6.81; + else if (name == "AVTAG") return 6.48; + else if (name == "AVCAT") return 6.81; + else { + cerr << "Unknown fuel type specified: "<< name << endl; + } + + return 6.6; +} + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // The bitmasked value choices are as follows: // unset: In this case (the default) JSBSim would only print diff --git a/src/FDM/JSBSim/models/propulsion/FGTank.h b/src/FDM/JSBSim/models/propulsion/FGTank.h index 7f4f75457..55930543f 100644 --- a/src/FDM/JSBSim/models/propulsion/FGTank.h +++ b/src/FDM/JSBSim/models/propulsion/FGTank.h @@ -126,6 +126,7 @@ CLASS DOCUMENTATION {number} {integer} {number} + {string} @endcode @@ -141,6 +142,9 @@ CLASS DOCUMENTATION - \b standpipe - Minimum contents to which tank can dump, defaults to pounds. - \b priority - Establishes feed sequence of tank. "1" is the highest priority. - \b density - Density of liquid tank contents. +- \b type - Named fuel type. One of AVGAS, JET-A, JET-A1, JET-B, JP-1, JP-2, JP-3, +- \b JP-4, JP-5, JP-6, JP-7, JP-8, JP-8+100, RP-1, T-1, ETHANOL, HYDRAZINE, +- \b F-34, F-35, F-40, F-44, AVTAG, AVCAT location: - \b x - Location of tank on aircraft's x-axis, defaults to inches. @@ -252,6 +256,10 @@ public: is given, otherwise 32 degrees F is returned. */ double GetTemperature(void) {return CelsiusToFahrenheit(Temperature);} + /** Returns the density of a named fuel type. + @return the density, in lbs/gal, or 6.6 if name cannot be resolved. */ + double ProcessFuelName(std::string const& name); + double GetIxx(void) {return Ixx;} double GetIyy(void) {return Iyy;} double GetIzz(void) {return Izz;} @@ -261,6 +269,9 @@ public: int GetPriority(void) const {return Priority;} void SetPriority(int p) { Priority = p; Selected = p>0 ? true:false; } + double GetDensity(void) const {return Density;} + void SetDensity(double d) { Density = d; } + const FGColumnVector3 GetXYZ(void); const double GetXYZ(int idx);