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