X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FFDM%2FJSBSim%2FFGFDMExec.cpp;h=a3b08a49ec5deaf6afdf01e392f4cfdcf5ac3f75;hb=de1564d83e32cf077a5367cc838f28271dd79381;hp=227c0267fc6d8b07152b7841dbced7d461aa7751;hpb=82364aa4da90f9efd0047ababb42fc402f382015;p=flightgear.git diff --git a/src/FDM/JSBSim/FGFDMExec.cpp b/src/FDM/JSBSim/FGFDMExec.cpp index 227c0267f..a3b08a49e 100644 --- a/src/FDM/JSBSim/FGFDMExec.cpp +++ b/src/FDM/JSBSim/FGFDMExec.cpp @@ -42,7 +42,6 @@ INCLUDES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ #include "FGFDMExec.h" -#include "FGState.h" #include "models/FGAtmosphere.h" #include "models/atmosphere/FGMSIS.h" #include "models/atmosphere/FGMars.h" @@ -72,46 +71,22 @@ using namespace std; namespace JSBSim { -static const char *IdSrc = "$Id$"; +static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.91 2011/04/05 20:20:21 andgi 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; @@ -129,27 +104,45 @@ 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. + + AircraftPath = "aircraft"; + EnginePath = "engine"; + SystemsPath = "systems"; 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. @@ -165,10 +158,14 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root) 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/do_trim_analysis", this, (iPMF)0, &FGFDMExec::DoTrimAnalysis, false); + instance->Tie("simulation/do_simple_trim", this, (iPMF)0, &FGFDMExec::DoTrim, false); + instance->Tie("simulation/reset", this, (iPMF)0, &FGFDMExec::ResetToInitialConditions, false); 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); + instance->Tie("simulation/frame", (int *)&Frame, false); + Constructing = false; } @@ -177,9 +174,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; } @@ -217,32 +225,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); @@ -257,6 +242,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; @@ -279,7 +271,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); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -345,10 +317,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); @@ -357,17 +325,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); @@ -378,14 +343,54 @@ 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) +{ + Setsim_time(0.0); + + Propagate->SetInitialState( FGIC ); + + Atmosphere->Run(); + Atmosphere->SetWindNED( FGIC->GetWindNFpsIC(), + FGIC->GetWindEFpsIC(), + FGIC->GetWindDFpsIC() ); + + FGColumnVector3 vAeroUVW; + + //ToDo: move this to the Auxiliary class !? + + 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 @@ -406,15 +411,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(); @@ -430,20 +430,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; @@ -459,35 +445,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 @@ -500,8 +485,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(); @@ -654,7 +639,9 @@ 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; + typedef double (FGOutput::*iOPMF)(void) const; + typedef int (FGFDMExec::*iOPV)(void) const; + typedef void (FGFDMExec::*vOPI)(int) const; element = document->FindElement("output"); while (element) { if (debug_lvl > 0) cout << endl << " Output data set: " << idx << " "; @@ -668,7 +655,8 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) } else { Outputs.push_back(Output); string outputProp = CreateIndexedPropertyName("simulation/output",idx); - instance->Tie(outputProp+"/log_rate_hz", Output, (iOPMF)0, &FGOutput::SetRate); + instance->Tie(outputProp+"/log_rate_hz", Output, (iOPMF)0, &FGOutput::SetRate, false); + instance->Tie("simulation/force-output", this, (iOPV)0, &FGFDMExec::ForceOutput, false); idx++; } element = document->FindNextElement("output"); @@ -687,6 +675,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 << "-------------------------------------------------------------------------------" @@ -701,11 +692,12 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) << fgdef << endl; } - struct PropertyCatalogStructure masterPCS; - masterPCS.base_string = ""; - masterPCS.node = (FGPropertyManager*)Root; - - BuildPropertyCatalog(&masterPCS); + if (result) { + struct PropertyCatalogStructure masterPCS; + masterPCS.base_string = ""; + masterPCS.node = (FGPropertyManager*)Root; + BuildPropertyCatalog(&masterPCS); + } return result; } @@ -738,7 +730,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"); @@ -930,20 +922,29 @@ void FGFDMExec::EnableOutput(void) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::SetOutputDirectives(string fname) +void FGFDMExec::ForceOutput(int idx) +{ + if (idx >= 0 && idx < Outputs.size()) Outputs[idx]->Print(); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +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); - 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); + if (result) { + Outputs.push_back(Output); + typedef double (FGOutput::*iOPMF)(void) const; + string outputProp = CreateIndexedPropertyName("simulation/output",Outputs.size()-1); + instance->Tie(outputProp+"/log_rate_hz", Output, (iOPMF)0, &FGOutput::SetRate, false); + } return result; } @@ -960,11 +961,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; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -978,7 +979,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); @@ -992,7 +993,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; @@ -1067,7 +1068,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