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