X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FFDM%2FJSBSim%2FFGFDMExec.cpp;h=ade4209cdf5a26fa07a7673964c13b66bcb8006f;hb=717ffe584f9e83ebfd5daebe226b5fac7832c64a;hp=91aff117788a7a7124819a7e930641ef5a611aa4;hpb=1ed6276f16d4c5eeef0527830c1bd190af06bdcc;p=flightgear.git diff --git a/src/FDM/JSBSim/FGFDMExec.cpp b/src/FDM/JSBSim/FGFDMExec.cpp index 91aff1177..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,73 +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() ) { - 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; @@ -126,30 +104,41 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root) Trim = 0; Script = 0; + RootDir = ""; + modelLoaded = false; IsChild = false; holding = false; Terminate = false; + StandAlone = false; - IdFDM = FDMctr; // The main (parent) JSBSim instance is always the "zeroth" - // instance. "child" instances are loaded last. + 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; + } - // JSBSim Standalone, multiple childs are allowed - FDMctr++; + 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. @@ -169,6 +158,9 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root) 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; } @@ -177,9 +169,20 @@ 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; } @@ -189,6 +192,8 @@ FGFDMExec::~FGFDMExec() PropertyCatalog.clear(); + FDMctr--; + Debug(1); } @@ -215,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); @@ -255,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; @@ -277,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); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -343,10 +312,6 @@ 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); @@ -355,17 +320,14 @@ bool FGFDMExec::Run(void) 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); @@ -376,14 +338,49 @@ 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::Initialize(FGInitialCondition *FGIC) +{ + Propagate->SetInitialState( FGIC ); + + Atmosphere->Run(); + Atmosphere->SetWindNED( FGIC->GetWindNFpsIC(), + FGIC->GetWindEFpsIC(), + FGIC->GetWindDFpsIC() ); + + FGColumnVector3 vAeroUVW; + vAeroUVW = Propagate->GetUVW() + Propagate->GetTl2b()*Atmosphere->GetTotalWindNED(); + + 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 @@ -404,15 +401,10 @@ void FGFDMExec::ResetToInitialConditions(int mode) void FGFDMExec::ResetToInitialConditions(void) { - FGModel* model_iterator; - - model_iterator = FirstModel; - if (model_iterator == 0L || Constructing) return; + if (Constructing) return; - while (model_iterator != 0L) { - model_iterator->InitModel(); - model_iterator = model_iterator->NextModel; - } + vector ::iterator it; + for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel(); RunIC(); if (Script) Script->ResetEvents(); @@ -428,20 +420,6 @@ void FGFDMExec::SetGroundCallback(FGGroundCallback* p) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -double FGFDMExec::GetSimTime(void) -{ - return (State->Getsim_time()); -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -double FGFDMExec::GetDeltaT(void) -{ - return (State->Getdt()); -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - vector FGFDMExec::EnumerateFDMs(void) { vector FDMList; @@ -457,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 @@ -498,8 +475,8 @@ 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(); @@ -651,16 +628,23 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) } // 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); - Outputs.push_back(Output); 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"); } @@ -678,6 +662,9 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) modelLoaded = true; 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 << "-------------------------------------------------------------------------------" @@ -692,11 +679,21 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) << fgdef << endl; } - 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; } @@ -707,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); @@ -729,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; iexec = new FGFDMExec(); + child->exec = new FGFDMExec(Root, FDMctr); child->exec->SetChild(true); string childAircraft = el->GetAttributeValue("name"); @@ -921,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; } @@ -947,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; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -965,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); @@ -979,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; @@ -1054,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