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