]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/models/FGPropulsion.cpp
Fix for bug #204 and #222 by Bertrand Coconnier; NaNs (bug #222) were basically gener...
[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         if (!IsBound) bind();
311         Engines.push_back(new FGPiston(FDMExec, document, numEngines));
312       } else if (type == "turbine_engine") {
313         HaveTurbineEngine = true;
314         if (!IsBound) bind();
315         Engines.push_back(new FGTurbine(FDMExec, document, numEngines));
316       } else if (type == "turboprop_engine") {
317         HaveTurboPropEngine = true;
318         if (!IsBound) bind();
319         Engines.push_back(new FGTurboProp(FDMExec, document, numEngines));
320       } else if (type == "rocket_engine") {
321         HaveRocketEngine = true;
322         if (!IsBound) bind();
323         Engines.push_back(new FGRocket(FDMExec, document, numEngines));
324       } else if (type == "electric_engine") {
325         HaveElectricEngine = true;
326         if (!IsBound) bind();
327         Engines.push_back(new FGElectric(FDMExec, document, numEngines));
328       } else {
329         cerr << "Unknown engine type: " << type << endl;
330         exit(-5);
331       }
332     } catch (std::string str) {
333       cerr << endl << fgred << str << reset << endl;
334       return false;
335     }
336
337     FDMExec->GetFCS()->AddThrottle();
338     ThrottleAdded = true;
339
340     numEngines++;
341
342     engine_element = el->FindNextElement("engine");
343     ResetParser();
344   }
345
346   CalculateTankInertias();
347   if (!ThrottleAdded) FDMExec->GetFCS()->AddThrottle(); // need to have at least one throttle
348
349   // Process fuel dump rate
350   if (el->FindElement("dump-rate"))
351     DumpRate = el->FindElementValueAsNumberConvertTo("dump-rate", "LBS/MIN");
352
353   PostLoad(el, PropertyManager);
354
355   return true;
356 }
357
358 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
359
360 string FGPropulsion::FindEngineFullPathname(const string& engine_filename)
361 {
362   string fullpath, localpath;
363   string enginePath = FDMExec->GetEnginePath();
364   string aircraftPath = FDMExec->GetFullAircraftPath();
365   ifstream engine_file;
366
367   string separator = "/";
368
369   fullpath = enginePath + separator;
370   localpath = aircraftPath + separator + "Engines" + separator;
371
372   engine_file.open(string(fullpath + engine_filename + ".xml").c_str());
373   if ( !engine_file.is_open()) {
374     engine_file.open(string(localpath + engine_filename + ".xml").c_str());
375       if ( !engine_file.is_open()) {
376         cerr << " Could not open engine file: " << engine_filename << " in path "
377              << fullpath << " or " << localpath << endl;
378         return string("");
379       } else {
380         return string(localpath + engine_filename + ".xml");
381       }
382   }
383   return string(fullpath + engine_filename + ".xml");
384 }
385
386 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
387
388 ifstream* FGPropulsion::FindEngineFile(const string& engine_filename)
389 {
390   string fullpath, localpath;
391   string enginePath = FDMExec->GetEnginePath();
392   string aircraftPath = FDMExec->GetFullAircraftPath();
393   ifstream* engine_file = new ifstream();
394
395   string separator = "/";
396
397   fullpath = enginePath + separator;
398   localpath = aircraftPath + separator + "Engines" + separator;
399
400   engine_file->open(string(fullpath + engine_filename + ".xml").c_str());
401   if ( !engine_file->is_open()) {
402     engine_file->open(string(localpath + engine_filename + ".xml").c_str());
403       if ( !engine_file->is_open()) {
404         cerr << " Could not open engine file: " << engine_filename << " in path "
405              << fullpath << " or " << localpath << endl;
406       }
407   }
408   return engine_file;
409 }
410
411 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412
413 string FGPropulsion::GetPropulsionStrings(const string& delimiter) const
414 {
415   unsigned int i;
416
417   string PropulsionStrings = "";
418   bool firstime = true;
419   stringstream buf;
420
421   for (i=0; i<Engines.size(); i++) {
422     if (firstime)  firstime = false;
423     else           PropulsionStrings += delimiter;
424
425     PropulsionStrings += Engines[i]->GetEngineLabels(delimiter);
426   }
427   for (i=0; i<Tanks.size(); i++) {
428     if (Tanks[i]->GetType() == FGTank::ttFUEL) buf << delimiter << "Fuel Tank " << i;
429     else if (Tanks[i]->GetType() == FGTank::ttOXIDIZER) buf << delimiter << "Oxidizer Tank " << i;
430   }
431
432   return PropulsionStrings;
433 }
434
435 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436
437 string FGPropulsion::GetPropulsionValues(const string& delimiter) const
438 {
439   unsigned int i;
440
441   string PropulsionValues = "";
442   bool firstime = true;
443   stringstream buf;
444
445   for (i=0; i<Engines.size(); i++) {
446     if (firstime)  firstime = false;
447     else           PropulsionValues += delimiter;
448
449     PropulsionValues += Engines[i]->GetEngineValues(delimiter);
450   }
451   for (i=0; i<Tanks.size(); i++) {
452     buf << delimiter;
453     buf << Tanks[i]->GetContents();
454   }
455
456   return PropulsionValues;
457 }
458
459 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
460
461 FGColumnVector3& FGPropulsion::GetTanksMoment(void)
462 {
463   vXYZtank_arm.InitMatrix();
464   for (unsigned int i=0; i<Tanks.size(); i++) {
465     vXYZtank_arm(eX) += Tanks[i]->GetXYZ(eX) * Tanks[i]->GetContents();
466     vXYZtank_arm(eY) += Tanks[i]->GetXYZ(eY) * Tanks[i]->GetContents();
467     vXYZtank_arm(eZ) += Tanks[i]->GetXYZ(eZ) * Tanks[i]->GetContents();
468   }
469   return vXYZtank_arm;
470 }
471
472 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473
474 double FGPropulsion::GetTanksWeight(void)
475 {
476   double Tw = 0.0;
477
478   for (unsigned int i=0; i<Tanks.size(); i++) Tw += Tanks[i]->GetContents();
479
480   return Tw;
481 }
482
483 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484
485 FGMatrix33& FGPropulsion::CalculateTankInertias(void)
486 {
487   unsigned int size;
488
489   size = Tanks.size();
490   if (size == 0) return tankJ;
491
492   tankJ = FGMatrix33();
493
494   for (unsigned int i=0; i<size; i++) {
495     tankJ += FDMExec->GetMassBalance()->GetPointmassInertia( lbtoslug * Tanks[i]->GetContents(),
496                                                Tanks[i]->GetXYZ() );
497     tankJ(1,1) += Tanks[i]->GetIxx();
498     tankJ(2,2) += Tanks[i]->GetIyy();
499     tankJ(3,3) += Tanks[i]->GetIzz();
500   }
501
502   return tankJ;
503 }
504
505 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
506
507 void FGPropulsion::SetMagnetos(int setting)
508 {
509   if (ActiveEngine < 0) {
510     for (unsigned i=0; i<Engines.size(); i++) {
511       // ToDo: first need to make sure the engine Type is really appropriate:
512       //   do a check to see if it is of type Piston. This should be done for
513       //   all of this kind of possibly across-the-board settings.
514       ((FGPiston*)Engines[i])->SetMagnetos(setting);
515     }
516   } else {
517     ((FGPiston*)Engines[ActiveEngine])->SetMagnetos(setting);
518   }
519 }
520
521 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
522
523 void FGPropulsion::SetStarter(int setting)
524 {
525   if (ActiveEngine < 0) {
526     for (unsigned i=0; i<Engines.size(); i++) {
527       if (setting == 0)
528         Engines[i]->SetStarter(false);
529       else
530         Engines[i]->SetStarter(true);
531     }
532   } else {
533     if (setting == 0)
534       Engines[ActiveEngine]->SetStarter(false);
535     else
536       Engines[ActiveEngine]->SetStarter(true);
537   }
538 }
539
540 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541
542 void FGPropulsion::SetCutoff(int setting)
543 {
544   if (ActiveEngine < 0) {
545     for (unsigned i=0; i<Engines.size(); i++) {
546       if (setting == 0)
547         ((FGTurbine*)Engines[i])->SetCutoff(false);
548       else
549         ((FGTurbine*)Engines[i])->SetCutoff(true);
550     }
551   } else {
552     if (setting == 0)
553       ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(false);
554     else
555       ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(true);
556   }
557 }
558
559 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560
561 void FGPropulsion::SetActiveEngine(int engine)
562 {
563   if (engine >= (int)Engines.size() || engine < 0)
564     ActiveEngine = -1;
565   else
566     ActiveEngine = engine;
567 }
568
569 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
570
571 double FGPropulsion::Transfer(int source, int target, double amount)
572 {
573  double shortage, overage;
574
575   if (source == -1) {
576      shortage = 0.0;
577   } else {
578      shortage = Tanks[source]->Drain(amount);
579   }
580   if (target == -1) {
581      overage = 0.0;
582   } else {
583      overage = Tanks[target]->Fill(amount - shortage);
584   }
585   return overage;
586 }
587
588 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
589
590 void FGPropulsion::DoRefuel(double time_slice)
591 {
592   unsigned int i;
593
594   double fillrate = 100 * time_slice;   // 100 lbs/sec = 6000 lbs/min
595   int TanksNotFull = 0;
596
597   for (i=0; i<numTanks; i++) {
598     if (Tanks[i]->GetPctFull() < 99.99) ++TanksNotFull;
599   }
600
601   if (TanksNotFull) {
602     for (i=0; i<numTanks; i++) {
603       if (Tanks[i]->GetPctFull() < 99.99)
604           Transfer(-1, i, fillrate/TanksNotFull);
605     }
606   }
607 }
608
609 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
610
611 void FGPropulsion::DumpFuel(double time_slice)
612 {
613   unsigned int i;
614   int TanksDumping = 0;
615
616   for (i=0; i<numTanks; i++) {
617     if (Tanks[i]->GetContents() > Tanks[i]->GetStandpipe()) ++TanksDumping;
618   }
619
620   if (TanksDumping == 0) return;
621
622   double dump_rate_per_tank = DumpRate / 60.0 * time_slice / TanksDumping;
623
624   for (i=0; i<numTanks; i++) {
625     if (Tanks[i]->GetContents() > Tanks[i]->GetStandpipe()) {
626       Transfer(i, -1, dump_rate_per_tank);
627     }
628   }
629 }
630
631 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
632
633 void FGPropulsion::SetFuelFreeze(bool f)
634 {
635   fuel_freeze = f;
636   for (unsigned int i=0; i<numEngines; i++) {
637     Engines[i]->SetFuelFreeze(f);
638   }
639 }
640
641 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
642
643 void FGPropulsion::bind(void)
644 {
645   typedef double (FGPropulsion::*PMF)(int) const;
646   typedef int (FGPropulsion::*iPMF)(void) const;
647
648   IsBound = true;
649   PropertyManager->Tie("propulsion/set-running", this, (iPMF)0, &FGPropulsion::InitRunning, false);
650   if (HaveTurbineEngine) {
651     PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter,  true);
652     PropertyManager->Tie("propulsion/cutoff_cmd", this,  (iPMF)0, &FGPropulsion::SetCutoff,   true);
653   }
654
655   if (HavePistonEngine) {
656     PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter,  true);
657     PropertyManager->Tie("propulsion/magneto_cmd", this, (iPMF)0, &FGPropulsion::SetMagnetos, true);
658   }
659
660   PropertyManager->Tie("propulsion/active_engine", this, (iPMF)&FGPropulsion::GetActiveEngine,
661                         &FGPropulsion::SetActiveEngine, true);
662   PropertyManager->Tie("propulsion/total-fuel-lbs", this, &FGPropulsion::GetTotalFuelQuantity);
663   PropertyManager->Tie("propulsion/refuel", this, &FGPropulsion::GetRefuel,
664                         &FGPropulsion::SetRefuel, true);
665   PropertyManager->Tie("propulsion/fuel_dump", this, &FGPropulsion::GetFuelDump,
666                         &FGPropulsion::SetFuelDump, true);
667   PropertyManager->Tie("forces/fbx-prop-lbs", this,1,
668                        (PMF)&FGPropulsion::GetForces);
669   PropertyManager->Tie("forces/fby-prop-lbs", this,2,
670                        (PMF)&FGPropulsion::GetForces);
671   PropertyManager->Tie("forces/fbz-prop-lbs", this,3,
672                        (PMF)&FGPropulsion::GetForces);
673   PropertyManager->Tie("moments/l-prop-lbsft", this,1,
674                        (PMF)&FGPropulsion::GetMoments);
675   PropertyManager->Tie("moments/m-prop-lbsft", this,2,
676                        (PMF)&FGPropulsion::GetMoments);
677   PropertyManager->Tie("moments/n-prop-lbsft", this,3,
678                        (PMF)&FGPropulsion::GetMoments);
679
680 }
681
682 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
683 //    The bitmasked value choices are as follows:
684 //    unset: In this case (the default) JSBSim would only print
685 //       out the normally expected messages, essentially echoing
686 //       the config files as they are read. If the environment
687 //       variable is not set, debug_lvl is set to 1 internally
688 //    0: This requests JSBSim not to output any messages
689 //       whatsoever.
690 //    1: This value explicity requests the normal JSBSim
691 //       startup messages
692 //    2: This value asks for a message to be printed out when
693 //       a class is instantiated
694 //    4: When this value is set, a message is displayed when a
695 //       FGModel object executes its Run() method
696 //    8: When this value is set, various runtime state variables
697 //       are printed out periodically
698 //    16: When set various parameters are sanity checked and
699 //       a message is printed out when they go out of bounds
700
701 void FGPropulsion::Debug(int from)
702 {
703   if (debug_lvl <= 0) return;
704
705   if (debug_lvl & 1) { // Standard console startup message output
706     if (from == 2) { // Loader
707       cout << endl << "  Propulsion:" << endl;
708     }
709   }
710   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
711     if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
712     if (from == 1) cout << "Destroyed:    FGPropulsion" << endl;
713   }
714   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
715   }
716   if (debug_lvl & 8 ) { // Runtime state variables
717   }
718   if (debug_lvl & 16) { // Sanity checking
719   }
720   if (debug_lvl & 64) {
721     if (from == 0) { // Constructor
722       cout << IdSrc << endl;
723       cout << IdHdr << endl;
724     }
725   }
726 }
727 }