X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FFDM%2FJSBSim%2FFGFDMExec.cpp;h=ade4209cdf5a26fa07a7673964c13b66bcb8006f;hb=0d233c0dfc2cab48be7642ef17f11e1b9ff9ced5;hp=25f849a9d8bd4614e57e18ae57d02d2e566b832c;hpb=48e948d4bcd65cc8ccdfb23097ed9ea592e4226c;p=flightgear.git diff --git a/src/FDM/JSBSim/FGFDMExec.cpp b/src/FDM/JSBSim/FGFDMExec.cpp index 25f849a9d..ade4209cd 100644 --- a/src/FDM/JSBSim/FGFDMExec.cpp +++ b/src/FDM/JSBSim/FGFDMExec.cpp @@ -5,7 +5,7 @@ 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 Lesser General Public License as published by the Free Software @@ -42,74 +42,51 @@ INCLUDES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ #include "FGFDMExec.h" -#include "FGState.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include // Remove until later -#include -#include +#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$"; +static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.84 2011/01/16 16:26:14 bcoconni Exp $"; static const char *IdHdr = ID_FDMEXEC; -/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -GLOBAL DECLARATIONS -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ - -unsigned int FGFDMExec::FDMctr = 0; -FGPropertyManager* FGFDMExec::master=0; - /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% CLASS IMPLEMENTATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ -void checkTied ( FGPropertyManager *node ) -{ - int N = node->nChildren(); - string name; - - for (int i=0; igetChild(i)->nChildren() ) { -// cout << "Untieing " << node->getChild(i)->getName() << " property branch." << endl; - checkTied( (FGPropertyManager*)node->getChild(i) ); - } else if ( node->getChild(i)->isTied() ) { - name = ((FGPropertyManager*)node->getChild(i))->GetFullyQualifiedName(); - node->Untie(name); - } - } -} - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // Constructor -FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root) +FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root), FDMctr(fdmctr) { Frame = 0; - FirstModel = 0; Error = 0; GroundCallback = 0; - State = 0; Atmosphere = 0; FCS = 0; Propulsion = 0; @@ -127,34 +104,41 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root) Trim = 0; Script = 0; + RootDir = ""; + modelLoaded = false; - IsSlave = false; + IsChild = false; holding = false; Terminate = false; + StandAlone = false; - // Multiple FDM's are stopped for now. We need to ensure that - // the "user" instance always gets the zeroeth instance number, - // because there may be instruments or scripts tied to properties - // in the jsbsim[0] node. - // ToDo: it could be that when JSBSim is reset and a new FDM is wanted, that - // process might try setting FDMctr = 0. Then the line below would not need - // to be commented out. - 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 = atoi(num); // set debug level - } catch (...) { // if error set to 1 + } catch (...) { // if error set to 1 debug_lvl = 1; } - if (Root == 0) { - if (master == 0) - master = new FGPropertyManager; - Root = master; + if (Root == 0) { // Then this is the root FDM + Root = new FGPropertyManager; // Create the property manager + StandAlone = true; + } + + 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 to catch errors in binding member functions to the property tree. @@ -172,7 +156,11 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root) 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; } @@ -181,17 +169,30 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root) FGFDMExec::~FGFDMExec() { try { - checkTied( instance ); + Unbind(); DeAllocate(); - if (Root == 0) delete master; + + 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; - SlaveFDMList.clear(); + for (unsigned int i=1; iexec; + ChildFDMList.clear(); + + PropertyCatalog.clear(); - //ToDo remove property catalog. + FDMctr--; Debug(1); } @@ -219,32 +220,9 @@ bool FGFDMExec::Allocate(void) Auxiliary = new FGAuxiliary(this); Input = new FGInput(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 - - Atmosphere->InitModel(); - FCS->InitModel(); - Propulsion->InitModel(); - MassBalance->InitModel(); - Aerodynamics->InitModel(); - Inertial->InitModel(); - GroundReactions->InitModel(); - ExternalReactions->InitModel(); - BuoyantForces->InitModel(); - Aircraft->InitModel(); - Propagate->InitModel(); - Auxiliary->InitModel(); - Input->InitModel(); - - IC = new FGInitialCondition(this); - // Schedule a model. The second arg (the integer) is the pass number. For - // instance, the atmosphere model could get executed every fifth pass it is called - // by the executive. IC and Trim objects are NOT scheduled. - + // instance, the atmosphere model could get executed every fifth pass it is called. + Schedule(Input, 1); Schedule(Atmosphere, 1); Schedule(FCS, 1); @@ -259,6 +237,13 @@ bool FGFDMExec::Allocate(void) Schedule(Propagate, 1); Schedule(Auxiliary, 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; return result; @@ -281,7 +266,6 @@ bool FGFDMExec::DeAllocate(void) delete Aircraft; delete Propagate; delete Auxiliary; - delete State; delete Script; for (unsigned i=0; iNextModel = 0L; - FirstModel->SetRate(rate); - - } else { // subsequent model - - while (model_iterator->NextModel != 0L) { - model_iterator = model_iterator->NextModel; - } - model_iterator->NextModel = model; - model_iterator->NextModel->SetRate(rate); - - } - - return 0; + model->SetRate(rate); + Models.push_back(model); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -347,29 +312,22 @@ int FGFDMExec::Schedule(FGModel* model, int rate) bool FGFDMExec::Run(void) { bool success=true; - FGModel* model_iterator; - - model_iterator = FirstModel; - if (model_iterator == 0L) return false; Debug(2); - for (unsigned int i=1; iexec->State->Initialize(); // Transfer state to the slave FDM -// SlaveFDMList[i]->exec->Run(); + for (unsigned int i=1; iAssignState(Propagate); // Transfer state to the child FDM + ChildFDMList[i]->Run(); } - // returns true if success - // false if complete - if (Script != 0 && !State->IntegrationSuspended()) success = Script->RunScript(); + // returns true if success, false if complete + if (Script != 0 && !IntegrationSuspended()) success = Script->RunScript(); - while (model_iterator != 0L) { - model_iterator->Run(); - model_iterator = model_iterator->NextModel; - } + vector ::iterator it; + for (it = Models.begin(); it != Models.end(); ++it) (*it)->Run(); Frame++; - if (!Holding()) State->IncrTime(); + if (!Holding()) IncrTime(); if (Terminate) success = false; return (success); @@ -380,52 +338,84 @@ bool FGFDMExec::Run(void) bool FGFDMExec::RunIC(void) { - State->SuspendIntegration(); - State->Initialize(IC); + SuspendIntegration(); // saves the integration rate, dt, then sets it to 0.0. + Initialize(IC); Run(); - State->ResumeIntegration(); + ResumeIntegration(); // Restores the integration rate to what it was. return true; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void FGFDMExec::ResetToInitialConditions(void) +void FGFDMExec::Initialize(FGInitialCondition *FGIC) { - FGModel* model_iterator; + Propagate->SetInitialState( FGIC ); - model_iterator = FirstModel; - if (model_iterator == 0L) return; + Atmosphere->Run(); + Atmosphere->SetWindNED( FGIC->GetWindNFpsIC(), + FGIC->GetWindEFpsIC(), + FGIC->GetWindDFpsIC() ); - while (model_iterator != 0L) { - model_iterator->InitModel(); - model_iterator = model_iterator->NextModel; - } + FGColumnVector3 vAeroUVW; + vAeroUVW = Propagate->GetUVW() + Propagate->GetTl2b()*Atmosphere->GetTotalWindNED(); - RunIC(); - if (Script) Script->ResetEvents(); + 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; + + Auxiliary->SetAB(alpha, beta); + + double Vt = vAeroUVW.Magnitude(); + Auxiliary->SetVt(Vt); + + Auxiliary->SetMach(Vt/Atmosphere->GetSoundSpeed()); + + 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. -void FGFDMExec::SetGroundCallback(FGGroundCallback* p) +void FGFDMExec::ResetToInitialConditions(int mode) { - delete GroundCallback; - GroundCallback = p; + if (mode == 1) { + for (unsigned int i=0; iSetStartNewFile(true); + } + } + + ResetToInitialConditions(); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -double FGFDMExec::GetSimTime(void) +void FGFDMExec::ResetToInitialConditions(void) { - return (State->Getsim_time()); + if (Constructing) return; + + vector ::iterator it; + for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel(); + + RunIC(); + if (Script) Script->ResetEvents(); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -double FGFDMExec::GetDeltaT(void) +void FGFDMExec::SetGroundCallback(FGGroundCallback* p) { - return (State->Getdt()); + delete GroundCallback; + GroundCallback = p; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -436,8 +426,8 @@ vector FGFDMExec::EnumerateFDMs(void) FDMList.push_back(Aircraft->GetAircraftName()); - for (unsigned int i=1; iexec->GetAircraft()->GetAircraftName()); + for (unsigned int i=1; iexec->GetAircraft()->GetAircraftName()); } return FDMList; @@ -445,35 +435,34 @@ vector FGFDMExec::EnumerateFDMs(void) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::LoadScript(string script) +bool FGFDMExec::LoadScript(const string& script, double deltaT) { bool result; Script = new FGScript(this); - result = Script->LoadScript(script); + result = Script->LoadScript(RootDir + script, deltaT); return result; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::LoadModel(string AircraftPath, string EnginePath, string SystemsPath, - string model, bool addModelToPath) +bool FGFDMExec::LoadModel(const string& AircraftPath, const string& EnginePath, const string& SystemsPath, + const string& model, bool addModelToPath) { - FGFDMExec::AircraftPath = AircraftPath; - FGFDMExec::EnginePath = EnginePath; - FGFDMExec::SystemsPath = SystemsPath; + FGFDMExec::AircraftPath = RootDir + AircraftPath; + FGFDMExec::EnginePath = RootDir + EnginePath; + FGFDMExec::SystemsPath = RootDir + SystemsPath; return LoadModel(model, addModelToPath); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::LoadModel(string model, bool addModelToPath) +bool FGFDMExec::LoadModel(const string& model, bool addModelToPath) { string token; string aircraftCfgFileName; - string separator = "/"; Element* element = 0L; bool result = false; // initialize result to false, indicating input file not yet read @@ -486,74 +475,225 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) } FullAircraftPath = AircraftPath; - if (addModelToPath) FullAircraftPath += separator + model; - aircraftCfgFileName = FullAircraftPath + separator + model + ".xml"; + if (addModelToPath) FullAircraftPath += "/" + model; + aircraftCfgFileName = FullAircraftPath + "/" + model + ".xml"; if (modelLoaded) { DeAllocate(); Allocate(); } + int saved_debug_lvl = debug_lvl; + document = LoadXMLDocument(aircraftCfgFileName); // "document" is a class member if (document) { + if (IsChild) debug_lvl = 0; + ReadPrologue(document); - element = document->GetElement(); - - result = true; - while (element && result) { - string element_name = element->GetName(); - if (element_name == "fileheader" ) result = ReadFileHeader(element); - else if (element_name == "slave") result = ReadSlave(element); - else if (element_name == "metrics") result = Aircraft->Load(element); - else if (element_name == "mass_balance") result = MassBalance->Load(element); - else if (element_name == "ground_reactions") result = GroundReactions->Load(element); - else if (element_name == "external_reactions") result = ExternalReactions->Load(element); - else if (element_name == "buoyant_forces") result = BuoyantForces->Load(element); - else if (element_name == "propulsion") result = Propulsion->Load(element); - else if (element_name == "system") result = FCS->Load(element, - FGFCS::stSystem); - else if (element_name == "autopilot") result = FCS->Load(element, - FGFCS::stAutoPilot); - else if (element_name == "flight_control") result = FCS->Load(element, - FGFCS::stFCS); - else if (element_name == "aerodynamics") result = Aerodynamics->Load(element); - else if (element_name == "input") result = Input->Load(element); - else if (element_name == "output") { - FGOutput* Output = new FGOutput(this); - Output->InitModel(); - Schedule(Output, 1); - result = Output->Load(element); - Outputs.push_back(Output); + + 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 << "Found unexpected subsystem: " << element_name << ", exiting." << endl; - result = false; - break; + } 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; } - element = document->GetNextElement(); } - } else { - cerr << fgred - << " JSBSim failed to load aircraft model." - << fgdef << endl; - return false; - } - 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 - << " JSBSim failed to load properly." + << " JSBSim failed to open the configuration file: " << aircraftCfgFileName << fgdef << endl; - return false; } - struct PropertyCatalogStructure masterPCS; - masterPCS.base_string = ""; - masterPCS.node = (FGPropertyManager*)Root; + // Late bind previously undefined FCS inputs. + try { + FCS->LateBind(); + } catch (string prop) { + cerr << endl << fgred << " Could not late bind property " << prop + << ". Aborting." << reset << endl; + result = false; + } - BuildPropertyCatalog(&masterPCS); + if (result) { + struct PropertyCatalogStructure masterPCS; + masterPCS.base_string = ""; + masterPCS.node = (FGPropertyManager*)Root; + BuildPropertyCatalog(&masterPCS); + } return result; } @@ -564,13 +704,13 @@ void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs) { struct PropertyCatalogStructure* pcsNew = new struct PropertyCatalogStructure; int node_idx = 0; - char int_buf[10]; - for (unsigned int i=0; inode->nChildren(); i++) { + 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(); - sprintf(int_buf, "[%d]", node_idx); - if (node_idx != 0) pcsNew->base_string += string(int_buf); + 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); @@ -586,7 +726,7 @@ void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -string FGFDMExec::QueryPropertyCatalog(string in) +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; - if (el->FindElement("description")) - cout << " Description: " << el->FindElement("description")->GetDataLine() << endl; return result; } @@ -690,54 +834,51 @@ bool FGFDMExec::ReadPrologue(Element* el) // el for ReadPrologue is the document //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::ReadSlave(Element* el) +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(true); -/* - string AircraftName = AC_cfg->GetValue("file"); - - debug_lvl = 0; // turn off debug output for slave vehicle - - SlaveFDMList.back()->exec->SetAircraftPath( AircraftPath ); - SlaveFDMList.back()->exec->SetEnginePath( EnginePath ); - SlaveFDMList.back()->exec->SetSystemsPath( SystemsPath ); - SlaveFDMList.back()->exec->LoadModel(AircraftName); - debug_lvl = saved_debug_lvl; // turn debug output back on for master vehicle - - AC_cfg->GetNextConfigLine(); - while ((token = AC_cfg->GetValue()) != string("/SLAVE")) { - *AC_cfg >> token; - if (token == "xloc") { *AC_cfg >> SlaveFDMList.back()->x; } - else if (token == "yloc") { *AC_cfg >> SlaveFDMList.back()->y; } - else if (token == "zloc") { *AC_cfg >> SlaveFDMList.back()->z; } - else if (token == "pitch") { *AC_cfg >> SlaveFDMList.back()->pitch;} - else if (token == "yaw") { *AC_cfg >> SlaveFDMList.back()->yaw; } - else if (token == "roll") { *AC_cfg >> SlaveFDMList.back()->roll; } - else cerr << "Unknown identifier: " << token << " in slave vehicle definition" << endl; + struct childData* child = new childData; + + child->exec = new FGFDMExec(Root, FDMctr); + child->exec->SetChild(true); + + 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); } -*/ - if (debug_lvl > 0) { - cout << " X = " << SlaveFDMList.back()->x << endl; - cout << " Y = " << SlaveFDMList.back()->y << endl; - cout << " Z = " << SlaveFDMList.back()->z << endl; - cout << " Pitch = " << SlaveFDMList.back()->pitch << endl; - cout << " Yaw = " << SlaveFDMList.back()->yaw << endl; - cout << " Roll = " << SlaveFDMList.back()->roll << endl; + + 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; } @@ -777,16 +918,22 @@ void FGFDMExec::EnableOutput(void) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::SetOutputDirectives(string fname) +bool FGFDMExec::SetOutputDirectives(const string& fname) { bool result; FGOutput* Output = new FGOutput(this); - Output->SetDirectivesFile(fname); + Output->SetDirectivesFile(RootDir + fname); Output->InitModel(); - Schedule(Output, 1); + Schedule(Output, 1); result = Output->Load(0); - Outputs.push_back(Output); + + 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 result; } @@ -803,11 +950,11 @@ void FGFDMExec::DoTrim(int mode) cerr << endl << "Illegal trimming mode!" << endl << endl; return; } - saved_time = State->Getsim_time(); + saved_time = sim_time; FGTrim trim(this, (JSBSim::TrimMode)mode); if ( !trim.DoTrim() ) cerr << endl << "Trim Failed" << endl << endl; trim.Report(); - State->Setsim_time(saved_time); + sim_time = saved_time; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -821,7 +968,7 @@ void FGFDMExec::DoTrimAnalysis(int mode) cerr << endl << "Illegal trimming mode!" << endl << endl; return; } - saved_time = State->Getsim_time(); + saved_time = sim_time; FGTrimAnalysis trimAnalysis(this, (JSBSim::TrimAnalysisMode)mode); @@ -835,7 +982,7 @@ void FGFDMExec::DoTrimAnalysis(int mode) if ( !result ) cerr << endl << "Trim Failed" << endl << endl; trimAnalysis.Report(); - State->Setsim_time(saved_time); + Setsim_time(saved_time); EnableOutput(); cout << "\nOutput: " << GetOutputFileName() << endl; @@ -910,7 +1057,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() << " dt: " << State->Getdt() << endl; + << sim_time << " dt: " << dT << endl; } } if (debug_lvl & 8 ) { // Runtime state variables