X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FFDM%2FJSBSim%2FFGFDMExec.cpp;h=ab0bf8a9acdd4cf50088aed6d31e78ee0b644894;hb=6b6d7059de394bf270c8a0660820c5fc0a4c7fd4;hp=a6b5a736708f8fe46f7ef9e07a901791f185c453;hpb=4aff7b279db80407d82d0a5556738cf111501457;p=flightgear.git diff --git a/src/FDM/JSBSim/FGFDMExec.cpp b/src/FDM/JSBSim/FGFDMExec.cpp index a6b5a7367..ab0bf8a9a 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,43 +42,38 @@ 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.83 2010/11/07 13:30:54 jberndt Exp $"; static const char *IdHdr = ID_FDMEXEC; -/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -GLOBAL DECLARATIONS -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ - -unsigned int FGFDMExec::FDMctr = 0; -FGPropertyManager* FGFDMExec::master=0; - /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% CLASS IMPLEMENTATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ @@ -91,7 +86,8 @@ void checkTied ( FGPropertyManager *node ) for (int i=0; igetChild(i)->nChildren() ) { checkTied( (FGPropertyManager*)node->getChild(i) ); - } else if ( node->getChild(i)->isTied() ) { + } + if ( node->getChild(i)->isTied() ) { name = ((FGPropertyManager*)node->getChild(i))->GetFullyQualifiedName(); node->Untie(name); } @@ -101,14 +97,12 @@ void checkTied ( FGPropertyManager *node ) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // 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,27 +120,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" - FDMctr++; // 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; } + 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. @@ -166,6 +174,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; } @@ -176,7 +187,18 @@ FGFDMExec::~FGFDMExec() try { checkTied( instance ); 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; } @@ -186,6 +208,8 @@ FGFDMExec::~FGFDMExec() PropertyCatalog.clear(); + FDMctr--; + Debug(1); } @@ -212,32 +236,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); @@ -252,6 +253,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; @@ -274,7 +282,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); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -340,10 +328,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); @@ -352,17 +336,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); @@ -373,14 +354,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 @@ -401,15 +417,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(); @@ -425,20 +436,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; @@ -454,35 +451,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 @@ -495,8 +491,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(); @@ -648,16 +644,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"); } @@ -675,6 +678,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 << "-------------------------------------------------------------------------------" @@ -689,11 +695,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." << endl; + result = false; + } - BuildPropertyCatalog(&masterPCS); + if (result) { + struct PropertyCatalogStructure masterPCS; + masterPCS.base_string = ""; + masterPCS.node = (FGPropertyManager*)Root; + BuildPropertyCatalog(&masterPCS); + } return result; } @@ -704,13 +720,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); @@ -726,7 +742,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"); @@ -918,16 +934,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; } @@ -944,11 +966,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; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -962,7 +984,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); @@ -976,7 +998,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; @@ -1051,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() << " dt: " << State->Getdt() << endl; + << sim_time << " dt: " << dT << endl; } } if (debug_lvl & 8 ) { // Runtime state variables