]> git.mxchange.org Git - flightgear.git/commitdiff
Sync. withn JSBSim CVS
authorehofman <ehofman>
Fri, 27 Nov 2009 08:54:33 +0000 (08:54 +0000)
committerTim Moore <timoore@redhat.com>
Sun, 29 Nov 2009 14:53:31 +0000 (15:53 +0100)
29 files changed:
src/FDM/JSBSim/FGFDMExec.cpp
src/FDM/JSBSim/FGFDMExec.h
src/FDM/JSBSim/math/FGFunction.cpp
src/FDM/JSBSim/math/FGFunction.h
src/FDM/JSBSim/math/FGMatrix33.cpp
src/FDM/JSBSim/math/FGMatrix33.h
src/FDM/JSBSim/models/FGAerodynamics.cpp
src/FDM/JSBSim/models/FGAircraft.cpp
src/FDM/JSBSim/models/FGAtmosphere.cpp
src/FDM/JSBSim/models/FGAuxiliary.cpp
src/FDM/JSBSim/models/FGBuoyantForces.cpp
src/FDM/JSBSim/models/FGExternalReactions.cpp
src/FDM/JSBSim/models/FGFCS.cpp
src/FDM/JSBSim/models/FGGroundReactions.cpp
src/FDM/JSBSim/models/FGInertial.cpp
src/FDM/JSBSim/models/FGInput.cpp
src/FDM/JSBSim/models/FGMassBalance.cpp
src/FDM/JSBSim/models/FGModel.cpp
src/FDM/JSBSim/models/FGModel.h
src/FDM/JSBSim/models/FGOutput.cpp
src/FDM/JSBSim/models/FGPropagate.cpp
src/FDM/JSBSim/models/FGPropulsion.cpp
src/FDM/JSBSim/models/atmosphere/FGMSIS.cpp
src/FDM/JSBSim/models/propulsion/FGEngine.cpp
src/FDM/JSBSim/models/propulsion/FGEngine.h
src/FDM/JSBSim/models/propulsion/FGRocket.cpp
src/FDM/JSBSim/models/propulsion/FGRocket.h
src/FDM/JSBSim/models/propulsion/FGTank.cpp
src/FDM/JSBSim/models/propulsion/FGTank.h

index 227c0267fc6d8b07152b7841dbced7d461aa7751..6851223810d1208eaca2be7bc291c05f934a3963 100644 (file)
@@ -94,7 +94,8 @@ void checkTied ( FGPropertyManager *node )
   for (int i=0; i<N; i++) {
     if (node->getChild(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 <FGModel*>::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 <FGModel*>::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;
-
-  model_iterator = FirstModel;
-  if (model_iterator == 0L || Constructing) return;
+  if (Constructing) return;
 
-  while (model_iterator != 0L) {
-    model_iterator->InitModel();
-    model_iterator = model_iterator->NextModel;
-  }
+  vector <FGModel*>::iterator it;
+  for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel();
 
   RunIC();
   if (Script) Script->ResetEvents();
index 5e1ee07193a5c30f40a7301ea6541943267c407a..c1fbbb8ef1a17f228582a9d6557223bf01b66d2b 100644 (file)
@@ -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 <string> PropertyCatalog;
   vector <FGOutput*> Outputs;
   vector <childData*> ChildFDMList;
+  vector <FGModel*> Models;
 
   bool ReadFileHeader(Element*);
   bool ReadChild(Element*);
index 1db1e6aecc7228930911009e350ad9317e990767..e45e6d9aa23c1a14181e4a9371fb2f2f9ad9e44b 100755 (executable)
@@ -31,6 +31,7 @@ INCLUDES
 #include <sstream>
 #include <iomanip>
 #include <cstdlib>
+#include <cmath>
 #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);
   }
 }
index 4c67ba46e851a9af672bdddd32eea38c0514794e..d122ffe20755952aa66a38b2704cbf067e51bde4 100755 (executable)
@@ -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 <FGParameter*> 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);
index 8f27e88a54c2a8e5696d3710d55a0763cb531e8b..5eccfdfce13576107bd707316b10c1c8bbc12393 100644 (file)
@@ -39,6 +39,8 @@ INCLUDES
 
 #include "FGMatrix33.h"
 #include "FGColumnVector3.h"
+#include <sstream>
+#include <iomanip>
 
 #include <iostream>
 
@@ -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++) {
index a31e05d88f3e6e6304051c263c894f993d1db8b7..d07687ea9808de43b31aaa2c5ef00e4a9d3570d0 100644 (file)
@@ -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.
index 5083bf7bc5f4c02d7c5823f1dc6566d32e987115..ab2381ce432ddd5d4124879d397bf617d23d4592 100644 (file)
@@ -108,9 +108,6 @@ FGAerodynamics::~FGAerodynamics()
 
   delete[] Coeff;
 
-  for (i=0; i<variables.size(); i++)
-    delete variables[i];
-
   delete AeroRPShift;
 
   Debug(1);
@@ -137,12 +134,14 @@ bool FGAerodynamics::InitModel(void)
 
 bool FGAerodynamics::Run(void)
 {
-  unsigned int axis_ctr, ctr, i;
+  unsigned int axis_ctr, ctr;
   double alpha, twovel;
 
   if (FGModel::Run()) return true;
   if (FDMExec->Holding()) 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; i<variables.size(); i++) variables[i]->cacheValue(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;
index 83a1bf1779b9f8feff5e401f7bb35115bf2f800e..75f9fba590b680eeb7b79a6273d8228e26fd2145 100644 (file)
@@ -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;
index c21e45cbc1dff8ee0a5bce9bc0122440d0c5d7f4..8acb17c1b42056c7c112169b7023c5294727a8f8 100644 (file)
@@ -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;
 }
index d8a8d77c0f2ce22d40e3356e607865d12b465bff..815a1b400d09e0e0790f2ffc83b687c62743f2e8 100755 (executable)
@@ -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;
 }
 
index 44ecd65959a5f09f60d84165446d3ceca46430f4..49d9cb2e5069402f35c9db616e99debf5bd6a17f 100644 (file)
@@ -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;
 }
 
index 58a334364e08362028ffba877ffe2c89eac36a13..a9b6ee2753b33f4c45331656e6c5ad2aad078d5a 100755 (executable)
@@ -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;
 }
 
index 3ee95811085376eb6889581641e9677a16c4d38d..477890295478671424b026873c20664dfeb362fb 100644 (file)
@@ -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; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
   for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
   for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
@@ -218,6 +220,8 @@ bool FGFCS::Run(void)
   // Execute Flight Control System
   for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
 
+  RunPostFunctions();
+
   return false;
 }
 
index 4de1c1960345bdab9c77dfbb3100c734fd62e726..c8afc723b711578848d01d2dd4b6cad3f31977d9 100644 (file)
@@ -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; i<lGear.size();i++) lGear[i]->bind();
 
+  FGModel::PostLoad(el);
+
   return true;
 }
 
@@ -185,7 +191,7 @@ string FGGroundReactions::GetGroundReactionValues(string delimeter)
   for (unsigned int i=0;i<lGear.size();i++) {
     if (lGear[i]->IsBogey()) {
       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
index 9bff3f6e898536320d9d08942e6141c748e65d6e..4ff657a51e8774471cab7986cd67374a10d56371 100644 (file)
@@ -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;
 }
 
index 6ba43df4ec73eabe33a0bdcdf2ca8a52c49d6495..dd124efa0937f74ddda21a65e130bfe87788a58e 100755 (executable)
@@ -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;
 }
 
index c866fa40a1ea0462beca5d6404c32d9da5839906..7b6752a3ea7e00e4a58bed237f28d3cbe419187b 100644 (file)
@@ -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; fdm<FDMExec->GetFDMCount(); 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;
index 3a16f493a4d47448ea86fe2cc1bc9dbfbf4f6772..2e2b8357e5bf70efe6a5e32039a675f22f3414f7 100644 (file)
@@ -105,6 +105,9 @@ FGModel::~FGModel()
   for (unsigned int i=0; i<interface_properties.size(); i++) delete interface_properties[i];
   interface_properties.clear();
 
+  for (unsigned int i=0; i<PreFunctions.size(); i++) delete PreFunctions[i];
+  for (unsigned int i=0; i<PostFunctions.size(); i++) delete PostFunctions[i];
+
   if (debug_lvl & 2) cout << "Destroyed:    FGModel" << endl;
 }
 
@@ -146,15 +149,16 @@ bool FGModel::InitModel(void)
 bool FGModel::Load(Element* el)
 {
   // Interface properties are all stored in the interface properties array.
-
   string interface_property_string = "";
 
   Element *property_element = el->FindElement("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 <FGFunction*>::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 <FGFunction*>::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 >= rate) exe_ctr = 1;
 
-  if (exe_ctr == 1) return false;
+  if (exe_ctr++ == 1) return false;
   else              return true;
 }
 
index bfba0af48437a511a2cd43fafd3c435e60ee6172..5907328f9e0514249f512ca8619ec8f65866be0c 100644 (file)
@@ -39,6 +39,7 @@ INCLUDES
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
 #include "FGJSBBase.h"
+#include "math/FGFunction.h"
 
 #include <string>
 #include <vector>
@@ -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 <FGFunction*> PreFunctions;
+  std::vector <FGFunction*> PostFunctions;
 
   std::vector <double*> interface_properties;
 };
index 2e509ff6387043d17c44772be50bf2bc421f0ae7..e358ce0285a9340136f19142254bda24606a80f5 100644 (file)
@@ -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);
index f2a1251fc4465e844a7c5144245620851183eb64..9bd50289882d378cae31575ecb69f13b59e308a2 100644 (file)
@@ -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;
 }
index b6e6c14ea5c59340413d948c78f6fba784c6e675..e71dfeaf03d11cc9dcb0fb8e017801a3a6b075a1 100644 (file)
@@ -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;
 }
index 0328581017fff44c68b4beba98d997dbd0ca499c..bd2a0abb86872db53b43457af7b300b217f2cefd 100755 (executable)
@@ -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;
index 4c98cd3d1d647045808ac3b21c5a3710174ddff3..b95837b041a2d1140be051992091d9aa97654255 100644 (file)
@@ -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);
 }
 
index 4876f571f3e9aa6cdf9675c944079067e6713de9..c758d3bc7620a7701a0f65c08b6efcf39802971e 100644 (file)
@@ -113,8 +113,7 @@ CLASS DOCUMENTATION
 @endcode
 <pre>
     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.
 </pre>     
@@ -226,6 +225,7 @@ protected:
 
   double FuelFlow_gph;
   double FuelFlow_pph;
+  double FuelDensity;
 
   FGFDMExec*      FDMExec;
   FGState*        State;
index eab01be1529c2d30939481ee56b17e200cd525c4..85b0fd57f63324291181f0aa1ae13c65b3d3eeda 100644 (file)
@@ -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);
+  }
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
index b2cb76f4e8cc827969bd5f1d981464fffcdb8ef8..4ff539572ff97cc6863a5c2a0009e3a777dd1a35 100644 (file)
@@ -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;
index dced188c54a9d5fe6a0108cd8c92d7bfad1305e4..f05831b73a0bf6ab7129a32784644f16cb781d0c 100644 (file)
@@ -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
index 7f4f7545768e21eb3e47a548512fffbf858d6f9c..55930543f660ef5c4f4227ebc135434bff683ceb 100644 (file)
@@ -126,6 +126,7 @@ CLASS DOCUMENTATION
   <standpipe unit="{LBS | KG"}> {number} </standpipe>
   <priority> {integer} </priority>
   <density unit="{KG/L | LBS/GAL}"> {number} </density>
+  <type> {string} </type> <!-- will override previous density setting -->
 </tank>
 @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);