]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGPropulsion.cpp
Remove std::
[flightgear.git] / src / FDM / JSBSim / 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, tanks, and thrusters associated
7                with this aircraft
8
9  ------------- Copyright (C) 2000  Jon S. Berndt (jsb@hal-pc.org) -------------
10
11  This program is free software; you can redistribute it and/or modify it under
12  the terms of the GNU 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 General Public License for more
19  details.
20
21  You should have received a copy of the GNU 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 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, tanks, and "thrusters" (the device that transforms the
32 engine power into a force that acts on the aircraft, such as a nozzle or
33 propeller). Once the Propulsion class gets the config file, it reads in
34 information which is specific to a type of engine. Then:
35
36 1) The appropriate engine type instance is created
37 2) A thruster object is instantiated, and is linked to the engine
38 3) At least one tank object is created, and is linked to an engine.
39
40 At Run time each engines Calculate() method is called to return the excess power
41 generated during that iteration. The drag from the previous iteration is sub-
42 tracted to give the excess power available for thrust this pass. That quantity
43 is passed to the thrusters associated with a particular engine - perhaps with a
44 scaling mechanism (gearing?) to allow the engine to give its associated thrust-
45 ers specific distributed portions of the excess power.
46
47 HISTORY
48 --------------------------------------------------------------------------------
49 08/20/00   JSB   Created
50
51 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52 INCLUDES
53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
54
55 #include "FGPropulsion.h"
56 #include "FGPropertyManager.h"
57
58 #if defined (__APPLE__)
59 /* Not all systems have the gcvt function */
60 inline char* gcvt (double value, int ndigits, char *buf) {
61     /* note that this is not exactly what gcvt is supposed to do! */
62     snprintf (buf, ndigits+1, "%f", value);
63     return buf;
64 }
65 #endif
66
67 namespace JSBSim {
68
69 static const char *IdSrc = "$Id$";
70 static const char *IdHdr = ID_PROPULSION;
71
72 extern short debug_lvl;
73
74
75 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 CLASS IMPLEMENTATION
77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
78
79 FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
80 {
81   Name = "FGPropulsion";
82   numSelectedFuelTanks = numSelectedOxiTanks = 0;
83   numTanks = numEngines = numThrusters = 0;
84   numOxiTanks = numFuelTanks = 0;
85   dt = 0.0;
86   ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...
87   bind();
88   Debug(0);
89 }
90
91 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92
93 FGPropulsion::~FGPropulsion()
94 {
95   for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
96   Engines.clear();
97   unbind();
98   Debug(1);
99 }
100
101 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102
103 bool FGPropulsion::Run(void)
104 {
105   double PowerAvailable;
106   dt = State->Getdt();
107
108   vForces.InitMatrix();
109   vMoments.InitMatrix();
110
111   if (!FGModel::Run()) {
112     for (unsigned int i=0; i<numEngines; i++) {
113       Thrusters[i]->SetdeltaT(dt*rate);
114       PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
115       Thrusters[i]->Calculate(PowerAvailable);
116       vForces  += Thrusters[i]->GetBodyForces();  // sum body frame forces
117       vMoments += Thrusters[i]->GetMoments();     // sum body frame moments
118     }
119     return false;
120   } else {
121     return true;
122   }
123 }
124
125 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126
127 bool FGPropulsion::GetSteadyState(void)
128 {
129   double PowerAvailable;
130   double currentThrust = 0, lastThrust=-1;
131   dt = State->Getdt();
132   int steady_count,j=0;
133   bool steady=false;
134
135   vForces.InitMatrix();
136   vMoments.InitMatrix();
137
138   if (!FGModel::Run()) {
139     for (unsigned int i=0; i<numEngines; i++) {
140       Engines[i]->SetTrimMode(true);
141       Thrusters[i]->SetdeltaT(dt*rate);
142       steady=false;
143       steady_count=0;
144       while (!steady && j < 6000) {
145         PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
146         lastThrust = currentThrust;
147         currentThrust = Thrusters[i]->Calculate(PowerAvailable);
148         if (fabs(lastThrust-currentThrust) < 0.0001) {
149           steady_count++;
150           if (steady_count > 120) { steady=true; }
151         } else {
152           steady_count=0;
153         }
154         j++;
155       }
156       vForces  += Thrusters[i]->GetBodyForces();  // sum body frame forces
157       vMoments += Thrusters[i]->GetMoments();     // sum body frame moments
158       Engines[i]->SetTrimMode(false);
159     }
160
161     return false;
162   } else {
163     return true;
164   }
165 }
166
167 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168
169 bool FGPropulsion::ICEngineStart(void)
170 {
171   double PowerAvailable;
172   int j;
173   dt = State->Getdt();
174
175   vForces.InitMatrix();
176   vMoments.InitMatrix();
177
178   for (unsigned int i=0; i<numEngines; i++) {
179     Engines[i]->SetTrimMode(true);
180     Thrusters[i]->SetdeltaT(dt*rate);
181     j=0;
182     while (!Engines[i]->GetRunning() && j < 2000) {
183       PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
184       Thrusters[i]->Calculate(PowerAvailable);
185       j++;
186     }
187     vForces  += Thrusters[i]->GetBodyForces();  // sum body frame forces
188     vMoments += Thrusters[i]->GetMoments();     // sum body frame moments
189     Engines[i]->SetTrimMode(false);
190   }
191   return true;
192 }
193
194 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
195
196 bool FGPropulsion::Load(FGConfigFile* AC_cfg)
197 {
198   string token, fullpath;
199   string engineFileName, engType;
200   string thrusterFileName, thrType;
201   string parameter;
202   string enginePath = FDMExec->GetEnginePath();
203   double xLoc, yLoc, zLoc, Pitch, Yaw;
204   double P_Factor = 0, Sense = 0.0;
205   int Feed;
206   bool ThrottleAdded = false;
207
208 # ifndef macintosh
209       fullpath = enginePath + "/";
210 # else
211       fullpath = enginePath + ";";
212 # endif
213
214   AC_cfg->GetNextConfigLine();
215
216   while ((token = AC_cfg->GetValue()) != string("/PROPULSION")) {
217
218     if (token == "AC_ENGINE") {                   // ============ READING ENGINES
219
220       engineFileName = AC_cfg->GetValue("FILE");
221
222       if (debug_lvl > 0) cout << "\n    Reading engine from file: " << fullpath
223                                                 + engineFileName + ".xml"<< endl;
224       FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
225
226       if (Eng_cfg.IsOpen()) {
227         Eng_cfg.GetNextConfigLine();
228         engType = Eng_cfg.GetValue();
229         cout << engType << endl;
230
231         FCS->AddThrottle();
232         ThrottleAdded = true;
233
234         if (engType == "FG_ROCKET") {
235           Engines.push_back(new FGRocket(FDMExec, &Eng_cfg));
236         } else if (engType == "FG_PISTON") {
237           Engines.push_back(new FGPiston(FDMExec, &Eng_cfg));
238         } else if (engType == "FG_TURBINE") {
239           Engines.push_back(new FGTurbine(FDMExec, &Eng_cfg));
240         } else {
241           cerr << fgred << "    Unrecognized engine type: " << underon << engType
242                     << underoff << " found in config file." << fgdef << endl;
243           return false;
244         }
245
246         AC_cfg->GetNextConfigLine();
247         while ((token = AC_cfg->GetValue()) != string("/AC_ENGINE")) {
248           *AC_cfg >> token;
249           if      (token == "XLOC")  { *AC_cfg >> xLoc; }
250           else if (token == "YLOC")  { *AC_cfg >> yLoc; }
251           else if (token == "ZLOC")  { *AC_cfg >> zLoc; }
252           else if (token == "PITCH") { *AC_cfg >> Pitch;}
253           else if (token == "YAW")   { *AC_cfg >> Yaw;}
254           else if (token == "FEED")  {
255             *AC_cfg >> Feed;
256             Engines[numEngines]->AddFeedTank(Feed);
257             if (debug_lvl > 0) cout << "      Feed tank: " << Feed << endl;
258           } else cerr << "Unknown identifier: " << token << " in engine file: "
259                                                         << engineFileName << endl;
260         }
261
262         if (debug_lvl > 0)  {
263           cout << "      X = " << xLoc << endl;
264           cout << "      Y = " << yLoc << endl;
265           cout << "      Z = " << zLoc << endl;
266           cout << "      Pitch = " << Pitch << endl;
267           cout << "      Yaw = " << Yaw << endl;
268         }
269
270         Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw);
271         Engines[numEngines]->SetEngineNumber(numEngines);
272         numEngines++;
273
274       } else {
275
276         cerr << fgred << "\n  Could not read engine config file: " << underon <<
277                     fullpath + engineFileName + ".xml" << underoff << fgdef << endl;
278         return false;
279       }
280
281     } else if (token == "AC_TANK") {              // ============== READING TANKS
282
283       if (debug_lvl > 0) cout << "\n    Reading tank definition" << endl;
284       Tanks.push_back(new FGTank(AC_cfg));
285       switch(Tanks[numTanks]->GetType()) {
286       case FGTank::ttFUEL:
287         numSelectedFuelTanks++;
288         numFuelTanks++;
289         break;
290       case FGTank::ttOXIDIZER:
291         numSelectedOxiTanks++;
292         numOxiTanks++;
293         break;
294       }
295
296       numTanks++;
297
298     } else if (token == "AC_THRUSTER") {          // ========== READING THRUSTERS
299
300       thrusterFileName = AC_cfg->GetValue("FILE");
301
302       if (debug_lvl > 0) cout << "\n    Reading thruster from file: " <<
303                                     fullpath + thrusterFileName + ".xml" << endl;
304       FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");
305
306       if (Thruster_cfg.IsOpen()) {
307         Thruster_cfg.GetNextConfigLine();
308         thrType = Thruster_cfg.GetValue();
309
310         if (thrType == "FG_PROPELLER") {
311           Thrusters.push_back(new FGPropeller(FDMExec, &Thruster_cfg));
312         } else if (thrType == "FG_NOZZLE") {
313           Thrusters.push_back(new FGNozzle(FDMExec, &Thruster_cfg ));
314         } else if (thrType == "FG_DIRECT") {
315           Thrusters.push_back(new FGThruster( FDMExec, &Thruster_cfg) );
316         }  
317
318         AC_cfg->GetNextConfigLine();
319         while ((token = AC_cfg->GetValue()) != string("/AC_THRUSTER")) {
320           *AC_cfg >> token;
321           if (token == "XLOC") *AC_cfg >> xLoc;
322           else if (token == "YLOC") *AC_cfg >> yLoc;
323           else if (token == "ZLOC") *AC_cfg >> zLoc;
324           else if (token == "PITCH") *AC_cfg >> Pitch;
325           else if (token == "YAW") *AC_cfg >> Yaw;
326           else if (token == "P_FACTOR") *AC_cfg >> P_Factor;
327           else if (token == "SENSE")   *AC_cfg >> Sense;
328           else cerr << "Unknown identifier: " << token << " in engine file: "
329                                                         << engineFileName << endl;
330         }
331
332         Thrusters[numThrusters]->SetLocation(xLoc, yLoc, zLoc);
333         Thrusters[numThrusters]->SetAnglesToBody(0, Pitch, Yaw);
334         if (thrType == "FG_PROPELLER" && P_Factor > 0.001) {
335           ((FGPropeller*)Thrusters[numThrusters])->SetPFactor(P_Factor);
336           if (debug_lvl > 0) cout << "      P-Factor: " << P_Factor << endl;
337           ((FGPropeller*)Thrusters[numThrusters])->SetSense(fabs(Sense)/Sense);
338           if (debug_lvl > 0) cout << "      Sense: " << Sense <<  endl;
339         }
340         Thrusters[numThrusters]->SetdeltaT(dt*rate);
341         Thrusters[numThrusters]->SetThrusterNumber(numThrusters);
342         numThrusters++;
343
344       } else {
345         cerr << "Could not read thruster config file: " << fullpath
346                                                 + thrusterFileName + ".xml" << endl;
347         return false;
348       }
349
350     }
351     AC_cfg->GetNextConfigLine();
352   }
353
354   if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
355
356   return true;
357 }
358
359 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
360
361 string FGPropulsion::GetPropulsionStrings(void)
362 {
363   string PropulsionStrings = "";
364   bool firstime = true;
365   char buffer[5];
366
367   for (unsigned int i=0;i<Engines.size();i++) {
368     if (firstime)  firstime = false;
369     else           PropulsionStrings += ", ";
370
371     sprintf(buffer, "%d", i);
372
373     switch(Engines[i]->GetType()) {
374     case FGEngine::etPiston:
375       PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail[" + buffer + "]");
376       break;
377     case FGEngine::etRocket:
378       PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress[" + buffer + "]");
379       break;
380     case FGEngine::etTurbine:
381       break;
382     default:
383       PropulsionStrings += "INVALID ENGINE TYPE";
384       break;
385     }
386
387     PropulsionStrings += ", ";
388
389     FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
390     switch(Thrusters[i]->GetType()) {
391     case FGThruster::ttNozzle:
392       PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");
393       break;
394     case FGThruster::ttRotor:
395       break;
396     case FGThruster::ttPropeller:
397       PropulsionStrings += (Thrusters[i]->GetName() + "_Torque[" + buffer + "], ");
398       PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Roll[" + buffer + "], ");
399       PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Pitch[" + buffer + "], ");
400       PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Yaw[" + buffer + "], ");
401       PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "], ");
402       if (Propeller->IsVPitch())
403         PropulsionStrings += (Thrusters[i]->GetName() + "_Pitch[" + buffer + "], ");
404       PropulsionStrings += (Thrusters[i]->GetName() + "_RPM[" + buffer + "]");
405       break;
406     default:
407       PropulsionStrings += "INVALID THRUSTER TYPE";
408       break;
409     }
410   }
411
412   return PropulsionStrings;
413 }
414
415 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
416
417 string FGPropulsion::GetPropulsionValues(void)
418 {
419   char buff[20];
420   string PropulsionValues = "";
421   bool firstime = true;
422
423   for (unsigned int i=0;i<Engines.size();i++) {
424     if (firstime)  firstime = false;
425     else           PropulsionValues += ", ";
426
427     switch(Engines[i]->GetType()) {
428     case FGEngine::etPiston:
429       PropulsionValues += (string(gcvt(((FGPiston*)Engines[i])->GetPowerAvailable(), 10, buff)));
430       break;
431     case FGEngine::etRocket:
432       PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));
433       break;
434     case FGEngine::etTurbine:
435       break;
436     }
437
438     PropulsionValues += ", ";
439
440     switch(Thrusters[i]->GetType()) {
441     case FGThruster::ttNozzle:
442       PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));
443       break;
444     case FGThruster::ttRotor:
445       break;
446     case FGThruster::ttPropeller:
447       FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
448       FGColumnVector3 vPFactor = Propeller->GetPFactor();
449       PropulsionValues += string(gcvt(Propeller->GetTorque(), 10, buff)) + ", ";
450       PropulsionValues += string(gcvt(vPFactor(eRoll), 10, buff)) + ", ";
451       PropulsionValues += string(gcvt(vPFactor(ePitch), 10, buff)) + ", ";
452       PropulsionValues += string(gcvt(vPFactor(eYaw), 10, buff)) + ", ";
453       PropulsionValues += string(gcvt(Propeller->GetThrust(), 10, buff)) + ", ";
454       if (Propeller->IsVPitch())
455         PropulsionValues += string(gcvt(Propeller->GetPitch(), 10, buff)) + ", ";
456       PropulsionValues += string(gcvt(Propeller->GetRPM(), 10, buff));
457       break;
458     }
459   }
460
461   return PropulsionValues;
462 }
463
464 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
465
466 FGColumnVector3& FGPropulsion::GetTanksMoment(void)
467 {
468   iTank = Tanks.begin();
469   vXYZtank.InitMatrix();
470   while (iTank < Tanks.end()) {
471     vXYZtank(eX) += (*iTank)->GetX()*(*iTank)->GetContents();
472     vXYZtank(eY) += (*iTank)->GetY()*(*iTank)->GetContents();
473     vXYZtank(eZ) += (*iTank)->GetZ()*(*iTank)->GetContents();
474     iTank++;
475   }
476   return vXYZtank;
477 }
478
479 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
480
481 double FGPropulsion::GetTanksWeight(void)
482 {
483   double Tw = 0.0;
484
485   iTank = Tanks.begin();
486   while (iTank < Tanks.end()) {
487     Tw += (*iTank)->GetContents();
488     iTank++;
489   }
490   return Tw;
491 }
492
493 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
494
495 double FGPropulsion::GetTanksIxx(const FGColumnVector3& vXYZcg)
496 {
497   double I = 0.0;
498   iTank = Tanks.begin();
499   while (iTank < Tanks.end()) {
500     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetX() - vXYZcg(eX)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
501     iTank++;
502   }
503   return I;
504 }
505
506 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
507
508 double FGPropulsion::GetTanksIyy(const FGColumnVector3& vXYZcg)
509 {
510   double I = 0.0;
511   iTank = Tanks.begin();
512   while (iTank < Tanks.end()) {
513     I += ((*iTank)->GetY() - vXYZcg(eY))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
514     iTank++;
515   }
516   return I;
517 }
518
519 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520
521 double FGPropulsion::GetTanksIzz(const FGColumnVector3& vXYZcg)
522 {
523   double I = 0.0;
524   iTank = Tanks.begin();
525   while (iTank < Tanks.end()) {
526     I += ((*iTank)->GetZ() - vXYZcg(eZ))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
527     iTank++;
528   }
529   return I;
530 }
531
532 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533
534 double FGPropulsion::GetTanksIxz(const FGColumnVector3& vXYZcg)
535 {
536   double I = 0.0;
537   iTank = Tanks.begin();
538   while (iTank < Tanks.end()) {
539     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
540     iTank++;
541   }
542   return I;
543 }
544
545 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546
547 double FGPropulsion::GetTanksIxy(const FGColumnVector3& vXYZcg)
548 {
549   double I = 0.0;
550   iTank = Tanks.begin();
551   while (iTank != Tanks.end()) {
552     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
553     iTank++;
554   }
555   return I;
556 }
557
558 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
559
560 void FGPropulsion::SetMagnetos(int setting)
561 {
562   if (ActiveEngine == -1) {
563     for (unsigned i=0; i<Engines.size(); i++) {
564       Engines[i]->SetMagnetos(setting);
565     }
566   } else {
567     Engines[ActiveEngine]->SetMagnetos(setting);
568   }
569 }
570
571 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
572
573 void FGPropulsion::SetStarter(int setting)
574 {
575   if (ActiveEngine == -1) {
576     for (unsigned i=0; i<Engines.size(); i++) {
577       Engines[i]->SetStarter(setting);
578     }
579   } else {
580     if (setting == 0)
581       Engines[ActiveEngine]->SetStarter(false);
582     else
583       Engines[ActiveEngine]->SetStarter(true);
584   }
585 }
586
587 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
588
589 void FGPropulsion::SetActiveEngine(int engine)
590 {
591   if ( unsigned(engine) > Engines.size())
592     ActiveEngine = -1;
593   else
594     ActiveEngine = engine;
595 }
596
597 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
598
599 void FGPropulsion::bind(void)
600 {
601   typedef double (FGPropulsion::*PMF)(int) const;
602   typedef int (FGPropulsion::*iPMF)(void) const;
603   /* PropertyManager->Tie("propulsion/num-engines", this,
604                        &FGPropulsion::GetNumEngines);
605   PropertyManager->Tie("propulsion/num-tanks", this,
606                        &FGPropulsion::GetNumTanks); */
607
608   PropertyManager->Tie("propulsion/magneto_cmd", this,
609                        (iPMF)0,
610                        &FGPropulsion::SetMagnetos,
611                        true);
612   PropertyManager->Tie("propulsion/starter_cmd", this,
613                        (iPMF)0,
614                        &FGPropulsion::SetStarter,
615                        true);
616   PropertyManager->Tie("propulsion/active_engine", this,
617                        (iPMF)0,
618                        &FGPropulsion::SetActiveEngine,
619                        true);
620
621   PropertyManager->Tie("propulsion/num-sel-fuel-tanks", this,
622                        &FGPropulsion::GetnumSelectedFuelTanks);
623   PropertyManager->Tie("propulsion/num-sel-ox-tanks", this,
624                        &FGPropulsion::GetnumSelectedOxiTanks);
625   PropertyManager->Tie("forces/fbx-prop-lbs", this,1,
626                        (PMF)&FGPropulsion::GetForces);
627   PropertyManager->Tie("forces/fby-prop-lbs", this,2,
628                        (PMF)&FGPropulsion::GetForces);
629   PropertyManager->Tie("forces/fbz-prop-lbs", this,3,
630                        (PMF)&FGPropulsion::GetForces);
631   PropertyManager->Tie("moments/l-prop-lbsft", this,1,
632                        (PMF)&FGPropulsion::GetMoments);
633   PropertyManager->Tie("moments/m-prop-lbsft", this,2,
634                        (PMF)&FGPropulsion::GetMoments);
635   PropertyManager->Tie("moments/n-prop-lbsft", this,3,
636                        (PMF)&FGPropulsion::GetMoments);
637   //PropertyManager->Tie("propulsion/tanks-weight-lbs", this,
638   //                     &FGPropulsion::GetTanksWeight);
639 }
640
641 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
642
643 void FGPropulsion::unbind(void)
644 {
645   /* PropertyManager->Untie("propulsion/num-engines");
646   PropertyManager->Untie("propulsion/num-tanks"); */
647   PropertyManager->Untie("propulsion/num-sel-fuel-tanks");
648   PropertyManager->Untie("propulsion/num-sel-ox-tanks");
649   PropertyManager->Untie("propulsion/magneto_cmd");
650   PropertyManager->Untie("propulsion/starter_cmd");
651   PropertyManager->Untie("propulsion/active_engine");
652   PropertyManager->Untie("forces/fbx-prop-lbs");
653   PropertyManager->Untie("forces/fby-prop-lbs");
654   PropertyManager->Untie("forces/fbz-prop-lbs");
655   PropertyManager->Untie("moments/l-prop-lbsft");
656   PropertyManager->Untie("moments/m-prop-lbsft");
657   PropertyManager->Untie("moments/n-prop-lbsft");
658   //PropertyManager->Untie("propulsion/tanks-weight-lbs");
659 }
660
661 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 //    The bitmasked value choices are as follows:
663 //    unset: In this case (the default) JSBSim would only print
664 //       out the normally expected messages, essentially echoing
665 //       the config files as they are read. If the environment
666 //       variable is not set, debug_lvl is set to 1 internally
667 //    0: This requests JSBSim not to output any messages
668 //       whatsoever.
669 //    1: This value explicity requests the normal JSBSim
670 //       startup messages
671 //    2: This value asks for a message to be printed out when
672 //       a class is instantiated
673 //    4: When this value is set, a message is displayed when a
674 //       FGModel object executes its Run() method
675 //    8: When this value is set, various runtime state variables
676 //       are printed out periodically
677 //    16: When set various parameters are sanity checked and
678 //       a message is printed out when they go out of bounds
679
680 void FGPropulsion::Debug(int from)
681 {
682   if (debug_lvl <= 0) return;
683
684   if (debug_lvl & 1) { // Standard console startup message output
685     if (from == 0) { // Constructor
686
687     }
688   }
689   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
690     if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
691     if (from == 1) cout << "Destroyed:    FGPropulsion" << endl;
692   }
693   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
694   }
695   if (debug_lvl & 8 ) { // Runtime state variables
696   }
697   if (debug_lvl & 16) { // Sanity checking
698   }
699   if (debug_lvl & 64) {
700     if (from == 0) { // Constructor
701       cout << IdSrc << endl;
702       cout << IdHdr << endl;
703     }
704   }
705 }
706 }