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