X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FFDM%2FJSBSim%2FFGFDMExec.cpp;h=b61529229c40c3947ff50ab9792c1792907a8bb8;hb=69baf3a9d6adb645325e7bfc0305b09604379d9f;hp=aef1ed1c364985f64870464ef60ab07711586fa6;hpb=27a730573637faa26c38c82d4b4b2a09f1079684;p=flightgear.git diff --git a/src/FDM/JSBSim/FGFDMExec.cpp b/src/FDM/JSBSim/FGFDMExec.cpp index aef1ed1c3..b61529229 100644 --- a/src/FDM/JSBSim/FGFDMExec.cpp +++ b/src/FDM/JSBSim/FGFDMExec.cpp @@ -1,3 +1,4 @@ + /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Module: FGFDMExec.cpp @@ -5,7 +6,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 @@ -41,121 +42,102 @@ COMMENTS, REFERENCES, and NOTES 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 #include +#include + +#include "FGFDMExec.h" +#include "models/atmosphere/FGStandardAtmosphere.h" +#include "models/atmosphere/FGWinds.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/FGAccelerations.h" +#include "models/FGPropagate.h" +#include "models/FGAuxiliary.h" +#include "models/FGInput.h" +#include "models/FGOutput.h" +#include "initialization/FGInitialCondition.h" +#include "initialization/FGSimplexTrim.h" +#include "initialization/FGLinearization.h" +#include "input_output/FGPropertyManager.h" +#include "input_output/FGScript.h" +#include "input_output/FGXMLFileRead.h" +#include "input_output/FGXMLElement.h" + +using namespace std; namespace JSBSim { -static const char *IdSrc = "$Id$"; +static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.150 2013/11/24 11:40:55 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() ) { -// cout << "Untieing " << node->getChild(i)->getName() << " property branch." << endl; - 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; - 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; - IsSlave = false; + IsChild = false; holding = false; Terminate = false; + StandAlone = false; - // Multiple FDM's are stopped for now. We need to ensure that - // the "user" instance always gets the zeroeth instance number, - // because there may be instruments or scripts tied to properties - // in the jsbsim[0] node. - // ToDo: it could be that when JSBSim is reset and a new FDM is wanted, that - // process might try setting FDMctr = 0. Then the line below would not need - // to be commented out. - IdFDM = FDMctr; - //FDMctr++; + IncrementThenHolding = false; // increment then hold is off by default + TimeStepsUntilHold = -1; + + 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; } - instance = Root->GetNode("/fdm/jsbsim",IdFDM,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. + + FGPropertyNode* instanceRoot = Root->GetNode("/fdm/jsbsim",IdFDM,true); + instance = new FGPropertyManager(instanceRoot); Debug(0); // this is to catch errors in binding member functions to the property tree. try { @@ -170,10 +152,62 @@ 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); + typedef double (FGFDMExec::*dPMF)(void) const; +// typedef unsigned int (FGFDMExec::*uiPMF)(void) const; +// 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/do_simplex_trim", this, (iPMF)0, &FGFDMExec::DoSimplexTrim); + instance->Tie("simulation/do_linearization", this, (iPMF)0, &FGFDMExec::DoLinearization); + instance->Tie("simulation/reset", this, (iPMF)0, &FGFDMExec::ResetToInitialConditions, false); + instance->Tie("simulation/randomseed", this, (iPMF)0, &FGFDMExec::SRand, false); instance->Tie("simulation/terminate", (int *)&Terminate); + instance->Tie("simulation/sim-time-sec", this, &FGFDMExec::GetSimTime); + instance->Tie("simulation/dt", this, &FGFDMExec::GetDeltaT); + instance->Tie("simulation/jsbsim-debug", this, &FGFDMExec::GetDebugLevel, &FGFDMExec::SetDebugLevel); + instance->Tie("simulation/frame", (int *)&Frame, false); + + // simplex trim properties + instanceRoot->SetDouble("trim/solver/rtol",0.0001); + instanceRoot->SetDouble("trim/solver/speed",2); + instanceRoot->SetDouble("trim/solver/abstol",0.001); + instanceRoot->SetDouble("trim/solver/iterMax",2000); + instanceRoot->SetInt("trim/solver/debugLevel",0); + instanceRoot->SetDouble("trim/solver/random",0); + instanceRoot->SetBool("trim/solver/showSimplex",false); + instanceRoot->SetBool("trim/solver/showConvergence",false); + instanceRoot->SetBool("trim/solver/pause",false); + instanceRoot->SetBool("trim/solver/variablePropPitch",false); + + instanceRoot->SetDouble("trim/solver/throttleGuess",0.50); + instanceRoot->SetDouble("trim/solver/throttleMin",0.0); + instanceRoot->SetDouble("trim/solver/throttleMax",1.0); + instanceRoot->SetDouble("trim/solver/throttleStep",0.1); + + instanceRoot->SetDouble("trim/solver/aileronGuess",0); + instanceRoot->SetDouble("trim/solver/aileronMin",-1.00); + instanceRoot->SetDouble("trim/solver/aileronMax",1.00); + instanceRoot->SetDouble("trim/solver/aileronStep",0.1); + + instanceRoot->SetDouble("trim/solver/rudderGuess",0); + instanceRoot->SetDouble("trim/solver/rudderMin",-1.00); + instanceRoot->SetDouble("trim/solver/rudderMax",1.00); + instanceRoot->SetDouble("trim/solver/rudderStep",0.1); + + instanceRoot->SetDouble("trim/solver/elevatorGuess",-0.1); + instanceRoot->SetDouble("trim/solver/elevatorMin",-1.0); + instanceRoot->SetDouble("trim/solver/elevatorMax",1.0); + instanceRoot->SetDouble("trim/solver/elevatorStep",0.1); + + instanceRoot->SetDouble("trim/solver/alphaGuess",0.05); + instanceRoot->SetDouble("trim/solver/alphaMin",-0.1); + instanceRoot->SetDouble("trim/solver/alphaMax",.18); + instanceRoot->SetDouble("trim/solver/alphaStep",0.05); + + instanceRoot->SetDouble("trim/solver/betaGuess",0); + instanceRoot->SetDouble("trim/solver/betaMin",-0.1); + instanceRoot->SetDouble("trim/solver/betaMax",0.1); + instanceRoot->SetDouble("trim/solver/betaStep",0.0001); + Constructing = false; } @@ -182,17 +216,32 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root) FGFDMExec::~FGFDMExec() { try { - checkTied( instance ); + Unbind(); DeAllocate(); - if (Root == 0) delete master; + + delete instance; + + 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; } - for (unsigned int i=1; iexec; - SlaveFDMList.clear(); + for (unsigned int i=1; iexec; + ChildFDMList.clear(); + + PropertyCatalog.clear(); - //ToDo remove property catalog. + if (FDMctr > 0) (*FDMctr)--; Debug(1); } @@ -203,63 +252,60 @@ 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 - - // 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(); + 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); + 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); + Models[eOutput] = new FGOutput(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]; + Output = (FGOutput*)Models[eOutput]; + + // Initialize planet (environment) constants + LoadPlanetConstants(); + GetGroundCallback()->SetSeaLevelRadius(Inertial->GetRefRadius()); + + // Initialize models + for (unsigned int i = 0; i < Models.size(); i++) { + // The Output model must not be initialized prior to IC loading + if (i == eOutput) continue; + + LoadInputs(i); + Models[i]->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. - - Schedule(Input, 1); - Schedule(Atmosphere, 1); - 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); - modelLoaded = false; return result; @@ -269,78 +315,26 @@ 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 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); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -348,95 +342,306 @@ 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); - for (unsigned int i=1; iexec->State->Initialize(); // Transfer state to the slave FDM -// SlaveFDMList[i]->exec->Run(); + for (unsigned int i=1; iAssignState( (FGPropagate*)Models[ePropagate] ); // Transfer state to the child FDM + ChildFDMList[i]->Run(); } - // returns true if success - // false if complete - if (Script != 0 && !State->IntegrationSuspended()) success = Script->RunScript(); + IncrTime(); + + // 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; + 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); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -// This call will cause the sim time to reset to 0.0 -bool FGFDMExec::RunIC(void) +void FGFDMExec::LoadInputs(unsigned int idx) { - State->SuspendIntegration(); - State->Initialize(IC); - Run(); - State->ResumeIntegration(); + 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.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(); + GroundReactions->in.vXYZcg = MassBalance->GetXYZcg(); + 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(); + 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.Tec2i = Propagate->GetTec2i(); + 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; + } +} - return true; +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGFDMExec::LoadPlanetConstants(void) +{ + Propagate->in.vOmegaPlanet = Inertial->GetOmegaPlanet(); + Accelerations->in.vOmegaPlanet = Inertial->GetOmegaPlanet(); + Propagate->in.SemiMajor = Inertial->GetSemimajor(); + Propagate->in.SemiMinor = Inertial->GetSemiminor(); + Auxiliary->in.SLGravity = Inertial->SLgravity(); + Auxiliary->in.ReferenceRadius = Inertial->GetRefRadius(); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -// -// A private, internal function call for Tie-ing to a property, so it needs an -// argument. Nothing is done with the argument, yet. -void FGFDMExec::ResetToInitialConditions(int mode) +void FGFDMExec::LoadModelConstants(void) { - ResetToInitialConditions(); + 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(); + GroundReactions->in.vXYZcg = MassBalance->GetXYZcg(); + + LoadPlanetConstants(); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// This call will cause the sim time to reset to 0.0 -void FGFDMExec::ResetToInitialConditions(void) +bool FGFDMExec::RunIC(void) { - FGModel* model_iterator; + FGPropulsion* propulsion = (FGPropulsion*)Models[ePropulsion]; - model_iterator = FirstModel; - if (model_iterator == 0L) return; + Models[eOutput]->InitModel(); - while (model_iterator != 0L) { - model_iterator->InitModel(); - model_iterator = model_iterator->NextModel; - } + SuspendIntegration(); // saves the integration rate, dt, then sets it to 0.0. + Initialize(IC); + Run(); + ResumeIntegration(); // Restores the integration rate to what it was. - RunIC(); - if (Script) Script->ResetEvents(); + for (unsigned int i=0; iGetNumEnginesRunning(); i++) + propulsion->InitRunning(IC->GetEngineRunning(i)); + + return true; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void FGFDMExec::SetGroundCallback(FGGroundCallback* p) +void FGFDMExec::Initialize(FGInitialCondition *FGIC) { - delete GroundCallback; - GroundCallback = p; + 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 +// argument. -double FGFDMExec::GetSimTime(void) +void FGFDMExec::ResetToInitialConditions(int mode) { - return (State->Getsim_time()); + if (mode == 1) Output->SetStartNewOutput(); + + ResetToInitialConditions(); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -double FGFDMExec::GetDeltaT(void) +void FGFDMExec::ResetToInitialConditions(void) { - return (State->Getdt()); + if (Constructing) return; + + for (unsigned int i = 0; i < Models.size(); i++) { + // The Output model will be initialized during the RunIC() execution + if (i == eOutput) continue; + + LoadInputs(i); + Models[i]->InitModel(); + } + + RunIC(); + + if (Script) Script->ResetEvents(); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -444,11 +649,12 @@ double FGFDMExec::GetDeltaT(void) vector FGFDMExec::EnumerateFDMs(void) { vector FDMList; + FGAircraft* Aircraft = (FGAircraft*)Models[eAircraft]; FDMList.push_back(Aircraft->GetAircraftName()); - for (unsigned int i=1; iexec->GetAircraft()->GetAircraftName()); + for (unsigned int i=1; iexec->GetAircraft()->GetAircraftName()); } return FDMList; @@ -456,35 +662,34 @@ vector FGFDMExec::EnumerateFDMs(void) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::LoadScript(string script) +bool FGFDMExec::LoadScript(const string& script, double deltaT, const string initfile) { bool result; Script = new FGScript(this); - result = Script->LoadScript(script); + result = Script->LoadScript(RootDir + script, deltaT, initfile); 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 @@ -497,98 +702,262 @@ 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(); Allocate(); } - document = LoadXMLDocument(aircraftCfgFileName); // "document" is a class member + int saved_debug_lvl = debug_lvl; + FGXMLFileRead XMLFileRead; + Element *document = XMLFileRead.LoadXMLDocument(aircraftCfgFileName); // "document" is a class member + if (document) { + if (IsChild) debug_lvl = 0; + ReadPrologue(document); - element = document->GetElement(); - - result = true; - while (element && result) { - string element_name = element->GetName(); - if (element_name == "fileheader" ) result = ReadFileHeader(element); - else if (element_name == "slave") result = ReadSlave(element); - else if (element_name == "metrics") result = Aircraft->Load(element); - else if (element_name == "mass_balance") result = MassBalance->Load(element); - else if (element_name == "ground_reactions") result = GroundReactions->Load(element); - else if (element_name == "external_reactions") result = ExternalReactions->Load(element); - else if (element_name == "buoyant_forces") result = BuoyantForces->Load(element); - else if (element_name == "propulsion") result = Propulsion->Load(element); - else if (element_name == "system") result = FCS->Load(element, - FGFCS::stSystem); - else if (element_name == "autopilot") result = FCS->Load(element, - FGFCS::stAutoPilot); - else if (element_name == "flight_control") result = FCS->Load(element, - FGFCS::stFCS); - else if (element_name == "aerodynamics") result = Aerodynamics->Load(element); - else if (element_name == "input") result = Input->Load(element); - else if (element_name == "output") { - FGOutput* Output = new FGOutput(this); - Output->InitModel(); - Schedule(Output, 1); - result = Output->Load(element); - Outputs.push_back(Output); + + if (IsChild) debug_lvl = saved_debug_lvl; + + // Process the fileheader element in the aircraft config file. This element is OPTIONAL. + element = document->FindElement("fileheader"); + if (element) { + result = ReadFileHeader(element); + if (!result) { + cerr << endl << "Aircraft fileheader element has problems in file " << aircraftCfgFileName << endl; + return result; } - else { - cerr << "Found unexpected subsystem: " << element_name << ", exiting." << endl; - result = false; - break; + } + + if (IsChild) debug_lvl = 0; + + // Process the metrics element. This element is REQUIRED. + element = document->FindElement("metrics"); + if (element) { + result = ((FGAircraft*)Models[eAircraft])->Load(element); + if (!result) { + cerr << endl << "Aircraft metrics element has problems in file " << aircraftCfgFileName << endl; + return result; } - element = document->GetNextElement(); + } else { + cerr << endl << "No metrics element was found in the aircraft config file." << endl; + return false; } - } else { - cerr << fgred - << " JSBSim failed to load aircraft model." - << fgdef << endl; - return false; - } - if (result) { + // Process the mass_balance element. This element is REQUIRED. + element = document->FindElement("mass_balance"); + if (element) { + result = ((FGMassBalance*)Models[eMassBalance])->Load(element); + if (!result) { + cerr << endl << "Aircraft mass_balance element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } else { + cerr << endl << "No mass_balance element was found in the aircraft config file." << endl; + return false; + } + + // Process the ground_reactions element. This element is REQUIRED. + element = document->FindElement("ground_reactions"); + if (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; + } + + // Process the external_reactions element. This element is OPTIONAL. + element = document->FindElement("external_reactions"); + if (element) { + result = ((FGExternalReactions*)Models[eExternalReactions])->Load(element); + if (!result) { + cerr << endl << "Aircraft external_reactions element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + // Process the buoyant_forces element. This element is OPTIONAL. + element = document->FindElement("buoyant_forces"); + if (element) { + result = ((FGBuoyantForces*)Models[eBuoyantForces])->Load(element); + if (!result) { + cerr << endl << "Aircraft buoyant_forces element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + // Process the propulsion element. This element is OPTIONAL. + element = document->FindElement("propulsion"); + if (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 = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stSystem); + if (!result) { + cerr << endl << "Aircraft system element has problems in file " << aircraftCfgFileName << endl; + return result; + } + element = document->FindNextElement("system"); + } + + // Process the autopilot element. This element is OPTIONAL. + element = document->FindElement("autopilot"); + if (element) { + result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stAutoPilot); + if (!result) { + cerr << endl << "Aircraft autopilot element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + // Process the flight_control element. This element is OPTIONAL. + element = document->FindElement("flight_control"); + if (element) { + result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stFCS); + if (!result) { + cerr << endl << "Aircraft flight_control element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + // Process the aerodynamics element. This element is OPTIONAL, but almost always expected. + element = document->FindElement("aerodynamics"); + if (element) { + result = ((FGAerodynamics*)Models[eAerodynamics])->Load(element); + if (!result) { + cerr << endl << "Aircraft aerodynamics element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } else { + cerr << endl << "No expected aerodynamics element was found in the aircraft config file." << endl; + } + + // Process the input element. This element is OPTIONAL. + element = document->FindElement("input"); + if (element) { + result = ((FGInput*)Models[eInput])->Load(element); + if (!result) { + cerr << endl << "Aircraft input element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + // Process the output element[s]. This element is OPTIONAL, and there may be more than one. + element = document->FindElement("output"); + while (element) { + string output_file_name = aircraftCfgFileName; + + if (!element->GetAttributeValue("file").empty()) { + output_file_name = RootDir + element->GetAttributeValue("file"); + result = ((FGOutput*)Models[eOutput])->SetDirectivesFile(output_file_name); + } + else + result = ((FGOutput*)Models[eOutput])->Load(element); + + if (!result) { + cerr << endl << "Aircraft output element has problems in file " << output_file_name << endl; + return result; + } + element = document->FindNextElement("output"); + } + + // Lastly, process the child element. This element is OPTIONAL - and NOT YET SUPPORTED. + element = document->FindElement("child"); + if (element) { + result = ReadChild(element); + if (!result) { + cerr << endl << "Aircraft child element has problems in file " << aircraftCfgFileName << endl; + return result; + } + } + + // Since all vehicle characteristics have been loaded, place the values in the Inputs + // structure for the FGModel-derived classes. + LoadModelConstants(); + modelLoaded = true; - Debug(3); + + 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. + LoadInputs(ePropulsion); // Update propulsion properties for the report. + Models[ePropulsion]->Run(false); // Update propulsion properties for the report. + LoadInputs(eMassBalance); // Update all (one more time) input mass properties for the report. + Models[eMassBalance]->Run(false); // Update all (one more time) mass properties for the report. + ((FGMassBalance*)Models[eMassBalance])->GetMassPropertiesReport(); + + cout << endl << fgblue << highint + << "End of vehicle configuration loading." << endl + << "-------------------------------------------------------------------------------" + << reset << endl; + } + + if (IsChild) debug_lvl = saved_debug_lvl; + } else { cerr << fgred - << " JSBSim failed to load properly." + << " JSBSim failed to open the configuration file: " << aircraftCfgFileName << fgdef << endl; - return false; } - 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 = Root->GetNode(); + BuildPropertyCatalog(&masterPCS); + } return result; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +string FGFDMExec::GetPropulsionTankReport() +{ + return ((FGPropulsion*)Models[ePropulsion])->GetPropulsionTankReport(); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + 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++) { + string access=""; 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")) { + if (pcsNew->base_string.substr(0,12) == string("/fdm/jsbsim/")) { pcsNew->base_string = pcsNew->base_string.erase(0,12); } - PropertyCatalog.push_back(pcsNew->base_string); + if (pcs->node->getChild(i)->getAttribute(SGPropertyNode::READ)) access="R"; + if (pcs->node->getChild(i)->getAttribute(SGPropertyNode::WRITE)) access+="W"; + PropertyCatalog.push_back(pcsNew->base_string+" ("+access+")"); } else { - pcsNew->node = (FGPropertyManager*)pcs->node->getChild(i); + pcsNew->node = (FGPropertyNode*)pcs->node->getChild(i); BuildPropertyCatalog(pcsNew); } } @@ -597,7 +966,7 @@ void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -string FGFDMExec::QueryPropertyCatalog(string in) +string FGFDMExec::QueryPropertyCatalog(const string& in) { string results=""; for (unsigned i=0; iFindElement("description")) + cout << " Description: " << el->FindElement("description")->GetDataLine() << endl; if (el->FindElement("author")) cout << " Model Author: " << el->FindElement("author")->GetDataLine() << endl; if (el->FindElement("filecreationdate")) cout << " Creation Date: " << el->FindElement("filecreationdate")->GetDataLine() << endl; if (el->FindElement("version")) cout << " Version: " << el->FindElement("version")->GetDataLine() << endl; - if (el->FindElement("description")) - cout << " Description: " << el->FindElement("description")->GetDataLine() << endl; return result; } @@ -648,7 +1021,7 @@ bool FGFDMExec::ReadPrologue(Element* el) // el for ReadPrologue is the document if (!el) return false; string AircraftName = el->GetAttributeValue("name"); - Aircraft->SetAircraftName(AircraftName); + ((FGAircraft*)Models[eAircraft])->SetAircraftName(AircraftName); if (debug_lvl & 1) cout << underon << "Reading Aircraft Configuration File" << underoff << ": " << highint << AircraftName << normint << endl; @@ -701,54 +1074,51 @@ bool FGFDMExec::ReadPrologue(Element* el) // el for ReadPrologue is the document //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool FGFDMExec::ReadSlave(Element* el) +bool FGFDMExec::ReadChild(Element* el) { - // Add a new slaveData object to the slave FDM list - // Populate that slaveData element with a new FDMExec object - // Set the IsSlave flag for that FDMExec object + // Add a new childData object to the child FDM list + // Populate that childData element with a new FDMExec object + // Set the IsChild flag for that FDMExec object // Get the aircraft name - // set debug level to print out no additional data for slave objects + // set debug level to print out no additional data for child objects // Load the model given the aircraft name // reset debug level to prior setting - int saved_debug_lvl = debug_lvl; string token; - SlaveFDMList.push_back(new slaveData); - SlaveFDMList.back()->exec = new FGFDMExec(); - SlaveFDMList.back()->exec->SetSlave(true); -/* - string AircraftName = AC_cfg->GetValue("file"); - - debug_lvl = 0; // turn off debug output for slave vehicle - - SlaveFDMList.back()->exec->SetAircraftPath( AircraftPath ); - SlaveFDMList.back()->exec->SetEnginePath( EnginePath ); - SlaveFDMList.back()->exec->SetSystemsPath( SystemsPath ); - SlaveFDMList.back()->exec->LoadModel(AircraftName); - debug_lvl = saved_debug_lvl; // turn debug output back on for master vehicle - - AC_cfg->GetNextConfigLine(); - while ((token = AC_cfg->GetValue()) != string("/SLAVE")) { - *AC_cfg >> token; - if (token == "xloc") { *AC_cfg >> SlaveFDMList.back()->x; } - else if (token == "yloc") { *AC_cfg >> SlaveFDMList.back()->y; } - else if (token == "zloc") { *AC_cfg >> SlaveFDMList.back()->z; } - else if (token == "pitch") { *AC_cfg >> SlaveFDMList.back()->pitch;} - else if (token == "yaw") { *AC_cfg >> SlaveFDMList.back()->yaw; } - else if (token == "roll") { *AC_cfg >> SlaveFDMList.back()->roll; } - else cerr << "Unknown identifier: " << token << " in slave vehicle definition" << endl; - } -*/ - if (debug_lvl > 0) { - cout << " X = " << SlaveFDMList.back()->x << endl; - cout << " Y = " << SlaveFDMList.back()->y << endl; - cout << " Z = " << SlaveFDMList.back()->z << endl; - cout << " Pitch = " << SlaveFDMList.back()->pitch << endl; - cout << " Yaw = " << SlaveFDMList.back()->yaw << endl; - cout << " Roll = " << SlaveFDMList.back()->roll << endl; + struct childData* child = new childData; + + child->exec = new FGFDMExec(Root, FDMctr); + child->exec->SetChild(true); + + string childAircraft = el->GetAttributeValue("name"); + string sMated = el->GetAttributeValue("mated"); + if (sMated == "false") child->mated = false; // child objects are mated by default. + string sInternal = el->GetAttributeValue("internal"); + if (sInternal == "true") child->internal = true; // child objects are external by default. + + child->exec->SetAircraftPath( AircraftPath ); + child->exec->SetEnginePath( EnginePath ); + child->exec->SetSystemsPath( SystemsPath ); + child->exec->LoadModel(childAircraft); + + Element* location = el->FindElement("location"); + if (location) { + child->Loc = location->FindElementTripletConvertTo("IN"); + } else { + cerr << endl << highint << fgred << " No location was found for this child object!" << reset << endl; + exit(-1); + } + + Element* orientation = el->FindElement("orient"); + if (orientation) { + child->Orient = orientation->FindElementTripletConvertTo("RAD"); + } else if (debug_lvl > 0) { + cerr << endl << highint << " No orientation was found for this child object! Assuming 0,0,0." << reset << endl; } + ChildFDMList.push_back(child); + return true; } @@ -770,36 +1140,26 @@ FGTrim* FGFDMExec::GetTrim(void) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void FGFDMExec::DisableOutput(void) +void FGFDMExec::CheckIncrementalHold(void) { - for (unsigned i=0; iDisable(); - } -} + // Only check if increment then hold is on + if( IncrementThenHolding ) { -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + if (TimeStepsUntilHold == 0) { -void FGFDMExec::EnableOutput(void) -{ - for (unsigned i=0; iEnable(); - } -} + // Should hold simulation if TimeStepsUntilHold has reached zero + holding = true; -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Still need to decrement TimeStepsUntilHold as value of -1 + // indicates that incremental then hold is turned off + IncrementThenHolding = false; + TimeStepsUntilHold--; -bool FGFDMExec::SetOutputDirectives(string fname) -{ - bool result; - - FGOutput* Output = new FGOutput(this); - Output->SetDirectivesFile(fname); - Output->InitModel(); - Schedule(Output, 1); - result = Output->Load(0); - Outputs.push_back(Output); - - return result; + } else if ( TimeStepsUntilHold > 0 ) { + // Keep decrementing until 0 is reached + TimeStepsUntilHold--; + } + } } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -814,71 +1174,47 @@ 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; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -/* -void FGFDMExec::DoTrimAnalysis(int mode) + +void FGFDMExec::DoSimplexTrim(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); + if (mode < 0 || mode > JSBSim::tNone) { + cerr << endl << "Illegal trimming mode!" << endl << endl; + return; } - - bool result = trimAnalysis.DoTrim(); - - if ( !result ) cerr << endl << "Trim Failed" << endl << endl; - - trimAnalysis.Report(); - State->Setsim_time(saved_time); - - EnableOutput(); - cout << "\nOutput: " << GetOutputFileName() << endl; - + saved_time = sim_time; + FGSimplexTrim trim(this, (JSBSim::TrimMode)mode); + sim_time = saved_time; + Setsim_time(saved_time); + std::cout << "dT: " << dT << std::endl; } -*/ + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void FGFDMExec::UseAtmosphereMSIS(void) +void FGFDMExec::DoLinearization(int mode) { - FGAtmosphere *oldAtmosphere = Atmosphere; - Atmosphere = new MSIS(this); - if (!Atmosphere->InitModel()) { - cerr << fgred << "MSIS Atmosphere model init failed" << fgdef << endl; - Error+=1; - } - delete oldAtmosphere; + double saved_time; + if (Constructing) return; + saved_time = sim_time; + FGLinearization lin(this,mode); + sim_time = saved_time; + Setsim_time(saved_time); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void FGFDMExec::UseAtmosphereMars(void) +void FGFDMExec::SRand(int sr) { -/* - FGAtmosphere *oldAtmosphere = Atmosphere; - Atmosphere = new FGMars(this); - if (!Atmosphere->InitModel()) { - cerr << fgred << "Mars Atmosphere model init failed" << fgdef << endl; - Error+=1; - } - delete oldAtmosphere; -*/ + srand(sr); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -906,10 +1242,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"; } @@ -921,7 +1257,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