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