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"
59 static const char *IdSrc = "$Id$";
60 static const char *IdHdr = ID_PROPULSION;
62 extern short debug_lvl;
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);
74 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
78 FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
80 Name = "FGPropulsion";
81 numSelectedFuelTanks = numSelectedOxiTanks = 0;
82 numTanks = numEngines = numThrusters = 0;
83 numOxiTanks = numFuelTanks = 0;
85 ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...
90 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 FGPropulsion::~FGPropulsion()
94 for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
100 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102 bool FGPropulsion::Run(void)
104 double PowerAvailable;
107 vForces.InitMatrix();
108 vMoments.InitMatrix();
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
124 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 bool FGPropulsion::GetSteadyState(void)
128 double PowerAvailable;
129 double currentThrust = 0, lastThrust=-1;
131 int steady_count,j=0;
134 vForces.InitMatrix();
135 vMoments.InitMatrix();
137 if (!FGModel::Run()) {
138 for (unsigned int i=0; i<numEngines; i++) {
139 Engines[i]->SetTrimMode(true);
140 Thrusters[i]->SetdeltaT(dt*rate);
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) {
149 if (steady_count > 120) { steady=true; }
155 vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces
156 vMoments += Thrusters[i]->GetMoments(); // sum body frame moments
157 Engines[i]->SetTrimMode(false);
166 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168 bool FGPropulsion::ICEngineStart(void)
170 double PowerAvailable;
174 vForces.InitMatrix();
175 vMoments.InitMatrix();
177 for (unsigned int i=0; i<numEngines; i++) {
178 Engines[i]->SetTrimMode(true);
179 Thrusters[i]->SetdeltaT(dt*rate);
181 while (!Engines[i]->GetRunning() && j < 2000) {
182 PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
183 Thrusters[i]->Calculate(PowerAvailable);
186 vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces
187 vMoments += Thrusters[i]->GetMoments(); // sum body frame moments
188 Engines[i]->SetTrimMode(false);
193 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
195 bool FGPropulsion::Load(FGConfigFile* AC_cfg)
197 string token, fullpath;
198 string engineFileName, engType;
199 string thrusterFileName, thrType;
201 string enginePath = FDMExec->GetEnginePath();
202 double xLoc, yLoc, zLoc, Pitch, Yaw;
203 double P_Factor = 0, Sense = 0.0;
205 bool ThrottleAdded = false;
208 fullpath = enginePath + "/";
210 fullpath = enginePath + ";";
213 AC_cfg->GetNextConfigLine();
215 while ((token = AC_cfg->GetValue()) != string("/PROPULSION")) {
217 if (token == "AC_ENGINE") { // ============ READING ENGINES
219 engineFileName = AC_cfg->GetValue("FILE");
221 if (debug_lvl > 0) cout << "\n Reading engine from file: " << fullpath
222 + engineFileName + ".xml"<< endl;
223 FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
225 if (Eng_cfg.IsOpen()) {
226 Eng_cfg.GetNextConfigLine();
227 engType = Eng_cfg.GetValue();
230 ThrottleAdded = true;
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));
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));
318 AC_cfg->GetNextConfigLine();
319 while ((token = AC_cfg->GetValue()) != string("/AC_THRUSTER")) {
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;
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;
340 Thrusters[numThrusters]->SetdeltaT(dt*rate);
341 Thrusters[numThrusters]->SetThrusterNumber(numThrusters);
345 cerr << "Could not read thruster config file: " << fullpath
346 + thrusterFileName + ".xml" << endl;
351 AC_cfg->GetNextConfigLine();
354 if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
359 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
361 string FGPropulsion::GetPropulsionStrings(void)
363 string PropulsionStrings = "";
364 bool firstime = true;
367 for (unsigned int i=0;i<Engines.size();i++) {
368 if (firstime) firstime = false;
369 else PropulsionStrings += ", ";
371 sprintf(buffer, "%d", i);
373 switch(Engines[i]->GetType()) {
374 case FGEngine::etPiston:
375 PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail[" + buffer + "]");
377 case FGEngine::etRocket:
378 PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress[" + buffer + "]");
380 case FGEngine::etTurboJet:
381 case FGEngine::etTurboProp:
382 case FGEngine::etTurboShaft:
385 PropulsionStrings += "INVALID ENGINE TYPE";
389 PropulsionStrings += ", ";
391 FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
392 switch(Thrusters[i]->GetType()) {
393 case FGThruster::ttNozzle:
394 PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");
396 case FGThruster::ttRotor:
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 + "]");
409 PropulsionStrings += "INVALID THRUSTER TYPE";
414 return PropulsionStrings;
417 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419 string FGPropulsion::GetPropulsionValues(void)
422 string PropulsionValues = "";
423 bool firstime = true;
425 for (unsigned int i=0;i<Engines.size();i++) {
426 if (firstime) firstime = false;
427 else PropulsionValues += ", ";
429 switch(Engines[i]->GetType()) {
430 case FGEngine::etPiston:
431 PropulsionValues += (string(gcvt(((FGPiston*)Engines[i])->GetPowerAvailable(), 10, buff)));
433 case FGEngine::etRocket:
434 PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));
436 case FGEngine::etTurboJet:
437 case FGEngine::etTurboProp:
438 case FGEngine::etTurboShaft:
442 PropulsionValues += ", ";
444 switch(Thrusters[i]->GetType()) {
445 case FGThruster::ttNozzle:
446 PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));
448 case FGThruster::ttRotor:
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));
465 return PropulsionValues;
468 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
470 FGColumnVector3& FGPropulsion::GetTanksMoment(void)
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();
483 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 double FGPropulsion::GetTanksWeight(void)
489 iTank = Tanks.begin();
490 while (iTank < Tanks.end()) {
491 Tw += (*iTank)->GetContents();
497 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
499 double FGPropulsion::GetTanksIxx(const FGColumnVector3& vXYZcg)
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());
510 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512 double FGPropulsion::GetTanksIyy(const FGColumnVector3& vXYZcg)
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());
523 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525 double FGPropulsion::GetTanksIzz(const FGColumnVector3& vXYZcg)
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());
536 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
538 double FGPropulsion::GetTanksIxz(const FGColumnVector3& vXYZcg)
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());
549 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
551 double FGPropulsion::GetTanksIxy(const FGColumnVector3& vXYZcg)
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());
562 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
564 void FGPropulsion::SetMagnetos(int setting)
566 if (ActiveEngine == -1) {
567 for (unsigned i=0; i<Engines.size(); i++) {
568 Engines[i]->SetMagnetos(setting);
571 Engines[ActiveEngine]->SetMagnetos(setting);
575 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
577 void FGPropulsion::SetStarter(int setting)
579 if (ActiveEngine == -1) {
580 for (unsigned i=0; i<Engines.size(); i++) {
581 Engines[i]->SetStarter(setting);
585 Engines[ActiveEngine]->SetStarter(false);
587 Engines[ActiveEngine]->SetStarter(true);
591 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
593 void FGPropulsion::SetActiveEngine(int engine)
595 if ( unsigned(engine) > Engines.size())
598 ActiveEngine = engine;
601 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
603 void FGPropulsion::bind(void)
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); */
612 PropertyManager->Tie("propulsion/magneto_cmd", this,
614 &FGPropulsion::SetMagnetos,
616 PropertyManager->Tie("propulsion/starter_cmd", this,
618 &FGPropulsion::SetStarter,
620 PropertyManager->Tie("propulsion/active_engine", this,
622 &FGPropulsion::SetActiveEngine,
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);
645 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
647 void FGPropulsion::unbind(void)
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");
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
673 // 1: This value explicity requests the normal JSBSim
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
684 void FGPropulsion::Debug(int from)
686 if (debug_lvl <= 0) return;
688 if (debug_lvl & 1) { // Standard console startup message output
689 if (from == 0) { // Constructor
693 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
694 if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
695 if (from == 1) cout << "Destroyed: FGPropulsion" << endl;
697 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
699 if (debug_lvl & 8 ) { // Runtime state variables
701 if (debug_lvl & 16) { // Sanity checking
703 if (debug_lvl & 64) {
704 if (from == 0) { // Constructor
705 cout << IdSrc << endl;
706 cout << IdHdr << endl;