]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/models/FGPropulsion.cpp
Sync with JSBSim cvs + Anders' patch to get it working with FlightGear.
[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 "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"
60 #include <iostream>
61 #include <sstream>
62 #include <cstdlib>
63
64 using namespace std;
65
66 namespace JSBSim {
67
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;
70
71 extern short debug_lvl;
72
73
74 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75 CLASS IMPLEMENTATION
76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
77
78 FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
79 {
80   Name = "FGPropulsion";
81
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 ...
87   tankJ.InitMatrix();
88   refuel = dump = false;
89   DumpRate = 0.0;
90   fuel_freeze = false;
91   TotalFuelQuantity = 0.0;
92   IsBound =
93   HavePistonEngine =
94   HaveTurbineEngine =
95   HaveRocketEngine =
96   HaveTurboPropEngine =
97   HaveElectricEngine = false;
98   HasInitializedEngines = false;
99
100   Debug(0);
101 }
102
103 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
104
105 FGPropulsion::~FGPropulsion()
106 {
107   for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
108   Engines.clear();
109   for (unsigned int i=0; i<Tanks.size(); i++) delete Tanks[i];
110   Tanks.clear();
111   Debug(1);
112 }
113
114 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115
116 bool FGPropulsion::InitModel(void)
117 {
118   if (!FGModel::InitModel()) return false;
119
120   for (unsigned int i=0; i<numTanks; i++) Tanks[i]->ResetToIC();
121
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);
127         break;
128       case FGEngine::etTurbine:
129         ((FGTurbine*)Engines[i])->ResetToIC();
130         if (HasInitializedEngines && (InitializedEngines & i)) InitRunning(i);
131         break;
132       default:
133         break;
134     }
135   }
136
137   return true;
138 }
139
140 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
141
142 bool FGPropulsion::Run(void)
143 {
144   unsigned int i;
145
146   if (FGModel::Run()) return true;
147   if (FDMExec->Holding()) return false;
148
149   RunPreFunctions();
150
151   double dt = FDMExec->GetDeltaT();
152
153   vForces.InitMatrix();
154   vMoments.InitMatrix();
155
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
160   }
161
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();
167     }
168   }
169
170   if (refuel) DoRefuel( dt * rate );
171   if (dump) DumpFuel( dt * rate );
172
173   RunPostFunctions();
174
175   return false;
176 }
177
178 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
179
180 bool FGPropulsion::GetSteadyState(void)
181 {
182   double currentThrust = 0, lastThrust = -1;
183   int steady_count = 0, j = 0;
184   bool steady = false;
185
186   vForces.InitMatrix();
187   vMoments.InitMatrix();
188
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);
193       steady=false;
194       steady_count=0;
195       j=0;
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) {
201           steady_count++;
202           if (steady_count > 120) {
203             steady=true;
204 //            cout << "    Steady state found at thrust: " << currentThrust << " lbs." << endl;
205           }
206         } else {
207           steady_count=0;
208         }
209         j++;
210       }
211 //      if (j >= 6000) {
212 //        cout << "    Could not find a steady state for this engine." << endl;
213 //      }
214       vForces  += Engines[i]->GetBodyForces();  // sum body frame forces
215       vMoments += Engines[i]->GetMoments();     // sum body frame moments
216       Engines[i]->SetTrimMode(false);
217     }
218
219     return false;
220   } else {
221     return true;
222   }
223 }
224
225 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226
227 void FGPropulsion::InitRunning(int n)
228 {
229   if (n > 0) { // A specific engine is supposed to be initialized
230
231     if (n >= (int)GetNumEngines() ) {
232       cerr << "Tried to initialize a non-existent engine!" << endl;
233       throw;
234     }
235     FCS->SetThrottleCmd(n,1);
236     FCS->SetMixtureCmd(n,1);
237     GetEngine(n)->InitRunning();
238     GetSteadyState();
239
240     InitializedEngines = 1 << n;
241     HasInitializedEngines = true;
242
243   } else if (n < 0) { // -1 refers to "All Engines"
244
245     for (unsigned int i=0; i<GetNumEngines(); i++) {
246       FCS->SetThrottleCmd(i,1);
247       FCS->SetMixtureCmd(i,1);
248       GetEngine(i)->InitRunning();
249     }
250     GetSteadyState();
251     InitializedEngines = -1;
252     HasInitializedEngines = true;
253
254   } else if (n == 0) { // No engines are to be initialized
255     // Do nothing
256   }
257 }
258
259 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260
261 bool FGPropulsion::Load(Element* el)
262 {
263   string type, engine_filename;
264   bool ThrottleAdded = false;
265
266   Debug(2);
267
268   FGModel::Load(el); // Perform base class Load.
269
270   // Process tank definitions first to establish the number of fuel tanks
271
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;}
278     numTanks++;
279     tank_element = el->FindNextElement("tank");
280   }
281   numSelectedFuelTanks = numFuelTanks;
282   numSelectedOxiTanks  = numOxiTanks;
283
284   Element* engine_element = el->FindElement("engine");
285   while (engine_element) {
286     engine_filename = engine_element->GetAttributeValue("file");
287
288     if (engine_filename.empty()) {
289       cerr << "Engine definition did not supply an engine file." << endl;
290       return false;
291     }
292
293     engine_filename = FindEngineFullPathname(engine_filename);
294     document = LoadXMLDocument(engine_filename);
295     document->SetParent(engine_element);
296
297     type = document->GetName();
298     try {
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     } catch (std::string str) {
324       cerr << endl << fgred << str << reset << endl;
325       return false;
326     }
327
328     FCS->AddThrottle();
329     ThrottleAdded = true;
330
331     numEngines++;
332
333     engine_element = el->FindNextElement("engine");
334     ResetParser();
335   }
336
337   CalculateTankInertias();
338   if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
339
340   // Process fuel dump rate
341   if (el->FindElement("dump-rate"))
342     DumpRate = el->FindElementValueAsNumberConvertTo("dump-rate", "LBS/MIN");
343
344   PostLoad(el, PropertyManager);
345
346   return true;
347 }
348
349 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350
351 string FGPropulsion::FindEngineFullPathname(const string& engine_filename)
352 {
353   string fullpath, localpath;
354   string enginePath = FDMExec->GetEnginePath();
355   string aircraftPath = FDMExec->GetFullAircraftPath();
356   ifstream engine_file;
357
358   string separator = "/";
359
360   fullpath = enginePath + separator;
361   localpath = aircraftPath + separator + "Engines" + separator;
362
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;
369         return string("");
370       } else {
371         return string(localpath + engine_filename + ".xml");
372       }
373   }
374   return string(fullpath + engine_filename + ".xml");
375 }
376
377 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378
379 ifstream* FGPropulsion::FindEngineFile(const string& engine_filename)
380 {
381   string fullpath, localpath;
382   string enginePath = FDMExec->GetEnginePath();
383   string aircraftPath = FDMExec->GetFullAircraftPath();
384   ifstream* engine_file = new ifstream();
385
386   string separator = "/";
387
388   fullpath = enginePath + separator;
389   localpath = aircraftPath + separator + "Engines" + separator;
390
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;
397       }
398   }
399   return engine_file;
400 }
401
402 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403
404 string FGPropulsion::GetPropulsionStrings(const string& delimiter)
405 {
406   unsigned int i;
407
408   string PropulsionStrings = "";
409   bool firstime = true;
410   stringstream buf;
411
412   for (i=0; i<Engines.size(); i++) {
413     if (firstime)  firstime = false;
414     else           PropulsionStrings += delimiter;
415
416     PropulsionStrings += Engines[i]->GetEngineLabels(delimiter);
417   }
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;
421   }
422
423   return PropulsionStrings;
424 }
425
426 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427
428 string FGPropulsion::GetPropulsionValues(const string& delimiter)
429 {
430   unsigned int i;
431
432   string PropulsionValues = "";
433   bool firstime = true;
434   stringstream buf;
435
436   for (i=0; i<Engines.size(); i++) {
437     if (firstime)  firstime = false;
438     else           PropulsionValues += delimiter;
439
440     PropulsionValues += Engines[i]->GetEngineValues(delimiter);
441   }
442   for (i=0; i<Tanks.size(); i++) {
443     buf << delimiter;
444     buf << Tanks[i]->GetContents();
445   }
446
447   return PropulsionValues;
448 }
449
450 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451
452 FGColumnVector3& FGPropulsion::GetTanksMoment(void)
453 {
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();
459   }
460   return vXYZtank_arm;
461 }
462
463 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
464
465 double FGPropulsion::GetTanksWeight(void)
466 {
467   double Tw = 0.0;
468
469   for (unsigned int i=0; i<Tanks.size(); i++) Tw += Tanks[i]->GetContents();
470
471   return Tw;
472 }
473
474 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
475
476 FGMatrix33& FGPropulsion::CalculateTankInertias(void)
477 {
478   unsigned int size;
479
480   size = Tanks.size();
481   if (size == 0) return tankJ;
482
483   tankJ = FGMatrix33();
484
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();
491   }
492
493   return tankJ;
494 }
495
496 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
497
498 void FGPropulsion::SetMagnetos(int setting)
499 {
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);
506     }
507   } else {
508     ((FGPiston*)Engines[ActiveEngine])->SetMagnetos(setting);
509   }
510 }
511
512 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
513
514 void FGPropulsion::SetStarter(int setting)
515 {
516   if (ActiveEngine < 0) {
517     for (unsigned i=0; i<Engines.size(); i++) {
518       if (setting == 0)
519         Engines[i]->SetStarter(false);
520       else
521         Engines[i]->SetStarter(true);
522     }
523   } else {
524     if (setting == 0)
525       Engines[ActiveEngine]->SetStarter(false);
526     else
527       Engines[ActiveEngine]->SetStarter(true);
528   }
529 }
530
531 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
532
533 void FGPropulsion::SetCutoff(int setting)
534 {
535   if (ActiveEngine < 0) {
536     for (unsigned i=0; i<Engines.size(); i++) {
537       if (setting == 0)
538         ((FGTurbine*)Engines[i])->SetCutoff(false);
539       else
540         ((FGTurbine*)Engines[i])->SetCutoff(true);
541     }
542   } else {
543     if (setting == 0)
544       ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(false);
545     else
546       ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(true);
547   }
548 }
549
550 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
551
552 void FGPropulsion::SetActiveEngine(int engine)
553 {
554   if (engine >= (int)Engines.size() || engine < 0)
555     ActiveEngine = -1;
556   else
557     ActiveEngine = engine;
558 }
559
560 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
561
562 double FGPropulsion::Transfer(int source, int target, double amount)
563 {
564  double shortage, overage;
565
566   if (source == -1) {
567      shortage = 0.0;
568   } else {
569      shortage = Tanks[source]->Drain(amount);
570   }
571   if (target == -1) {
572      overage = 0.0;
573   } else {
574      overage = Tanks[target]->Fill(amount - shortage);
575   }
576   return overage;
577 }
578
579 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
580
581 void FGPropulsion::DoRefuel(double time_slice)
582 {
583   unsigned int i;
584
585   double fillrate = 100 * time_slice;   // 100 lbs/sec = 6000 lbs/min
586   int TanksNotFull = 0;
587
588   for (i=0; i<numTanks; i++) {
589     if (Tanks[i]->GetPctFull() < 99.99) ++TanksNotFull;
590   }
591
592   if (TanksNotFull) {
593     for (i=0; i<numTanks; i++) {
594       if (Tanks[i]->GetPctFull() < 99.99)
595           Transfer(-1, i, fillrate/TanksNotFull);
596     }
597   }
598 }
599
600 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
601
602 void FGPropulsion::DumpFuel(double time_slice)
603 {
604   unsigned int i;
605   int TanksDumping = 0;
606
607   for (i=0; i<numTanks; i++) {
608     if (Tanks[i]->GetContents() > Tanks[i]->GetStandpipe()) ++TanksDumping;
609   }
610
611   if (TanksDumping == 0) return;
612
613   double dump_rate_per_tank = DumpRate / 60.0 * time_slice / TanksDumping;
614
615   for (i=0; i<numTanks; i++) {
616     if (Tanks[i]->GetContents() > Tanks[i]->GetStandpipe()) {
617       Transfer(i, -1, dump_rate_per_tank);
618     }
619   }
620 }
621
622 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
623
624 void FGPropulsion::SetFuelFreeze(bool f)
625 {
626   fuel_freeze = f;
627   for (unsigned int i=0; i<numEngines; i++) {
628     Engines[i]->SetFuelFreeze(f);
629   }
630 }
631
632 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
633
634 void FGPropulsion::bind(void)
635 {
636   typedef double (FGPropulsion::*PMF)(int) const;
637   typedef int (FGPropulsion::*iPMF)(void) const;
638
639   IsBound = true;
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);
644   }
645
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);
649   }
650
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);
670
671 }
672
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
680 //       whatsoever.
681 //    1: This value explicity requests the normal JSBSim
682 //       startup messages
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
691
692 void FGPropulsion::Debug(int from)
693 {
694   if (debug_lvl <= 0) return;
695
696   if (debug_lvl & 1) { // Standard console startup message output
697     if (from == 2) { // Loader
698       cout << endl << "  Propulsion:" << endl;
699     }
700   }
701   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
702     if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
703     if (from == 1) cout << "Destroyed:    FGPropulsion" << endl;
704   }
705   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
706   }
707   if (debug_lvl & 8 ) { // Runtime state variables
708   }
709   if (debug_lvl & 16) { // Sanity checking
710   }
711   if (debug_lvl & 64) {
712     if (from == 0) { // Constructor
713       cout << IdSrc << endl;
714       cout << IdHdr << endl;
715     }
716   }
717 }
718 }