JSBSim Flight Dynamics Model  1.1.11 (13 Feb 2022)
An Open Source Flight Dynamics and Control Software Library in C++
FGTank.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Module: FGTank.cpp
4  Author: Jon Berndt
5  Date started: 01/21/99
6  Called by: FGAircraft
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
12  Software Foundation; either version 2 of the License, or (at your option) any
13  later 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
21  with this program; if not, write to the Free Software Foundation, Inc., 59
22  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24  Further information about the GNU Lesser General Public License can also be
25  found on the world wide web at http://www.gnu.org.
26 
27 FUNCTIONAL DESCRIPTION
28 --------------------------------------------------------------------------------
29 See header file.
30 
31 HISTORY
32 --------------------------------------------------------------------------------
33 01/21/99 JSB Created
34 
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 INCLUDES
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
38 
39 #include "FGTank.h"
40 #include "FGFDMExec.h"
41 #include "input_output/FGXMLElement.h"
42 
43 using namespace std;
44 
45 namespace JSBSim {
46 
47 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
48 CLASS IMPLEMENTATION
49 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
50 
51 FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
52  : TankNumber(tank_number)
53 {
54  string token, strFuelName;
55  Element* element;
56  Element* element_Grain;
57  FGPropertyManager *PropertyManager = exec->GetPropertyManager();
58  Area = 1.0;
59  Density = 6.6;
60  InitialTemperature = Temperature = -9999.0;
61  Ixx = Iyy = Izz = 0.0;
62  InertiaFactor = 1.0;
63  Radius = Contents = Standpipe = Length = InnerRadius = 0.0;
64  ExternalFlow = 0.0;
65  InitialStandpipe = 0.0;
66  Capacity = 0.00001; UnusableVol = 0.0;
67  Priority = InitialPriority = 1;
68  vXYZ.InitMatrix();
69  vXYZ_drain.InitMatrix();
70  ixx_unit = iyy_unit = izz_unit = 1.0;
71  grainType = gtUNKNOWN; // This is the default
72 
73  type = el->GetAttributeValue("type");
74  if (type == "FUEL") Type = ttFUEL;
75  else if (type == "OXIDIZER") Type = ttOXIDIZER;
76  else Type = ttUNKNOWN;
77 
78  element = el->FindElement("location");
79  if (element) vXYZ = element->FindElementTripletConvertTo("IN");
80  else cerr << el->ReadFrom() << "No location found for this tank."
81  << endl;
82 
83  vXYZ_drain = vXYZ; // Set initial drain location to initial tank CG
84 
85  element = el->FindElement("drain_location");
86  if (element) {
87  vXYZ_drain = element->FindElementTripletConvertTo("IN");
88  }
89 
90  if (el->FindElement("radius"))
91  Radius = el->FindElementValueAsNumberConvertTo("radius", "IN");
92  if (el->FindElement("inertia_factor"))
93  InertiaFactor = el->FindElementValueAsNumber("inertia_factor");
94  if (el->FindElement("capacity"))
95  Capacity = el->FindElementValueAsNumberConvertTo("capacity", "LBS");
96  if (el->FindElement("contents"))
97  InitialContents = Contents = el->FindElementValueAsNumberConvertTo("contents", "LBS");
98  if (el->FindElement("unusable-volume"))
99  UnusableVol = el->FindElementValueAsNumberConvertTo("unusable-volume", "GAL");
100  if (el->FindElement("temperature"))
101  InitialTemperature = Temperature = el->FindElementValueAsNumber("temperature");
102  if (el->FindElement("standpipe"))
103  InitialStandpipe = Standpipe = el->FindElementValueAsNumberConvertTo("standpipe", "LBS");
104  if (el->FindElement("priority"))
105  InitialPriority = Priority = (int)el->FindElementValueAsNumber("priority");
106  if (el->FindElement("density"))
107  Density = el->FindElementValueAsNumberConvertTo("density", "LBS/GAL");
108  if (el->FindElement("type"))
109  strFuelName = el->FindElementValue("type");
110 
111 
112  SetPriority( InitialPriority ); // this will also set the Selected flag
113 
114  if (Capacity == 0) {
115  cerr << el->ReadFrom()
116  << "Tank capacity must not be zero. Reset to 0.00001 lbs!" << endl;
117  Capacity = 0.00001;
118  Contents = 0.0;
119  }
120  if (Capacity <= GetUnusable()) {
121  cerr << el->ReadFrom() << "Tank capacity (" << Capacity
122  << " lbs) is lower than the amount of unusable fuel (" << GetUnusable()
123  << " lbs) for tank " << tank_number
124  << "! Did you accidentally swap unusable and capacity?" << endl;
125  throw("tank definition error");
126  }
127  if (Contents > Capacity) {
128  cerr << el->ReadFrom() << "Tank content (" << Contents
129  << " lbs) is greater than tank capacity (" << Capacity
130  << " lbs) for tank " << tank_number
131  << "! Did you accidentally swap contents and capacity?" << endl;
132  throw("tank definition error");
133  }
134  if (Contents < GetUnusable()) {
135  cerr << el->ReadFrom() << "Tank content (" << Contents
136  << " lbs) is lower than the amount of unusable fuel (" << GetUnusable()
137  << " lbs) for tank " << tank_number << endl;
138  }
139 
140  PctFull = 100.0*Contents/Capacity; // percent full; 0 to 100.0
141 
142  // Check whether this is a solid propellant "tank". Initialize it if true.
143 
144  element_Grain = el->FindElement("grain_config");
145  if (element_Grain) {
146 
147  strGType = element_Grain->GetAttributeValue("type");
148  if (strGType == "CYLINDRICAL") grainType = gtCYLINDRICAL;
149  else if (strGType == "ENDBURNING") grainType = gtENDBURNING;
150  else if (strGType == "FUNCTION") {
151  grainType = gtFUNCTION;
152  if (element_Grain->FindElement("ixx") != 0) {
153  Element* element_ixx = element_Grain->FindElement("ixx");
154  if (element_ixx->GetAttributeValue("unit") == "KG*M2") ixx_unit = 1.0/1.35594;
155  if (element_ixx->FindElement("function") != 0) {
156  function_ixx = new FGFunction(exec, element_ixx->FindElement("function"));
157  }
158  } else {
159  throw("For tank "+to_string(TankNumber)+" and when grain_config is specified an ixx must be specified when the FUNCTION grain type is specified.");
160  }
161 
162  if (element_Grain->FindElement("iyy")) {
163  Element* element_iyy = element_Grain->FindElement("iyy");
164  if (element_iyy->GetAttributeValue("unit") == "KG*M2") iyy_unit = 1.0/1.35594;
165  if (element_iyy->FindElement("function") != 0) {
166  function_iyy = new FGFunction(exec, element_iyy->FindElement("function"));
167  }
168  } else {
169  throw("For tank "+to_string(TankNumber)+" and when grain_config is specified an iyy must be specified when the FUNCTION grain type is specified.");
170  }
171 
172  if (element_Grain->FindElement("izz")) {
173  Element* element_izz = element_Grain->FindElement("izz");
174  if (element_izz->GetAttributeValue("unit") == "KG*M2") izz_unit = 1.0/1.35594;
175  if (element_izz->FindElement("function") != 0) {
176  function_izz = new FGFunction(exec, element_izz->FindElement("function"));
177  }
178  } else {
179  throw("For tank "+to_string(TankNumber)+" and when grain_config is specified an izz must be specified when the FUNCTION grain type is specified.");
180  }
181  }
182  else
183  cerr << el->ReadFrom() << "Unknown propellant grain type specified"
184  << endl;
185 
186  if (element_Grain->FindElement("length"))
187  Length = element_Grain->FindElementValueAsNumberConvertTo("length", "IN");
188  if (element_Grain->FindElement("bore_diameter"))
189  InnerRadius = element_Grain->FindElementValueAsNumberConvertTo("bore_diameter", "IN")/2.0;
190 
191  // Initialize solid propellant values for debug and runtime use.
192 
193  switch (grainType) {
194  case gtCYLINDRICAL:
195  if (Radius <= InnerRadius) {
196  const string s("The bore diameter should be smaller than the total grain diameter!");
197  cerr << element_Grain->ReadFrom() << endl << s << endl;
198  throw BaseException(s);
199  }
200  Volume = M_PI * Length * (Radius*Radius - InnerRadius*InnerRadius); // cubic inches
201  break;
202  case gtENDBURNING:
203  Volume = M_PI * Length * Radius * Radius; // cubic inches
204  break;
205  case gtFUNCTION:
206  Volume = 1; // Volume is irrelevant for the FUNCTION type, but it can't be zero!
207  break;
208  case gtUNKNOWN:
209  {
210  const string s("Unknown grain type found in this rocket engine definition.");
211  cerr << el->ReadFrom() << endl << s << endl;
212  throw BaseException(s);
213  }
214  }
215  Density = (Capacity*lbtoslug)/Volume; // slugs/in^3
216  }
217 
218  CalculateInertias();
219 
220  if (Temperature != -9999.0) InitialTemperature = Temperature = FahrenheitToCelsius(Temperature);
221  Area = 40.0 * pow(Capacity/1975, 0.666666667);
222 
223  // A named fuel type will override a previous density value
224  if (!strFuelName.empty()) Density = ProcessFuelName(strFuelName);
225 
226  bind(PropertyManager);
227 
228  Debug(0);
229 }
230 
231 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232 
234 {
235  Debug(1);
236 }
237 
238 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 
241 {
242  SetTemperature( InitialTemperature );
243  SetStandpipe ( InitialStandpipe );
244  SetContents ( InitialContents );
245  PctFull = 100.0*Contents/Capacity;
246  SetPriority( InitialPriority );
247  CalculateInertias();
248 }
249 
250 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251 
252 FGColumnVector3 FGTank::GetXYZ(void) const
253 {
254  return vXYZ_drain + (Contents/Capacity)*(vXYZ - vXYZ_drain);
255 }
256 
257 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258 
259 double FGTank::GetXYZ(int idx) const
260 {
261  return vXYZ_drain(idx) + (Contents/Capacity)*(vXYZ(idx)-vXYZ_drain(idx));
262 }
263 
264 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265 
266 double FGTank::Drain(double used)
267 {
268  double remaining = Contents - used;
269 
270  if (remaining >= GetUnusable()) { // Reduce contents by amount used.
271  Contents -= used;
272  } else { // This tank must be empty.
273  if (Contents > GetUnusable())
274  Contents = GetUnusable();
275 
276  remaining = Contents;
277  }
278 
279  PctFull = 100.0*Contents/Capacity;
280  CalculateInertias();
281 
282  return remaining;
283 }
284 
285 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 
287 double FGTank::Fill(double amount)
288 {
289  double overage = 0.0;
290 
291  Contents += amount;
292 
293  if (Contents > Capacity) {
294  overage = Contents - Capacity;
295  Contents = Capacity;
296  PctFull = 100.0;
297  } else {
298  PctFull = Contents/Capacity*100.0;
299  }
300 
301  CalculateInertias();
302 
303  return overage;
304 }
305 
306 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
307 
308 void FGTank::SetContents(double amount)
309 {
310  Contents = amount;
311  if (Contents > Capacity) {
312  Contents = Capacity;
313  PctFull = 100.0;
314  } else {
315  PctFull = Contents/Capacity*100.0;
316  }
317 
318  CalculateInertias();
319 }
320 
321 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322 
323 void FGTank::SetContentsGallons(double gallons)
324 {
325  SetContents(gallons * Density);
326 }
327 
328 
329 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330 
331 double FGTank::Calculate(double dt, double TAT_C)
332 {
333  if(ExternalFlow < 0.) Drain( -ExternalFlow *dt);
334  else Fill(ExternalFlow * dt);
335 
336  if (Temperature == -9999.0) return 0.0;
337  double HeatCapacity = 900.0; // Joules/lbm/C
338  double TempFlowFactor = 1.115; // Watts/sqft/C
339  double Tdiff = TAT_C - Temperature;
340  double dTemp = 0.0; // Temp change due to one surface
341  if (fabs(Tdiff) > 0.1 && Contents > 0.01) {
342  dTemp = (TempFlowFactor * Area * Tdiff * dt) / (Contents * HeatCapacity);
343  }
344 
345  return Temperature += (dTemp + dTemp); // For now, assume upper/lower the same
346 }
347 
348 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
349 // This function calculates the moments of inertia for a solid propellant
350 // grain - either an end burning cylindrical grain or a bored cylindrical
351 // grain, as well as liquid propellants IF a tank radius and inertia factor
352 // are given.
353 //
354 // From NASA CR-383, the MoI of a tank with liquid propellant is specified
355 // for baffled and non-baffled tanks as a ratio compared to that in which the
356 // propellant is solid. The more baffles, the more "rigid" the propellant and
357 // the higher the ratio (up to 1.0). For a cube tank with five baffles, the
358 // ratio ranges from 0.5 to 0.7. For a cube tank with no baffles, the ratio is
359 // roughly 0.18. One might estimate that for a spherical tank with no baffles
360 // the ratio might be somewhere around 0.10 to 0.15. Cylindrical tanks with or
361 // without baffles might have biased moment of inertia effects based on the
362 // baffle layout and tank geometry. A vector inertia_factor may be supported
363 // at some point.
364 
365 void FGTank::CalculateInertias(void)
366 {
367  double Mass = Contents*lbtoslug;
368  double RadSumSqr;
369  double Rad2 = Radius*Radius;
370 
371  if (grainType != gtUNKNOWN) { // assume solid propellant
372 
373  if (Density > 0.0) {
374  Volume = (Contents*lbtoslug)/Density; // in^3
375  } else if (Contents <= 0.0) {
376  Volume = 0;
377  } else {
378  const string s(" Solid propellant grain density is zero!");
379  cerr << endl << s << endl;
380  throw BaseException(s);
381  }
382 
383  switch (grainType) {
384  case gtCYLINDRICAL:
385  InnerRadius = sqrt(Rad2 - Volume/(M_PI * Length));
386  RadSumSqr = (Rad2 + InnerRadius*InnerRadius)/144.0;
387  Ixx = 0.5*Mass*RadSumSqr;
388  Iyy = Mass*(3.0*RadSumSqr + Length*Length/144.0)/12.0;
389  Izz = Iyy;
390  break;
391  case gtENDBURNING:
392  Length = Volume/(M_PI*Rad2);
393  Ixx = 0.5*Mass*Rad2/144.0;
394  Iyy = Mass*(3.0*Rad2 + Length*Length)/(144.0*12.0);
395  Izz = Iyy;
396  break;
397  case gtFUNCTION:
398  Ixx = function_ixx->GetValue()*ixx_unit;
399  Iyy = function_iyy->GetValue()*iyy_unit;
400  Izz = function_izz->GetValue()*izz_unit;
401  break;
402  default:
403  {
404  const string s("Unknown grain type found.");
405  cerr << s << endl;
406  throw BaseException(s);
407  }
408  }
409 
410  } else { // assume liquid propellant: shrinking snowball
411 
412  if (Radius > 0.0) Ixx = Iyy = Izz = Mass * InertiaFactor * 0.4 * Radius * Radius / 144.0;
413 
414  }
415 }
416 
417 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
418 
419 double FGTank::ProcessFuelName(const std::string& name)
420 {
421  if (name == "AVGAS") return 6.02;
422  else if (name == "JET-A") return 6.74;
423  else if (name == "JET-A1") return 6.74;
424  else if (name == "JET-B") return 6.48;
425  else if (name == "JP-1") return 6.76;
426  else if (name == "JP-2") return 6.38;
427  else if (name == "JP-3") return 6.34;
428  else if (name == "JP-4") return 6.48;
429  else if (name == "JP-5") return 6.81;
430  else if (name == "JP-6") return 6.55;
431  else if (name == "JP-7") return 6.61;
432  else if (name == "JP-8") return 6.66;
433  else if (name == "JP-8+100") return 6.66;
434  //else if (name == "JP-9") return 6.74;
435  //else if (name == "JPTS") return 6.74;
436  else if (name == "RP-1") return 6.73;
437  else if (name == "T-1") return 6.88;
438  else if (name == "ETHANOL") return 6.58;
439  else if (name == "HYDRAZINE")return 8.61;
440  else if (name == "F-34") return 6.66;
441  else if (name == "F-35") return 6.74;
442  else if (name == "F-40") return 6.48;
443  else if (name == "F-44") return 6.81;
444  else if (name == "AVTAG") return 6.48;
445  else if (name == "AVCAT") return 6.81;
446  else {
447  cerr << "Unknown fuel type specified: "<< name << endl;
448  }
449 
450  return 6.6;
451 }
452 
453 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
454 
455 void FGTank::bind(FGPropertyManager* PropertyManager)
456 {
457  string property_name, base_property_name;
458  base_property_name = CreateIndexedPropertyName("propulsion/tank", TankNumber);
459  property_name = base_property_name + "/contents-lbs";
460  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetContents,
461  &FGTank::SetContents );
462  property_name = base_property_name + "/unusable-volume-gal";
463  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetUnusableVolume,
465  property_name = base_property_name + "/pct-full";
466  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetPctFull);
467  property_name = base_property_name + "/density-lbs_per_gal";
468  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetDensity);
469 
470  property_name = base_property_name + "/priority";
471  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetPriority,
472  &FGTank::SetPriority );
473  property_name = base_property_name + "/external-flow-rate-pps";
474  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetExternalFlow,
475  &FGTank::SetExternalFlow );
476  property_name = base_property_name + "/local-ixx-slug_ft2";
477  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetIxx);
478  property_name = base_property_name + "/local-iyy-slug_ft2";
479  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetIyy);
480  property_name = base_property_name + "/local-izz-slug_ft2";
481  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetIzz);
482 
483  property_name = base_property_name + "/x-position";
484  PropertyManager->Tie(property_name.c_str(), (FGTank*)this, &FGTank::GetLocationX, &FGTank::SetLocationX);
485  property_name = base_property_name + "/y-position";
486  PropertyManager->Tie(property_name.c_str(), (FGTank*)this, &FGTank::GetLocationY, &FGTank::SetLocationY);
487  property_name = base_property_name + "/z-position";
488  PropertyManager->Tie(property_name.c_str(), (FGTank*)this, &FGTank::GetLocationZ, &FGTank::SetLocationZ);
489 
490 }
491 
492 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493 // The bitmasked value choices are as follows:
494 // unset: In this case (the default) JSBSim would only print
495 // out the normally expected messages, essentially echoing
496 // the config files as they are read. If the environment
497 // variable is not set, debug_lvl is set to 1 internally
498 // 0: This requests JSBSim not to output any messages
499 // whatsoever.
500 // 1: This value explicity requests the normal JSBSim
501 // startup messages
502 // 2: This value asks for a message to be printed out when
503 // a class is instantiated
504 // 4: When this value is set, a message is displayed when a
505 // FGModel object executes its Run() method
506 // 8: When this value is set, various runtime state variables
507 // are printed out periodically
508 // 16: When set various parameters are sanity checked and
509 // a message is printed out when they go out of bounds
510 
511 void FGTank::Debug(int from)
512 {
513  if (debug_lvl <= 0) return;
514 
515  if (debug_lvl & 1) { // Standard console startup message output
516  if (from == 0) { // Constructor
517  cout << " " << type << " tank holds " << Capacity << " lbs. " << type << endl;
518  cout << " currently at " << PctFull << "% of maximum capacity" << endl;
519  cout << " Tank location (X, Y, Z): " << vXYZ(eX) << ", " << vXYZ(eY) << ", " << vXYZ(eZ) << endl;
520  cout << " Effective radius: " << Radius << " inches" << endl;
521  cout << " Initial temperature: " << Temperature << " Fahrenheit" << endl;
522  cout << " Priority: " << Priority << endl;
523  }
524  }
525  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
526  if (from == 0) cout << "Instantiated: FGTank" << endl;
527  if (from == 1) cout << "Destroyed: FGTank" << endl;
528  }
529  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
530  }
531  if (debug_lvl & 8 ) { // Runtime state variables
532  }
533  if (debug_lvl & 16) { // Sanity checking
534  }
535  if (debug_lvl & 64) {
536  if (from == 0) { // Constructor
537  }
538  }
539 }
540 }
JSBSim::FGFDMExec
Encapsulates the JSBSim simulation executive.
Definition: FGFDMExec.h:185
JSBSim::FGJSBBase::FahrenheitToCelsius
static constexpr double FahrenheitToCelsius(double fahrenheit)
Converts from degrees Fahrenheit to degrees Celsius.
Definition: FGJSBBase.h:230
JSBSim::FGTank::SetUnusableVolume
void SetUnusableVolume(double volume)
Sets the volume of unusable fuel in the tank.
Definition: FGTank.h:294
JSBSim::FGTank::GetContents
double GetContents(void) const
Gets the contents of the tank.
Definition: FGTank.h:260
JSBSim::FGFunction
Represents a mathematical function.
Definition: FGFunction.h:752
JSBSim::FGColumnVector3
This class implements a 3 element column vector.
Definition: FGColumnVector3.h:63
JSBSim::FGTank::Calculate
double Calculate(double dt, double TempC)
Performs local, tanks-specific calculations, such as fuel temperature.
Definition: FGTank.cpp:331
JSBSim::Element::GetAttributeValue
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
Definition: FGXMLElement.cpp:260
JSBSim::FGTank::GetUnusable
double GetUnusable(void) const
Returns the amount of unusable fuel in the tank.
Definition: FGTank.h:286
JSBSim::Element::FindElement
Element * FindElement(const std::string &el="")
Searches for a specified element.
Definition: FGXMLElement.cpp:389
JSBSim::Element::FindElementValueAsNumber
double FindElementValueAsNumber(const std::string &el="")
Searches for the named element and returns the data belonging to it as a number.
Definition: FGXMLElement.cpp:429
JSBSim::FGTank
Models a fuel tank.
Definition: FGTank.h:201
JSBSim::FGTank::ProcessFuelName
double ProcessFuelName(const std::string &name)
Returns the density of a named fuel type.
Definition: FGTank.cpp:419
JSBSim::Element::FindElementValueAsNumberConvertTo
double FindElementValueAsNumberConvertTo(const std::string &el, const std::string &target_units)
Searches for the named element and converts and returns the data belonging to it.
Definition: FGXMLElement.cpp:480
JSBSim::FGFDMExec::GetPropertyManager
FGPropertyManager * GetPropertyManager(void)
Returns a pointer to the property manager object.
Definition: FGFDMExec.cpp:1121
JSBSim::BaseException
Definition: FGJSBBase.h:59
JSBSim::FGTank::GetPctFull
double GetPctFull(void) const
Gets the tank fill level.
Definition: FGTank.h:248
JSBSim::FGTank::Drain
double Drain(double used)
Removes fuel from the tank.
Definition: FGTank.cpp:266
JSBSim::Element::FindElementValue
std::string FindElementValue(const std::string &el="")
Searches for the named element and returns the string data belonging to it.
Definition: FGXMLElement.cpp:468
JSBSim::FGTank::ResetToIC
void ResetToIC(void)
Resets the tank parameters to the initial conditions.
Definition: FGTank.cpp:240
JSBSim::FGTank::GetUnusableVolume
double GetUnusableVolume(void) const
Returns the unusable volume of fuel in the tank.
Definition: FGTank.h:290
JSBSim::FGTank::~FGTank
~FGTank()
Destructor.
Definition: FGTank.cpp:233
JSBSim::FGFunction::GetValue
double GetValue(void) const override
Retrieves the value of the function object.
Definition: FGFunction.cpp:925
JSBSim::Element::ReadFrom
std::string ReadFrom(void) const
Return a string that contains a description of the location where the current XML element was read fr...
Definition: FGXMLElement.cpp:738
JSBSim::FGTank::GetDensity
double GetDensity(void) const
Returns the fuel density.
Definition: FGTank.h:314
JSBSim::FGPropertyManager
Definition: FGPropertyManager.h:373
JSBSim::Element
Definition: FGXMLElement.h:143
JSBSim::FGPropertyManager::Tie
void Tie(const std::string &name, T *pointer)
Tie a property to an external variable.
Definition: FGPropertyManager.h:449
JSBSim::Element::FindElementTripletConvertTo
FGColumnVector3 FindElementTripletConvertTo(const std::string &target_units)
Composes a 3-element column vector for the supplied location or orientation.
Definition: FGXMLElement.cpp:589