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