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