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