X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FFDM%2FJSBSim%2FFGFDMExec.cpp;h=ab0bf8a9acdd4cf50088aed6d31e78ee0b644894;hb=6b6d7059de394bf270c8a0660820c5fc0a4c7fd4;hp=84945690ddcc0506ff9d529ed33fe7615f0b3533;hpb=adcb4fc30ec52bcdab526edd2ebcd6cfdfd49b0b;p=flightgear.git diff --git a/src/FDM/JSBSim/FGFDMExec.cpp b/src/FDM/JSBSim/FGFDMExec.cpp index 84945690d..ab0bf8a9a 100644 --- a/src/FDM/JSBSim/FGFDMExec.cpp +++ b/src/FDM/JSBSim/FGFDMExec.cpp @@ -5,23 +5,23 @@ Date started: 11/17/98 Purpose: Schedules and runs the model routines. - ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------- + ------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) ------------- This program is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free Software + the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - You should have received a copy of the GNU General Public License along with + You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - Further information about the GNU General Public License can also be found on + Further information about the GNU Lesser General Public License can also be found on the world wide web at http://www.gnu.org. FUNCTIONAL DESCRIPTION @@ -41,61 +41,68 @@ COMMENTS, REFERENCES, and NOTES INCLUDES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ -#ifdef FGFS -# include -# include STL_IOSTREAM -# include STL_ITERATOR -#else -# if defined(sgi) && !defined(__GNUC__) -# include -# else -# include -# endif -# include -#endif - #include "FGFDMExec.h" -#include "FGState.h" -#include "FGAtmosphere.h" -#include "FGFCS.h" -#include "FGPropulsion.h" -#include "FGMassBalance.h" -#include "FGGroundReactions.h" -#include "FGAerodynamics.h" -#include "FGInertial.h" -#include "FGAircraft.h" -#include "FGTranslation.h" -#include "FGRotation.h" -#include "FGPosition.h" -#include "FGAuxiliary.h" -#include "FGOutput.h" -#include "FGConfigFile.h" -#include "FGInitialCondition.h" -#include "FGPropertyManager.h" - -static const char *IdSrc = "$Id$"; +#include "models/FGAtmosphere.h" +#include "models/atmosphere/FGMSIS.h" +#include "models/atmosphere/FGMars.h" +#include "models/FGFCS.h" +#include "models/FGPropulsion.h" +#include "models/FGMassBalance.h" +#include "models/FGGroundReactions.h" +#include "models/FGExternalReactions.h" +#include "models/FGBuoyantForces.h" +#include "models/FGAerodynamics.h" +#include "models/FGInertial.h" +#include "models/FGAircraft.h" +#include "models/FGPropagate.h" +#include "models/FGAuxiliary.h" +#include "models/FGInput.h" +#include "models/FGOutput.h" +#include "initialization/FGInitialCondition.h" +//#include "initialization/FGTrimAnalysis.h" // Remove until later +#include "input_output/FGPropertyManager.h" +#include "input_output/FGScript.h" + +#include +#include +#include + +using namespace std; + +namespace JSBSim { + +static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.83 2010/11/07 13:30:54 jberndt Exp $"; static const char *IdHdr = ID_FDMEXEC; /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -GLOBAL DECLARATIONS +CLASS IMPLEMENTATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ -unsigned int FGFDMExec::FDMctr = 0; -FGPropertyManager* FGFDMExec::master=0; +void checkTied ( FGPropertyManager *node ) +{ + int N = node->nChildren(); + string name; -/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -CLASS IMPLEMENTATION -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + for (int i=0; igetChild(i)->nChildren() ) { + checkTied( (FGPropertyManager*)node->getChild(i) ); + } + if ( node->getChild(i)->isTied() ) { + name = ((FGPropertyManager*)node->getChild(i))->GetFullyQualifiedName(); + node->Untie(name); + } + } +} +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // Constructor -FGFDMExec::FGFDMExec(FGPropertyManager* root) +FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root), FDMctr(fdmctr) { - + Frame = 0; - FirstModel = 0; Error = 0; - State = 0; + GroundCallback = 0; Atmosphere = 0; FCS = 0; Propulsion = 0; @@ -103,45 +110,74 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) Aerodynamics = 0; Inertial = 0; GroundReactions = 0; + ExternalReactions = 0; + BuoyantForces = 0; Aircraft = 0; - Translation = 0; - Rotation = 0; - Position = 0; + Propagate = 0; Auxiliary = 0; - Output = 0; + Input = 0; + IC = 0; + Trim = 0; + Script = 0; + + RootDir = ""; - terminate = false; - frozen = false; modelLoaded = false; - IsSlave = false; + IsChild = false; + holding = false; + Terminate = false; + StandAlone = false; - IdFDM = FDMctr; - FDMctr++; + sim_time = 0.0; + dT = 1.0/120.0; // a default timestep size. This is needed for when JSBSim is + // run in standalone mode with no initialization file. try { char* num = getenv("JSBSIM_DEBUG"); - if (!num) debug_lvl = 1; - else debug_lvl = atoi(num); // set debug level - } catch (...) { // if error set to 1 + if (num) debug_lvl = atoi(num); // set debug level + } catch (...) { // if error set to 1 debug_lvl = 1; } - if (root == 0) master= new FGPropertyManager; - else master = root; + if (Root == 0) { // Then this is the root FDM + Root = new FGPropertyManager; // Create the property manager + StandAlone = true; + } - instance = master->GetNode("/fdm/jsbsim",IdFDM,true); - instance->SetDouble("zero",0); - + if (FDMctr == 0) { + FDMctr = new unsigned int; // Create and initialize the child FDM counter + (*FDMctr) = 0; + } + + // Store this FDM's ID + IdFDM = (*FDMctr); // The main (parent) JSBSim instance is always the "zeroth" + + // Prepare FDMctr for the next child FDM id + (*FDMctr)++; // instance. "child" instances are loaded last. + + instance = Root->GetNode("/fdm/jsbsim",IdFDM,true); Debug(0); - - // this is here to catch errors in binding member functions - // to the property tree. + // this is to catch errors in binding member functions to the property tree. try { Allocate(); } catch ( string msg ) { cout << "Caught error: " << msg << endl; exit(1); - } + } + + trim_status = false; + ta_mode = 99; + + Constructing = true; + typedef int (FGFDMExec::*iPMF)(void) const; +// instance->Tie("simulation/do_trim_analysis", this, (iPMF)0, &FGFDMExec::DoTrimAnalysis); + instance->Tie("simulation/do_simple_trim", this, (iPMF)0, &FGFDMExec::DoTrim); + instance->Tie("simulation/reset", this, (iPMF)0, &FGFDMExec::ResetToInitialConditions); + instance->Tie("simulation/terminate", (int *)&Terminate); + instance->Tie("simulation/sim-time-sec", this, &FGFDMExec::GetSimTime); + instance->Tie("simulation/jsbsim-debug", this, &FGFDMExec::GetDebugLevel, &FGFDMExec::SetDebugLevel); + + Constructing = false; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -149,14 +185,31 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) FGFDMExec::~FGFDMExec() { try { + checkTied( instance ); DeAllocate(); + + if (IdFDM == 0) { // Meaning this is no child FDM + if(Root != 0) { + if(StandAlone) + delete Root; + Root = 0; + } + if(FDMctr != 0) { + delete FDMctr; + FDMctr = 0; + } + } } catch ( string msg ) { cout << "Caught error: " << msg << endl; - } + } + + for (unsigned int i=1; iexec; + ChildFDMList.clear(); + + PropertyCatalog.clear(); + + FDMctr--; - for (int i=1; iexec; - SlaveFDMList.clear(); - Debug(1); } @@ -172,66 +225,21 @@ bool FGFDMExec::Allocate(void) MassBalance = new FGMassBalance(this); Aerodynamics = new FGAerodynamics (this); Inertial = new FGInertial(this); + + GroundCallback = new FGGroundCallback(Inertial->GetRefRadius()); + GroundReactions = new FGGroundReactions(this); + ExternalReactions = new FGExternalReactions(this); + BuoyantForces = new FGBuoyantForces(this); Aircraft = new FGAircraft(this); - Translation = new FGTranslation(this); - Rotation = new FGRotation(this); - Position = new FGPosition(this); + Propagate = new FGPropagate(this); Auxiliary = new FGAuxiliary(this); - Output = new FGOutput(this); - - State = new FGState(this); // This must be done here, as the FGState - // class needs valid pointers to the above - // model classes - - // Initialize models so they can communicate with each other - - if (!Atmosphere->InitModel()) { - cerr << fgred << "Atmosphere model init failed" << fgdef << endl; - Error+=1;} - if (!FCS->InitModel()) { - cerr << fgred << "FCS model init failed" << fgdef << endl; - Error+=2;} - if (!Propulsion->InitModel()) { - cerr << fgred << "FGPropulsion model init failed" << fgdef << endl; - Error+=4;} - if (!MassBalance->InitModel()) { - cerr << fgred << "FGMassBalance model init failed" << fgdef << endl; - Error+=8;} - if (!Aerodynamics->InitModel()) { - cerr << fgred << "FGAerodynamics model init failed" << fgdef << endl; - Error+=16;} - if (!Inertial->InitModel()) { - cerr << fgred << "FGInertial model init failed" << fgdef << endl; - Error+=32;} - if (!GroundReactions->InitModel()) { - cerr << fgred << "Ground Reactions model init failed" << fgdef << endl; - Error+=64;} - if (!Aircraft->InitModel()) { - cerr << fgred << "Aircraft model init failed" << fgdef << endl; - Error+=128;} - if (!Translation->InitModel()) { - cerr << fgred << "Translation model init failed" << fgdef << endl; - Error+=256;} - if (!Rotation->InitModel()) { - cerr << fgred << "Rotation model init failed" << fgdef << endl; - Error+=512;} - if (!Position->InitModel()) { - cerr << fgred << "Position model init failed" << fgdef << endl; - Error+=1024;} - if (!Auxiliary->InitModel()) { - cerr << fgred << "Auxiliary model init failed" << fgdef << endl; - Error+=2058;} - if (!Output->InitModel()) { - cerr << fgred << "Output model init failed" << fgdef << endl; - Error+=4096;} - - if (Error > 0) result = false; + Input = new FGInput(this); // Schedule a model. The second arg (the integer) is the pass number. For - // instance, the atmosphere model gets executed every fifth pass it is called - // by the executive. Everything else here gets executed each pass. - + // instance, the atmosphere model could get executed every fifth pass it is called. + + Schedule(Input, 1); Schedule(Atmosphere, 1); Schedule(FCS, 1); Schedule(Propulsion, 1); @@ -239,12 +247,18 @@ bool FGFDMExec::Allocate(void) Schedule(Aerodynamics, 1); Schedule(Inertial, 1); Schedule(GroundReactions, 1); + Schedule(ExternalReactions, 1); + Schedule(BuoyantForces, 1); Schedule(Aircraft, 1); - Schedule(Rotation, 1); - Schedule(Translation, 1); - Schedule(Position, 1); + Schedule(Propagate, 1); Schedule(Auxiliary, 1); - Schedule(Output, 1); + + // Initialize models so they can communicate with each other + + vector ::iterator it; + for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel(); + + IC = new FGInitialCondition(this); modelLoaded = false; @@ -253,27 +267,34 @@ bool FGFDMExec::Allocate(void) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::DeAllocate(void) { - - if ( Atmosphere != 0 ) delete Atmosphere; - if ( FCS != 0 ) delete FCS; - if ( Propulsion != 0) delete Propulsion; - if ( MassBalance != 0) delete MassBalance; - if ( Aerodynamics != 0) delete Aerodynamics; - if ( Inertial != 0) delete Inertial; - if ( GroundReactions != 0) delete GroundReactions; - if ( Aircraft != 0 ) delete Aircraft; - if ( Translation != 0 ) delete Translation; - if ( Rotation != 0 ) delete Rotation; - if ( Position != 0 ) delete Position; - if ( Auxiliary != 0 ) delete Auxiliary; - if ( Output != 0 ) delete Output; - if ( State != 0 ) delete State; - - FirstModel = 0L; +bool FGFDMExec::DeAllocate(void) +{ + delete Input; + delete Atmosphere; + delete FCS; + delete Propulsion; + delete MassBalance; + delete Aerodynamics; + delete Inertial; + delete GroundReactions; + delete ExternalReactions; + delete BuoyantForces; + delete Aircraft; + delete Propagate; + delete Auxiliary; + delete Script; + + for (unsigned i=0; iSetRate(rate); + Models.push_back(model); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +bool FGFDMExec::Run(void) { - FGModel* model_iterator; + bool success=true; - model_iterator = FirstModel; + Debug(2); - if (model_iterator == 0L) { // this is the first model + for (unsigned int i=1; iAssignState(Propagate); // Transfer state to the child FDM + ChildFDMList[i]->Run(); + } - FirstModel = model; - FirstModel->NextModel = 0L; - FirstModel->SetRate(rate); + // returns true if success, false if complete + if (Script != 0 && !IntegrationSuspended()) success = Script->RunScript(); - } else { // subsequent model + vector ::iterator it; + for (it = Models.begin(); it != Models.end(); ++it) (*it)->Run(); - while (model_iterator->NextModel != 0L) { - model_iterator = model_iterator->NextModel; - } - model_iterator->NextModel = model; - model_iterator->NextModel->SetRate(rate); + Frame++; + if (!Holding()) IncrTime(); + if (Terminate) success = false; - } - - return 0; + return (success); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// This call will cause the sim time to reset to 0.0 -bool FGFDMExec::Run(void) +bool FGFDMExec::RunIC(void) +{ + SuspendIntegration(); // saves the integration rate, dt, then sets it to 0.0. + Initialize(IC); + Run(); + ResumeIntegration(); // Restores the integration rate to what it was. + + return true; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGFDMExec::Initialize(FGInitialCondition *FGIC) { - FGModel* model_iterator; + Propagate->SetInitialState( FGIC ); - if (frozen) return true; + Atmosphere->Run(); + Atmosphere->SetWindNED( FGIC->GetWindNFpsIC(), + FGIC->GetWindEFpsIC(), + FGIC->GetWindDFpsIC() ); - model_iterator = FirstModel; - if (model_iterator == 0L) return false; + FGColumnVector3 vAeroUVW; + vAeroUVW = Propagate->GetUVW() + Propagate->GetTl2b()*Atmosphere->GetTotalWindNED(); - Debug(2); + double alpha, beta; + if (vAeroUVW(eW) != 0.0) + alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0; + else + alpha = 0.0; + if (vAeroUVW(eV) != 0.0) + beta = vAeroUVW(eU)*vAeroUVW(eU)+vAeroUVW(eW)*vAeroUVW(eW) > 0.0 ? atan2(vAeroUVW(eV), (fabs(vAeroUVW(eU))/vAeroUVW(eU))*sqrt(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW))) : 0.0; + else + beta = 0.0; - for (int i=0; iSetAB(alpha, beta); - while (!model_iterator->Run()) { - model_iterator = model_iterator->NextModel; - if (model_iterator == 0L) break; - } + double Vt = vAeroUVW.Magnitude(); + Auxiliary->SetVt(Vt); - frame = Frame++; - State->IncrTime(); + Auxiliary->SetMach(Vt/Atmosphere->GetSoundSpeed()); - return true; + double qbar = 0.5*Vt*Vt*Atmosphere->GetDensity(); + Auxiliary->Setqbar(qbar); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// +// A private, internal function call for Tie-ing to a property, so it needs an +// argument. -bool FGFDMExec::RunIC(FGInitialCondition *fgic) +void FGFDMExec::ResetToInitialConditions(int mode) { - State->Suspend(); - State->Initialize(fgic); - Run(); - State->Resume(); - return true; + if (mode == 1) { + for (unsigned int i=0; iSetStartNewFile(true); + } + } + + ResetToInitialConditions(); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGFDMExec::ResetToInitialConditions(void) +{ + if (Constructing) return; + + vector ::iterator it; + for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel(); + + RunIC(); + if (Script) Script->ResetEvents(); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void FGFDMExec::TransferState(int idxFDM) +void FGFDMExec::SetGroundCallback(FGGroundCallback* p) { - SlaveFDMList[idxFDM]->exec->GetRotation()->SetEuler(Rotation->GetEuler()); - SlaveFDMList[idxFDM]->exec->GetRotation()->SetAeroPQR(Rotation->GetAeroPQR()); - SlaveFDMList[idxFDM]->exec->GetTranslation()->SetAeroUVW(Translation->GetAeroUVW()); - SlaveFDMList[idxFDM]->exec->GetRotation()->SetEuler(Rotation->GetEuler()); + delete GroundCallback; + GroundCallback = p; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -377,8 +442,8 @@ vector FGFDMExec::EnumerateFDMs(void) FDMList.push_back(Aircraft->GetAircraftName()); - for (int i=1; iexec->GetAircraft()->GetAircraftName()); + for (unsigned int i=1; iexec->GetAircraft()->GetAircraftName()); } return FDMList; @@ -386,88 +451,361 @@ vector FGFDMExec::EnumerateFDMs(void) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::LoadModel(string APath, string EPath, string model) +bool FGFDMExec::LoadScript(const string& script, double deltaT) +{ + bool result; + + Script = new FGScript(this); + result = Script->LoadScript(RootDir + script, deltaT); + + return result; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +bool FGFDMExec::LoadModel(const string& AircraftPath, const string& EnginePath, const string& SystemsPath, + const string& model, bool addModelToPath) +{ + FGFDMExec::AircraftPath = RootDir + AircraftPath; + FGFDMExec::EnginePath = RootDir + EnginePath; + FGFDMExec::SystemsPath = RootDir + SystemsPath; + + return LoadModel(model, addModelToPath); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +bool FGFDMExec::LoadModel(const string& model, bool addModelToPath) { - bool result = true; string token; string aircraftCfgFileName; + Element* element = 0L; + bool result = false; // initialize result to false, indicating input file not yet read - AircraftPath = APath; - EnginePath = EPath; + modelName = model; // Set the class modelName attribute -# ifndef macintosh - aircraftCfgFileName = AircraftPath + "/" + model + "/" + model + ".xml"; -# else - aircraftCfgFileName = AircraftPath + ";" + model + ";" + model + ".xml"; -# endif + if( AircraftPath.empty() || EnginePath.empty() || SystemsPath.empty()) { + cerr << "Error: attempted to load aircraft with undefined "; + cerr << "aircraft, engine, and system paths" << endl; + return false; + } - FGConfigFile AC_cfg(aircraftCfgFileName); - if (!AC_cfg.IsOpen()) return false; + FullAircraftPath = AircraftPath; + if (addModelToPath) FullAircraftPath += "/" + model; + aircraftCfgFileName = FullAircraftPath + "/" + model + ".xml"; if (modelLoaded) { DeAllocate(); Allocate(); } - if (!ReadPrologue(&AC_cfg)) return false; - - while ((AC_cfg.GetNextConfigLine() != string("EOF")) && - (token = AC_cfg.GetValue()) != string("/FDM_CONFIG")) { - if (token == "METRICS") { - if (debug_lvl > 0) cout << fgcyan << "\n Reading Metrics" << fgdef << endl; - if (!ReadMetrics(&AC_cfg)) result = false; - } else if (token == "SLAVE") { - if (debug_lvl > 0) cout << fgcyan << "\n Reading Slave flight vehicle: " << fgdef - << AC_cfg.GetValue("NAME") << endl; - if (!ReadSlave(&AC_cfg)) result = false; - } else if (token == "AERODYNAMICS") { - if (debug_lvl > 0) cout << fgcyan << "\n Reading Aerodynamics" << fgdef << endl; - if (!ReadAerodynamics(&AC_cfg)) result = false; - } else if (token == "UNDERCARRIAGE") { - if (debug_lvl > 0) cout << fgcyan << "\n Reading Landing Gear" << fgdef << endl; - if (!ReadUndercarriage(&AC_cfg)) result = false; - } else if (token == "PROPULSION") { - if (debug_lvl > 0) cout << fgcyan << "\n Reading Propulsion" << fgdef << endl; - if (!ReadPropulsion(&AC_cfg)) result = false; - } else if (token == "FLIGHT_CONTROL") { - if (debug_lvl > 0) cout << fgcyan << "\n Reading Flight Control" << fgdef << endl; - if (!ReadFlightControls(&AC_cfg)) result = false; - } else if (token == "OUTPUT") { - if (debug_lvl > 0) cout << fgcyan << "\n Reading Output directives" << fgdef << endl; - if (!ReadOutput(&AC_cfg)) result = false; + int saved_debug_lvl = debug_lvl; + + document = LoadXMLDocument(aircraftCfgFileName); // "document" is a class member + if (document) { + if (IsChild) debug_lvl = 0; + + ReadPrologue(document); + + if (IsChild) debug_lvl = saved_debug_lvl; + + // Process the fileheader element in the aircraft config file. This element is OPTIONAL. + element = document->FindElement("fileheader"); + if (element) { + result = ReadFileHeader(element); + if (!result) { + cerr << endl << "Aircraft fileheader element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + if (IsChild) debug_lvl = 0; + + // Process the metrics element. This element is REQUIRED. + element = document->FindElement("metrics"); + if (element) { + result = Aircraft->Load(element); + if (!result) { + cerr << endl << "Aircraft metrics element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } else { + cerr << endl << "No metrics element was found in the aircraft config file." << endl; + return false; + } + + // Process the mass_balance element. This element is REQUIRED. + element = document->FindElement("mass_balance"); + if (element) { + result = MassBalance->Load(element); + if (!result) { + cerr << endl << "Aircraft mass_balance element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } else { + cerr << endl << "No mass_balance element was found in the aircraft config file." << endl; + return false; + } + + // Process the ground_reactions element. This element is REQUIRED. + element = document->FindElement("ground_reactions"); + if (element) { + result = GroundReactions->Load(element); + if (!result) { + cerr << endl << "Aircraft ground_reactions element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } else { + cerr << endl << "No ground_reactions element was found in the aircraft config file." << endl; + return false; + } + + // Process the external_reactions element. This element is OPTIONAL. + element = document->FindElement("external_reactions"); + if (element) { + result = ExternalReactions->Load(element); + if (!result) { + cerr << endl << "Aircraft external_reactions element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + // Process the buoyant_forces element. This element is OPTIONAL. + element = document->FindElement("buoyant_forces"); + if (element) { + result = BuoyantForces->Load(element); + if (!result) { + cerr << endl << "Aircraft buoyant_forces element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + // Process the propulsion element. This element is OPTIONAL. + element = document->FindElement("propulsion"); + if (element) { + result = Propulsion->Load(element); + if (!result) { + cerr << endl << "Aircraft propulsion element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + // Process the system element[s]. This element is OPTIONAL, and there may be more than one. + element = document->FindElement("system"); + while (element) { + result = FCS->Load(element, FGFCS::stSystem); + if (!result) { + cerr << endl << "Aircraft system element has problems in file " << aircraftCfgFileName << endl; + return result; + } + element = document->FindNextElement("system"); + } + + // Process the autopilot element. This element is OPTIONAL. + element = document->FindElement("autopilot"); + if (element) { + result = FCS->Load(element, FGFCS::stAutoPilot); + if (!result) { + cerr << endl << "Aircraft autopilot element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + // Process the flight_control element. This element is OPTIONAL. + element = document->FindElement("flight_control"); + if (element) { + result = FCS->Load(element, FGFCS::stFCS); + if (!result) { + cerr << endl << "Aircraft flight_control element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + // Process the aerodynamics element. This element is OPTIONAL, but almost always expected. + element = document->FindElement("aerodynamics"); + if (element) { + result = Aerodynamics->Load(element); + if (!result) { + cerr << endl << "Aircraft aerodynamics element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } else { + cerr << endl << "No expected aerodynamics element was found in the aircraft config file." << endl; + } + + // Process the input element. This element is OPTIONAL. + element = document->FindElement("input"); + if (element) { + result = Input->Load(element); + if (!result) { + cerr << endl << "Aircraft input element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + // Process the output element[s]. This element is OPTIONAL, and there may be more than one. + unsigned int idx=0; + typedef int (FGOutput::*iOPMF)(void) const; + element = document->FindElement("output"); + while (element) { + if (debug_lvl > 0) cout << endl << " Output data set: " << idx << " "; + FGOutput* Output = new FGOutput(this); + Output->InitModel(); + Schedule(Output, 1); + result = Output->Load(element); + if (!result) { + cerr << endl << "Aircraft output element has problems in file " << aircraftCfgFileName << endl; + return result; + } else { + Outputs.push_back(Output); + string outputProp = CreateIndexedPropertyName("simulation/output",idx); + instance->Tie(outputProp+"/log_rate_hz", Output, (iOPMF)0, &FGOutput::SetRate); + idx++; + } + element = document->FindNextElement("output"); + } + + // Lastly, process the child element. This element is OPTIONAL - and NOT YET SUPPORTED. + element = document->FindElement("child"); + if (element) { + result = ReadChild(element); + if (!result) { + cerr << endl << "Aircraft child element has problems in file " << aircraftCfgFileName << endl; + return result; + } } - } - if (result) { modelLoaded = true; - Debug(3); + + if (debug_lvl > 0) { + MassBalance->Run(); // Update all mass properties for the report. + MassBalance->GetMassPropertiesReport(); + + cout << endl << fgblue << highint + << "End of vehicle configuration loading." << endl + << "-------------------------------------------------------------------------------" + << reset << endl; + } + + if (IsChild) debug_lvl = saved_debug_lvl; + } else { cerr << fgred - << " FGFDMExec: Failed to load aircraft and/or engine model" + << " JSBSim failed to open the configuration file: " << aircraftCfgFileName << fgdef << endl; } + // Late bind previously undefined FCS inputs. + try { + FCS->LateBind(); + } catch (string prop) { + cerr << endl << fgred << " Could not late bind property " << prop + << ". Aborting." << endl; + result = false; + } + + if (result) { + struct PropertyCatalogStructure masterPCS; + masterPCS.base_string = ""; + masterPCS.node = (FGPropertyManager*)Root; + BuildPropertyCatalog(&masterPCS); + } + + return result; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs) +{ + struct PropertyCatalogStructure* pcsNew = new struct PropertyCatalogStructure; + int node_idx = 0; + + for (int i=0; inode->nChildren(); i++) { + pcsNew->base_string = pcs->base_string + "/" + pcs->node->getChild(i)->getName(); + node_idx = pcs->node->getChild(i)->getIndex(); + if (node_idx != 0) { + pcsNew->base_string = CreateIndexedPropertyName(pcsNew->base_string, node_idx); + } + if (pcs->node->getChild(i)->nChildren() == 0) { + if (pcsNew->base_string.substr(0,11) == string("/fdm/jsbsim")) { + pcsNew->base_string = pcsNew->base_string.erase(0,12); + } + PropertyCatalog.push_back(pcsNew->base_string); + } else { + pcsNew->node = (FGPropertyManager*)pcs->node->getChild(i); + BuildPropertyCatalog(pcsNew); + } + } + delete pcsNew; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +string FGFDMExec::QueryPropertyCatalog(const string& in) +{ + string results=""; + for (unsigned i=0; iFindElement("description")) + cout << " Description: " << el->FindElement("description")->GetDataLine() << endl; + if (el->FindElement("author")) + cout << " Model Author: " << el->FindElement("author")->GetDataLine() << endl; + if (el->FindElement("filecreationdate")) + cout << " Creation Date: " << el->FindElement("filecreationdate")->GetDataLine() << endl; + if (el->FindElement("version")) + cout << " Version: " << el->FindElement("version")->GetDataLine() << endl; + return result; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::ReadPrologue(FGConfigFile* AC_cfg) +bool FGFDMExec::ReadPrologue(Element* el) // el for ReadPrologue is the document element { - string token = AC_cfg->GetValue(); - string scratch; - string AircraftName; + bool result = true; // true for success - AircraftName = AC_cfg->GetValue("NAME"); + if (!el) return false; + + string AircraftName = el->GetAttributeValue("name"); Aircraft->SetAircraftName(AircraftName); - if (debug_lvl > 0) cout << underon << "Reading Aircraft Configuration File" + if (debug_lvl & 1) cout << underon << "Reading Aircraft Configuration File" << underoff << ": " << highint << AircraftName << normint << endl; - scratch = AC_cfg->GetValue("VERSION").c_str(); - CFGVersion = AC_cfg->GetValue("VERSION"); + CFGVersion = el->GetAttributeValue("version"); + Release = el->GetAttributeValue("release"); - if (debug_lvl > 0) + if (debug_lvl & 1) cout << " Version: " << highint << CFGVersion << normint << endl; if (CFGVersion != needed_cfg_version) { @@ -478,106 +816,221 @@ bool FGFDMExec::ReadPrologue(FGConfigFile* AC_cfg) return false; } - return true; + if (Release == "ALPHA" && (debug_lvl & 1)) { + cout << endl << endl + << highint << "This aircraft model is an " << fgred << Release + << reset << highint << " release!!!" << endl << endl << reset + << "This aircraft model may not even properly load, and probably" + << " will not fly as expected." << endl << endl + << fgred << highint << "Use this model for development purposes ONLY!!!" + << normint << reset << endl << endl; + } else if (Release == "BETA" && (debug_lvl & 1)) { + cout << endl << endl + << highint << "This aircraft model is a " << fgred << Release + << reset << highint << " release!!!" << endl << endl << reset + << "This aircraft model probably will not fly as expected." << endl << endl + << fgblue << highint << "Use this model for development purposes ONLY!!!" + << normint << reset << endl << endl; + } else if (Release == "PRODUCTION" && (debug_lvl & 1)) { + cout << endl << endl + << highint << "This aircraft model is a " << fgblue << Release + << reset << highint << " release." << endl << endl << reset; + } else if (debug_lvl & 1) { + cout << endl << endl + << highint << "This aircraft model is an " << fgred << Release + << reset << highint << " release!!!" << endl << endl << reset + << "This aircraft model may not even properly load, and probably" + << " will not fly as expected." << endl << endl + << fgred << highint << "Use this model for development purposes ONLY!!!" + << normint << reset << endl << endl; + } + + return result; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::ReadSlave(FGConfigFile* AC_cfg) +bool FGFDMExec::ReadChild(Element* el) { - // Add a new slaveData object to the slave FDM list - // Populate that slaveData element with a new FDMExec object - // Set the IsSlave flag for that FDMExec object + // Add a new childData object to the child FDM list + // Populate that childData element with a new FDMExec object + // Set the IsChild flag for that FDMExec object // Get the aircraft name - // set debug level to print out no additional data for slave objects + // set debug level to print out no additional data for child objects // Load the model given the aircraft name // reset debug level to prior setting - int saved_debug_lvl = debug_lvl; + string token; - SlaveFDMList.push_back(new slaveData); - SlaveFDMList.back()->exec = new FGFDMExec(); - SlaveFDMList.back()->exec->SetSlave(); + struct childData* child = new childData; - string AircraftName = AC_cfg->GetValue("FILE"); + child->exec = new FGFDMExec(Root, FDMctr); + child->exec->SetChild(true); - debug_lvl = 0; - SlaveFDMList.back()->exec->LoadModel("aircraft", "engine", AircraftName); - debug_lvl = saved_debug_lvl; + string childAircraft = el->GetAttributeValue("name"); + string sMated = el->GetAttributeValue("mated"); + if (sMated == "false") child->mated = false; // child objects are mated by default. + string sInternal = el->GetAttributeValue("internal"); + if (sInternal == "true") child->internal = true; // child objects are external by default. + + child->exec->SetAircraftPath( AircraftPath ); + child->exec->SetEnginePath( EnginePath ); + child->exec->SetSystemsPath( SystemsPath ); + child->exec->LoadModel(childAircraft); + + Element* location = el->FindElement("location"); + if (location) { + child->Loc = location->FindElementTripletConvertTo("IN"); + } else { + cerr << endl << highint << fgred << " No location was found for this child object!" << reset << endl; + exit(-1); + } + + Element* orientation = el->FindElement("orient"); + if (orientation) { + child->Orient = orientation->FindElementTripletConvertTo("RAD"); + } else if (debug_lvl > 0) { + cerr << endl << highint << " No orientation was found for this child object! Assuming 0,0,0." << reset << endl; + } + + ChildFDMList.push_back(child); return true; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::ReadPropulsion(FGConfigFile* AC_cfg) +FGPropertyManager* FGFDMExec::GetPropertyManager(void) { - if (!Propulsion->Load(AC_cfg)) { - cerr << " Propulsion not successfully loaded" << endl; - return false; - } - return true; + return instance; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::ReadFlightControls(FGConfigFile* AC_cfg) +FGTrim* FGFDMExec::GetTrim(void) { - if (!FCS->Load(AC_cfg)) { - cerr << " Flight Controls not successfully loaded" << endl; - return false; + delete Trim; + Trim = new FGTrim(this,tNone); + return Trim; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGFDMExec::DisableOutput(void) +{ + for (unsigned i=0; iDisable(); } - return true; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::ReadAerodynamics(FGConfigFile* AC_cfg) +void FGFDMExec::EnableOutput(void) { - if (!Aerodynamics->Load(AC_cfg)) { - cerr << " Aerodynamics not successfully loaded" << endl; - return false; + for (unsigned i=0; iEnable(); } - return true; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::ReadUndercarriage(FGConfigFile* AC_cfg) +bool FGFDMExec::SetOutputDirectives(const string& fname) { - if (!GroundReactions->Load(AC_cfg)) { - cerr << " Ground Reactions not successfully loaded" << endl; - return false; + bool result; + + FGOutput* Output = new FGOutput(this); + Output->SetDirectivesFile(RootDir + fname); + Output->InitModel(); + Schedule(Output, 1); + result = Output->Load(0); + + if (result) { + Outputs.push_back(Output); + typedef int (FGOutput::*iOPMF)(void) const; + string outputProp = CreateIndexedPropertyName("simulation/output",Outputs.size()-1); + instance->Tie(outputProp+"/log_rate_hz", Output, (iOPMF)0, &FGOutput::SetRate); } - return true; + + return result; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::ReadMetrics(FGConfigFile* AC_cfg) +void FGFDMExec::DoTrim(int mode) { - if (!Aircraft->Load(AC_cfg)) { - cerr << " Aircraft metrics not successfully loaded" << endl; - return false; + double saved_time; + + if (Constructing) return; + + if (mode < 0 || mode > JSBSim::tNone) { + cerr << endl << "Illegal trimming mode!" << endl << endl; + return; } - return true; + saved_time = sim_time; + FGTrim trim(this, (JSBSim::TrimMode)mode); + if ( !trim.DoTrim() ) cerr << endl << "Trim Failed" << endl << endl; + trim.Report(); + sim_time = saved_time; } +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +/* +void FGFDMExec::DoTrimAnalysis(int mode) +{ + double saved_time; + if (Constructing) return; + + if (mode < 0 || mode > JSBSim::taNone) { + cerr << endl << "Illegal trimming mode!" << endl << endl; + return; + } + saved_time = sim_time; + + FGTrimAnalysis trimAnalysis(this, (JSBSim::TrimAnalysisMode)mode); + + if ( !trimAnalysis.Load(IC->GetInitFile(), false) ) { + cerr << "A problem occurred with trim configuration file " << trimAnalysis.Load(IC->GetInitFile()) << endl; + exit(-1); + } + + bool result = trimAnalysis.DoTrim(); + + if ( !result ) cerr << endl << "Trim Failed" << endl << endl; + + trimAnalysis.Report(); + Setsim_time(saved_time); + + EnableOutput(); + cout << "\nOutput: " << GetOutputFileName() << endl; + +} +*/ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::ReadOutput(FGConfigFile* AC_cfg) +void FGFDMExec::UseAtmosphereMSIS(void) { - if (!Output->Load(AC_cfg)) { - cerr << " Output not successfully loaded" << endl; - return false; + FGAtmosphere *oldAtmosphere = Atmosphere; + Atmosphere = new MSIS(this); + if (!Atmosphere->InitModel()) { + cerr << fgred << "MSIS Atmosphere model init failed" << fgdef << endl; + Error+=1; } - return true; + delete oldAtmosphere; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -FGPropertyManager* FGFDMExec::GetPropertyManager(void) { - return instance; +void FGFDMExec::UseAtmosphereMars(void) +{ +/* + FGAtmosphere *oldAtmosphere = Atmosphere; + Atmosphere = new FGMars(this); + if (!Atmosphere->InitModel()) { + cerr << fgred << "Mars Atmosphere model init failed" << fgdef << endl; + Error+=1; + } + delete oldAtmosphere; +*/ } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -603,11 +1056,11 @@ void FGFDMExec::Debug(int from) { if (debug_lvl <= 0) return; - if (debug_lvl & 1) { // Standard console startup message output + if (debug_lvl & 1 && IdFDM == 0) { // Standard console startup message output if (from == 0) { // Constructor cout << "\n\n " << highint << underon << "JSBSim Flight Dynamics Model v" << JSBSim_version << underoff << normint << endl; - cout << halfint << " [cfg file spec v" << needed_cfg_version << "]\n\n"; + cout << halfint << " [JSBSim-ML v" << needed_cfg_version << "]\n\n"; cout << normint << "JSBSim startup beginning ...\n\n"; } else if (from == 3) { cout << "\n\nJSBSim startup complete\n\n"; @@ -620,7 +1073,7 @@ void FGFDMExec::Debug(int from) if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects if (from == 2) { cout << "================== Frame: " << Frame << " Time: " - << State->Getsim_time() << endl; + << sim_time << " dt: " << dT << endl; } } if (debug_lvl & 8 ) { // Runtime state variables @@ -634,4 +1087,6 @@ void FGFDMExec::Debug(int from) } } } +} +