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