Exemplo n.º 1
0
bool FGAircraft::Load(Element* el)
{
  string element_name;
  Element* element;

  if (!FGModel::Load(el)) return false;

  if (el->FindElement("wingarea"))
    WingArea = el->FindElementValueAsNumberConvertTo("wingarea", "FT2");
  if (el->FindElement("wingspan"))
    WingSpan = el->FindElementValueAsNumberConvertTo("wingspan", "FT");
  if (el->FindElement("chord"))
    cbar = el->FindElementValueAsNumberConvertTo("chord", "FT");
  if (el->FindElement("wing_incidence"))
    WingIncidence = el->FindElementValueAsNumberConvertTo("wing_incidence", "RAD");
  if (el->FindElement("htailarea"))
    HTailArea = el->FindElementValueAsNumberConvertTo("htailarea", "FT2");
  if (el->FindElement("htailarm"))
    HTailArm = el->FindElementValueAsNumberConvertTo("htailarm", "FT");
  if (el->FindElement("vtailarea"))
    VTailArea = el->FindElementValueAsNumberConvertTo("vtailarea", "FT2");
  if (el->FindElement("vtailarm"))
    VTailArm = el->FindElementValueAsNumberConvertTo("vtailarm", "FT");
  if (el->FindElement("pitot_angle"))
    PitotAngle = el->FindElementValueAsNumberConvertTo("pitot_angle", "RAD");

  // Find all LOCATION elements that descend from this METRICS branch of the
  // config file. This would be CG location, eyepoint, etc.

  element = el->FindElement("location");
  while (element) {
    element_name = element->GetAttributeValue("name");

    if (element_name == "AERORP") vXYZrp = element->FindElementTripletConvertTo("IN");
    else if (element_name == "EYEPOINT") vXYZep = element->FindElementTripletConvertTo("IN");
    else if (element_name == "VRP") vXYZvrp = element->FindElementTripletConvertTo("IN");

    element = el->FindNextElement("location");
  }

  // calculate some derived parameters
  if (cbar != 0.0) {
    lbarh = HTailArm/cbar;
    lbarv = VTailArm/cbar;
    if (WingArea != 0.0) {
      vbarh = HTailArm*HTailArea / (cbar*WingArea);
      vbarv = VTailArm*VTailArea / (WingSpan*WingArea);
    }
  }

  PostLoad(el, PropertyManager);

  Debug(2);

  return true;
}
Exemplo n.º 2
0
bool FGFDMExec::ReadChild(Element* el)
{
  // 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 child objects
  // Load the model given the aircraft name
  // reset debug level to prior setting

  string token;

  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;
}
Exemplo n.º 3
0
bool FGMassBalance::Load(Element* document)
{
  string element_name = "";

  Name = "Mass Properties Model: " + document->GetAttributeValue("name");

  // Perform base class Pre-Load
  if (!FGModel::Load(document))
    return false;

  SetAircraftBaseInertias(ReadInertiaMatrix(document));
  if (document->FindElement("emptywt")) {
    EmptyWeight = document->FindElementValueAsNumberConvertTo("emptywt", "LBS");
  }

  Element *element = document->FindElement("location");
  while (element) {
    element_name = element->GetAttributeValue("name");
    if (element_name == "CG") vbaseXYZcg = element->FindElementTripletConvertTo("IN");
    element = document->FindNextElement("location");
  }

// Find all POINTMASS elements that descend from this METRICS branch of the
// config file.

  element = document->FindElement("pointmass");
  while (element) {
    AddPointMass(element);
    element = document->FindNextElement("pointmass");
  }

  double ChildFDMWeight = 0.0;
  for (int fdm=0; fdm<FDMExec->GetFDMCount(); fdm++) {
    if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
  }

  Weight = EmptyWeight + in.TanksWeight + GetTotalPointMassWeight()
    + in.GasMass*slugtolb + ChildFDMWeight;

  Mass = lbtoslug*Weight;

  PostLoad(document, PropertyManager);

  Debug(2);
  return true;
}
Exemplo n.º 4
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;
  ReverserAngle = 0.0;
  Thrust = 0.0;
  EngineNum = num;
  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);
  }

  }


  Debug(0);
}
Exemplo n.º 5
0
FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
                  : TankNumber(tank_number)
{
  string token, strFuelName;
  Element* element;
  Element* element_Grain;
  FGPropertyManager *PropertyManager = exec->GetPropertyManager();
  Area = 1.0;
  Density = 6.6;
  InitialTemperature = Temperature = -9999.0;
  Ixx = Iyy = Izz = 0.0;
  InertiaFactor = 1.0;
  Radius = Contents = Standpipe = Length = InnerRadius = 0.0;
  ExternalFlow = 0.0;
  InitialStandpipe = 0.0;
  Capacity = 0.00001;
  Priority = InitialPriority = 1;
  vXYZ.InitMatrix();
  vXYZ_drain.InitMatrix();
  ixx_unit = iyy_unit = izz_unit = 1.0;
  grainType = gtUNKNOWN; // This is the default

  type = el->GetAttributeValue("type");
  if      (type == "FUEL")     Type = ttFUEL;
  else if (type == "OXIDIZER") Type = ttOXIDIZER;
  else                         Type = ttUNKNOWN;

  element = el->FindElement("location");
  if (element)  vXYZ = element->FindElementTripletConvertTo("IN");
  else          cerr << "No location found for this tank." << endl;

  vXYZ_drain = vXYZ; // Set initial drain location to initial tank CG

  element = el->FindElement("drain_location");
  if (element)  {
    vXYZ_drain = element->FindElementTripletConvertTo("IN");
  }

  if (el->FindElement("radius"))
    Radius = el->FindElementValueAsNumberConvertTo("radius", "IN");
  if (el->FindElement("inertia_factor"))
    InertiaFactor = el->FindElementValueAsNumber("inertia_factor");
  if (el->FindElement("capacity"))
    Capacity = el->FindElementValueAsNumberConvertTo("capacity", "LBS");
  if (el->FindElement("contents"))
    InitialContents = Contents = el->FindElementValueAsNumberConvertTo("contents", "LBS");
  if (el->FindElement("temperature"))
    InitialTemperature = Temperature = el->FindElementValueAsNumber("temperature");
  if (el->FindElement("standpipe"))
    InitialStandpipe = Standpipe = el->FindElementValueAsNumberConvertTo("standpipe", "LBS");
  if (el->FindElement("priority"))
    InitialPriority = Priority = (int)el->FindElementValueAsNumber("priority");
  if (el->FindElement("density"))
    Density = el->FindElementValueAsNumberConvertTo("density", "LBS/GAL");
  if (el->FindElement("type"))
    strFuelName = el->FindElementValue("type");


  SetPriority( InitialPriority );     // this will also set the Selected flag

  if (Capacity == 0) {
    cerr << "Tank capacity must not be zero. Reset to 0.00001 lbs!" << endl;
    Capacity = 0.00001;
    Contents = 0.0;
  }
  if (Contents > Capacity) {
    cerr << "Tank content (" << Contents << " lbs) is greater than tank capacity ("
         << Capacity << " lbs) for tank " << tank_number
         << "! Did you accidentally swap contents and capacity?" << endl;
    throw("tank definition error");
  }

  PctFull = 100.0*Contents/Capacity;            // percent full; 0 to 100.0

  // Check whether this is a solid propellant "tank". Initialize it if true.

  element_Grain = el->FindElement("grain_config");
  if (element_Grain) {

    strGType = element_Grain->GetAttributeValue("type");
    if (strGType == "CYLINDRICAL")     grainType = gtCYLINDRICAL;
    else if (strGType == "ENDBURNING") grainType = gtENDBURNING;
    else if (strGType == "FUNCTION")   {
      grainType = gtFUNCTION;
      if (element_Grain->FindElement("ixx") != 0) {
        Element* element_ixx = element_Grain->FindElement("ixx");
        if (element_ixx->GetAttributeValue("unit") == "KG*M2") ixx_unit = 1.0/1.35594;
        if (element_ixx->FindElement("function") != 0) {
          function_ixx = new FGFunction(PropertyManager, element_ixx->FindElement("function"));
        }
      } else {
        throw("For tank "+to_string(TankNumber)+" and when grain_config is specified an ixx must be specified when the FUNCTION grain type is specified.");
      }

      if (element_Grain->FindElement("iyy")) {
        Element* element_iyy = element_Grain->FindElement("iyy");
        if (element_iyy->GetAttributeValue("unit") == "KG*M2") iyy_unit = 1.0/1.35594;
        if (element_iyy->FindElement("function") != 0) {
          function_iyy = new FGFunction(PropertyManager, element_iyy->FindElement("function"));
        }
      } else {
        throw("For tank "+to_string(TankNumber)+" and when grain_config is specified an iyy must be specified when the FUNCTION grain type is specified.");
      }

      if (element_Grain->FindElement("izz")) {
        Element* element_izz = element_Grain->FindElement("izz");
        if (element_izz->GetAttributeValue("unit") == "KG*M2") izz_unit = 1.0/1.35594;
        if (element_izz->FindElement("function") != 0) {
          function_izz = new FGFunction(PropertyManager, element_izz->FindElement("function"));
        }
      } else {
        throw("For tank "+to_string(TankNumber)+" and when grain_config is specified an izz must be specified when the FUNCTION grain type is specified.");
      }
    }
    else                               cerr << "Unknown propellant grain type specified" << endl;

    if (element_Grain->FindElement("length"))
      Length = element_Grain->FindElementValueAsNumberConvertTo("length", "IN");
    if (element_Grain->FindElement("bore_diameter"))
      InnerRadius = element_Grain->FindElementValueAsNumberConvertTo("bore_diameter", "IN")/2.0;

    // Initialize solid propellant values for debug and runtime use.

    switch (grainType) {
      case gtCYLINDRICAL:
        if (Radius <= InnerRadius) {
            std::stringstream error;
          error << "The bore diameter should be smaller than the total grain diameter!" << endl;
          throw std::runtime_error(error.str());
        }
        Volume = M_PI * Length * (Radius*Radius - InnerRadius*InnerRadius); // cubic inches
        break;
      case gtENDBURNING:
        Volume = M_PI * Length * Radius * Radius; // cubic inches
        break;
      case gtFUNCTION:
        Volume = 1;  // Volume is irrelevant for the FUNCTION type, but it can't be zero!
        break;
      case gtUNKNOWN:
          std::stringstream error;
        error << "Unknown grain type found in this rocket engine definition." << endl;
        throw std::runtime_error(error.str());
    }
    Density = (Contents*lbtoslug)/Volume; // slugs/in^3
  }

  CalculateInertias();

  if (Temperature != -9999.0)  InitialTemperature = Temperature = FahrenheitToCelsius(Temperature);
  Area = 40.0 * pow(Capacity/1975, 0.666666667);

  // A named fuel type will override a previous density value
  if (!strFuelName.empty()) Density = ProcessFuelName(strFuelName); 

  bind(PropertyManager);

  Debug(0);
}
Exemplo n.º 6
0
FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
                  : TankNumber(tank_number), Exec(exec)
{
  string token, strFuelName;
  Element* element;
  Element* element_Grain;
  Area = 1.0;
  Density = 6.6;
  InitialTemperature = Temperature = -9999.0;
  Ixx = Iyy = Izz = 0.0;
  InertiaFactor = 1.0;
  Radius = Contents = Standpipe = Length = InnerRadius = 0.0;
  PreviousUsed = 0.0;
  ExternalFlow = 0.0;
  InitialStandpipe = 0.0;
  Capacity = 0.00001;
  Priority = InitialPriority = 1;
  PropertyManager = Exec->GetPropertyManager();
  vXYZ.InitMatrix();
  vXYZ_drain.InitMatrix();

  type = el->GetAttributeValue("type");
  if      (type == "FUEL")     Type = ttFUEL;
  else if (type == "OXIDIZER") Type = ttOXIDIZER;
  else                         Type = ttUNKNOWN;

  element = el->FindElement("location");
  if (element)  vXYZ = element->FindElementTripletConvertTo("IN");
  else          cerr << "No location found for this tank." << endl;

  vXYZ_drain = vXYZ; // Set initial drain location to initial tank CG

  element = el->FindElement("drain_location");
  if (element)  {
    vXYZ_drain = element->FindElementTripletConvertTo("IN");
  }

  if (el->FindElement("radius"))
    Radius = el->FindElementValueAsNumberConvertTo("radius", "IN");
  if (el->FindElement("inertia_factor"))
    InertiaFactor = el->FindElementValueAsNumber("inertia_factor");
  if (el->FindElement("capacity"))
    Capacity = el->FindElementValueAsNumberConvertTo("capacity", "LBS");
  if (el->FindElement("contents"))
    InitialContents = Contents = el->FindElementValueAsNumberConvertTo("contents", "LBS");
  if (el->FindElement("temperature"))
    InitialTemperature = Temperature = el->FindElementValueAsNumber("temperature");
  if (el->FindElement("standpipe"))
    InitialStandpipe = Standpipe = el->FindElementValueAsNumberConvertTo("standpipe", "LBS");
  if (el->FindElement("priority"))
    InitialPriority = Priority = (int)el->FindElementValueAsNumber("priority");
  if (el->FindElement("density"))
    Density = el->FindElementValueAsNumberConvertTo("density", "LBS/GAL");
  if (el->FindElement("type"))
    strFuelName = el->FindElementValue("type");


  SetPriority( InitialPriority );     // this will also set the Selected flag

  if (Capacity == 0) {
    cerr << "Tank capacity must not be zero. Reset to 0.00001 lbs!" << endl;
    Capacity = 0.00001;
    Contents = 0.0;
  }
  if (Contents > Capacity) {
    cerr << "Tank content (" << Contents << " lbs) is greater than tank capacity ("
         << Capacity << " lbs) for tank " << tank_number
         << "! Did you accidentally swap contents and capacity?" << endl;
    throw("tank definition error");
  }

  PctFull = 100.0*Contents/Capacity;            // percent full; 0 to 100.0

  // Check whether this is a solid propellant "tank". Initialize it if true.

  grainType = gtUNKNOWN; // This is the default
  
  element_Grain = el->FindElement("grain_config");
  if (element_Grain) {

    strGType = element_Grain->GetAttributeValue("type");
    if (strGType == "CYLINDRICAL")     grainType = gtCYLINDRICAL;
    else if (strGType == "ENDBURNING") grainType = gtENDBURNING;
    else                               cerr << "Unknown propellant grain type specified" << endl;

    if (element_Grain->FindElement("length"))
      Length = element_Grain->FindElementValueAsNumberConvertTo("length", "IN");
    if (element_Grain->FindElement("bore_diameter"))
      InnerRadius = element_Grain->FindElementValueAsNumberConvertTo("bore_diameter", "IN")/2.0;

    // Initialize solid propellant values for debug and runtime use.

    switch (grainType) {
      case gtCYLINDRICAL:
        if (Radius <= InnerRadius) {
          cerr << "The bore diameter should be smaller than the total grain diameter!" << endl;
          exit(-1);
        }
        Volume = M_PI * Length * (Radius*Radius - InnerRadius*InnerRadius); // cubic inches
        break;
      case gtENDBURNING:
        Volume = M_PI * Length * Radius * Radius; // cubic inches
        break;
      case gtUNKNOWN:
        cerr << "Unknown grain type found in this rocket engine definition." << endl;
        exit(-1);
    }
    Density = (Contents*lbtoslug)/Volume; // slugs/in^3
  }

    CalculateInertias();

  string property_name, base_property_name;
  base_property_name = CreateIndexedPropertyName("propulsion/tank", TankNumber);
  property_name = base_property_name + "/contents-lbs";
  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetContents,
                                       &FGTank::SetContents );
  property_name = base_property_name + "/pct-full";
  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetPctFull);

  property_name = base_property_name + "/priority";
  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetPriority,
                                       &FGTank::SetPriority );
  property_name = base_property_name + "/external-flow-rate-pps";
  PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetExternalFlow,
                                       &FGTank::SetExternalFlow );

  if (Temperature != -9999.0)  InitialTemperature = Temperature = FahrenheitToCelsius(Temperature);
  Area = 40.0 * pow(Capacity/1975, 0.666666667);

  // A named fuel type will override a previous density value
  if (!strFuelName.empty()) Density = ProcessFuelName(strFuelName); 

  Debug(0);
}
Exemplo n.º 7
0
bool FGMassBalance::Load(Element* elem)
{
  string element_name = "";
  double bixx, biyy, bizz, bixy, bixz, biyz;
  string fname="", file="";
  string separator = "/";

  fname = elem->GetAttributeValue("file");
  if (!fname.empty()) {
    file = FDMExec->GetFullAircraftPath() + separator + fname;
    document = LoadXMLDocument(file);
    if (document == 0L) return false;
  } else {
    document = elem;
  }

  FGModel::Load(document); // Perform base class Load.

  bixx = biyy = bizz = bixy = bixz = biyz = 0.0;
  if (document->FindElement("ixx"))
    bixx = document->FindElementValueAsNumberConvertTo("ixx", "SLUG*FT2");
  if (document->FindElement("iyy"))
    biyy = document->FindElementValueAsNumberConvertTo("iyy", "SLUG*FT2");
  if (document->FindElement("izz"))
    bizz = document->FindElementValueAsNumberConvertTo("izz", "SLUG*FT2");
  if (document->FindElement("ixy"))
    bixy = document->FindElementValueAsNumberConvertTo("ixy", "SLUG*FT2");
  if (document->FindElement("ixz"))
    bixz = document->FindElementValueAsNumberConvertTo("ixz", "SLUG*FT2");
  if (document->FindElement("iyz"))
    biyz = document->FindElementValueAsNumberConvertTo("iyz", "SLUG*FT2");
  SetAircraftBaseInertias(FGMatrix33(  bixx,  -bixy,  bixz,
                                      -bixy,  biyy,  -biyz,
                                       bixz,  -biyz,  bizz ));
  if (document->FindElement("emptywt")) {
    EmptyWeight = document->FindElementValueAsNumberConvertTo("emptywt", "LBS");
  }

  Element *element = document->FindElement("location");
  while (element) {
    element_name = element->GetAttributeValue("name");
    if (element_name == "CG") vbaseXYZcg = element->FindElementTripletConvertTo("IN");
    element = document->FindNextElement("location");
  }

// Find all POINTMASS elements that descend from this METRICS branch of the
// config file.

  element = document->FindElement("pointmass");
  while (element) {
    AddPointMass(element);
    element = document->FindNextElement("pointmass");
  }

  double ChildFDMWeight = 0.0;
  for (int fdm=0; fdm<FDMExec->GetFDMCount(); fdm++) {
    if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
  }

  Weight = EmptyWeight + in.TanksWeight + GetTotalPointMassWeight()
    + in.GasMass*slugtolb + ChildFDMWeight;

  Mass = lbtoslug*Weight;

  PostLoad(document, PropertyManager);

  Debug(2);
  return true;
}
Exemplo n.º 8
0
FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, unsigned int num,
                     const struct Inputs& input)
  : FGForce(exec), in(input)
{
  string token;
  Element* element;

  FGPropertyManager* PropertyManager = exec->GetPropertyManager();
  MassBalance = exec->GetMassBalance();

  gasCellJ = FGMatrix33();
  gasCellM = FGColumnVector3();

  Buoyancy = MaxVolume = MaxOverpressure = Temperature = Pressure =
    Contents = Volume = dVolumeIdeal = 0.0;
  Xradius = Yradius = Zradius = Xwidth = Ywidth = Zwidth = 0.0;
  ValveCoefficient = ValveOpen = 0.0;
  CellNum = num;

  // NOTE: In the local system X points north, Y points east and Z points down.
  SetTransformType(FGForce::tLocalBody);

  type = el->GetAttributeValue("type");
  if      (type == "HYDROGEN") Type = ttHYDROGEN;
  else if (type == "HELIUM")   Type = ttHELIUM;
  else if (type == "AIR")      Type = ttAIR;
  else                         Type = ttUNKNOWN;

  element = el->FindElement("location");
  if (element) {
    vXYZ = element->FindElementTripletConvertTo("IN");
  } else {
      std::stringstream error;
    error << "Fatal Error: No location found for this gas cell." << endl;
    throw std::runtime_error(error.str());
  }
  if ((el->FindElement("x_radius") || el->FindElement("x_width")) &&
      (el->FindElement("y_radius") || el->FindElement("y_width")) &&
      (el->FindElement("z_radius") || el->FindElement("z_width"))) {

    if (el->FindElement("x_radius")) {
      Xradius = el->FindElementValueAsNumberConvertTo("x_radius", "FT");
    }
    if (el->FindElement("y_radius")) {
      Yradius = el->FindElementValueAsNumberConvertTo("y_radius", "FT");
    }
    if (el->FindElement("z_radius")) {
      Zradius = el->FindElementValueAsNumberConvertTo("z_radius", "FT");
    }

    if (el->FindElement("x_width")) {
      Xwidth = el->FindElementValueAsNumberConvertTo("x_width", "FT");
    }
    if (el->FindElement("y_width")) {
      Ywidth = el->FindElementValueAsNumberConvertTo("y_width", "FT");
    }
    if (el->FindElement("z_width")) {
      Zwidth = el->FindElementValueAsNumberConvertTo("z_width", "FT");
    }

    // The volume is a (potentially) extruded ellipsoid.
    // However, currently only a few combinations of radius and width are
    // fully supported.
    if ((Xradius != 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
        (Xwidth  == 0.0) && (Ywidth  == 0.0) && (Zwidth  == 0.0)) {
      // Ellipsoid volume.
      MaxVolume = 4.0  * M_PI * Xradius * Yradius * Zradius / 3.0;
    } else if  ((Xradius == 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
                (Xwidth  != 0.0) && (Ywidth  == 0.0) && (Zwidth  == 0.0)) {
      // Cylindrical volume.
      MaxVolume = M_PI * Yradius * Zradius * Xwidth;
    } else {
      cerr << "Warning: Unsupported gas cell shape." << endl;
      MaxVolume = 
        (4.0  * M_PI * Xradius * Yradius * Zradius / 3.0 +
         M_PI * Yradius * Zradius * Xwidth +
         M_PI * Xradius * Zradius * Ywidth +
         M_PI * Xradius * Yradius * Zwidth +
         2.0  * Xradius * Ywidth * Zwidth +
         2.0  * Yradius * Xwidth * Zwidth +
         2.0  * Zradius * Xwidth * Ywidth +
         Xwidth * Ywidth * Zwidth);
    }
  } else {
      std::stringstream error;
    error << "Fatal Error: Gas cell shape must be given." << endl;
    throw std::runtime_error(error.str());
  }
  if (el->FindElement("max_overpressure")) {
    MaxOverpressure = el->FindElementValueAsNumberConvertTo("max_overpressure",
                                                            "LBS/FT2");
  }
  if (el->FindElement("fullness")) {
    const double Fullness = el->FindElementValueAsNumber("fullness");
    if (0 <= Fullness) { 
      Volume = Fullness * MaxVolume; 
    } else {
      cerr << "Warning: Invalid initial gas cell fullness value." << endl;
    }
  }  
  if (el->FindElement("valve_coefficient")) {
    ValveCoefficient =
      el->FindElementValueAsNumberConvertTo("valve_coefficient",
                                            "FT4*SEC/SLUG");
    ValveCoefficient = max(ValveCoefficient, 0.0);
  }

  // Initialize state
  SetLocation(vXYZ);

  if (Temperature == 0.0) {
    Temperature = in.Temperature;
  }
  if (Pressure == 0.0) {
    Pressure = in.Pressure;
  }
  if (Volume != 0.0) {
    // Calculate initial gas content.
    Contents = Pressure * Volume / (R * Temperature);
    
    // Clip to max allowed value.
    const double IdealPressure = Contents * R * Temperature / MaxVolume;
    if (IdealPressure > Pressure + MaxOverpressure) {
      Contents = (Pressure + MaxOverpressure) * MaxVolume / (R * Temperature);
      Pressure = Pressure + MaxOverpressure;
    } else {
      Pressure = max(IdealPressure, Pressure);
    }
  } else {
    // Calculate initial gas content.
    Contents = Pressure * MaxVolume / (R * Temperature);
  }

  Volume = Contents * R * Temperature / Pressure;
  Mass = Contents * M_gas();

  // Bind relevant properties
  string property_name, base_property_name;

  base_property_name = CreateIndexedPropertyName("buoyant_forces/gas-cell", CellNum);

  property_name = base_property_name + "/max_volume-ft3";
  PropertyManager->Tie( property_name.c_str(), &MaxVolume, false );
  PropertyManager->GetNode()->SetWritable( property_name, false );
  property_name = base_property_name + "/temp-R";
  PropertyManager->Tie( property_name.c_str(), &Temperature, false );
  property_name = base_property_name + "/pressure-psf";
  PropertyManager->Tie( property_name.c_str(), &Pressure, false );
  property_name = base_property_name + "/volume-ft3";
  PropertyManager->Tie( property_name.c_str(), &Volume, false );
  property_name = base_property_name + "/buoyancy-lbs";
  PropertyManager->Tie( property_name.c_str(), &Buoyancy, false );
  property_name = base_property_name + "/contents-mol";
  PropertyManager->Tie( property_name.c_str(), &Contents, false );
  property_name = base_property_name + "/valve_open";
  PropertyManager->Tie( property_name.c_str(), &ValveOpen, false );

  Debug(0);

  // Read heat transfer coefficients
  if (Element* heat = el->FindElement("heat")) {
    Element* function_element = heat->FindElement("function");
    while (function_element) {
      HeatTransferCoeff.push_back(new FGFunction(PropertyManager,
                                                 function_element));
      function_element = heat->FindNextElement("function");
    }
  }

  // Load ballonets if there are any
  if (Element* ballonet_element = el->FindElement("ballonet")) {
    while (ballonet_element) {
      Ballonet.push_back(new FGBallonet(exec,
                                        ballonet_element,
                                        Ballonet.size(),
                                        this, in));
      ballonet_element = el->FindNextElement("ballonet");
    }
  }

}
Exemplo n.º 9
0
FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, unsigned int num,
                       FGGasCell* parent, const struct FGGasCell::Inputs& input)
  : in(input)
{
  string token;
  Element* element;

  FGPropertyManager* PropertyManager = exec->GetPropertyManager();
  MassBalance = exec->GetMassBalance();

  ballonetJ = FGMatrix33();

  MaxVolume = MaxOverpressure = Temperature = Pressure =
    Contents = Volume = dVolumeIdeal = dU = 0.0;
  Xradius = Yradius = Zradius = Xwidth = Ywidth = Zwidth = 0.0;
  ValveCoefficient = ValveOpen = 0.0;
  BlowerInput = NULL;
  CellNum = num;
  Parent = parent;

  // NOTE: In the local system X points north, Y points east and Z points down.
  element = el->FindElement("location");
  if (element) {
    vXYZ = element->FindElementTripletConvertTo("IN");
  } else {
      std::stringstream error;
    error << "Fatal Error: No location found for this ballonet." << endl;
    throw std::runtime_error(error.str());
  }
  if ((el->FindElement("x_radius") || el->FindElement("x_width")) &&
      (el->FindElement("y_radius") || el->FindElement("y_width")) &&
      (el->FindElement("z_radius") || el->FindElement("z_width"))) {

    if (el->FindElement("x_radius")) {
      Xradius = el->FindElementValueAsNumberConvertTo("x_radius", "FT");
    }
    if (el->FindElement("y_radius")) {
      Yradius = el->FindElementValueAsNumberConvertTo("y_radius", "FT");
    }
    if (el->FindElement("z_radius")) {
      Zradius = el->FindElementValueAsNumberConvertTo("z_radius", "FT");
    }

    if (el->FindElement("x_width")) {
      Xwidth = el->FindElementValueAsNumberConvertTo("x_width", "FT");
    }
    if (el->FindElement("y_width")) {
      Ywidth = el->FindElementValueAsNumberConvertTo("y_width", "FT");
    }
    if (el->FindElement("z_width")) {
      Zwidth = el->FindElementValueAsNumberConvertTo("z_width", "FT");
    }

    // The volume is a (potentially) extruded ellipsoid.
    // FIXME: However, currently only a few combinations of radius and
    //        width are fully supported.
    if ((Xradius != 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
        (Xwidth  == 0.0) && (Ywidth  == 0.0) && (Zwidth  == 0.0)) {
      // Ellipsoid volume.
      MaxVolume = 4.0  * M_PI * Xradius * Yradius * Zradius / 3.0;
    } else if  ((Xradius == 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
                (Xwidth  != 0.0) && (Ywidth  == 0.0) && (Zwidth  == 0.0)) {
      // Cylindrical volume.
      MaxVolume = M_PI * Yradius * Zradius * Xwidth;
    } else {
      cerr << "Warning: Unsupported ballonet shape." << endl;
      MaxVolume = 
        (4.0  * M_PI * Xradius * Yradius * Zradius / 3.0 +
         M_PI * Yradius * Zradius * Xwidth +
         M_PI * Xradius * Zradius * Ywidth +
         M_PI * Xradius * Yradius * Zwidth +
         2.0  * Xradius * Ywidth * Zwidth +
         2.0  * Yradius * Xwidth * Zwidth +
         2.0  * Zradius * Xwidth * Ywidth +
         Xwidth * Ywidth * Zwidth);
    }
  } else {
      std::stringstream error;
    error << "Fatal Error: Ballonet shape must be given." << endl;
    throw std::runtime_error(error.str());
  }
  if (el->FindElement("max_overpressure")) {
    MaxOverpressure = el->FindElementValueAsNumberConvertTo("max_overpressure",
                                                            "LBS/FT2");
  }
  if (el->FindElement("fullness")) {
    const double Fullness = el->FindElementValueAsNumber("fullness");
    if (0 <= Fullness) { 
      Volume = Fullness * MaxVolume; 
    } else {
      cerr << "Warning: Invalid initial ballonet fullness value." << endl;
    }
  }  
  if (el->FindElement("valve_coefficient")) {
    ValveCoefficient =
      el->FindElementValueAsNumberConvertTo("valve_coefficient",
                                            "FT4*SEC/SLUG");
    ValveCoefficient = max(ValveCoefficient, 0.0);
  }

  // Initialize state
  if (Temperature == 0.0) {
    Temperature = Parent->GetTemperature();
  }
  if (Pressure == 0.0) {
    Pressure = Parent->GetPressure();
  }
  if (Volume != 0.0) {
    // Calculate initial air content.
    Contents = Pressure * Volume / (R * Temperature);
    
    // Clip to max allowed value.
    const double IdealPressure = Contents * R * Temperature / MaxVolume;
    if (IdealPressure > Pressure + MaxOverpressure) {
      Contents = (Pressure + MaxOverpressure) * MaxVolume / (R * Temperature);
      Pressure = Pressure + MaxOverpressure;
    } else {
      Pressure = max(IdealPressure, Pressure);
    }
  } else {
    // Calculate initial air content.
    Contents = Pressure * MaxVolume / (R * Temperature);
  }

  Volume = Contents * R * Temperature / Pressure;

  // Bind relevant properties
  string property_name, base_property_name;
  base_property_name = CreateIndexedPropertyName("buoyant_forces/gas-cell", Parent->GetIndex());
  base_property_name = CreateIndexedPropertyName(base_property_name + "/ballonet", CellNum);

  property_name = base_property_name + "/max_volume-ft3";
  PropertyManager->Tie( property_name, &MaxVolume, false );
  PropertyManager->GetNode()->SetWritable( property_name, false );

  property_name = base_property_name + "/temp-R";
  PropertyManager->Tie( property_name, &Temperature, false );

  property_name = base_property_name + "/pressure-psf";
  PropertyManager->Tie( property_name, &Pressure, false );

  property_name = base_property_name + "/volume-ft3";
  PropertyManager->Tie( property_name, &Volume, false );

  property_name = base_property_name + "/contents-mol";
  PropertyManager->Tie( property_name, &Contents, false );

  property_name = base_property_name + "/valve_open";
  PropertyManager->Tie( property_name, &ValveOpen, false );

  Debug(0);

  // Read heat transfer coefficients
  if (Element* heat = el->FindElement("heat")) {
    Element* function_element = heat->FindElement("function");
    while (function_element) {
      HeatTransferCoeff.push_back(new FGFunction(PropertyManager,
                                                 function_element));
      function_element = heat->FindNextElement("function");
    }
  }
  // Read blower input function
  if (Element* blower = el->FindElement("blower_input")) {
    Element* function_element = blower->FindElement("function");
    BlowerInput = new FGFunction(PropertyManager,
                                 function_element);
  }
}