%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFDMExec.h"
-#include "FGState.h"
#include "models/FGAtmosphere.h"
#include "models/atmosphere/FGMSIS.h"
#include "models/atmosphere/FGMars.h"
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; i<N; i++) {
- if (node->getChild(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) : Root(root)
+FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root), FDMctr(fdmctr)
{
Frame = 0;
Error = 0;
GroundCallback = 0;
- State = 0;
Atmosphere = 0;
FCS = 0;
Propulsion = 0;
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.
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;
}
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;
}
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
-
// 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.
Schedule(Input, 1);
- Schedule(Atmosphere, 30);
+ Schedule(Atmosphere, 1);
Schedule(FCS, 1);
Schedule(Propulsion, 1);
Schedule(MassBalance, 1);
delete Aircraft;
delete Propagate;
delete Auxiliary;
- delete State;
delete Script;
for (unsigned i=0; i<Outputs.size(); i++) delete Outputs[i];
Error = 0;
- State = 0;
Input = 0;
Atmosphere = 0;
FCS = 0;
}
// returns true if success, false if complete
- if (Script != 0 && !State->IntegrationSuspended()) success = Script->RunScript();
+ if (Script != 0 && !IntegrationSuspended()) success = Script->RunScript();
vector <FGModel*>::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);
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
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-double FGFDMExec::GetSimTime(void)
-{
- return (State->Getsim_time());
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGFDMExec::GetDeltaT(void)
-{
- return (State->Getdt());
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
vector <string> FGFDMExec::EnumerateFDMs(void)
{
vector <string> FDMList;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-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
}
FullAircraftPath = AircraftPath;
- if (addModelToPath) FullAircraftPath += separator + model;
- aircraftCfgFileName = FullAircraftPath + separator + model + ".xml";
+ if (addModelToPath) FullAircraftPath += "/" + model;
+ aircraftCfgFileName = FullAircraftPath + "/" + model + ".xml";
if (modelLoaded) {
DeAllocate();
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
<< "-------------------------------------------------------------------------------"
<< 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;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-string FGFDMExec::QueryPropertyCatalog(string in)
+string FGFDMExec::QueryPropertyCatalog(const string& in)
{
string results="";
for (unsigned i=0; i<PropertyCatalog.size(); i++) {
struct childData* child = new childData;
- child->exec = new FGFDMExec();
+ child->exec = new FGFDMExec(Root, FDMctr);
child->exec->SetChild(true);
string childAircraft = el->GetAttributeValue("name");
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-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);
- 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 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;
}
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;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cerr << endl << "Illegal trimming mode!" << endl << endl;
return;
}
- saved_time = State->Getsim_time();
+ saved_time = sim_time;
FGTrimAnalysis trimAnalysis(this, (JSBSim::TrimAnalysisMode)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;
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