40 #include "FGFDMExec.h"
41 #include "input_output/FGXMLElement.h"
52 : TankNumber(tank_number)
54 string token, strFuelName;
60 InitialTemperature = Temperature = -9999.0;
61 Ixx = Iyy = Izz = 0.0;
63 Radius = Contents = Standpipe = Length = InnerRadius = 0.0;
65 InitialStandpipe = 0.0;
66 Capacity = 0.00001; UnusableVol = 0.0;
67 Priority = InitialPriority = 1;
69 vXYZ_drain.InitMatrix();
70 ixx_unit = iyy_unit = izz_unit = 1.0;
71 grainType = gtUNKNOWN;
74 if (type ==
"FUEL") Type = ttFUEL;
75 else if (type ==
"OXIDIZER") Type = ttOXIDIZER;
76 else Type = ttUNKNOWN;
80 else cerr << el->
ReadFrom() <<
"No location found for this tank."
112 SetPriority( InitialPriority );
116 <<
"Tank capacity must not be zero. Reset to 0.00001 lbs!" << endl;
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");
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");
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;
140 PctFull = 100.0*Contents/Capacity;
148 if (strGType ==
"CYLINDRICAL") grainType = gtCYLINDRICAL;
149 else if (strGType ==
"ENDBURNING") grainType = gtENDBURNING;
150 else if (strGType ==
"FUNCTION") {
151 grainType = gtFUNCTION;
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.");
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.");
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.");
183 cerr << el->
ReadFrom() <<
"Unknown propellant grain type specified"
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;
200 Volume = M_PI * Length * (Radius*Radius - InnerRadius*InnerRadius);
203 Volume = M_PI * Length * Radius * Radius;
210 const string s(
"Unknown grain type found in this rocket engine definition.");
211 cerr << el->
ReadFrom() << endl << s << endl;
215 Density = (Capacity*lbtoslug)/Volume;
220 if (Temperature != -9999.0) InitialTemperature = Temperature =
FahrenheitToCelsius(Temperature);
221 Area = 40.0 * pow(Capacity/1975, 0.666666667);
226 bind(PropertyManager);
242 SetTemperature( InitialTemperature );
243 SetStandpipe ( InitialStandpipe );
244 SetContents ( InitialContents );
245 PctFull = 100.0*Contents/Capacity;
246 SetPriority( InitialPriority );
254 return vXYZ_drain + (Contents/Capacity)*(vXYZ - vXYZ_drain);
259 double FGTank::GetXYZ(
int idx)
const
261 return vXYZ_drain(idx) + (Contents/Capacity)*(vXYZ(idx)-vXYZ_drain(idx));
268 double remaining = Contents - used;
276 remaining = Contents;
279 PctFull = 100.0*Contents/Capacity;
287 double FGTank::Fill(
double amount)
289 double overage = 0.0;
293 if (Contents > Capacity) {
294 overage = Contents - Capacity;
298 PctFull = Contents/Capacity*100.0;
308 void FGTank::SetContents(
double amount)
311 if (Contents > Capacity) {
315 PctFull = Contents/Capacity*100.0;
323 void FGTank::SetContentsGallons(
double gallons)
325 SetContents(gallons * Density);
333 if(ExternalFlow < 0.)
Drain( -ExternalFlow *dt);
334 else Fill(ExternalFlow * dt);
336 if (Temperature == -9999.0)
return 0.0;
337 double HeatCapacity = 900.0;
338 double TempFlowFactor = 1.115;
339 double Tdiff = TAT_C - Temperature;
341 if (fabs(Tdiff) > 0.1 && Contents > 0.01) {
342 dTemp = (TempFlowFactor * Area * Tdiff * dt) / (Contents * HeatCapacity);
345 return Temperature += (dTemp + dTemp);
365 void FGTank::CalculateInertias(
void)
367 double Mass = Contents*lbtoslug;
369 double Rad2 = Radius*Radius;
371 if (grainType != gtUNKNOWN) {
374 Volume = (Contents*lbtoslug)/Density;
375 }
else if (Contents <= 0.0) {
378 const string s(
" Solid propellant grain density is zero!");
379 cerr << endl << s << endl;
380 throw BaseException(s);
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;
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);
398 Ixx = function_ixx->
GetValue()*ixx_unit;
399 Iyy = function_iyy->
GetValue()*iyy_unit;
400 Izz = function_izz->
GetValue()*izz_unit;
404 const string s(
"Unknown grain type found.");
406 throw BaseException(s);
412 if (Radius > 0.0) Ixx = Iyy = Izz = Mass * InertiaFactor * 0.4 * Radius * Radius / 144.0;
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;
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;
447 cerr <<
"Unknown fuel type specified: "<< name << endl;
457 string property_name, base_property_name;
458 base_property_name = CreateIndexedPropertyName(
"propulsion/tank", TankNumber);
459 property_name = base_property_name +
"/contents-lbs";
461 &FGTank::SetContents );
462 property_name = base_property_name +
"/unusable-volume-gal";
465 property_name = base_property_name +
"/pct-full";
467 property_name = base_property_name +
"/density-lbs_per_gal";
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);
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);
511 void FGTank::Debug(
int from)
513 if (debug_lvl <= 0)
return;
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;
525 if (debug_lvl & 2 ) {
526 if (from == 0) cout <<
"Instantiated: FGTank" << endl;
527 if (from == 1) cout <<
"Destroyed: FGTank" << endl;
529 if (debug_lvl & 4 ) {
531 if (debug_lvl & 8 ) {
533 if (debug_lvl & 16) {
535 if (debug_lvl & 64) {