X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FFDM%2FJSBSim%2FFGFDMExec.cpp;h=d5c81f8217d5a6f7b3e8b33f30e9fb49f7facac9;hb=c112b8b8e169a427e8cb0da871347e5c10031479;hp=6851223810d1208eaca2be7bc291c05f934a3963;hpb=cf9a520a9f404e66cef7fd1955a62127e6d31f93;p=flightgear.git diff --git a/src/FDM/JSBSim/FGFDMExec.cpp b/src/FDM/JSBSim/FGFDMExec.cpp index 685122381..d5c81f821 100644 --- a/src/FDM/JSBSim/FGFDMExec.cpp +++ b/src/FDM/JSBSim/FGFDMExec.cpp @@ -41,11 +41,13 @@ COMMENTS, REFERENCES, and NOTES INCLUDES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ +#include +#include +#include + #include "FGFDMExec.h" -#include "FGState.h" -#include "models/FGAtmosphere.h" -#include "models/atmosphere/FGMSIS.h" -#include "models/atmosphere/FGMars.h" +#include "models/atmosphere/FGStandardAtmosphere.h" +#include "models/atmosphere/FGWinds.h" #include "models/FGFCS.h" #include "models/FGPropulsion.h" #include "models/FGMassBalance.h" @@ -55,101 +57,78 @@ INCLUDES #include "models/FGAerodynamics.h" #include "models/FGInertial.h" #include "models/FGAircraft.h" +#include "models/FGAccelerations.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.120 2011/11/10 12:06:13 jberndt 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) ); - } - 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; - MassBalance = 0; - Aerodynamics = 0; - Inertial = 0; - GroundReactions = 0; - ExternalReactions = 0; - BuoyantForces = 0; - Aircraft = 0; - Propagate = 0; - Auxiliary = 0; - Input = 0; + SetGroundCallback(new FGDefaultGroundCallback()); IC = 0; Trim = 0; Script = 0; + RootDir = ""; + modelLoaded = false; IsChild = false; holding = false; Terminate = false; + StandAlone = false; + firstPass = true; + + 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. - IdFDM = FDMctr; // The main (parent) JSBSim instance is always the "zeroth" - FDMctr++; // instance. "child" instances are loaded last. + 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 +144,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 +160,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,7 +183,7 @@ FGFDMExec::~FGFDMExec() PropertyCatalog.clear(); - FDMctr--; + if (FDMctr > 0) (*FDMctr)--; Debug(1); } @@ -200,48 +194,54 @@ bool FGFDMExec::Allocate(void) { bool result=true; - Atmosphere = new FGAtmosphere(this); - FCS = new FGFCS(this); - Propulsion = new FGPropulsion(this); - MassBalance = new FGMassBalance(this); - Aerodynamics = new FGAerodynamics (this); - Inertial = new FGInertial(this); - - GroundCallback = new FGGroundCallback(Inertial->GetRefRadius()); - - GroundReactions = new FGGroundReactions(this); - ExternalReactions = new FGExternalReactions(this); - BuoyantForces = new FGBuoyantForces(this); - Aircraft = new FGAircraft(this); - Propagate = new FGPropagate(this); - 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(FCS, 1); - Schedule(Propulsion, 1); - Schedule(MassBalance, 1); - Schedule(Aerodynamics, 1); - Schedule(Inertial, 1); - Schedule(GroundReactions, 1); - Schedule(ExternalReactions, 1); - Schedule(BuoyantForces, 1); - Schedule(Aircraft, 1); - 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(); + Models.resize(eNumStandardModels); + + // See the eModels enum specification in the header file. The order of the enums + // specifies the order of execution. The Models[] vector is the primary + // storage array for the list of models. + Models[ePropagate] = new FGPropagate(this); + Models[eInput] = new FGInput(this); + Models[eInertial] = new FGInertial(this); + Models[eAtmosphere] = new FGStandardAtmosphere(this); + Models[eWinds] = new FGWinds(this); + Models[eAuxiliary] = new FGAuxiliary(this); + Models[eSystems] = new FGFCS(this); + Models[ePropulsion] = new FGPropulsion(this); + Models[eAerodynamics] = new FGAerodynamics (this); + + GetGroundCallback()->SetSeaLevelRadius(((FGInertial*)Models[eInertial])->GetRefRadius()); + + Models[eGroundReactions] = new FGGroundReactions(this); + Models[eExternalReactions] = new FGExternalReactions(this); + Models[eBuoyantForces] = new FGBuoyantForces(this); + Models[eMassBalance] = new FGMassBalance(this); + Models[eAircraft] = new FGAircraft(this); + Models[eAccelerations] = new FGAccelerations(this); + + // Assign the Model shortcuts for internal executive use only. + Propagate = (FGPropagate*)Models[ePropagate]; + Inertial = (FGInertial*)Models[eInertial]; + Atmosphere = (FGAtmosphere*)Models[eAtmosphere]; + Winds = (FGWinds*)Models[eWinds]; + Auxiliary = (FGAuxiliary*)Models[eAuxiliary]; + FCS = (FGFCS*)Models[eSystems]; + Propulsion = (FGPropulsion*)Models[ePropulsion]; + Aerodynamics = (FGAerodynamics*)Models[eAerodynamics]; + GroundReactions = (FGGroundReactions*)Models[eGroundReactions]; + ExternalReactions = (FGExternalReactions*)Models[eExternalReactions]; + BuoyantForces = (FGBuoyantForces*)Models[eBuoyantForces]; + MassBalance = (FGMassBalance*)Models[eMassBalance]; + Aircraft = (FGAircraft*)Models[eAircraft]; + Accelerations = (FGAccelerations*)Models[eAccelerations]; + + // Initialize planet (environment) constants + LoadPlanetConstants(); + + // Initialize models + for (unsigned int i = 0; i < Models.size(); i++) { + LoadInputs(i); + Models[i]->InitModel(); + } IC = new FGInitialCondition(this); @@ -254,50 +254,19 @@ bool FGFDMExec::Allocate(void) bool FGFDMExec::DeAllocate(void) { - delete Input; - delete Atmosphere; - delete FCS; - delete Propulsion; - delete MassBalance; - delete Aerodynamics; - delete Inertial; - delete GroundReactions; - delete ExternalReactions; - delete BuoyantForces; - delete Aircraft; - delete Propagate; - delete Auxiliary; - delete State; - delete Script; + + for (unsigned int i=0; iAssignState(Propagate); // Transfer state to the child FDM + ChildFDMList[i]->AssignState( (FGPropagate*)Models[ePropagate] ); // Transfer state to the child FDM ChildFDMList[i]->Run(); } + if (firstPass && !IntegrationSuspended()) { + // Outputs the initial conditions + for (unsigned int i = 0; i < Outputs.size(); i++) + Outputs[i]->Run(holding); + + firstPass = false; + } + + IncrTime(); + // returns true if success, false if complete - if (Script != 0 && !State->IntegrationSuspended()) success = Script->RunScript(); + if (Script != 0 && !IntegrationSuspended()) success = Script->RunScript(); - vector ::iterator it; - for (it = Models.begin(); it != Models.end(); ++it) (*it)->Run(); + for (unsigned int i = 0; i < Models.size(); i++) { + LoadInputs(i); + Models[i]->Run(holding); + } - Frame++; - if (!Holding()) State->IncrTime(); if (Terminate) success = false; return (success); } +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGFDMExec::LoadInputs(unsigned int idx) +{ + switch(idx) { + case ePropagate: + Propagate->in.vPQRidot = Accelerations->GetPQRidot(); + Propagate->in.vQtrndot = Accelerations->GetQuaterniondot(); + Propagate->in.vUVWidot = Accelerations->GetUVWidot(); + Propagate->in.DeltaT = dT; + break; + case eInput: + break; + case eInertial: + Inertial->in.Radius = Propagate->GetRadius(); + Inertial->in.Latitude = Propagate->GetLatitude(); + break; + case eAtmosphere: + Atmosphere->in.altitudeASL = Propagate->GetAltitudeASL(); + break; + case eWinds: + Winds->in.AltitudeASL = Propagate->GetAltitudeASL(); + Winds->in.DistanceAGL = Propagate->GetDistanceAGL(); + Winds->in.Tl2b = Propagate->GetTl2b(); + Winds->in.Tw2b = Auxiliary->GetTw2b(); + Winds->in.V = Auxiliary->GetVt(); + Winds->in.totalDeltaT = dT * Winds->GetRate(); + break; + case eAuxiliary: + Auxiliary->in.Pressure = Atmosphere->GetPressure(); + Auxiliary->in.Density = Atmosphere->GetDensity(); + Auxiliary->in.DensitySL = Atmosphere->GetDensitySL(); + Auxiliary->in.PressureSL = Atmosphere->GetPressureSL(); + Auxiliary->in.Temperature = Atmosphere->GetTemperature(); + Auxiliary->in.SoundSpeed = Atmosphere->GetSoundSpeed(); + Auxiliary->in.KinematicViscosity = Atmosphere->GetKinematicViscosity(); + Auxiliary->in.DistanceAGL = Propagate->GetDistanceAGL(); + Auxiliary->in.Mass = MassBalance->GetMass(); + Auxiliary->in.Tl2b = Propagate->GetTl2b(); + Auxiliary->in.Tb2l = Propagate->GetTb2l(); + Auxiliary->in.vPQR = Propagate->GetPQR(); + Auxiliary->in.vPQRdot = Accelerations->GetPQRdot(); + Auxiliary->in.vUVW = Propagate->GetUVW(); + Auxiliary->in.vUVWdot = Accelerations->GetUVWdot(); + Auxiliary->in.vVel = Propagate->GetVel(); + Auxiliary->in.vBodyAccel = Accelerations->GetBodyAccel(); + Auxiliary->in.ToEyePt = MassBalance->StructuralToBody(Aircraft->GetXYZep()); + Auxiliary->in.VRPBody = MassBalance->StructuralToBody(Aircraft->GetXYZvrp()); + Auxiliary->in.RPBody = MassBalance->StructuralToBody(Aircraft->GetXYZrp()); + Auxiliary->in.vFw = Aerodynamics->GetvFw(); + Auxiliary->in.vLocation = Propagate->GetLocation(); + Auxiliary->in.Latitude = Propagate->GetLatitude(); + Auxiliary->in.Longitude = Propagate->GetLongitude(); + Auxiliary->in.CosTht = Propagate->GetCosEuler(eTht); + Auxiliary->in.SinTht = Propagate->GetSinEuler(eTht); + Auxiliary->in.CosPhi = Propagate->GetCosEuler(ePhi); + Auxiliary->in.SinPhi = Propagate->GetSinEuler(ePhi); + Auxiliary->in.Psi = Propagate->GetEuler(ePsi); + Auxiliary->in.TotalWindNED = Winds->GetTotalWindNED(); + Auxiliary->in.TurbPQR = Winds->GetTurbPQR(); + Auxiliary->in.WindPsi = Winds->GetWindPsi(); + Auxiliary->in.Vwind = Winds->GetTotalWindNED().Magnitude(); + break; + case eSystems: + // Dynamic inputs come into the components that FCS manages through properties + break; + case ePropulsion: + Propulsion->in.SLPressure = Atmosphere->GetPressureSL(); + Propulsion->in.Pressure = Atmosphere->GetPressure(); + Propulsion->in.PressureRatio = Atmosphere->GetPressureRatio(); + Propulsion->in.Temperature = Atmosphere->GetTemperature(); + Propulsion->in.DensityRatio = Atmosphere->GetDensityRatio(); + Propulsion->in.Density = Atmosphere->GetDensity(); + Propulsion->in.Soundspeed = Atmosphere->GetSoundSpeed(); + Propulsion->in.TotalPressure = Auxiliary->GetTotalPressure(); + Propulsion->in.TotalTempearture = Auxiliary->GetTotalTemperature(); + Propulsion->in.Vc = Auxiliary->GetVcalibratedKTS(); + Propulsion->in.Vt = Auxiliary->GetVt(); + Propulsion->in.qbar = Auxiliary->Getqbar(); + Propulsion->in.TAT_c = Auxiliary->GetTAT_C(); + Propulsion->in.AeroUVW = Auxiliary->GetAeroUVW(); + Propulsion->in.AeroPQR = Auxiliary->GetAeroPQR(); + Propulsion->in.alpha = Auxiliary->Getalpha(); + Propulsion->in.beta = Auxiliary->Getbeta(); + Propulsion->in.TotalDeltaT = dT * Propulsion->GetRate(); + Propulsion->in.ThrottlePos = FCS->GetThrottlePos(); + Propulsion->in.MixturePos = FCS->GetMixturePos(); + Propulsion->in.ThrottleCmd = FCS->GetThrottleCmd(); + Propulsion->in.MixtureCmd = FCS->GetMixtureCmd(); + Propulsion->in.PropAdvance = FCS->GetPropAdvance(); + Propulsion->in.PropFeather = FCS->GetPropFeather(); + Propulsion->in.H_agl = Propagate->GetDistanceAGL(); + Propulsion->in.PQR = Propagate->GetPQR(); + break; + case eAerodynamics: + Aerodynamics->in.Alpha = Auxiliary->Getalpha(); + Aerodynamics->in.Beta = Auxiliary->Getbeta(); + Aerodynamics->in.Qbar = Auxiliary->Getqbar(); + Aerodynamics->in.Vt = Auxiliary->GetVt(); + Aerodynamics->in.Tb2w = Auxiliary->GetTb2w(); + Aerodynamics->in.Tw2b = Auxiliary->GetTw2b(); + Aerodynamics->in.RPBody = MassBalance->StructuralToBody(Aircraft->GetXYZrp()); + break; + case eGroundReactions: + // There are no external inputs to this model. + GroundReactions->in.Vground = Auxiliary->GetVground(); + GroundReactions->in.VcalibratedKts = Auxiliary->GetVcalibratedKTS(); + GroundReactions->in.Temperature = Atmosphere->GetTemperature(); + GroundReactions->in.TakeoffThrottle = (FCS->GetThrottlePos().size() > 0) ? (FCS->GetThrottlePos(0) > 0.90) : false; + GroundReactions->in.SteerPosDeg = FCS->GetSteerPosDeg(); + GroundReactions->in.BrakePos = FCS->GetBrakePos(); + GroundReactions->in.FCSGearPos = FCS->GetGearPos(); + GroundReactions->in.EmptyWeight = MassBalance->GetEmptyWeight(); + GroundReactions->in.Tb2l = Propagate->GetTb2l(); + GroundReactions->in.Tec2l = Propagate->GetTec2l(); + GroundReactions->in.Tec2b = Propagate->GetTec2b(); + GroundReactions->in.PQR = Propagate->GetPQR(); + GroundReactions->in.UVW = Propagate->GetUVW(); + GroundReactions->in.DistanceAGL = Propagate->GetDistanceAGL(); + GroundReactions->in.DistanceASL = Propagate->GetAltitudeASL(); + GroundReactions->in.TotalDeltaT = dT * GroundReactions->GetRate(); + GroundReactions->in.WOW = GroundReactions->GetWOW(); + GroundReactions->in.Location = Propagate->GetLocation(); + for (int i=0; iGetNumGearUnits(); i++) { + GroundReactions->in.vWhlBodyVec[i] = MassBalance->StructuralToBody(GroundReactions->GetGearUnit(i)->GetLocation()); + } + break; + case eExternalReactions: + // There are no external inputs to this model. + break; + case eBuoyantForces: + BuoyantForces->in.Density = Atmosphere->GetDensity(); + BuoyantForces->in.Pressure = Atmosphere->GetPressure(); + BuoyantForces->in.Temperature = Atmosphere->GetTemperature(); + BuoyantForces->in.gravity = Inertial->gravity(); + break; + case eMassBalance: + MassBalance->in.GasInertia = BuoyantForces->GetGasMassInertia(); + MassBalance->in.GasMass = BuoyantForces->GetGasMass(); + MassBalance->in.GasMoment = BuoyantForces->GetGasMassMoment(); + MassBalance->in.TanksWeight = Propulsion->GetTanksWeight(); + MassBalance->in.TanksMoment = Propulsion->GetTanksMoment(); + MassBalance->in.TankInertia = Propulsion->CalculateTankInertias(); + break; + case eAircraft: + Aircraft->in.AeroForce = Aerodynamics->GetForces(); + Aircraft->in.PropForce = Propulsion->GetForces(); + Aircraft->in.GroundForce = GroundReactions->GetForces(); + Aircraft->in.ExternalForce = ExternalReactions->GetForces(); + Aircraft->in.BuoyantForce = BuoyantForces->GetForces(); + Aircraft->in.AeroMoment = Aerodynamics->GetMoments(); + Aircraft->in.PropMoment = Propulsion->GetMoments(); + Aircraft->in.GroundMoment = GroundReactions->GetMoments(); + Aircraft->in.ExternalMoment = ExternalReactions->GetMoments(); + Aircraft->in.BuoyantMoment = BuoyantForces->GetMoments(); + Aircraft->in.Weight = MassBalance->GetWeight(); + Aircraft->in.Tl2b = Propagate->GetTl2b(); + break; + case eAccelerations: + Accelerations->in.J = MassBalance->GetJ(); + Accelerations->in.Jinv = MassBalance->GetJinv(); + Accelerations->in.Ti2b = Propagate->GetTi2b(); + Accelerations->in.Tb2i = Propagate->GetTb2i(); + Accelerations->in.Tec2b = Propagate->GetTec2b(); + Accelerations->in.Tl2b = Propagate->GetTl2b(); + Accelerations->in.qAttitudeECI = Propagate->GetQuaternionECI(); + Accelerations->in.Moment = Aircraft->GetMoments(); + Accelerations->in.GroundMoment = GroundReactions->GetMoments(); + Accelerations->in.Force = Aircraft->GetForces(); + Accelerations->in.GroundForce = GroundReactions->GetForces(); + Accelerations->in.GAccel = Inertial->GetGAccel(Propagate->GetRadius()); + Accelerations->in.J2Grav = Inertial->GetGravityJ2(Propagate->GetLocation()); + Accelerations->in.vPQRi = Propagate->GetPQRi(); + Accelerations->in.vPQR = Propagate->GetPQR(); + Accelerations->in.vUVW = Propagate->GetUVW(); + Accelerations->in.vInertialPosition = Propagate->GetInertialPosition(); + Accelerations->in.DeltaT = dT; + Accelerations->in.Mass = MassBalance->GetMass(); + Accelerations->in.MultipliersList = GroundReactions->GetMultipliersList(); + Accelerations->in.TerrainVelocity = Propagate->GetTerrainVelocity(); + Accelerations->in.TerrainAngularVel = Propagate->GetTerrainAngularVelocity(); + break; + default: + break; + } +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGFDMExec::LoadPlanetConstants(void) +{ + Propagate->in.vOmegaPlanet = Inertial->GetOmegaPlanet(); + Accelerations->in.vOmegaPlanet = Inertial->GetOmegaPlanet(); + Propagate->in.RefRadius = Inertial->GetRefRadius(); + Propagate->in.SemiMajor = Inertial->GetSemimajor(); + Propagate->in.SemiMinor = Inertial->GetSemiminor(); + Auxiliary->in.SLGravity = Inertial->SLgravity(); + Auxiliary->in.ReferenceRadius = Inertial->GetRefRadius(); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGFDMExec::LoadModelConstants(void) +{ + Winds->in.wingspan = Aircraft->GetWingSpan(); + FCS->in.NumGear = GroundReactions->GetNumGearUnits(); + Aerodynamics->in.Wingarea = Aircraft->GetWingArea(); + Aerodynamics->in.Wingchord = Aircraft->Getcbar(); + Aerodynamics->in.Wingincidence = Aircraft->GetWingIncidence(); + Aerodynamics->in.Wingspan = Aircraft->GetWingSpan(); + Auxiliary->in.Wingspan = Aircraft->GetWingSpan(); + Auxiliary->in.Wingchord = Aircraft->Getcbar(); + for (int i=0; iGetNumGearUnits(); i++) { + GroundReactions->in.vWhlBodyVec[i] = MassBalance->StructuralToBody(GroundReactions->GetGearUnit(i)->GetLocation()); + } + + LoadPlanetConstants(); +} + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // This call will cause the sim time to reset to 0.0 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 ); + LoadInputs(eAccelerations); + Accelerations->Run(false); + LoadInputs(ePropagate); + Propagate->InitializeDerivatives(); + LoadInputs(eAtmosphere); + Atmosphere->Run(false); + Winds->SetWindNED(FGIC->GetWindNEDFpsIC()); + Auxiliary->Run(false); +} + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // // A private, internal function call for Tie-ing to a property, so it needs an @@ -380,24 +595,19 @@ void FGFDMExec::ResetToInitialConditions(void) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void FGFDMExec::SetGroundCallback(FGGroundCallback* p) +bool FGFDMExec::SetOutputFileName(const string& fname) { - delete GroundCallback; - GroundCallback = p; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -double FGFDMExec::GetSimTime(void) -{ - return (State->Getsim_time()); + if (Outputs.size() > 0) Outputs[0]->SetOutputFileName(fname); + else return false; + return true; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -double FGFDMExec::GetDeltaT(void) +string FGFDMExec::GetOutputFileName(void) { - return (State->Getdt()); + if (Outputs.size() > 0) return Outputs[0]->GetOutputFileName(); + else return string(""); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -405,6 +615,7 @@ double FGFDMExec::GetDeltaT(void) vector FGFDMExec::EnumerateFDMs(void) { vector FDMList; + FGAircraft* Aircraft = (FGAircraft*)Models[eAircraft]; FDMList.push_back(Aircraft->GetAircraftName()); @@ -417,35 +628,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 @@ -458,8 +668,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(); @@ -491,7 +701,7 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) // Process the metrics element. This element is REQUIRED. element = document->FindElement("metrics"); if (element) { - result = Aircraft->Load(element); + result = ((FGAircraft*)Models[eAircraft])->Load(element); if (!result) { cerr << endl << "Aircraft metrics element has problems in file " << aircraftCfgFileName << endl; return result; @@ -504,7 +714,7 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) // Process the mass_balance element. This element is REQUIRED. element = document->FindElement("mass_balance"); if (element) { - result = MassBalance->Load(element); + result = ((FGMassBalance*)Models[eMassBalance])->Load(element); if (!result) { cerr << endl << "Aircraft mass_balance element has problems in file " << aircraftCfgFileName << endl; return result; @@ -517,11 +727,12 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) // Process the ground_reactions element. This element is REQUIRED. element = document->FindElement("ground_reactions"); if (element) { - result = GroundReactions->Load(element); + result = ((FGGroundReactions*)Models[eGroundReactions])->Load(element); if (!result) { cerr << endl << "Aircraft ground_reactions element has problems in file " << aircraftCfgFileName << endl; return result; } + ((FGFCS*)Models[eSystems])->AddGear(((FGGroundReactions*)Models[eGroundReactions])->GetNumGearUnits()); } else { cerr << endl << "No ground_reactions element was found in the aircraft config file." << endl; return false; @@ -530,7 +741,7 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) // Process the external_reactions element. This element is OPTIONAL. element = document->FindElement("external_reactions"); if (element) { - result = ExternalReactions->Load(element); + result = ((FGExternalReactions*)Models[eExternalReactions])->Load(element); if (!result) { cerr << endl << "Aircraft external_reactions element has problems in file " << aircraftCfgFileName << endl; return result; @@ -540,7 +751,7 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) // Process the buoyant_forces element. This element is OPTIONAL. element = document->FindElement("buoyant_forces"); if (element) { - result = BuoyantForces->Load(element); + result = ((FGBuoyantForces*)Models[eBuoyantForces])->Load(element); if (!result) { cerr << endl << "Aircraft buoyant_forces element has problems in file " << aircraftCfgFileName << endl; return result; @@ -550,17 +761,19 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) // Process the propulsion element. This element is OPTIONAL. element = document->FindElement("propulsion"); if (element) { - result = Propulsion->Load(element); + result = ((FGPropulsion*)Models[ePropulsion])->Load(element); if (!result) { cerr << endl << "Aircraft propulsion element has problems in file " << aircraftCfgFileName << endl; return result; } + for (unsigned int i=0; i<((FGPropulsion*)Models[ePropulsion])->GetNumEngines(); i++) + ((FGFCS*)Models[eSystems])->AddThrottle(); } // 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); + result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stSystem); if (!result) { cerr << endl << "Aircraft system element has problems in file " << aircraftCfgFileName << endl; return result; @@ -571,7 +784,7 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) // Process the autopilot element. This element is OPTIONAL. element = document->FindElement("autopilot"); if (element) { - result = FCS->Load(element, FGFCS::stAutoPilot); + result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stAutoPilot); if (!result) { cerr << endl << "Aircraft autopilot element has problems in file " << aircraftCfgFileName << endl; return result; @@ -581,7 +794,7 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) // Process the flight_control element. This element is OPTIONAL. element = document->FindElement("flight_control"); if (element) { - result = FCS->Load(element, FGFCS::stFCS); + result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stFCS); if (!result) { cerr << endl << "Aircraft flight_control element has problems in file " << aircraftCfgFileName << endl; return result; @@ -591,7 +804,7 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) // Process the aerodynamics element. This element is OPTIONAL, but almost always expected. element = document->FindElement("aerodynamics"); if (element) { - result = Aerodynamics->Load(element); + result = ((FGAerodynamics*)Models[eAerodynamics])->Load(element); if (!result) { cerr << endl << "Aircraft aerodynamics element has problems in file " << aircraftCfgFileName << endl; return result; @@ -603,7 +816,7 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) // Process the input element. This element is OPTIONAL. element = document->FindElement("input"); if (element) { - result = Input->Load(element); + result = ((FGInput*)Models[eInput])->Load(element); if (!result) { cerr << endl << "Aircraft input element has problems in file " << aircraftCfgFileName << endl; return result; @@ -612,13 +825,14 @@ 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; 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); + Schedule(Output); result = Output->Load(element); if (!result) { cerr << endl << "Aircraft output element has problems in file " << aircraftCfgFileName << endl; @@ -626,7 +840,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"); @@ -642,9 +857,17 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) } } + // Since all vehicle characteristics have been loaded, place the values in the Inputs + // structure for the FGModel-derived classes. + LoadModelConstants(); + modelLoaded = true; if (debug_lvl > 0) { + LoadInputs(eMassBalance); // Update all input mass properties for the report. + Models[eMassBalance]->Run(false); // Update all mass properties for the report. + ((FGMassBalance*)Models[eMassBalance])->GetMassPropertiesReport(); + cout << endl << fgblue << highint << "End of vehicle configuration loading." << endl << "-------------------------------------------------------------------------------" @@ -659,17 +882,27 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) << fgdef << endl; } - struct PropertyCatalogStructure masterPCS; - masterPCS.base_string = ""; - masterPCS.node = (FGPropertyManager*)Root; + for (unsigned int i=0; i< Models.size(); i++) LoadInputs(i); - BuildPropertyCatalog(&masterPCS); + if (result) { + struct PropertyCatalogStructure masterPCS; + masterPCS.base_string = ""; + masterPCS.node = (FGPropertyManager*)Root; + BuildPropertyCatalog(&masterPCS); + } return result; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +string FGFDMExec::GetPropulsionTankReport() +{ + return ((FGPropulsion*)Models[ePropulsion])->GetPropulsionTankReport(); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs) { struct PropertyCatalogStructure* pcsNew = new struct PropertyCatalogStructure; @@ -696,7 +929,7 @@ void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -string FGFDMExec::QueryPropertyCatalog(string in) +string FGFDMExec::QueryPropertyCatalog(const string& in) { string results=""; for (unsigned i=0; iGetAttributeValue("name"); - Aircraft->SetAircraftName(AircraftName); + ((FGAircraft*)Models[eAircraft])->SetAircraftName(AircraftName); if (debug_lvl & 1) cout << underon << "Reading Aircraft Configuration File" << underoff << ": " << highint << AircraftName << normint << endl; @@ -818,7 +1051,7 @@ bool FGFDMExec::ReadChild(Element* el) struct childData* child = new childData; - child->exec = new FGFDMExec(); + child->exec = new FGFDMExec(Root, FDMctr); child->exec->SetChild(true); string childAircraft = el->GetAttributeValue("name"); @@ -888,20 +1121,32 @@ void FGFDMExec::EnableOutput(void) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::SetOutputDirectives(string fname) +void FGFDMExec::ForceOutput(int idx) +{ + if (idx >= (int)0 && idx < (int)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); 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) { + Output->Run(holding); + 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); + } + else + delete Output; return result; } @@ -918,71 +1163,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); -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -/* -void FGFDMExec::DoTrimAnalysis(int mode) -{ - double saved_time; - if (Constructing) return; - - if (mode < 0 || mode > JSBSim::taNone) { - cerr << endl << "Illegal trimming mode!" << endl << endl; - return; - } - saved_time = State->Getsim_time(); - - FGTrimAnalysis trimAnalysis(this, (JSBSim::TrimAnalysisMode)mode); - - if ( !trimAnalysis.Load(IC->GetInitFile(), false) ) { - cerr << "A problem occurred with trim configuration file " << trimAnalysis.Load(IC->GetInitFile()) << endl; - exit(-1); - } - - bool result = trimAnalysis.DoTrim(); - - if ( !result ) cerr << endl << "Trim Failed" << endl << endl; - - trimAnalysis.Report(); - State->Setsim_time(saved_time); - - EnableOutput(); - cout << "\nOutput: " << GetOutputFileName() << endl; - -} -*/ -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -void FGFDMExec::UseAtmosphereMSIS(void) -{ - FGAtmosphere *oldAtmosphere = Atmosphere; - Atmosphere = new MSIS(this); - if (!Atmosphere->InitModel()) { - cerr << fgred << "MSIS Atmosphere model init failed" << fgdef << endl; - Error+=1; - } - delete oldAtmosphere; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -void FGFDMExec::UseAtmosphereMars(void) -{ -/* - FGAtmosphere *oldAtmosphere = Atmosphere; - Atmosphere = new FGMars(this); - if (!Atmosphere->InitModel()) { - cerr << fgred << "Mars Atmosphere model init failed" << fgdef << endl; - Error+=1; - } - delete oldAtmosphere; -*/ + sim_time = saved_time; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1010,10 +1195,10 @@ void FGFDMExec::Debug(int from) if (debug_lvl & 1 && IdFDM == 0) { // Standard console startup message output if (from == 0) { // Constructor - cout << "\n\n " << highint << underon << "JSBSim Flight Dynamics Model v" - << JSBSim_version << underoff << normint << endl; - cout << halfint << " [JSBSim-ML v" << needed_cfg_version << "]\n\n"; - cout << normint << "JSBSim startup beginning ...\n\n"; + cout << "\n\n " + << "JSBSim Flight Dynamics Model v" << JSBSim_version << endl; + cout << " [JSBSim-ML v" << needed_cfg_version << "]\n\n"; + cout << "JSBSim startup beginning ...\n\n"; } else if (from == 3) { cout << "\n\nJSBSim startup complete\n\n"; } @@ -1025,7 +1210,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