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