1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8 ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
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 General Public License for more
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 Place - Suite 330, Boston, MA 02111-1307, USA.
24 Further information about the GNU General Public License can also be found on
25 the world wide web at http://www.gnu.org.
27 FUNCTIONAL DESCRIPTION
28 --------------------------------------------------------------------------------
32 --------------------------------------------------------------------------------
34 09/03/99 JSB Changed Rocket thrust equation to correct -= Thrust instead of
35 += Thrust (thanks to Tony Peden)
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
42 # include <simgear/compiler.h>
43 # ifdef SG_HAVE_STD_INCLUDES
49 # if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
58 #include "FGPropeller.h"
63 static const char *IdSrc = "$Id$";
64 static const char *IdHdr = ID_ENGINE;
66 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
68 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
71 FGEngine::FGEngine(FGFDMExec* exec, int engine_number) : EngineNumber(engine_number)
76 EnginePitch = EngineYaw = 0.0;
77 SLFuelFlowMax = SLOxiFlowMax = 0.0;
84 FuelNeed = OxidizerNeed = 0.0;
85 Starved = Running = Cranking = false;
93 State = FDMExec->GetState();
94 Atmosphere = FDMExec->GetAtmosphere();
95 FCS = FDMExec->GetFCS();
96 Propulsion = FDMExec->GetPropulsion();
97 Aircraft = FDMExec->GetAircraft();
98 Propagate = FDMExec->GetPropagate();
99 Auxiliary = FDMExec->GetAuxiliary();
100 Output = FDMExec->GetOutput();
102 PropertyManager = FDMExec->GetPropertyManager();
104 char property_name[80];
105 snprintf(property_name, 80, "propulsion/engine[%u]/thrust", EngineNumber);
106 PropertyManager->Tie( property_name, &Thrust);
111 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113 FGEngine::~FGEngine()
115 if (Thruster) delete Thruster;
117 char property_name[80];
118 snprintf(property_name, 80, "propulsion/engine[%u]/thrust", EngineNumber);
119 PropertyManager->Untie( property_name);
124 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125 // This base class function should be called from within the
126 // derived class' Calculate() function before any other calculations are done.
127 // This base class method removes fuel from the fuel tanks as appropriate,
128 // and sets the starved flag if necessary.
130 void FGEngine::ConsumeFuel(void)
132 if (FuelFreeze) return;
134 double Fshortage, Oshortage, TanksWithFuel, TanksWithOxidizer;
136 bool haveOxTanks = false;
138 if (TrimMode) return;
139 Fshortage = Oshortage = TanksWithFuel = TanksWithOxidizer = 0.0;
141 // count how many assigned tanks have fuel or oxidizer
142 for (i=0; i<SourceTanks.size(); i++) {
143 Tank = Propulsion->GetTank(SourceTanks[i]);
144 if (Tank->GetType() == FGTank::ttFUEL){
145 if (Tank->GetContents() > 0.0) {
148 } else if (Tank->GetType() == FGTank::ttOXIDIZER) {
150 if (Tank->GetContents() > 0.0) {
155 if (!TanksWithFuel || (haveOxTanks && !TanksWithOxidizer)) return;
157 for (i=0; i<SourceTanks.size(); i++) {
158 Tank = Propulsion->GetTank(SourceTanks[i]);
159 if (Tank->GetType() == FGTank::ttFUEL) {
160 Fshortage += Tank->Drain(CalcFuelNeed()/TanksWithFuel);
161 } else if (Tank->GetType() == FGTank::ttOXIDIZER) {
162 Oshortage += Tank->Drain(CalcOxidizerNeed()/TanksWithOxidizer);
166 if (Fshortage < 0.00 || Oshortage < 0.00) Starved = true;
167 else Starved = false;
170 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 double FGEngine::CalcFuelNeed(void)
174 FuelNeed = SLFuelFlowMax*PctPower*State->Getdt()*Propulsion->GetRate();
178 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180 double FGEngine::CalcOxidizerNeed(void)
182 OxidizerNeed = SLOxiFlowMax*PctPower*State->Getdt()*Propulsion->GetRate();
186 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188 void FGEngine::SetPlacement(double x, double y, double z, double pitch, double yaw)
197 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199 void FGEngine::AddFeedTank(int tkID)
201 SourceTanks.push_back(tkID);
204 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206 FGColumnVector3& FGEngine::GetBodyForces(void)
208 return Thruster->GetBodyForces();
211 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
213 FGColumnVector3& FGEngine::GetMoments(void)
215 return Thruster->GetMoments();
218 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220 bool FGEngine::LoadThruster(FGConfigFile* AC_cfg)
222 string token, fullpath, localpath;
223 string thrType, engineFileName;
224 FGConfigFile* Cfg_ptr = 0;
225 double xLoc, yLoc, zLoc, Pitch, Yaw;
226 double P_Factor = 0, Sense = 0.0;
227 string enginePath = FDMExec->GetEnginePath();
228 string aircraftPath = FDMExec->GetAircraftPath();
229 thrusterFileName = AC_cfg->GetValue("FILE");
232 fullpath = enginePath + "/";
233 localpath = aircraftPath + "/" + "/Engines/";
235 fullpath = enginePath + ";";
236 localpath = aircraftPath + ";" + ";Engines;";
239 // Look in the Aircraft/Engines directory first
240 FGConfigFile Local_Thruster_cfg(localpath + thrusterFileName + ".xml");
241 FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");
243 if (Local_Thruster_cfg.IsOpen()) {
244 Cfg_ptr = &Local_Thruster_cfg;
245 if (debug_lvl > 0) cout << "\n Reading thruster from file: " << localpath
246 + thrusterFileName + ".xml"<< endl;
248 if (Thruster_cfg.IsOpen()) {
249 Cfg_ptr = &Thruster_cfg;
250 if (debug_lvl > 0) cout << "\n Reading thruster from file: " << fullpath
251 + thrusterFileName + ".xml"<< endl;
256 Cfg_ptr->GetNextConfigLine();
257 thrType = Cfg_ptr->GetValue();
259 if (thrType == "FG_PROPELLER") {
260 Thruster = new FGPropeller(FDMExec, Cfg_ptr, EngineNumber);
261 } else if (thrType == "FG_NOZZLE") {
262 Thruster = new FGNozzle(FDMExec, Cfg_ptr, EngineNumber);
263 } else if (thrType == "FG_DIRECT") {
264 Thruster = new FGThruster( FDMExec, Cfg_ptr, EngineNumber);
267 AC_cfg->GetNextConfigLine();
268 while ((token = AC_cfg->GetValue()) != string("/AC_THRUSTER")) {
270 if (token == "XLOC") *AC_cfg >> xLoc;
271 else if (token == "YLOC") *AC_cfg >> yLoc;
272 else if (token == "ZLOC") *AC_cfg >> zLoc;
273 else if (token == "PITCH") *AC_cfg >> Pitch;
274 else if (token == "YAW") *AC_cfg >> Yaw;
275 else if (token == "P_FACTOR") *AC_cfg >> P_Factor;
276 else if (token == "SENSE") *AC_cfg >> Sense;
277 else cerr << "Unknown identifier: " << token << " in engine file: "
278 << engineFileName << endl;
281 Thruster->SetLocation(xLoc, yLoc, zLoc);
282 Thruster->SetAnglesToBody(0, Pitch, Yaw);
283 if (thrType == "FG_PROPELLER" && P_Factor > 0.001) {
284 ((FGPropeller*)Thruster)->SetPFactor(P_Factor);
285 if (debug_lvl > 0) cout << " P-Factor: " << P_Factor << endl;
286 ((FGPropeller*)Thruster)->SetSense(fabs(Sense)/Sense);
287 if (debug_lvl > 0) cout << " Sense: " << Sense << endl;
289 Thruster->SetdeltaT(State->Getdt() * Propulsion->GetRate());
293 cerr << "Could not read thruster config file: " << fullpath
294 + thrusterFileName + ".xml" << endl;
300 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
301 // The bitmasked value choices are as follows:
302 // unset: In this case (the default) JSBSim would only print
303 // out the normally expected messages, essentially echoing
304 // the config files as they are read. If the environment
305 // variable is not set, debug_lvl is set to 1 internally
306 // 0: This requests JSBSim not to output any messages
308 // 1: This value explicity requests the normal JSBSim
310 // 2: This value asks for a message to be printed out when
311 // a class is instantiated
312 // 4: When this value is set, a message is displayed when a
313 // FGModel object executes its Run() method
314 // 8: When this value is set, various runtime state variables
315 // are printed out periodically
316 // 16: When set various parameters are sanity checked and
317 // a message is printed out when they go out of bounds
319 void FGEngine::Debug(int from)
321 if (debug_lvl <= 0) return;
323 if (debug_lvl & 1) { // Standard console startup message output
324 if (from == 0) { // Constructor
328 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
329 if (from == 0) cout << "Instantiated: FGEngine" << endl;
330 if (from == 1) cout << "Destroyed: FGEngine" << endl;
332 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
334 if (debug_lvl & 8 ) { // Runtime state variables
336 if (debug_lvl & 16) { // Sanity checking
338 if (debug_lvl & 64) {
339 if (from == 0) { // Constructor
340 cout << IdSrc << endl;
341 cout << IdHdr << endl;