1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 Module: FGPropulsion.cpp
6 Purpose: Encapsulates the set of engines and tanks associated
9 ------------- Copyright (C) 2000 Jon S. Berndt (jon@jsbsim.org) -------------
11 This program is free software; you can redistribute it and/or modify it under
12 the terms of the GNU Lesser General Public License as published by the Free Software
13 Foundation; either version 2 of the License, or (at your option) any later
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
21 You should have received a copy of the GNU Lesser General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23 Place - Suite 330, Boston, MA 02111-1307, USA.
25 Further information about the GNU Lesser General Public License can also be found on
26 the world wide web at http://www.gnu.org.
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30 The Propulsion class is the container for the entire propulsion system, which is
31 comprised of engines and tanks. Once the Propulsion class gets the config file,
32 it reads in information which is specific to a type of engine. Then:
34 1) The appropriate engine type instance is created
35 2) At least one tank object is created, and is linked to an engine.
37 At Run time each engines Calculate() method is called.
40 --------------------------------------------------------------------------------
43 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
45 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
47 #include "FGPropulsion.h"
48 #include "models/FGFCS.h"
49 #include "models/FGMassBalance.h"
50 #include "models/propulsion/FGThruster.h"
51 #include "models/propulsion/FGRocket.h"
52 #include "models/propulsion/FGTurbine.h"
53 #include "models/propulsion/FGPiston.h"
54 #include "models/propulsion/FGElectric.h"
55 #include "models/propulsion/FGTurboProp.h"
56 #include "models/propulsion/FGTank.h"
57 #include "input_output/FGPropertyManager.h"
58 #include "input_output/FGXMLParse.h"
59 #include "math/FGColumnVector3.h"
68 static const char *IdSrc = "$Id: FGPropulsion.cpp,v 1.41 2010/10/15 11:32:41 jberndt Exp $";
69 static const char *IdHdr = ID_PROPULSION;
71 extern short debug_lvl;
74 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
78 FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
80 Name = "FGPropulsion";
82 InitializedEngines = 0;
83 numSelectedFuelTanks = numSelectedOxiTanks = 0;
84 numTanks = numEngines = 0;
85 numOxiTanks = numFuelTanks = 0;
86 ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...
88 refuel = dump = false;
91 TotalFuelQuantity = 0.0;
97 HaveElectricEngine = false;
98 HasInitializedEngines = false;
103 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 FGPropulsion::~FGPropulsion()
107 for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
109 for (unsigned int i=0; i<Tanks.size(); i++) delete Tanks[i];
114 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116 bool FGPropulsion::InitModel(void)
118 if (!FGModel::InitModel()) return false;
120 for (unsigned int i=0; i<numTanks; i++) Tanks[i]->ResetToIC();
122 for (unsigned int i=0; i<numEngines; i++) {
123 switch (Engines[i]->GetType()) {
124 case FGEngine::etPiston:
125 ((FGPiston*)Engines[i])->ResetToIC();
126 if (HasInitializedEngines && (InitializedEngines & i)) InitRunning(i);
128 case FGEngine::etTurbine:
129 ((FGTurbine*)Engines[i])->ResetToIC();
130 if (HasInitializedEngines && (InitializedEngines & i)) InitRunning(i);
140 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142 bool FGPropulsion::Run(void)
146 if (FGModel::Run()) return true;
147 if (FDMExec->Holding()) return false;
151 double dt = FDMExec->GetDeltaT();
153 vForces.InitMatrix();
154 vMoments.InitMatrix();
156 for (i=0; i<numEngines; i++) {
157 Engines[i]->Calculate();
158 vForces += Engines[i]->GetBodyForces(); // sum body frame forces
159 vMoments += Engines[i]->GetMoments(); // sum body frame moments
162 TotalFuelQuantity = 0.0;
163 for (i=0; i<numTanks; i++) {
164 Tanks[i]->Calculate( dt * rate );
165 if (Tanks[i]->GetType() == FGTank::ttFUEL) {
166 TotalFuelQuantity += Tanks[i]->GetContents();
170 if (refuel) DoRefuel( dt * rate );
171 if (dump) DumpFuel( dt * rate );
178 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180 bool FGPropulsion::GetSteadyState(void)
182 double currentThrust = 0, lastThrust = -1;
183 int steady_count = 0, j = 0;
186 vForces.InitMatrix();
187 vMoments.InitMatrix();
189 if (!FGModel::Run()) {
190 for (unsigned int i=0; i<numEngines; i++) {
191 // cout << " Finding steady state for engine " << i << endl;
192 Engines[i]->SetTrimMode(true);
196 while (!steady && j < 6000) {
197 Engines[i]->Calculate();
198 lastThrust = currentThrust;
199 currentThrust = Engines[i]->GetThruster()->GetThrust();
200 if (fabs(lastThrust-currentThrust) < 0.0001) {
202 if (steady_count > 120) {
204 // cout << " Steady state found at thrust: " << currentThrust << " lbs." << endl;
212 // cout << " Could not find a steady state for this engine." << endl;
214 vForces += Engines[i]->GetBodyForces(); // sum body frame forces
215 vMoments += Engines[i]->GetMoments(); // sum body frame moments
216 Engines[i]->SetTrimMode(false);
225 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227 void FGPropulsion::InitRunning(int n)
229 if (n > 0) { // A specific engine is supposed to be initialized
231 if (n >= (int)GetNumEngines() ) {
232 cerr << "Tried to initialize a non-existent engine!" << endl;
235 FCS->SetThrottleCmd(n,1);
236 FCS->SetMixtureCmd(n,1);
237 GetEngine(n)->InitRunning();
240 InitializedEngines = 1 << n;
241 HasInitializedEngines = true;
243 } else if (n < 0) { // -1 refers to "All Engines"
245 for (unsigned int i=0; i<GetNumEngines(); i++) {
246 FCS->SetThrottleCmd(i,1);
247 FCS->SetMixtureCmd(i,1);
248 GetEngine(i)->InitRunning();
251 InitializedEngines = -1;
252 HasInitializedEngines = true;
254 } else if (n == 0) { // No engines are to be initialized
259 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261 bool FGPropulsion::Load(Element* el)
263 string type, engine_filename;
264 bool ThrottleAdded = false;
268 FGModel::Load(el); // Perform base class Load.
270 // Process tank definitions first to establish the number of fuel tanks
272 Element* tank_element = el->FindElement("tank");
273 while (tank_element) {
274 Tanks.push_back(new FGTank(FDMExec, tank_element, numTanks));
275 if (Tanks.back()->GetType() == FGTank::ttFUEL) numFuelTanks++;
276 else if (Tanks.back()->GetType() == FGTank::ttOXIDIZER) numOxiTanks++;
277 else {cerr << "Unknown tank type specified." << endl; return false;}
279 tank_element = el->FindNextElement("tank");
281 numSelectedFuelTanks = numFuelTanks;
282 numSelectedOxiTanks = numOxiTanks;
284 Element* engine_element = el->FindElement("engine");
285 while (engine_element) {
286 engine_filename = engine_element->GetAttributeValue("file");
288 if (engine_filename.empty()) {
289 cerr << "Engine definition did not supply an engine file." << endl;
293 engine_filename = FindEngineFullPathname(engine_filename);
294 document = LoadXMLDocument(engine_filename);
295 document->SetParent(engine_element);
297 type = document->GetName();
299 if (type == "piston_engine") {
300 HavePistonEngine = true;
301 if (!IsBound) bind();
302 Engines.push_back(new FGPiston(FDMExec, document, numEngines));
303 } else if (type == "turbine_engine") {
304 HaveTurbineEngine = true;
305 if (!IsBound) bind();
306 Engines.push_back(new FGTurbine(FDMExec, document, numEngines));
307 } else if (type == "turboprop_engine") {
308 HaveTurboPropEngine = true;
309 if (!IsBound) bind();
310 Engines.push_back(new FGTurboProp(FDMExec, document, numEngines));
311 } else if (type == "rocket_engine") {
312 HaveRocketEngine = true;
313 if (!IsBound) bind();
314 Engines.push_back(new FGRocket(FDMExec, document, numEngines));
315 } else if (type == "electric_engine") {
316 HaveElectricEngine = true;
317 if (!IsBound) bind();
318 Engines.push_back(new FGElectric(FDMExec, document, numEngines));
320 cerr << "Unknown engine type: " << type << endl;
323 } catch (std::string str) {
324 cerr << endl << fgred << str << reset << endl;
329 ThrottleAdded = true;
333 engine_element = el->FindNextElement("engine");
337 CalculateTankInertias();
338 if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
340 // Process fuel dump rate
341 if (el->FindElement("dump-rate"))
342 DumpRate = el->FindElementValueAsNumberConvertTo("dump-rate", "LBS/MIN");
344 PostLoad(el, PropertyManager);
349 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351 string FGPropulsion::FindEngineFullPathname(const string& engine_filename)
353 string fullpath, localpath;
354 string enginePath = FDMExec->GetEnginePath();
355 string aircraftPath = FDMExec->GetFullAircraftPath();
356 ifstream engine_file;
358 string separator = "/";
360 fullpath = enginePath + separator;
361 localpath = aircraftPath + separator + "Engines" + separator;
363 engine_file.open(string(fullpath + engine_filename + ".xml").c_str());
364 if ( !engine_file.is_open()) {
365 engine_file.open(string(localpath + engine_filename + ".xml").c_str());
366 if ( !engine_file.is_open()) {
367 cerr << " Could not open engine file: " << engine_filename << " in path "
368 << fullpath << " or " << localpath << endl;
371 return string(localpath + engine_filename + ".xml");
374 return string(fullpath + engine_filename + ".xml");
377 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379 ifstream* FGPropulsion::FindEngineFile(const string& engine_filename)
381 string fullpath, localpath;
382 string enginePath = FDMExec->GetEnginePath();
383 string aircraftPath = FDMExec->GetFullAircraftPath();
384 ifstream* engine_file = new ifstream();
386 string separator = "/";
388 fullpath = enginePath + separator;
389 localpath = aircraftPath + separator + "Engines" + separator;
391 engine_file->open(string(fullpath + engine_filename + ".xml").c_str());
392 if ( !engine_file->is_open()) {
393 engine_file->open(string(localpath + engine_filename + ".xml").c_str());
394 if ( !engine_file->is_open()) {
395 cerr << " Could not open engine file: " << engine_filename << " in path "
396 << fullpath << " or " << localpath << endl;
402 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404 string FGPropulsion::GetPropulsionStrings(const string& delimiter)
408 string PropulsionStrings = "";
409 bool firstime = true;
412 for (i=0; i<Engines.size(); i++) {
413 if (firstime) firstime = false;
414 else PropulsionStrings += delimiter;
416 PropulsionStrings += Engines[i]->GetEngineLabels(delimiter);
418 for (i=0; i<Tanks.size(); i++) {
419 if (Tanks[i]->GetType() == FGTank::ttFUEL) buf << delimiter << "Fuel Tank " << i;
420 else if (Tanks[i]->GetType() == FGTank::ttOXIDIZER) buf << delimiter << "Oxidizer Tank " << i;
423 return PropulsionStrings;
426 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
428 string FGPropulsion::GetPropulsionValues(const string& delimiter)
432 string PropulsionValues = "";
433 bool firstime = true;
436 for (i=0; i<Engines.size(); i++) {
437 if (firstime) firstime = false;
438 else PropulsionValues += delimiter;
440 PropulsionValues += Engines[i]->GetEngineValues(delimiter);
442 for (i=0; i<Tanks.size(); i++) {
444 buf << Tanks[i]->GetContents();
447 return PropulsionValues;
450 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
452 FGColumnVector3& FGPropulsion::GetTanksMoment(void)
454 vXYZtank_arm.InitMatrix();
455 for (unsigned int i=0; i<Tanks.size(); i++) {
456 vXYZtank_arm(eX) += Tanks[i]->GetXYZ(eX) * Tanks[i]->GetContents();
457 vXYZtank_arm(eY) += Tanks[i]->GetXYZ(eY) * Tanks[i]->GetContents();
458 vXYZtank_arm(eZ) += Tanks[i]->GetXYZ(eZ) * Tanks[i]->GetContents();
463 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
465 double FGPropulsion::GetTanksWeight(void)
469 for (unsigned int i=0; i<Tanks.size(); i++) Tw += Tanks[i]->GetContents();
474 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
476 FGMatrix33& FGPropulsion::CalculateTankInertias(void)
481 if (size == 0) return tankJ;
483 tankJ = FGMatrix33();
485 for (unsigned int i=0; i<size; i++) {
486 tankJ += MassBalance->GetPointmassInertia( lbtoslug * Tanks[i]->GetContents(),
487 Tanks[i]->GetXYZ() );
488 tankJ(1,1) += Tanks[i]->GetIxx();
489 tankJ(2,2) += Tanks[i]->GetIyy();
490 tankJ(3,3) += Tanks[i]->GetIzz();
496 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
498 void FGPropulsion::SetMagnetos(int setting)
500 if (ActiveEngine < 0) {
501 for (unsigned i=0; i<Engines.size(); i++) {
502 // ToDo: first need to make sure the engine Type is really appropriate:
503 // do a check to see if it is of type Piston. This should be done for
504 // all of this kind of possibly across-the-board settings.
505 ((FGPiston*)Engines[i])->SetMagnetos(setting);
508 ((FGPiston*)Engines[ActiveEngine])->SetMagnetos(setting);
512 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
514 void FGPropulsion::SetStarter(int setting)
516 if (ActiveEngine < 0) {
517 for (unsigned i=0; i<Engines.size(); i++) {
519 Engines[i]->SetStarter(false);
521 Engines[i]->SetStarter(true);
525 Engines[ActiveEngine]->SetStarter(false);
527 Engines[ActiveEngine]->SetStarter(true);
531 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533 void FGPropulsion::SetCutoff(int setting)
535 if (ActiveEngine < 0) {
536 for (unsigned i=0; i<Engines.size(); i++) {
538 ((FGTurbine*)Engines[i])->SetCutoff(false);
540 ((FGTurbine*)Engines[i])->SetCutoff(true);
544 ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(false);
546 ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(true);
550 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
552 void FGPropulsion::SetActiveEngine(int engine)
554 if (engine >= (int)Engines.size() || engine < 0)
557 ActiveEngine = engine;
560 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562 double FGPropulsion::Transfer(int source, int target, double amount)
564 double shortage, overage;
569 shortage = Tanks[source]->Drain(amount);
574 overage = Tanks[target]->Fill(amount - shortage);
579 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
581 void FGPropulsion::DoRefuel(double time_slice)
585 double fillrate = 100 * time_slice; // 100 lbs/sec = 6000 lbs/min
586 int TanksNotFull = 0;
588 for (i=0; i<numTanks; i++) {
589 if (Tanks[i]->GetPctFull() < 99.99) ++TanksNotFull;
593 for (i=0; i<numTanks; i++) {
594 if (Tanks[i]->GetPctFull() < 99.99)
595 Transfer(-1, i, fillrate/TanksNotFull);
600 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
602 void FGPropulsion::DumpFuel(double time_slice)
605 int TanksDumping = 0;
607 for (i=0; i<numTanks; i++) {
608 if (Tanks[i]->GetContents() > Tanks[i]->GetStandpipe()) ++TanksDumping;
611 if (TanksDumping == 0) return;
613 double dump_rate_per_tank = DumpRate / 60.0 * time_slice / TanksDumping;
615 for (i=0; i<numTanks; i++) {
616 if (Tanks[i]->GetContents() > Tanks[i]->GetStandpipe()) {
617 Transfer(i, -1, dump_rate_per_tank);
622 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
624 void FGPropulsion::SetFuelFreeze(bool f)
627 for (unsigned int i=0; i<numEngines; i++) {
628 Engines[i]->SetFuelFreeze(f);
632 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
634 void FGPropulsion::bind(void)
636 typedef double (FGPropulsion::*PMF)(int) const;
637 typedef int (FGPropulsion::*iPMF)(void) const;
640 PropertyManager->Tie("propulsion/set-running", this, (iPMF)0, &FGPropulsion::InitRunning, true);
641 if (HaveTurbineEngine) {
642 PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter, true);
643 PropertyManager->Tie("propulsion/cutoff_cmd", this, (iPMF)0, &FGPropulsion::SetCutoff, true);
646 if (HavePistonEngine) {
647 PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter, true);
648 PropertyManager->Tie("propulsion/magneto_cmd", this, (iPMF)0, &FGPropulsion::SetMagnetos, true);
651 PropertyManager->Tie("propulsion/active_engine", this, (iPMF)&FGPropulsion::GetActiveEngine,
652 &FGPropulsion::SetActiveEngine, true);
653 PropertyManager->Tie("propulsion/total-fuel-lbs", this, &FGPropulsion::GetTotalFuelQuantity);
654 PropertyManager->Tie("propulsion/refuel", this, &FGPropulsion::GetRefuel,
655 &FGPropulsion::SetRefuel, true);
656 PropertyManager->Tie("propulsion/fuel_dump", this, &FGPropulsion::GetFuelDump,
657 &FGPropulsion::SetFuelDump, true);
658 PropertyManager->Tie("forces/fbx-prop-lbs", this,1,
659 (PMF)&FGPropulsion::GetForces);
660 PropertyManager->Tie("forces/fby-prop-lbs", this,2,
661 (PMF)&FGPropulsion::GetForces);
662 PropertyManager->Tie("forces/fbz-prop-lbs", this,3,
663 (PMF)&FGPropulsion::GetForces);
664 PropertyManager->Tie("moments/l-prop-lbsft", this,1,
665 (PMF)&FGPropulsion::GetMoments);
666 PropertyManager->Tie("moments/m-prop-lbsft", this,2,
667 (PMF)&FGPropulsion::GetMoments);
668 PropertyManager->Tie("moments/n-prop-lbsft", this,3,
669 (PMF)&FGPropulsion::GetMoments);
673 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
674 // The bitmasked value choices are as follows:
675 // unset: In this case (the default) JSBSim would only print
676 // out the normally expected messages, essentially echoing
677 // the config files as they are read. If the environment
678 // variable is not set, debug_lvl is set to 1 internally
679 // 0: This requests JSBSim not to output any messages
681 // 1: This value explicity requests the normal JSBSim
683 // 2: This value asks for a message to be printed out when
684 // a class is instantiated
685 // 4: When this value is set, a message is displayed when a
686 // FGModel object executes its Run() method
687 // 8: When this value is set, various runtime state variables
688 // are printed out periodically
689 // 16: When set various parameters are sanity checked and
690 // a message is printed out when they go out of bounds
692 void FGPropulsion::Debug(int from)
694 if (debug_lvl <= 0) return;
696 if (debug_lvl & 1) { // Standard console startup message output
697 if (from == 2) { // Loader
698 cout << endl << " Propulsion:" << endl;
701 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
702 if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
703 if (from == 1) cout << "Destroyed: FGPropulsion" << endl;
705 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
707 if (debug_lvl & 8 ) { // Runtime state variables
709 if (debug_lvl & 16) { // Sanity checking
711 if (debug_lvl & 64) {
712 if (from == 0) { // Constructor
713 cout << IdSrc << endl;
714 cout << IdHdr << endl;