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