42 #include "FGFDMExec.h" 43 #include "input_output/FGXMLElement.h" 44 #include "input_output/FGPropertyManager.h" 45 #include "input_output/string_utilities.h" 51 IDENT(IdSrc,
"$Id: FGTank.cpp,v 1.46 2017/02/21 21:07:04 bcoconni Exp $");
59 : TankNumber(tank_number)
61 string token, strFuelName;
67 InitialTemperature = Temperature = -9999.0;
68 Ixx = Iyy = Izz = 0.0;
70 Radius = Contents = Standpipe = Length = InnerRadius = 0.0;
72 InitialStandpipe = 0.0;
74 Priority = InitialPriority = 1;
76 vXYZ_drain.InitMatrix();
77 ixx_unit = iyy_unit = izz_unit = 1.0;
78 grainType = gtUNKNOWN;
81 if (type ==
"FUEL") Type = ttFUEL;
82 else if (type ==
"OXIDIZER") Type = ttOXIDIZER;
83 else Type = ttUNKNOWN;
87 else cerr << el->
ReadFrom() <<
"No location found for this tank." 117 SetPriority( InitialPriority );
121 <<
"Tank capacity must not be zero. Reset to 0.00001 lbs!" << endl;
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");
133 PctFull = 100.0*Contents/Capacity;
141 if (strGType ==
"CYLINDRICAL") grainType = gtCYLINDRICAL;
142 else if (strGType ==
"ENDBURNING") grainType = gtENDBURNING;
143 else if (strGType ==
"FUNCTION") {
144 grainType = gtFUNCTION;
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.");
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.");
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.");
176 cerr << el->
ReadFrom() <<
"Unknown propellant grain type specified" 188 if (Radius <= InnerRadius) {
190 <<
"The bore diameter should be smaller than the total grain diameter!" 194 Volume = M_PI * Length * (Radius*Radius - InnerRadius*InnerRadius);
197 Volume = M_PI * Length * Radius * Radius;
204 <<
"Unknown grain type found in this rocket engine definition." 208 Density = (Capacity*lbtoslug)/Volume;
213 if (Temperature != -9999.0) InitialTemperature = Temperature =
FahrenheitToCelsius(Temperature);
214 Area = 40.0 * pow(Capacity/1975, 0.666666667);
219 bind(PropertyManager);
235 SetTemperature( InitialTemperature );
236 SetStandpipe ( InitialStandpipe );
237 SetContents ( InitialContents );
238 PctFull = 100.0*Contents/Capacity;
239 SetPriority( InitialPriority );
247 return vXYZ_drain + (Contents/Capacity)*(vXYZ - vXYZ_drain);
252 double FGTank::GetXYZ(
int idx)
const 254 return vXYZ_drain(idx) + (Contents/Capacity)*(vXYZ(idx)-vXYZ_drain(idx));
261 double remaining = Contents - used;
263 if (remaining >= 0) {
266 PctFull = 100.0*Contents/Capacity;
281 double FGTank::Fill(
double amount)
283 double overage = 0.0;
287 if (Contents > Capacity) {
288 overage = Contents - Capacity;
292 PctFull = Contents/Capacity*100.0;
302 void FGTank::SetContents(
double amount)
305 if (Contents > Capacity) {
309 PctFull = Contents/Capacity*100.0;
317 void FGTank::SetContentsGallons(
double gallons)
319 SetContents(gallons * Density);
327 if(ExternalFlow < 0.)
Drain( -ExternalFlow *dt);
328 else Fill(ExternalFlow * dt);
330 if (Temperature == -9999.0)
return 0.0;
331 double HeatCapacity = 900.0;
332 double TempFlowFactor = 1.115;
333 double Tdiff = TAT_C - Temperature;
335 if (fabs(Tdiff) > 0.1 && Contents > 0.01) {
336 dTemp = (TempFlowFactor * Area * Tdiff * dt) / (Contents * HeatCapacity);
339 return Temperature += (dTemp + dTemp);
359 void FGTank::CalculateInertias(
void)
361 double Mass = Contents*lbtoslug;
363 double Rad2 = Radius*Radius;
365 if (grainType != gtUNKNOWN) {
368 Volume = (Contents*lbtoslug)/Density;
369 }
else if (Contents <= 0.0) {
372 cerr << endl <<
" Solid propellant grain density is zero!" << endl << endl;
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;
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);
391 Ixx = function_ixx->
GetValue()*ixx_unit;
392 Iyy = function_iyy->
GetValue()*iyy_unit;
393 Izz = function_izz->
GetValue()*izz_unit;
396 cerr <<
"Unknown grain type found." << endl;
403 if (Radius > 0.0) Ixx = Iyy = Izz = Mass * InertiaFactor * 0.4 * Radius * Radius / 144.0;
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;
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;
438 cerr <<
"Unknown fuel type specified: "<< name << endl;
448 string property_name, base_property_name;
449 base_property_name = CreateIndexedPropertyName(
"propulsion/tank", TankNumber);
450 property_name = base_property_name +
"/contents-lbs";
452 &FGTank::SetContents );
453 property_name = base_property_name +
"/pct-full";
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);
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);
497 void FGTank::Debug(
int from)
499 if (debug_lvl <= 0)
return;
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;
511 if (debug_lvl & 2 ) {
512 if (from == 0) cout <<
"Instantiated: FGTank" << endl;
513 if (from == 1) cout <<
"Destroyed: FGTank" << endl;
515 if (debug_lvl & 4 ) {
517 if (debug_lvl & 8 ) {
519 if (debug_lvl & 16) {
521 if (debug_lvl & 64) {
523 cout << IdSrc << endl;
524 cout << IdHdr << endl;
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. ...
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.
double GetValue(void) const
Retrieves the value of the function object.
FGPropertyManager * GetPropertyManager(void)
Returns a pointer to the property manager object.
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.
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.
Represents a mathematical function.
This class implements a 3 element column vector.
double ProcessFuelName(const std::string &name)
Returns the density of a named fuel type.
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.
static double FahrenheitToCelsius(double fahrenheit)
Converts from degrees Fahrenheit to degrees Celsius.
double GetPctFull(void) const
Gets the tank fill level.
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.
void ResetToIC(void)
Resets the tank parameters to the initial conditions.