]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGFDMExec.cpp
Synchronized with JSBSim/CVS
[flightgear.git] / src / FDM / JSBSim / FGFDMExec.cpp
1
2 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
4  Module:       FGFDMExec.cpp
5  Author:       Jon S. Berndt
6  Date started: 11/17/98
7  Purpose:      Schedules and runs the model routines.
8
9  ------------- Copyright (C) 1999  Jon S. Berndt (jon@jsbsim.org) -------------
10
11  This program is free software; you can redistribute it and/or modify it under
12  the terms of the GNU Lesser General Public License as published by the Free Software
13  Foundation; either version 2 of the License, or (at your option) any later
14  version.
15
16  This program is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
19  details.
20
21  You should have received a copy of the GNU Lesser General Public License along with
22  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23  Place - Suite 330, Boston, MA  02111-1307, USA.
24
25  Further information about the GNU Lesser General Public License can also be found on
26  the world wide web at http://www.gnu.org.
27
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30
31 This class wraps up the simulation scheduling routines.
32
33 HISTORY
34 --------------------------------------------------------------------------------
35 11/17/98   JSB   Created
36
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 COMMENTS, REFERENCES,  and NOTES
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40
41 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 INCLUDES
43 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
44
45 #include <iostream>
46 #include <iterator>
47 #include <cstdlib>
48
49 #include "FGFDMExec.h"
50 #include "models/atmosphere/FGStandardAtmosphere.h"
51 #include "models/atmosphere/FGWinds.h"
52 #include "models/FGFCS.h"
53 #include "models/FGPropulsion.h"
54 #include "models/FGMassBalance.h"
55 #include "models/FGGroundReactions.h"
56 #include "models/FGExternalReactions.h"
57 #include "models/FGBuoyantForces.h"
58 #include "models/FGAerodynamics.h"
59 #include "models/FGInertial.h"
60 #include "models/FGAircraft.h"
61 #include "models/FGAccelerations.h"
62 #include "models/FGPropagate.h"
63 #include "models/FGAuxiliary.h"
64 #include "models/FGInput.h"
65 #include "models/FGOutput.h"
66 #include "initialization/FGInitialCondition.h"
67 #include "initialization/FGSimplexTrim.h"
68 #include "initialization/FGLinearization.h"
69 #include "input_output/FGPropertyManager.h"
70 #include "input_output/FGScript.h"
71 #include "input_output/FGXMLFileRead.h"
72 #include "input_output/FGXMLElement.h"
73
74 using namespace std;
75
76 namespace JSBSim {
77
78 static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.150 2013/11/24 11:40:55 bcoconni Exp $";
79 static const char *IdHdr = ID_FDMEXEC;
80
81 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82 CLASS IMPLEMENTATION
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
84
85 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86 // Constructor
87
88 FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root), FDMctr(fdmctr)
89 {
90   Frame           = 0;
91   Error           = 0;
92   SetGroundCallback(new FGDefaultGroundCallback());
93   IC              = 0;
94   Trim            = 0;
95   Script          = 0;
96
97   RootDir = "";
98
99   modelLoaded = false;
100   IsChild = false;
101   holding = false;
102   Terminate = false;
103   StandAlone = false;
104
105   IncrementThenHolding = false;  // increment then hold is off by default
106   TimeStepsUntilHold = -1;
107
108   sim_time = 0.0;
109   dT = 1.0/120.0; // a default timestep size. This is needed for when JSBSim is
110                   // run in standalone mode with no initialization file.
111
112   AircraftPath = "aircraft";
113   EnginePath = "engine";
114   SystemsPath = "systems";
115
116   try {
117     char* num = getenv("JSBSIM_DEBUG");
118     if (num) debug_lvl = atoi(num); // set debug level
119   } catch (...) {                   // if error set to 1
120     debug_lvl = 1;
121   }
122
123   if (Root == 0) {                 // Then this is the root FDM
124     Root = new FGPropertyManager;  // Create the property manager
125     StandAlone = true;
126   }
127
128   if (FDMctr == 0) {
129     FDMctr = new unsigned int;     // Create and initialize the child FDM counter
130     (*FDMctr) = 0;
131   }
132
133   // Store this FDM's ID
134   IdFDM = (*FDMctr); // The main (parent) JSBSim instance is always the "zeroth"
135
136   // Prepare FDMctr for the next child FDM id
137   (*FDMctr)++;       // instance. "child" instances are loaded last.
138
139   FGPropertyNode* instanceRoot = Root->GetNode("/fdm/jsbsim",IdFDM,true);
140   instance = new FGPropertyManager(instanceRoot);
141   Debug(0);
142   // this is to catch errors in binding member functions to the property tree.
143   try {
144     Allocate();
145   } catch ( string msg ) {
146     cout << "Caught error: " << msg << endl;
147     exit(1);
148   }
149
150   trim_status = false;
151   ta_mode     = 99;
152
153   Constructing = true;
154   typedef int (FGFDMExec::*iPMF)(void) const;
155   typedef double (FGFDMExec::*dPMF)(void) const;
156 //  typedef unsigned int (FGFDMExec::*uiPMF)(void) const;
157 //  instance->Tie("simulation/do_trim_analysis", this, (iPMF)0, &FGFDMExec::DoTrimAnalysis, false);
158   instance->Tie("simulation/do_simple_trim", this, (iPMF)0, &FGFDMExec::DoTrim, false);
159   instance->Tie("simulation/do_simplex_trim", this, (iPMF)0, &FGFDMExec::DoSimplexTrim);
160   instance->Tie("simulation/do_linearization", this, (iPMF)0, &FGFDMExec::DoLinearization);
161   instance->Tie("simulation/reset", this, (iPMF)0, &FGFDMExec::ResetToInitialConditions, false);
162   instance->Tie("simulation/randomseed", this, (iPMF)0, &FGFDMExec::SRand, false);
163   instance->Tie("simulation/terminate", (int *)&Terminate);
164   instance->Tie("simulation/sim-time-sec", this, &FGFDMExec::GetSimTime);
165   instance->Tie("simulation/dt", this, &FGFDMExec::GetDeltaT);
166   instance->Tie("simulation/jsbsim-debug", this, &FGFDMExec::GetDebugLevel, &FGFDMExec::SetDebugLevel);
167   instance->Tie("simulation/frame", (int *)&Frame, false);
168
169   // simplex trim properties
170   instanceRoot->SetDouble("trim/solver/rtol",0.0001);
171   instanceRoot->SetDouble("trim/solver/speed",2);
172   instanceRoot->SetDouble("trim/solver/abstol",0.001);
173   instanceRoot->SetDouble("trim/solver/iterMax",2000);
174   instanceRoot->SetInt("trim/solver/debugLevel",0);
175   instanceRoot->SetDouble("trim/solver/random",0);
176   instanceRoot->SetBool("trim/solver/showSimplex",false);
177   instanceRoot->SetBool("trim/solver/showConvergence",false);
178   instanceRoot->SetBool("trim/solver/pause",false);
179   instanceRoot->SetBool("trim/solver/variablePropPitch",false);
180
181   instanceRoot->SetDouble("trim/solver/throttleGuess",0.50);
182   instanceRoot->SetDouble("trim/solver/throttleMin",0.0);
183   instanceRoot->SetDouble("trim/solver/throttleMax",1.0);
184   instanceRoot->SetDouble("trim/solver/throttleStep",0.1);
185
186   instanceRoot->SetDouble("trim/solver/aileronGuess",0);
187   instanceRoot->SetDouble("trim/solver/aileronMin",-1.00);
188   instanceRoot->SetDouble("trim/solver/aileronMax",1.00);
189   instanceRoot->SetDouble("trim/solver/aileronStep",0.1);
190
191   instanceRoot->SetDouble("trim/solver/rudderGuess",0);
192   instanceRoot->SetDouble("trim/solver/rudderMin",-1.00);
193   instanceRoot->SetDouble("trim/solver/rudderMax",1.00);
194   instanceRoot->SetDouble("trim/solver/rudderStep",0.1);
195
196   instanceRoot->SetDouble("trim/solver/elevatorGuess",-0.1);
197   instanceRoot->SetDouble("trim/solver/elevatorMin",-1.0);
198   instanceRoot->SetDouble("trim/solver/elevatorMax",1.0);
199   instanceRoot->SetDouble("trim/solver/elevatorStep",0.1);
200
201   instanceRoot->SetDouble("trim/solver/alphaGuess",0.05);
202   instanceRoot->SetDouble("trim/solver/alphaMin",-0.1);
203   instanceRoot->SetDouble("trim/solver/alphaMax",.18);
204   instanceRoot->SetDouble("trim/solver/alphaStep",0.05);
205
206   instanceRoot->SetDouble("trim/solver/betaGuess",0);
207   instanceRoot->SetDouble("trim/solver/betaMin",-0.1);
208   instanceRoot->SetDouble("trim/solver/betaMax",0.1);
209   instanceRoot->SetDouble("trim/solver/betaStep",0.0001);
210
211   Constructing = false;
212 }
213
214 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
215
216 FGFDMExec::~FGFDMExec()
217 {
218   try {
219     Unbind();
220     DeAllocate();
221
222     delete instance;
223
224     if (IdFDM == 0) { // Meaning this is no child FDM
225       if(Root != 0) {
226          if(StandAlone)
227             delete Root;
228          Root = 0;
229       }
230       if(FDMctr != 0) {
231          delete FDMctr;
232          FDMctr = 0;
233       }
234     }
235   } catch ( string msg ) {
236     cout << "Caught error: " << msg << endl;
237   }
238
239   for (unsigned int i=1; i<ChildFDMList.size(); i++) delete ChildFDMList[i]->exec;
240   ChildFDMList.clear();
241
242   PropertyCatalog.clear();
243
244   if (FDMctr > 0) (*FDMctr)--;
245
246   Debug(1);
247 }
248
249 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250
251 bool FGFDMExec::Allocate(void)
252 {
253   bool result=true;
254
255   Models.resize(eNumStandardModels);
256
257   // See the eModels enum specification in the header file. The order of the enums
258   // specifies the order of execution. The Models[] vector is the primary
259   // storage array for the list of models.
260   Models[ePropagate]         = new FGPropagate(this);
261   Models[eInput]             = new FGInput(this);
262   Models[eInertial]          = new FGInertial(this);
263   Models[eAtmosphere]        = new FGStandardAtmosphere(this);
264   Models[eWinds]             = new FGWinds(this);
265   Models[eAuxiliary]         = new FGAuxiliary(this);
266   Models[eSystems]           = new FGFCS(this);
267   Models[ePropulsion]        = new FGPropulsion(this);
268   Models[eAerodynamics]      = new FGAerodynamics (this);
269   Models[eGroundReactions]   = new FGGroundReactions(this);
270   Models[eExternalReactions] = new FGExternalReactions(this);
271   Models[eBuoyantForces]     = new FGBuoyantForces(this);
272   Models[eMassBalance]       = new FGMassBalance(this);
273   Models[eAircraft]          = new FGAircraft(this);
274   Models[eAccelerations]     = new FGAccelerations(this);
275   Models[eOutput]            = new FGOutput(this);
276
277   // Assign the Model shortcuts for internal executive use only.
278   Propagate = (FGPropagate*)Models[ePropagate];
279   Inertial = (FGInertial*)Models[eInertial];
280   Atmosphere = (FGAtmosphere*)Models[eAtmosphere];
281   Winds = (FGWinds*)Models[eWinds];
282   Auxiliary = (FGAuxiliary*)Models[eAuxiliary];
283   FCS = (FGFCS*)Models[eSystems];
284   Propulsion = (FGPropulsion*)Models[ePropulsion];
285   Aerodynamics = (FGAerodynamics*)Models[eAerodynamics];
286   GroundReactions = (FGGroundReactions*)Models[eGroundReactions];
287   ExternalReactions = (FGExternalReactions*)Models[eExternalReactions];
288   BuoyantForces = (FGBuoyantForces*)Models[eBuoyantForces];
289   MassBalance = (FGMassBalance*)Models[eMassBalance];
290   Aircraft = (FGAircraft*)Models[eAircraft];
291   Accelerations = (FGAccelerations*)Models[eAccelerations];
292   Output = (FGOutput*)Models[eOutput];
293
294   // Initialize planet (environment) constants
295   LoadPlanetConstants();
296   GetGroundCallback()->SetSeaLevelRadius(Inertial->GetRefRadius());
297
298   // Initialize models
299   for (unsigned int i = 0; i < Models.size(); i++) {
300     // The Output model must not be initialized prior to IC loading
301     if (i == eOutput) continue;
302
303     LoadInputs(i);
304     Models[i]->InitModel();
305   }
306
307   IC = new FGInitialCondition(this);
308
309   modelLoaded = false;
310
311   return result;
312 }
313
314 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
315
316 bool FGFDMExec::DeAllocate(void)
317 {
318
319   for (unsigned int i=0; i<eNumStandardModels; i++) delete Models[i];
320   Models.clear();
321
322   delete Script;
323   delete IC;
324   delete Trim;
325
326   Error       = 0;
327
328   modelLoaded = false;
329   return modelLoaded;
330 }
331
332 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333
334 void FGFDMExec::Schedule(FGModel* model, int rate)
335 {
336   model->SetRate(rate);
337   Models.push_back(model);
338 }
339
340 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341
342 bool FGFDMExec::Run(void)
343 {
344   bool success=true;
345
346   Debug(2);
347
348   for (unsigned int i=1; i<ChildFDMList.size(); i++) {
349     ChildFDMList[i]->AssignState( (FGPropagate*)Models[ePropagate] ); // Transfer state to the child FDM
350     ChildFDMList[i]->Run();
351   }
352
353   IncrTime();
354
355   // returns true if success, false if complete
356   if (Script != 0 && !IntegrationSuspended()) success = Script->RunScript();
357
358   for (unsigned int i = 0; i < Models.size(); i++) {
359     LoadInputs(i);
360     Models[i]->Run(holding);
361   }
362
363   if (Terminate) success = false;
364
365   return (success);
366 }
367
368 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
369
370 void FGFDMExec::LoadInputs(unsigned int idx)
371 {
372   switch(idx) {
373   case ePropagate:
374     Propagate->in.vPQRidot     = Accelerations->GetPQRidot();
375     Propagate->in.vQtrndot     = Accelerations->GetQuaterniondot();
376     Propagate->in.vUVWidot     = Accelerations->GetUVWidot();
377     Propagate->in.DeltaT       = dT;
378     break;
379   case eInput:
380     break;
381   case eInertial:
382     Inertial->in.Radius        = Propagate->GetRadius();
383     Inertial->in.Latitude      = Propagate->GetLatitude();
384     break;
385   case eAtmosphere:
386     Atmosphere->in.altitudeASL = Propagate->GetAltitudeASL();
387     break;
388   case eWinds:
389     Winds->in.AltitudeASL      = Propagate->GetAltitudeASL();
390     Winds->in.DistanceAGL      = Propagate->GetDistanceAGL();
391     Winds->in.Tl2b             = Propagate->GetTl2b();
392     Winds->in.Tw2b             = Auxiliary->GetTw2b();
393     Winds->in.V                = Auxiliary->GetVt();
394     Winds->in.totalDeltaT      = dT * Winds->GetRate();
395     break;
396   case eAuxiliary:
397     Auxiliary->in.Pressure     = Atmosphere->GetPressure();
398     Auxiliary->in.Density      = Atmosphere->GetDensity();
399     Auxiliary->in.DensitySL    = Atmosphere->GetDensitySL();
400     Auxiliary->in.PressureSL   = Atmosphere->GetPressureSL();
401     Auxiliary->in.Temperature  = Atmosphere->GetTemperature();
402     Auxiliary->in.SoundSpeed   = Atmosphere->GetSoundSpeed();
403     Auxiliary->in.KinematicViscosity = Atmosphere->GetKinematicViscosity();
404     Auxiliary->in.DistanceAGL  = Propagate->GetDistanceAGL();
405     Auxiliary->in.Mass         = MassBalance->GetMass();
406     Auxiliary->in.Tl2b         = Propagate->GetTl2b();
407     Auxiliary->in.Tb2l         = Propagate->GetTb2l();
408     Auxiliary->in.vPQR         = Propagate->GetPQR();
409     Auxiliary->in.vPQRdot      = Accelerations->GetPQRdot();
410     Auxiliary->in.vUVW         = Propagate->GetUVW();
411     Auxiliary->in.vUVWdot      = Accelerations->GetUVWdot();
412     Auxiliary->in.vVel         = Propagate->GetVel();
413     Auxiliary->in.vBodyAccel   = Accelerations->GetBodyAccel();
414     Auxiliary->in.ToEyePt      = MassBalance->StructuralToBody(Aircraft->GetXYZep());
415     Auxiliary->in.VRPBody      = MassBalance->StructuralToBody(Aircraft->GetXYZvrp());
416     Auxiliary->in.RPBody       = MassBalance->StructuralToBody(Aircraft->GetXYZrp());
417     Auxiliary->in.vFw          = Aerodynamics->GetvFw();
418     Auxiliary->in.vLocation    = Propagate->GetLocation();
419     Auxiliary->in.CosTht       = Propagate->GetCosEuler(eTht);
420     Auxiliary->in.SinTht       = Propagate->GetSinEuler(eTht);
421     Auxiliary->in.CosPhi       = Propagate->GetCosEuler(ePhi);
422     Auxiliary->in.SinPhi       = Propagate->GetSinEuler(ePhi);
423     Auxiliary->in.Psi          = Propagate->GetEuler(ePsi);
424     Auxiliary->in.TotalWindNED = Winds->GetTotalWindNED();
425     Auxiliary->in.TurbPQR      = Winds->GetTurbPQR();
426     Auxiliary->in.WindPsi      = Winds->GetWindPsi();
427     Auxiliary->in.Vwind        = Winds->GetTotalWindNED().Magnitude();
428     break;
429   case eSystems:
430     // Dynamic inputs come into the components that FCS manages through properties
431     break;
432   case ePropulsion:
433     Propulsion->in.SLPressure       = Atmosphere->GetPressureSL();
434     Propulsion->in.Pressure         = Atmosphere->GetPressure();
435     Propulsion->in.PressureRatio    = Atmosphere->GetPressureRatio();
436     Propulsion->in.Temperature      = Atmosphere->GetTemperature();
437     Propulsion->in.DensityRatio     = Atmosphere->GetDensityRatio();
438     Propulsion->in.Density          = Atmosphere->GetDensity();
439     Propulsion->in.Soundspeed       = Atmosphere->GetSoundSpeed();
440     Propulsion->in.TotalPressure    = Auxiliary->GetTotalPressure();
441     Propulsion->in.TotalTempearture = Auxiliary->GetTotalTemperature();
442     Propulsion->in.Vc               = Auxiliary->GetVcalibratedKTS();
443     Propulsion->in.Vt               = Auxiliary->GetVt();
444     Propulsion->in.qbar             = Auxiliary->Getqbar();
445     Propulsion->in.TAT_c            = Auxiliary->GetTAT_C();
446     Propulsion->in.AeroUVW          = Auxiliary->GetAeroUVW();
447     Propulsion->in.AeroPQR          = Auxiliary->GetAeroPQR();
448     Propulsion->in.alpha            = Auxiliary->Getalpha();
449     Propulsion->in.beta             = Auxiliary->Getbeta();
450     Propulsion->in.TotalDeltaT      = dT * Propulsion->GetRate();
451     Propulsion->in.ThrottlePos      = FCS->GetThrottlePos();
452     Propulsion->in.MixturePos       = FCS->GetMixturePos();
453     Propulsion->in.ThrottleCmd      = FCS->GetThrottleCmd();
454     Propulsion->in.MixtureCmd       = FCS->GetMixtureCmd();
455     Propulsion->in.PropAdvance      = FCS->GetPropAdvance();
456     Propulsion->in.PropFeather      = FCS->GetPropFeather();
457     Propulsion->in.H_agl            = Propagate->GetDistanceAGL();
458     Propulsion->in.PQR              = Propagate->GetPQR();
459
460     break;
461   case eAerodynamics:
462     Aerodynamics->in.Alpha     = Auxiliary->Getalpha();
463     Aerodynamics->in.Beta      = Auxiliary->Getbeta();
464     Aerodynamics->in.Qbar      = Auxiliary->Getqbar();
465     Aerodynamics->in.Vt        = Auxiliary->GetVt();
466     Aerodynamics->in.Tb2w      = Auxiliary->GetTb2w();
467     Aerodynamics->in.Tw2b      = Auxiliary->GetTw2b();
468     Aerodynamics->in.RPBody    = MassBalance->StructuralToBody(Aircraft->GetXYZrp());
469     break;
470   case eGroundReactions:
471     // There are no external inputs to this model.
472     GroundReactions->in.Vground         = Auxiliary->GetVground();
473     GroundReactions->in.VcalibratedKts  = Auxiliary->GetVcalibratedKTS();
474     GroundReactions->in.Temperature     = Atmosphere->GetTemperature();
475     GroundReactions->in.TakeoffThrottle = (FCS->GetThrottlePos().size() > 0) ? (FCS->GetThrottlePos(0) > 0.90) : false;
476     GroundReactions->in.SteerPosDeg     = FCS->GetSteerPosDeg();
477     GroundReactions->in.BrakePos        = FCS->GetBrakePos();
478     GroundReactions->in.FCSGearPos      = FCS->GetGearPos();
479     GroundReactions->in.EmptyWeight     = MassBalance->GetEmptyWeight();
480     GroundReactions->in.Tb2l            = Propagate->GetTb2l();
481     GroundReactions->in.Tec2l           = Propagate->GetTec2l();
482     GroundReactions->in.Tec2b           = Propagate->GetTec2b();
483     GroundReactions->in.PQR             = Propagate->GetPQR();
484     GroundReactions->in.UVW             = Propagate->GetUVW();
485     GroundReactions->in.DistanceAGL     = Propagate->GetDistanceAGL();
486     GroundReactions->in.DistanceASL     = Propagate->GetAltitudeASL();
487     GroundReactions->in.TotalDeltaT     = dT * GroundReactions->GetRate();
488     GroundReactions->in.WOW             = GroundReactions->GetWOW();
489     GroundReactions->in.Location        = Propagate->GetLocation();
490     GroundReactions->in.vXYZcg          = MassBalance->GetXYZcg();
491     break;
492   case eExternalReactions:
493     // There are no external inputs to this model.
494     break;
495   case eBuoyantForces:
496     BuoyantForces->in.Density     = Atmosphere->GetDensity();
497     BuoyantForces->in.Pressure    = Atmosphere->GetPressure();
498     BuoyantForces->in.Temperature = Atmosphere->GetTemperature();
499     BuoyantForces->in.gravity     = Inertial->gravity();
500     break;
501   case eMassBalance:
502     MassBalance->in.GasInertia  = BuoyantForces->GetGasMassInertia();
503     MassBalance->in.GasMass     = BuoyantForces->GetGasMass();
504     MassBalance->in.GasMoment   = BuoyantForces->GetGasMassMoment();
505     MassBalance->in.TanksWeight = Propulsion->GetTanksWeight();
506     MassBalance->in.TanksMoment = Propulsion->GetTanksMoment();
507     MassBalance->in.TankInertia = Propulsion->CalculateTankInertias();
508     break;
509   case eAircraft:
510     Aircraft->in.AeroForce     = Aerodynamics->GetForces();
511     Aircraft->in.PropForce     = Propulsion->GetForces();
512     Aircraft->in.GroundForce   = GroundReactions->GetForces();
513     Aircraft->in.ExternalForce = ExternalReactions->GetForces();
514     Aircraft->in.BuoyantForce  = BuoyantForces->GetForces();
515     Aircraft->in.AeroMoment    = Aerodynamics->GetMoments();
516     Aircraft->in.PropMoment    = Propulsion->GetMoments();
517     Aircraft->in.GroundMoment  = GroundReactions->GetMoments();
518     Aircraft->in.ExternalMoment = ExternalReactions->GetMoments();
519     Aircraft->in.BuoyantMoment = BuoyantForces->GetMoments();
520     break;
521   case eAccelerations:
522     Accelerations->in.J        = MassBalance->GetJ();
523     Accelerations->in.Jinv     = MassBalance->GetJinv();
524     Accelerations->in.Ti2b     = Propagate->GetTi2b();
525     Accelerations->in.Tb2i     = Propagate->GetTb2i();
526     Accelerations->in.Tec2b    = Propagate->GetTec2b();
527     Accelerations->in.Tec2i    = Propagate->GetTec2i();
528     Accelerations->in.qAttitudeECI = Propagate->GetQuaternionECI();
529     Accelerations->in.Moment   = Aircraft->GetMoments();
530     Accelerations->in.GroundMoment  = GroundReactions->GetMoments();
531     Accelerations->in.Force    = Aircraft->GetForces();
532     Accelerations->in.GroundForce   = GroundReactions->GetForces();
533     Accelerations->in.GAccel   = Inertial->GetGAccel(Propagate->GetRadius());
534     Accelerations->in.J2Grav  = Inertial->GetGravityJ2(Propagate->GetLocation());
535     Accelerations->in.vPQRi    = Propagate->GetPQRi();
536     Accelerations->in.vPQR     = Propagate->GetPQR();
537     Accelerations->in.vUVW     = Propagate->GetUVW();
538     Accelerations->in.vInertialPosition = Propagate->GetInertialPosition();
539     Accelerations->in.DeltaT   = dT;
540     Accelerations->in.Mass     = MassBalance->GetMass();
541     Accelerations->in.MultipliersList = GroundReactions->GetMultipliersList();
542     Accelerations->in.TerrainVelocity = Propagate->GetTerrainVelocity();
543     Accelerations->in.TerrainAngularVel = Propagate->GetTerrainAngularVelocity();
544     break;
545   default:
546     break;
547   }
548 }
549
550 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
551
552 void FGFDMExec::LoadPlanetConstants(void)
553 {
554   Propagate->in.vOmegaPlanet     = Inertial->GetOmegaPlanet();
555   Accelerations->in.vOmegaPlanet = Inertial->GetOmegaPlanet();
556   Propagate->in.SemiMajor        = Inertial->GetSemimajor();
557   Propagate->in.SemiMinor        = Inertial->GetSemiminor();
558   Auxiliary->in.SLGravity        = Inertial->SLgravity();
559   Auxiliary->in.ReferenceRadius  = Inertial->GetRefRadius();
560 }
561
562 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
563
564 void FGFDMExec::LoadModelConstants(void)
565 {
566   Winds->in.wingspan             = Aircraft->GetWingSpan();
567   FCS->in.NumGear                = GroundReactions->GetNumGearUnits();
568   Aerodynamics->in.Wingarea      = Aircraft->GetWingArea();
569   Aerodynamics->in.Wingchord     = Aircraft->Getcbar();
570   Aerodynamics->in.Wingincidence = Aircraft->GetWingIncidence();
571   Aerodynamics->in.Wingspan      = Aircraft->GetWingSpan();
572   Auxiliary->in.Wingspan         = Aircraft->GetWingSpan();
573   Auxiliary->in.Wingchord        = Aircraft->Getcbar();
574   GroundReactions->in.vXYZcg     = MassBalance->GetXYZcg();
575
576   LoadPlanetConstants();
577 }
578
579 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
580 // This call will cause the sim time to reset to 0.0
581
582 bool FGFDMExec::RunIC(void)
583 {
584   FGPropulsion* propulsion = (FGPropulsion*)Models[ePropulsion];
585
586   Models[eOutput]->InitModel();
587
588   SuspendIntegration(); // saves the integration rate, dt, then sets it to 0.0.
589   Initialize(IC);
590   Run();
591   ResumeIntegration(); // Restores the integration rate to what it was.
592
593   for (unsigned int i=0; i<IC->GetNumEnginesRunning(); i++)
594     propulsion->InitRunning(IC->GetEngineRunning(i));
595
596   return true;
597 }
598
599 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
600
601 void FGFDMExec::Initialize(FGInitialCondition *FGIC)
602 {
603   Setsim_time(0.0);
604
605   Propagate->SetInitialState( FGIC );
606   LoadInputs(eAccelerations);
607   Accelerations->Run(false);
608   LoadInputs(ePropagate);
609   Propagate->InitializeDerivatives();
610   LoadInputs(eAtmosphere);
611   Atmosphere->Run(false);
612   Winds->SetWindNED(FGIC->GetWindNEDFpsIC());
613   Auxiliary->Run(false);
614 }
615
616 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
617 //
618 // A private, internal function call for Tie-ing to a property, so it needs an
619 // argument.
620
621 void FGFDMExec::ResetToInitialConditions(int mode)
622 {
623   if (mode == 1) Output->SetStartNewOutput();
624
625   ResetToInitialConditions();
626 }
627
628 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629
630 void FGFDMExec::ResetToInitialConditions(void)
631 {
632   if (Constructing) return;
633
634   for (unsigned int i = 0; i < Models.size(); i++) {
635     // The Output model will be initialized during the RunIC() execution
636     if (i == eOutput) continue;
637
638     LoadInputs(i);
639     Models[i]->InitModel();
640   }
641
642   RunIC();
643
644   if (Script) Script->ResetEvents();
645 }
646
647 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
648
649 vector <string> FGFDMExec::EnumerateFDMs(void)
650 {
651   vector <string> FDMList;
652   FGAircraft* Aircraft = (FGAircraft*)Models[eAircraft];
653
654   FDMList.push_back(Aircraft->GetAircraftName());
655
656   for (unsigned int i=1; i<ChildFDMList.size(); i++) {
657     FDMList.push_back(ChildFDMList[i]->exec->GetAircraft()->GetAircraftName());
658   }
659
660   return FDMList;
661 }
662
663 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
664
665 bool FGFDMExec::LoadScript(const string& script, double deltaT, const string initfile)
666 {
667   bool result;
668
669   Script = new FGScript(this);
670   result = Script->LoadScript(RootDir + script, deltaT, initfile);
671
672   return result;
673 }
674
675 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
676
677 bool FGFDMExec::LoadModel(const string& AircraftPath, const string& EnginePath, const string& SystemsPath,
678                 const string& model, bool addModelToPath)
679 {
680   FGFDMExec::AircraftPath = RootDir + AircraftPath;
681   FGFDMExec::EnginePath = RootDir + EnginePath;
682   FGFDMExec::SystemsPath = RootDir + SystemsPath;
683
684   return LoadModel(model, addModelToPath);
685 }
686
687 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
688
689 bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
690 {
691   string token;
692   string aircraftCfgFileName;
693   Element* element = 0L;
694   bool result = false; // initialize result to false, indicating input file not yet read
695
696   modelName = model; // Set the class modelName attribute
697
698   if( AircraftPath.empty() || EnginePath.empty() || SystemsPath.empty()) {
699     cerr << "Error: attempted to load aircraft with undefined ";
700     cerr << "aircraft, engine, and system paths" << endl;
701     return false;
702   }
703
704   FullAircraftPath = AircraftPath;
705   if (addModelToPath) FullAircraftPath += "/" + model;
706   aircraftCfgFileName = FullAircraftPath + "/" + model + ".xml";
707
708   if (modelLoaded) {
709     DeAllocate();
710     Allocate();
711   }
712
713   int saved_debug_lvl = debug_lvl;
714   FGXMLFileRead XMLFileRead;
715   Element *document = XMLFileRead.LoadXMLDocument(aircraftCfgFileName); // "document" is a class member
716
717   if (document) {
718     if (IsChild) debug_lvl = 0;
719
720     ReadPrologue(document);
721
722     if (IsChild) debug_lvl = saved_debug_lvl;
723
724     // Process the fileheader element in the aircraft config file. This element is OPTIONAL.
725     element = document->FindElement("fileheader");
726     if (element) {
727       result = ReadFileHeader(element);
728       if (!result) {
729         cerr << endl << "Aircraft fileheader element has problems in file " << aircraftCfgFileName << endl;
730         return result;
731       }
732     }
733
734     if (IsChild) debug_lvl = 0;
735
736     // Process the metrics element. This element is REQUIRED.
737     element = document->FindElement("metrics");
738     if (element) {
739       result = ((FGAircraft*)Models[eAircraft])->Load(element);
740       if (!result) {
741         cerr << endl << "Aircraft metrics element has problems in file " << aircraftCfgFileName << endl;
742         return result;
743       }
744     } else {
745       cerr << endl << "No metrics element was found in the aircraft config file." << endl;
746       return false;
747     }
748
749     // Process the mass_balance element. This element is REQUIRED.
750     element = document->FindElement("mass_balance");
751     if (element) {
752       result = ((FGMassBalance*)Models[eMassBalance])->Load(element);
753       if (!result) {
754         cerr << endl << "Aircraft mass_balance element has problems in file " << aircraftCfgFileName << endl;
755         return result;
756       }
757     } else {
758       cerr << endl << "No mass_balance element was found in the aircraft config file." << endl;
759       return false;
760     }
761
762     // Process the ground_reactions element. This element is REQUIRED.
763     element = document->FindElement("ground_reactions");
764     if (element) {
765       result = ((FGGroundReactions*)Models[eGroundReactions])->Load(element);
766       if (!result) {
767         cerr << endl << "Aircraft ground_reactions element has problems in file " << aircraftCfgFileName << endl;
768         return result;
769       }
770       ((FGFCS*)Models[eSystems])->AddGear(((FGGroundReactions*)Models[eGroundReactions])->GetNumGearUnits());
771     } else {
772       cerr << endl << "No ground_reactions element was found in the aircraft config file." << endl;
773       return false;
774     }
775
776     // Process the external_reactions element. This element is OPTIONAL.
777     element = document->FindElement("external_reactions");
778     if (element) {
779       result = ((FGExternalReactions*)Models[eExternalReactions])->Load(element);
780       if (!result) {
781         cerr << endl << "Aircraft external_reactions element has problems in file " << aircraftCfgFileName << endl;
782         return result;
783       }
784     }
785
786     // Process the buoyant_forces element. This element is OPTIONAL.
787     element = document->FindElement("buoyant_forces");
788     if (element) {
789       result = ((FGBuoyantForces*)Models[eBuoyantForces])->Load(element);
790       if (!result) {
791         cerr << endl << "Aircraft buoyant_forces element has problems in file " << aircraftCfgFileName << endl;
792         return result;
793       }
794     }
795
796     // Process the propulsion element. This element is OPTIONAL.
797     element = document->FindElement("propulsion");
798     if (element) {
799       result = ((FGPropulsion*)Models[ePropulsion])->Load(element);
800       if (!result) {
801         cerr << endl << "Aircraft propulsion element has problems in file " << aircraftCfgFileName << endl;
802         return result;
803       }
804       for (unsigned int i=0; i<((FGPropulsion*)Models[ePropulsion])->GetNumEngines(); i++)
805         ((FGFCS*)Models[eSystems])->AddThrottle();
806     }
807
808     // Process the system element[s]. This element is OPTIONAL, and there may be more than one.
809     element = document->FindElement("system");
810     while (element) {
811       result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stSystem);
812       if (!result) {
813         cerr << endl << "Aircraft system element has problems in file " << aircraftCfgFileName << endl;
814         return result;
815       }
816       element = document->FindNextElement("system");
817     }
818
819     // Process the autopilot element. This element is OPTIONAL.
820     element = document->FindElement("autopilot");
821     if (element) {
822       result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stAutoPilot);
823       if (!result) {
824         cerr << endl << "Aircraft autopilot element has problems in file " << aircraftCfgFileName << endl;
825         return result;
826       }
827     }
828
829     // Process the flight_control element. This element is OPTIONAL.
830     element = document->FindElement("flight_control");
831     if (element) {
832       result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stFCS);
833       if (!result) {
834         cerr << endl << "Aircraft flight_control element has problems in file " << aircraftCfgFileName << endl;
835         return result;
836       }
837     }
838
839     // Process the aerodynamics element. This element is OPTIONAL, but almost always expected.
840     element = document->FindElement("aerodynamics");
841     if (element) {
842       result = ((FGAerodynamics*)Models[eAerodynamics])->Load(element);
843       if (!result) {
844         cerr << endl << "Aircraft aerodynamics element has problems in file " << aircraftCfgFileName << endl;
845         return result;
846       }
847     } else {
848       cerr << endl << "No expected aerodynamics element was found in the aircraft config file." << endl;
849     }
850
851     // Process the input element. This element is OPTIONAL.
852     element = document->FindElement("input");
853     if (element) {
854       result = ((FGInput*)Models[eInput])->Load(element);
855       if (!result) {
856         cerr << endl << "Aircraft input element has problems in file " << aircraftCfgFileName << endl;
857         return result;
858       }
859     }
860
861     // Process the output element[s]. This element is OPTIONAL, and there may be more than one.
862     element = document->FindElement("output");
863     while (element) {
864       string output_file_name = aircraftCfgFileName;
865
866       if (!element->GetAttributeValue("file").empty()) {
867         output_file_name = RootDir + element->GetAttributeValue("file");
868         result = ((FGOutput*)Models[eOutput])->SetDirectivesFile(output_file_name);
869       }
870       else
871         result = ((FGOutput*)Models[eOutput])->Load(element);
872
873       if (!result) {
874         cerr << endl << "Aircraft output element has problems in file " << output_file_name << endl;
875         return result;
876       }
877       element = document->FindNextElement("output");
878     }
879
880     // Lastly, process the child element. This element is OPTIONAL - and NOT YET SUPPORTED.
881     element = document->FindElement("child");
882     if (element) {
883       result = ReadChild(element);
884       if (!result) {
885         cerr << endl << "Aircraft child element has problems in file " << aircraftCfgFileName << endl;
886         return result;
887       }
888     }
889
890     // Since all vehicle characteristics have been loaded, place the values in the Inputs
891     // structure for the FGModel-derived classes.
892     LoadModelConstants();
893
894     modelLoaded = true;
895
896     if (debug_lvl > 0) {
897       LoadInputs(eMassBalance); // Update all input mass properties for the report.
898       Models[eMassBalance]->Run(false);  // Update all mass properties for the report.
899       LoadInputs(ePropulsion); // Update propulsion properties for the report.
900       Models[ePropulsion]->Run(false);  // Update propulsion properties for the report.
901       LoadInputs(eMassBalance); // Update all (one more time) input mass properties for the report.
902       Models[eMassBalance]->Run(false);  // Update all (one more time) mass properties for the report.
903       ((FGMassBalance*)Models[eMassBalance])->GetMassPropertiesReport();
904
905       cout << endl << fgblue << highint
906            << "End of vehicle configuration loading." << endl
907            << "-------------------------------------------------------------------------------"
908            << reset << endl;
909     }
910
911     if (IsChild) debug_lvl = saved_debug_lvl;
912
913   } else {
914     cerr << fgred
915          << "  JSBSim failed to open the configuration file: " << aircraftCfgFileName
916          << fgdef << endl;
917   }
918
919   for (unsigned int i=0; i< Models.size(); i++) LoadInputs(i);
920
921   if (result) {
922     struct PropertyCatalogStructure masterPCS;
923     masterPCS.base_string = "";
924     masterPCS.node = Root->GetNode();
925     BuildPropertyCatalog(&masterPCS);
926   }
927
928   return result;
929 }
930
931 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
932
933 string FGFDMExec::GetPropulsionTankReport()
934 {
935   return ((FGPropulsion*)Models[ePropulsion])->GetPropulsionTankReport();
936 }
937
938 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
939
940 void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs)
941 {
942   struct PropertyCatalogStructure* pcsNew = new struct PropertyCatalogStructure;
943   int node_idx = 0;
944
945   for (int i=0; i<pcs->node->nChildren(); i++) {
946     string access="";
947     pcsNew->base_string = pcs->base_string + "/" + pcs->node->getChild(i)->getName();
948     node_idx = pcs->node->getChild(i)->getIndex();
949     if (node_idx != 0) {
950       pcsNew->base_string = CreateIndexedPropertyName(pcsNew->base_string, node_idx);
951     }
952     if (pcs->node->getChild(i)->nChildren() == 0) {
953       if (pcsNew->base_string.substr(0,12) == string("/fdm/jsbsim/")) {
954         pcsNew->base_string = pcsNew->base_string.erase(0,12);
955       }
956       if (pcs->node->getChild(i)->getAttribute(SGPropertyNode::READ)) access="R";
957       if (pcs->node->getChild(i)->getAttribute(SGPropertyNode::WRITE)) access+="W";
958       PropertyCatalog.push_back(pcsNew->base_string+" ("+access+")");
959     } else {
960       pcsNew->node = (FGPropertyNode*)pcs->node->getChild(i);
961       BuildPropertyCatalog(pcsNew);
962     }
963   }
964   delete pcsNew;
965 }
966
967 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
968
969 string FGFDMExec::QueryPropertyCatalog(const string& in)
970 {
971   string results="";
972   for (unsigned i=0; i<PropertyCatalog.size(); i++) {
973     if (PropertyCatalog[i].find(in) != string::npos) results += PropertyCatalog[i] + "\n";
974   }
975   if (results.empty()) return "No matches found\n";
976   return results;
977 }
978
979 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980
981 void FGFDMExec::PrintPropertyCatalog(void)
982 {
983   cout << endl;
984   cout << "  " << fgblue << highint << underon << "Property Catalog for "
985        << modelName << reset << endl << endl;
986   for (unsigned i=0; i<PropertyCatalog.size(); i++) {
987     cout << "    " << PropertyCatalog[i] << endl;
988   }
989 }
990
991 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992
993 bool FGFDMExec::ReadFileHeader(Element* el)
994 {
995   bool result = true; // true for success
996
997   if (debug_lvl == 0) return result;
998
999   if (IsChild) {
1000     cout << endl <<highint << fgblue << "Reading child model: " << IdFDM << reset << endl << endl;
1001   }
1002
1003   if (el->FindElement("description"))
1004     cout << "  Description:   " << el->FindElement("description")->GetDataLine() << endl;
1005   if (el->FindElement("author"))
1006     cout << "  Model Author:  " << el->FindElement("author")->GetDataLine() << endl;
1007   if (el->FindElement("filecreationdate"))
1008     cout << "  Creation Date: " << el->FindElement("filecreationdate")->GetDataLine() << endl;
1009   if (el->FindElement("version"))
1010     cout << "  Version:       " << el->FindElement("version")->GetDataLine() << endl;
1011
1012   return result;
1013 }
1014
1015 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1016
1017 bool FGFDMExec::ReadPrologue(Element* el) // el for ReadPrologue is the document element
1018 {
1019   bool result = true; // true for success
1020
1021   if (!el) return false;
1022
1023   string AircraftName = el->GetAttributeValue("name");
1024   ((FGAircraft*)Models[eAircraft])->SetAircraftName(AircraftName);
1025
1026   if (debug_lvl & 1) cout << underon << "Reading Aircraft Configuration File"
1027             << underoff << ": " << highint << AircraftName << normint << endl;
1028
1029   CFGVersion = el->GetAttributeValue("version");
1030   Release    = el->GetAttributeValue("release");
1031
1032   if (debug_lvl & 1)
1033     cout << "                            Version: " << highint << CFGVersion
1034                                                     << normint << endl;
1035   if (CFGVersion != needed_cfg_version) {
1036     cerr << endl << fgred << "YOU HAVE AN INCOMPATIBLE CFG FILE FOR THIS AIRCRAFT."
1037             " RESULTS WILL BE UNPREDICTABLE !!" << endl;
1038     cerr << "Current version needed is: " << needed_cfg_version << endl;
1039     cerr << "         You have version: " << CFGVersion << endl << fgdef << endl;
1040     return false;
1041   }
1042
1043   if (Release == "ALPHA" && (debug_lvl & 1)) {
1044     cout << endl << endl
1045          << highint << "This aircraft model is an " << fgred << Release
1046          << reset << highint << " release!!!" << endl << endl << reset
1047          << "This aircraft model may not even properly load, and probably"
1048          << " will not fly as expected." << endl << endl
1049          << fgred << highint << "Use this model for development purposes ONLY!!!"
1050          << normint << reset << endl << endl;
1051   } else if (Release == "BETA" && (debug_lvl & 1)) {
1052     cout << endl << endl
1053          << highint << "This aircraft model is a " << fgred << Release
1054          << reset << highint << " release!!!" << endl << endl << reset
1055          << "This aircraft model probably will not fly as expected." << endl << endl
1056          << fgblue << highint << "Use this model for development purposes ONLY!!!"
1057          << normint << reset << endl << endl;
1058   } else if (Release == "PRODUCTION" && (debug_lvl & 1)) {
1059     cout << endl << endl
1060          << highint << "This aircraft model is a " << fgblue << Release
1061          << reset << highint << " release." << endl << endl << reset;
1062   } else if (debug_lvl & 1) {
1063     cout << endl << endl
1064          << highint << "This aircraft model is an " << fgred << Release
1065          << reset << highint << " release!!!" << endl << endl << reset
1066          << "This aircraft model may not even properly load, and probably"
1067          << " will not fly as expected." << endl << endl
1068          << fgred << highint << "Use this model for development purposes ONLY!!!"
1069          << normint << reset << endl << endl;
1070   }
1071
1072   return result;
1073 }
1074
1075 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1076
1077 bool FGFDMExec::ReadChild(Element* el)
1078 {
1079   // Add a new childData object to the child FDM list
1080   // Populate that childData element with a new FDMExec object
1081   // Set the IsChild flag for that FDMExec object
1082   // Get the aircraft name
1083   // set debug level to print out no additional data for child objects
1084   // Load the model given the aircraft name
1085   // reset debug level to prior setting
1086
1087   string token;
1088
1089   struct childData* child = new childData;
1090
1091   child->exec = new FGFDMExec(Root, FDMctr);
1092   child->exec->SetChild(true);
1093
1094   string childAircraft = el->GetAttributeValue("name");
1095   string sMated = el->GetAttributeValue("mated");
1096   if (sMated == "false") child->mated = false; // child objects are mated by default.
1097   string sInternal = el->GetAttributeValue("internal");
1098   if (sInternal == "true") child->internal = true; // child objects are external by default.
1099
1100   child->exec->SetAircraftPath( AircraftPath );
1101   child->exec->SetEnginePath( EnginePath );
1102   child->exec->SetSystemsPath( SystemsPath );
1103   child->exec->LoadModel(childAircraft);
1104
1105   Element* location = el->FindElement("location");
1106   if (location) {
1107     child->Loc = location->FindElementTripletConvertTo("IN");
1108   } else {
1109     cerr << endl << highint << fgred << "  No location was found for this child object!" << reset << endl;
1110     exit(-1);
1111   }
1112
1113   Element* orientation = el->FindElement("orient");
1114   if (orientation) {
1115     child->Orient = orientation->FindElementTripletConvertTo("RAD");
1116   } else if (debug_lvl > 0) {
1117     cerr << endl << highint << "  No orientation was found for this child object! Assuming 0,0,0." << reset << endl;
1118   }
1119
1120   ChildFDMList.push_back(child);
1121
1122   return true;
1123 }
1124
1125 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1126
1127 FGPropertyManager* FGFDMExec::GetPropertyManager(void)
1128 {
1129   return instance;
1130 }
1131
1132 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1133
1134 FGTrim* FGFDMExec::GetTrim(void)
1135 {
1136   delete Trim;
1137   Trim = new FGTrim(this,tNone);
1138   return Trim;
1139 }
1140
1141 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1142
1143 void FGFDMExec::CheckIncrementalHold(void)
1144 {
1145   // Only check if increment then hold is on
1146   if( IncrementThenHolding ) {
1147
1148     if (TimeStepsUntilHold == 0) {
1149
1150       // Should hold simulation if TimeStepsUntilHold has reached zero
1151       holding = true;
1152
1153       // Still need to decrement TimeStepsUntilHold as value of -1
1154       // indicates that incremental then hold is turned off
1155       IncrementThenHolding = false;
1156       TimeStepsUntilHold--;
1157
1158     } else if ( TimeStepsUntilHold > 0 ) {
1159       // Keep decrementing until 0 is reached
1160       TimeStepsUntilHold--;
1161     }
1162   }
1163 }
1164
1165 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1166
1167 void FGFDMExec::DoTrim(int mode)
1168 {
1169   double saved_time;
1170
1171   if (Constructing) return;
1172
1173   if (mode < 0 || mode > JSBSim::tNone) {
1174     cerr << endl << "Illegal trimming mode!" << endl << endl;
1175     return;
1176   }
1177   saved_time = sim_time;
1178   FGTrim trim(this, (JSBSim::TrimMode)mode);
1179   if ( !trim.DoTrim() ) cerr << endl << "Trim Failed" << endl << endl;
1180   trim.Report();
1181   sim_time = saved_time;
1182 }
1183
1184 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1185
1186 void FGFDMExec::DoSimplexTrim(int mode)
1187 {
1188   double saved_time;
1189   if (Constructing) return;
1190   if (mode < 0 || mode > JSBSim::tNone) {
1191       cerr << endl << "Illegal trimming mode!" << endl << endl;
1192       return;
1193   }
1194   saved_time = sim_time;
1195   FGSimplexTrim trim(this, (JSBSim::TrimMode)mode);
1196   sim_time = saved_time;
1197   Setsim_time(saved_time);
1198   std::cout << "dT: " << dT << std::endl;
1199 }
1200
1201 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1202
1203 void FGFDMExec::DoLinearization(int mode)
1204 {
1205   double saved_time;
1206   if (Constructing) return;
1207   saved_time = sim_time;
1208   FGLinearization lin(this,mode);
1209   sim_time = saved_time;
1210   Setsim_time(saved_time);
1211 }
1212
1213 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1214
1215 void FGFDMExec::SRand(int sr)
1216 {
1217   srand(sr);
1218 }
1219
1220 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1221 //    The bitmasked value choices are as follows:
1222 //    unset: In this case (the default) JSBSim would only print
1223 //       out the normally expected messages, essentially echoing
1224 //       the config files as they are read. If the environment
1225 //       variable is not set, debug_lvl is set to 1 internally
1226 //    0: This requests JSBSim not to output any messages
1227 //       whatsoever.
1228 //    1: This value explicity requests the normal JSBSim
1229 //       startup messages
1230 //    2: This value asks for a message to be printed out when
1231 //       a class is instantiated
1232 //    4: When this value is set, a message is displayed when a
1233 //       FGModel object executes its Run() method
1234 //    8: When this value is set, various runtime state variables
1235 //       are printed out periodically
1236 //    16: When set various parameters are sanity checked and
1237 //       a message is printed out when they go out of bounds
1238
1239 void FGFDMExec::Debug(int from)
1240 {
1241   if (debug_lvl <= 0) return;
1242
1243   if (debug_lvl & 1 && IdFDM == 0) { // Standard console startup message output
1244     if (from == 0) { // Constructor
1245       cout << "\n\n     "
1246            << "JSBSim Flight Dynamics Model v" << JSBSim_version << endl;
1247       cout << "            [JSBSim-ML v" << needed_cfg_version << "]\n\n";
1248       cout << "JSBSim startup beginning ...\n\n";
1249     } else if (from == 3) {
1250       cout << "\n\nJSBSim startup complete\n\n";
1251     }
1252   }
1253   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
1254     if (from == 0) cout << "Instantiated: FGFDMExec" << endl;
1255     if (from == 1) cout << "Destroyed:    FGFDMExec" << endl;
1256   }
1257   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
1258     if (from == 2) {
1259       cout << "================== Frame: " << Frame << "  Time: "
1260            << sim_time << " dt: " << dT << endl;
1261     }
1262   }
1263   if (debug_lvl & 8 ) { // Runtime state variables
1264   }
1265   if (debug_lvl & 16) { // Sanity checking
1266   }
1267   if (debug_lvl & 64) {
1268     if (from == 0) { // Constructor
1269       cout << IdSrc << endl;
1270       cout << IdHdr << endl;
1271     }
1272   }
1273 }
1274 }
1275
1276