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