JSBSim Flight Dynamics Model  1.0 (02 March 2017)
An Open Source Flight Dynamics and Control Software Library in C++
FGAerodynamics.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Module: FGAerodynamics.cpp
4  Author: Jon S. Berndt
5  Date started: 09/13/00
6  Purpose: Encapsulates the aerodynamic forces
7 
8  ------------- Copyright (C) 2000 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 HISTORY
31 --------------------------------------------------------------------------------
32 09/13/00 JSB Created
33 04/22/01 JSB Moved code into here from FGAircraft
34 
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 INCLUDES
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
38 
39 #include <iostream>
40 #include <sstream>
41 #include <iomanip>
42 #include <cstdlib>
43 
44 #include "FGFDMExec.h"
45 #include "FGAerodynamics.h"
46 #include "input_output/FGPropertyManager.h"
47 #include "input_output/FGXMLElement.h"
48 
49 using namespace std;
50 
51 namespace JSBSim {
52 
53 IDENT(IdSrc,"$Id: FGAerodynamics.cpp,v 1.60 2016/05/30 19:05:58 bcoconni Exp $");
54 IDENT(IdHdr,ID_AERODYNAMICS);
55 
56 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57 CLASS IMPLEMENTATION
58 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
59 
60 
61 FGAerodynamics::FGAerodynamics(FGFDMExec* FDMExec) : FGModel(FDMExec)
62 {
63  Name = "FGAerodynamics";
64 
65  AxisIdx["DRAG"] = 0;
66  AxisIdx["SIDE"] = 1;
67  AxisIdx["LIFT"] = 2;
68  AxisIdx["ROLL"] = 3;
69  AxisIdx["PITCH"] = 4;
70  AxisIdx["YAW"] = 5;
71 
72  AxisIdx["AXIAL"] = 0;
73  AxisIdx["NORMAL"] = 2;
74 
75  AxisIdx["X"] = 0;
76  AxisIdx["Y"] = 1;
77  AxisIdx["Z"] = 2;
78 
79  axisType = atNone;
80 
81  AeroFunctions = new AeroFunctionArray[6];
82  AeroFunctionsAtCG = new AeroFunctionArray[6];
83 
84  impending_stall = stall_hyst = 0.0;
85  alphaclmin = alphaclmax = 0.0;
86  alphaclmin0 = alphaclmax0 = 0.0;
87  alphahystmin = alphahystmax = 0.0;
88  clsq = lod = 0.0;
89  alphaw = 0.0;
90  bi2vel = ci2vel = 0.0;
91  AeroRPShift = 0;
92  vDeltaRP.InitMatrix();
93 
94  bind();
95 
96  Debug(0);
97 }
98 
99 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100 
102 {
103  unsigned int i,j;
104 
105  for (i=0; i<6; i++)
106  for (j=0; j<AeroFunctions[i].size(); j++)
107  delete AeroFunctions[i][j];
108  for (i=0; i<6; i++)
109  for (j=0; j<AeroFunctionsAtCG[i].size(); j++)
110  delete AeroFunctionsAtCG[i][j];
111 
112  delete[] AeroFunctions;
113  delete[] AeroFunctionsAtCG;
114 
115  delete AeroRPShift;
116 
117  Debug(1);
118 }
119 
120 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121 
122 bool FGAerodynamics::InitModel(void)
123 {
124  if (!FGModel::InitModel()) return false;
125 
126  impending_stall = stall_hyst = 0.0;
127  alphaclmin = alphaclmin0;
128  alphaclmax = alphaclmax0;
129  alphahystmin = alphahystmax = 0.0;
130  clsq = lod = 0.0;
131  alphaw = 0.0;
132  bi2vel = ci2vel = 0.0;
133  AeroRPShift = 0;
134  vDeltaRP.InitMatrix();
135  vForces.InitMatrix();
136  vMoments.InitMatrix();
137  return true;
138 }
139 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140 
141 bool FGAerodynamics::Run(bool Holding)
142 {
143 
144  if (FGModel::Run(Holding)) return true;
145  if (Holding) return false; // if paused don't execute
146 
147  unsigned int axis_ctr;
148  const double twovel=2*in.Vt;
149 
150  // The lift coefficient squared (property aero/cl-squared) is computed before
151  // the aero functions are called to make sure that they use the same value for
152  // qbar.
153  if ( in.Qbar > 1.0) {
154  // Skip the computation if qbar is close to zero to avoid huge values for
155  // aero/cl-squared when a non-null lift coincides with a very small aero
156  // velocity (i.e. when qbar is close to zero).
157  clsq = (vFw(eLift) + vFwAtCG(eLift))/ (in.Wingarea*in.Qbar);
158  clsq *= clsq;
159  }
160 
161  RunPreFunctions();
162 
163  // calculate some oft-used quantities for speed
164 
165  if (twovel != 0) {
166  bi2vel = in.Wingspan / twovel;
167  ci2vel = in.Wingchord / twovel;
168  }
169  alphaw = in.Alpha + in.Wingincidence;
170  qbar_area = in.Wingarea * in.Qbar;
171 
172  if (alphaclmax != 0) {
173  if (in.Alpha > 0.85*alphaclmax) {
174  impending_stall = 10*(in.Alpha/alphaclmax - 0.85);
175  } else {
176  impending_stall = 0;
177  }
178  }
179 
180  if (alphahystmax != 0.0 && alphahystmin != 0.0) {
181  if (in.Alpha > alphahystmax) {
182  stall_hyst = 1;
183  } else if (in.Alpha < alphahystmin) {
184  stall_hyst = 0;
185  }
186  }
187 
188  vFw.InitMatrix();
189  vFwAtCG.InitMatrix();
190  vFnative.InitMatrix();
191  vFnativeAtCG.InitMatrix();
192 
193  for (axis_ctr = 0; axis_ctr < 3; ++axis_ctr) {
194  AeroFunctionArray::iterator f;
195 
196  AeroFunctionArray* array = &AeroFunctions[axis_ctr];
197  for (f=array->begin(); f != array->end(); ++f) {
198  // Tell the Functions to cache values, so when the function values are
199  // being requested for output, the functions do not get calculated again
200  // in a context that might have changed, but instead use the values that
201  // have already been calculated for this frame.
202  (*f)->cacheValue(true);
203  vFnative(axis_ctr+1) += (*f)->GetValue();
204  }
205 
206  array = &AeroFunctionsAtCG[axis_ctr];
207  for (f=array->begin(); f != array->end(); ++f) {
208  (*f)->cacheValue(true); // Same as above
209  vFnativeAtCG(axis_ctr+1) += (*f)->GetValue();
210  }
211  }
212 
213  // Note that we still need to convert to wind axes here, because it is
214  // used in the L/D calculation, and we still may want to look at Lift
215  // and Drag.
216 
217  // JSB 4/27/12 - After use, convert wind axes to produce normal lift
218  // and drag values - not negative ones!
219 
220  // As a clarification, JSBSim assumes that drag and lift values are defined
221  // in wind axes - BUT with a 180 rotation about the Y axis. That is, lift and
222  // drag will be positive up and aft, respectively, so that they are reported
223  // as positive numbers. However, the wind axes themselves assume that the X
224  // and Z forces are positive forward and down.
225 
226  switch (axisType) {
227  case atBodyXYZ: // Forces already in body axes; no manipulation needed
228  vFw = in.Tb2w*vFnative;
229  vForces = vFnative;
230  vFw(eDrag)*=-1; vFw(eLift)*=-1;
231 
232  vFwAtCG = in.Tb2w*vFnativeAtCG;
233  vForcesAtCG = vFnativeAtCG;
234  vFwAtCG(eDrag)*=-1; vFwAtCG(eLift)*=-1;
235  break;
236  case atLiftDrag: // Copy forces into wind axes
237  vFw = vFnative;
238  vFw(eDrag)*=-1; vFw(eLift)*=-1;
239  vForces = in.Tw2b*vFw;
240  vFw(eDrag)*=-1; vFw(eLift)*=-1;
241 
242  vFwAtCG = vFnativeAtCG;
243  vFwAtCG(eDrag)*=-1; vFwAtCG(eLift)*=-1;
244  vForcesAtCG = in.Tw2b*vFwAtCG;
245  vFwAtCG(eDrag)*=-1; vFwAtCG(eLift)*=-1;
246  break;
247  case atAxialNormal: // Convert native forces into Axial|Normal|Side system
248  vFw = in.Tb2w*vFnative;
249  vFnative(eX)*=-1; vFnative(eZ)*=-1;
250  vForces = vFnative;
251 
252  vFwAtCG = in.Tb2w*vFnativeAtCG;
253  vFnativeAtCG(eX)*=-1; vFnativeAtCG(eZ)*=-1;
254  vForcesAtCG = vFnativeAtCG;
255  break;
256  default:
257  cerr << endl << " A proper axis type has NOT been selected. Check "
258  << "your aerodynamics definition." << endl;
259  exit(-1);
260  }
261 
262  // Calculate lift Lift over Drag
263  if ( fabs(vFw(eDrag) + vFwAtCG(eDrag)) > 0.0)
264  lod = fabs( (vFw(eLift) + vFwAtCG(eLift))/ (vFw(eDrag) + vFwAtCG(eDrag)));
265 
266  // Calculate aerodynamic reference point shift, if any. The shift
267  // takes place in the structual axis. That is, if the shift is positive,
268  // it is towards the back (tail) of the vehicle. The AeroRPShift
269  // function should be non-dimensionalized by the wing chord. The
270  // calculated vDeltaRP will be in feet.
271  if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*in.Wingchord;
272 
273  vDXYZcg(eX) = in.RPBody(eX) - vDeltaRP(eX); // vDeltaRP is given in the structural frame
274  vDXYZcg(eY) = in.RPBody(eY) + vDeltaRP(eY);
275  vDXYZcg(eZ) = in.RPBody(eZ) - vDeltaRP(eZ);
276 
277  vMomentsMRC.InitMatrix();
278 
279  for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
280  AeroFunctionArray* array = &AeroFunctions[axis_ctr+3];
281  for (AeroFunctionArray::iterator f=array->begin(); f != array->end(); ++f) {
282  // Tell the Functions to cache values, so when the function values are
283  // being requested for output, the functions do not get calculated again
284  // in a context that might have changed, but instead use the values that
285  // have already been calculated for this frame.
286  (*f)->cacheValue(true);
287  vMomentsMRC(axis_ctr+1) += (*f)->GetValue();
288  }
289  }
290  vMoments = vMomentsMRC + vDXYZcg*vForces; // M = r X F
291  // Now add the "at CG" values to base forces - after the moments have been transferred
292  vForces += vForcesAtCG;
293  vFnative += vFnativeAtCG;
294  vFw += vFwAtCG;
295 
296  RunPostFunctions();
297 
298  return false;
299 }
300 
301 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
302 
304 {
305  string axis;
306  string scratch_unit="";
307  Element *temp_element, *axis_element, *function_element;
308 
309  Name = "Aerodynamics Model: " + document->GetAttributeValue("name");
310 
311  // Perform base class Pre-Load
312  if (!FGModel::Load(document))
313  return false;
314 
315  DetermineAxisSystem(document); // Determine if Lift/Side/Drag, etc. is used.
316 
317  Debug(2);
318 
319  if ((temp_element = document->FindElement("alphalimits"))) {
320  scratch_unit = temp_element->GetAttributeValue("unit");
321  if (scratch_unit.empty()) scratch_unit = "RAD";
322  alphaclmin0 = temp_element->FindElementValueAsNumberConvertFromTo("min", scratch_unit, "RAD");
323  alphaclmax0 = temp_element->FindElementValueAsNumberConvertFromTo("max", scratch_unit, "RAD");
324  alphaclmin = alphaclmin0;
325  alphaclmax = alphaclmax0;
326  }
327 
328  if ((temp_element = document->FindElement("hysteresis_limits"))) {
329  scratch_unit = temp_element->GetAttributeValue("unit");
330  if (scratch_unit.empty()) scratch_unit = "RAD";
331  alphahystmin = temp_element->FindElementValueAsNumberConvertFromTo("min", scratch_unit, "RAD");
332  alphahystmax = temp_element->FindElementValueAsNumberConvertFromTo("max", scratch_unit, "RAD");
333  }
334 
335  if ((temp_element = document->FindElement("aero_ref_pt_shift_x"))) {
336  function_element = temp_element->FindElement("function");
337  AeroRPShift = new FGFunction(PropertyManager, function_element);
338  }
339 
340  axis_element = document->FindElement("axis");
341  while (axis_element) {
342  AeroFunctionArray ca;
343  AeroFunctionArray ca_atCG;
344  axis = axis_element->GetAttributeValue("name");
345  function_element = axis_element->FindElement("function");
346  while (function_element) {
347  string current_func_name = function_element->GetAttributeValue("name");
348  bool apply_at_cg = false;
349  if (function_element->HasAttribute("apply_at_cg")) {
350  if (function_element->GetAttributeValue("apply_at_cg") == "true") apply_at_cg = true;
351  }
352  if (!apply_at_cg) {
353  try {
354  ca.push_back( new FGFunction(PropertyManager, function_element) );
355  } catch (const string& str) {
356  cerr << endl << fgred << "Error loading aerodynamic function in "
357  << current_func_name << ":" << str << " Aborting." << reset << endl;
358  return false;
359  }
360  } else {
361  try {
362  ca_atCG.push_back( new FGFunction(PropertyManager, function_element) );
363  } catch (const string& str) {
364  cerr << endl << fgred << "Error loading aerodynamic function in "
365  << current_func_name << ":" << str << " Aborting." << reset << endl;
366  return false;
367  }
368  }
369  function_element = axis_element->FindNextElement("function");
370  }
371  AeroFunctions[AxisIdx[axis]] = ca;
372  AeroFunctionsAtCG[AxisIdx[axis]] = ca_atCG;
373  axis_element = document->FindNextElement("axis");
374  }
375 
376  PostLoad(document, PropertyManager); // Perform base class Post-Load
377 
378  return true;
379 }
380 
381 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382 //
383 // This private class function checks to verify consistency in the choice of
384 // aerodynamic axes used in the config file. One set of LIFT|DRAG|SIDE, or
385 // X|Y|Z, or AXIAL|NORMAL|SIDE must be chosen; mixed system axes are not allowed.
386 // Note that if the "SIDE" axis specifier is entered first in a config file,
387 // a warning message will be given IF the AXIAL|NORMAL specifiers are also given.
388 // This is OK, and the warning is due to the SIDE specifier used for both
389 // the Lift/Drag and Axial/Normal axis systems.
390 
391 void FGAerodynamics::DetermineAxisSystem(Element* document)
392 {
393  Element* axis_element = document->FindElement("axis");
394  string axis;
395  while (axis_element) {
396  axis = axis_element->GetAttributeValue("name");
397  if (axis == "LIFT" || axis == "DRAG") {
398  if (axisType == atNone) axisType = atLiftDrag;
399  else if (axisType != atLiftDrag) {
400  cerr << endl << " Mixed aerodynamic axis systems have been used in the"
401  << " aircraft config file. (LIFT DRAG)" << endl;
402  }
403  } else if (axis == "SIDE") {
404  if (axisType != atNone && axisType != atLiftDrag && axisType != atAxialNormal) {
405  cerr << endl << " Mixed aerodynamic axis systems have been used in the"
406  << " aircraft config file. (SIDE)" << endl;
407  }
408  } else if (axis == "AXIAL" || axis == "NORMAL") {
409  if (axisType == atNone) axisType = atAxialNormal;
410  else if (axisType != atAxialNormal) {
411  cerr << endl << " Mixed aerodynamic axis systems have been used in the"
412  << " aircraft config file. (NORMAL AXIAL)" << endl;
413  }
414  } else if (axis == "X" || axis == "Y" || axis == "Z") {
415  if (axisType == atNone) axisType = atBodyXYZ;
416  else if (axisType != atBodyXYZ) {
417  cerr << endl << " Mixed aerodynamic axis systems have been used in the"
418  << " aircraft config file. (XYZ)" << endl;
419  }
420  } else if (axis != "ROLL" && axis != "PITCH" && axis != "YAW") { // error
421  cerr << endl << " An unknown axis type, " << axis << " has been specified"
422  << " in the aircraft configuration file." << endl;
423  exit(-1);
424  }
425  axis_element = document->FindNextElement("axis");
426  }
427  if (axisType == atNone) {
428  axisType = atLiftDrag;
429  cerr << endl << " The aerodynamic axis system has been set by default"
430  << " to the Lift/Side/Drag system." << endl;
431  }
432 }
433 
434 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435 
436 string FGAerodynamics::GetAeroFunctionStrings(const string& delimeter) const
437 {
438  string AeroFunctionStrings = "";
439  bool firstime = true;
440  unsigned int axis, sd;
441 
442  for (axis = 0; axis < 6; axis++) {
443  for (sd = 0; sd < AeroFunctions[axis].size(); sd++) {
444  if (firstime) {
445  firstime = false;
446  } else {
447  AeroFunctionStrings += delimeter;
448  }
449  AeroFunctionStrings += AeroFunctions[axis][sd]->GetName();
450  }
451  }
452 
453  string FunctionStrings = FGModelFunctions::GetFunctionStrings(delimeter);
454 
455  if (FunctionStrings.size() > 0) {
456  if (AeroFunctionStrings.size() > 0) {
457  AeroFunctionStrings += delimeter + FunctionStrings;
458  } else {
459  AeroFunctionStrings = FunctionStrings;
460  }
461  }
462 
463  return AeroFunctionStrings;
464 }
465 
466 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467 
468 string FGAerodynamics::GetAeroFunctionValues(const string& delimeter) const
469 {
470  ostringstream buf;
471 
472  for (unsigned int axis = 0; axis < 6; axis++) {
473  for (unsigned int sd = 0; sd < AeroFunctions[axis].size(); sd++) {
474  if (buf.tellp() > 0) buf << delimeter;
475  buf << AeroFunctions[axis][sd]->GetValue();
476  }
477  }
478 
479  string FunctionValues = FGModelFunctions::GetFunctionValues(delimeter);
480 
481  if (FunctionValues.size() > 0) {
482  if (buf.str().size() > 0) {
483  buf << delimeter << FunctionValues;
484  } else {
485  buf << FunctionValues;
486  }
487  }
488 
489  return buf.str();
490 }
491 
492 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493 
494 void FGAerodynamics::bind(void)
495 {
496  typedef double (FGAerodynamics::*PMF)(int) const;
497 
498  PropertyManager->Tie("forces/fbx-aero-lbs", this, 1, (PMF)&FGAerodynamics::GetForces);
499  PropertyManager->Tie("forces/fby-aero-lbs", this, 2, (PMF)&FGAerodynamics::GetForces);
500  PropertyManager->Tie("forces/fbz-aero-lbs", this, 3, (PMF)&FGAerodynamics::GetForces);
501  PropertyManager->Tie("moments/l-aero-lbsft", this, 1, (PMF)&FGAerodynamics::GetMoments);
502  PropertyManager->Tie("moments/m-aero-lbsft", this, 2, (PMF)&FGAerodynamics::GetMoments);
503  PropertyManager->Tie("moments/n-aero-lbsft", this, 3, (PMF)&FGAerodynamics::GetMoments);
504  PropertyManager->Tie("forces/fwx-aero-lbs", this, 1, (PMF)&FGAerodynamics::GetvFw);
505  PropertyManager->Tie("forces/fwy-aero-lbs", this, 2, (PMF)&FGAerodynamics::GetvFw);
506  PropertyManager->Tie("forces/fwz-aero-lbs", this, 3, (PMF)&FGAerodynamics::GetvFw);
507  PropertyManager->Tie("forces/lod-norm", this, &FGAerodynamics::GetLoD);
508  PropertyManager->Tie("aero/cl-squared", this, &FGAerodynamics::GetClSquared);
509  PropertyManager->Tie("aero/qbar-area", &qbar_area);
510  PropertyManager->Tie("aero/alpha-max-rad", this, &FGAerodynamics::GetAlphaCLMax, &FGAerodynamics::SetAlphaCLMax, true);
511  PropertyManager->Tie("aero/alpha-min-rad", this, &FGAerodynamics::GetAlphaCLMin, &FGAerodynamics::SetAlphaCLMin, true);
512  PropertyManager->Tie("aero/bi2vel", this, &FGAerodynamics::GetBI2Vel);
513  PropertyManager->Tie("aero/ci2vel", this, &FGAerodynamics::GetCI2Vel);
514  PropertyManager->Tie("aero/alpha-wing-rad", this, &FGAerodynamics::GetAlphaW);
515  PropertyManager->Tie("systems/stall-warn-norm", this, &FGAerodynamics::GetStallWarn);
516  PropertyManager->Tie("aero/stall-hyst-norm", this, &FGAerodynamics::GetHysteresisParm);
517 }
518 
519 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520 // The bitmasked value choices are as follows:
521 // unset: In this case (the default) JSBSim would only print
522 // out the normally expected messages, essentially echoing
523 // the config files as they are read. If the environment
524 // variable is not set, debug_lvl is set to 1 internally
525 // 0: This requests JSBSim not to output any messages
526 // whatsoever.
527 // 1: This value explicity requests the normal JSBSim
528 // startup messages
529 // 2: This value asks for a message to be printed out when
530 // a class is instantiated
531 // 4: When this value is set, a message is displayed when a
532 // FGModel object executes its Run() method
533 // 8: When this value is set, various runtime state variables
534 // are printed out periodically
535 // 16: When set various parameters are sanity checked and
536 // a message is printed out when they go out of bounds
537 
538 void FGAerodynamics::Debug(int from)
539 {
540  if (debug_lvl <= 0) return;
541 
542  if (debug_lvl & 1) { // Standard console startup message output
543  if (from == 2) { // Loader
544  switch (axisType) {
545  case (atLiftDrag):
546  cout << endl << " Aerodynamics (Lift|Side|Drag axes):" << endl << endl;
547  break;
548  case (atAxialNormal):
549  cout << endl << " Aerodynamics (Axial|Side|Normal axes):" << endl << endl;
550  break;
551  case (atBodyXYZ):
552  cout << endl << " Aerodynamics (X|Y|Z axes):" << endl << endl;
553  break;
554  case (atNone):
555  cout << endl << " Aerodynamics (undefined axes):" << endl << endl;
556  break;
557  }
558  }
559  }
560  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
561  if (from == 0) cout << "Instantiated: FGAerodynamics" << endl;
562  if (from == 1) cout << "Destroyed: FGAerodynamics" << endl;
563  }
564  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
565  }
566  if (debug_lvl & 8 ) { // Runtime state variables
567  }
568  if (debug_lvl & 16) { // Sanity checking
569  }
570  if (debug_lvl & 64) {
571  if (from == 0) { // Constructor
572  cout << IdSrc << endl;
573  cout << IdHdr << endl;
574  }
575  }
576 }
577 
578 } // namespace JSBSim
double GetLoD(void) const
Retrieves the lift over drag ratio.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
bool HasAttribute(const std::string &key)
Determines if an element has the supplied attribute.
Definition: FGXMLElement.h:162
std::string GetAeroFunctionValues(const std::string &delimeter) const
Gets the aero function values.
static char reset[5]
resets text properties
Definition: FGJSBBase.h:131
Encapsulates the aerodynamic calculations.
STL namespace.
Element * FindElement(const std::string &el="")
Searches for a specified element.
double FindElementValueAsNumberConvertFromTo(const std::string &el, const std::string &supplied_units, const std::string &target_units)
Searches for the named element and converts and returns the data belonging to it. ...
std::string GetFunctionStrings(const std::string &delimeter) const
Gets the strings for the current set of functions.
double GetValue(void) const
Retrieves the value of the function object.
Definition: FGFunction.cpp:364
const FGColumnVector3 & GetvFw(void) const
Retrieves the aerodynamic forces in the wind axes.
static char fgred[6]
red text
Definition: FGJSBBase.h:141
virtual bool Run(bool Holding)
Runs the model; called by the Executive.
Definition: FGModel.cpp:92
double GetClSquared(void) const
Retrieves the square of the lift coefficient.
void Tie(const std::string &name, bool *pointer, bool useDefault=true)
Tie a property to an external bool variable.
const FGColumnVector3 & GetForces(void) const
Gets the total aerodynamic force vector.
std::string GetAeroFunctionStrings(const std::string &delimeter) const
Gets the strings for the current set of aero functions.
Base class for all scheduled JSBSim models.
Definition: FGModel.h:74
Represents a mathematical function.
Definition: FGFunction.h:699
~FGAerodynamics()
Destructor.
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
Encapsulates the JSBSim simulation executive.
Definition: FGFDMExec.h:189
virtual bool Load(Element *el)
Loads this model.
Definition: FGModel.cpp:113
bool Load(Element *element)
Loads the Aerodynamics model.
std::string GetFunctionValues(const std::string &delimeter) const
Gets the function values.
bool Run(bool Holding)
Runs the Aerodynamics model; called by the Executive Can pass in a value indicating if the executive ...
const FGColumnVector3 & GetMoments(void) const
Gets the total aerodynamic moment vector about the CG.