]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGPropulsion.cpp
Added FGTurbine.[ch]*
[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_TURBOJET") {
237           Engines.push_back(new FGTurboJet(FDMExec, &Eng_cfg));
238         } else if (engType == "FG_TURBOSHAFT") {
239           Engines.push_back(new FGTurboShaft(FDMExec, &Eng_cfg));
240         } else if (engType == "FG_TURBOPROP") {
241           Engines.push_back(new FGTurboProp(FDMExec, &Eng_cfg));
242         } else {
243           cerr << fgred << "    Unrecognized engine type: " << underon << engType
244                     << underoff << " found in config file." << fgdef << endl;
245           return false;
246         }
247
248         AC_cfg->GetNextConfigLine();
249         while ((token = AC_cfg->GetValue()) != string("/AC_ENGINE")) {
250           *AC_cfg >> token;
251           if      (token == "XLOC")  { *AC_cfg >> xLoc; }
252           else if (token == "YLOC")  { *AC_cfg >> yLoc; }
253           else if (token == "ZLOC")  { *AC_cfg >> zLoc; }
254           else if (token == "PITCH") { *AC_cfg >> Pitch;}
255           else if (token == "YAW")   { *AC_cfg >> Yaw;}
256           else if (token == "FEED")  {
257             *AC_cfg >> Feed;
258             Engines[numEngines]->AddFeedTank(Feed);
259             if (debug_lvl > 0) cout << "      Feed tank: " << Feed << endl;
260           } else cerr << "Unknown identifier: " << token << " in engine file: "
261                                                         << engineFileName << endl;
262         }
263
264         if (debug_lvl > 0)  {
265           cout << "      X = " << xLoc << endl;
266           cout << "      Y = " << yLoc << endl;
267           cout << "      Z = " << zLoc << endl;
268           cout << "      Pitch = " << Pitch << endl;
269           cout << "      Yaw = " << Yaw << endl;
270         }
271
272         Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw);
273         Engines[numEngines]->SetEngineNumber(numEngines);
274         numEngines++;
275
276       } else {
277
278         cerr << fgred << "\n  Could not read engine config file: " << underon <<
279                     fullpath + engineFileName + ".xml" << underoff << fgdef << endl;
280         return false;
281       }
282
283     } else if (token == "AC_TANK") {              // ============== READING TANKS
284
285       if (debug_lvl > 0) cout << "\n    Reading tank definition" << endl;
286       Tanks.push_back(new FGTank(AC_cfg));
287       switch(Tanks[numTanks]->GetType()) {
288       case FGTank::ttFUEL:
289         numSelectedFuelTanks++;
290         numFuelTanks++;
291         break;
292       case FGTank::ttOXIDIZER:
293         numSelectedOxiTanks++;
294         numOxiTanks++;
295         break;
296       }
297
298       numTanks++;
299
300     } else if (token == "AC_THRUSTER") {          // ========== READING THRUSTERS
301
302       thrusterFileName = AC_cfg->GetValue("FILE");
303
304       if (debug_lvl > 0) cout << "\n    Reading thruster from file: " <<
305                                     fullpath + thrusterFileName + ".xml" << endl;
306       FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");
307
308       if (Thruster_cfg.IsOpen()) {
309         Thruster_cfg.GetNextConfigLine();
310         thrType = Thruster_cfg.GetValue();
311
312         if (thrType == "FG_PROPELLER") {
313           Thrusters.push_back(new FGPropeller(FDMExec, &Thruster_cfg));
314         } else if (thrType == "FG_NOZZLE") {
315           Thrusters.push_back(new FGNozzle(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     default:
381       PropulsionStrings += "INVALID ENGINE TYPE";
382       break;
383     }
384
385     PropulsionStrings += ", ";
386
387     FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
388     switch(Thrusters[i]->GetType()) {
389     case FGThruster::ttNozzle:
390       PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");
391       break;
392     case FGThruster::ttRotor:
393       break;
394     case FGThruster::ttPropeller:
395       PropulsionStrings += (Thrusters[i]->GetName() + "_Torque[" + buffer + "], ");
396       PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Roll[" + buffer + "], ");
397       PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Pitch[" + buffer + "], ");
398       PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Yaw[" + buffer + "], ");
399       PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "], ");
400       if (Propeller->IsVPitch())
401         PropulsionStrings += (Thrusters[i]->GetName() + "_Pitch[" + buffer + "], ");
402       PropulsionStrings += (Thrusters[i]->GetName() + "_RPM[" + buffer + "]");
403       break;
404     default:
405       PropulsionStrings += "INVALID THRUSTER TYPE";
406       break;
407     }    
408   }
409
410   return PropulsionStrings;
411 }
412
413 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
414
415 string FGPropulsion::GetPropulsionValues(void)
416 {
417   char buff[20];
418   string PropulsionValues = "";
419   bool firstime = true;
420
421   for (unsigned int i=0;i<Engines.size();i++) {
422     if (firstime)  firstime = false;
423     else           PropulsionValues += ", ";
424
425     switch(Engines[i]->GetType()) {
426     case FGEngine::etPiston:
427       PropulsionValues += (string(gcvt(((FGPiston*)Engines[i])->GetPowerAvailable(), 10, buff)));
428       break;
429     case FGEngine::etRocket:
430       PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));
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