]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/input_output/FGScript.cpp
Merge branch 'next' of git://gitorious.org/fg/flightgear
[flightgear.git] / src / FDM / JSBSim / input_output / FGScript.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Module:       FGScript.cpp
4  Author:       Jon S. Berndt
5  Date started: 12/21/01
6  Purpose:      Loads and runs JSBSim scripts.
7
8  ------------- Copyright (C) 1999  Jon S. Berndt (jon@jsbsim.org) -------------
9
10  This program is free software; you can redistribute it and/or modify it under
11  the terms of the GNU Lesser General Public License as published by the Free Software
12  Foundation; either version 2 of the License, or (at your option) any later
13  version.
14
15  This program is distributed in the hope that it will be useful, but WITHOUT
16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
18  details.
19
20  You should have received a copy of the GNU Lesser General Public License along with
21  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22  Place - Suite 330, Boston, MA  02111-1307, USA.
23
24  Further information about the GNU Lesser General Public License can also be found on
25  the world wide web at http://www.gnu.org.
26
27 FUNCTIONAL DESCRIPTION
28 --------------------------------------------------------------------------------
29
30 This class wraps up the simulation scripting routines.
31
32 HISTORY
33 --------------------------------------------------------------------------------
34 12/21/01   JSB   Created
35
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 COMMENTS, REFERENCES,  and NOTES
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39
40 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41 INCLUDES
42 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
43
44 #include "FGScript.h"
45 #include "input_output/FGXMLElement.h"
46 #include "input_output/FGXMLParse.h"
47 #include "initialization/FGTrim.h"
48
49 #include <iostream>
50 #include <cstdlib>
51 #include <iomanip>
52
53 using namespace std;
54
55 namespace JSBSim {
56
57 static const char *IdSrc = "$Id: FGScript.cpp,v 1.46 2011/02/18 12:44:16 jberndt Exp $";
58 static const char *IdHdr = ID_FGSCRIPT;
59
60 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61 GLOBAL DECLARATIONS
62 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
63
64 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65 CLASS IMPLEMENTATION
66 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
67
68 // Constructor
69
70 FGScript::FGScript(FGFDMExec* fgex) : FDMExec(fgex)
71 {
72   PropertyManager=FDMExec->GetPropertyManager();
73
74   Debug(0);
75 }
76
77 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78
79 FGScript::~FGScript()
80 {
81   unsigned int i, j;
82
83   for (i=0; i<local_properties.size(); i++) {
84     delete local_properties[i]->value;
85     delete local_properties[i];
86   }
87   local_properties.clear();
88
89   for (i=0; i<Events.size(); i++) {
90     delete Events[i].Condition;
91     for (j=0; j<Events[i].Functions.size(); j++)
92       delete Events[i].Functions[j];
93   }
94   Events.clear();
95
96   Debug(1);
97 }
98
99 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100
101 bool FGScript::LoadScript(string script, double deltaT)
102 {
103   string aircraft="", initialize="", comparison = "", prop_name="";
104   string notifyPropertyName="";
105   Element *element=0, *run_element=0, *event_element=0;
106   Element *condition_element=0, *set_element=0, *delay_element=0;
107   Element *notify_element = 0L, *notify_property_element = 0L;
108   Element *property_element = 0L;
109   Element *output_element = 0L;
110   Element *input_element = 0L;
111   bool result = false;
112   double dt = 0.0, value = 0.0;
113   struct event *newEvent;
114   FGCondition *newCondition;
115
116   document = LoadXMLDocument(script);
117
118   if (!document) {
119     cerr << "File: " << script << " could not be loaded." << endl;
120     return false;
121   }
122
123   // Set up input and output files if specified
124   
125   output_element = document->FindElement("output");
126   input_element = document->FindElement("input");
127
128   if (document->GetName() != string("runscript")) {
129     cerr << "File: " << script << " is not a script file" << endl;
130     return false;
131   }
132
133   ScriptName = document->GetAttributeValue("name");
134
135  // First, find "run" element and set delta T
136
137   run_element = document->FindElement("run");
138
139   if (!run_element) {
140     cerr << "No \"run\" element found in script." << endl;
141     return false;
142   }
143
144   // Set sim timing
145
146   StartTime = run_element->GetAttributeValueAsNumber("start");
147   FDMExec->Setsim_time(StartTime);
148   EndTime   = run_element->GetAttributeValueAsNumber("end");
149   // Make sure that the desired time is reached and executed.
150   EndTime += 0.99*FDMExec->GetDeltaT();
151
152   if (deltaT == 0.0)
153     dt = run_element->GetAttributeValueAsNumber("dt");
154   else {
155     dt = deltaT;
156     cout << endl << "Overriding simulation step size from the command line. New step size is: "
157          << deltaT << " seconds (" << 1/deltaT << " Hz)" << endl << endl;
158   }
159
160   FDMExec->Setdt(dt);
161   
162   // read aircraft and initialization files
163
164   element = document->FindElement("use");
165   if (element) {
166     aircraft = element->GetAttributeValue("aircraft");
167     if (!aircraft.empty()) {
168       result = FDMExec->LoadModel(aircraft);
169       if (!result) return false;
170     } else {
171       cerr << "Aircraft must be specified in use element." << endl;
172       return false;
173     }
174
175     initialize = element->GetAttributeValue("initialize");
176     if (initialize.empty()) {
177       cerr << "Initialization file must be specified in use element." << endl;
178       return false;
179     }
180
181   } else {
182     cerr << "No \"use\" directives in the script file." << endl;
183     return false;
184   }
185
186   // Now, read input spec if given.
187   if (input_element > 0) {
188     FDMExec->GetInput()->Load(input_element);
189   }
190
191   // Now, read output spec if given.
192   if (output_element > 0) {
193     string output_file = output_element->GetAttributeValue("file");
194     if (output_file.empty()) {
195       cerr << "No logging directives file was specified." << endl;
196     } else {
197       if (!FDMExec->SetOutputDirectives(output_file)) return false;
198     }
199   }
200
201   // Read local property/value declarations
202   property_element = run_element->FindElement("property");
203   while (property_element) {
204
205     double value=0.0;
206     string title="";
207
208     title = property_element->GetDataLine();
209     if ( ! property_element->GetAttributeValue("value").empty())
210       value = property_element->GetAttributeValueAsNumber("value");
211
212     LocalProps *localProp = new LocalProps(value);
213     localProp->title = title;
214     local_properties.push_back(localProp);
215     if (PropertyManager->HasNode(title)) {
216       PropertyManager->GetNode(title)->setDoubleValue(value);
217     } else {
218       PropertyManager->Tie(localProp->title, localProp->value);
219     }
220     property_element = run_element->FindNextElement("property");
221   }
222
223   // Read "events" from script
224
225   event_element = run_element->FindElement("event");
226   while (event_element) { // event processing
227
228     // Create the event structure
229     newEvent = new struct event();
230
231     // Retrieve the event name if given
232     newEvent->Name = event_element->GetAttributeValue("name");
233
234     // Is this event persistent? That is, does it execute every time the
235     // condition triggers to true, or does it execute as a one-shot event, only?
236     if (event_element->GetAttributeValue("persistent") == string("true")) {
237       newEvent->Persistent = true;
238     }
239
240     // Does this event execute continuously when triggered to true?
241     if (event_element->GetAttributeValue("continuous") == string("true")) {
242       newEvent->Continuous = true;
243     }
244
245     // Process the conditions
246     condition_element = event_element->FindElement("condition");
247     if (condition_element != 0) {
248       try {
249         newCondition = new FGCondition(condition_element, PropertyManager);
250       } catch(string str) {
251         cout << endl << fgred << str << reset << endl << endl;
252         delete newEvent;
253         return false;
254       }
255       newEvent->Condition = newCondition;
256     } else {
257       cerr << "No condition specified in script event " << newEvent->Name << endl;
258       delete newEvent;
259       return false;
260     }
261
262     // Is there a delay between the time this event is triggered, and when the event
263     // actions are executed?
264
265     delay_element = event_element->FindElement("delay");
266     if (delay_element) newEvent->Delay = event_element->FindElementValueAsNumber("delay");
267     else newEvent->Delay = 0.0;
268
269     // Notify about when this event is triggered?
270     if ((notify_element = event_element->FindElement("notify")) != 0) {
271       newEvent->Notify = true;
272       // Check here for new <description> tag that gets echoed
273       string notify_description = notify_element->FindElementValue("description");
274       if (!notify_description.empty()) {
275         newEvent->Description = notify_description;
276       }
277       notify_property_element = notify_element->FindElement("property");
278       while (notify_property_element) {
279         notifyPropertyName = notify_property_element->GetDataLine();
280         if (PropertyManager->GetNode(notifyPropertyName)) {
281           newEvent->NotifyProperties.push_back( PropertyManager->GetNode(notifyPropertyName) );
282           string caption_attribute = notify_property_element->GetAttributeValue("caption");
283           if (caption_attribute.empty()) {
284             newEvent->DisplayString.push_back(notifyPropertyName);
285           } else {
286             newEvent->DisplayString.push_back(caption_attribute);
287           }
288         } else {
289           cout << endl << fgred << "  Could not find the property named "
290                << notifyPropertyName << " in script" << endl << "  \""
291                << ScriptName << "\". Execution is aborted. Please recheck "
292                << "your input files and scripts." << reset << endl;
293           delete newEvent->Condition;
294           delete newEvent;
295           return false;
296         }
297         notify_property_element = notify_element->FindNextElement("property");
298       }
299     }
300
301     // Read set definitions (these define the actions to be taken when the event is triggered).
302     set_element = event_element->FindElement("set");
303     while (set_element) {
304       prop_name = set_element->GetAttributeValue("name");
305       newEvent->SetParam.push_back( PropertyManager->GetNode(prop_name) );
306       //Todo - should probably do some safety checking here to make sure one or the other
307       //of value or function is specified.
308       if (!set_element->GetAttributeValue("value").empty()) {
309         value = set_element->GetAttributeValueAsNumber("value");
310         newEvent->Functions.push_back((FGFunction*)0L);
311       } else if (set_element->FindElement("function")) {
312         value = 0.0;
313         newEvent->Functions.push_back(new FGFunction(PropertyManager, set_element->FindElement("function")));
314       }
315       newEvent->SetValue.push_back(value);
316       newEvent->OriginalValue.push_back(0.0);
317       newEvent->newValue.push_back(0.0);
318       newEvent->ValueSpan.push_back(0.0);
319       string tempCompare = set_element->GetAttributeValue("type");
320       if      (to_lower(tempCompare).find("delta") != string::npos) newEvent->Type.push_back(FG_DELTA);
321       else if (to_lower(tempCompare).find("bool") != string::npos)  newEvent->Type.push_back(FG_BOOL);
322       else if (to_lower(tempCompare).find("value") != string::npos) newEvent->Type.push_back(FG_VALUE);
323       else                                newEvent->Type.push_back(FG_VALUE); // DEFAULT
324       tempCompare = set_element->GetAttributeValue("action");
325       if      (to_lower(tempCompare).find("ramp") != string::npos) newEvent->Action.push_back(FG_RAMP);
326       else if (to_lower(tempCompare).find("step") != string::npos) newEvent->Action.push_back(FG_STEP);
327       else if (to_lower(tempCompare).find("exp") != string::npos) newEvent->Action.push_back(FG_EXP);
328       else                               newEvent->Action.push_back(FG_STEP); // DEFAULT
329
330       if (!set_element->GetAttributeValue("tc").empty())
331         newEvent->TC.push_back(set_element->GetAttributeValueAsNumber("tc"));
332       else
333         newEvent->TC.push_back(1.0); // DEFAULT
334
335       newEvent->Transiting.push_back(false);
336
337       set_element = event_element->FindNextElement("set");
338     }
339     Events.push_back(*newEvent);
340     delete newEvent;
341
342     event_element = run_element->FindNextElement("event");
343   }
344
345   Debug(4);
346
347   FGInitialCondition *IC=FDMExec->GetIC();
348   if ( ! IC->Load( initialize )) {
349     cerr << "Initialization unsuccessful" << endl;
350     exit(-1);
351   }
352
353   return true;
354 }
355
356 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357
358 bool FGScript::RunScript(void)
359 {
360   unsigned i, j;
361   unsigned event_ctr = 0;
362
363   double currentTime = FDMExec->GetSimTime();
364   double newSetValue = 0;
365
366   if (currentTime > EndTime) return false;
367
368   // Iterate over all events.
369   for (unsigned int ev_ctr=0; ev_ctr < Events.size(); ev_ctr++) {
370     // Determine whether the set of conditional tests for this condition equate
371     // to true and should cause the event to execute. If the conditions evaluate 
372     // to true, then the event is triggered. If the event is not persistent,
373     // then this trigger will remain set true. If the event is persistent,
374     // the trigger will reset to false when the condition evaluates to false.
375     if (Events[ev_ctr].Condition->Evaluate()) {
376       if (!Events[ev_ctr].Triggered) {
377
378         // The conditions are true, do the setting of the desired Event parameters
379         for (i=0; i<Events[ev_ctr].SetValue.size(); i++) {
380           Events[ev_ctr].OriginalValue[i] = Events[ev_ctr].SetParam[i]->getDoubleValue();
381           if (Events[ev_ctr].Functions[i] != 0) { // Parameter should be set to a function value
382             Events[ev_ctr].SetValue[i] = Events[ev_ctr].Functions[i]->GetValue();
383           }
384           switch (Events[ev_ctr].Type[i]) {
385           case FG_VALUE:
386           case FG_BOOL:
387             Events[ev_ctr].newValue[i] = Events[ev_ctr].SetValue[i];
388             break;
389           case FG_DELTA:
390             Events[ev_ctr].newValue[i] = Events[ev_ctr].OriginalValue[i] + Events[ev_ctr].SetValue[i];
391             break;
392           default:
393             cerr << "Invalid Type specified" << endl;
394             break;
395           }
396           Events[ev_ctr].StartTime = currentTime + Events[ev_ctr].Delay;
397           Events[ev_ctr].ValueSpan[i] = Events[ev_ctr].newValue[i] - Events[ev_ctr].OriginalValue[i];
398           Events[ev_ctr].Transiting[i] = true;
399         }
400       }
401       Events[ev_ctr].Triggered = true;
402
403     } else if (Events[ev_ctr].Persistent) { // If the event is persistent, reset the trigger.
404       Events[ev_ctr].Triggered = false; // Reset the trigger for persistent events
405       Events[ev_ctr].Notified = false;  // Also reset the notification flag
406     } else if (Events[ev_ctr].Continuous) { // If the event is continuous, reset the trigger.
407       Events[ev_ctr].Triggered = false; // Reset the trigger for persistent events
408       Events[ev_ctr].Notified = false;  // Also reset the notification flag
409     }
410
411     if ((currentTime >= Events[ev_ctr].StartTime) && Events[ev_ctr].Triggered) {
412
413       for (i=0; i<Events[ev_ctr].SetValue.size(); i++) {
414         if (Events[ev_ctr].Transiting[i]) {
415           Events[ev_ctr].TimeSpan = currentTime - Events[ev_ctr].StartTime;
416           switch (Events[ev_ctr].Action[i]) {
417           case FG_RAMP:
418             if (Events[ev_ctr].TimeSpan <= Events[ev_ctr].TC[i]) {
419               newSetValue = Events[ev_ctr].TimeSpan/Events[ev_ctr].TC[i] * Events[ev_ctr].ValueSpan[i] + Events[ev_ctr].OriginalValue[i];
420             } else {
421               newSetValue = Events[ev_ctr].newValue[i];
422               if (Events[ev_ctr].Continuous != true) Events[ev_ctr].Transiting[i] = false;
423             }
424             break;
425           case FG_STEP:
426             newSetValue = Events[ev_ctr].newValue[i];
427
428             // If this is not a continuous event, reset the transiting flag.
429             // Otherwise, it is known that the event is a continuous event.
430             // Furthermore, if the event is to be determined by a function,
431             // then the function will be continuously calculated.
432             if (Events[ev_ctr].Continuous != true)
433               Events[ev_ctr].Transiting[i] = false;
434             else if (Events[ev_ctr].Functions[i] != 0)
435               newSetValue = Events[ev_ctr].Functions[i]->GetValue();
436
437             break;
438           case FG_EXP:
439             newSetValue = (1 - exp( -Events[ev_ctr].TimeSpan/Events[ev_ctr].TC[i] )) * Events[ev_ctr].ValueSpan[i] + Events[ev_ctr].OriginalValue[i];
440             break;
441           default:
442             cerr << "Invalid Action specified" << endl;
443             break;
444           }
445           Events[ev_ctr].SetParam[i]->setDoubleValue(newSetValue);
446         }
447       }
448
449       // Print notification values after setting them
450       if (Events[ev_ctr].Notify && !Events[ev_ctr].Notified) {
451         cout << endl << "  Event " << event_ctr << " (" << Events[ev_ctr].Name << ")"
452              << " executed at time: " << currentTime << endl;
453         if (!Events[ev_ctr].Description.empty()) {
454           cout << "    " << Events[ev_ctr].Description << endl;
455         }
456         for (j=0; j<Events[ev_ctr].NotifyProperties.size();j++) {
457 //          cout << "    " << Events[ev_ctr].NotifyProperties[j]->GetRelativeName()
458           cout << "    " << Events[ev_ctr].DisplayString[j]
459                << " = " << Events[ev_ctr].NotifyProperties[j]->getDoubleValue() << endl;
460         }
461         cout << endl;
462         Events[ev_ctr].Notified = true;
463       }
464
465     }
466
467     event_ctr++;
468   }
469   return true;
470 }
471
472 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473 //    The bitmasked value choices are as follows:
474 //    unset: In this case (the default) JSBSim would only print
475 //       out the normally expected messages, essentially echoing
476 //       the config files as they are read. If the environment
477 //       variable is not set, debug_lvl is set to 1 internally
478 //    0: This requests JSBSim not to output any messages
479 //       whatsoever.
480 //    1: This value explicity requests the normal JSBSim
481 //       startup messages
482 //    2: This value asks for a message to be printed out when
483 //       a class is instantiated
484 //    4: When this value is set, a message is displayed when a
485 //       FGModel object executes its Run() method
486 //    8: When this value is set, various runtime state variables
487 //       are printed out periodically
488 //    16: When set various parameters are sanity checked and
489 //       a message is printed out when they go out of bounds
490
491 void FGScript::Debug(int from)
492 {
493   if (debug_lvl <= 0) return;
494
495   if (debug_lvl & 1) { // Standard console startup message output
496     if (from == 0) { // Constructor
497     } else if (from == 3) {
498     } else if (from == 4)  { // print out script data
499       cout << endl;
500       cout << "Script: \"" << ScriptName << "\"" << endl;
501       cout << "  begins at " << StartTime << " seconds and runs to " << EndTime
502         << " seconds with dt = " << setprecision(6) << FDMExec->GetDeltaT() << " (" <<
503         ceil(1.0/FDMExec->GetDeltaT()) << " Hz)" << endl;
504       cout << endl;
505
506       for (unsigned int i=0; i<local_properties.size(); i++) {
507         cout << "Local property: " << local_properties[i]->title 
508              << " = " << PropertyManager->GetNode(local_properties[i]->title)->getDoubleValue()
509              << endl;
510       }
511       
512       if (local_properties.size() > 0) cout << endl;
513
514       for (unsigned i=0; i<Events.size(); i++) {
515         cout << "Event " << i;
516         if (!Events[i].Name.empty()) cout << " (" << Events[i].Name << ")";
517         cout << ":" << endl;
518
519         if (Events[i].Persistent)
520           cout << "  " << "Whenever triggered, executes once";
521         else if (Events[i].Continuous)
522           cout << "  " << "While true, always executes";
523         else
524           cout << "  " << "When first triggered, executes once";
525
526         Events[i].Condition->PrintCondition();
527
528         cout << endl << "  Actions taken";
529         if (Events[i].Delay > 0.0)
530           cout << " (after a delay of " << Events[i].Delay << " secs)";
531         cout << ":" << endl << "    {";
532         for (unsigned j=0; j<Events[i].SetValue.size(); j++) {
533           if (Events[i].SetValue[j] == 0.0 && Events[i].Functions[j] != 0L) {
534             if (Events[i].SetParam[j] == 0) {
535               cerr << fgred << highint << endl
536                    << "  An attempt has been made to access a non-existent property" << endl
537                    << "  in this event. Please check the property names used, spelling, etc."
538                    << reset << endl;
539               exit(-1);
540             }
541             cout << endl << "      set " << Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
542                  << " to function value";
543           } else {
544             if (Events[i].SetParam[j] == 0) {
545               cerr << fgred << highint << endl
546                    << "  An attempt has been made to access a non-existent property" << endl
547                    << "  in this event. Please check the property names used, spelling, etc."
548                    << reset << endl;
549               exit(-1);
550             }
551             cout << endl << "      set " << Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
552                  << " to " << Events[i].SetValue[j];
553           }
554
555           switch (Events[i].Type[j]) {
556           case FG_VALUE:
557           case FG_BOOL:
558             cout << " (constant";
559             break;
560           case FG_DELTA:
561             cout << " (delta";
562             break;
563           default:
564             cout << " (unspecified type";
565           }
566
567           switch (Events[i].Action[j]) {
568           case FG_RAMP:
569             cout << " via ramp";
570             break;
571           case FG_STEP:
572             cout << " via step)";
573             break;
574           case FG_EXP:
575             cout << " via exponential approach";
576             break;
577           default:
578             cout << " via unspecified action)";
579           }
580
581           if (Events[i].Action[j] == FG_RAMP || Events[i].Action[j] == FG_EXP)
582             cout << " with time constant " << Events[i].TC[j] << ")";
583         }
584         cout << endl << "    }" << endl;
585
586         // Print notifications
587         if (Events[i].Notify) {
588           if (Events[i].NotifyProperties.size() > 0) {
589             cout << "  Notifications" << ":" << endl << "    {" << endl;
590             for (unsigned j=0; j<Events[i].NotifyProperties.size();j++) {
591               cout << "      "
592                    << Events[i].NotifyProperties[j]->GetRelativeName("/fdm/jsbsim/")
593                    << endl;
594             }
595             cout << "    }" << endl;
596           }
597         }
598         cout << endl;
599       }
600     }
601   }
602   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
603     if (from == 0) cout << "Instantiated: FGScript" << endl;
604     if (from == 1) cout << "Destroyed:    FGScript" << endl;
605   }
606   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
607   }
608   if (debug_lvl & 8 ) { // Runtime state variables
609   }
610   if (debug_lvl & 16) { // Sanity checking
611   }
612   if (debug_lvl & 64) {
613     if (from == 0) { // Constructor
614       cout << IdSrc << endl;
615       cout << IdHdr << endl;
616     }
617   }
618 }
619 }