FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number) : TankNumber(tank_number) { string token, strFuelName; Element* element; Element* element_Grain; FGPropertyManager *PropertyManager = exec->GetPropertyManager(); Area = 1.0; Density = 6.6; InitialTemperature = Temperature = -9999.0; Ixx = Iyy = Izz = 0.0; InertiaFactor = 1.0; Radius = Contents = Standpipe = Length = InnerRadius = 0.0; ExternalFlow = 0.0; InitialStandpipe = 0.0; Capacity = 0.00001; Priority = InitialPriority = 1; vXYZ.InitMatrix(); vXYZ_drain.InitMatrix(); ixx_unit = iyy_unit = izz_unit = 1.0; grainType = gtUNKNOWN; // This is the default type = el->GetAttributeValue("type"); if (type == "FUEL") Type = ttFUEL; else if (type == "OXIDIZER") Type = ttOXIDIZER; else Type = ttUNKNOWN; element = el->FindElement("location"); if (element) vXYZ = element->FindElementTripletConvertTo("IN"); else cerr << "No location found for this tank." << endl; vXYZ_drain = vXYZ; // Set initial drain location to initial tank CG element = el->FindElement("drain_location"); if (element) { vXYZ_drain = element->FindElementTripletConvertTo("IN"); } if (el->FindElement("radius")) Radius = el->FindElementValueAsNumberConvertTo("radius", "IN"); if (el->FindElement("inertia_factor")) InertiaFactor = el->FindElementValueAsNumber("inertia_factor"); if (el->FindElement("capacity")) Capacity = el->FindElementValueAsNumberConvertTo("capacity", "LBS"); if (el->FindElement("contents")) InitialContents = Contents = el->FindElementValueAsNumberConvertTo("contents", "LBS"); if (el->FindElement("temperature")) InitialTemperature = Temperature = el->FindElementValueAsNumber("temperature"); if (el->FindElement("standpipe")) InitialStandpipe = Standpipe = el->FindElementValueAsNumberConvertTo("standpipe", "LBS"); if (el->FindElement("priority")) InitialPriority = Priority = (int)el->FindElementValueAsNumber("priority"); if (el->FindElement("density")) Density = el->FindElementValueAsNumberConvertTo("density", "LBS/GAL"); if (el->FindElement("type")) strFuelName = el->FindElementValue("type"); SetPriority( InitialPriority ); // this will also set the Selected flag if (Capacity == 0) { cerr << "Tank capacity must not be zero. Reset to 0.00001 lbs!" << endl; Capacity = 0.00001; Contents = 0.0; } if (Contents > Capacity) { cerr << "Tank content (" << Contents << " lbs) is greater than tank capacity (" << Capacity << " lbs) for tank " << tank_number << "! Did you accidentally swap contents and capacity?" << endl; throw("tank definition error"); } PctFull = 100.0*Contents/Capacity; // percent full; 0 to 100.0 // Check whether this is a solid propellant "tank". Initialize it if true. element_Grain = el->FindElement("grain_config"); if (element_Grain) { strGType = element_Grain->GetAttributeValue("type"); if (strGType == "CYLINDRICAL") grainType = gtCYLINDRICAL; else if (strGType == "ENDBURNING") grainType = gtENDBURNING; else if (strGType == "FUNCTION") { grainType = gtFUNCTION; if (element_Grain->FindElement("ixx") != 0) { Element* element_ixx = element_Grain->FindElement("ixx"); if (element_ixx->GetAttributeValue("unit") == "KG*M2") ixx_unit = 1.0/1.35594; if (element_ixx->FindElement("function") != 0) { function_ixx = new FGFunction(PropertyManager, element_ixx->FindElement("function")); } } else { throw("For tank "+to_string(TankNumber)+" and when grain_config is specified an ixx must be specified when the FUNCTION grain type is specified."); } if (element_Grain->FindElement("iyy")) { Element* element_iyy = element_Grain->FindElement("iyy"); if (element_iyy->GetAttributeValue("unit") == "KG*M2") iyy_unit = 1.0/1.35594; if (element_iyy->FindElement("function") != 0) { function_iyy = new FGFunction(PropertyManager, element_iyy->FindElement("function")); } } else { throw("For tank "+to_string(TankNumber)+" and when grain_config is specified an iyy must be specified when the FUNCTION grain type is specified."); } if (element_Grain->FindElement("izz")) { Element* element_izz = element_Grain->FindElement("izz"); if (element_izz->GetAttributeValue("unit") == "KG*M2") izz_unit = 1.0/1.35594; if (element_izz->FindElement("function") != 0) { function_izz = new FGFunction(PropertyManager, element_izz->FindElement("function")); } } else { throw("For tank "+to_string(TankNumber)+" and when grain_config is specified an izz must be specified when the FUNCTION grain type is specified."); } } else cerr << "Unknown propellant grain type specified" << endl; if (element_Grain->FindElement("length")) Length = element_Grain->FindElementValueAsNumberConvertTo("length", "IN"); if (element_Grain->FindElement("bore_diameter")) InnerRadius = element_Grain->FindElementValueAsNumberConvertTo("bore_diameter", "IN")/2.0; // Initialize solid propellant values for debug and runtime use. switch (grainType) { case gtCYLINDRICAL: if (Radius <= InnerRadius) { std::stringstream error; error << "The bore diameter should be smaller than the total grain diameter!" << endl; throw std::runtime_error(error.str()); } Volume = M_PI * Length * (Radius*Radius - InnerRadius*InnerRadius); // cubic inches break; case gtENDBURNING: Volume = M_PI * Length * Radius * Radius; // cubic inches break; case gtFUNCTION: Volume = 1; // Volume is irrelevant for the FUNCTION type, but it can't be zero! break; case gtUNKNOWN: std::stringstream error; error << "Unknown grain type found in this rocket engine definition." << endl; throw std::runtime_error(error.str()); } Density = (Contents*lbtoslug)/Volume; // slugs/in^3 } CalculateInertias(); if (Temperature != -9999.0) InitialTemperature = Temperature = FahrenheitToCelsius(Temperature); Area = 40.0 * pow(Capacity/1975, 0.666666667); // A named fuel type will override a previous density value if (!strFuelName.empty()) Density = ProcessFuelName(strFuelName); bind(PropertyManager); Debug(0); }
FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number) : TankNumber(tank_number), Exec(exec) { string token, strFuelName; Element* element; Element* element_Grain; Area = 1.0; Density = 6.6; InitialTemperature = Temperature = -9999.0; Ixx = Iyy = Izz = 0.0; InertiaFactor = 1.0; Radius = Contents = Standpipe = Length = InnerRadius = 0.0; PreviousUsed = 0.0; ExternalFlow = 0.0; InitialStandpipe = 0.0; Capacity = 0.00001; Priority = InitialPriority = 1; PropertyManager = Exec->GetPropertyManager(); vXYZ.InitMatrix(); vXYZ_drain.InitMatrix(); type = el->GetAttributeValue("type"); if (type == "FUEL") Type = ttFUEL; else if (type == "OXIDIZER") Type = ttOXIDIZER; else Type = ttUNKNOWN; element = el->FindElement("location"); if (element) vXYZ = element->FindElementTripletConvertTo("IN"); else cerr << "No location found for this tank." << endl; vXYZ_drain = vXYZ; // Set initial drain location to initial tank CG element = el->FindElement("drain_location"); if (element) { vXYZ_drain = element->FindElementTripletConvertTo("IN"); } if (el->FindElement("radius")) Radius = el->FindElementValueAsNumberConvertTo("radius", "IN"); if (el->FindElement("inertia_factor")) InertiaFactor = el->FindElementValueAsNumber("inertia_factor"); if (el->FindElement("capacity")) Capacity = el->FindElementValueAsNumberConvertTo("capacity", "LBS"); if (el->FindElement("contents")) InitialContents = Contents = el->FindElementValueAsNumberConvertTo("contents", "LBS"); if (el->FindElement("temperature")) InitialTemperature = Temperature = el->FindElementValueAsNumber("temperature"); if (el->FindElement("standpipe")) InitialStandpipe = Standpipe = el->FindElementValueAsNumberConvertTo("standpipe", "LBS"); if (el->FindElement("priority")) InitialPriority = Priority = (int)el->FindElementValueAsNumber("priority"); if (el->FindElement("density")) Density = el->FindElementValueAsNumberConvertTo("density", "LBS/GAL"); if (el->FindElement("type")) strFuelName = el->FindElementValue("type"); SetPriority( InitialPriority ); // this will also set the Selected flag if (Capacity == 0) { cerr << "Tank capacity must not be zero. Reset to 0.00001 lbs!" << endl; Capacity = 0.00001; Contents = 0.0; } if (Contents > Capacity) { cerr << "Tank content (" << Contents << " lbs) is greater than tank capacity (" << Capacity << " lbs) for tank " << tank_number << "! Did you accidentally swap contents and capacity?" << endl; throw("tank definition error"); } PctFull = 100.0*Contents/Capacity; // percent full; 0 to 100.0 // Check whether this is a solid propellant "tank". Initialize it if true. grainType = gtUNKNOWN; // This is the default element_Grain = el->FindElement("grain_config"); if (element_Grain) { strGType = element_Grain->GetAttributeValue("type"); if (strGType == "CYLINDRICAL") grainType = gtCYLINDRICAL; else if (strGType == "ENDBURNING") grainType = gtENDBURNING; else cerr << "Unknown propellant grain type specified" << endl; if (element_Grain->FindElement("length")) Length = element_Grain->FindElementValueAsNumberConvertTo("length", "IN"); if (element_Grain->FindElement("bore_diameter")) InnerRadius = element_Grain->FindElementValueAsNumberConvertTo("bore_diameter", "IN")/2.0; // Initialize solid propellant values for debug and runtime use. switch (grainType) { case gtCYLINDRICAL: if (Radius <= InnerRadius) { cerr << "The bore diameter should be smaller than the total grain diameter!" << endl; exit(-1); } Volume = M_PI * Length * (Radius*Radius - InnerRadius*InnerRadius); // cubic inches break; case gtENDBURNING: Volume = M_PI * Length * Radius * Radius; // cubic inches break; case gtUNKNOWN: cerr << "Unknown grain type found in this rocket engine definition." << endl; exit(-1); } Density = (Contents*lbtoslug)/Volume; // slugs/in^3 } CalculateInertias(); string property_name, base_property_name; base_property_name = CreateIndexedPropertyName("propulsion/tank", TankNumber); property_name = base_property_name + "/contents-lbs"; PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetContents, &FGTank::SetContents ); property_name = base_property_name + "/pct-full"; PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetPctFull); property_name = base_property_name + "/priority"; PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetPriority, &FGTank::SetPriority ); property_name = base_property_name + "/external-flow-rate-pps"; PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetExternalFlow, &FGTank::SetExternalFlow ); if (Temperature != -9999.0) InitialTemperature = Temperature = FahrenheitToCelsius(Temperature); Area = 40.0 * pow(Capacity/1975, 0.666666667); // A named fuel type will override a previous density value if (!strFuelName.empty()) Density = ProcessFuelName(strFuelName); Debug(0); }