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