Exemplo n.º 1
0
FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number, struct Inputs& input)
  : FGEngine(exec, el, engine_number, input),
  R_air(287.3),                  // Gas constant for air J/Kg/K
  rho_fuel(800),                 // estimate
  calorific_value_fuel(47.3e6),  // J/Kg
  Cp_air(1005),                  // Specific heat (constant pressure) J/Kg/K
  Cp_fuel(1700),
  standard_pressure(101320.73)
{
  Element *table_element;
  string token;
  string name="";

  // Defaults and initializations

  Type = etPiston;

  // These items are read from the configuration file
  // Defaults are from a Lycoming O-360, more or less

  Cycles = 4;
  IdleRPM = 600;
  MaxRPM = 2800;
  Displacement = 360;
  SparkFailDrop = 1.0;
  MaxHP = 200;
  MinManifoldPressure_inHg = 6.5;
  MaxManifoldPressure_inHg = 28.5;
  ManifoldPressureLag=1.0;
  ISFC = -1;
  volumetric_efficiency = 0.85;
  Bore = 5.125;
  Stroke = 4.375;
  Cylinders = 4;
  CylinderHeadMass = 2; //kg
  CompressionRatio = 8.5;
  Z_airbox = -999;
  Ram_Air_Factor = 1;
  PeakMeanPistonSpeed_fps = 100;
  FMEPDynamic= 18400;
  FMEPStatic = 46500;
  Cooling_Factor = 0.5144444;
  StaticFriction_HP = 1.5;
  StarterGain = 1.;
  StarterTorque = -1.;
  StarterRPM = -1.;

  // These are internal program variables

  Lookup_Combustion_Efficiency = 0;
  Mixture_Efficiency_Correlation = 0;
  crank_counter = 0;
  Magnetos = 0;
  minMAP = 21950;
  maxMAP = 96250;

  ResetToIC();

  // Supercharging
  BoostSpeeds = 0;  // Default to no supercharging
  BoostSpeed = 0;
  Boosted = false;
  BoostOverride = 0;
  BoostManual = 0;
  bBoostOverride = false;
  bTakeoffBoost = false;
  TakeoffBoost = 0.0;   // Default to no extra takeoff-boost
  int i;
  for (i=0; i<FG_MAX_BOOST_SPEEDS; i++) {
    RatedBoost[i] = 0.0;
    RatedPower[i] = 0.0;
    RatedAltitude[i] = 0.0;
    BoostMul[i] = 1.0;
    RatedMAP[i] = 100000;
    RatedRPM[i] = 2500;
    TakeoffMAP[i] = 100000;
  }
  for (i=0; i<FG_MAX_BOOST_SPEEDS-1; i++) {
    BoostSwitchAltitude[i] = 0.0;
    BoostSwitchPressure[i] = 0.0;
  }

  // Read inputs from engine data file where present.

  if (el->FindElement("minmp")) 
    MinManifoldPressure_inHg = el->FindElementValueAsNumberConvertTo("minmp","INHG");
  if (el->FindElement("maxmp"))
    MaxManifoldPressure_inHg = el->FindElementValueAsNumberConvertTo("maxmp","INHG");
  if (el->FindElement("man-press-lag"))
    ManifoldPressureLag = el->FindElementValueAsNumber("man-press-lag");
  if (el->FindElement("displacement"))
    Displacement = el->FindElementValueAsNumberConvertTo("displacement","IN3");
  if (el->FindElement("maxhp"))
    MaxHP = el->FindElementValueAsNumberConvertTo("maxhp","HP");
  if (el->FindElement("static-friction"))
    StaticFriction_HP = el->FindElementValueAsNumberConvertTo("static-friction","HP");
  if (el->FindElement("sparkfaildrop"))
    SparkFailDrop = Constrain(0, 1 - el->FindElementValueAsNumber("sparkfaildrop"), 1);
  if (el->FindElement("cycles"))
    Cycles = el->FindElementValueAsNumber("cycles");
  if (el->FindElement("idlerpm"))
    IdleRPM = el->FindElementValueAsNumber("idlerpm");
  if (el->FindElement("maxrpm"))
    MaxRPM = el->FindElementValueAsNumber("maxrpm");
  if (el->FindElement("maxthrottle"))
    MaxThrottle = el->FindElementValueAsNumber("maxthrottle");
  if (el->FindElement("minthrottle"))
    MinThrottle = el->FindElementValueAsNumber("minthrottle");
  if (el->FindElement("bsfc"))
    ISFC = el->FindElementValueAsNumberConvertTo("bsfc", "LBS/HP*HR");
  if (el->FindElement("volumetric-efficiency"))
    volumetric_efficiency = el->FindElementValueAsNumber("volumetric-efficiency");
  if (el->FindElement("compression-ratio"))
    CompressionRatio = el->FindElementValueAsNumber("compression-ratio");
  if (el->FindElement("bore"))
    Bore = el->FindElementValueAsNumberConvertTo("bore","IN");
  if (el->FindElement("stroke"))
    Stroke = el->FindElementValueAsNumberConvertTo("stroke","IN");
  if (el->FindElement("cylinders"))
    Cylinders = el->FindElementValueAsNumber("cylinders");
  if (el->FindElement("cylinder-head-mass"))
    CylinderHeadMass = el->FindElementValueAsNumberConvertTo("cylinder-head-mass","KG");
  if (el->FindElement("air-intake-impedance-factor"))
    Z_airbox = el->FindElementValueAsNumber("air-intake-impedance-factor");
  if (el->FindElement("ram-air-factor"))
    Ram_Air_Factor  = el->FindElementValueAsNumber("ram-air-factor");
  if (el->FindElement("cooling-factor"))
    Cooling_Factor  = el->FindElementValueAsNumber("cooling-factor");
  if (el->FindElement("starter-rpm"))
    StarterRPM  = el->FindElementValueAsNumber("starter-rpm");
  if (el->FindElement("starter-torque"))
    StarterTorque  = el->FindElementValueAsNumber("starter-torque");
  if (el->FindElement("dynamic-fmep"))
    FMEPDynamic= el->FindElementValueAsNumberConvertTo("dynamic-fmep","PA");
  if (el->FindElement("static-fmep"))
    FMEPStatic = el->FindElementValueAsNumberConvertTo("static-fmep","PA");
  if (el->FindElement("peak-piston-speed"))
    PeakMeanPistonSpeed_fps  = el->FindElementValueAsNumber("peak-piston-speed");
  if (el->FindElement("numboostspeeds")) { // Turbo- and super-charging parameters
    BoostSpeeds = (int)el->FindElementValueAsNumber("numboostspeeds");
    if (el->FindElement("boostoverride"))
      BoostOverride = (int)el->FindElementValueAsNumber("boostoverride");
    if (el->FindElement("boostmanual"))
      BoostManual = (int)el->FindElementValueAsNumber("boostmanual");
    if (el->FindElement("takeoffboost"))
      TakeoffBoost = el->FindElementValueAsNumberConvertTo("takeoffboost", "PSI");
    if (el->FindElement("ratedboost1"))
      RatedBoost[0] = el->FindElementValueAsNumberConvertTo("ratedboost1", "PSI");
    if (el->FindElement("ratedboost2"))
      RatedBoost[1] = el->FindElementValueAsNumberConvertTo("ratedboost2", "PSI");
    if (el->FindElement("ratedboost3"))
      RatedBoost[2] = el->FindElementValueAsNumberConvertTo("ratedboost3", "PSI");
    if (el->FindElement("ratedpower1"))
      RatedPower[0] = el->FindElementValueAsNumberConvertTo("ratedpower1", "HP");
    if (el->FindElement("ratedpower2"))
      RatedPower[1] = el->FindElementValueAsNumberConvertTo("ratedpower2", "HP");
    if (el->FindElement("ratedpower3"))
      RatedPower[2] = el->FindElementValueAsNumberConvertTo("ratedpower3", "HP");
    if (el->FindElement("ratedrpm1"))
      RatedRPM[0] = el->FindElementValueAsNumber("ratedrpm1");
    if (el->FindElement("ratedrpm2"))
      RatedRPM[1] = el->FindElementValueAsNumber("ratedrpm2");
    if (el->FindElement("ratedrpm3"))
      RatedRPM[2] = el->FindElementValueAsNumber("ratedrpm3");
    if (el->FindElement("ratedaltitude1"))
      RatedAltitude[0] = el->FindElementValueAsNumberConvertTo("ratedaltitude1", "FT");
    if (el->FindElement("ratedaltitude2"))
      RatedAltitude[1] = el->FindElementValueAsNumberConvertTo("ratedaltitude2", "FT");
    if (el->FindElement("ratedaltitude3"))
      RatedAltitude[2] = el->FindElementValueAsNumberConvertTo("ratedaltitude3", "FT");
  }

  while((table_element = el->FindNextElement("table")) != 0) {
    name = table_element->GetAttributeValue("name");
    try {
      if (name == "COMBUSTION") {
        Lookup_Combustion_Efficiency = new FGTable(PropertyManager, table_element);
      } else if (name == "MIXTURE") {
        Mixture_Efficiency_Correlation = new FGTable(PropertyManager, table_element);
      } else {
        cerr << "Unknown table type: " << name << " in piston engine definition." << endl;
      }
    } catch (std::string str) {
      throw("Error loading piston engine table:" + name + ". " + str);
    }
  }


  volumetric_efficiency_reduced = volumetric_efficiency;

  if(StarterRPM < 0.) StarterRPM = 2*IdleRPM;
  if(StarterTorque < 0)
    StarterTorque = (MaxHP)*0.4; //just a wag.

  displacement_SI = Displacement * in3tom3;
  RatedMeanPistonSpeed_fps =  ( MaxRPM * Stroke) / (360); // AKA 2 * (RPM/60) * ( Stroke / 12) or 2NS

  // Create IFSC to match the engine if not provided
  if (ISFC < 0) {
      double pmep = 29.92 - MaxManifoldPressure_inHg;
      pmep *= inhgtopa  * volumetric_efficiency;
      double fmep = (FMEPDynamic * RatedMeanPistonSpeed_fps * fttom + FMEPStatic);
      double hp_loss = ((pmep + fmep) * displacement_SI * MaxRPM)/(Cycles*22371);
      ISFC = ( 1.1*Displacement * MaxRPM * volumetric_efficiency *(MaxManifoldPressure_inHg / 29.92) ) / (9411 * (MaxHP+hp_loss-StaticFriction_HP));
// cout <<"FMEP: "<< fmep <<" PMEP: "<< pmep << " hp_loss: " <<hp_loss <<endl;
  }
  if ( MaxManifoldPressure_inHg > 29.9 ) {   // Don't allow boosting with a bogus number
      MaxManifoldPressure_inHg = 29.9;
  }
  minMAP = MinManifoldPressure_inHg * inhgtopa;  // inHg to Pa
  maxMAP = MaxManifoldPressure_inHg * inhgtopa;

// For throttle
/*
 * Pm = ( Ze / ( Ze + Zi + Zt ) ) * Pa
 * Where:
 * Pm = Manifold Pressure
 * Pa = Ambient Pressre
 * Ze = engine impedance, Ze is effectively 1 / Mean Piston Speed
 * Zi = airbox impedance
 * Zt = throttle impedance
 *
 * For the calculation below throttle is fully open or Zt = 0
 *
 *
 *
 */
  if(Z_airbox < 0.0){
    double Ze=PeakMeanPistonSpeed_fps/RatedMeanPistonSpeed_fps; // engine impedence
    Z_airbox = (standard_pressure *Ze / maxMAP) - Ze; // impedence of airbox
  }
  // Constant for Throttle impedence
  Z_throttle=(PeakMeanPistonSpeed_fps/((IdleRPM * Stroke) / 360))*(standard_pressure/minMAP - 1) - Z_airbox; 
  //  Z_throttle=(MaxRPM/IdleRPM )*(standard_pressure/minMAP+2); // Constant for Throttle impedence

// Default tables if not provided in the configuration file
  if(Lookup_Combustion_Efficiency == 0) {
    // First column is thi, second is neta (combustion efficiency)
    Lookup_Combustion_Efficiency = new FGTable(12);
    *Lookup_Combustion_Efficiency << 0.00 << 0.980;
    *Lookup_Combustion_Efficiency << 0.90 << 0.980;
    *Lookup_Combustion_Efficiency << 1.00 << 0.970;
    *Lookup_Combustion_Efficiency << 1.05 << 0.950;
    *Lookup_Combustion_Efficiency << 1.10 << 0.900;
    *Lookup_Combustion_Efficiency << 1.15 << 0.850;
    *Lookup_Combustion_Efficiency << 1.20 << 0.790;
    *Lookup_Combustion_Efficiency << 1.30 << 0.700;
    *Lookup_Combustion_Efficiency << 1.40 << 0.630;
    *Lookup_Combustion_Efficiency << 1.50 << 0.570;
    *Lookup_Combustion_Efficiency << 1.60 << 0.525;
    *Lookup_Combustion_Efficiency << 2.00 << 0.345;
  }

    // First column is Fuel/Air Ratio, second is neta (mixture efficiency)
  if( Mixture_Efficiency_Correlation == 0) {
    Mixture_Efficiency_Correlation = new FGTable(15);
    *Mixture_Efficiency_Correlation << 0.05000 << 0.00000;
    *Mixture_Efficiency_Correlation << 0.05137 << 0.00862;
    *Mixture_Efficiency_Correlation << 0.05179 << 0.21552;
    *Mixture_Efficiency_Correlation << 0.05430 << 0.48276;
    *Mixture_Efficiency_Correlation << 0.05842 << 0.70690;
    *Mixture_Efficiency_Correlation << 0.06312 << 0.83621;
    *Mixture_Efficiency_Correlation << 0.06942 << 0.93103;
    *Mixture_Efficiency_Correlation << 0.07786 << 1.00000;
    *Mixture_Efficiency_Correlation << 0.08845 << 1.00000;
    *Mixture_Efficiency_Correlation << 0.09270 << 0.98276;
    *Mixture_Efficiency_Correlation << 0.10120 << 0.93103;
    *Mixture_Efficiency_Correlation << 0.11455 << 0.72414;
    *Mixture_Efficiency_Correlation << 0.12158 << 0.45690;
    *Mixture_Efficiency_Correlation << 0.12435 << 0.23276;
    *Mixture_Efficiency_Correlation << 0.12500 << 0.00000;
  }

  string property_name, base_property_name;
  base_property_name = CreateIndexedPropertyName("propulsion/engine", EngineNumber);
  property_name = base_property_name + "/power-hp";
  PropertyManager->Tie(property_name, &HP);
  property_name = base_property_name + "/bsfc-lbs_hphr";
  PropertyManager->Tie(property_name, &ISFC);
  property_name = base_property_name + "/starter-norm";
  PropertyManager->Tie(property_name, &StarterGain);
  property_name = base_property_name + "/volumetric-efficiency";
  PropertyManager->Tie(property_name, &volumetric_efficiency);
  property_name = base_property_name + "/map-pa";
  PropertyManager->Tie(property_name, &MAP);
  property_name = base_property_name + "/map-inhg";
  PropertyManager->Tie(property_name, &ManifoldPressure_inHg);
  property_name = base_property_name + "/air-intake-impedance-factor";
  PropertyManager->Tie(property_name, &Z_airbox);
  property_name = base_property_name + "/ram-air-factor";
  PropertyManager->Tie(property_name, &Ram_Air_Factor);
  property_name = base_property_name + "/cooling-factor";
  PropertyManager->Tie(property_name, &Cooling_Factor);
  property_name = base_property_name + "/boost-speed";
  PropertyManager->Tie(property_name, &BoostSpeed);
  property_name = base_property_name + "/cht-degF";
  PropertyManager->Tie(property_name, this, &FGPiston::getCylinderHeadTemp_degF);
  property_name = base_property_name + "/oil-temperature-degF";
  PropertyManager->Tie(property_name, this, &FGPiston::getOilTemp_degF);
  property_name = base_property_name + "/oil-pressure-psi";
  PropertyManager->Tie(property_name, this, &FGPiston::getOilPressure_psi);
  property_name = base_property_name + "/egt-degF";
  PropertyManager->Tie(property_name, this, &FGPiston::getExhaustGasTemp_degF);

  // Set up and sanity-check the turbo/supercharging configuration based on the input values.
  if (TakeoffBoost > RatedBoost[0]) bTakeoffBoost = true;
  for (i=0; i<BoostSpeeds; ++i) {
    bool bad = false;
    if (RatedBoost[i] <= 0.0) bad = true;
    if (RatedPower[i] <= 0.0) bad = true;
    if (RatedAltitude[i] < 0.0) bad = true;  // 0.0 is deliberately allowed - this corresponds to unregulated supercharging.
    if (i > 0 && RatedAltitude[i] < RatedAltitude[i - 1]) bad = true;
    if (bad) {
      // We can't recover from the above - don't use this supercharger speed.
      BoostSpeeds--;
      // TODO - put out a massive error message!
      break;
    }
    // Now sanity-check stuff that is recoverable.
    if (i < BoostSpeeds - 1) {
      if (BoostSwitchAltitude[i] < RatedAltitude[i]) {
        // TODO - put out an error message
        // But we can also make a reasonable estimate, as below.
        BoostSwitchAltitude[i] = RatedAltitude[i] + 1000;
      }
      BoostSwitchPressure[i] = GetStdPressure100K(BoostSwitchAltitude[i]) * psftopa;
      //cout << "BoostSwitchAlt = " << BoostSwitchAltitude[i] << ", pressure = " << BoostSwitchPressure[i] << '\n';
      // Assume there is some hysteresis on the supercharger gear switch, and guess the value for now
      BoostSwitchHysteresis = 1000;
    }
    // Now work out the supercharger pressure multiplier of this speed from the rated boost and altitude.
    RatedMAP[i] = standard_pressure + RatedBoost[i] * 6895;  // psi*6895 = Pa.
    // Sometimes a separate BCV setting for takeoff or extra power is fitted.
    if (TakeoffBoost > RatedBoost[0]) {
      // Assume that the effect on the BCV is the same whichever speed is in use.
      TakeoffMAP[i] = RatedMAP[i] + ((TakeoffBoost - RatedBoost[0]) * 6895);
      bTakeoffBoost = true;
    } else {
      TakeoffMAP[i] = RatedMAP[i];
      bTakeoffBoost = false;
    }
    BoostMul[i] = RatedMAP[i] / (GetStdPressure100K(RatedAltitude[i]) * psftopa);

  }

  if (BoostSpeeds > 0) {
    Boosted = true;
    BoostSpeed = 0;
  }
  bBoostOverride = (BoostOverride == 1 ? true : false);
  bBoostManual   = (BoostManual   == 1 ? true : false);
  Debug(0); // Call Debug() routine from constructor if needed
}
Exemplo n.º 2
0
FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number, struct Inputs& input)
                      : in(input), EngineNumber(engine_number)
{
  Element* local_element;
  FGColumnVector3 location, orientation;

  Name = "";
  Type = etUnknown;
  X = Y = Z = 0.0;
  EnginePitch = EngineYaw = 0.0;
  SLFuelFlowMax = 0.0;
  FuelExpended = 0.0;
  MaxThrottle = 1.0;
  MinThrottle = 0.0;

  ResetToIC(); // initialize dynamic terms

  FDMExec = exec;

  PropertyManager = FDMExec->GetPropertyManager();

  Name = engine_element->GetAttributeValue("name");

  Load(engine_element, PropertyManager, to_string(EngineNumber)); // Call ModelFunctions loader

// Find and set engine location

  local_element = engine_element->GetParent()->FindElement("location");
  if (local_element)  location = local_element->FindElementTripletConvertTo("IN");
  else      cerr << "No engine location found for this engine." << endl;

  local_element = engine_element->GetParent()->FindElement("orient");
  if (local_element)  orientation = local_element->FindElementTripletConvertTo("RAD");
//  else          cerr << "No engine orientation found for this engine." << endl;
// Jon: The engine orientation has a default and is not normally used.

  SetPlacement(location, orientation);

  // Load thruster
  local_element = engine_element->GetParent()->FindElement("thruster");
  if (local_element) {
    try {
      if (!LoadThruster(local_element)) exit(-1);
    } catch (std::string str) {
      throw("Error loading engine " + Name + ". " + str);
    }
  } else {
    cerr << "No thruster definition supplied with engine definition." << endl;
  }

  // Load feed tank[s] references
  local_element = engine_element->GetParent()->FindElement("feed");
  while (local_element) {
    int tankID = (int)local_element->GetDataAsNumber();
    SourceTanks.push_back(tankID);
    local_element = engine_element->GetParent()->FindNextElement("feed");
  }

  string property_name, base_property_name;
  base_property_name = CreateIndexedPropertyName("propulsion/engine", EngineNumber);

  property_name = base_property_name + "/set-running";
  PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetRunning, &FGEngine::SetRunning );
  property_name = base_property_name + "/thrust-lbs";
  PropertyManager->Tie( property_name.c_str(), Thruster, &FGThruster::GetThrust);
  property_name = base_property_name + "/fuel-flow-rate-pps";
  PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetFuelFlowRate);
  property_name = base_property_name + "/fuel-flow-rate-gph";
  PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetFuelFlowRateGPH);
  property_name = base_property_name + "/fuel-used-lbs";
  PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetFuelUsedLbs);

  PostLoad(engine_element, PropertyManager, to_string(EngineNumber));

  Debug(0);
}
Exemplo n.º 3
0
FGThruster::FGThruster(FGFDMExec *FDMExec, Element *el, int num ): FGForce(FDMExec)
{
  Element* thruster_element = el->GetParent();
  Element* element;
  FGColumnVector3 location, orientation, pointing;

  Type = ttDirect;
  SetTransformType(FGForce::tCustom);

  Name = el->GetAttributeValue("name");

  GearRatio = 1.0;
  EngineNum = num;
  FGPropertyManager* PropertyManager = FDMExec->GetPropertyManager();

// Determine the initial location and orientation of this thruster and load the
// thruster with this information.

  element = thruster_element->FindElement("location");
  if (element)  location = element->FindElementTripletConvertTo("IN");
  else          cerr << fgred << "      No thruster location found." << reset << endl;

  SetLocation(location);

  string property_name, base_property_name;
  base_property_name = CreateIndexedPropertyName("propulsion/engine", EngineNum);

  element = thruster_element->FindElement("pointing");
  if (element)  {

    // This defines a fixed nozzle that has no public interface property to gimbal or reverse it.
    pointing = element->FindElementTripletConvertTo("RAD"); // The specification of RAD here is superfluous,
                                                            // and simply precludes a conversion.
    mT.InitMatrix();
    mT(1,1) = pointing(1);
    mT(2,1) = pointing(2);
    mT(3,1) = pointing(3);

  } else {

    element = thruster_element->FindElement("orient");
    if (element)  orientation = element->FindElementTripletConvertTo("RAD");

    SetAnglesToBody(orientation);
    property_name = base_property_name + "/pitch-angle-rad";
    PropertyManager->Tie( property_name.c_str(), (FGForce *)this, &FGForce::GetPitch, &FGForce::SetPitch);
    property_name = base_property_name + "/yaw-angle-rad";
    PropertyManager->Tie( property_name.c_str(), (FGForce *)this, &FGForce::GetYaw, &FGForce::SetYaw);

    if (el->GetName() == "direct") // this is a direct thruster. At this time
                                   // only a direct thruster can be reversed.
      {
        property_name = base_property_name + "/reverser-angle-rad";
        PropertyManager->Tie( property_name.c_str(), (FGThruster *)this, &FGThruster::GetReverserAngle,
                              &FGThruster::SetReverserAngle);
      }

  }

  ResetToIC();

  Debug(0);
}
Exemplo n.º 4
0
bool FGTurbine::Load(FGFDMExec* exec, Element *el)
{
  Element* function_element = el->FindElement("function");

  while(function_element) {
    string name = function_element->GetAttributeValue("name");
    if (name == "IdleThrust" || name == "MilThrust" || name == "AugThrust" || name == "Injection")
      function_element->SetAttributeValue("name", string("propulsion/engine[#]/") + name);

    function_element = el->FindNextElement("function");
  }

  FGEngine::Load(exec, el);

  ResetToIC();

  if (el->FindElement("milthrust"))
    MilThrust = el->FindElementValueAsNumberConvertTo("milthrust","LBS");
  if (el->FindElement("maxthrust"))
    MaxThrust = el->FindElementValueAsNumberConvertTo("maxthrust","LBS");
  if (el->FindElement("bypassratio"))
    BypassRatio = el->FindElementValueAsNumber("bypassratio");
  if (el->FindElement("bleed"))
    BleedDemand = el->FindElementValueAsNumber("bleed");
  if (el->FindElement("tsfc"))
    TSFC = el->FindElementValueAsNumber("tsfc");
  if (el->FindElement("atsfc"))
    ATSFC = el->FindElementValueAsNumber("atsfc");
  if (el->FindElement("idlen1"))
    IdleN1 = el->FindElementValueAsNumber("idlen1");
  if (el->FindElement("idlen2"))
    IdleN2 = el->FindElementValueAsNumber("idlen2");
  if (el->FindElement("maxn1"))
    MaxN1 = el->FindElementValueAsNumber("maxn1");
  if (el->FindElement("maxn2"))
    MaxN2 = el->FindElementValueAsNumber("maxn2");
  if (el->FindElement("n1spinup"))
    N1_spinup = el->FindElementValueAsNumber("n1spinup");
  if (el->FindElement("n2spinup"))
    N2_spinup = el->FindElementValueAsNumber("n2spinup");
  if (el->FindElement("augmented"))
    Augmented = (int)el->FindElementValueAsNumber("augmented");
  if (el->FindElement("augmethod"))
    AugMethod = (int)el->FindElementValueAsNumber("augmethod");
  if (el->FindElement("injected"))
    Injected = (int)el->FindElementValueAsNumber("injected");
  if (el->FindElement("injection-time")){
    InjectionTime = el->FindElementValueAsNumber("injection-time");
    InjWaterNorm =1.0;
  }
  if (el->FindElement("injection-N1-inc"))
    InjN1increment = el->FindElementValueAsNumber("injection-N1-inc");
  if (el->FindElement("injection-N2-inc"))
    InjN2increment = el->FindElementValueAsNumber("injection-N2-inc");

  string property_prefix = CreateIndexedPropertyName("propulsion/engine", EngineNumber);

  IdleThrustLookup = GetPreFunction(property_prefix+"/IdleThrust");
  MilThrustLookup = GetPreFunction(property_prefix+"/MilThrust");
  MaxThrustLookup = GetPreFunction(property_prefix+"/AugThrust");
  InjectionLookup = GetPreFunction(property_prefix+"/Injection");

  // Pre-calculations and initializations

  delay = 90.0 / (BypassRatio + 3.0);
  N1_factor = MaxN1 - IdleN1;
  N2_factor = MaxN2 - IdleN2;
  OilTemp_degK = in.TAT_c + 273.0;
  IdleFF = pow(MilThrust, 0.2) * 107.0;  // just an estimate

  bindmodel(exec->GetPropertyManager());
  return true;
}