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