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