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