1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 Module: FGPropulsion.cpp
6 Purpose: Encapsulates the set of engines, tanks, and thrusters associated
9 ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
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
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
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.
25 Further information about the GNU General Public License can also be found on
26 the world wide web at http://www.gnu.org.
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:
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.
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.
48 --------------------------------------------------------------------------------
51 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
55 #include "FGPropulsion.h"
56 #include "FGPropertyManager.h"
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);
69 static const char *IdSrc = "$Id$";
70 static const char *IdHdr = ID_PROPULSION;
72 extern short debug_lvl;
75 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
79 FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
81 Name = "FGPropulsion";
82 numSelectedFuelTanks = numSelectedOxiTanks = 0;
83 numTanks = numEngines = numThrusters = 0;
84 numOxiTanks = numFuelTanks = 0;
86 ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...
91 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 FGPropulsion::~FGPropulsion()
95 for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
101 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
103 bool FGPropulsion::Run(void)
105 double PowerAvailable;
108 vForces.InitMatrix();
109 vMoments.InitMatrix();
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
125 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
127 bool FGPropulsion::GetSteadyState(void)
129 double PowerAvailable;
130 double currentThrust = 0, lastThrust=-1;
132 int steady_count,j=0;
135 vForces.InitMatrix();
136 vMoments.InitMatrix();
138 if (!FGModel::Run()) {
139 for (unsigned int i=0; i<numEngines; i++) {
140 Engines[i]->SetTrimMode(true);
141 Thrusters[i]->SetdeltaT(dt*rate);
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) {
150 if (steady_count > 120) { steady=true; }
156 vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces
157 vMoments += Thrusters[i]->GetMoments(); // sum body frame moments
158 Engines[i]->SetTrimMode(false);
167 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169 bool FGPropulsion::ICEngineStart(void)
171 double PowerAvailable;
175 vForces.InitMatrix();
176 vMoments.InitMatrix();
178 for (unsigned int i=0; i<numEngines; i++) {
179 Engines[i]->SetTrimMode(true);
180 Thrusters[i]->SetdeltaT(dt*rate);
182 while (!Engines[i]->GetRunning() && j < 2000) {
183 PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
184 Thrusters[i]->Calculate(PowerAvailable);
187 vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces
188 vMoments += Thrusters[i]->GetMoments(); // sum body frame moments
189 Engines[i]->SetTrimMode(false);
194 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196 bool FGPropulsion::Load(FGConfigFile* AC_cfg)
198 string token, fullpath;
199 string engineFileName, engType;
200 string thrusterFileName, thrType;
202 string enginePath = FDMExec->GetEnginePath();
203 double xLoc, yLoc, zLoc, Pitch, Yaw;
204 double P_Factor = 0, Sense = 0.0;
206 bool ThrottleAdded = false;
209 fullpath = enginePath + "/";
211 fullpath = enginePath + ";";
214 AC_cfg->GetNextConfigLine();
216 while ((token = AC_cfg->GetValue()) != string("/PROPULSION")) {
218 if (token == "AC_ENGINE") { // ============ READING ENGINES
220 engineFileName = AC_cfg->GetValue("FILE");
222 if (debug_lvl > 0) cout << "\n Reading engine from file: " << fullpath
223 + engineFileName + ".xml"<< endl;
224 FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
226 if (Eng_cfg.IsOpen()) {
227 Eng_cfg.GetNextConfigLine();
228 engType = Eng_cfg.GetValue();
229 cout << engType << endl;
232 ThrottleAdded = true;
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));
243 cerr << fgred << " Unrecognized engine type: " << underon << engType
244 << underoff << " found in config file." << fgdef << endl;
248 AC_cfg->GetNextConfigLine();
249 while ((token = AC_cfg->GetValue()) != string("/AC_ENGINE")) {
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") {
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;
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;
272 Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw);
273 Engines[numEngines]->SetEngineNumber(numEngines);
278 cerr << fgred << "\n Could not read engine config file: " << underon <<
279 fullpath + engineFileName + ".xml" << underoff << fgdef << endl;
283 } else if (token == "AC_TANK") { // ============== READING TANKS
285 if (debug_lvl > 0) cout << "\n Reading tank definition" << endl;
286 Tanks.push_back(new FGTank(AC_cfg));
287 switch(Tanks[numTanks]->GetType()) {
289 numSelectedFuelTanks++;
292 case FGTank::ttOXIDIZER:
293 numSelectedOxiTanks++;
300 } else if (token == "AC_THRUSTER") { // ========== READING THRUSTERS
302 thrusterFileName = AC_cfg->GetValue("FILE");
304 if (debug_lvl > 0) cout << "\n Reading thruster from file: " <<
305 fullpath + thrusterFileName + ".xml" << endl;
306 FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");
308 if (Thruster_cfg.IsOpen()) {
309 Thruster_cfg.GetNextConfigLine();
310 thrType = Thruster_cfg.GetValue();
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) );
320 AC_cfg->GetNextConfigLine();
321 while ((token = AC_cfg->GetValue()) != string("/AC_THRUSTER")) {
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;
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;
342 Thrusters[numThrusters]->SetdeltaT(dt*rate);
343 Thrusters[numThrusters]->SetThrusterNumber(numThrusters);
347 cerr << "Could not read thruster config file: " << fullpath
348 + thrusterFileName + ".xml" << endl;
353 AC_cfg->GetNextConfigLine();
356 if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
361 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363 string FGPropulsion::GetPropulsionStrings(void)
365 string PropulsionStrings = "";
366 bool firstime = true;
369 for (unsigned int i=0;i<Engines.size();i++) {
370 if (firstime) firstime = false;
371 else PropulsionStrings += ", ";
373 sprintf(buffer, "%d", i);
375 switch(Engines[i]->GetType()) {
376 case FGEngine::etPiston:
377 PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail[" + buffer + "]");
379 case FGEngine::etRocket:
380 PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress[" + buffer + "]");
382 case FGEngine::etTurbine:
384 case FGEngine::etSimTurbine:
387 PropulsionStrings += "INVALID ENGINE TYPE";
391 PropulsionStrings += ", ";
393 FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
394 switch(Thrusters[i]->GetType()) {
395 case FGThruster::ttNozzle:
396 PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");
398 case FGThruster::ttRotor:
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 + "]");
411 PropulsionStrings += "INVALID THRUSTER TYPE";
416 return PropulsionStrings;
419 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
421 string FGPropulsion::GetPropulsionValues(void)
424 string PropulsionValues = "";
425 bool firstime = true;
427 for (unsigned int i=0;i<Engines.size();i++) {
428 if (firstime) firstime = false;
429 else PropulsionValues += ", ";
431 switch(Engines[i]->GetType()) {
432 case FGEngine::etPiston:
433 PropulsionValues += (string(gcvt(((FGPiston*)Engines[i])->GetPowerAvailable(), 10, buff)));
435 case FGEngine::etRocket:
436 PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));
438 case FGEngine::etTurbine:
440 case FGEngine::etSimTurbine:
444 PropulsionValues += ", ";
446 switch(Thrusters[i]->GetType()) {
447 case FGThruster::ttNozzle:
448 PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));
450 case FGThruster::ttRotor:
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));
467 return PropulsionValues;
470 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472 FGColumnVector3& FGPropulsion::GetTanksMoment(void)
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();
485 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
487 double FGPropulsion::GetTanksWeight(void)
491 iTank = Tanks.begin();
492 while (iTank < Tanks.end()) {
493 Tw += (*iTank)->GetContents();
499 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
501 double FGPropulsion::GetTanksIxx(const FGColumnVector3& vXYZcg)
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());
512 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
514 double FGPropulsion::GetTanksIyy(const FGColumnVector3& vXYZcg)
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());
525 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
527 double FGPropulsion::GetTanksIzz(const FGColumnVector3& vXYZcg)
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());
538 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
540 double FGPropulsion::GetTanksIxz(const FGColumnVector3& vXYZcg)
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());
551 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
553 double FGPropulsion::GetTanksIxy(const FGColumnVector3& vXYZcg)
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());
564 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
566 void FGPropulsion::SetMagnetos(int setting)
568 if (ActiveEngine == -1) {
569 for (unsigned i=0; i<Engines.size(); i++) {
570 Engines[i]->SetMagnetos(setting);
573 Engines[ActiveEngine]->SetMagnetos(setting);
577 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
579 void FGPropulsion::SetStarter(int setting)
581 if (ActiveEngine == -1) {
582 for (unsigned i=0; i<Engines.size(); i++) {
583 Engines[i]->SetStarter(setting);
587 Engines[ActiveEngine]->SetStarter(false);
589 Engines[ActiveEngine]->SetStarter(true);
593 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
595 void FGPropulsion::SetActiveEngine(int engine)
597 if ( unsigned(engine) > Engines.size())
600 ActiveEngine = engine;
603 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
605 void FGPropulsion::bind(void)
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); */
614 PropertyManager->Tie("propulsion/magneto_cmd", this,
616 &FGPropulsion::SetMagnetos,
618 PropertyManager->Tie("propulsion/starter_cmd", this,
620 &FGPropulsion::SetStarter,
622 PropertyManager->Tie("propulsion/active_engine", this,
624 &FGPropulsion::SetActiveEngine,
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);
647 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
649 void FGPropulsion::unbind(void)
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");
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
675 // 1: This value explicity requests the normal JSBSim
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
686 void FGPropulsion::Debug(int from)
688 if (debug_lvl <= 0) return;
690 if (debug_lvl & 1) { // Standard console startup message output
691 if (from == 0) { // Constructor
695 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
696 if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
697 if (from == 1) cout << "Destroyed: FGPropulsion" << endl;
699 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
701 if (debug_lvl & 8 ) { // Runtime state variables
703 if (debug_lvl & 16) { // Sanity checking
705 if (debug_lvl & 64) {
706 if (from == 0) { // Constructor
707 cout << IdSrc << endl;
708 cout << IdHdr << endl;