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