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