]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGFDMExec.cpp
Do not use the new JSBSim ground reactions code by default until there is a good...
[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 IDENT(IdSrc,"$Id: FGFDMExec.cpp,v 1.154 2014/01/13 10:45:59 ehofman Exp $");
79 IDENT(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   ResetMode = 0;
105
106   IncrementThenHolding = false;  // increment then hold is off by default
107   TimeStepsUntilHold = -1;
108
109   sim_time = 0.0;
110   dT = 1.0/120.0; // a default timestep size. This is needed for when JSBSim is
111                   // run in standalone mode with no initialization file.
112
113   AircraftPath = "aircraft";
114   EnginePath = "engine";
115   SystemsPath = "systems";
116
117   try {
118     char* num = getenv("JSBSIM_DEBUG");
119     if (num) debug_lvl = atoi(num); // set debug level
120   } catch (...) {                   // if error set to 1
121     debug_lvl = 1;
122   }
123
124   if (Root == 0) {                 // Then this is the root FDM
125     Root = new FGPropertyManager;  // Create the property manager
126     StandAlone = true;
127   }
128
129   if (FDMctr == 0) {
130     FDMctr = new unsigned int;     // Create and initialize the child FDM counter
131     (*FDMctr) = 0;
132   }
133
134   // Store this FDM's ID
135   IdFDM = (*FDMctr); // The main (parent) JSBSim instance is always the "zeroth"
136
137   // Prepare FDMctr for the next child FDM id
138   (*FDMctr)++;       // instance. "child" instances are loaded last.
139
140   FGPropertyNode* instanceRoot = Root->GetNode("/fdm/jsbsim",IdFDM,true);
141   instance = new FGPropertyManager(instanceRoot);
142   Debug(0);
143   // this is to catch errors in binding member functions to the property tree.
144   try {
145     Allocate();
146   } catch ( string msg ) {
147     cout << "Caught error: " << msg << endl;
148     exit(1);
149   }
150
151   trim_status = false;
152   ta_mode     = 99;
153
154   Constructing = true;
155   typedef int (FGFDMExec::*iPMF)(void) const;
156 //  typedef double (FGFDMExec::*dPMF)(void) const;
157 //  typedef unsigned int (FGFDMExec::*uiPMF)(void) const;
158 //  instance->Tie("simulation/do_trim_analysis", this, (iPMF)0, &FGFDMExec::DoTrimAnalysis, false);
159   instance->Tie("simulation/do_simple_trim", this, (iPMF)0, &FGFDMExec::DoTrim, false);
160   instance->Tie("simulation/do_simplex_trim", this, (iPMF)0, &FGFDMExec::DoSimplexTrim);
161   instance->Tie("simulation/do_linearization", this, (iPMF)0, &FGFDMExec::DoLinearization);
162   instance->Tie("simulation/reset", (int*)&ResetMode);
163   instance->Tie("simulation/randomseed", this, (iPMF)0, &FGFDMExec::SRand, false);
164   instance->Tie("simulation/terminate", (int *)&Terminate);
165   instance->Tie("simulation/sim-time-sec", this, &FGFDMExec::GetSimTime);
166   instance->Tie("simulation/dt", this, &FGFDMExec::GetDeltaT);
167   instance->Tie("simulation/jsbsim-debug", this, &FGFDMExec::GetDebugLevel, &FGFDMExec::SetDebugLevel);
168   instance->Tie("simulation/frame", (int *)&Frame, false);
169
170   // simplex trim properties
171   instanceRoot->SetDouble("trim/solver/rtol",0.0001);
172   instanceRoot->SetDouble("trim/solver/speed",2);
173   instanceRoot->SetDouble("trim/solver/abstol",0.001);
174   instanceRoot->SetDouble("trim/solver/iterMax",2000);
175   instanceRoot->SetInt("trim/solver/debugLevel",0);
176   instanceRoot->SetDouble("trim/solver/random",0);
177   instanceRoot->SetBool("trim/solver/showSimplex",false);
178   instanceRoot->SetBool("trim/solver/showConvergence",false);
179   instanceRoot->SetBool("trim/solver/pause",false);
180   instanceRoot->SetBool("trim/solver/variablePropPitch",false);
181
182   instanceRoot->SetDouble("trim/solver/throttleGuess",0.50);
183   instanceRoot->SetDouble("trim/solver/throttleMin",0.0);
184   instanceRoot->SetDouble("trim/solver/throttleMax",1.0);
185   instanceRoot->SetDouble("trim/solver/throttleStep",0.1);
186
187   instanceRoot->SetDouble("trim/solver/aileronGuess",0);
188   instanceRoot->SetDouble("trim/solver/aileronMin",-1.00);
189   instanceRoot->SetDouble("trim/solver/aileronMax",1.00);
190   instanceRoot->SetDouble("trim/solver/aileronStep",0.1);
191
192   instanceRoot->SetDouble("trim/solver/rudderGuess",0);
193   instanceRoot->SetDouble("trim/solver/rudderMin",-1.00);
194   instanceRoot->SetDouble("trim/solver/rudderMax",1.00);
195   instanceRoot->SetDouble("trim/solver/rudderStep",0.1);
196
197   instanceRoot->SetDouble("trim/solver/elevatorGuess",-0.1);
198   instanceRoot->SetDouble("trim/solver/elevatorMin",-1.0);
199   instanceRoot->SetDouble("trim/solver/elevatorMax",1.0);
200   instanceRoot->SetDouble("trim/solver/elevatorStep",0.1);
201
202   instanceRoot->SetDouble("trim/solver/alphaGuess",0.05);
203   instanceRoot->SetDouble("trim/solver/alphaMin",-0.1);
204   instanceRoot->SetDouble("trim/solver/alphaMax",.18);
205   instanceRoot->SetDouble("trim/solver/alphaStep",0.05);
206
207   instanceRoot->SetDouble("trim/solver/betaGuess",0);
208   instanceRoot->SetDouble("trim/solver/betaMin",-0.1);
209   instanceRoot->SetDouble("trim/solver/betaMax",0.1);
210   instanceRoot->SetDouble("trim/solver/betaStep",0.0001);
211
212   Constructing = false;
213 }
214
215 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216
217 FGFDMExec::~FGFDMExec()
218 {
219   try {
220     Unbind();
221     DeAllocate();
222
223     delete instance;
224
225     if (IdFDM == 0) { // Meaning this is no child FDM
226       if(Root != 0) {
227          if(StandAlone)
228             delete Root;
229          Root = 0;
230       }
231       if(FDMctr != 0) {
232          delete FDMctr;
233          FDMctr = 0;
234       }
235     }
236   } catch ( string msg ) {
237     cout << "Caught error: " << msg << endl;
238   }
239
240   for (unsigned int i=1; i<ChildFDMList.size(); i++) delete ChildFDMList[i]->exec;
241   ChildFDMList.clear();
242
243   PropertyCatalog.clear();
244
245   if (FDMctr > 0) (*FDMctr)--;
246
247   Debug(1);
248 }
249
250 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251
252 bool FGFDMExec::Allocate(void)
253 {
254   bool result=true;
255
256   Models.resize(eNumStandardModels);
257
258   // See the eModels enum specification in the header file. The order of the enums
259   // specifies the order of execution. The Models[] vector is the primary
260   // storage array for the list of models.
261   Models[ePropagate]         = new FGPropagate(this);
262   Models[eInput]             = new FGInput(this);
263   Models[eInertial]          = new FGInertial(this);
264   Models[eAtmosphere]        = new FGStandardAtmosphere(this);
265   Models[eWinds]             = new FGWinds(this);
266   Models[eAuxiliary]         = new FGAuxiliary(this);
267   Models[eSystems]           = new FGFCS(this);
268   Models[ePropulsion]        = new FGPropulsion(this);
269   Models[eAerodynamics]      = new FGAerodynamics (this);
270   Models[eGroundReactions]   = new FGGroundReactions(this);
271   Models[eExternalReactions] = new FGExternalReactions(this);
272   Models[eBuoyantForces]     = new FGBuoyantForces(this);
273   Models[eMassBalance]       = new FGMassBalance(this);
274   Models[eAircraft]          = new FGAircraft(this);
275   Models[eAccelerations]     = new FGAccelerations(this);
276   Models[eOutput]            = new FGOutput(this);
277
278   // Assign the Model shortcuts for internal executive use only.
279   Propagate = (FGPropagate*)Models[ePropagate];
280   Inertial = (FGInertial*)Models[eInertial];
281   Atmosphere = (FGAtmosphere*)Models[eAtmosphere];
282   Winds = (FGWinds*)Models[eWinds];
283   Auxiliary = (FGAuxiliary*)Models[eAuxiliary];
284   FCS = (FGFCS*)Models[eSystems];
285   Propulsion = (FGPropulsion*)Models[ePropulsion];
286   Aerodynamics = (FGAerodynamics*)Models[eAerodynamics];
287   GroundReactions = (FGGroundReactions*)Models[eGroundReactions];
288   ExternalReactions = (FGExternalReactions*)Models[eExternalReactions];
289   BuoyantForces = (FGBuoyantForces*)Models[eBuoyantForces];
290   MassBalance = (FGMassBalance*)Models[eMassBalance];
291   Aircraft = (FGAircraft*)Models[eAircraft];
292   Accelerations = (FGAccelerations*)Models[eAccelerations];
293   Output = (FGOutput*)Models[eOutput];
294
295   // Initialize planet (environment) constants
296   LoadPlanetConstants();
297   GetGroundCallback()->SetSeaLevelRadius(Inertial->GetRefRadius());
298
299   // Initialize models
300   for (unsigned int i = 0; i < Models.size(); i++) {
301     // The Output model must not be initialized prior to IC loading
302     if (i == eOutput) continue;
303
304     LoadInputs(i);
305     Models[i]->InitModel();
306   }
307
308   IC = new FGInitialCondition(this);
309
310   modelLoaded = false;
311
312   return result;
313 }
314
315 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
316
317 bool FGFDMExec::DeAllocate(void)
318 {
319
320   for (unsigned int i=0; i<eNumStandardModels; i++) delete Models[i];
321   Models.clear();
322
323   delete Script;
324   delete IC;
325   delete Trim;
326
327   Error       = 0;
328
329   modelLoaded = false;
330   return modelLoaded;
331 }
332
333 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334
335 void FGFDMExec::Schedule(FGModel* model, int rate)
336 {
337   model->SetRate(rate);
338   Models.push_back(model);
339 }
340
341 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342
343 bool FGFDMExec::Run(void)
344 {
345   bool success=true;
346
347   Debug(2);
348
349   for (unsigned int i=1; i<ChildFDMList.size(); i++) {
350     ChildFDMList[i]->AssignState( (FGPropagate*)Models[ePropagate] ); // Transfer state to the child FDM
351     ChildFDMList[i]->Run();
352   }
353
354   IncrTime();
355
356   // returns true if success, false if complete
357   if (Script != 0 && !IntegrationSuspended()) success = Script->RunScript();
358
359   for (unsigned int i = 0; i < Models.size(); i++) {
360     LoadInputs(i);
361     Models[i]->Run(holding);
362   }
363
364   if (ResetMode) {
365     if (ResetMode == 1) Output->SetStartNewOutput();
366
367     ResetMode = 0;
368     ResetToInitialConditions();
369   }
370
371   if (Terminate) success = false;
372
373   return success;
374 }
375
376 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377
378 void FGFDMExec::LoadInputs(unsigned int idx)
379 {
380   switch(idx) {
381   case ePropagate:
382     Propagate->in.vPQRidot     = Accelerations->GetPQRidot();
383     Propagate->in.vQtrndot     = Accelerations->GetQuaterniondot();
384     Propagate->in.vUVWidot     = Accelerations->GetUVWidot();
385     Propagate->in.DeltaT       = dT;
386     break;
387   case eInput:
388     break;
389   case eInertial:
390     Inertial->in.Radius        = Propagate->GetRadius();
391     Inertial->in.Latitude      = Propagate->GetLatitude();
392     break;
393   case eAtmosphere:
394     Atmosphere->in.altitudeASL = Propagate->GetAltitudeASL();
395     break;
396   case eWinds:
397     Winds->in.AltitudeASL      = Propagate->GetAltitudeASL();
398     Winds->in.DistanceAGL      = Propagate->GetDistanceAGL();
399     Winds->in.Tl2b             = Propagate->GetTl2b();
400     Winds->in.Tw2b             = Auxiliary->GetTw2b();
401     Winds->in.V                = Auxiliary->GetVt();
402     Winds->in.totalDeltaT      = dT * Winds->GetRate();
403     break;
404   case eAuxiliary:
405     Auxiliary->in.Pressure     = Atmosphere->GetPressure();
406     Auxiliary->in.Density      = Atmosphere->GetDensity();
407     Auxiliary->in.DensitySL    = Atmosphere->GetDensitySL();
408     Auxiliary->in.PressureSL   = Atmosphere->GetPressureSL();
409     Auxiliary->in.Temperature  = Atmosphere->GetTemperature();
410     Auxiliary->in.SoundSpeed   = Atmosphere->GetSoundSpeed();
411     Auxiliary->in.KinematicViscosity = Atmosphere->GetKinematicViscosity();
412     Auxiliary->in.DistanceAGL  = Propagate->GetDistanceAGL();
413     Auxiliary->in.Mass         = MassBalance->GetMass();
414     Auxiliary->in.Tl2b         = Propagate->GetTl2b();
415     Auxiliary->in.Tb2l         = Propagate->GetTb2l();
416     Auxiliary->in.vPQR         = Propagate->GetPQR();
417     Auxiliary->in.vPQRdot      = Accelerations->GetPQRdot();
418     Auxiliary->in.vUVW         = Propagate->GetUVW();
419     Auxiliary->in.vUVWdot      = Accelerations->GetUVWdot();
420     Auxiliary->in.vVel         = Propagate->GetVel();
421     Auxiliary->in.vBodyAccel   = Accelerations->GetBodyAccel();
422     Auxiliary->in.ToEyePt      = MassBalance->StructuralToBody(Aircraft->GetXYZep());
423     Auxiliary->in.VRPBody      = MassBalance->StructuralToBody(Aircraft->GetXYZvrp());
424     Auxiliary->in.RPBody       = MassBalance->StructuralToBody(Aircraft->GetXYZrp());
425     Auxiliary->in.vFw          = Aerodynamics->GetvFw();
426     Auxiliary->in.vLocation    = Propagate->GetLocation();
427     Auxiliary->in.CosTht       = Propagate->GetCosEuler(eTht);
428     Auxiliary->in.SinTht       = Propagate->GetSinEuler(eTht);
429     Auxiliary->in.CosPhi       = Propagate->GetCosEuler(ePhi);
430     Auxiliary->in.SinPhi       = Propagate->GetSinEuler(ePhi);
431     Auxiliary->in.Psi          = Propagate->GetEuler(ePsi);
432     Auxiliary->in.TotalWindNED = Winds->GetTotalWindNED();
433     Auxiliary->in.TurbPQR      = Winds->GetTurbPQR();
434     Auxiliary->in.WindPsi      = Winds->GetWindPsi();
435     Auxiliary->in.Vwind        = Winds->GetTotalWindNED().Magnitude();
436     break;
437   case eSystems:
438     // Dynamic inputs come into the components that FCS manages through properties
439     break;
440   case ePropulsion:
441     Propulsion->in.SLPressure       = Atmosphere->GetPressureSL();
442     Propulsion->in.Pressure         = Atmosphere->GetPressure();
443     Propulsion->in.PressureRatio    = Atmosphere->GetPressureRatio();
444     Propulsion->in.Temperature      = Atmosphere->GetTemperature();
445     Propulsion->in.DensityRatio     = Atmosphere->GetDensityRatio();
446     Propulsion->in.Density          = Atmosphere->GetDensity();
447     Propulsion->in.Soundspeed       = Atmosphere->GetSoundSpeed();
448     Propulsion->in.TotalPressure    = Auxiliary->GetTotalPressure();
449     Propulsion->in.TotalTempearture = Auxiliary->GetTotalTemperature();
450     Propulsion->in.Vc               = Auxiliary->GetVcalibratedKTS();
451     Propulsion->in.Vt               = Auxiliary->GetVt();
452     Propulsion->in.qbar             = Auxiliary->Getqbar();
453     Propulsion->in.TAT_c            = Auxiliary->GetTAT_C();
454     Propulsion->in.AeroUVW          = Auxiliary->GetAeroUVW();
455     Propulsion->in.AeroPQR          = Auxiliary->GetAeroPQR();
456     Propulsion->in.alpha            = Auxiliary->Getalpha();
457     Propulsion->in.beta             = Auxiliary->Getbeta();
458     Propulsion->in.TotalDeltaT      = dT * Propulsion->GetRate();
459     Propulsion->in.ThrottlePos      = FCS->GetThrottlePos();
460     Propulsion->in.MixturePos       = FCS->GetMixturePos();
461     Propulsion->in.ThrottleCmd      = FCS->GetThrottleCmd();
462     Propulsion->in.MixtureCmd       = FCS->GetMixtureCmd();
463     Propulsion->in.PropAdvance      = FCS->GetPropAdvance();
464     Propulsion->in.PropFeather      = FCS->GetPropFeather();
465     Propulsion->in.H_agl            = Propagate->GetDistanceAGL();
466     Propulsion->in.PQR              = Propagate->GetPQR();
467
468     break;
469   case eAerodynamics:
470     Aerodynamics->in.Alpha     = Auxiliary->Getalpha();
471     Aerodynamics->in.Beta      = Auxiliary->Getbeta();
472     Aerodynamics->in.Qbar      = Auxiliary->Getqbar();
473     Aerodynamics->in.Vt        = Auxiliary->GetVt();
474     Aerodynamics->in.Tb2w      = Auxiliary->GetTb2w();
475     Aerodynamics->in.Tw2b      = Auxiliary->GetTw2b();
476     Aerodynamics->in.RPBody    = MassBalance->StructuralToBody(Aircraft->GetXYZrp());
477     break;
478   case eGroundReactions:
479     // There are no external inputs to this model.
480     GroundReactions->in.Vground         = Auxiliary->GetVground();
481     GroundReactions->in.VcalibratedKts  = Auxiliary->GetVcalibratedKTS();
482     GroundReactions->in.Temperature     = Atmosphere->GetTemperature();
483     GroundReactions->in.TakeoffThrottle = (FCS->GetThrottlePos().size() > 0) ? (FCS->GetThrottlePos(0) > 0.90) : false;
484     GroundReactions->in.SteerPosDeg     = FCS->GetSteerPosDeg();
485     GroundReactions->in.BrakePos        = FCS->GetBrakePos();
486     GroundReactions->in.FCSGearPos      = FCS->GetGearPos();
487     GroundReactions->in.EmptyWeight     = MassBalance->GetEmptyWeight();
488     GroundReactions->in.Tb2l            = Propagate->GetTb2l();
489     GroundReactions->in.Tec2l           = Propagate->GetTec2l();
490     GroundReactions->in.Tec2b           = Propagate->GetTec2b();
491     GroundReactions->in.PQR             = Propagate->GetPQR();
492     GroundReactions->in.UVW             = Propagate->GetUVW();
493     GroundReactions->in.DistanceAGL     = Propagate->GetDistanceAGL();
494     GroundReactions->in.DistanceASL     = Propagate->GetAltitudeASL();
495     GroundReactions->in.TotalDeltaT     = dT * GroundReactions->GetRate();
496     GroundReactions->in.WOW             = GroundReactions->GetWOW();
497     GroundReactions->in.Location        = Propagate->GetLocation();
498     GroundReactions->in.vXYZcg          = MassBalance->GetXYZcg();
499     break;
500   case eExternalReactions:
501     // There are no external inputs to this model.
502     break;
503   case eBuoyantForces:
504     BuoyantForces->in.Density     = Atmosphere->GetDensity();
505     BuoyantForces->in.Pressure    = Atmosphere->GetPressure();
506     BuoyantForces->in.Temperature = Atmosphere->GetTemperature();
507     BuoyantForces->in.gravity     = Inertial->gravity();
508     break;
509   case eMassBalance:
510     MassBalance->in.GasInertia  = BuoyantForces->GetGasMassInertia();
511     MassBalance->in.GasMass     = BuoyantForces->GetGasMass();
512     MassBalance->in.GasMoment   = BuoyantForces->GetGasMassMoment();
513     MassBalance->in.TanksWeight = Propulsion->GetTanksWeight();
514     MassBalance->in.TanksMoment = Propulsion->GetTanksMoment();
515     MassBalance->in.TankInertia = Propulsion->CalculateTankInertias();
516     break;
517   case eAircraft:
518     Aircraft->in.AeroForce     = Aerodynamics->GetForces();
519     Aircraft->in.PropForce     = Propulsion->GetForces();
520     Aircraft->in.GroundForce   = GroundReactions->GetForces();
521     Aircraft->in.ExternalForce = ExternalReactions->GetForces();
522     Aircraft->in.BuoyantForce  = BuoyantForces->GetForces();
523     Aircraft->in.AeroMoment    = Aerodynamics->GetMoments();
524     Aircraft->in.PropMoment    = Propulsion->GetMoments();
525     Aircraft->in.GroundMoment  = GroundReactions->GetMoments();
526     Aircraft->in.ExternalMoment = ExternalReactions->GetMoments();
527     Aircraft->in.BuoyantMoment = BuoyantForces->GetMoments();
528     break;
529   case eAccelerations:
530     Accelerations->in.J        = MassBalance->GetJ();
531     Accelerations->in.Jinv     = MassBalance->GetJinv();
532     Accelerations->in.Ti2b     = Propagate->GetTi2b();
533     Accelerations->in.Tb2i     = Propagate->GetTb2i();
534     Accelerations->in.Tec2b    = Propagate->GetTec2b();
535     Accelerations->in.Tec2i    = Propagate->GetTec2i();
536     Accelerations->in.qAttitudeECI = Propagate->GetQuaternionECI();
537     Accelerations->in.Moment   = Aircraft->GetMoments();
538     Accelerations->in.GroundMoment  = GroundReactions->GetMoments();
539     Accelerations->in.Force    = Aircraft->GetForces();
540     Accelerations->in.GroundForce   = GroundReactions->GetForces();
541     Accelerations->in.GAccel   = Inertial->GetGAccel(Propagate->GetRadius());
542     Accelerations->in.J2Grav  = Inertial->GetGravityJ2(Propagate->GetLocation());
543     Accelerations->in.vPQRi    = Propagate->GetPQRi();
544     Accelerations->in.vPQR     = Propagate->GetPQR();
545     Accelerations->in.vUVW     = Propagate->GetUVW();
546     Accelerations->in.vInertialPosition = Propagate->GetInertialPosition();
547     Accelerations->in.DeltaT   = dT;
548     Accelerations->in.Mass     = MassBalance->GetMass();
549     Accelerations->in.MultipliersList = GroundReactions->GetMultipliersList();
550     Accelerations->in.TerrainVelocity = Propagate->GetTerrainVelocity();
551     Accelerations->in.TerrainAngularVel = Propagate->GetTerrainAngularVelocity();
552     break;
553   default:
554     break;
555   }
556 }
557
558 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
559
560 void FGFDMExec::LoadPlanetConstants(void)
561 {
562   Propagate->in.vOmegaPlanet     = Inertial->GetOmegaPlanet();
563   Accelerations->in.vOmegaPlanet = Inertial->GetOmegaPlanet();
564   Propagate->in.SemiMajor        = Inertial->GetSemimajor();
565   Propagate->in.SemiMinor        = Inertial->GetSemiminor();
566   Auxiliary->in.SLGravity        = Inertial->SLgravity();
567   Auxiliary->in.ReferenceRadius  = Inertial->GetRefRadius();
568 }
569
570 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
571
572 void FGFDMExec::LoadModelConstants(void)
573 {
574   Winds->in.wingspan             = Aircraft->GetWingSpan();
575   FCS->in.NumGear                = GroundReactions->GetNumGearUnits();
576   Aerodynamics->in.Wingarea      = Aircraft->GetWingArea();
577   Aerodynamics->in.Wingchord     = Aircraft->Getcbar();
578   Aerodynamics->in.Wingincidence = Aircraft->GetWingIncidence();
579   Aerodynamics->in.Wingspan      = Aircraft->GetWingSpan();
580   Auxiliary->in.Wingspan         = Aircraft->GetWingSpan();
581   Auxiliary->in.Wingchord        = Aircraft->Getcbar();
582   GroundReactions->in.vXYZcg     = MassBalance->GetXYZcg();
583
584   LoadPlanetConstants();
585 }
586
587 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
588 // This call will cause the sim time to reset to 0.0
589
590 bool FGFDMExec::RunIC(void)
591 {
592   FGPropulsion* propulsion = (FGPropulsion*)Models[ePropulsion];
593
594   if (!trim_status)
595     Models[eOutput]->InitModel();
596
597   SuspendIntegration(); // saves the integration rate, dt, then sets it to 0.0.
598   Initialize(IC);
599   Run();
600   ResumeIntegration(); // Restores the integration rate to what it was.
601
602   for (unsigned int i=0; i<IC->GetNumEnginesRunning(); i++)
603     propulsion->InitRunning(IC->GetEngineRunning(i));
604
605   return true;
606 }
607
608 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
609
610 void FGFDMExec::Initialize(FGInitialCondition *FGIC)
611 {
612   Setsim_time(0.0);
613
614   Propagate->SetInitialState( FGIC );
615   LoadInputs(eInertial);
616   Inertial->Run(false);
617   LoadInputs(eAccelerations);
618   Accelerations->Run(false);
619   LoadInputs(ePropagate);
620   Propagate->InitializeDerivatives();
621   Winds->SetWindNED(FGIC->GetWindNEDFpsIC());
622   LoadInputs(eMassBalance);
623   MassBalance->Run(false);
624 }
625
626 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
627
628 void FGFDMExec::ResetToInitialConditions(void)
629 {
630   if (Constructing) return;
631
632   for (unsigned int i = 0; i < Models.size(); i++) {
633     // The Output model will be initialized during the RunIC() execution
634     if (i == eOutput) continue;
635
636     LoadInputs(i);
637     Models[i]->InitModel();
638   }
639
640   if (Script) Script->ResetEvents();
641
642   RunIC();
643 }
644
645 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
646
647 vector <string> FGFDMExec::EnumerateFDMs(void)
648 {
649   vector <string> FDMList;
650   FGAircraft* Aircraft = (FGAircraft*)Models[eAircraft];
651
652   FDMList.push_back(Aircraft->GetAircraftName());
653
654   for (unsigned int i=1; i<ChildFDMList.size(); i++) {
655     FDMList.push_back(ChildFDMList[i]->exec->GetAircraft()->GetAircraftName());
656   }
657
658   return FDMList;
659 }
660
661 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662
663 bool FGFDMExec::LoadScript(const string& script, double deltaT, const string initfile)
664 {
665   bool result;
666
667   Script = new FGScript(this);
668   result = Script->LoadScript(RootDir + script, deltaT, initfile);
669
670   return result;
671 }
672
673 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
674
675 bool FGFDMExec::LoadModel(const string& AircraftPath, const string& EnginePath, const string& SystemsPath,
676                 const string& model, bool addModelToPath)
677 {
678   FGFDMExec::AircraftPath = RootDir + AircraftPath;
679   FGFDMExec::EnginePath = RootDir + EnginePath;
680   FGFDMExec::SystemsPath = RootDir + SystemsPath;
681
682   return LoadModel(model, addModelToPath);
683 }
684
685 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686
687 bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
688 {
689   string token;
690   string aircraftCfgFileName;
691   Element* element = 0L;
692   bool result = false; // initialize result to false, indicating input file not yet read
693
694   modelName = model; // Set the class modelName attribute
695
696   if( AircraftPath.empty() || EnginePath.empty() || SystemsPath.empty()) {
697     cerr << "Error: attempted to load aircraft with undefined ";
698     cerr << "aircraft, engine, and system paths" << endl;
699     return false;
700   }
701
702   FullAircraftPath = AircraftPath;
703   if (addModelToPath) FullAircraftPath += "/" + model;
704   aircraftCfgFileName = FullAircraftPath + "/" + model + ".xml";
705
706   if (modelLoaded) {
707     DeAllocate();
708     Allocate();
709   }
710
711   int saved_debug_lvl = debug_lvl;
712   FGXMLFileRead XMLFileRead;
713   Element *document = XMLFileRead.LoadXMLDocument(aircraftCfgFileName); // "document" is a class member
714
715   if (document) {
716     if (IsChild) debug_lvl = 0;
717
718     ReadPrologue(document);
719
720     if (IsChild) debug_lvl = saved_debug_lvl;
721
722     // Process the fileheader element in the aircraft config file. This element is OPTIONAL.
723     element = document->FindElement("fileheader");
724     if (element) {
725       result = ReadFileHeader(element);
726       if (!result) {
727         cerr << endl << "Aircraft fileheader element has problems in file " << aircraftCfgFileName << endl;
728         return result;
729       }
730     }
731
732     if (IsChild) debug_lvl = 0;
733
734     // Process the metrics element. This element is REQUIRED.
735     element = document->FindElement("metrics");
736     if (element) {
737       result = ((FGAircraft*)Models[eAircraft])->Load(element);
738       if (!result) {
739         cerr << endl << "Aircraft metrics element has problems in file " << aircraftCfgFileName << endl;
740         return result;
741       }
742     } else {
743       cerr << endl << "No metrics element was found in the aircraft config file." << endl;
744       return false;
745     }
746
747     // Process the mass_balance element. This element is REQUIRED.
748     element = document->FindElement("mass_balance");
749     if (element) {
750       result = ((FGMassBalance*)Models[eMassBalance])->Load(element);
751       if (!result) {
752         cerr << endl << "Aircraft mass_balance element has problems in file " << aircraftCfgFileName << endl;
753         return result;
754       }
755     } else {
756       cerr << endl << "No mass_balance element was found in the aircraft config file." << endl;
757       return false;
758     }
759
760     // Process the ground_reactions element. This element is REQUIRED.
761     element = document->FindElement("ground_reactions");
762     if (element) {
763       result = ((FGGroundReactions*)Models[eGroundReactions])->Load(element);
764       if (!result) {
765         cerr << endl << "Aircraft ground_reactions element has problems in file " << aircraftCfgFileName << endl;
766         return result;
767       }
768       ((FGFCS*)Models[eSystems])->AddGear(((FGGroundReactions*)Models[eGroundReactions])->GetNumGearUnits());
769     } else {
770       cerr << endl << "No ground_reactions element was found in the aircraft config file." << endl;
771       return false;
772     }
773
774     // Process the external_reactions element. This element is OPTIONAL.
775     element = document->FindElement("external_reactions");
776     if (element) {
777       result = ((FGExternalReactions*)Models[eExternalReactions])->Load(element);
778       if (!result) {
779         cerr << endl << "Aircraft external_reactions element has problems in file " << aircraftCfgFileName << endl;
780         return result;
781       }
782     }
783
784     // Process the buoyant_forces element. This element is OPTIONAL.
785     element = document->FindElement("buoyant_forces");
786     if (element) {
787       result = ((FGBuoyantForces*)Models[eBuoyantForces])->Load(element);
788       if (!result) {
789         cerr << endl << "Aircraft buoyant_forces element has problems in file " << aircraftCfgFileName << endl;
790         return result;
791       }
792     }
793
794     // Process the propulsion element. This element is OPTIONAL.
795     element = document->FindElement("propulsion");
796     if (element) {
797       result = ((FGPropulsion*)Models[ePropulsion])->Load(element);
798       if (!result) {
799         cerr << endl << "Aircraft propulsion element has problems in file " << aircraftCfgFileName << endl;
800         return result;
801       }
802       for (unsigned int i=0; i<((FGPropulsion*)Models[ePropulsion])->GetNumEngines(); i++)
803         ((FGFCS*)Models[eSystems])->AddThrottle();
804     }
805
806     // Process the system element[s]. This element is OPTIONAL, and there may be more than one.
807     element = document->FindElement("system");
808     while (element) {
809       result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stSystem);
810       if (!result) {
811         cerr << endl << "Aircraft system element has problems in file " << aircraftCfgFileName << endl;
812         return result;
813       }
814       element = document->FindNextElement("system");
815     }
816
817     // Process the autopilot element. This element is OPTIONAL.
818     element = document->FindElement("autopilot");
819     if (element) {
820       result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stAutoPilot);
821       if (!result) {
822         cerr << endl << "Aircraft autopilot element has problems in file " << aircraftCfgFileName << endl;
823         return result;
824       }
825     }
826
827     // Process the flight_control element. This element is OPTIONAL.
828     element = document->FindElement("flight_control");
829     if (element) {
830       result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stFCS);
831       if (!result) {
832         cerr << endl << "Aircraft flight_control element has problems in file " << aircraftCfgFileName << endl;
833         return result;
834       }
835     }
836
837     // Process the aerodynamics element. This element is OPTIONAL, but almost always expected.
838     element = document->FindElement("aerodynamics");
839     if (element) {
840       result = ((FGAerodynamics*)Models[eAerodynamics])->Load(element);
841       if (!result) {
842         cerr << endl << "Aircraft aerodynamics element has problems in file " << aircraftCfgFileName << endl;
843         return result;
844       }
845     } else {
846       cerr << endl << "No expected aerodynamics element was found in the aircraft config file." << endl;
847     }
848
849     // Process the input element. This element is OPTIONAL.
850     element = document->FindElement("input");
851     if (element) {
852       result = ((FGInput*)Models[eInput])->Load(element);
853       if (!result) {
854         cerr << endl << "Aircraft input element has problems in file " << aircraftCfgFileName << endl;
855         return result;
856       }
857     }
858
859     // Process the output element[s]. This element is OPTIONAL, and there may be more than one.
860     element = document->FindElement("output");
861     while (element) {
862       string output_file_name = aircraftCfgFileName;
863
864       if (!element->GetAttributeValue("file").empty()) {
865         output_file_name = RootDir + element->GetAttributeValue("file");
866         result = ((FGOutput*)Models[eOutput])->SetDirectivesFile(output_file_name);
867       }
868       else
869         result = ((FGOutput*)Models[eOutput])->Load(element);
870
871       if (!result) {
872         cerr << endl << "Aircraft output element has problems in file " << output_file_name << endl;
873         return result;
874       }
875       element = document->FindNextElement("output");
876     }
877
878     // Lastly, process the child element. This element is OPTIONAL - and NOT YET SUPPORTED.
879     element = document->FindElement("child");
880     if (element) {
881       result = ReadChild(element);
882       if (!result) {
883         cerr << endl << "Aircraft child element has problems in file " << aircraftCfgFileName << endl;
884         return result;
885       }
886     }
887
888     // Since all vehicle characteristics have been loaded, place the values in the Inputs
889     // structure for the FGModel-derived classes.
890     LoadModelConstants();
891
892     modelLoaded = true;
893
894     if (debug_lvl > 0) {
895       LoadInputs(eMassBalance); // Update all input mass properties for the report.
896       Models[eMassBalance]->Run(false);  // Update all mass properties for the report.
897       LoadInputs(ePropulsion); // Update propulsion properties for the report.
898       Models[ePropulsion]->Run(false);  // Update propulsion properties for the report.
899       LoadInputs(eMassBalance); // Update all (one more time) input mass properties for the report.
900       Models[eMassBalance]->Run(false);  // Update all (one more time) mass properties for the report.
901       ((FGMassBalance*)Models[eMassBalance])->GetMassPropertiesReport();
902
903       cout << endl << fgblue << highint
904            << "End of vehicle configuration loading." << endl
905            << "-------------------------------------------------------------------------------"
906            << reset << endl;
907     }
908
909     if (IsChild) debug_lvl = saved_debug_lvl;
910
911   } else {
912     cerr << fgred
913          << "  JSBSim failed to open the configuration file: " << aircraftCfgFileName
914          << fgdef << endl;
915   }
916
917   for (unsigned int i=0; i< Models.size(); i++) LoadInputs(i);
918
919   if (result) {
920     struct PropertyCatalogStructure masterPCS;
921     masterPCS.base_string = "";
922     masterPCS.node = Root->GetNode();
923     BuildPropertyCatalog(&masterPCS);
924   }
925
926   return result;
927 }
928
929 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
930
931 string FGFDMExec::GetPropulsionTankReport()
932 {
933   return ((FGPropulsion*)Models[ePropulsion])->GetPropulsionTankReport();
934 }
935
936 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
937
938 void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs)
939 {
940   struct PropertyCatalogStructure* pcsNew = new struct PropertyCatalogStructure;
941   int node_idx = 0;
942
943   for (int i=0; i<pcs->node->nChildren(); i++) {
944     string access="";
945     pcsNew->base_string = pcs->base_string + "/" + pcs->node->getChild(i)->getName();
946     node_idx = pcs->node->getChild(i)->getIndex();
947     if (node_idx != 0) {
948       pcsNew->base_string = CreateIndexedPropertyName(pcsNew->base_string, node_idx);
949     }
950     if (pcs->node->getChild(i)->nChildren() == 0) {
951       if (pcsNew->base_string.substr(0,12) == string("/fdm/jsbsim/")) {
952         pcsNew->base_string = pcsNew->base_string.erase(0,12);
953       }
954       if (pcs->node->getChild(i)->getAttribute(SGPropertyNode::READ)) access="R";
955       if (pcs->node->getChild(i)->getAttribute(SGPropertyNode::WRITE)) access+="W";
956       PropertyCatalog.push_back(pcsNew->base_string+" ("+access+")");
957     } else {
958       pcsNew->node = (FGPropertyNode*)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   std::cout << "dT: " << dT << std::endl;
1197 }
1198
1199 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1200
1201 void FGFDMExec::DoLinearization(int mode)
1202 {
1203   double saved_time;
1204   if (Constructing) return;
1205   saved_time = sim_time;
1206   FGLinearization lin(this,mode);
1207   sim_time = saved_time;
1208   Setsim_time(saved_time);
1209 }
1210
1211 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1212
1213 void FGFDMExec::SRand(int sr)
1214 {
1215   srand(sr);
1216 }
1217
1218 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1219 //    The bitmasked value choices are as follows:
1220 //    unset: In this case (the default) JSBSim would only print
1221 //       out the normally expected messages, essentially echoing
1222 //       the config files as they are read. If the environment
1223 //       variable is not set, debug_lvl is set to 1 internally
1224 //    0: This requests JSBSim not to output any messages
1225 //       whatsoever.
1226 //    1: This value explicity requests the normal JSBSim
1227 //       startup messages
1228 //    2: This value asks for a message to be printed out when
1229 //       a class is instantiated
1230 //    4: When this value is set, a message is displayed when a
1231 //       FGModel object executes its Run() method
1232 //    8: When this value is set, various runtime state variables
1233 //       are printed out periodically
1234 //    16: When set various parameters are sanity checked and
1235 //       a message is printed out when they go out of bounds
1236
1237 void FGFDMExec::Debug(int from)
1238 {
1239   if (debug_lvl <= 0) return;
1240
1241   if (debug_lvl & 1 && IdFDM == 0) { // Standard console startup message output
1242     if (from == 0) { // Constructor
1243       cout << "\n\n     "
1244            << "JSBSim Flight Dynamics Model v" << JSBSim_version << endl;
1245       cout << "            [JSBSim-ML v" << needed_cfg_version << "]\n\n";
1246       cout << "JSBSim startup beginning ...\n\n";
1247     } else if (from == 3) {
1248       cout << "\n\nJSBSim startup complete\n\n";
1249     }
1250   }
1251   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
1252     if (from == 0) cout << "Instantiated: FGFDMExec" << endl;
1253     if (from == 1) cout << "Destroyed:    FGFDMExec" << endl;
1254   }
1255   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
1256     if (from == 2) {
1257       cout << "================== Frame: " << Frame << "  Time: "
1258            << sim_time << " dt: " << dT << endl;
1259     }
1260   }
1261   if (debug_lvl & 8 ) { // Runtime state variables
1262   }
1263   if (debug_lvl & 16) { // Sanity checking
1264   }
1265   if (debug_lvl & 64) {
1266     if (from == 0) { // Constructor
1267       cout << IdSrc << endl;
1268       cout << IdHdr << endl;
1269     }
1270   }
1271 }
1272 }
1273
1274