]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGFDMExec.cpp
ed10e6986e958f6a090e0456c3b5d4559672481e
[flightgear.git] / src / FDM / JSBSim / FGFDMExec.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Module:       FGFDMExec.cpp
4  Author:       Jon S. Berndt
5  Date started: 11/17/98
6  Purpose:      Schedules and runs the model routines.
7  Called by:    The GUI.
8
9  ------------- Copyright (C) 1999  Jon S. Berndt (jsb@hal-pc.org) -------------
10
11  This program is free software; you can redistribute it and/or modify it under
12  the terms of the GNU 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 General Public License for more
19  details.
20
21  You should have received a copy of the GNU 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 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 #ifdef FGFS
46 #  include <time.h>
47 #  include <simgear/compiler.h>
48 #  include STL_IOSTREAM
49 #  include STL_ITERATOR
50 #else
51 #  include <iostream>
52 #  include <ctime>
53 #  include <iterator>
54 #endif
55
56 #include "FGFDMExec.h"
57 #include "FGState.h"
58 #include "FGAtmosphere.h"
59 #include "FGFCS.h"
60 #include "FGPropulsion.h"
61 #include "FGMassBalance.h"
62 #include "FGAerodynamics.h"
63 #include "FGInertial.h"
64 #include "FGAircraft.h"
65 #include "FGTranslation.h"
66 #include "FGRotation.h"
67 #include "FGPosition.h"
68 #include "FGAuxiliary.h"
69 #include "FGOutput.h"
70 #include "FGConfigFile.h"
71
72 static const char *IdSrc = "$Id$";
73 static const char *IdHdr = ID_FDMEXEC;
74
75 char highint[5]  = {27, '[', '1', 'm', '\0'      };
76 char halfint[5]  = {27, '[', '2', 'm', '\0'      };
77 char normint[6]  = {27, '[', '2', '2', 'm', '\0' };
78 char reset[5]    = {27, '[', '0', 'm', '\0'      };
79 char underon[5]  = {27, '[', '4', 'm', '\0'      };
80 char underoff[6] = {27, '[', '2', '4', 'm', '\0' };
81 char fgblue[6]   = {27, '[', '3', '4', 'm', '\0' };
82 char fgcyan[6]   = {27, '[', '3', '6', 'm', '\0' };
83 char fgred[6]    = {27, '[', '3', '1', 'm', '\0' };
84 char fggreen[6]  = {27, '[', '3', '2', 'm', '\0' };
85 char fgdef[6]    = {27, '[', '3', '9', 'm', '\0' };
86
87 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88 GLOBAL DECLARATIONS
89 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
90
91 short debug_lvl;  // This describes to any interested entity the debug level
92                   // requested by setting the JSBSIM_DEBUG environment variable.
93                   // The bitmasked value choices are as follows:
94                   // a) unset: In this case (the default) JSBSim would only print
95                   //    out the normally expected messages, essentially echoing
96                   //    the config files as they are read. If the environment
97                   //    variable is not set, debug_lvl is set to 1 internally
98                   // b) 0: This requests JSBSim not to output any messages
99                   //    whatsoever.
100                   // c) 1: This value explicity requests the normal JSBSim
101                   //    startup messages
102                   // d) 2: This value asks for a message to be printed out when
103                   //    a class is instantiated
104                   // e) 4: When this value is set, a message is displayed when a
105                   //    FGModel object executes its Run() method
106                   // f) 8: When this value is set, various runtime state variables
107                   //    are printed out periodically
108                   // g) 16: When set various parameters are sanity checked and
109                   //    a message is printed out when they go out of bounds.
110
111 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
112 CLASS IMPLEMENTATION
113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
114
115 // Constructor
116
117 FGFDMExec::FGFDMExec(void)
118 {
119   Frame        = 0;
120   FirstModel   = 0;
121   Error        = 0;
122   State        = 0;
123   Atmosphere   = 0;
124   FCS          = 0;
125   Propulsion   = 0;
126   MassBalance  = 0;
127   Aerodynamics = 0;
128   Inertial     = 0;
129   Aircraft     = 0;
130   Translation  = 0;
131   Rotation     = 0;
132   Position     = 0;
133   Auxiliary    = 0;
134   Output       = 0;
135
136   terminate = false;
137   frozen = false;
138   modelLoaded = false;
139   Scripted = false;
140
141   try {
142     char* num = getenv("JSBSIM_DEBUG");
143     if (!num) debug_lvl = 1;
144     else debug_lvl = atoi(num); // set debug level
145   } catch (...) {               // if error set to 1
146     debug_lvl = 1;
147   }
148
149   if (debug_lvl > 0) {
150     cout << "\n\n     " << highint << underon << "JSBSim Flight Dynamics Model v"
151                                    << JSBSIM_VERSION << underoff << normint << endl;
152     cout << halfint << "            [cfg file spec v" << NEEDED_CFG_VERSION << "]\n\n";
153     cout << normint << "JSBSim startup beginning ...\n\n";
154   }
155
156   if (debug_lvl & 2) cout << "Instantiated: FGFDMExec" << endl;
157
158   Allocate();
159 }
160
161 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
162
163 FGFDMExec::~FGFDMExec() {
164   DeAllocate();
165   if (debug_lvl & 2) cout << "Destroyed:    FGFDMExec" << endl;
166 }
167
168 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169
170 bool FGFDMExec::Allocate(void) {
171
172   bool result=true;
173
174   Atmosphere   = new FGAtmosphere(this);
175   FCS          = new FGFCS(this);
176   Propulsion   = new FGPropulsion(this);
177   MassBalance  = new FGMassBalance(this);
178   Aerodynamics = new FGAerodynamics (this);
179   Inertial     = new FGInertial(this);
180   Aircraft     = new FGAircraft(this);
181   Translation  = new FGTranslation(this);
182   Rotation     = new FGRotation(this);
183   Position     = new FGPosition(this);
184   Auxiliary    = new FGAuxiliary(this);
185   Output       = new FGOutput(this);
186
187   State        = new FGState(this); // This must be done here, as the FGState
188                                     // class needs valid pointers to the above
189   // model classes
190
191   // Initialize models so they can communicate with each other
192
193   if (!Atmosphere->InitModel()) {
194     cerr << fgred << "Atmosphere model init failed" << fgdef << endl;
195     Error+=1;}
196   if (!FCS->InitModel())        {
197     cerr << fgred << "FCS model init failed" << fgdef << endl;
198     Error+=2;}
199   if (!Propulsion->InitModel()) {
200     cerr << fgred << "FGPropulsion model init failed" << fgdef << endl;
201     Error+=4;}
202   if (!MassBalance->InitModel()) {
203     cerr << fgred << "FGMassBalance model init failed" << fgdef << endl;
204     Error+=8;}
205   if (!Aerodynamics->InitModel()) {
206     cerr << fgred << "FGAerodynamics model init failed" << fgdef << endl;
207     Error+=16;}
208   if (!Inertial->InitModel()) {
209     cerr << fgred << "FGInertial model init failed" << fgdef << endl;
210     Error+=32;}
211   if (!Aircraft->InitModel())   {
212     cerr << fgred << "Aircraft model init failed" << fgdef << endl;
213     Error+=64;}
214   if (!Translation->InitModel()){
215     cerr << fgred << "Translation model init failed" << fgdef << endl;
216     Error+=128;}
217   if (!Rotation->InitModel())   {
218     cerr << fgred << "Rotation model init failed" << fgdef << endl;
219     Error+=256;}
220   if (!Position->InitModel())   {
221     cerr << fgred << "Position model init failed" << fgdef << endl;
222     Error+=512;}
223   if (!Auxiliary->InitModel())  {
224     cerr << fgred << "Auxiliary model init failed" << fgdef << endl;
225     Error+=1024;}
226   if (!Output->InitModel())     {
227     cerr << fgred << "Output model init failed" << fgdef << endl;
228     Error+=2048;}
229
230   if (Error > 0) result = false;
231
232   // Schedule a model. The second arg (the integer) is the pass number. For
233   // instance, the atmosphere model gets executed every fifth pass it is called
234   // by the executive. Everything else here gets executed each pass.
235
236   Schedule(Atmosphere,   1);
237   Schedule(FCS,          1);
238   Schedule(Propulsion,   1);
239   Schedule(MassBalance,  1);
240   Schedule(Aerodynamics, 1);
241   Schedule(Inertial,     1);
242   Schedule(Aircraft,     1);
243   Schedule(Rotation,     1);
244   Schedule(Translation,  1);
245   Schedule(Position,     1);
246   Schedule(Auxiliary,    1);
247   Schedule(Output,       1);
248
249   modelLoaded = false;
250
251   return result;
252 }
253
254 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255
256 bool FGFDMExec::DeAllocate(void) {
257
258   if ( Atmosphere != 0 )  delete Atmosphere;
259   if ( FCS != 0 )         delete FCS;
260   if ( Propulsion != 0)   delete Propulsion;
261   if ( MassBalance != 0)  delete MassBalance;
262   if ( Aerodynamics != 0) delete Aerodynamics;
263   if ( Inertial != 0)     delete Inertial;
264   if ( Aircraft != 0 )    delete Aircraft;
265   if ( Translation != 0 ) delete Translation;
266   if ( Rotation != 0 )    delete Rotation;
267   if ( Position != 0 )    delete Position;
268   if ( Auxiliary != 0 )   delete Auxiliary;
269   if ( Output != 0 )      delete Output;
270   if ( State != 0 )       delete State;
271
272   FirstModel  = 0L;
273   Error       = 0;
274
275   State        = 0;
276   Atmosphere   = 0;
277   FCS          = 0;
278   Propulsion   = 0;
279   MassBalance  = 0;
280   Aerodynamics = 0;
281   Inertial     = 0;
282   Aircraft     = 0;
283   Translation  = 0;
284   Rotation     = 0;
285   Position     = 0;
286   Auxiliary    = 0;
287   Output       = 0;
288
289   modelLoaded = false;
290   return modelLoaded;
291 }
292
293 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
294
295 int FGFDMExec::Schedule(FGModel* model, int rate)
296 {
297   FGModel* model_iterator;
298
299   model_iterator = FirstModel;
300
301   if (model_iterator == 0L) {                  // this is the first model
302
303     FirstModel = model;
304     FirstModel->NextModel = 0L;
305     FirstModel->SetRate(rate);
306
307   } else {                                     // subsequent model
308
309     while (model_iterator->NextModel != 0L) {
310       model_iterator = model_iterator->NextModel;
311     }
312     model_iterator->NextModel = model;
313     model_iterator->NextModel->SetRate(rate);
314
315   }
316   return 0;
317 }
318
319 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320
321 bool FGFDMExec::Run(void)
322 {
323   FGModel* model_iterator;
324
325   if (frozen) return true;
326
327   model_iterator = FirstModel;
328   if (model_iterator == 0L) return false;
329
330   if (Scripted) {
331     RunScript();
332     if (State->Getsim_time() >= EndTime) return false;
333   }
334
335   if (debug_lvl & 4)
336     cout << "================== Frame: " << Frame << "  Time: "
337          << State->Getsim_time() << endl;
338
339   while (!model_iterator->Run()) {
340     model_iterator = model_iterator->NextModel;
341     if (model_iterator == 0L) break;
342   }
343
344   Frame++;
345   State->IncrTime();
346
347   return true;
348 }
349
350 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351
352 bool FGFDMExec::RunIC(FGInitialCondition *fgic)
353 {
354   State->Suspend();
355   State->Initialize(fgic);
356   Run();
357   State->Resume();
358   return true;
359 }
360
361 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362
363 bool FGFDMExec::LoadModel(string APath, string EPath, string model)
364 {
365   bool result = false;
366
367   string aircraftCfgFileName;
368
369   AircraftPath = APath;
370   EnginePath   = EPath;
371
372 # ifndef macintosh
373   aircraftCfgFileName = AircraftPath + "/" + model + "/" + model + ".xml";
374 # else
375   aircraftCfgFileName = AircraftPath + ";" + model + ";" + model + ".xml";
376 # endif
377
378   FGConfigFile AC_cfg(aircraftCfgFileName);
379   if (!AC_cfg.IsOpen()) return false;
380
381   if (modelLoaded) {
382     DeAllocate();
383     Allocate();
384   }
385
386   result = Aircraft->Load(&AC_cfg);
387
388   if (result) {
389     modelLoaded = true;
390   } else {
391     cerr << fgred
392          << "FGFDMExec: Failed to load aircraft and/or engine model"
393          << fgdef << endl;
394   }
395
396   if (debug_lvl > 0) cout << "\n\nJSBSim startup complete\n\n";
397   return result;
398 }
399
400 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
401
402 bool FGFDMExec::LoadScript(string script)
403 {
404   FGConfigFile Script(script);
405   string token="";
406   string aircraft="";
407   string initialize="";
408   bool result=false;
409   float dt=0.0;
410   int i;
411   struct condition *newCondition;
412
413   if (!Script.IsOpen()) return false;
414
415   Script.GetNextConfigLine();
416   ScriptName = Script.GetValue("name");
417   Scripted = true;
418   if (debug_lvl > 0) cout << "Reading Script File " << ScriptName << endl;
419
420   while (Script.GetNextConfigLine() != "EOF" && Script.GetValue() != "/runscript") {
421     token = Script.GetValue();
422     if (token == "use") {
423       if ((token = Script.GetValue("aircraft")) != "") {
424         aircraft = token;
425         if (debug_lvl > 0) cout << "  Use aircraft: " << token << endl;
426       } else if ((token = Script.GetValue("initialize")) != "") {
427         initialize = token;
428         if (debug_lvl > 0) cout << "  Use reset file: " << token << endl;
429       } else {
430         cerr << "Unknown 'use' keyword: \"" << token << "\"" << endl;
431       }
432     } else if (token == "run") {
433       StartTime = strtod(Script.GetValue("start").c_str(), NULL);
434       State->Setsim_time(StartTime);
435       EndTime   = strtod(Script.GetValue("end").c_str(), NULL);
436       dt        = strtod(Script.GetValue("dt").c_str(), NULL);
437       State->Setdt(dt);
438       Script.GetNextConfigLine();
439       token = Script.GetValue();
440       while (token != "/run") {
441
442         if (token == "when") {
443           Script.GetNextConfigLine();
444           token = Script.GetValue();
445           newCondition = new struct condition();
446           while (token != "/when") {
447             if (token == "parameter") {
448               newCondition->TestParam.push_back(State->GetParameterIndex(Script.GetValue("name")));
449               newCondition->TestValue.push_back(strtod(Script.GetValue("value").c_str(), NULL));
450               newCondition->Comparison.push_back(Script.GetValue("comparison"));
451             } else if (token == "set") {
452               newCondition->SetParam.push_back(State->GetParameterIndex(Script.GetValue("name")));
453               newCondition->SetValue.push_back(strtod(Script.GetValue("value").c_str(), NULL));
454               newCondition->Triggered.push_back(false);
455               newCondition->OriginalValue.push_back(0.0);
456               newCondition->newValue.push_back(0.0);
457               newCondition->StartTime.push_back(0.0);
458               newCondition->EndTime.push_back(0.0);
459               string tempCompare = Script.GetValue("type");
460               if      (tempCompare == "FG_DELTA") newCondition->Type.push_back(FG_DELTA);
461               else if (tempCompare == "FG_BOOL")  newCondition->Type.push_back(FG_BOOL);
462               else if (tempCompare == "FG_VALUE") newCondition->Type.push_back(FG_VALUE);
463               else                                newCondition->Type.push_back((eType)0);
464               tempCompare = Script.GetValue("action");
465               if      (tempCompare == "FG_RAMP") newCondition->Action.push_back(FG_RAMP);
466               else if (tempCompare == "FG_STEP") newCondition->Action.push_back(FG_STEP);
467               else if (tempCompare == "FG_EXP")  newCondition->Action.push_back(FG_EXP);
468               else                               newCondition->Action.push_back((eAction)0);
469               
470               if (Script.GetValue("persistent") == "true")
471                 newCondition->Persistent.push_back(true);
472               else
473                 newCondition->Persistent.push_back(false);
474                 
475               newCondition->TC.push_back(strtod(Script.GetValue("tc").c_str(), NULL));
476               
477             } else {
478               cerr << "Unrecognized keyword in script file: \" [when] " << token << "\"" << endl;
479             }
480             Script.GetNextConfigLine();
481             token = Script.GetValue();
482           }
483           Conditions.push_back(*newCondition);
484           Script.GetNextConfigLine();
485           token = Script.GetValue();
486
487         } else {
488           cerr << "Error reading script file: expected \"when\", got \"" << token << "\"" << endl;
489         }
490
491       }
492     } else {
493       cerr << "Unrecognized keyword in script file: \"" << token << "\" [runscript] " << endl;
494     }
495   }
496
497   if (aircraft == "") {
498     cerr << "Aircraft file not loaded in script" << endl;
499     exit(-1);
500   }
501
502   // print out conditions for double-checking if requested
503
504   if (debug_lvl > 0) {
505     vector <struct condition>::iterator iterConditions = Conditions.begin();
506     int count=0;
507
508     cout << "\n  Script goes from " << StartTime << " to " << EndTime
509          << " with dt = " << dt << endl << endl;
510
511     while (iterConditions < Conditions.end()) {
512       cout << "  Condition: " << count++ << endl;
513       cout << "    if (";
514
515       for (i=0; i<iterConditions->TestValue.size(); i++) {
516         if (i>0) cout << " and" << endl << "        ";
517         cout << "(" << State->paramdef[iterConditions->TestParam[i]]
518                     << iterConditions->Comparison[i] << " "
519                     << iterConditions->TestValue[i] << ")";
520       }
521       cout << ") then {" << endl;
522
523       for (i=0; i<iterConditions->SetValue.size(); i++) {
524         cout << "      set" << State->paramdef[iterConditions->SetParam[i]]
525              << "to " << iterConditions->SetValue[i];
526
527         switch (iterConditions->Type[i]) {
528         case FG_VALUE:
529           cout << " (constant";
530           break;
531         case FG_DELTA:
532           cout << " (delta";
533           break;
534         case FG_BOOL:
535           cout << " (boolean";
536           break;
537         default:
538           cout << " (unspecified type";
539         }
540
541         switch (iterConditions->Action[i]) {
542         case FG_RAMP:
543           cout << " via ramp";
544           break;
545         case FG_STEP:
546           cout << " via step";
547           break;
548         case FG_EXP:
549           cout << " via exponential approach";
550           break;
551         default:
552           cout << " via unspecified action";
553         }
554
555         if (!iterConditions->Persistent[i]) cout << endl
556                            << "                              once";
557         else cout << endl
558                            << "                              repeatedly";
559
560         if (iterConditions->Action[i] == FG_RAMP ||
561             iterConditions->Action[i] == FG_EXP) cout << endl
562                            << "                              with time constant "
563                            << iterConditions->TC[i];
564       }
565       cout << ")" << endl << "    }" << endl << endl;
566
567       iterConditions++;
568     }
569
570     cout << endl;
571   }
572
573   result = LoadModel("aircraft", "engine", aircraft);
574   if (!result) {
575     cerr << "Aircraft file " << aircraft << " was not found" << endl;
576           exit(-1);
577   }
578   if ( ! State->Reset("aircraft", aircraft, initialize))
579                  State->Initialize(2000,0,0,0,0,0,0.5,0.5,40000);
580
581   return true;
582 }
583
584 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
585
586 void FGFDMExec::RunScript(void)
587 {
588   vector <struct condition>::iterator iC = Conditions.begin();
589   bool truth;
590   bool WholeTruth;
591   int i;
592
593   int count=0;
594
595   float currentTime = State->Getsim_time();
596   float newSetValue;
597
598   while (iC < Conditions.end()) {
599     // determine whether the set of conditional tests for this condition equate
600     // to true
601     for (i=0; i<iC->TestValue.size(); i++) {
602            if (iC->Comparison[i] == "lt")
603               truth = State->GetParameter(iC->TestParam[i]) <  iC->TestValue[i];
604       else if (iC->Comparison[i] == "le")
605               truth = State->GetParameter(iC->TestParam[i]) <= iC->TestValue[i];
606       else if (iC->Comparison[i] == "eq")
607               truth = State->GetParameter(iC->TestParam[i]) == iC->TestValue[i];
608       else if (iC->Comparison[i] == "ge")
609               truth = State->GetParameter(iC->TestParam[i]) >= iC->TestValue[i];
610       else if (iC->Comparison[i] == "gt")
611               truth = State->GetParameter(iC->TestParam[i]) >  iC->TestValue[i];
612       else if (iC->Comparison[i] == "ne")
613               truth = State->GetParameter(iC->TestParam[i]) != iC->TestValue[i];
614       else
615               cerr << "Bad comparison" << endl;
616
617       if (i == 0) WholeTruth = truth;
618       else        WholeTruth = WholeTruth && truth;
619
620       if (!truth && iC->Persistent[i] && iC->Triggered[i]) iC->Triggered[i] = false;
621     }
622
623     // if the conditions are true, do the setting of the desired parameters
624
625     if (WholeTruth) {
626       for (i=0; i<iC->SetValue.size(); i++) {
627         if ( ! iC->Triggered[i]) {
628           iC->OriginalValue[i] = State->GetParameter(iC->SetParam[i]);
629           switch (iC->Type[i]) {
630           case FG_VALUE:
631             iC->newValue[i] = iC->SetValue[i];
632             break;
633           case FG_DELTA:
634             iC->newValue[i] = iC->OriginalValue[i] + iC->SetValue[i];
635             break;
636           case FG_BOOL:
637             break;
638           default:
639             cerr << "Invalid Type specified" << endl;
640             break;
641           }
642           iC->Triggered[i] = true;
643           iC->StartTime[i] = currentTime;
644         }
645
646         switch (iC->Action[i]) {
647         case FG_RAMP:
648           newSetValue = (currentTime - iC->StartTime[i])/(iC->TC[i])
649                       * (iC->newValue[i] - iC->OriginalValue[i]) + iC->OriginalValue[i];
650           if (newSetValue > iC->newValue[i]) newSetValue = iC->newValue[i];
651           break;
652         case FG_STEP:
653           newSetValue = iC->newValue[i];
654           break;
655         case FG_EXP:
656           newSetValue = (1 - exp(-(currentTime - iC->StartTime[i])/(iC->TC[i])))
657               * (iC->newValue[i] - iC->OriginalValue[i]) + iC->OriginalValue[i];
658           break;
659         default:
660           cerr << "Invalid Action specified" << endl;
661           break;
662         }
663         State->SetParameter(iC->SetParam[i], newSetValue);
664       }
665     }
666     iC++;
667   }
668 }
669
670 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
671
672 void FGFDMExec::Debug(void)
673 {
674     //TODO: Add your source code here
675 }
676