]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/math/FGFunction.cpp
Improve timing statistics
[flightgear.git] / src / FDM / JSBSim / math / FGFunction.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Module: FGFunction.cpp
4 Author: Jon Berndt
5 Date started: 8/25/2004
6 Purpose: Stores various parameter types for functions
7
8  ------------- Copyright (C) 2004  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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
28 INCLUDES
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
30
31 #include <sstream>
32 #include <iomanip>
33 #include <cstdlib>
34 #include <cmath>
35 #include "FGFunction.h"
36 #include "FGTable.h"
37 #include "FGPropertyValue.h"
38 #include "FGRealValue.h"
39 #include "input_output/FGXMLElement.h"
40 #include "input_output/FGPropertyManager.h"
41
42 using namespace std;
43
44 namespace JSBSim {
45
46 static const char *IdSrc = "$Id: FGFunction.cpp,v 1.35 2010/08/28 12:41:56 jberndt Exp $";
47 static const char *IdHdr = ID_FUNCTION;
48
49 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
50 CLASS IMPLEMENTATION
51 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
52
53 FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& prefix)
54                                       : PropertyManager(propMan), Prefix(prefix)
55 {
56   Element* element;
57   string operation, property_name;
58   cached = false;
59   cachedValue = -HUGE_VAL;
60   invlog2val = 1.0/log10(2.0);
61
62   property_string = "property";
63   value_string = "value";
64   table_string = "table";
65   p_string = "p";
66   v_string = "v";
67   t_string = "t";
68
69   function_string = "function";
70   description_string = "description";
71   sum_string = "sum";
72   difference_string = "difference";
73   product_string = "product";
74   quotient_string = "quotient";
75   pow_string = "pow";
76   exp_string = "exp";
77   log2_string = "log2";
78   ln_string = "ln";
79   log10_string = "log10";
80   abs_string = "abs";
81   sin_string = "sin";
82   cos_string = "cos";
83   tan_string = "tan";
84   asin_string = "asin";
85   acos_string = "acos";
86   atan_string = "atan";
87   atan2_string = "atan2";
88   min_string = "min";
89   max_string = "max";
90   avg_string = "avg";
91   fraction_string = "fraction";
92   mod_string = "mod";
93   random_string = "random";
94   integer_string = "integer";
95
96   Name = el->GetAttributeValue("name");
97   operation = el->GetName();
98
99   if (operation == function_string) {
100     Type = eTopLevel;
101   } else if (operation == product_string) {
102     Type = eProduct;
103   } else if (operation == difference_string) {
104     Type = eDifference;
105   } else if (operation == sum_string) {
106     Type = eSum;
107   } else if (operation == quotient_string) {
108     Type = eQuotient;
109   } else if (operation == pow_string) {
110     Type = ePow;
111   } else if (operation == log2_string) {
112     Type = eLog2;
113   } else if (operation == ln_string) {
114     Type = eLn;
115   } else if (operation == log10_string) {
116     Type = eLog10;
117   } else if (operation == abs_string) {
118     Type = eAbs;
119   } else if (operation == sin_string) {
120     Type = eSin;
121   } else if (operation == exp_string) {
122     Type = eExp;
123   } else if (operation == cos_string) {
124     Type = eCos;
125   } else if (operation == tan_string) {
126     Type = eTan;
127   } else if (operation == asin_string) {
128     Type = eASin;
129   } else if (operation == acos_string) {
130     Type = eACos;
131   } else if (operation == atan_string) {
132     Type = eATan;
133   } else if (operation == atan2_string) {
134     Type = eATan2;
135   } else if (operation == min_string) {
136     Type = eMin;
137   } else if (operation == max_string) {
138     Type = eMax;
139   } else if (operation == avg_string) {
140     Type = eAvg;
141   } else if (operation == fraction_string) {
142     Type = eFrac;
143   } else if (operation == integer_string) {
144     Type = eInteger;
145   } else if (operation == mod_string) {
146     Type = eMod;
147   } else if (operation == random_string) {
148     Type = eRandom;
149   } else if (operation != description_string) {
150     cerr << "Bad operation " << operation << " detected in configuration file" << endl;
151   }
152
153   element = el->GetElement();
154   if (!element) {
155     cerr << fgred << highint << endl;
156     cerr << "  No element was specified as an argument to the \"" << operation << "\" operation" << endl;
157     cerr << "  This can happen when, for instance, a cos operation is specified and a " << endl;
158     cerr << "  property name is given explicitly, but is not placed within a" << endl;
159     cerr << "  <property></property> element tag pair." << endl;
160     cerr << reset;
161     exit(-2);
162   }
163   
164   while (element) {
165     operation = element->GetName();
166
167     // data types
168     if (operation == property_string || operation == p_string) {
169       property_name = element->GetDataLine();
170       if (property_name.find("#") != string::npos) {
171         if (is_number(Prefix)) {
172           property_name = replace(property_name,"#",Prefix);
173         }
174       }
175       FGPropertyManager* newNode = 0L;
176       if (PropertyManager->HasNode(property_name)) {
177         newNode = PropertyManager->GetNode(property_name);
178         Parameters.push_back(new FGPropertyValue( newNode ));
179       } else {
180         cerr << fgcyan << "The property " + property_name + " is initially undefined."
181              << reset << endl;
182         Parameters.push_back(new FGPropertyValue( property_name ));
183       }
184     } else if (operation == value_string || operation == v_string) {
185       Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
186     } else if (operation == table_string || operation == t_string) {
187       Parameters.push_back(new FGTable(PropertyManager, element));
188     // operations
189     } else if (operation == product_string ||
190                operation == difference_string ||
191                operation == sum_string ||
192                operation == quotient_string ||
193                operation == pow_string ||
194                operation == exp_string ||
195                operation == log2_string ||
196                operation == ln_string ||
197                operation == log10_string ||
198                operation == abs_string ||
199                operation == sin_string ||
200                operation == cos_string ||
201                operation == tan_string ||
202                operation == asin_string ||
203                operation == acos_string ||
204                operation == atan_string ||
205                operation == atan2_string ||
206                operation == min_string ||
207                operation == max_string ||
208                operation == fraction_string ||
209                operation == integer_string ||
210                operation == mod_string ||
211                operation == random_string ||
212                operation == avg_string )
213     {
214       Parameters.push_back(new FGFunction(PropertyManager, element, Prefix));
215     } else if (operation != description_string) {
216       cerr << "Bad operation " << operation << " detected in configuration file" << endl;
217     }
218     element = el->GetNextElement();
219   }
220
221   bind(); // Allow any function to save its value
222
223   Debug(0);
224 }
225
226 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227
228 FGFunction::~FGFunction(void)
229 {
230   for (unsigned int i=0; i<Parameters.size(); i++) delete Parameters[i];
231 }
232
233 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234
235 void FGFunction::cacheValue(bool cache)
236 {
237   cached = false; // Must set cached to false prior to calling GetValue(), else
238                   // it will _never_ calculate the value;
239   if (cache) {
240     cachedValue = GetValue();
241     cached = true;
242   }
243 }
244
245 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
246
247 double FGFunction::GetValue(void) const
248 {
249   unsigned int i;
250   double scratch;
251   double temp=0;
252
253   if (cached) return cachedValue;
254
255   try {
256     temp = Parameters[0]->GetValue();
257   } catch (string prop) {
258     if (PropertyManager->HasNode(prop)) {
259       ((FGPropertyValue*)Parameters[0])->SetNode(PropertyManager->GetNode(prop));
260       temp = Parameters[0]->GetValue();
261     } else {
262       throw("Property " + prop + " was not defined anywhere.");
263     }
264   }
265
266   switch (Type) {
267   case eTopLevel:
268     break;
269   case eProduct:
270     for (i=1;i<Parameters.size();i++) {
271       temp *= Parameters[i]->GetValue();
272     }
273     break;
274   case eDifference:
275     for (i=1;i<Parameters.size();i++) {
276       temp -= Parameters[i]->GetValue();
277     }
278     break;
279   case eSum:
280     for (i=1;i<Parameters.size();i++) {
281       temp += Parameters[i]->GetValue();
282     }
283     break;
284   case eQuotient:
285     if (Parameters[1]->GetValue() != 0.0)
286       temp /= Parameters[1]->GetValue();
287     else
288       temp = HUGE_VAL;
289     break;
290   case ePow:
291     temp = pow(temp,Parameters[1]->GetValue());
292     break;
293   case eExp:
294     temp = exp(temp);
295     break;
296   case eLog2:
297     if (temp > 0.00) temp = log10(temp)*invlog2val;
298     else temp = -HUGE_VAL;
299     break;
300   case eLn:
301     if (temp > 0.00) temp = log(temp);
302     else temp = -HUGE_VAL;
303     break;
304   case eLog10:
305     if (temp > 0.00) temp = log10(temp);
306     else temp = -HUGE_VAL;
307     break;
308   case eAbs:
309     temp = fabs(temp);
310     break;
311   case eSin:
312     temp = sin(temp);
313     break;
314   case eCos:
315     temp = cos(temp);
316     break;
317   case eTan:
318     temp = tan(temp);
319     break;
320   case eACos:
321     temp = acos(temp);
322     break;
323   case eASin:
324     temp = asin(temp);
325     break;
326   case eATan:
327     temp = atan(temp);
328     break;
329   case eATan2:
330     temp = atan2(temp, Parameters[1]->GetValue());
331     break;
332   case eMod:
333     temp = ((int)temp) % ((int) Parameters[1]->GetValue());
334     break;
335   case eMin:
336     for (i=1;i<Parameters.size();i++) {
337       if (Parameters[i]->GetValue() < temp) temp = Parameters[i]->GetValue();
338     }    
339     break;
340   case eMax:
341     for (i=1;i<Parameters.size();i++) {
342       if (Parameters[i]->GetValue() > temp) temp = Parameters[i]->GetValue();
343     }    
344     break;
345   case eAvg:
346     for (i=1;i<Parameters.size();i++) {
347       temp += Parameters[i]->GetValue();
348     }
349     temp /= Parameters.size();
350     break;
351   case eFrac:
352     temp = modf(temp, &scratch);
353     break;
354   case eInteger:
355     modf(temp, &scratch);
356     temp = scratch;
357     break;
358   case eRandom:
359     temp = GaussianRandomNumber();
360     break;
361   default:
362     cerr << "Unknown function operation type" << endl;
363     break;
364   }
365
366   return temp;
367 }
368
369 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370
371 string FGFunction::GetValueAsString(void) const
372 {
373   ostringstream buffer;
374
375   buffer << setw(9) << setprecision(6) << GetValue();
376   return buffer.str();
377 }
378
379 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380
381 void FGFunction::bind(void)
382 {
383   if ( !Name.empty() ) {
384     string tmp;
385     if (Prefix.empty())
386       tmp  = PropertyManager->mkPropertyName(Name, false);
387     else {
388       if (is_number(Prefix)) {
389         if (Name.find("#") != string::npos) { // if "#" is found
390           Name = replace(Name,"#",Prefix);
391           tmp  = PropertyManager->mkPropertyName(Name, false);
392         } else {
393           cerr << "Malformed function name with number: " << Prefix
394             << " and property name: " << Name
395             << " but no \"#\" sign for substitution." << endl;
396         }
397       } else {
398         tmp  = PropertyManager->mkPropertyName(Prefix + "/" + Name, false);
399       }
400     }
401
402     PropertyManager->Tie( tmp, this, &FGFunction::GetValue);
403   }
404 }
405
406 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407 //    The bitmasked value choices are as follows:
408 //    unset: In this case (the default) JSBSim would only print
409 //       out the normally expected messages, essentially echoing
410 //       the config files as they are read. If the environment
411 //       variable is not set, debug_lvl is set to 1 internally
412 //    0: This requests JSBSim not to output any messages
413 //       whatsoever.
414 //    1: This value explicity requests the normal JSBSim
415 //       startup messages
416 //    2: This value asks for a message to be printed out when
417 //       a class is instantiated
418 //    4: When this value is set, a message is displayed when a
419 //       FGModel object executes its Run() method
420 //    8: When this value is set, various runtime state variables
421 //       are printed out periodically
422 //    16: When set various parameters are sanity checked and
423 //       a message is printed out when they go out of bounds
424
425 void FGFunction::Debug(int from)
426 {
427   if (debug_lvl <= 0) return;
428
429   if (debug_lvl & 1) { // Standard console startup message output
430     if (from == 0) { // Constructor
431       if (Type == eTopLevel)
432         cout << "    Function: " << Name << endl;
433     }
434   }
435   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
436     if (from == 0) cout << "Instantiated: FGFunction" << endl;
437     if (from == 1) cout << "Destroyed:    FGFunction" << endl;
438   }
439   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
440   }
441   if (debug_lvl & 8 ) { // Runtime state variables
442   }
443   if (debug_lvl & 16) { // Sanity checking
444   }
445   if (debug_lvl & 64) {
446     if (from == 0) { // Constructor
447       cout << IdSrc << endl;
448       cout << IdHdr << endl;
449     }
450   }
451 }
452
453 }