]> git.mxchange.org Git - flightgear.git/blobdiff - src/FDM/JSBSim/FGFDMExec.cpp
Synchronized with JSBSim/CVS
[flightgear.git] / src / FDM / JSBSim / FGFDMExec.cpp
index d5c81f8217d5a6f7b3e8b33f30e9fb49f7facac9..b61529229c40c3947ff50ab9792c1792907a8bb8 100644 (file)
@@ -1,3 +1,4 @@
+
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
  Module:       FGFDMExec.cpp
@@ -63,14 +64,18 @@ INCLUDES
 #include "models/FGInput.h"
 #include "models/FGOutput.h"
 #include "initialization/FGInitialCondition.h"
+#include "initialization/FGSimplexTrim.h"
+#include "initialization/FGLinearization.h"
 #include "input_output/FGPropertyManager.h"
 #include "input_output/FGScript.h"
+#include "input_output/FGXMLFileRead.h"
+#include "input_output/FGXMLElement.h"
 
 using namespace std;
 
 namespace JSBSim {
 
-static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.120 2011/11/10 12:06:13 jberndt Exp $";
+static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.150 2013/11/24 11:40:55 bcoconni Exp $";
 static const char *IdHdr = ID_FDMEXEC;
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -96,7 +101,9 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
   holding = false;
   Terminate = false;
   StandAlone = false;
-  firstPass = true;
+
+  IncrementThenHolding = false;  // increment then hold is off by default
+  TimeStepsUntilHold = -1;
 
   sim_time = 0.0;
   dT = 1.0/120.0; // a default timestep size. This is needed for when JSBSim is
@@ -125,11 +132,12 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
 
   // Store this FDM's ID
   IdFDM = (*FDMctr); // The main (parent) JSBSim instance is always the "zeroth"
-                                                                      
+
   // Prepare FDMctr for the next child FDM id
   (*FDMctr)++;       // instance. "child" instances are loaded last.
 
-  instance = Root->GetNode("/fdm/jsbsim",IdFDM,true);
+  FGPropertyNode* instanceRoot = Root->GetNode("/fdm/jsbsim",IdFDM,true);
+  instance = new FGPropertyManager(instanceRoot);
   Debug(0);
   // this is to catch errors in binding member functions to the property tree.
   try {
@@ -144,14 +152,62 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
 
   Constructing = true;
   typedef int (FGFDMExec::*iPMF)(void) const;
+  typedef double (FGFDMExec::*dPMF)(void) const;
+//  typedef unsigned int (FGFDMExec::*uiPMF)(void) const;
 //  instance->Tie("simulation/do_trim_analysis", this, (iPMF)0, &FGFDMExec::DoTrimAnalysis, false);
   instance->Tie("simulation/do_simple_trim", this, (iPMF)0, &FGFDMExec::DoTrim, false);
+  instance->Tie("simulation/do_simplex_trim", this, (iPMF)0, &FGFDMExec::DoSimplexTrim);
+  instance->Tie("simulation/do_linearization", this, (iPMF)0, &FGFDMExec::DoLinearization);
   instance->Tie("simulation/reset", this, (iPMF)0, &FGFDMExec::ResetToInitialConditions, false);
+  instance->Tie("simulation/randomseed", this, (iPMF)0, &FGFDMExec::SRand, false);
   instance->Tie("simulation/terminate", (int *)&Terminate);
   instance->Tie("simulation/sim-time-sec", this, &FGFDMExec::GetSimTime);
+  instance->Tie("simulation/dt", this, &FGFDMExec::GetDeltaT);
   instance->Tie("simulation/jsbsim-debug", this, &FGFDMExec::GetDebugLevel, &FGFDMExec::SetDebugLevel);
   instance->Tie("simulation/frame", (int *)&Frame, false);
 
+  // simplex trim properties
+  instanceRoot->SetDouble("trim/solver/rtol",0.0001);
+  instanceRoot->SetDouble("trim/solver/speed",2);
+  instanceRoot->SetDouble("trim/solver/abstol",0.001);
+  instanceRoot->SetDouble("trim/solver/iterMax",2000);
+  instanceRoot->SetInt("trim/solver/debugLevel",0);
+  instanceRoot->SetDouble("trim/solver/random",0);
+  instanceRoot->SetBool("trim/solver/showSimplex",false);
+  instanceRoot->SetBool("trim/solver/showConvergence",false);
+  instanceRoot->SetBool("trim/solver/pause",false);
+  instanceRoot->SetBool("trim/solver/variablePropPitch",false);
+
+  instanceRoot->SetDouble("trim/solver/throttleGuess",0.50);
+  instanceRoot->SetDouble("trim/solver/throttleMin",0.0);
+  instanceRoot->SetDouble("trim/solver/throttleMax",1.0);
+  instanceRoot->SetDouble("trim/solver/throttleStep",0.1);
+
+  instanceRoot->SetDouble("trim/solver/aileronGuess",0);
+  instanceRoot->SetDouble("trim/solver/aileronMin",-1.00);
+  instanceRoot->SetDouble("trim/solver/aileronMax",1.00);
+  instanceRoot->SetDouble("trim/solver/aileronStep",0.1);
+
+  instanceRoot->SetDouble("trim/solver/rudderGuess",0);
+  instanceRoot->SetDouble("trim/solver/rudderMin",-1.00);
+  instanceRoot->SetDouble("trim/solver/rudderMax",1.00);
+  instanceRoot->SetDouble("trim/solver/rudderStep",0.1);
+
+  instanceRoot->SetDouble("trim/solver/elevatorGuess",-0.1);
+  instanceRoot->SetDouble("trim/solver/elevatorMin",-1.0);
+  instanceRoot->SetDouble("trim/solver/elevatorMax",1.0);
+  instanceRoot->SetDouble("trim/solver/elevatorStep",0.1);
+
+  instanceRoot->SetDouble("trim/solver/alphaGuess",0.05);
+  instanceRoot->SetDouble("trim/solver/alphaMin",-0.1);
+  instanceRoot->SetDouble("trim/solver/alphaMax",.18);
+  instanceRoot->SetDouble("trim/solver/alphaStep",0.05);
+
+  instanceRoot->SetDouble("trim/solver/betaGuess",0);
+  instanceRoot->SetDouble("trim/solver/betaMin",-0.1);
+  instanceRoot->SetDouble("trim/solver/betaMax",0.1);
+  instanceRoot->SetDouble("trim/solver/betaStep",0.0001);
+
   Constructing = false;
 }
 
@@ -162,7 +218,9 @@ FGFDMExec::~FGFDMExec()
   try {
     Unbind();
     DeAllocate();
-    
+
+    delete instance;
+
     if (IdFDM == 0) { // Meaning this is no child FDM
       if(Root != 0) {
          if(StandAlone)
@@ -208,15 +266,13 @@ bool FGFDMExec::Allocate(void)
   Models[eSystems]           = new FGFCS(this);
   Models[ePropulsion]        = new FGPropulsion(this);
   Models[eAerodynamics]      = new FGAerodynamics (this);
-
-  GetGroundCallback()->SetSeaLevelRadius(((FGInertial*)Models[eInertial])->GetRefRadius());
-
   Models[eGroundReactions]   = new FGGroundReactions(this);
   Models[eExternalReactions] = new FGExternalReactions(this);
   Models[eBuoyantForces]     = new FGBuoyantForces(this);
   Models[eMassBalance]       = new FGMassBalance(this);
   Models[eAircraft]          = new FGAircraft(this);
   Models[eAccelerations]     = new FGAccelerations(this);
+  Models[eOutput]            = new FGOutput(this);
 
   // Assign the Model shortcuts for internal executive use only.
   Propagate = (FGPropagate*)Models[ePropagate];
@@ -233,12 +289,17 @@ bool FGFDMExec::Allocate(void)
   MassBalance = (FGMassBalance*)Models[eMassBalance];
   Aircraft = (FGAircraft*)Models[eAircraft];
   Accelerations = (FGAccelerations*)Models[eAccelerations];
+  Output = (FGOutput*)Models[eOutput];
 
   // Initialize planet (environment) constants
   LoadPlanetConstants();
+  GetGroundCallback()->SetSeaLevelRadius(Inertial->GetRefRadius());
 
   // Initialize models
   for (unsigned int i = 0; i < Models.size(); i++) {
+    // The Output model must not be initialized prior to IC loading
+    if (i == eOutput) continue;
+
     LoadInputs(i);
     Models[i]->InitModel();
   }
@@ -258,9 +319,6 @@ bool FGFDMExec::DeAllocate(void)
   for (unsigned int i=0; i<eNumStandardModels; i++) delete Models[i];
   Models.clear();
 
-  for (unsigned i=0; i<Outputs.size(); i++) delete Outputs[i];
-  Outputs.clear();
-
   delete Script;
   delete IC;
   delete Trim;
@@ -292,14 +350,6 @@ bool FGFDMExec::Run(void)
     ChildFDMList[i]->Run();
   }
 
-  if (firstPass && !IntegrationSuspended()) {
-    // Outputs the initial conditions
-    for (unsigned int i = 0; i < Outputs.size(); i++)
-      Outputs[i]->Run(holding);
-
-    firstPass = false;
-  }
-
   IncrTime();
 
   // returns true if success, false if complete
@@ -366,8 +416,6 @@ void FGFDMExec::LoadInputs(unsigned int idx)
     Auxiliary->in.RPBody       = MassBalance->StructuralToBody(Aircraft->GetXYZrp());
     Auxiliary->in.vFw          = Aerodynamics->GetvFw();
     Auxiliary->in.vLocation    = Propagate->GetLocation();
-    Auxiliary->in.Latitude     = Propagate->GetLatitude();
-    Auxiliary->in.Longitude    = Propagate->GetLongitude();
     Auxiliary->in.CosTht       = Propagate->GetCosEuler(eTht);
     Auxiliary->in.SinTht       = Propagate->GetSinEuler(eTht);
     Auxiliary->in.CosPhi       = Propagate->GetCosEuler(ePhi);
@@ -408,6 +456,7 @@ void FGFDMExec::LoadInputs(unsigned int idx)
     Propulsion->in.PropFeather      = FCS->GetPropFeather();
     Propulsion->in.H_agl            = Propagate->GetDistanceAGL();
     Propulsion->in.PQR              = Propagate->GetPQR();
+
     break;
   case eAerodynamics:
     Aerodynamics->in.Alpha     = Auxiliary->Getalpha();
@@ -438,9 +487,7 @@ void FGFDMExec::LoadInputs(unsigned int idx)
     GroundReactions->in.TotalDeltaT     = dT * GroundReactions->GetRate();
     GroundReactions->in.WOW             = GroundReactions->GetWOW();
     GroundReactions->in.Location        = Propagate->GetLocation();
-    for (int i=0; i<GroundReactions->GetNumGearUnits(); i++) {
-      GroundReactions->in.vWhlBodyVec[i] = MassBalance->StructuralToBody(GroundReactions->GetGearUnit(i)->GetLocation());
-    }
+    GroundReactions->in.vXYZcg          = MassBalance->GetXYZcg();
     break;
   case eExternalReactions:
     // There are no external inputs to this model.
@@ -470,8 +517,6 @@ void FGFDMExec::LoadInputs(unsigned int idx)
     Aircraft->in.GroundMoment  = GroundReactions->GetMoments();
     Aircraft->in.ExternalMoment = ExternalReactions->GetMoments();
     Aircraft->in.BuoyantMoment = BuoyantForces->GetMoments();
-    Aircraft->in.Weight        = MassBalance->GetWeight();
-    Aircraft->in.Tl2b          = Propagate->GetTl2b();
     break;
   case eAccelerations:
     Accelerations->in.J        = MassBalance->GetJ();
@@ -479,7 +524,7 @@ void FGFDMExec::LoadInputs(unsigned int idx)
     Accelerations->in.Ti2b     = Propagate->GetTi2b();
     Accelerations->in.Tb2i     = Propagate->GetTb2i();
     Accelerations->in.Tec2b    = Propagate->GetTec2b();
-    Accelerations->in.Tl2b     = Propagate->GetTl2b();
+    Accelerations->in.Tec2i    = Propagate->GetTec2i();
     Accelerations->in.qAttitudeECI = Propagate->GetQuaternionECI();
     Accelerations->in.Moment   = Aircraft->GetMoments();
     Accelerations->in.GroundMoment  = GroundReactions->GetMoments();
@@ -508,7 +553,6 @@ void FGFDMExec::LoadPlanetConstants(void)
 {
   Propagate->in.vOmegaPlanet     = Inertial->GetOmegaPlanet();
   Accelerations->in.vOmegaPlanet = Inertial->GetOmegaPlanet();
-  Propagate->in.RefRadius        = Inertial->GetRefRadius();
   Propagate->in.SemiMajor        = Inertial->GetSemimajor();
   Propagate->in.SemiMinor        = Inertial->GetSemiminor();
   Auxiliary->in.SLGravity        = Inertial->SLgravity();
@@ -527,9 +571,7 @@ void FGFDMExec::LoadModelConstants(void)
   Aerodynamics->in.Wingspan      = Aircraft->GetWingSpan();
   Auxiliary->in.Wingspan         = Aircraft->GetWingSpan();
   Auxiliary->in.Wingchord        = Aircraft->Getcbar();
-  for (int i=0; i<GroundReactions->GetNumGearUnits(); i++) {
-    GroundReactions->in.vWhlBodyVec[i] = MassBalance->StructuralToBody(GroundReactions->GetGearUnit(i)->GetLocation());
-  }
+  GroundReactions->in.vXYZcg     = MassBalance->GetXYZcg();
 
   LoadPlanetConstants();
 }
@@ -539,11 +581,18 @@ void FGFDMExec::LoadModelConstants(void)
 
 bool FGFDMExec::RunIC(void)
 {
+  FGPropulsion* propulsion = (FGPropulsion*)Models[ePropulsion];
+
+  Models[eOutput]->InitModel();
+
   SuspendIntegration(); // saves the integration rate, dt, then sets it to 0.0.
   Initialize(IC);
   Run();
   ResumeIntegration(); // Restores the integration rate to what it was.
 
+  for (unsigned int i=0; i<IC->GetNumEnginesRunning(); i++)
+    propulsion->InitRunning(IC->GetEngineRunning(i));
+
   return true;
 }
 
@@ -571,12 +620,8 @@ void FGFDMExec::Initialize(FGInitialCondition *FGIC)
 
 void FGFDMExec::ResetToInitialConditions(int mode)
 {
-  if (mode == 1) {
-    for (unsigned int i=0; i<Outputs.size(); i++) {
-      Outputs[i]->SetStartNewFile(true); 
-    }
-  }
-  
+  if (mode == 1) Output->SetStartNewOutput();
+
   ResetToInitialConditions();
 }
 
@@ -586,28 +631,17 @@ void FGFDMExec::ResetToInitialConditions(void)
 {
   if (Constructing) return;
 
-  vector <FGModel*>::iterator it;
-  for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel();
-
-  RunIC();
-  if (Script) Script->ResetEvents();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  for (unsigned int i = 0; i < Models.size(); i++) {
+    // The Output model will be initialized during the RunIC() execution
+    if (i == eOutput) continue;
 
-bool FGFDMExec::SetOutputFileName(const string& fname)
-{
-  if (Outputs.size() > 0) Outputs[0]->SetOutputFileName(fname);
-  else return false;
-  return true;
-}
+    LoadInputs(i);
+    Models[i]->InitModel();
+  }
 
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  RunIC();
 
-string FGFDMExec::GetOutputFileName(void)
-{
-  if (Outputs.size() > 0) return Outputs[0]->GetOutputFileName();
-  else return string("");
+  if (Script) Script->ResetEvents();
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -628,12 +662,12 @@ vector <string> FGFDMExec::EnumerateFDMs(void)
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-bool FGFDMExec::LoadScript(const string& script, double deltaT)
+bool FGFDMExec::LoadScript(const string& script, double deltaT, const string initfile)
 {
   bool result;
 
   Script = new FGScript(this);
-  result = Script->LoadScript(RootDir + script, deltaT);
+  result = Script->LoadScript(RootDir + script, deltaT, initfile);
 
   return result;
 }
@@ -677,8 +711,9 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
   }
 
   int saved_debug_lvl = debug_lvl;
+  FGXMLFileRead XMLFileRead;
+  Element *document = XMLFileRead.LoadXMLDocument(aircraftCfgFileName); // "document" is a class member
 
-  document = LoadXMLDocument(aircraftCfgFileName); // "document" is a class member
   if (document) {
     if (IsChild) debug_lvl = 0;
 
@@ -824,25 +859,20 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
     }
 
     // Process the output element[s]. This element is OPTIONAL, and there may be more than one.
-    unsigned int idx=0;
-    typedef double (FGOutput::*iOPMF)(void) const;
-    typedef int (FGFDMExec::*iOPV)(void) const;
     element = document->FindElement("output");
     while (element) {
-      if (debug_lvl > 0) cout << endl << "  Output data set: " << idx << "  ";
-      FGOutput* Output = new FGOutput(this);
-      Output->InitModel();
-      Schedule(Output);
-      result = Output->Load(element);
+      string output_file_name = aircraftCfgFileName;
+
+      if (!element->GetAttributeValue("file").empty()) {
+        output_file_name = RootDir + element->GetAttributeValue("file");
+        result = ((FGOutput*)Models[eOutput])->SetDirectivesFile(output_file_name);
+      }
+      else
+        result = ((FGOutput*)Models[eOutput])->Load(element);
+
       if (!result) {
-        cerr << endl << "Aircraft output element has problems in file " << aircraftCfgFileName << endl;
+        cerr << endl << "Aircraft output element has problems in file " << output_file_name << endl;
         return result;
-      } else {
-        Outputs.push_back(Output);
-        string outputProp = CreateIndexedPropertyName("simulation/output",idx);
-        instance->Tie(outputProp+"/log_rate_hz", Output, (iOPMF)0, &FGOutput::SetRate, false);
-        instance->Tie("simulation/force-output", this, (iOPV)0, &FGFDMExec::ForceOutput, false);
-        idx++;
       }
       element = document->FindNextElement("output");
     }
@@ -866,6 +896,10 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
     if (debug_lvl > 0) {
       LoadInputs(eMassBalance); // Update all input mass properties for the report.
       Models[eMassBalance]->Run(false);  // Update all mass properties for the report.
+      LoadInputs(ePropulsion); // Update propulsion properties for the report.
+      Models[ePropulsion]->Run(false);  // Update propulsion properties for the report.
+      LoadInputs(eMassBalance); // Update all (one more time) input mass properties for the report.
+      Models[eMassBalance]->Run(false);  // Update all (one more time) mass properties for the report.
       ((FGMassBalance*)Models[eMassBalance])->GetMassPropertiesReport();
 
       cout << endl << fgblue << highint
@@ -873,7 +907,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
            << "-------------------------------------------------------------------------------"
            << reset << endl;
     }
-    
+
     if (IsChild) debug_lvl = saved_debug_lvl;
 
   } else {
@@ -887,7 +921,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
   if (result) {
     struct PropertyCatalogStructure masterPCS;
     masterPCS.base_string = "";
-    masterPCS.node = (FGPropertyManager*)Root;
+    masterPCS.node = Root->GetNode();
     BuildPropertyCatalog(&masterPCS);
   }
 
@@ -909,18 +943,21 @@ void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs)
   int node_idx = 0;
 
   for (int i=0; i<pcs->node->nChildren(); i++) {
+    string access="";
     pcsNew->base_string = pcs->base_string + "/" + pcs->node->getChild(i)->getName();
     node_idx = pcs->node->getChild(i)->getIndex();
     if (node_idx != 0) {
       pcsNew->base_string = CreateIndexedPropertyName(pcsNew->base_string, node_idx);
     }
     if (pcs->node->getChild(i)->nChildren() == 0) {
-      if (pcsNew->base_string.substr(0,11) == string("/fdm/jsbsim")) {
+      if (pcsNew->base_string.substr(0,12) == string("/fdm/jsbsim/")) {
         pcsNew->base_string = pcsNew->base_string.erase(0,12);
       }
-      PropertyCatalog.push_back(pcsNew->base_string);
+      if (pcs->node->getChild(i)->getAttribute(SGPropertyNode::READ)) access="R";
+      if (pcs->node->getChild(i)->getAttribute(SGPropertyNode::WRITE)) access+="W";
+      PropertyCatalog.push_back(pcsNew->base_string+" ("+access+")");
     } else {
-      pcsNew->node = (FGPropertyManager*)pcs->node->getChild(i);
+      pcsNew->node = (FGPropertyNode*)pcs->node->getChild(i);
       BuildPropertyCatalog(pcsNew);
     }
   }
@@ -1072,7 +1109,7 @@ bool FGFDMExec::ReadChild(Element* el)
     cerr << endl << highint << fgred << "  No location was found for this child object!" << reset << endl;
     exit(-1);
   }
-  
+
   Element* orientation = el->FindElement("orient");
   if (orientation) {
     child->Orient = orientation->FindElementTripletConvertTo("RAD");
@@ -1103,52 +1140,26 @@ FGTrim* FGFDMExec::GetTrim(void)
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGFDMExec::DisableOutput(void)
+void FGFDMExec::CheckIncrementalHold(void)
 {
-  for (unsigned i=0; i<Outputs.size(); i++) {
-    Outputs[i]->Disable();
-  }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGFDMExec::EnableOutput(void)
-{
-  for (unsigned i=0; i<Outputs.size(); i++) {
-    Outputs[i]->Enable();
-  }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGFDMExec::ForceOutput(int idx)
-{
-  if (idx >= (int)0 && idx < (int)Outputs.size()) Outputs[idx]->Print();
-}
+  // Only check if increment then hold is on
+  if( IncrementThenHolding ) {
 
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if (TimeStepsUntilHold == 0) {
 
-bool FGFDMExec::SetOutputDirectives(const string& fname)
-{
-  bool result;
+      // Should hold simulation if TimeStepsUntilHold has reached zero
+      holding = true;
 
-  FGOutput* Output = new FGOutput(this);
-  Output->SetDirectivesFile(RootDir + fname);
-  Output->InitModel();
-  Schedule(Output);
-  result = Output->Load(0);
+      // Still need to decrement TimeStepsUntilHold as value of -1
+      // indicates that incremental then hold is turned off
+      IncrementThenHolding = false;
+      TimeStepsUntilHold--;
 
-  if (result) {
-    Output->Run(holding);
-    Outputs.push_back(Output);
-    typedef double (FGOutput::*iOPMF)(void) const;
-    string outputProp = CreateIndexedPropertyName("simulation/output",Outputs.size()-1);
-    instance->Tie(outputProp+"/log_rate_hz", Output, (iOPMF)0, &FGOutput::SetRate, false);
+    } else if ( TimeStepsUntilHold > 0 ) {
+      // Keep decrementing until 0 is reached
+      TimeStepsUntilHold--;
+    }
   }
-  else
-    delete Output;
-
-  return result;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1170,6 +1181,42 @@ void FGFDMExec::DoTrim(int mode)
   sim_time = saved_time;
 }
 
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFDMExec::DoSimplexTrim(int mode)
+{
+  double saved_time;
+  if (Constructing) return;
+  if (mode < 0 || mode > JSBSim::tNone) {
+      cerr << endl << "Illegal trimming mode!" << endl << endl;
+      return;
+  }
+  saved_time = sim_time;
+  FGSimplexTrim trim(this, (JSBSim::TrimMode)mode);
+  sim_time = saved_time;
+  Setsim_time(saved_time);
+  std::cout << "dT: " << dT << std::endl;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFDMExec::DoLinearization(int mode)
+{
+  double saved_time;
+  if (Constructing) return;
+  saved_time = sim_time;
+  FGLinearization lin(this,mode);
+  sim_time = saved_time;
+  Setsim_time(saved_time);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFDMExec::SRand(int sr)
+{
+  srand(sr);
+}
+
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 //    The bitmasked value choices are as follows:
 //    unset: In this case (the default) JSBSim would only print
@@ -1195,7 +1242,7 @@ void FGFDMExec::Debug(int from)
 
   if (debug_lvl & 1 && IdFDM == 0) { // Standard console startup message output
     if (from == 0) { // Constructor
-      cout << "\n\n     " 
+      cout << "\n\n     "
            << "JSBSim Flight Dynamics Model v" << JSBSim_version << endl;
       cout << "            [JSBSim-ML v" << needed_cfg_version << "]\n\n";
       cout << "JSBSim startup beginning ...\n\n";