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