]> git.mxchange.org Git - flightgear.git/blobdiff - src/FDM/JSBSim/FGPropulsion.cpp
Make yasim accept the launchbar and hook properties. They are not tied to anything...
[flightgear.git] / src / FDM / JSBSim / FGPropulsion.cpp
index 1a2dba8c7d226b12450a06d9dceab085056f6a26..bdb0a211bf3af0d128488b844449d192121d3f93 100644 (file)
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
- Module:       FGPropulsion.cpp\r
- Author:       Jon S. Berndt\r
- Date started: 08/20/00\r
- Purpose:      Encapsulates the set of engines, tanks, and thrusters associated\r
-               with this aircraft\r
-\r
- ------------- Copyright (C) 2000  Jon S. Berndt (jsb@hal-pc.org) -------------\r
-\r
- This program is free software; you can redistribute it and/or modify it under\r
- the terms of the GNU General Public License as published by the Free Software\r
- Foundation; either version 2 of the License, or (at your option) any later\r
- version.\r
-\r
- This program is distributed in the hope that it will be useful, but WITHOUT\r
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
- FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\r
- details.\r
-\r
- You should have received a copy of the GNU General Public License along with\r
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple\r
- Place - Suite 330, Boston, MA  02111-1307, USA.\r
-\r
- Further information about the GNU General Public License can also be found on\r
- the world wide web at http://www.gnu.org.\r
-\r
-FUNCTIONAL DESCRIPTION\r
---------------------------------------------------------------------------------\r
-The Propulsion class is the container for the entire propulsion system, which is\r
-comprised of engines, tanks, and "thrusters" (the device that transforms the\r
-engine power into a force that acts on the aircraft, such as a nozzle or\r
-propeller). Once the Propulsion class gets the config file, it reads in\r
-information which is specific to a type of engine. Then:\r
-\r
-1) The appropriate engine type instance is created\r
-2) A thruster object is instantiated, and is linked to the engine\r
-3) At least one tank object is created, and is linked to an engine.\r
-\r
-At Run time each engines Calculate() method is called to return the excess power\r
-generated during that iteration. The drag from the previous iteration is sub-\r
-tracted to give the excess power available for thrust this pass. That quantity\r
-is passed to the thrusters associated with a particular engine - perhaps with a\r
-scaling mechanism (gearing?) to allow the engine to give its associated thrust-\r
-ers specific distributed portions of the excess power.\r
-\r
-HISTORY\r
---------------------------------------------------------------------------------\r
-08/20/00   JSB   Created\r
-\r
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-INCLUDES\r
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/\r
-\r
-#include "FGPropulsion.h"\r
-#include "FGPropertyManager.h"\r
-\r
-\r
-static const char *IdSrc = "$Id$";\r
-static const char *IdHdr = ID_PROPULSION;\r
-\r
-extern short debug_lvl;\r
-\r
-#if defined (__APPLE__)\r
-/* Not all systems have the gcvt function */\r
-inline char* gcvt (double value, int ndigits, char *buf) {\r
-    /* note that this is not exactly what gcvt is supposed to do! */\r
-    snprintf (buf, ndigits+1, "%f", value);\r
-    return buf;\r
-}\r
-#endif\r
-\r
-\r
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-CLASS IMPLEMENTATION\r
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/\r
-\r
-FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)\r
-{\r
-  Name = "FGPropulsion";\r
-  numSelectedFuelTanks = numSelectedOxiTanks = 0;\r
-  numTanks = numEngines = numThrusters = 0;\r
-  numOxiTanks = numFuelTanks = 0;\r
-  dt = 0.0;\r
-  ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...\r
-  bind();\r
-  Debug(0);\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-FGPropulsion::~FGPropulsion()\r
-{\r
-  for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];\r
-  Engines.clear();\r
-  unbind();\r
-  Debug(1);\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-bool FGPropulsion::Run(void)\r
-{\r
-  double PowerAvailable;\r
-  dt = State->Getdt();\r
-\r
-  vForces.InitMatrix();\r
-  vMoments.InitMatrix();\r
-\r
-  if (!FGModel::Run()) {\r
-    for (unsigned int i=0; i<numEngines; i++) {\r
-      Thrusters[i]->SetdeltaT(dt*rate);\r
-      PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());\r
-      Thrusters[i]->Calculate(PowerAvailable);\r
-      vForces  += Thrusters[i]->GetBodyForces();  // sum body frame forces\r
-      vMoments += Thrusters[i]->GetMoments();     // sum body frame moments\r
-    }\r
-    return false;\r
-  } else {\r
-    return true;\r
-  }\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-bool FGPropulsion::GetSteadyState(void)\r
-{\r
-  double PowerAvailable;\r
-  double currentThrust = 0, lastThrust=-1;\r
-  dt = State->Getdt();\r
-  int steady_count,j=0;\r
-  bool steady=false;\r
-\r
-  vForces.InitMatrix();\r
-  vMoments.InitMatrix();\r
-\r
-  if (!FGModel::Run()) {\r
-    for (unsigned int i=0; i<numEngines; i++) {\r
-      Engines[i]->SetTrimMode(true);\r
-      Thrusters[i]->SetdeltaT(dt*rate);\r
-      steady=false;\r
-      steady_count=0;\r
-      while (!steady && j < 6000) {\r
-        PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());\r
-        lastThrust = currentThrust;\r
-        currentThrust = Thrusters[i]->Calculate(PowerAvailable);\r
-        if (fabs(lastThrust-currentThrust) < 0.0001) {\r
-          steady_count++;\r
-          if (steady_count > 120) { steady=true; }\r
-        } else {\r
-          steady_count=0;\r
-        }\r
-        j++;    \r
-      }\r
-      vForces  += Thrusters[i]->GetBodyForces();  // sum body frame forces\r
-      vMoments += Thrusters[i]->GetMoments();     // sum body frame moments\r
-      Engines[i]->SetTrimMode(false);\r
-    }\r
-\r
-    return false;\r
-  } else {\r
-    return true;\r
-  }\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-bool FGPropulsion::ICEngineStart(void)\r
-{\r
-  double PowerAvailable;\r
-  int j;\r
-  dt = State->Getdt();\r
-\r
-  vForces.InitMatrix();\r
-  vMoments.InitMatrix();\r
-    \r
-  for (unsigned int i=0; i<numEngines; i++) {\r
-    Engines[i]->SetTrimMode(true);\r
-    Thrusters[i]->SetdeltaT(dt*rate);\r
-    j=0;\r
-    while (!Engines[i]->GetRunning() && j < 2000) {\r
-      PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());\r
-      Thrusters[i]->Calculate(PowerAvailable);\r
-      j++;    \r
-    }\r
-    vForces  += Thrusters[i]->GetBodyForces();  // sum body frame forces\r
-    vMoments += Thrusters[i]->GetMoments();     // sum body frame moments\r
-    Engines[i]->SetTrimMode(false);\r
-  }\r
-  return true;\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-bool FGPropulsion::Load(FGConfigFile* AC_cfg)\r
-{\r
-  string token, fullpath;\r
-  string engineFileName, engType;\r
-  string thrusterFileName, thrType;\r
-  string parameter;\r
-  string enginePath = FDMExec->GetEnginePath();\r
-  double xLoc, yLoc, zLoc, Pitch, Yaw;\r
-  double P_Factor = 0, Sense = 0.0;\r
-  int Feed;\r
-  bool ThrottleAdded = false;\r
-\r
-# ifndef macintosh\r
-      fullpath = enginePath + "/";\r
-# else\r
-      fullpath = enginePath + ";";\r
-# endif\r
-\r
-  AC_cfg->GetNextConfigLine();\r
-\r
-  while ((token = AC_cfg->GetValue()) != string("/PROPULSION")) {\r
-\r
-    if (token == "AC_ENGINE") {                   // ============ READING ENGINES\r
-\r
-      engineFileName = AC_cfg->GetValue("FILE");\r
-\r
-      if (debug_lvl > 0) cout << "\n    Reading engine from file: " << fullpath\r
-                                                + engineFileName + ".xml"<< endl;\r
-      FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");\r
-\r
-      if (Eng_cfg.IsOpen()) {\r
-        Eng_cfg.GetNextConfigLine();\r
-        engType = Eng_cfg.GetValue();\r
-\r
-        FCS->AddThrottle();\r
-        ThrottleAdded = true;\r
-\r
-        if (engType == "FG_ROCKET") {\r
-          Engines.push_back(new FGRocket(FDMExec, &Eng_cfg));\r
-        } else if (engType == "FG_PISTON") {\r
-          Engines.push_back(new FGPiston(FDMExec, &Eng_cfg));\r
-        } else if (engType == "FG_TURBOJET") {\r
-          Engines.push_back(new FGTurboJet(FDMExec, &Eng_cfg));\r
-        } else if (engType == "FG_TURBOSHAFT") {\r
-          Engines.push_back(new FGTurboShaft(FDMExec, &Eng_cfg));\r
-        } else if (engType == "FG_TURBOPROP") {\r
-          Engines.push_back(new FGTurboProp(FDMExec, &Eng_cfg));\r
-        } else {\r
-          cerr << fgred << "    Unrecognized engine type: " << underon << engType\r
-                    << underoff << " found in config file." << fgdef << endl;\r
-          return false;\r
-        }\r
-\r
-        AC_cfg->GetNextConfigLine();\r
-        while ((token = AC_cfg->GetValue()) != string("/AC_ENGINE")) {\r
-          *AC_cfg >> token;\r
-          if      (token == "XLOC")  { *AC_cfg >> xLoc; }\r
-          else if (token == "YLOC")  { *AC_cfg >> yLoc; }\r
-          else if (token == "ZLOC")  { *AC_cfg >> zLoc; }\r
-          else if (token == "PITCH") { *AC_cfg >> Pitch;}\r
-          else if (token == "YAW")   { *AC_cfg >> Yaw;}\r
-          else if (token == "FEED")  {\r
-            *AC_cfg >> Feed;\r
-            Engines[numEngines]->AddFeedTank(Feed);\r
-            if (debug_lvl > 0) cout << "      Feed tank: " << Feed << endl;\r
-          } else cerr << "Unknown identifier: " << token << " in engine file: "\r
-                                                        << engineFileName << endl;\r
-        }\r
-\r
-        if (debug_lvl > 0)  {\r
-          cout << "      X = " << xLoc << endl;\r
-          cout << "      Y = " << yLoc << endl;\r
-          cout << "      Z = " << zLoc << endl;\r
-          cout << "      Pitch = " << Pitch << endl;\r
-          cout << "      Yaw = " << Yaw << endl;\r
-        }\r
-\r
-        Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw);\r
-        Engines[numEngines]->SetEngineNumber(numEngines);\r
-        numEngines++;\r
-\r
-      } else {\r
-\r
-        cerr << fgred << "\n  Could not read engine config file: " << underon <<\r
-                    fullpath + engineFileName + ".xml" << underoff << fgdef << endl;\r
-        return false;\r
-      }\r
-\r
-    } else if (token == "AC_TANK") {              // ============== READING TANKS\r
-\r
-      if (debug_lvl > 0) cout << "\n    Reading tank definition" << endl;\r
-      Tanks.push_back(new FGTank(AC_cfg));\r
-      switch(Tanks[numTanks]->GetType()) {\r
-      case FGTank::ttFUEL:\r
-        numSelectedFuelTanks++;\r
-        numFuelTanks++;\r
-        break;\r
-      case FGTank::ttOXIDIZER:\r
-        numSelectedOxiTanks++;\r
-        numOxiTanks++;\r
-        break;\r
-      }\r
-\r
-      numTanks++;\r
-\r
-    } else if (token == "AC_THRUSTER") {          // ========== READING THRUSTERS\r
-\r
-      thrusterFileName = AC_cfg->GetValue("FILE");\r
-\r
-      if (debug_lvl > 0) cout << "\n    Reading thruster from file: " <<\r
-                                    fullpath + thrusterFileName + ".xml" << endl;\r
-      FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");\r
-\r
-      if (Thruster_cfg.IsOpen()) {\r
-        Thruster_cfg.GetNextConfigLine();\r
-        thrType = Thruster_cfg.GetValue();\r
-\r
-        if (thrType == "FG_PROPELLER") {\r
-          Thrusters.push_back(new FGPropeller(FDMExec, &Thruster_cfg));\r
-        } else if (thrType == "FG_NOZZLE") {\r
-          Thrusters.push_back(new FGNozzle(FDMExec, &Thruster_cfg));\r
-        }\r
-\r
-        AC_cfg->GetNextConfigLine();\r
-        while ((token = AC_cfg->GetValue()) != string("/AC_THRUSTER")) {\r
-          *AC_cfg >> token;\r
-          if (token == "XLOC") *AC_cfg >> xLoc;\r
-          else if (token == "YLOC") *AC_cfg >> yLoc;\r
-          else if (token == "ZLOC") *AC_cfg >> zLoc;\r
-          else if (token == "PITCH") *AC_cfg >> Pitch;\r
-          else if (token == "YAW") *AC_cfg >> Yaw;\r
-          else if (token == "P_FACTOR") *AC_cfg >> P_Factor;\r
-          else if (token == "SENSE")   *AC_cfg >> Sense;\r
-          else cerr << "Unknown identifier: " << token << " in engine file: "\r
-                                                        << engineFileName << endl;\r
-        }\r
-\r
-        Thrusters[numThrusters]->SetLocation(xLoc, yLoc, zLoc);\r
-        Thrusters[numThrusters]->SetAnglesToBody(0, Pitch, Yaw);\r
-        if (thrType == "FG_PROPELLER" && P_Factor > 0.001) {\r
-          ((FGPropeller*)Thrusters[numThrusters])->SetPFactor(P_Factor);\r
-          if (debug_lvl > 0) cout << "      P-Factor: " << P_Factor << endl;\r
-          ((FGPropeller*)Thrusters[numThrusters])->SetSense(fabs(Sense)/Sense);\r
-          if (debug_lvl > 0) cout << "      Sense: " << Sense <<  endl;\r
-        }\r
-        Thrusters[numThrusters]->SetdeltaT(dt*rate);\r
-        Thrusters[numThrusters]->SetThrusterNumber(numThrusters);\r
-        numThrusters++;\r
-\r
-      } else {\r
-        cerr << "Could not read thruster config file: " << fullpath\r
-                                                + thrusterFileName + ".xml" << endl;\r
-        return false;\r
-      }\r
-\r
-    }\r
-    AC_cfg->GetNextConfigLine();\r
-  }\r
-\r
-  if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle\r
-\r
-  return true;\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-string FGPropulsion::GetPropulsionStrings(void)\r
-{\r
-  string PropulsionStrings = "";\r
-  bool firstime = true;\r
-  char buffer[5];\r
-\r
-  for (unsigned int i=0;i<Engines.size();i++) {\r
-    if (firstime)  firstime = false;\r
-    else           PropulsionStrings += ", ";\r
-\r
-    sprintf(buffer, "%d", i);\r
-\r
-    switch(Engines[i]->GetType()) {\r
-    case FGEngine::etPiston:\r
-      PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail[" + buffer + "]");\r
-      break;\r
-    case FGEngine::etRocket:\r
-      PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress[" + buffer + "]");\r
-      break;\r
-    case FGEngine::etTurboJet:\r
-    case FGEngine::etTurboProp:\r
-    case FGEngine::etTurboShaft:\r
-      break;\r
-    default:\r
-      PropulsionStrings += "INVALID ENGINE TYPE";\r
-      break;\r
-    }\r
-\r
-    PropulsionStrings += ", ";\r
-\r
-    FGPropeller* Propeller = (FGPropeller*)Thrusters[i];\r
-    switch(Thrusters[i]->GetType()) {\r
-    case FGThruster::ttNozzle:\r
-      PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");\r
-      break;\r
-    case FGThruster::ttRotor:\r
-      break;\r
-    case FGThruster::ttPropeller:\r
-      PropulsionStrings += (Thrusters[i]->GetName() + "_Torque[" + buffer + "], ");\r
-      PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Roll[" + buffer + "], ");\r
-      PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Pitch[" + buffer + "], ");\r
-      PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Yaw[" + buffer + "], ");\r
-      PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "], ");\r
-      if (Propeller->IsVPitch())\r
-        PropulsionStrings += (Thrusters[i]->GetName() + "_Pitch[" + buffer + "], ");\r
-      PropulsionStrings += (Thrusters[i]->GetName() + "_RPM[" + buffer + "]");\r
-      break;\r
-    default:\r
-      PropulsionStrings += "INVALID THRUSTER TYPE";\r
-      break;\r
-    }    \r
-  }\r
-\r
-  return PropulsionStrings;\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-string FGPropulsion::GetPropulsionValues(void)\r
-{\r
-  char buff[20];\r
-  string PropulsionValues = "";\r
-  bool firstime = true;\r
-\r
-  for (unsigned int i=0;i<Engines.size();i++) {\r
-    if (firstime)  firstime = false;\r
-    else           PropulsionValues += ", ";\r
-\r
-    switch(Engines[i]->GetType()) {\r
-    case FGEngine::etPiston:\r
-      PropulsionValues += (string(gcvt(((FGPiston*)Engines[i])->GetPowerAvailable(), 10, buff)));\r
-      break;\r
-    case FGEngine::etRocket:\r
-      PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));\r
-      break;\r
-    case FGEngine::etTurboJet:\r
-    case FGEngine::etTurboProp:\r
-    case FGEngine::etTurboShaft:\r
-      break;\r
-    }\r
-\r
-    PropulsionValues += ", ";\r
-\r
-    switch(Thrusters[i]->GetType()) {\r
-    case FGThruster::ttNozzle:\r
-      PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));\r
-      break;\r
-    case FGThruster::ttRotor:\r
-      break;\r
-    case FGThruster::ttPropeller:\r
-      FGPropeller* Propeller = (FGPropeller*)Thrusters[i];\r
-      FGColumnVector3 vPFactor = Propeller->GetPFactor();\r
-      PropulsionValues += string(gcvt(Propeller->GetTorque(), 10, buff)) + ", ";\r
-      PropulsionValues += string(gcvt(vPFactor(eRoll), 10, buff)) + ", ";\r
-      PropulsionValues += string(gcvt(vPFactor(ePitch), 10, buff)) + ", ";\r
-      PropulsionValues += string(gcvt(vPFactor(eYaw), 10, buff)) + ", ";\r
-      PropulsionValues += string(gcvt(Propeller->GetThrust(), 10, buff)) + ", ";\r
-      if (Propeller->IsVPitch())\r
-        PropulsionValues += string(gcvt(Propeller->GetPitch(), 10, buff)) + ", ";\r
-      PropulsionValues += string(gcvt(Propeller->GetRPM(), 10, buff));\r
-      break;\r
-    }\r
-  }\r
-\r
-  return PropulsionValues;\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-FGColumnVector3& FGPropulsion::GetTanksMoment(void)\r
-{\r
-  iTank = Tanks.begin();\r
-  vXYZtank.InitMatrix();\r
-  while (iTank < Tanks.end()) {\r
-    vXYZtank(eX) += (*iTank)->GetX()*(*iTank)->GetContents();\r
-    vXYZtank(eY) += (*iTank)->GetY()*(*iTank)->GetContents();\r
-    vXYZtank(eZ) += (*iTank)->GetZ()*(*iTank)->GetContents();\r
-    iTank++;\r
-  }\r
-  return vXYZtank;\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-double FGPropulsion::GetTanksWeight(void)\r
-{\r
-  double Tw = 0.0;\r
-\r
-  iTank = Tanks.begin();\r
-  while (iTank < Tanks.end()) {\r
-    Tw += (*iTank)->GetContents();\r
-    iTank++;\r
-  }\r
-  return Tw;\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-double FGPropulsion::GetTanksIxx(const FGColumnVector3& vXYZcg)\r
-{\r
-  double I = 0.0;\r
-  iTank = Tanks.begin();\r
-  while (iTank < Tanks.end()) {\r
-    I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetX() - vXYZcg(eX)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());\r
-    iTank++;\r
-  }\r
-  return I;\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-double FGPropulsion::GetTanksIyy(const FGColumnVector3& vXYZcg)\r
-{\r
-  double I = 0.0;\r
-  iTank = Tanks.begin();\r
-  while (iTank < Tanks.end()) {\r
-    I += ((*iTank)->GetY() - vXYZcg(eY))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());\r
-    iTank++;\r
-  }\r
-  return I;\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-double FGPropulsion::GetTanksIzz(const FGColumnVector3& vXYZcg)\r
-{\r
-  double I = 0.0;\r
-  iTank = Tanks.begin();\r
-  while (iTank < Tanks.end()) {\r
-    I += ((*iTank)->GetZ() - vXYZcg(eZ))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());\r
-    iTank++;\r
-  }\r
-  return I;\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-double FGPropulsion::GetTanksIxz(const FGColumnVector3& vXYZcg)\r
-{\r
-  double I = 0.0;\r
-  iTank = Tanks.begin();\r
-  while (iTank < Tanks.end()) {\r
-    I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());\r
-    iTank++;\r
-  }\r
-  return I;\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-double FGPropulsion::GetTanksIxy(const FGColumnVector3& vXYZcg)\r
-{\r
-  double I = 0.0;\r
-  iTank = Tanks.begin();\r
-  while (iTank != Tanks.end()) {\r
-    I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());\r
-    iTank++;\r
-  }\r
-  return I;\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-void FGPropulsion::SetMagnetos(int setting)\r
-{\r
-  if (ActiveEngine == -1) {\r
-    for (unsigned i=0; i<Engines.size(); i++) {\r
-      Engines[i]->SetMagnetos(setting);\r
-    }\r
-  } else {\r
-    Engines[ActiveEngine]->SetMagnetos(setting);\r
-  }\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-void FGPropulsion::SetStarter(int setting)\r
-{\r
-  if (ActiveEngine == -1) {\r
-    for (unsigned i=0; i<Engines.size(); i++) {\r
-      Engines[i]->SetStarter(setting);\r
-    }\r
-  } else {\r
-    if (setting == 0)\r
-      Engines[ActiveEngine]->SetStarter(false);\r
-    else\r
-      Engines[ActiveEngine]->SetStarter(true);\r
-  }\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-void FGPropulsion::SetActiveEngine(int engine)\r
-{\r
-  if ( unsigned(engine) > Engines.size())\r
-    ActiveEngine = -1;\r
-  else\r
-    ActiveEngine = engine;\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-void FGPropulsion::bind(void)\r
-{\r
-  typedef double (FGPropulsion::*PMF)(int) const;\r
-  typedef int (FGPropulsion::*iPMF)(void) const;\r
-  /* PropertyManager->Tie("propulsion/num-engines", this,\r
-                       &FGPropulsion::GetNumEngines);\r
-  PropertyManager->Tie("propulsion/num-tanks", this,\r
-                       &FGPropulsion::GetNumTanks); */\r
-\r
-  PropertyManager->Tie("propulsion/magneto_cmd", this,\r
-                       (iPMF)0,\r
-                       &FGPropulsion::SetMagnetos,\r
-                       true);\r
-  PropertyManager->Tie("propulsion/starter_cmd", this,\r
-                       (iPMF)0,\r
-                       &FGPropulsion::SetStarter,\r
-                       true);\r
-  PropertyManager->Tie("propulsion/active_engine", this,\r
-                       (iPMF)0,\r
-                       &FGPropulsion::SetActiveEngine,\r
-                       true);\r
-\r
-  PropertyManager->Tie("propulsion/num-sel-fuel-tanks", this,\r
-                       &FGPropulsion::GetnumSelectedFuelTanks);\r
-  PropertyManager->Tie("propulsion/num-sel-ox-tanks", this,\r
-                       &FGPropulsion::GetnumSelectedOxiTanks);\r
-  PropertyManager->Tie("forces/fbx-prop-lbs", this,1,\r
-                       (PMF)&FGPropulsion::GetForces);\r
-  PropertyManager->Tie("forces/fby-prop-lbs", this,2,\r
-                       (PMF)&FGPropulsion::GetForces);\r
-  PropertyManager->Tie("forces/fbz-prop-lbs", this,3,\r
-                       (PMF)&FGPropulsion::GetForces);\r
-  PropertyManager->Tie("moments/l-prop-lbsft", this,1,\r
-                       (PMF)&FGPropulsion::GetMoments);\r
-  PropertyManager->Tie("moments/m-prop-lbsft", this,2,\r
-                       (PMF)&FGPropulsion::GetMoments);\r
-  PropertyManager->Tie("moments/n-prop-lbsft", this,3,\r
-                       (PMF)&FGPropulsion::GetMoments);\r
-  //PropertyManager->Tie("propulsion/tanks-weight-lbs", this,\r
-  //                     &FGPropulsion::GetTanksWeight);\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-void FGPropulsion::unbind(void)\r
-{\r
-  /* PropertyManager->Untie("propulsion/num-engines");\r
-  PropertyManager->Untie("propulsion/num-tanks"); */\r
-  PropertyManager->Untie("propulsion/num-sel-fuel-tanks");\r
-  PropertyManager->Untie("propulsion/num-sel-ox-tanks");\r
-  PropertyManager->Untie("propulsion/magneto_cmd");\r
-  PropertyManager->Untie("propulsion/starter_cmd");\r
-  PropertyManager->Untie("propulsion/active_engine");\r
-  PropertyManager->Untie("forces/fbx-prop-lbs");\r
-  PropertyManager->Untie("forces/fby-prop-lbs");\r
-  PropertyManager->Untie("forces/fbz-prop-lbs");\r
-  PropertyManager->Untie("moments/l-prop-lbsft");\r
-  PropertyManager->Untie("moments/m-prop-lbsft");\r
-  PropertyManager->Untie("moments/n-prop-lbsft");\r
-  //PropertyManager->Untie("propulsion/tanks-weight-lbs");\r
-}\r
-\r
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-//    The bitmasked value choices are as follows:\r
-//    unset: In this case (the default) JSBSim would only print\r
-//       out the normally expected messages, essentially echoing\r
-//       the config files as they are read. If the environment\r
-//       variable is not set, debug_lvl is set to 1 internally\r
-//    0: This requests JSBSim not to output any messages\r
-//       whatsoever.\r
-//    1: This value explicity requests the normal JSBSim\r
-//       startup messages\r
-//    2: This value asks for a message to be printed out when\r
-//       a class is instantiated\r
-//    4: When this value is set, a message is displayed when a\r
-//       FGModel object executes its Run() method\r
-//    8: When this value is set, various runtime state variables\r
-//       are printed out periodically\r
-//    16: When set various parameters are sanity checked and\r
-//       a message is printed out when they go out of bounds\r
-\r
-void FGPropulsion::Debug(int from)\r
-{\r
-  if (debug_lvl <= 0) return;\r
-\r
-  if (debug_lvl & 1) { // Standard console startup message output\r
-    if (from == 0) { // Constructor\r
-\r
-    }\r
-  }\r
-  if (debug_lvl & 2 ) { // Instantiation/Destruction notification\r
-    if (from == 0) cout << "Instantiated: FGPropulsion" << endl;\r
-    if (from == 1) cout << "Destroyed:    FGPropulsion" << endl;\r
-  }\r
-  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects\r
-  }\r
-  if (debug_lvl & 8 ) { // Runtime state variables\r
-  }\r
-  if (debug_lvl & 16) { // Sanity checking\r
-  }\r
-  if (debug_lvl & 64) {\r
-    if (from == 0) { // Constructor\r
-      cout << IdSrc << endl;\r
-      cout << IdHdr << endl;\r
-    }\r
-  }\r
-}\r
-\r
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module:       FGPropulsion.cpp
+ Author:       Jon S. Berndt
+ Date started: 08/20/00
+ Purpose:      Encapsulates the set of engines and tanks associated
+               with this aircraft
+
+ ------------- Copyright (C) 2000  Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA  02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+The Propulsion class is the container for the entire propulsion system, which is
+comprised of engines and tanks. Once the Propulsion class gets the config file,
+it reads in information which is specific to a type of engine. Then:
+
+1) The appropriate engine type instance is created
+2) At least one tank object is created, and is linked to an engine.
+
+At Run time each engines Calculate() method is called.
+
+HISTORY
+--------------------------------------------------------------------------------
+08/20/00   JSB   Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGPropulsion.h"
+#include "FGRocket.h"
+#include "FGTurbine.h"
+#include "FGPiston.h"
+#include "FGElectric.h"
+#include "FGPropertyManager.h"
+#include <sstream>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_PROPULSION;
+
+extern short debug_lvl;
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
+{
+  Name = "FGPropulsion";
+
+  numSelectedFuelTanks = numSelectedOxiTanks = 0;
+  numTanks = numEngines = 0;
+  numOxiTanks = numFuelTanks = 0;
+  ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...
+  tankJ.InitMatrix();
+  refuel = false;
+  fuel_freeze = false;
+
+  bind();
+
+  Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGPropulsion::~FGPropulsion()
+{
+  for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
+  Engines.clear();
+  unbind();
+  Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropulsion::Run(void)
+{
+  unsigned int i;
+
+  if (FGModel::Run()) return true;
+
+  double dt = State->Getdt();
+
+  vForces.InitMatrix();
+  vMoments.InitMatrix();
+
+  for (i=0; i<numEngines; i++) {
+    Engines[i]->Calculate();
+    vForces  += Engines[i]->GetBodyForces();  // sum body frame forces
+    vMoments += Engines[i]->GetMoments();     // sum body frame moments
+  }
+
+  for (i=0; i<numTanks; i++) {
+    Tanks[i]->Calculate( dt * rate );
+  }
+
+  if (refuel) DoRefuel( dt * rate );
+  
+  return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropulsion::GetSteadyState(void)
+{
+  double currentThrust = 0, lastThrust=-1;
+  int steady_count,j=0;
+  bool steady=false;
+
+  vForces.InitMatrix();
+  vMoments.InitMatrix();
+
+  if (!FGModel::Run()) {
+    for (unsigned int i=0; i<numEngines; i++) {
+      Engines[i]->SetTrimMode(true);
+      steady=false;
+      steady_count=0;
+      while (!steady && j < 6000) {
+        Engines[i]->Calculate();
+        lastThrust = currentThrust;
+        currentThrust = Engines[i]->GetThrust();
+        if (fabs(lastThrust-currentThrust) < 0.0001) {
+          steady_count++;
+          if (steady_count > 120) { steady=true; }
+        } else {
+          steady_count=0;
+        }
+        j++;
+      }
+      vForces  += Engines[i]->GetBodyForces();  // sum body frame forces
+      vMoments += Engines[i]->GetMoments();     // sum body frame moments
+      Engines[i]->SetTrimMode(false);
+    }
+
+    return false;
+  } else {
+    return true;
+  }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropulsion::ICEngineStart(void)
+{
+  int j;
+
+  vForces.InitMatrix();
+  vMoments.InitMatrix();
+
+  for (unsigned int i=0; i<numEngines; i++) {
+    Engines[i]->SetTrimMode(true);
+    j=0;
+    while (!Engines[i]->GetRunning() && j < 2000) {
+      Engines[i]->Calculate();
+      j++;
+    }
+    vForces  += Engines[i]->GetBodyForces();  // sum body frame forces
+    vMoments += Engines[i]->GetMoments();     // sum body frame moments
+    Engines[i]->SetTrimMode(false);
+  }
+  return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropulsion::Load(FGConfigFile* AC_cfg)
+{
+  string token, fullpath, localpath;
+  string engineFileName, engType;
+  string parameter;
+  string enginePath = FDMExec->GetEnginePath();
+  string aircraftPath = FDMExec->GetAircraftPath();
+  double xLoc, yLoc, zLoc, Pitch, Yaw;
+  int Feed;
+  bool ThrottleAdded = false;
+  FGConfigFile* Cfg_ptr = 0;
+
+# ifndef macintosh
+      fullpath = enginePath + "/";
+      localpath = aircraftPath + "/Engines/";
+# else
+      fullpath = enginePath + ";";
+      localpath = aircraftPath +  ";Engines;";
+# endif
+
+  AC_cfg->GetNextConfigLine();
+
+  while ((token = AC_cfg->GetValue()) != string("/PROPULSION")) {
+
+    if (token == "AC_ENGINE") {                   // ============ READING ENGINES
+
+      engineFileName = AC_cfg->GetValue("FILE");
+
+      // Look in the Aircraft/Engines directory first
+      Cfg_ptr = 0;
+      FGConfigFile Local_cfg(localpath + engineFileName + ".xml");
+      FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
+      if (Local_cfg.IsOpen()) {
+        Cfg_ptr = &Local_cfg;
+        if (debug_lvl > 0) cout << "\n    Reading engine from file: " << localpath
+                                                + engineFileName + ".xml"<< endl;
+      } else {
+        if (Eng_cfg.IsOpen()) {
+          Cfg_ptr = &Eng_cfg;
+          if (debug_lvl > 0) cout << "\n    Reading engine from file: " << fullpath
+                                                + engineFileName + ".xml"<< endl;
+        }
+      }
+
+      if (Cfg_ptr) {
+        Cfg_ptr->GetNextConfigLine();
+        engType = Cfg_ptr->GetValue();
+
+        FCS->AddThrottle();
+        ThrottleAdded = true;
+
+        if (engType == "FG_ROCKET") {
+          Engines.push_back(new FGRocket(FDMExec, Cfg_ptr, numEngines));
+        } else if (engType == "FG_PISTON") {
+          Engines.push_back(new FGPiston(FDMExec, Cfg_ptr, numEngines));
+        } else if (engType == "FG_TURBINE") {
+          Engines.push_back(new FGTurbine(FDMExec, Cfg_ptr, numEngines));
+        } else if (engType == "FG_SIMTURBINE") {
+          cerr << endl;
+          cerr << "The FG_SIMTURBINE engine type has been renamed to FG_TURBINE." << endl;
+          cerr << "To fix this problem, simply replace the FG_SIMTURBINE name " << endl;
+          cerr << "in your engine file to FG_TURBINE." << endl;
+          cerr << endl;
+          Engines.push_back(new FGTurbine(FDMExec, Cfg_ptr, numEngines));
+        } else if (engType == "FG_ELECTRIC") {
+          Engines.push_back(new FGElectric(FDMExec, Cfg_ptr, numEngines));
+        } else {
+          cerr << fgred << "    Unrecognized engine type: " << underon << engType
+                    << underoff << " found in config file." << fgdef << endl;
+          return false;
+        }
+
+        AC_cfg->GetNextConfigLine();
+        while ((token = AC_cfg->GetValue()) != string("/AC_ENGINE")) {
+          *AC_cfg >> token;
+          if      (token == "XLOC")  { *AC_cfg >> xLoc; }
+          else if (token == "YLOC")  { *AC_cfg >> yLoc; }
+          else if (token == "ZLOC")  { *AC_cfg >> zLoc; }
+          else if (token == "PITCH") { *AC_cfg >> Pitch;}
+          else if (token == "YAW")   { *AC_cfg >> Yaw;  }
+          else if (token.find("AC_THRUSTER") != string::npos) {
+            if (debug_lvl > 0) cout << "\n    Reading thruster definition" << endl;
+              Engines.back()->LoadThruster(AC_cfg);
+              AC_cfg->GetNextConfigLine();
+          }
+          else if (token == "FEED")  {
+            *AC_cfg >> Feed;
+            Engines[numEngines]->AddFeedTank(Feed);
+            if (debug_lvl > 0) cout << "      Feed tank: " << Feed << endl;
+          } else cerr << "Unknown identifier: " << token << " in engine file: "
+                                                        << engineFileName << endl;
+        }
+
+        if (debug_lvl > 0)  {
+          cout << "      X = " << xLoc << endl;
+          cout << "      Y = " << yLoc << endl;
+          cout << "      Z = " << zLoc << endl;
+          cout << "      Pitch = " << Pitch << endl;
+          cout << "      Yaw = " << Yaw << endl;
+        }
+
+        Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw);
+        numEngines++;
+
+      } else {
+
+        cerr << fgred << "\n  Could not read engine config file: " << underon <<
+                    engineFileName + ".xml" << underoff << fgdef << endl;
+        return false;
+      }
+
+    } else if (token == "AC_TANK") {              // ============== READING TANKS
+
+      if (debug_lvl > 0) cout << "\n    Reading tank definition" << endl;
+      Tanks.push_back(new FGTank(AC_cfg, FDMExec));
+      switch(Tanks[numTanks]->GetType()) {
+      case FGTank::ttFUEL:
+        numSelectedFuelTanks++;
+        numFuelTanks++;
+        break;
+      case FGTank::ttOXIDIZER:
+        numSelectedOxiTanks++;
+        numOxiTanks++;
+        break;
+      }
+
+      numTanks++;
+    }
+    AC_cfg->GetNextConfigLine();
+  }
+
+  CalculateTankInertias();
+  if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
+
+  return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropulsion::GetPropulsionStrings(string delimeter)
+{
+  unsigned int i;
+
+  string PropulsionStrings = "";
+  bool firstime = true;
+  stringstream buf;
+
+  for (i=0; i<Engines.size(); i++) {
+    if (firstime)  firstime = false;
+    else           PropulsionStrings += delimeter;
+
+    PropulsionStrings += Engines[i]->GetEngineLabels(delimeter);
+  }
+  for (i=0; i<Tanks.size(); i++) {
+    if (Tanks[i]->GetType() == FGTank::ttFUEL) buf << delimeter << "Fuel Tank " << i;
+    else if (Tanks[i]->GetType() == FGTank::ttOXIDIZER) buf << delimeter << "Oxidizer Tank " << i;
+  }
+
+  return PropulsionStrings;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropulsion::GetPropulsionValues(string delimeter)
+{
+  unsigned int i;
+
+  string PropulsionValues = "";
+  bool firstime = true;
+  stringstream buf;
+
+  for (i=0; i<Engines.size(); i++) {
+    if (firstime)  firstime = false;
+    else           PropulsionValues += delimeter;
+
+    PropulsionValues += Engines[i]->GetEngineValues(delimeter);
+  }
+  for (i=0; i<Tanks.size(); i++) {
+    buf << delimeter;
+    buf << Tanks[i]->GetContents();
+  }
+
+  return PropulsionValues;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3& FGPropulsion::GetTanksMoment(void)
+{
+  iTank = Tanks.begin();
+  vXYZtank_arm.InitMatrix();
+  while (iTank < Tanks.end()) {
+    vXYZtank_arm(eX) += (*iTank)->GetXYZ(eX)*(*iTank)->GetContents();
+    vXYZtank_arm(eY) += (*iTank)->GetXYZ(eY)*(*iTank)->GetContents();
+    vXYZtank_arm(eZ) += (*iTank)->GetXYZ(eZ)*(*iTank)->GetContents();
+    iTank++;
+  }
+  return vXYZtank_arm;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGPropulsion::GetTanksWeight(void)
+{
+  double Tw = 0.0;
+
+  iTank = Tanks.begin();
+  while (iTank < Tanks.end()) {
+    Tw += (*iTank)->GetContents();
+    iTank++;
+  }
+  return Tw;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33& FGPropulsion::CalculateTankInertias(void)
+{
+  unsigned int size;
+
+  size = Tanks.size();
+  if (size == 0) return tankJ;
+
+  tankJ = FGMatrix33();
+
+  for (unsigned int i=0; i<size; i++)
+    tankJ += MassBalance->GetPointmassInertia( lbtoslug * Tanks[i]->GetContents(),
+                                               Tanks[i]->GetXYZ() );
+
+  return tankJ;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::SetMagnetos(int setting)
+{
+  if (ActiveEngine < 0) {
+    for (unsigned i=0; i<Engines.size(); i++) {
+      ((FGPiston*)Engines[i])->SetMagnetos(setting);
+    }
+  } else {
+    ((FGPiston*)Engines[ActiveEngine])->SetMagnetos(setting);
+  }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::SetStarter(int setting)
+{
+  if (ActiveEngine < 0) {
+    for (unsigned i=0; i<Engines.size(); i++) {
+      if (setting == 0)
+        Engines[i]->SetStarter(false);
+      else
+        Engines[i]->SetStarter(true);
+    }
+  } else {
+    if (setting == 0)
+      Engines[ActiveEngine]->SetStarter(false);
+    else
+      Engines[ActiveEngine]->SetStarter(true);
+  }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::SetCutoff(int setting)
+{
+  if (ActiveEngine < 0) {
+    for (unsigned i=0; i<Engines.size(); i++) {
+      if (setting == 0)
+        ((FGTurbine*)Engines[i])->SetCutoff(false);
+      else
+        ((FGTurbine*)Engines[i])->SetCutoff(true);
+    }
+  } else {
+    if (setting == 0)
+      ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(false);
+    else
+      ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(true);
+  }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::SetActiveEngine(int engine)
+{
+  if (engine >= Engines.size() || engine < 0)
+    ActiveEngine = -1;
+  else
+    ActiveEngine = engine;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGPropulsion::Transfer(int source, int target, double amount)
+{
+ double shortage, overage;
+
+  if (source == -1) {
+     shortage = 0.0;
+  } else {
+     shortage = Tanks[source]->Drain(amount);
+  }
+  if (target == -1) {
+     overage = 0.0;
+  } else {
+     overage = Tanks[target]->Fill(amount - shortage);
+  }
+  return overage;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::DoRefuel(double time_slice)
+{
+  double fillrate = 100 * time_slice;   // 100 lbs/sec = 6000 lbs/min
+  int TanksNotFull = 0;
+
+  for (unsigned int i=0; i<numTanks; i++) {
+    if (Tanks[i]->GetPctFull() < 99.99) ++TanksNotFull;
+  }
+
+  if (TanksNotFull) {
+    for (unsigned int i=0; i<numTanks; i++) {
+      if (Tanks[i]->GetPctFull() < 99.99)
+          Transfer(-1, i, fillrate/TanksNotFull);
+    }
+  }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::SetFuelFreeze(bool f) 
+{
+  fuel_freeze = f;
+  for (unsigned int i=0; i<numEngines; i++) {
+    Engines[i]->SetFuelFreeze(f);
+  }
+}  
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::bind(void)
+{
+  typedef double (FGPropulsion::*PMF)(int) const;
+  typedef int (FGPropulsion::*iPMF)(void) const;
+
+  PropertyManager->Tie("propulsion/magneto_cmd", this,
+                       (iPMF)0, &FGPropulsion::SetMagnetos, true);
+  PropertyManager->Tie("propulsion/starter_cmd", this,
+                       (iPMF)0, &FGPropulsion::SetStarter,  true);
+  PropertyManager->Tie("propulsion/cutoff_cmd", this,
+                       (iPMF)0, &FGPropulsion::SetCutoff,   true);
+
+  PropertyManager->Tie("forces/fbx-prop-lbs", this,1,
+                       (PMF)&FGPropulsion::GetForces);
+  PropertyManager->Tie("forces/fby-prop-lbs", this,2,
+                       (PMF)&FGPropulsion::GetForces);
+  PropertyManager->Tie("forces/fbz-prop-lbs", this,3,
+                       (PMF)&FGPropulsion::GetForces);
+  PropertyManager->Tie("moments/l-prop-lbsft", this,1,
+                       (PMF)&FGPropulsion::GetMoments);
+  PropertyManager->Tie("moments/m-prop-lbsft", this,2,
+                       (PMF)&FGPropulsion::GetMoments);
+  PropertyManager->Tie("moments/n-prop-lbsft", this,3,
+                       (PMF)&FGPropulsion::GetMoments);
+
+  PropertyManager->Tie("propulsion/active_engine", this,
+           (iPMF)&FGPropulsion::GetActiveEngine, &FGPropulsion::SetActiveEngine, true);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::unbind(void)
+{
+  PropertyManager->Untie("propulsion/magneto_cmd");
+  PropertyManager->Untie("propulsion/starter_cmd");
+  PropertyManager->Untie("propulsion/cutoff_cmd");
+  PropertyManager->Untie("propulsion/active_engine");
+  PropertyManager->Untie("forces/fbx-prop-lbs");
+  PropertyManager->Untie("forces/fby-prop-lbs");
+  PropertyManager->Untie("forces/fbz-prop-lbs");
+  PropertyManager->Untie("moments/l-prop-lbsft");
+  PropertyManager->Untie("moments/m-prop-lbsft");
+  PropertyManager->Untie("moments/n-prop-lbsft");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//    The bitmasked value choices are as follows:
+//    unset: In this case (the default) JSBSim would only print
+//       out the normally expected messages, essentially echoing
+//       the config files as they are read. If the environment
+//       variable is not set, debug_lvl is set to 1 internally
+//    0: This requests JSBSim not to output any messages
+//       whatsoever.
+//    1: This value explicity requests the normal JSBSim
+//       startup messages
+//    2: This value asks for a message to be printed out when
+//       a class is instantiated
+//    4: When this value is set, a message is displayed when a
+//       FGModel object executes its Run() method
+//    8: When this value is set, various runtime state variables
+//       are printed out periodically
+//    16: When set various parameters are sanity checked and
+//       a message is printed out when they go out of bounds
+
+void FGPropulsion::Debug(int from)
+{
+  if (debug_lvl <= 0) return;
+
+  if (debug_lvl & 1) { // Standard console startup message output
+    if (from == 0) { // Constructor
+
+    }
+  }
+  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+    if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
+    if (from == 1) cout << "Destroyed:    FGPropulsion" << endl;
+  }
+  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+  }
+  if (debug_lvl & 8 ) { // Runtime state variables
+  }
+  if (debug_lvl & 16) { // Sanity checking
+  }
+  if (debug_lvl & 64) {
+    if (from == 0) { // Constructor
+      cout << IdSrc << endl;
+      cout << IdHdr << endl;
+    }
+  }
+}
+}