]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/models/FGPropulsion.cpp
2ec2e2bb3551b1a76fddd29d3a9b29c71a05b7de
[flightgear.git] / src / FDM / JSBSim / models / FGPropulsion.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Module:       FGPropulsion.cpp
4  Author:       Jon S. Berndt
5  Date started: 08/20/00
6  Purpose:      Encapsulates the set of engines and tanks associated
7                with this aircraft
8
9  ------------- Copyright (C) 2000  Jon S. Berndt (jsb@hal-pc.org) -------------
10
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
14  version.
15
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
19  details.
20
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.
24
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.
27
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:
33
34 1) The appropriate engine type instance is created
35 2) At least one tank object is created, and is linked to an engine.
36
37 At Run time each engines Calculate() method is called.
38
39 HISTORY
40 --------------------------------------------------------------------------------
41 08/20/00   JSB   Created
42
43 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44 INCLUDES
45 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
46
47 #include "FGPropulsion.h"
48 #include <models/propulsion/FGRocket.h>
49 #include <models/propulsion/FGTurbine.h>
50 #include <models/propulsion/FGPiston.h>
51 #include <models/propulsion/FGElectric.h>
52 #include <models/propulsion/FGTurboProp.h>
53 #include <input_output/FGPropertyManager.h>
54 #include <input_output/FGXMLParse.h>
55 #include <math/FGColumnVector3.h>
56 #include <sstream>
57
58 namespace JSBSim {
59
60 static const char *IdSrc = "$Id$";
61 static const char *IdHdr = ID_PROPULSION;
62
63 extern short debug_lvl;
64
65
66 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67 CLASS IMPLEMENTATION
68 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
69
70 FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
71 {
72   Name = "FGPropulsion";
73
74   InitializedEngines = 0;
75   numSelectedFuelTanks = numSelectedOxiTanks = 0;
76   numTanks = numEngines = 0;
77   numOxiTanks = numFuelTanks = 0;
78   ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...
79   tankJ.InitMatrix();
80   refuel = dump = false;
81   DumpRate = 0.0;
82   fuel_freeze = false;
83   TotalFuelQuantity = 0.0;
84   IsBound =
85   HavePistonEngine =
86   HaveTurbineEngine =
87   HaveRocketEngine =
88   HaveTurboPropEngine =
89   HaveElectricEngine = false;
90   HasInitializedEngines = false;
91
92   Debug(0);
93 }
94
95 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
96
97 FGPropulsion::~FGPropulsion()
98 {
99   for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
100   Engines.clear();
101   for (unsigned int i=0; i<Tanks.size(); i++) delete Tanks[i];
102   Tanks.clear();
103   Debug(1);
104 }
105
106 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107
108 bool FGPropulsion::InitModel(void)
109 {
110   if (!FGModel::InitModel()) return false;
111
112   for (unsigned int i=0; i<numTanks; i++) Tanks[i]->ResetToIC();
113
114   for (unsigned int i=0; i<numEngines; i++) {
115     switch (Engines[i]->GetType()) {
116       case FGEngine::etPiston:
117         ((FGPiston*)Engines[i])->ResetToIC();
118         if (HasInitializedEngines && (InitializedEngines & i)) InitRunning(i);
119         break;
120       case FGEngine::etTurbine:
121         ((FGTurbine*)Engines[i])->ResetToIC();
122         if (HasInitializedEngines && (InitializedEngines & i)) InitRunning(i);
123         break;
124       default:
125         break;
126     }
127   }
128
129   return true;
130 }
131
132 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133
134 bool FGPropulsion::Run(void)
135 {
136   unsigned int i;
137
138   if (FGModel::Run()) return true;
139   if (FDMExec->Holding()) return false;
140
141   double dt = State->Getdt();
142
143   vForces.InitMatrix();
144   vMoments.InitMatrix();
145
146   for (i=0; i<numEngines; i++) {
147     Engines[i]->Calculate();
148     vForces  += Engines[i]->GetBodyForces();  // sum body frame forces
149     vMoments += Engines[i]->GetMoments();     // sum body frame moments
150   }
151
152   TotalFuelQuantity = 0.0;
153   for (i=0; i<numTanks; i++) {
154     Tanks[i]->Calculate( dt * rate );
155     if (Tanks[i]->GetType() == FGTank::ttFUEL) {
156       TotalFuelQuantity += Tanks[i]->GetContents();
157     }
158   }
159
160   if (refuel) DoRefuel( dt * rate );
161   if (dump) DumpFuel( dt * rate );
162
163   return false;
164 }
165
166 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167
168 bool FGPropulsion::GetSteadyState(void)
169 {
170   double currentThrust = 0, lastThrust = -1;
171   int steady_count = 0, j = 0;
172   bool steady = false;
173
174   vForces.InitMatrix();
175   vMoments.InitMatrix();
176
177   if (!FGModel::Run()) {
178     for (unsigned int i=0; i<numEngines; i++) {
179 //      cout << "  Finding steady state for engine " << i << endl;
180       Engines[i]->SetTrimMode(true);
181       steady=false;
182       steady_count=0;
183       j=0;
184       while (!steady && j < 6000) {
185         Engines[i]->Calculate();
186         lastThrust = currentThrust;
187         currentThrust = Engines[i]->GetThrust();
188         if (fabs(lastThrust-currentThrust) < 0.0001) {
189           steady_count++;
190           if (steady_count > 120) {
191             steady=true;
192 //            cout << "    Steady state found at thrust: " << currentThrust << " lbs." << endl;
193           }
194         } else {
195           steady_count=0;
196         }
197         j++;
198       }
199 //      if (j >= 6000) {
200 //        cout << "    Could not find a steady state for this engine." << endl;
201 //      }
202       vForces  += Engines[i]->GetBodyForces();  // sum body frame forces
203       vMoments += Engines[i]->GetMoments();     // sum body frame moments
204       Engines[i]->SetTrimMode(false);
205     }
206
207     return false;
208   } else {
209     return true;
210   }
211 }
212
213 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214
215 void FGPropulsion::InitRunning(int n)
216 {
217   if (n > 0) { // A specific engine is supposed to be initialized
218
219     if (n >= GetNumEngines() ) {
220       cerr << "Tried to initialize a non-existent engine!" << endl;
221       throw;
222     }
223     FCS->SetThrottleCmd(n,1);
224     FCS->SetMixtureCmd(n,1);
225     GetEngine(n)->InitRunning();
226     GetSteadyState();
227
228     InitializedEngines = 1 << n;
229     HasInitializedEngines = true;
230
231   } else if (n < 0) { // -1 refers to "All Engines"
232
233     for (unsigned int i=0; i<GetNumEngines(); i++) {
234       FCS->SetThrottleCmd(i,1);
235       FCS->SetMixtureCmd(i,1);
236       GetEngine(i)->InitRunning();
237     }
238     GetSteadyState();
239     InitializedEngines = -1;
240     HasInitializedEngines = true;
241
242   } else if (n == 0) { // No engines are to be initialized
243     // Do nothing
244   }
245 }
246
247 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248
249 bool FGPropulsion::Load(Element* el)
250 {
251   string type, engine_filename;
252   bool ThrottleAdded = false;
253
254   Debug(2);
255
256   Element* engine_element = el->FindElement("engine");
257   while (engine_element) {
258     engine_filename = engine_element->GetAttributeValue("file");
259
260     if (engine_filename.empty()) {
261       cerr << "Engine definition did not supply an engine file." << endl;
262       return false;
263     }
264
265     engine_filename = FindEngineFullPathname(engine_filename);
266     document = LoadXMLDocument(engine_filename);
267     document->SetParent(engine_element);
268
269     type = document->GetName();
270     if (type == "piston_engine") {
271       HavePistonEngine = true;
272       if (!IsBound) bind();
273       Engines.push_back(new FGPiston(FDMExec, document, numEngines));
274     } else if (type == "turbine_engine") {
275       HaveTurbineEngine = true;
276       if (!IsBound) bind();
277       Engines.push_back(new FGTurbine(FDMExec, document, numEngines));
278     } else if (type == "turboprop_engine") {
279       HaveTurboPropEngine = true;
280       if (!IsBound) bind();
281       Engines.push_back(new FGTurboProp(FDMExec, document, numEngines));
282     } else if (type == "rocket_engine") {
283       HaveRocketEngine = true;
284       if (!IsBound) bind();
285       Engines.push_back(new FGRocket(FDMExec, document, numEngines));
286     } else if (type == "electric_engine") {
287       HaveElectricEngine = true;
288       if (!IsBound) bind();
289       Engines.push_back(new FGElectric(FDMExec, document, numEngines));
290     } else {
291       cerr << "Unknown engine type: " << type << endl;
292       exit(-5);
293     }
294
295     FCS->AddThrottle();
296     ThrottleAdded = true;
297
298     numEngines++;
299
300     engine_element = el->FindNextElement("engine");
301     ResetParser();
302   }
303
304   // Process tank definitions
305
306   Element* tank_element = el->FindElement("tank");
307   while (tank_element) {
308     Tanks.push_back(new FGTank(FDMExec, tank_element, numTanks));
309     if (Tanks.back()->GetType() == FGTank::ttFUEL) numFuelTanks++;
310     else if (Tanks.back()->GetType() == FGTank::ttOXIDIZER) numOxiTanks++;
311     else {cerr << "Unknown tank type specified." << endl; return false;}
312     numTanks++;
313     tank_element = el->FindNextElement("tank");
314   }
315   numSelectedFuelTanks = numFuelTanks;
316   numSelectedOxiTanks  = numOxiTanks;
317
318   CalculateTankInertias();
319   if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
320
321   // Process fuel dump rate
322   if (el->FindElement("dump-rate"))
323     DumpRate = el->FindElementValueAsNumberConvertTo("dump-rate", "LBS/MIN");
324
325
326   return true;
327 }
328
329 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330
331 string FGPropulsion::FindEngineFullPathname(string engine_filename)
332 {
333   string fullpath, localpath;
334   string enginePath = FDMExec->GetEnginePath();
335   string aircraftPath = FDMExec->GetFullAircraftPath();
336   ifstream engine_file;
337
338   string separator = "/";
339
340   fullpath = enginePath + separator;
341   localpath = aircraftPath + separator + "Engines" + separator;
342
343   engine_file.open(string(fullpath + engine_filename + ".xml").c_str());
344   if ( !engine_file.is_open()) {
345     engine_file.open(string(localpath + engine_filename + ".xml").c_str());
346       if ( !engine_file.is_open()) {
347         cerr << " Could not open engine file: " << engine_filename << " in path "
348              << fullpath << " or " << localpath << endl;
349         return string("");
350       } else {
351         return string(localpath + engine_filename + ".xml");
352       }
353   }
354   return string(fullpath + engine_filename + ".xml");
355 }
356
357 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358
359 ifstream* FGPropulsion::FindEngineFile(string engine_filename)
360 {
361   string fullpath, localpath;
362   string enginePath = FDMExec->GetEnginePath();
363   string aircraftPath = FDMExec->GetFullAircraftPath();
364   ifstream* engine_file = new ifstream();
365
366   string separator = "/";
367
368   fullpath = enginePath + separator;
369   localpath = aircraftPath + separator + "Engines" + separator;
370
371   engine_file->open(string(fullpath + engine_filename + ".xml").c_str());
372   if ( !engine_file->is_open()) {
373     engine_file->open(string(localpath + engine_filename + ".xml").c_str());
374       if ( !engine_file->is_open()) {
375         cerr << " Could not open engine file: " << engine_filename << " in path "
376              << fullpath << " or " << localpath << endl;
377       }
378   }
379   return engine_file;
380 }
381
382 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383
384 string FGPropulsion::GetPropulsionStrings(string delimeter)
385 {
386   unsigned int i;
387
388   string PropulsionStrings = "";
389   bool firstime = true;
390   stringstream buf;
391
392   for (i=0; i<Engines.size(); i++) {
393     if (firstime)  firstime = false;
394     else           PropulsionStrings += delimeter;
395
396     PropulsionStrings += Engines[i]->GetEngineLabels(delimeter);
397   }
398   for (i=0; i<Tanks.size(); i++) {
399     if (Tanks[i]->GetType() == FGTank::ttFUEL) buf << delimeter << "Fuel Tank " << i;
400     else if (Tanks[i]->GetType() == FGTank::ttOXIDIZER) buf << delimeter << "Oxidizer Tank " << i;
401   }
402
403   return PropulsionStrings;
404 }
405
406 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407
408 string FGPropulsion::GetPropulsionValues(string delimeter)
409 {
410   unsigned int i;
411
412   string PropulsionValues = "";
413   bool firstime = true;
414   stringstream buf;
415
416   for (i=0; i<Engines.size(); i++) {
417     if (firstime)  firstime = false;
418     else           PropulsionValues += delimeter;
419
420     PropulsionValues += Engines[i]->GetEngineValues(delimeter);
421   }
422   for (i=0; i<Tanks.size(); i++) {
423     buf << delimeter;
424     buf << Tanks[i]->GetContents();
425   }
426
427   return PropulsionValues;
428 }
429
430 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
431
432 FGColumnVector3& FGPropulsion::GetTanksMoment(void)
433 {
434   vXYZtank_arm.InitMatrix();
435   for (unsigned int i=0; i<Tanks.size(); i++) {
436     vXYZtank_arm(eX) += Tanks[i]->GetXYZ(eX) * Tanks[i]->GetContents();
437     vXYZtank_arm(eY) += Tanks[i]->GetXYZ(eY) * Tanks[i]->GetContents();
438     vXYZtank_arm(eZ) += Tanks[i]->GetXYZ(eZ) * Tanks[i]->GetContents();
439   }
440   return vXYZtank_arm;
441 }
442
443 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
444
445 double FGPropulsion::GetTanksWeight(void)
446 {
447   double Tw = 0.0;
448
449   for (unsigned int i=0; i<Tanks.size(); i++) Tw += Tanks[i]->GetContents();
450
451   return Tw;
452 }
453
454 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
455
456 FGMatrix33& FGPropulsion::CalculateTankInertias(void)
457 {
458   unsigned int size;
459
460   size = Tanks.size();
461   if (size == 0) return tankJ;
462
463   tankJ = FGMatrix33();
464
465   for (unsigned int i=0; i<size; i++) {
466     tankJ += MassBalance->GetPointmassInertia( lbtoslug * Tanks[i]->GetContents(),
467                                                Tanks[i]->GetXYZ() );
468     tankJ(1,1) += Tanks[i]->GetIxx();
469     tankJ(2,2) += Tanks[i]->GetIyy();
470     tankJ(3,3) += Tanks[i]->GetIzz();
471   }
472
473   return tankJ;
474 }
475
476 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477
478 void FGPropulsion::SetMagnetos(int setting)
479 {
480   if (ActiveEngine < 0) {
481     for (unsigned i=0; i<Engines.size(); i++) {
482       // ToDo: first need to make sure the engine Type is really appropriate:
483       //   do a check to see if it is of type Piston. This should be done for
484       //   all of this kind of possibly across-the-board settings.
485       ((FGPiston*)Engines[i])->SetMagnetos(setting);
486     }
487   } else {
488     ((FGPiston*)Engines[ActiveEngine])->SetMagnetos(setting);
489   }
490 }
491
492 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493
494 void FGPropulsion::SetStarter(int setting)
495 {
496   if (ActiveEngine < 0) {
497     for (unsigned i=0; i<Engines.size(); i++) {
498       if (setting == 0)
499         Engines[i]->SetStarter(false);
500       else
501         Engines[i]->SetStarter(true);
502     }
503   } else {
504     if (setting == 0)
505       Engines[ActiveEngine]->SetStarter(false);
506     else
507       Engines[ActiveEngine]->SetStarter(true);
508   }
509 }
510
511 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512
513 void FGPropulsion::SetCutoff(int setting)
514 {
515   if (ActiveEngine < 0) {
516     for (unsigned i=0; i<Engines.size(); i++) {
517       if (setting == 0)
518         ((FGTurbine*)Engines[i])->SetCutoff(false);
519       else
520         ((FGTurbine*)Engines[i])->SetCutoff(true);
521     }
522   } else {
523     if (setting == 0)
524       ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(false);
525     else
526       ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(true);
527   }
528 }
529
530 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
531
532 void FGPropulsion::SetActiveEngine(int engine)
533 {
534   if (engine >= (int)Engines.size() || engine < 0)
535     ActiveEngine = -1;
536   else
537     ActiveEngine = engine;
538 }
539
540 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541
542 double FGPropulsion::Transfer(int source, int target, double amount)
543 {
544  double shortage, overage;
545
546   if (source == -1) {
547      shortage = 0.0;
548   } else {
549      shortage = Tanks[source]->Drain(amount);
550   }
551   if (target == -1) {
552      overage = 0.0;
553   } else {
554      overage = Tanks[target]->Fill(amount - shortage);
555   }
556   return overage;
557 }
558
559 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560
561 void FGPropulsion::DoRefuel(double time_slice)
562 {
563   unsigned int i;
564
565   double fillrate = 100 * time_slice;   // 100 lbs/sec = 6000 lbs/min
566   int TanksNotFull = 0;
567
568   for (i=0; i<numTanks; i++) {
569     if (Tanks[i]->GetPctFull() < 99.99) ++TanksNotFull;
570   }
571
572   if (TanksNotFull) {
573     for (i=0; i<numTanks; i++) {
574       if (Tanks[i]->GetPctFull() < 99.99)
575           Transfer(-1, i, fillrate/TanksNotFull);
576     }
577   }
578 }
579
580 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
581
582 void FGPropulsion::DumpFuel(double time_slice)
583 {
584   unsigned int i;
585   int TanksDumping = 0;
586
587   for (i=0; i<numTanks; i++) {
588     if (Tanks[i]->GetContents() > Tanks[i]->GetStandpipe()) ++TanksDumping;
589   }
590
591   if (TanksDumping == 0) return;
592
593   double dump_rate_per_tank = DumpRate / 60.0 * time_slice / TanksDumping;
594
595   for (i=0; i<numTanks; i++) {
596     if (Tanks[i]->GetContents() > Tanks[i]->GetStandpipe()) {
597       Transfer(i, -1, dump_rate_per_tank);
598     }
599   }
600 }
601
602 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
603
604 void FGPropulsion::SetFuelFreeze(bool f)
605 {
606   fuel_freeze = f;
607   for (unsigned int i=0; i<numEngines; i++) {
608     Engines[i]->SetFuelFreeze(f);
609   }
610 }
611
612 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
613
614 void FGPropulsion::bind(void)
615 {
616   typedef double (FGPropulsion::*PMF)(int) const;
617   typedef int (FGPropulsion::*iPMF)(void) const;
618
619   IsBound = true;
620   PropertyManager->Tie("propulsion/set-running", this, (iPMF)0, &FGPropulsion::InitRunning, true);
621   if (HaveTurbineEngine) {
622     PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter,  true);
623     PropertyManager->Tie("propulsion/cutoff_cmd", this,  (iPMF)0, &FGPropulsion::SetCutoff,   true);
624   }
625
626   if (HavePistonEngine) {
627     PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter,  true);
628     PropertyManager->Tie("propulsion/magneto_cmd", this, (iPMF)0, &FGPropulsion::SetMagnetos, true);
629   }
630
631   PropertyManager->Tie("propulsion/active_engine", this, (iPMF)&FGPropulsion::GetActiveEngine,
632                         &FGPropulsion::SetActiveEngine, true);
633   PropertyManager->Tie("propulsion/total-fuel-lbs", this, &FGPropulsion::GetTotalFuelQuantity);
634   PropertyManager->Tie("propulsion/refuel", this, &FGPropulsion::GetRefuel,
635                         &FGPropulsion::SetRefuel, true);
636   PropertyManager->Tie("propulsion/fuel_dump", this, &FGPropulsion::GetFuelDump,
637                         &FGPropulsion::SetFuelDump, true);
638   PropertyManager->Tie("forces/fbx-prop-lbs", this,1,
639                        (PMF)&FGPropulsion::GetForces);
640   PropertyManager->Tie("forces/fby-prop-lbs", this,2,
641                        (PMF)&FGPropulsion::GetForces);
642   PropertyManager->Tie("forces/fbz-prop-lbs", this,3,
643                        (PMF)&FGPropulsion::GetForces);
644   PropertyManager->Tie("moments/l-prop-lbsft", this,1,
645                        (PMF)&FGPropulsion::GetMoments);
646   PropertyManager->Tie("moments/m-prop-lbsft", this,2,
647                        (PMF)&FGPropulsion::GetMoments);
648   PropertyManager->Tie("moments/n-prop-lbsft", this,3,
649                        (PMF)&FGPropulsion::GetMoments);
650
651 }
652
653 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654 //    The bitmasked value choices are as follows:
655 //    unset: In this case (the default) JSBSim would only print
656 //       out the normally expected messages, essentially echoing
657 //       the config files as they are read. If the environment
658 //       variable is not set, debug_lvl is set to 1 internally
659 //    0: This requests JSBSim not to output any messages
660 //       whatsoever.
661 //    1: This value explicity requests the normal JSBSim
662 //       startup messages
663 //    2: This value asks for a message to be printed out when
664 //       a class is instantiated
665 //    4: When this value is set, a message is displayed when a
666 //       FGModel object executes its Run() method
667 //    8: When this value is set, various runtime state variables
668 //       are printed out periodically
669 //    16: When set various parameters are sanity checked and
670 //       a message is printed out when they go out of bounds
671
672 void FGPropulsion::Debug(int from)
673 {
674   if (debug_lvl <= 0) return;
675
676   if (debug_lvl & 1) { // Standard console startup message output
677     if (from == 2) { // Loader
678       cout << endl << "  Propulsion:" << endl;
679     }
680   }
681   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
682     if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
683     if (from == 1) cout << "Destroyed:    FGPropulsion" << endl;
684   }
685   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
686   }
687   if (debug_lvl & 8 ) { // Runtime state variables
688   }
689   if (debug_lvl & 16) { // Sanity checking
690   }
691   if (debug_lvl & 64) {
692     if (from == 0) { // Constructor
693       cout << IdSrc << endl;
694       cout << IdHdr << endl;
695     }
696   }
697 }
698 }