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