]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGPropulsion.cpp
Strip dos line endings.
[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     case FGEngine::etTurboJet:
381     case FGEngine::etTurboProp:
382     case FGEngine::etTurboShaft:
383       break;
384     default:
385       PropulsionStrings += "INVALID ENGINE TYPE";
386       break;
387     }
388
389     PropulsionStrings += ", ";
390
391     FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
392     switch(Thrusters[i]->GetType()) {
393     case FGThruster::ttNozzle:
394       PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");
395       break;
396     case FGThruster::ttRotor:
397       break;
398     case FGThruster::ttPropeller:
399       PropulsionStrings += (Thrusters[i]->GetName() + "_Torque[" + buffer + "], ");
400       PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Roll[" + buffer + "], ");
401       PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Pitch[" + buffer + "], ");
402       PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Yaw[" + buffer + "], ");
403       PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "], ");
404       if (Propeller->IsVPitch())
405         PropulsionStrings += (Thrusters[i]->GetName() + "_Pitch[" + buffer + "], ");
406       PropulsionStrings += (Thrusters[i]->GetName() + "_RPM[" + buffer + "]");
407       break;
408     default:
409       PropulsionStrings += "INVALID THRUSTER TYPE";
410       break;
411     }    
412   }
413
414   return PropulsionStrings;
415 }
416
417 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
418
419 string FGPropulsion::GetPropulsionValues(void)
420 {
421   char buff[20];
422   string PropulsionValues = "";
423   bool firstime = true;
424
425   for (unsigned int i=0;i<Engines.size();i++) {
426     if (firstime)  firstime = false;
427     else           PropulsionValues += ", ";
428
429     switch(Engines[i]->GetType()) {
430     case FGEngine::etPiston:
431       PropulsionValues += (string(gcvt(((FGPiston*)Engines[i])->GetPowerAvailable(), 10, buff)));
432       break;
433     case FGEngine::etRocket:
434       PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));
435       break;
436     case FGEngine::etTurboJet:
437     case FGEngine::etTurboProp:
438     case FGEngine::etTurboShaft:
439       break;
440     }
441
442     PropulsionValues += ", ";
443
444     switch(Thrusters[i]->GetType()) {
445     case FGThruster::ttNozzle:
446       PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));
447       break;
448     case FGThruster::ttRotor:
449       break;
450     case FGThruster::ttPropeller:
451       FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
452       FGColumnVector3 vPFactor = Propeller->GetPFactor();
453       PropulsionValues += string(gcvt(Propeller->GetTorque(), 10, buff)) + ", ";
454       PropulsionValues += string(gcvt(vPFactor(eRoll), 10, buff)) + ", ";
455       PropulsionValues += string(gcvt(vPFactor(ePitch), 10, buff)) + ", ";
456       PropulsionValues += string(gcvt(vPFactor(eYaw), 10, buff)) + ", ";
457       PropulsionValues += string(gcvt(Propeller->GetThrust(), 10, buff)) + ", ";
458       if (Propeller->IsVPitch())
459         PropulsionValues += string(gcvt(Propeller->GetPitch(), 10, buff)) + ", ";
460       PropulsionValues += string(gcvt(Propeller->GetRPM(), 10, buff));
461       break;
462     }
463   }
464
465   return PropulsionValues;
466 }
467
468 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
469
470 FGColumnVector3& FGPropulsion::GetTanksMoment(void)
471 {
472   iTank = Tanks.begin();
473   vXYZtank.InitMatrix();
474   while (iTank < Tanks.end()) {
475     vXYZtank(eX) += (*iTank)->GetX()*(*iTank)->GetContents();
476     vXYZtank(eY) += (*iTank)->GetY()*(*iTank)->GetContents();
477     vXYZtank(eZ) += (*iTank)->GetZ()*(*iTank)->GetContents();
478     iTank++;
479   }
480   return vXYZtank;
481 }
482
483 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484
485 double FGPropulsion::GetTanksWeight(void)
486 {
487   double Tw = 0.0;
488
489   iTank = Tanks.begin();
490   while (iTank < Tanks.end()) {
491     Tw += (*iTank)->GetContents();
492     iTank++;
493   }
494   return Tw;
495 }
496
497 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
498
499 double FGPropulsion::GetTanksIxx(const FGColumnVector3& vXYZcg)
500 {
501   double I = 0.0;
502   iTank = Tanks.begin();
503   while (iTank < Tanks.end()) {
504     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetX() - vXYZcg(eX)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
505     iTank++;
506   }
507   return I;
508 }
509
510 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
511
512 double FGPropulsion::GetTanksIyy(const FGColumnVector3& vXYZcg)
513 {
514   double I = 0.0;
515   iTank = Tanks.begin();
516   while (iTank < Tanks.end()) {
517     I += ((*iTank)->GetY() - vXYZcg(eY))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
518     iTank++;
519   }
520   return I;
521 }
522
523 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
524
525 double FGPropulsion::GetTanksIzz(const FGColumnVector3& vXYZcg)
526 {
527   double I = 0.0;
528   iTank = Tanks.begin();
529   while (iTank < Tanks.end()) {
530     I += ((*iTank)->GetZ() - vXYZcg(eZ))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
531     iTank++;
532   }
533   return I;
534 }
535
536 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
537
538 double FGPropulsion::GetTanksIxz(const FGColumnVector3& vXYZcg)
539 {
540   double I = 0.0;
541   iTank = Tanks.begin();
542   while (iTank < Tanks.end()) {
543     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
544     iTank++;
545   }
546   return I;
547 }
548
549 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
550
551 double FGPropulsion::GetTanksIxy(const FGColumnVector3& vXYZcg)
552 {
553   double I = 0.0;
554   iTank = Tanks.begin();
555   while (iTank != Tanks.end()) {
556     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
557     iTank++;
558   }
559   return I;
560 }
561
562 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
563
564 void FGPropulsion::SetMagnetos(int setting)
565 {
566   if (ActiveEngine == -1) {
567     for (unsigned i=0; i<Engines.size(); i++) {
568       Engines[i]->SetMagnetos(setting);
569     }
570   } else {
571     Engines[ActiveEngine]->SetMagnetos(setting);
572   }
573 }
574
575 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
576
577 void FGPropulsion::SetStarter(int setting)
578 {
579   if (ActiveEngine == -1) {
580     for (unsigned i=0; i<Engines.size(); i++) {
581       Engines[i]->SetStarter(setting);
582     }
583   } else {
584     if (setting == 0)
585       Engines[ActiveEngine]->SetStarter(false);
586     else
587       Engines[ActiveEngine]->SetStarter(true);
588   }
589 }
590
591 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592
593 void FGPropulsion::SetActiveEngine(int engine)
594 {
595   if ( unsigned(engine) > Engines.size())
596     ActiveEngine = -1;
597   else
598     ActiveEngine = engine;
599 }
600
601 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
602
603 void FGPropulsion::bind(void)
604 {
605   typedef double (FGPropulsion::*PMF)(int) const;
606   typedef int (FGPropulsion::*iPMF)(void) const;
607   /* PropertyManager->Tie("propulsion/num-engines", this,
608                        &FGPropulsion::GetNumEngines);
609   PropertyManager->Tie("propulsion/num-tanks", this,
610                        &FGPropulsion::GetNumTanks); */
611
612   PropertyManager->Tie("propulsion/magneto_cmd", this,
613                        (iPMF)0,
614                        &FGPropulsion::SetMagnetos,
615                        true);
616   PropertyManager->Tie("propulsion/starter_cmd", this,
617                        (iPMF)0,
618                        &FGPropulsion::SetStarter,
619                        true);
620   PropertyManager->Tie("propulsion/active_engine", this,
621                        (iPMF)0,
622                        &FGPropulsion::SetActiveEngine,
623                        true);
624
625   PropertyManager->Tie("propulsion/num-sel-fuel-tanks", this,
626                        &FGPropulsion::GetnumSelectedFuelTanks);
627   PropertyManager->Tie("propulsion/num-sel-ox-tanks", this,
628                        &FGPropulsion::GetnumSelectedOxiTanks);
629   PropertyManager->Tie("forces/fbx-prop-lbs", this,1,
630                        (PMF)&FGPropulsion::GetForces);
631   PropertyManager->Tie("forces/fby-prop-lbs", this,2,
632                        (PMF)&FGPropulsion::GetForces);
633   PropertyManager->Tie("forces/fbz-prop-lbs", this,3,
634                        (PMF)&FGPropulsion::GetForces);
635   PropertyManager->Tie("moments/l-prop-lbsft", this,1,
636                        (PMF)&FGPropulsion::GetMoments);
637   PropertyManager->Tie("moments/m-prop-lbsft", this,2,
638                        (PMF)&FGPropulsion::GetMoments);
639   PropertyManager->Tie("moments/n-prop-lbsft", this,3,
640                        (PMF)&FGPropulsion::GetMoments);
641   //PropertyManager->Tie("propulsion/tanks-weight-lbs", this,
642   //                     &FGPropulsion::GetTanksWeight);
643 }
644
645 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
646
647 void FGPropulsion::unbind(void)
648 {
649   /* PropertyManager->Untie("propulsion/num-engines");
650   PropertyManager->Untie("propulsion/num-tanks"); */
651   PropertyManager->Untie("propulsion/num-sel-fuel-tanks");
652   PropertyManager->Untie("propulsion/num-sel-ox-tanks");
653   PropertyManager->Untie("propulsion/magneto_cmd");
654   PropertyManager->Untie("propulsion/starter_cmd");
655   PropertyManager->Untie("propulsion/active_engine");
656   PropertyManager->Untie("forces/fbx-prop-lbs");
657   PropertyManager->Untie("forces/fby-prop-lbs");
658   PropertyManager->Untie("forces/fbz-prop-lbs");
659   PropertyManager->Untie("moments/l-prop-lbsft");
660   PropertyManager->Untie("moments/m-prop-lbsft");
661   PropertyManager->Untie("moments/n-prop-lbsft");
662   //PropertyManager->Untie("propulsion/tanks-weight-lbs");
663 }
664
665 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
666 //    The bitmasked value choices are as follows:
667 //    unset: In this case (the default) JSBSim would only print
668 //       out the normally expected messages, essentially echoing
669 //       the config files as they are read. If the environment
670 //       variable is not set, debug_lvl is set to 1 internally
671 //    0: This requests JSBSim not to output any messages
672 //       whatsoever.
673 //    1: This value explicity requests the normal JSBSim
674 //       startup messages
675 //    2: This value asks for a message to be printed out when
676 //       a class is instantiated
677 //    4: When this value is set, a message is displayed when a
678 //       FGModel object executes its Run() method
679 //    8: When this value is set, various runtime state variables
680 //       are printed out periodically
681 //    16: When set various parameters are sanity checked and
682 //       a message is printed out when they go out of bounds
683
684 void FGPropulsion::Debug(int from)
685 {
686   if (debug_lvl <= 0) return;
687
688   if (debug_lvl & 1) { // Standard console startup message output
689     if (from == 0) { // Constructor
690
691     }
692   }
693   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
694     if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
695     if (from == 1) cout << "Destroyed:    FGPropulsion" << endl;
696   }
697   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
698   }
699   if (debug_lvl & 8 ) { // Runtime state variables
700   }
701   if (debug_lvl & 16) { // Sanity checking
702   }
703   if (debug_lvl & 64) {
704     if (from == 0) { // Constructor
705       cout << IdSrc << endl;
706       cout << IdHdr << endl;
707     }
708   }
709 }
710