diff --git a/src/FDM/JSBSim/JSBSim.cxx b/src/FDM/JSBSim/JSBSim.cxx index 004647c81..14855def1 100644 --- a/src/FDM/JSBSim/JSBSim.cxx +++ b/src/FDM/JSBSim/JSBSim.cxx @@ -273,19 +273,29 @@ FGJSBsim::FGJSBsim( double dt ) double d; SGPropertyNode * node = fgGetNode("/consumables/fuel/tank", i, true); FGTank* tank = Propulsion->GetTank(i); + SGPropertyNode * prop = node->getNode( "density-ppg", true ); - d = node->getNode( "density-ppg", true )->getDoubleValue(); + d = prop->getDoubleValue(); if( d > 0.0 ) { tank->SetDensity( d ); } else { - node->getNode( "density-ppg", true )->setDoubleValue( SG_MAX2<double>(tank->GetDensity(), 0.1) ); + prop->setDoubleValue( SG_MAX2<double>(tank->GetDensity(), 0.1) ); } - d = node->getNode( "level-lbs", true )->getDoubleValue(); + prop = node->getNode( "level-lbs", true ); + d = prop->getDoubleValue(); if( d > 0.0 ) { tank->SetContents( d ); } else { - node->getNode( "level-lbs", true )->setDoubleValue( tank->GetContents() ); + prop->setDoubleValue( tank->GetContents() ); + } + + prop = node->getNode( "unusable-gal_us", true ); + d = prop->getDoubleValue(); + if ( d > 0.0 ) { + tank->SetUnusableVolume( d ); + } else { + prop->setDoubleValue(tank->GetUnusableVolume()); } /* Capacity is read-only in FGTank and can't be overwritten from FlightGear */ node->getNode("capacity-gal_us", true )->setDoubleValue( tank->GetCapacityGallons() ); diff --git a/src/FDM/JSBSim/input_output/FGXMLElement.cpp b/src/FDM/JSBSim/input_output/FGXMLElement.cpp index 55e0fc09f..a4861052b 100644 --- a/src/FDM/JSBSim/input_output/FGXMLElement.cpp +++ b/src/FDM/JSBSim/input_output/FGXMLElement.cpp @@ -8,33 +8,27 @@ ------------- Copyright (C) 2001 Jon S. Berndt (jon@jsbsim.org) ------------- This program is free software; you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by the Free Software - Foundation; either version 2 of the License, or (at your option) any later - version. + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) any + later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 Temple - Place - Suite 330, Boston, MA 02111-1307, USA. + You should have received a copy of the GNU Lesser General Public License along + with this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. - Further information about the GNU Lesser General Public License can also be found on - the world wide web at http://www.gnu.org. + Further information about the GNU Lesser General Public License can also be + found on the world wide web at http://www.gnu.org. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% INCLUDES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ -#include <cmath> -#include <cstdlib> -#include <iostream> -#include <sstream> - #include "FGXMLElement.h" -#include "string_utilities.h" #include "FGJSBBase.h" using namespace std; @@ -91,6 +85,12 @@ Element::Element(const string& nm) convert["FT3"]["M3"] = 1.0/convert["M3"]["FT3"]; convert["LTR"]["IN3"] = 61.0237441; convert["IN3"]["LTR"] = 1.0/convert["LTR"]["IN3"]; + convert["GAL"]["FT3"] = 0.133681; + convert["FT3"]["GAL"] = 1.0/convert["GAL"]["FT3"]; + convert["IN3"]["GAL"] = convert["IN3"]["FT3"]*convert["FT3"]["GAL"]; + convert["LTR"]["GAL"] = convert["LTR"]["IN3"]*convert["IN3"]["GAL"]; + convert["M3"]["GAL"] = 1000.*convert["LTR"]["GAL"]; + convert["CC"]["GAL"] = convert["CC"]["IN3"]*convert["IN3"]["GAL"]; // Mass & Weight convert["LBS"]["KG"] = 0.45359237; convert["KG"]["LBS"] = 1.0/convert["LBS"]["KG"]; @@ -177,6 +177,7 @@ Element::Element(const string& nm) convert["M3"]["M3"] = 1.0; convert["FT3"]["FT3"] = 1.0; convert["LTR"]["LTR"] = 1.0; + convert["GAL"]["GAL"] = 1.0; // Mass & Weight convert["KG"]["KG"] = 1.00; convert["LBS"]["LBS"] = 1.00; diff --git a/src/FDM/JSBSim/models/FGPropulsion.cpp b/src/FDM/JSBSim/models/FGPropulsion.cpp index c78ddc9a8..0ebaaf623 100644 --- a/src/FDM/JSBSim/models/FGPropulsion.cpp +++ b/src/FDM/JSBSim/models/FGPropulsion.cpp @@ -204,7 +204,7 @@ void FGPropulsion::ConsumeFuel(FGEngine* engine) if (TankPriority != 0) { switch(Tank->GetType()) { case FGTank::ttFUEL: - if ((Tank->GetContents() > 0.0) && Tank->GetSelected() && (TankPriority == CurrentFuelTankPriority)) { + if ((Tank->GetContents() > Tank->GetUnusable()) && Tank->GetSelected() && (TankPriority == CurrentFuelTankPriority)) { TanksWithFuel++; Starved = false; FeedListFuel.push_back(TankId); @@ -236,7 +236,7 @@ void FGPropulsion::ConsumeFuel(FGEngine* engine) break; case FGTank::ttOXIDIZER: hasOxTanks = true; - if (Tank->GetContents() > 0.0 && Tank->GetSelected() && TankPriority == CurrentOxidizerTankPriority) { + if (Tank->GetContents() > Tank->GetUnusable() && Tank->GetSelected() && TankPriority == CurrentOxidizerTankPriority) { TanksWithOxidizer++; if (TanksWithFuel > 0) Starved = false; FeedListOxi.push_back(TankId); diff --git a/src/FDM/JSBSim/models/propulsion/FGTank.cpp b/src/FDM/JSBSim/models/propulsion/FGTank.cpp index a414a5810..864076b0e 100644 --- a/src/FDM/JSBSim/models/propulsion/FGTank.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGTank.cpp @@ -63,7 +63,7 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number) Radius = Contents = Standpipe = Length = InnerRadius = 0.0; ExternalFlow = 0.0; InitialStandpipe = 0.0; - Capacity = 0.00001; + Capacity = 0.00001; UnusableVol = 0.0; Priority = InitialPriority = 1; vXYZ.InitMatrix(); vXYZ_drain.InitMatrix(); @@ -95,6 +95,8 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number) Capacity = el->FindElementValueAsNumberConvertTo("capacity", "LBS"); if (el->FindElement("contents")) InitialContents = Contents = el->FindElementValueAsNumberConvertTo("contents", "LBS"); + if (el->FindElement("unusable-volume")) + UnusableVol = el->FindElementValueAsNumberConvertTo("unusable-volume", "GAL"); if (el->FindElement("temperature")) InitialTemperature = Temperature = el->FindElementValueAsNumber("temperature"); if (el->FindElement("standpipe")) @@ -115,6 +117,13 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number) Capacity = 0.00001; Contents = 0.0; } + if (Capacity <= GetUnusable()) { + cerr << el->ReadFrom() << "Tank capacity (" << Capacity + << " lbs) is lower than the amount of unusable fuel (" << GetUnusable() + << " lbs) for tank " << tank_number + << "! Did you accidentally swap unusable and capacity?" << endl; + throw("tank definition error"); + } if (Contents > Capacity) { cerr << el->ReadFrom() << "Tank content (" << Contents << " lbs) is greater than tank capacity (" << Capacity @@ -122,6 +131,11 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number) << "! Did you accidentally swap contents and capacity?" << endl; throw("tank definition error"); } + if (Contents < GetUnusable()) { + cerr << el->ReadFrom() << "Tank content (" << Contents + << " lbs) is lower than the amount of unusable fuel (" << GetUnusable() + << " lbs) for tank " << tank_number << endl; + } PctFull = 100.0*Contents/Capacity; // percent full; 0 to 100.0 @@ -253,17 +267,16 @@ double FGTank::Drain(double used) { double remaining = Contents - used; - if (remaining >= 0) { // Reduce contents by amount used. - + if (remaining >= GetUnusable()) { // Reduce contents by amount used. Contents -= used; - PctFull = 100.0*Contents/Capacity; - } else { // This tank must be empty. + if (Contents > GetUnusable()) + Contents = GetUnusable(); - Contents = 0.0; - PctFull = 0.0; + remaining = Contents; } + PctFull = 100.0*Contents/Capacity; CalculateInertias(); return remaining; @@ -443,6 +456,9 @@ void FGTank::bind(FGPropertyManager* PropertyManager) property_name = base_property_name + "/contents-lbs"; PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetContents, &FGTank::SetContents ); + property_name = base_property_name + "/unusable-volume-gal"; + PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetUnusableVolume, + &FGTank::SetUnusableVolume ); property_name = base_property_name + "/pct-full"; PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetPctFull); diff --git a/src/FDM/JSBSim/models/propulsion/FGTank.h b/src/FDM/JSBSim/models/propulsion/FGTank.h index 0c003d6f7..5ccf5c366 100644 --- a/src/FDM/JSBSim/models/propulsion/FGTank.h +++ b/src/FDM/JSBSim/models/propulsion/FGTank.h @@ -7,21 +7,21 @@ ------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) ------------- This program is free software; you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by the Free Software - Foundation; either version 2 of the License, or (at your option) any later - version. + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) any + later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 Temple - Place - Suite 330, Boston, MA 02111-1307, USA. + You should have received a copy of the GNU Lesser General Public License along + with this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. - Further information about the GNU Lesser General Public License can also be found on - the world wide web at http://www.gnu.org. + Further information about the GNU Lesser General Public License can also be + found on the world wide web at http://www.gnu.org. FUNCTIONAL DESCRIPTION -------------------------------------------------------------------------------- @@ -46,8 +46,6 @@ INCLUDES #include "FGJSBBase.h" #include "math/FGColumnVector3.h" -#include "math/FGFunction.h" -#include <string> /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FORWARD DECLARATIONS @@ -58,6 +56,7 @@ namespace JSBSim { class Element; class FGPropertyManager; class FGFDMExec; +class FGFunction; /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% CLASS DOCUMENTATION @@ -69,8 +68,8 @@ CLASS DOCUMENTATION Fuel temperature is calculated using the following assumptions: - Fuel temperature will only be calculated for tanks which have an initial fuel - temperature specified in the configuration file. + Fuel temperature will only be calculated for tanks which have an initial + fuel temperature specified in the configuration file. The surface area of the tank is estimated from the capacity in pounds. It is assumed that the tank is a wing tank with dimensions h by 4h by 10h. The @@ -84,27 +83,30 @@ CLASS DOCUMENTATION <h3>Fuel Dump:</h3> - Fuel dumping is handled by the FGPropulsion class. A standpipe can be defined - here for each tank which sets the level of contents (in pounds) which is not dumpable. - Default standpipe level is zero, making all contents dumpable. + Fuel dumping is handled by the FGPropulsion class. A standpipe can be + defined here for each tank which sets the level of contents (in pounds) + which is not dumpable. Default standpipe level is zero, making all contents + dumpable. <h3>Fuel Transfer:</h3> - Fuel transfer is handled by the FGPropulsion class, however the contents of tanks - may be manipulated directly using the SetContents() function here, or via the property - tree at <tt>propulsion/tank[i]/contents-lbs</tt>, where i is the tank number (Tanks - are automatically numbered, starting at zero, in the order in which they are read in - the aircraft configuration file). The latter method allows one to use a system of FCS - components to control tank contents. + Fuel transfer is handled by the FGPropulsion class, however the contents of + tanks may be manipulated directly using the SetContents() function here, or + via the property tree at <tt>propulsion/tank[i]/contents-lbs</tt>, where i + is the tank number (Tanks are automatically numbered, starting at zero, in + the order in which they are read in the aircraft configuration file). The + latter method allows one to use a system of FCS components to control tank + contents. - There is also a property <tt>propulsion/tank[i]/external-flow-rate-pps</tt>. Setting - this property to a positive value causes the tank to fill at the rate specified. - Setting a negative number causes the tank to drain. The value is the rate in pounds - of fuel per second. The tank will not fill past 100% full and will not drain below 0%. - Fuel may be transfered between two tanks by setting the source tank's external flow rate - to a negative value and the destination's external flow rate to the same positive value. - Care must be taken to stop fuel flow before the source tank becomes empty to prevent - phantom fuel being created. + There is also a property + <tt>propulsion/tank[i]/external-flow-rate-pps</tt>. Setting this property to + a positive value causes the tank to fill at the rate specified. Setting a + negative number causes the tank to drain. The value is the rate in pounds of + fuel per second. The tank will not fill past 100% full and will not drain + below 0%. Fuel may be transfered between two tanks by setting the source + tank's external flow rate to a negative value and the destination's external + flow rate to the same positive value. Care must be taken to stop fuel flow + before the source tank becomes empty to prevent phantom fuel being created. <h3>Configuration File Format:</h3> @@ -133,6 +135,7 @@ CLASS DOCUMENTATION <contents unit="{LBS | KG}"> {number} </contents> <temperature> {number} </temperature> <!-- must be degrees fahrenheit --> <standpipe unit="{LBS | KG"}> {number} </standpipe> + <unusable unit="{LBS | KG}"> {number} </unusable> <priority> {integer} </priority> <density unit="{KG/L | LBS/GAL}"> {number} </density> <type> {string} </type> <!-- will override previous density setting --> @@ -144,16 +147,19 @@ CLASS DOCUMENTATION - \b type - One of FUEL or OXIDIZER. This is required. - \b radius - Equivalent radius of tank for modeling slosh, defaults to inches. - \b grain_config type - One of CYLINDRICAL or ENDBURNING. -- \b length - length of tank for modeling solid fuel propellant grain, defaults to inches. +- \b length - length of tank for modeling solid fuel propellant grain, defaults + to inches. - \b capacity - Capacity, defaults to pounds. - \b contents - Initial contents, defaults to pounds. - \b temperature - Initial temperature, defaults to degrees Fahrenheit. - \b standpipe - Minimum contents to which tank can dump, defaults to pounds. +- \b unusable - Contents that cannot be used for combustion in the engine, + defaults to pounds. - \b priority - Establishes feed sequence of tank. "1" is the highest priority. - \b density - Density of liquid tank contents. -- \b type - Named fuel type. One of AVGAS, JET-A, JET-A1, JET-B, JP-1, JP-2, JP-3, -- \b JP-4, JP-5, JP-6, JP-7, JP-8, JP-8+100, RP-1, T-1, ETHANOL, HYDRAZINE, -- \b F-34, F-35, F-40, F-44, AVTAG, AVCAT +- \b type - Named fuel type. One of AVGAS, JET-A, JET-A1, JET-B, JP-1, JP-2, + JP-3, JP-4, JP-5, JP-6, JP-7, JP-8, JP-8+100, RP-1, T-1, ETHANOL, + HYDRAZINE, F-34, F-35, F-40, F-44, AVTAG, AVCAT location: - \b x - Location of tank on aircraft's x-axis, defaults to inches. @@ -178,6 +184,7 @@ be printed to the console if the location is not given - \b contents - 0.0 - \b temperature - -9999.0 (flag which indicates no temperature is set) - \b standpipe - 0.0 (all contents may be dumped) +- \b unusable - 0.0 (all contents may be burnt) - \b priority - 1 (highest feed sequence priority) - \b density - 6.6 @@ -195,7 +202,8 @@ class FGTank : public FGJSBBase { public: /** Constructor. - The constructor reads in the defining parameters from a configuration file. + The constructor reads in the defining parameters from a configuration + file. @param exec a pointer to the base FGFDMExec instance. @param el a pointer to the Tank element. @param tank_number the tank number (zero based). @@ -271,7 +279,19 @@ public: /** Returns the density of a named fuel type. @return the density, in lbs/gal, or 6.6 if name cannot be resolved. */ - double ProcessFuelName(const std::string& name); + double ProcessFuelName(const std::string& name); + + /** Returns the amount of unusable fuel in the tank. + @return the amount in lbs. */ + double GetUnusable(void) const {return UnusableVol*Density;} + + /** Returns the unusable volume of fuel in the tank. + @return the volume in gal. */ + double GetUnusableVolume(void) const {return UnusableVol;} + + /** Sets the volume of unusable fuel in the tank. + @param amount the amount of unusable fuel in gal. */ + void SetUnusableVolume(double volume) {UnusableVol = volume;} double GetIxx(void) const {return Ixx;} double GetIyy(void) const {return Iyy;} @@ -289,7 +309,11 @@ public: int GetPriority(void) const {return Priority;} void SetPriority(int p) { Priority = p; Selected = p>0 ? true:false; } + /** Returns the fuel density. + @return the density in lbs/gal. */ double GetDensity(void) const {return Density;} + /** Sets the fuel density. + @param d the density in lbs/gal. */ void SetDensity(double d) { Density = d; } double GetExternalFlow(void) const {return ExternalFlow;} @@ -298,7 +322,7 @@ public: FGColumnVector3 GetXYZ(void) const; double GetXYZ(int idx) const; - const GrainType GetGrainType(void) const {return grainType;} + GrainType GetGrainType(void) const {return grainType;} double Fill(double amount); void SetContents(double amount); @@ -321,7 +345,7 @@ private: FGFunction* function_ixx; FGFunction* function_iyy; FGFunction* function_izz; - double Capacity; + double Capacity, UnusableVol; double Radius; double InnerRadius; double Length;