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