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