OptionalModelObject ReverseTranslator::translateSizingSystem( const WorkspaceObject & workspaceObject )
{
  boost::optional<WorkspaceObject> _airLoopHVAC = workspaceObject.getTarget(Sizing_SystemFields::AirLoopName);

  boost::optional<AirLoopHVAC> airLoopHVAC;

  if( _airLoopHVAC )
  {
    boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(_airLoopHVAC.get());

    if( mo )
    {
      airLoopHVAC = mo->optionalCast<AirLoopHVAC>();
    }
  }

  if( ! airLoopHVAC )
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't find associated AirLoopHVAC.");

    return boost::none;
  }

  openstudio::model::SizingSystem sizingSystem = airLoopHVAC->sizingSystem(); 

  boost::optional<std::string> s;
  boost::optional<double> value;

  // TypeofLoadtoSizeOn

  s = workspaceObject.getString(Sizing_SystemFields::TypeofLoadtoSizeOn);
  if( s )
  {
    sizingSystem.setTypeofLoadtoSizeOn(s.get());
  }

  // DesignOutdoorAirFlowRate

  s = workspaceObject.getString(Sizing_SystemFields::DesignOutdoorAirFlowRate);
  value = workspaceObject.getDouble(Sizing_SystemFields::DesignOutdoorAirFlowRate);
  if( value )
  {
    sizingSystem.setDesignOutdoorAirFlowRate(value.get());
  }
  else if( s && istringEqual(s.get(),"Autosize") )
  {
    sizingSystem.autosizeDesignOutdoorAirFlowRate();
  }

  // MinimumSystemAirFlowRatio

  value = workspaceObject.getDouble(Sizing_SystemFields::CentralHeatingMaximumSystemAirFlowRatio);
  if( value )
  {
    sizingSystem.setMinimumSystemAirFlowRatio(value.get());
  }

  // PreheatDesignTemperature

  value = workspaceObject.getDouble(Sizing_SystemFields::PreheatDesignTemperature);
  if( value )
  {
    sizingSystem.setPreheatDesignTemperature(value.get());
  }

  // PreheatDesignHumidityRatio

  value = workspaceObject.getDouble(Sizing_SystemFields::PreheatDesignHumidityRatio);
  if( value )
  {
    sizingSystem.setPreheatDesignHumidityRatio(value.get());
  }

  // PrecoolDesignTemperature

  value = workspaceObject.getDouble(Sizing_SystemFields::PrecoolDesignTemperature);
  if( value )
  {
    sizingSystem.setPrecoolDesignTemperature(value.get());
  }

  // PrecoolDesignHumidityRatio

  value = workspaceObject.getDouble(Sizing_SystemFields::PrecoolDesignHumidityRatio);
  if( value )
  {
    sizingSystem.setPrecoolDesignHumidityRatio(value.get());
  }

  // CentralCoolingDesignSupplyAirTemperature

  value = workspaceObject.getDouble(Sizing_SystemFields::CentralCoolingDesignSupplyAirTemperature);
  if( value )
  {
    sizingSystem.setCentralCoolingDesignSupplyAirTemperature(value.get());
  }

  // CentralHeatingDesignSupplyAirTemperature

  value = workspaceObject.getDouble(Sizing_SystemFields::CentralHeatingDesignSupplyAirTemperature);
  if( value )
  {
    sizingSystem.setCentralHeatingDesignSupplyAirTemperature(value.get());
  }

  // SizingOption

  s = workspaceObject.getString(Sizing_SystemFields::TypeofZoneSumtoUse);
  if( s )
  {
    sizingSystem.setSizingOption(s.get());
  }

  // AllOutdoorAirinCooling

  s = workspaceObject.getString(Sizing_SystemFields::AllOutdoorAirinCooling);
  if( s && istringEqual(s.get(),"Yes") )
  {
    sizingSystem.setAllOutdoorAirinCooling(true);
  }
  else if( s && istringEqual(s.get(),"No") )
  {
    sizingSystem.setAllOutdoorAirinCooling(false);
  }

  // AllOutdoorAirinHeating

  s = workspaceObject.getString(Sizing_SystemFields::AllOutdoorAirinHeating);
  if( s && istringEqual(s.get(),"Yes")  )
  {
    sizingSystem.setAllOutdoorAirinHeating(true);
  }
  else if( s && istringEqual(s.get(),"No") )
  {
    sizingSystem.setAllOutdoorAirinHeating(false);
  }

  // CentralCoolingDesignSupplyAirHumidityRatio

  value = workspaceObject.getDouble(Sizing_SystemFields::CentralCoolingDesignSupplyAirHumidityRatio);
  if( value )
  {
    sizingSystem.setCentralCoolingDesignSupplyAirHumidityRatio(value.get());
  }

  // CentralHeatingDesignSupplyAirHumidityRatio

  value = workspaceObject.getDouble(Sizing_SystemFields::CentralHeatingDesignSupplyAirHumidityRatio);
  if( value )
  {
    sizingSystem.setCentralHeatingDesignSupplyAirHumidityRatio(value.get());
  }

  // CoolingDesignAirFlowMethod

  s = workspaceObject.getString(Sizing_SystemFields::CoolingSupplyAirFlowRateMethod);
  if( s )
  {
    sizingSystem.setCoolingDesignAirFlowMethod(s.get());
  }

  // CoolingDesignAirFlowRate

  value = workspaceObject.getDouble(Sizing_SystemFields::CoolingSupplyAirFlowRate);
  if( value )
  {
    sizingSystem.setCoolingDesignAirFlowRate(value.get());
  }

  // HeatingDesignAirFlowMethod

  s = workspaceObject.getString(Sizing_SystemFields::HeatingSupplyAirFlowRateMethod);
  if( s )
  {
    sizingSystem.setHeatingDesignAirFlowMethod(s.get());
  }

  // HeatingDesignAirFlowRate

  value = workspaceObject.getDouble(Sizing_SystemFields::HeatingSupplyAirFlowRate);
  if( value )
  {
    sizingSystem.setHeatingDesignAirFlowRate(value.get());
  }

  // SystemOutdoorAirMethod

  s = workspaceObject.getString(Sizing_SystemFields::SystemOutdoorAirMethod);
  if( s )
  {
    sizingSystem.setSystemOutdoorAirMethod(s.get());
  }

  return sizingSystem;
}
OptionalModelObject ReverseTranslator::translateSetpointManagerSingleZoneReheat( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::SetpointManager_SingleZone_Reheat )
  {
     LOG(Error, "WorkspaceObject is not IddObjectType: SetpointManager_SingleZone_Reheat");
     return boost::none;
  }

  bool nodeFound = false;

  if( boost::optional<std::string> setpointNodeName = workspaceObject.getString(SetpointManager_SingleZone_ReheatFields::SetpointNodeorNodeListName) )
  {
    boost::optional<Node> setpointNode = m_model.getModelObjectByName<Node>(setpointNodeName.get());

    if( setpointNode ) { nodeFound = true; }
  }

  if( ! nodeFound )
  {
    LOG(Error, workspaceObject.briefDescription() << " is not attached to a node in the model");

    return boost::none;
  }

  SetpointManagerSingleZoneReheat mo(m_model);

  boost::optional<std::string> s = workspaceObject.getString(SetpointManager_SingleZone_ReheatFields::Name);
  if( s )
  {
    mo.setName(s.get());
  }

  boost::optional<double> value = workspaceObject.getDouble(SetpointManager_SingleZone_ReheatFields::MinimumSupplyAirTemperature);
  if( value )
  {
    mo.setMinimumSupplyAirTemperature(value.get());
  }

  value = workspaceObject.getDouble(SetpointManager_SingleZone_ReheatFields::MaximumSupplyAirTemperature);
  if( value )
  {
    mo.setMaximumSupplyAirTemperature(value.get());
  }

  s = workspaceObject.getString(SetpointManager_SingleZone_ReheatFields::ControlZoneName);
  if( s )
  {
    boost::optional<ModelObject> modelObject;
    boost::optional<Space> space;

    if( boost::optional<WorkspaceObject> _zone = 
          workspaceObject.workspace().getObjectByTypeAndName(IddObjectType::Zone,s.get()) )
    {
      modelObject = translateAndMapWorkspaceObject(_zone.get());
    }

    if( modelObject )
    {
      if( (space = modelObject->optionalCast<Space>()) )
      {
        if( boost::optional<ThermalZone> thermalZone = space->thermalZone() )
        {
          mo.setControlZone(thermalZone.get());
        }
      }
    }
  }

  s = workspaceObject.getString(SetpointManager_SingleZone_ReheatFields::SetpointNodeorNodeListName);
  if( s )
  {
    if( boost::optional<Node> node = m_model.getModelObjectByName<Node>(s.get()) )
    {
      mo.addToNode(node.get());
    }
  }

  if( mo.setpointNode() )
  {
    return mo;
  }
  else
  {
    return boost::none;
  }
}
OptionalModelObject ReverseTranslator::translateEvaporativeFluidCoolerSingleSpeed( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::EvaporativeFluidCooler_SingleSpeed )
  {
     LOG(Error, "WorkspaceObject is not IddObjectType: EvaporativeFluidCooler_SingleSpeed");
     return boost::none;
  }

  boost::optional<EvaporativeFluidCoolerSingleSpeed> evapCooler;

  evapCooler = EvaporativeFluidCoolerSingleSpeed( m_model );

  if( evapCooler )
  {
    boost::optional<double> value;
    boost::optional<std::string> s = workspaceObject.getString(EvaporativeFluidCooler_SingleSpeedFields::Name);

    if( s )
    {
      evapCooler->setName(s.get());
    }

    // DesignAirFlowRate
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::DesignAirFlowRate);
    s = workspaceObject.getString(EvaporativeFluidCooler_SingleSpeedFields::DesignAirFlowRate);
    if( value )
    {
      evapCooler->setDesignAirFlowRate(value.get());
    }
    else if( s && istringEqual(s.get(),"Autosize") )
    {
      evapCooler->autosizeDesignAirFlowRate();
    }
    else if( s && istringEqual(s.get(),"Autocalculate") )
    {
      evapCooler->autosizeDesignAirFlowRate();
    }

    // FanPoweratDesignAirFlowRate
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::DesignAirFlowRateFanPower);
    s = workspaceObject.getString(EvaporativeFluidCooler_SingleSpeedFields::DesignAirFlowRateFanPower);
    if( value )
    {
      evapCooler->setFanPoweratDesignAirFlowRate(value.get());
    }
    else if( s && istringEqual(s.get(),"Autosize") )
    {
      evapCooler->autosizeFanPoweratDesignAirFlowRate();
    }
    else if( s && istringEqual(s.get(),"Autocalculate") )
    {
      evapCooler->autosizeFanPoweratDesignAirFlowRate();
    }

    // DesignSprayWaterFlowRate
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::DesignSprayWaterFlowRate);
    if( value )
    {
      evapCooler->setDesignSprayWaterFlowRate(value.get());
    }

    // PerformanceInputMethod
    s = workspaceObject.getString(EvaporativeFluidCooler_SingleSpeedFields::PerformanceInputMethod);
    if( s )
    {
      evapCooler->setPerformanceInputMethod(s.get());
    }

    // StandardDesignCapacity
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::StandardDesignCapacity);
    if( value )
    {
      evapCooler->setStandardDesignCapacity(value.get());
    }

    // UfactorTimesAreaValueatDesignAirFlowRate
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::DesignAirFlowRateUfactorTimesAreaValue);
    s = workspaceObject.getString(EvaporativeFluidCooler_SingleSpeedFields::DesignAirFlowRateUfactorTimesAreaValue);
    if( value )
    {
      evapCooler->setUfactorTimesAreaValueatDesignAirFlowRate(value.get());
    }
    else if( s && istringEqual(s.get(),"Autosize") )
    {
      evapCooler->autosizeUfactorTimesAreaValueatDesignAirFlowRate();
    }
    else if( s && istringEqual(s.get(),"Autocalculate") )
    {
      evapCooler->autosizeUfactorTimesAreaValueatDesignAirFlowRate();
    }

    // DesignWaterFlowRate
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::DesignWaterFlowRate);
    s = workspaceObject.getString(EvaporativeFluidCooler_SingleSpeedFields::DesignWaterFlowRate);
    if( value )
    {
      evapCooler->setDesignWaterFlowRate(value.get());
    }
    else if( s && istringEqual(s.get(),"Autosize") )
    {
      evapCooler->autosizeDesignWaterFlowRate();
    }
    else if( s && istringEqual(s.get(),"Autocalculate") )
    {
      evapCooler->autosizeDesignWaterFlowRate();
    }

    // UserSpecifiedDesignCapacity
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::UserSpecifiedDesignCapacity);
    if( value )
    {
      evapCooler->setUserSpecifiedDesignCapacity(value.get());
    }

    // DesignEnteringWaterTemperature
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::DesignEnteringWaterTemperature);
    if( value )
    {
      evapCooler->setDesignEnteringWaterTemperature(value.get());
    }

    // DesignEnteringAirTemperature
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::DesignEnteringAirTemperature);
    if( value )
    {
      evapCooler->setDesignEnteringAirTemperature(value.get());
    }

    // DesignEnteringAirWetbulbTemperature
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::DesignEnteringAirWetbulbTemperature);
    if( value )
    {
      evapCooler->setDesignEnteringAirWetbulbTemperature(value.get());
    }

    // CapacityControl
    s = workspaceObject.getString(EvaporativeFluidCooler_SingleSpeedFields::CapacityControl);
    if( s )
    {
      evapCooler->setCapacityControl(s.get());
    }

    // SizingFactor
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::SizingFactor);
    if( value )
    {
      evapCooler->setSizingFactor(value.get());
    }

    // EvaporationLossMode
    s = workspaceObject.getString(EvaporativeFluidCooler_SingleSpeedFields::EvaporationLossMode);
    if( s )
    {
      evapCooler->setEvaporationLossMode(s.get());
    }

    // EvaporationLossFactor
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::EvaporationLossFactor);
    if( value )
    {
      evapCooler->setEvaporationLossFactor(value.get());
    }

    // DriftLossPercent
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::DriftLossPercent);
    if( value )
    {
      evapCooler->setDriftLossPercent(value.get());
    }

    // BlowdownCalculationMode
    s = workspaceObject.getString(EvaporativeFluidCooler_SingleSpeedFields::BlowdownCalculationMode);
    if( s )
    {
      evapCooler->setBlowdownCalculationMode(s.get());
    }

    // BlowdownConcentrationRatio
    value = workspaceObject.getDouble(EvaporativeFluidCooler_SingleSpeedFields::BlowdownConcentrationRatio);
    if( value )
    {
      evapCooler->setBlowdownConcentrationRatio(value.get());
    }

    boost::optional<WorkspaceObject> _schedule;

    // BlowdownMakeupWaterUsageScheduleName
    _schedule = workspaceObject.getTarget(EvaporativeFluidCooler_SingleSpeedFields::BlowdownMakeupWaterUsageScheduleName);
    if( _schedule )
    {
      boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(_schedule.get());
      if( mo )
      {
        if( boost::optional<Schedule> schedule = mo->optionalCast<Schedule>() )
        {
          evapCooler->setBlowdownMakeupWaterUsageSchedule(schedule.get());
        }
      }
    }

    return evapCooler.get();
  }
  else
  {
    LOG(Error, "Unknown error translating " << workspaceObject.briefDescription());

    return boost::none;
  }
}
OptionalModelObject ReverseTranslator::translateFanConstantVolume( const WorkspaceObject & workspaceObject )
{
OptionalModelObject result,temp;
  OptionalSchedule schedule;

  OptionalWorkspaceObject owo = workspaceObject.getTarget(Fan_ConstantVolumeFields::AvailabilityScheduleName);
  if(!owo)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't find Schedule: ");
    return result;
  }
  temp = translateAndMapWorkspaceObject( *owo);
  if(temp)
  {
    schedule = temp->optionalCast<Schedule>();
  }

  if( !schedule )
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.name().get()
             <<"Failed to convert iddObjects into model Objects. Maybe they do not exist in model yet");

    return result;
  }

  openstudio::model::FanConstantVolume fan( m_model, *schedule );
  OptionalString optS = workspaceObject.name();
  if(optS)
  {
    fan.setName(*optS);
  }
  //inlet and outlet nodes are set my the HVACAirLoop
  OptionalDouble d;
  d = workspaceObject.getDouble(openstudio::Fan_ConstantVolumeFields::FanTotalEfficiency);
  if(d)
  {
    fan.setFanEfficiency(*d);
  }
  d = workspaceObject.getDouble(openstudio::Fan_ConstantVolumeFields::PressureRise);
  if(d)
  {
    fan.setPressureRise(*d);
  }
  d = workspaceObject.getDouble(openstudio::Fan_ConstantVolumeFields::MaximumFlowRate);
  if(d)
  {
    fan.setMaximumFlowRate(*d);
  }
  d = workspaceObject.getDouble(openstudio::Fan_ConstantVolumeFields::MotorEfficiency);
  if(d)
  {
    fan.setMotorEfficiency(*d);
  }
  d = workspaceObject.getDouble(openstudio::Fan_ConstantVolumeFields::MotorInAirstreamFraction);
  if(d)
  {
    fan.setMotorInAirstreamFraction(*d);
  }

  optS=workspaceObject.getString(openstudio::Fan_ConstantVolumeFields::EndUseSubcategory);
  if(optS)
  {
    fan.setEndUseSubcategory(*optS);
  }

  result=fan;
  return result;
}
OptionalModelObject ReverseTranslator::translateSiteGroundReflectance( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::Site_GroundReflectance )
  {
     LOG(Error, "WorkspaceObject is not IddObjectType: Site_GroundReflectance");
     return boost::none;
  }

  SiteGroundReflectance mo = m_model.getUniqueModelObject<SiteGroundReflectance>();

  boost::optional<double> value = workspaceObject.getDouble(Site_GroundReflectanceFields::JanuaryGroundReflectance);
  if( value )
  {
    mo.setJanuaryGroundReflectance(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundReflectanceFields::FebruaryGroundReflectance);
  if( value )
  {
    mo.setFebruaryGroundReflectance(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundReflectanceFields::MarchGroundReflectance);
  if( value )
  {
    mo.setMarchGroundReflectance(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundReflectanceFields::AprilGroundReflectance);
  if( value )
  {
    mo.setAprilGroundReflectance(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundReflectanceFields::MayGroundReflectance);
  if( value )
  {
    mo.setMayGroundReflectance(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundReflectanceFields::JuneGroundReflectance);
  if( value )
  {
    mo.setJuneGroundReflectance(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundReflectanceFields::JulyGroundReflectance);
  if( value )
  {
    mo.setJulyGroundReflectance(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundReflectanceFields::AugustGroundReflectance);
  if( value )
  {
    mo.setAugustGroundReflectance(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundReflectanceFields::SeptemberGroundReflectance);
  if( value )
  {
    mo.setSeptemberGroundReflectance(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundReflectanceFields::OctoberGroundReflectance);
  if( value )
  {
    mo.setOctoberGroundReflectance(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundReflectanceFields::NovemberGroundReflectance);
  if( value )
  {
    mo.setNovemberGroundReflectance(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundReflectanceFields::DecemberGroundReflectance);
  if( value )
  {
    mo.setDecemberGroundReflectance(value.get());
  }

  return mo;

}
OptionalModelObject ReverseTranslator::translateAirTerminalSingleDuctConstantVolumeReheat( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::AirTerminal_SingleDuct_ConstantVolume_Reheat )
  {
     LOG(Error, "WorkspaceObject is not IddObjectType: AirTerminal_SingleDuct_ConstantVolume_Reheat");
     return boost::none;
  }

  boost::optional<WorkspaceObject> wo = workspaceObject.getTarget(AirTerminal_SingleDuct_ConstantVolume_ReheatFields::AvailabilityScheduleName);
  boost::optional<Schedule> schedule;
  boost::optional<HVACComponent> coil;
  boost::optional<AirTerminalSingleDuctConstantVolumeReheat> airTerminal;

  if( wo )
  {
    boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get());
    if( mo )
    {
      if( ! (schedule = mo->optionalCast<Schedule>()) )
      {
        LOG(Error, workspaceObject.briefDescription() << " does not have an associated availability schedule");

        return boost::none;
      }
    }
  }

  wo = workspaceObject.getTarget(AirTerminal_SingleDuct_ConstantVolume_ReheatFields::ReheatCoilName);
  if( wo )
  {
    boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get());
    if( mo )
    {
      if( ! coil )
      {
        //TODO: Maybe try to cast this to different types depending on ReheatCoilType
        coil = mo->optionalCast<CoilHeatingElectric>();
      }
    }
  }

  if( schedule && coil )
  {
    airTerminal = AirTerminalSingleDuctConstantVolumeReheat( m_model,schedule.get(),coil.get() );
  }

  if( airTerminal )
  {
    boost::optional<double> value;
    boost::optional<std::string> s = workspaceObject.getString(AirTerminal_SingleDuct_ConstantVolume_ReheatFields::Name);

    if( s )
    {
      airTerminal->setName(s.get());
    }

    // MaximumAirFlowRate
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_ConstantVolume_ReheatFields::MaximumAirFlowRate);
    if( value )
    {
      airTerminal->setMaximumAirFlowRate(value.get());
    }
    else
    {
      s = workspaceObject.getString(AirTerminal_SingleDuct_ConstantVolume_ReheatFields::MaximumAirFlowRate);
      if( s && istringEqual(s.get(),"Autosize") )
      {
        airTerminal->autosizeMaximumAirFlowRate();
      }
      else if( s && istringEqual(s.get(),"Autocalculate") )
      {
        airTerminal->autosizeMaximumAirFlowRate();
      }
    }
  
    // MaximumHotWaterorSteamFlowRate
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_ConstantVolume_ReheatFields::MaximumHotWaterorSteamFlowRate);
    if( value )
    {
      airTerminal->setMaximumHotWaterorSteamFlowRate(value.get());
    }
    else
    {
      s = workspaceObject.getString(AirTerminal_SingleDuct_ConstantVolume_ReheatFields::MaximumHotWaterorSteamFlowRate);
      if( s && istringEqual(s.get(),"Autosize") )
      {
        airTerminal->autosizeMaximumHotWaterorSteamFlowRate();
      }
      else if( s && istringEqual(s.get(),"Autocalculate") )
      {
        airTerminal->autosizeMaximumHotWaterorSteamFlowRate();
      }
    }

    // MinimumHotWaterorSteamFlowRate
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_ConstantVolume_ReheatFields::MinimumHotWaterorSteamFlowRate);
    if( value )
    {
      airTerminal->setMinimumHotWaterorSteamFlowRate(value.get());
    }

    // ConvergenceTolerance
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_ConstantVolume_ReheatFields::ConvergenceTolerance);
    if( value )
    {
      airTerminal->setConvergenceTolerance(value.get());
    }

    // MaximumReheatAirTemperature
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_ConstantVolume_ReheatFields::MaximumReheatAirTemperature);
    if( value )
    {
      airTerminal->setMaximumReheatAirTemperature(value.get());
    }

    return airTerminal.get();
  }
  else
  {
    LOG(Error, "Unknown error translating " << workspaceObject.briefDescription());

    return boost::none;
  }
}
boost::optional<ModelObject> ReverseTranslator::translateWindowMaterialGlazing( 
    const WorkspaceObject& workspaceObject)
{
  OptionalModelObject result;
  StandardGlazing standardGlazing(m_model);
  OptionalString optS = workspaceObject.name();
  if(optS) {
    standardGlazing.setName(*optS);
  }

  optS = workspaceObject.getString(WindowMaterial_GlazingFields::OpticalDataType);
  if (optS) {
    standardGlazing.setOpticalDataType(*optS);
  }

  optS = workspaceObject.getString(WindowMaterial_GlazingFields::WindowGlassSpectralDataSetName);
  if (optS) {
    standardGlazing.setWindowGlassSpectralDataSetName(*optS);
  }

  OptionalDouble d = workspaceObject.getDouble(WindowMaterial_GlazingFields::Thickness);
  if (d) {
    standardGlazing.setThickness(*d);
  }

  d = workspaceObject.getDouble(WindowMaterial_GlazingFields::SolarTransmittanceatNormalIncidence);
  if (d) {
    standardGlazing.setSolarTransmittance(*d);
  }

  d = workspaceObject.getDouble(WindowMaterial_GlazingFields::FrontSideSolarReflectanceatNormalIncidence);
  if (d) {
    standardGlazing.setFrontSideSolarReflectanceatNormalIncidence(*d);
  }

  d = workspaceObject.getDouble(WindowMaterial_GlazingFields::BackSideSolarReflectanceatNormalIncidence);
  if (d) {
    standardGlazing.setBackSideSolarReflectanceatNormalIncidence(*d);
  }

  d = workspaceObject.getDouble(WindowMaterial_GlazingFields::VisibleTransmittanceatNormalIncidence);
  if (d) {
    standardGlazing.setVisibleTransmittance(*d);
  }

  d = workspaceObject.getDouble(WindowMaterial_GlazingFields::FrontSideVisibleReflectanceatNormalIncidence);
  if (d) {
    standardGlazing.setFrontSideVisibleReflectanceatNormalIncidence(*d);
  }

  d = workspaceObject.getDouble(WindowMaterial_GlazingFields::BackSideVisibleReflectanceatNormalIncidence);
  if (d) {
    standardGlazing.setBackSideVisibleReflectanceatNormalIncidence(*d);
  }

  d = workspaceObject.getDouble(WindowMaterial_GlazingFields::InfraredTransmittanceatNormalIncidence);
  if (d) {
    standardGlazing.setInfraredTransmittance(*d);
  }

  d = workspaceObject.getDouble(WindowMaterial_GlazingFields::FrontSideInfraredHemisphericalEmissivity);
  if (d) {
    standardGlazing.setFrontSideInfraredHemisphericalEmissivity(*d);
  }

  d = workspaceObject.getDouble(WindowMaterial_GlazingFields::BackSideInfraredHemisphericalEmissivity);
  if (d) {
    standardGlazing.setBackSideInfraredHemisphericalEmissivity(*d);
  }

  d = workspaceObject.getDouble(WindowMaterial_GlazingFields::Conductivity);
  if (d) {
    standardGlazing.setThermalConductivity(*d);
  }

  d = workspaceObject.getDouble(WindowMaterial_GlazingFields::DirtCorrectionFactorforSolarandVisibleTransmittance);
  if (d) {
    standardGlazing.setDirtCorrectionFactorforSolarandVisibleTransmittance(*d);
  }  

  optS = workspaceObject.getString(WindowMaterial_GlazingFields::SolarDiffusing);
  if (optS) {
    std::string temp=*optS;
    boost::to_lower(temp);
    if( temp == "no") {
      standardGlazing.setSolarDiffusing(false);
    }
    else {
      standardGlazing.setSolarDiffusing(true);
    }
  }

  result = standardGlazing;
  return result;
}
OptionalModelObject ReverseTranslator::translateCoilCoolingDXSingleSpeed( const WorkspaceObject & workspaceObject )
{
OptionalModelObject result,temp;
  OptionalSchedule schedule;

  //get the Schedule
  OptionalWorkspaceObject owo = workspaceObject.getTarget(Coil_Cooling_DX_SingleSpeedFields::AvailabilityScheduleName);
  if(!owo)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't find Schedule.");
    return result;
  }
  temp = translateAndMapWorkspaceObject(*owo);
  if(temp)
  {
    schedule=temp->optionalCast<Schedule>();
  }

  if( !schedule  )
  {
    LOG(Error,"Error importing object: "
             << workspaceObject.briefDescription()
             <<"Failed to convert iddObject (schedule) into ModelObject. Maybe it does not exist in model yet");
    return result;
  }

  //collect the curves
  owo = workspaceObject.getTarget(Coil_Cooling_DX_SingleSpeedFields::TotalCoolingCapacityFunctionofTemperatureCurveName);
  if(!owo)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't find TotalCoolingCapacityFunctionOfTemperatureCurve.");
    return result;
  }
  if( owo->numSources() > 1 )
  {
    owo = owo->workspace().addObject(owo.get());
  }

  temp= translateAndMapWorkspaceObject( *owo );

  if(!temp)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't convert workspace curve into a model curve. ");
    return result;
  }
  boost::optional<Curve> tccfot = temp->optionalCast<Curve>();
  if( ! tccfot )
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " curve is wrong type. ");
    return result;
  }

  owo = workspaceObject.getTarget(Coil_Cooling_DX_SingleSpeedFields::EnergyInputRatioFunctionofTemperatureCurveName);
  if(!owo)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't find EnergyInputRatioFunctionofTemperatureCurveName.");
    return result;
  }
  if( owo->numSources() > 1 )
  {
    owo = owo->workspace().addObject(owo.get());
  }
  temp = translateAndMapWorkspaceObject( *owo );
  if(!temp)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't convert workspace curve into a model curve. ");
    return result;
  }
  boost::optional<Curve> eirfot = temp->optionalCast<Curve>();
  if( ! eirfot )
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " curve is wrong type. ");
    return result;
  }


  owo = workspaceObject.getTarget(Coil_Cooling_DX_SingleSpeedFields::TotalCoolingCapacityFunctionofFlowFractionCurveName);
  if(!owo)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't find TotalCoolingCapacityFunctionofFlowFractionCurveName.");
    return result;
  }
  if( owo->numSources() > 1 )
  {
    owo = owo->workspace().addObject(owo.get());
  }
  temp = translateAndMapWorkspaceObject( *owo );
  if(!temp)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't convert workspace curve into a model curve. ");
    return result;
  }
  boost::optional<Curve> tccfoff = temp->optionalCast<Curve>();
  if( ! tccfoff )
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " curve is wrong type. ");
    return result;
  }

  owo = workspaceObject.getTarget(Coil_Cooling_DX_SingleSpeedFields::EnergyInputRatioFunctionofFlowFractionCurveName);
  if(!owo)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't find EnergyInputRatioFunctionofFlowFractionCurveName.");
    return result;
  }
  if( owo->numSources() > 1 )
  {
    owo = owo->workspace().addObject(owo.get());
  }
  temp = translateAndMapWorkspaceObject( *owo );
  if(!temp)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't convert workspace curve into a model curve. ");
    return result;
  }
  boost::optional<Curve> eirfoff = temp->optionalCast<Curve>();
  if( ! eirfoff )
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " curve is wrong type. ");
    return result;
  }

  owo = workspaceObject.getTarget(Coil_Cooling_DX_SingleSpeedFields::PartLoadFractionCorrelationCurveName);
  if(!owo)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't find PartLoadFractionCorrelationCurveName.");
    return result;
  }
  if( owo->numSources() > 1 )
  {
    owo = owo->workspace().addObject(owo.get());
  }
  temp = translateAndMapWorkspaceObject( *owo );
  if(!temp)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't convert workspace curve into a model curve. ");
    return result;
  }
  boost::optional<Curve> plfcc = temp->optionalCast<Curve>();
  if( ! plfcc )
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " curve is wrong type. ");
    return result;
  }


  try {
    CoilCoolingDXSingleSpeed coil(m_model,
                                  *schedule,
                                  *tccfot,
                                  *tccfoff,
                                  *eirfot,
                                  *eirfoff,
                                  *plfcc);

    OptionalString optS = workspaceObject.name();
    if( optS )
    {
      coil.setName( *optS );
    }


    OptionalDouble d = workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::GrossRatedTotalCoolingCapacity);
    if(d)
    {
      coil.setRatedTotalCoolingCapacity(*d);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::GrossRatedSensibleHeatRatio);
    if(d)
    {
      coil.setRatedSensibleHeatRatio(*d);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::GrossRatedCoolingCOP);
    if(d)
    {
      coil.setRatedCOP(*d);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::RatedAirFlowRate);
    if(d)
    {
      coil.setRatedAirFlowRate(*d);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::RatedEvaporatorFanPowerPerVolumeFlowRate);
    if(d)
    {
      coil.setRatedEvaporatorFanPowerPerVolumeFlowRate(*d);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::NominalTimeforCondensateRemovaltoBegin);
    if(d)
    {
      coil.setNominalTimeForCondensateRemovalToBegin(*d);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::RatioofInitialMoistureEvaporationRateandSteadyStateLatentCapacity);
    if(d)
    {
      coil.setRatioOfInitialMoistureEvaporationRateAndSteadyStateLatentCapacity(*d);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::MaximumCyclingRate);
    if(d)
    {
      coil.setMaximumCyclingRate(*d);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::LatentCapacityTimeConstant);
    if(d)
    {
      coil.setLatentCapacityTimeConstant(*d);
    }

    optS=workspaceObject.getString(Coil_Cooling_DX_SingleSpeedFields::CondenserAirInletNodeName);
    if(optS)
    {
      coil.setCondenserAirInletNodeName(*optS);
    }

    optS = workspaceObject.getString(Coil_Cooling_DX_SingleSpeedFields::CondenserType);
    if(optS)
    {
      coil.setCondenserType(*optS);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::EvaporativeCondenserEffectiveness);
    if(d)
    {
      coil.setEvaporativeCondenserEffectiveness(*d);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::EvaporativeCondenserAirFlowRate);
    if(d)
    {
      coil.setEvaporativeCondenserAirFlowRate(*d);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::EvaporativeCondenserPumpRatedPowerConsumption);
    if(d)
    {
      coil.setEvaporativeCondenserPumpRatedPowerConsumption(*d);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::CrankcaseHeaterCapacity);
    if(d)
    {
      coil.setCrankcaseHeaterCapacity(*d);
    }

    d=workspaceObject.getDouble(Coil_Cooling_DX_SingleSpeedFields::MaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation);
    if(d)
    {
      coil.setMaximumOutdoorDryBulbTemperatureForCrankcaseHeaterOperation(*d);
    }

    result=coil;

  }
  catch (std::exception& e) {
    LOG(Error,"Could not reverse translate " << workspaceObject.briefDescription()
        << ", because " << e.what() << ".");
  }
  return result;
}
OptionalModelObject ReverseTranslator::translateEvaporativeCoolerDirectResearchSpecial( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::EvaporativeCooler_Direct_ResearchSpecial )
  {
     LOG(Error, "WorkspaceObject is not IddObjectType: EvaporativeCooler_Direct_ResearchSpecial");
     return boost::none;
  }

  boost::optional<Schedule> schedule;
  boost::optional<EvaporativeCoolerDirectResearchSpecial> mo;

  boost::optional<WorkspaceObject> wo = workspaceObject.getTarget(EvaporativeCooler_Direct_ResearchSpecialFields::AvailabilityScheduleName);
  if( wo )
  {
    boost::optional<ModelObject> mo2 = translateAndMapWorkspaceObject(wo.get());
    if( mo2 )
    {
      if( ! (schedule = mo2->optionalCast<Schedule>()) )
      {
        LOG(Error, workspaceObject.briefDescription() << " does not have an associated availability schedule");

        return boost::none;
      }
    }
  }

  if( schedule )
  {
    mo = EvaporativeCoolerDirectResearchSpecial(m_model,schedule.get());
  }

  if( mo )
  {
    boost::optional<std::string> s = workspaceObject.getString(EvaporativeCooler_Direct_ResearchSpecialFields::Name);
    if( s )
    {
      mo->setName(s.get());
    }

    boost::optional<double> value = workspaceObject.getDouble(EvaporativeCooler_Direct_ResearchSpecialFields::CoolerEffectiveness);
    if( s )
    {
      mo->setCoolerEffectiveness(value.get());
    }

    value = workspaceObject.getDouble(EvaporativeCooler_Direct_ResearchSpecialFields::RecirculatingWaterPumpPowerConsumption);
    if( value )
    {
      mo->setRecirculatingWaterPumpPowerConsumption(value.get());
    }

    value = workspaceObject.getDouble(EvaporativeCooler_Direct_ResearchSpecialFields::DriftLossFraction);
    if( value )
    {
      mo->setDriftLossFraction(value.get());
    }

    value = workspaceObject.getDouble(EvaporativeCooler_Direct_ResearchSpecialFields::BlowdownConcentrationRatio);
    if( value )
    {
      mo->setBlowdownConcentrationRatio(value.get());
    }

    return mo.get();
  }
  else
  {
    LOG(Error, "Unknown error translating " << workspaceObject.briefDescription());

    return boost::none;
  }
}
OptionalModelObject ReverseTranslator::translateSizingZone( const WorkspaceObject & workspaceObject )
{
    boost::optional<WorkspaceObject> target = workspaceObject.getTarget(Sizing_ZoneFields::ZoneorZoneListName);

    std::vector<ThermalZone> thermalZones;

    if( target ) {

        // just one thermal zone
        boost::optional<ModelObject> mo;
        if (target->iddObject().type() == IddObjectType::Zone) {
            mo = translateAndMapWorkspaceObject(target.get());
            if( mo ) {
                if( boost::optional<Space> space = mo->optionalCast<Space>() ) {
                    boost::optional<ThermalZone> thermalZone = space->thermalZone();
                    if (thermalZone) {
                        thermalZones.push_back(*thermalZone);
                    }
                }
            }
        } else if (target->iddObject().type() == IddObjectType::ZoneList) {

            // get all thermal zones in zone list
            for (const IdfExtensibleGroup& idfGroup : target->extensibleGroups()) {
                WorkspaceExtensibleGroup workspaceGroup = idfGroup.cast<WorkspaceExtensibleGroup>();
                OptionalWorkspaceObject owo = workspaceGroup.getTarget(0);
                if (owo) {
                    mo = translateAndMapWorkspaceObject(owo.get());
                    if( mo ) {
                        if( boost::optional<Space> space = mo->optionalCast<Space>() ) {
                            boost::optional<ThermalZone> thermalZone = space->thermalZone();
                            if (thermalZone) {
                                thermalZones.push_back(*thermalZone);
                            }
                        }
                    }
                }
            }
        }
    }

    if(thermalZones.empty())
    {
        LOG(Error, "Error importing object: "
            << workspaceObject.briefDescription()
            << " Can't find associated ThermalZone(s).");

        return boost::none;
    }

    boost::optional<ModelObject> result;
    for (ThermalZone thermalZone : thermalZones) {

        // sizing zone is constructed in thermal zone ctor
        openstudio::model::SizingZone sizingZone = thermalZone.sizingZone();

        // return first sizing zone
        if (!result) {
            result = sizingZone;
        }

        boost::optional<std::string> s;
        boost::optional<double> value;

        // ZoneCoolingDesignSupplyAirTemperature

        value = workspaceObject.getDouble(Sizing_ZoneFields::ZoneCoolingDesignSupplyAirTemperature);
        if( value )
        {
            sizingZone.setZoneCoolingDesignSupplyAirTemperature(value.get());
        }

        // ZoneHeatingDesignSupplyAirTemperature

        value = workspaceObject.getDouble(Sizing_ZoneFields::ZoneHeatingDesignSupplyAirTemperature);
        if( value )
        {
            sizingZone.setZoneHeatingDesignSupplyAirTemperature(value.get());
        }

        // ZoneCoolingDesignSupplyAirHumidityRatio

        value = workspaceObject.getDouble(Sizing_ZoneFields::ZoneHeatingDesignSupplyAirHumidityRatio);
        if( value )
        {
            sizingZone.setZoneHeatingDesignSupplyAirHumidityRatio(value.get());
        }

        // ZoneHeatingDesignSupplyAirHumidityRatio

        value = workspaceObject.getDouble(Sizing_ZoneFields::ZoneHeatingDesignSupplyAirHumidityRatio);
        if( value )
        {
            sizingZone.setZoneHeatingDesignSupplyAirHumidityRatio(value.get());
        }

        // DesignSpecificationOutdoorAirObjectName

        target = workspaceObject.getTarget(Sizing_ZoneFields::DesignSpecificationOutdoorAirObjectName);
        if (target) {
            OptionalModelObject mo = translateDesignSpecificationOutdoorAir(*target);
            if (mo) {
                if (mo->optionalCast<DesignSpecificationOutdoorAir>()) {
                    std::vector<Space> spaces = thermalZone.spaces();
                    OS_ASSERT(spaces.size() == 1);
                    spaces[0].setDesignSpecificationOutdoorAir(mo->cast<DesignSpecificationOutdoorAir>());
                }
            }
        }

        // ZoneHeatingSizingFactor

        value = workspaceObject.getDouble(Sizing_ZoneFields::ZoneHeatingSizingFactor);
        if( value )
        {
            sizingZone.setZoneHeatingSizingFactor(value.get());
        }

        // ZoneCoolingSizingFactor

        value = workspaceObject.getDouble(Sizing_ZoneFields::ZoneCoolingSizingFactor);
        if( value )
        {
            sizingZone.setZoneCoolingSizingFactor(value.get());
        }

        // CoolingDesignAirFlowMethod

        s = workspaceObject.getString(Sizing_ZoneFields::CoolingDesignAirFlowMethod);
        if( s )
        {
            sizingZone.setCoolingDesignAirFlowMethod(s.get());
        }

        // CoolingDesignAirFlowRate

        value = workspaceObject.getDouble(Sizing_ZoneFields::CoolingDesignAirFlowRate);
        if( value )
        {
            sizingZone.setCoolingDesignAirFlowRate(value.get());
        }

        // CoolingMinimumAirFlowperZoneFloorArea

        value = workspaceObject.getDouble(Sizing_ZoneFields::CoolingMinimumAirFlowperZoneFloorArea);
        if( value )
        {
            sizingZone.setCoolingMinimumAirFlowperZoneFloorArea(value.get());
        }

        // CoolingMinimumAirFlow

        value = workspaceObject.getDouble(Sizing_ZoneFields::CoolingMinimumAirFlow);
        if( value )
        {
            sizingZone.setCoolingMinimumAirFlow(value.get());
        }

        // CoolingMinimumAirFlowFraction

        value = workspaceObject.getDouble(Sizing_ZoneFields::CoolingMinimumAirFlowFraction);
        if( value )
        {
            sizingZone.setCoolingMinimumAirFlowFraction(value.get());
        }

        // HeatingDesignAirFlowMethod

        s = workspaceObject.getString(Sizing_ZoneFields::HeatingDesignAirFlowMethod);
        if( s )
        {
            sizingZone.setHeatingDesignAirFlowMethod(s.get());
        }

        // HeatingDesignAirFlowRate

        value = workspaceObject.getDouble(Sizing_ZoneFields::HeatingDesignAirFlowRate);
        if( value )
        {
            sizingZone.setHeatingDesignAirFlowRate(value.get());
        }

        // HeatingMaximumAirFlowperZoneFloorArea

        value = workspaceObject.getDouble(Sizing_ZoneFields::HeatingMaximumAirFlowperZoneFloorArea);
        if( value )
        {
            sizingZone.setHeatingMaximumAirFlowperZoneFloorArea(value.get());
        }

        // HeatingMaximumAirFlow

        value = workspaceObject.getDouble(Sizing_ZoneFields::HeatingMaximumAirFlow);
        if( value )
        {
            sizingZone.setHeatingMaximumAirFlow(value.get());
        }

        // HeatingMaximumAirFlowFraction

        value = workspaceObject.getDouble(Sizing_ZoneFields::HeatingMaximumAirFlowFraction);
        if( value )
        {
            sizingZone.setHeatingMaximumAirFlowFraction(value.get());
        }

        //DesignSpecification_ZoneAirDistribution

        boost::optional<WorkspaceObject> _designSpecification
            = workspaceObject.getTarget(Sizing_ZoneFields::DesignSpecificationZoneAirDistributionObjectName);

        if( _designSpecification )
        {
            // ZoneAirDistributionEffectivenessinCoolingMode

            value = _designSpecification->getDouble(
                        DesignSpecification_ZoneAirDistributionFields::ZoneAirDistributionEffectivenessinCoolingMode);
            if( value )
            {
                sizingZone.setDesignZoneAirDistributionEffectivenessinCoolingMode(value.get());
            }

            // ZoneAirDistributionEffectivenessinHeatingMode

            value = _designSpecification->getDouble(
                        DesignSpecification_ZoneAirDistributionFields::ZoneAirDistributionEffectivenessinHeatingMode);
            if( value )
            {
                sizingZone.setDesignZoneAirDistributionEffectivenessinHeatingMode(value.get());
            }
        }

    }

    return result;
}
OptionalModelObject ReverseTranslator::translateZoneInfiltrationDesignFlowRate( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::ZoneInfiltration_DesignFlowRate ){
    LOG(Error, "WorkspaceObject is not IddObjectType: ZoneInfiltration:DesignFlowRate");
    return boost::none;
  }

  openstudio::model::SpaceInfiltrationDesignFlowRate infiltration(m_model);
  
  OptionalString s = workspaceObject.name();
  if(s){
    infiltration.setName(*s);
  }

  OptionalWorkspaceObject target = workspaceObject.getTarget(openstudio::ZoneInfiltration_DesignFlowRateFields::ZoneorZoneListName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<Space>()){
        infiltration.setSpace(modelObject->cast<Space>());
      }else if (modelObject->optionalCast<SpaceType>()){
        infiltration.setSpaceType(modelObject->cast<SpaceType>());
      }
    }
  }

  target = workspaceObject.getTarget(openstudio::ZoneInfiltration_DesignFlowRateFields::ScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (OptionalSchedule intermediate = modelObject->optionalCast<Schedule>()){
        Schedule schedule(*intermediate);
        infiltration.setSchedule(schedule);
      }
    }
  }

  s = workspaceObject.getString(openstudio::ZoneInfiltration_DesignFlowRateFields::DesignFlowRateCalculationMethod, true);
  OS_ASSERT(s);

  OptionalDouble d;
  if (istringEqual("Flow/Zone", *s)){
    d = workspaceObject.getDouble(openstudio::ZoneInfiltration_DesignFlowRateFields::DesignFlowRate);
    if (d){
      infiltration.setDesignFlowRate(*d);
    }else{
      LOG(Error, "Flow/Zone value not found for workspace object " << workspaceObject);
    }
  }else if(istringEqual("Flow/Area", *s)){
    d = workspaceObject.getDouble(openstudio::ZoneInfiltration_DesignFlowRateFields::FlowperZoneFloorArea);
    if (d){
      infiltration.setFlowperSpaceFloorArea(*d);
    }else{
      LOG(Error, "Flow/Area value not found for workspace object " << workspaceObject);
    }
  }else if(istringEqual("Flow/ExteriorArea", *s)){
    d = workspaceObject.getDouble(openstudio::ZoneInfiltration_DesignFlowRateFields::FlowperExteriorSurfaceArea);
    if (d){
      infiltration.setFlowperExteriorSurfaceArea(*d);
    }else{
      LOG(Error, "Flow/ExteriorArea value not found for workspace object " << workspaceObject);
    }
  }else if(istringEqual("Flow/ExteriorWallArea", *s)){
    d = workspaceObject.getDouble(openstudio::ZoneInfiltration_DesignFlowRateFields::FlowperExteriorSurfaceArea);
    if (d){
      infiltration.setFlowperExteriorWallArea(*d);
    }else{
      LOG(Error, "Flow/ExteriorWallArea value not found for workspace object " << workspaceObject);
    }
  }else if(istringEqual("AirChanges/Hour", *s)){
    d = workspaceObject.getDouble(openstudio::ZoneInfiltration_DesignFlowRateFields::AirChangesperHour);
    if (d){
      infiltration.setAirChangesperHour(*d);
    }else{
      LOG(Error, "AirChanges/Hour value not found for workspace object " << workspaceObject);
    }
  }else{
    LOG(Error, "Unknown DesignLevelCalculationMethod value for workspace object" << workspaceObject);
  }

  d = workspaceObject.getDouble(openstudio::ZoneInfiltration_DesignFlowRateFields::ConstantTermCoefficient);
  if (d){
    infiltration.setConstantTermCoefficient(*d);
  }

  d = workspaceObject.getDouble(openstudio::ZoneInfiltration_DesignFlowRateFields::TemperatureTermCoefficient);
  if (d){
    infiltration.setTemperatureTermCoefficient(*d);
  }

  d = workspaceObject.getDouble(openstudio::ZoneInfiltration_DesignFlowRateFields::VelocityTermCoefficient);
  if (d){
    infiltration.setVelocityTermCoefficient(*d);
  }

  d = workspaceObject.getDouble(openstudio::ZoneInfiltration_DesignFlowRateFields::VelocitySquaredTermCoefficient);
  if (d){
    infiltration.setVelocitySquaredTermCoefficient(*d);
  }

  return infiltration;
}
OptionalModelObject ReverseTranslator::translateRefrigerationCompressor( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::Refrigeration_Compressor )
  {
     LOG(Error, "WorkspaceObject is not IddObjectType: Refrigeration_Compressor");
     return boost::none;
  }

  boost::optional<RefrigerationCompressor> refrigerationCompressor = RefrigerationCompressor( m_model );
  boost::optional<WorkspaceObject> wo;

  if( refrigerationCompressor )
  {
    boost::optional<double> value;
    boost::optional<std::string> s = workspaceObject.getString(Refrigeration_CompressorFields::Name);

// Name
    if( s )
    {
      refrigerationCompressor->setName(s.get());
    }

// RefrigerationCompressorPowerCurveName
    if( (wo = workspaceObject.getTarget(Refrigeration_CompressorFields::RefrigerationCompressorPowerCurveName)) )
    {
      if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get()) )
      {
        if( boost::optional<CurveBicubic> curve = mo->optionalCast<CurveBicubic>() )
        {
          refrigerationCompressor->setRefrigerationCompressorPowerCurve(curve.get());
        }
      }
    }
// RefrigerationCompressorCapacityCurveName
    if( (wo = workspaceObject.getTarget(Refrigeration_CompressorFields::RefrigerationCompressorCapacityCurveName)) )
    {
      if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get()) )
      {
        if( boost::optional<CurveBicubic> curve = mo->optionalCast<CurveBicubic>() )
        {
          refrigerationCompressor->setRefrigerationCompressorCapacityCurve(curve.get());
        }
      }
    }
// RatedSuperheat
    value = workspaceObject.getDouble(Refrigeration_CompressorFields::RatedSuperheat);
    if( value )
    {
      refrigerationCompressor->setRatedSuperheat(value.get());
    }
// RatedReturnGasTemperature
    value = workspaceObject.getDouble(Refrigeration_CompressorFields::RatedReturnGasTemperature);
    if( value )
    {
      refrigerationCompressor->setRatedReturnGasTemperature(value.get());
    }
// RatedLiquidTemperature
    value = workspaceObject.getDouble(Refrigeration_CompressorFields::RatedLiquidTemperature);
    if( value )
    {
      refrigerationCompressor->setRatedLiquidTemperature(value.get());
    }
// RatedSubcooling
    value = workspaceObject.getDouble(Refrigeration_CompressorFields::RatedSubcooling);
    if( value )
    {
      refrigerationCompressor->setRatedSubcooling(value.get());
    }
// EndUseSubcategory
    s = workspaceObject.getString(Refrigeration_CompressorFields::EndUseSubcategory);
    if( s )
    {
      refrigerationCompressor->setEndUseSubcategory(s.get());
    }
// ModeofOperation
// TranscriticalCompressorPowerCurveName
    if( (wo = workspaceObject.getTarget(Refrigeration_CompressorFields::TranscriticalCompressorPowerCurveName)) )
    {
      if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get()) )
      {
        if( boost::optional<CurveBicubic> curve = mo->optionalCast<CurveBicubic>() )
        {
          refrigerationCompressor->setTranscriticalCompressorPowerCurve(curve.get());
        }
      }
    }
// TranscriticalCompressorCapacityCurveName
    if( (wo = workspaceObject.getTarget(Refrigeration_CompressorFields::TranscriticalCompressorCapacityCurveName)) )
    {
      if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get()) )
      {
        if( boost::optional<CurveBicubic> curve = mo->optionalCast<CurveBicubic>() )
        {
          refrigerationCompressor->setTranscriticalCompressorCapacityCurve(curve.get());
        }
      }
    }

    return refrigerationCompressor.get();
  }
  else
  {
    LOG(Error, "Unknown error translating " << workspaceObject.briefDescription());

    return boost::none;
  }
}
boost::optional<ModelObject> ReverseTranslator::translateCurveTriquadratic( 
    const WorkspaceObject& workspaceObject)
{
  CurveTriquadratic curve(m_model);

  OptionalString s;
  OptionalDouble d;
  
  if ((s = workspaceObject.name())) {
    curve.setName(*s);
  }

  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient1Constant))) {
    curve.setCoefficient1Constant(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient2x_POW_2))) {
    curve.setCoefficient2xPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient3x))) {
    curve.setCoefficient3x(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient4y_POW_2))) {
    curve.setCoefficient4yPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient5y))) {
    curve.setCoefficient5y(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient6z_POW_2))) {
    curve.setCoefficient6zPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient7z))) {
    curve.setCoefficient7z(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient8x_POW_2_TIMES_y_POW_2))) {
    curve.setCoefficient8xPOW2TIMESYPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient9x_TIMES_y))) {
    curve.setCoefficient9xTIMESY(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient10x_TIMES_y_POW_2))) {
    curve.setCoefficient10xTIMESYPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient11x_POW_2_TIMES_y))) {
    curve.setCoefficient11xPOW2TIMESY(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient12x_POW_2_TIMES_z_POW_2))) {
    curve.setCoefficient12xPOW2TIMESZPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient13x_TIMES_z))) {
    curve.setCoefficient13xTIMESZ(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient14x_TIMES_z_POW_2))) {
    curve.setCoefficient14xTIMESZPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient15x_POW_2_TIMES_z))) {
    curve.setCoefficient15xPOW2TIMESZ(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient16y_POW_2_TIMES_z_POW_2))) {
    curve.setCoefficient16yPOW2TIMESZPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient17y_TIMES_z))) {
    curve.setCoefficient17yTIMESZ(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient18y_TIMES_z_POW_2))) {
    curve.setCoefficient18yTIMESZPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient19y_POW_2_TIMES_z))) {
    curve.setCoefficient19yPOW2TIMESZ(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient20x_POW_2_TIMES_y_POW_2_TIMES_z_POW_2))) {
    curve.setCoefficient20xPOW2TIMESYPOW2TIMESZPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient21x_POW_2_TIMES_y_POW_2_TIMES_z))) {
    curve.setCoefficient21xPOW2TIMESYPOW2TIMESZ(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient22x_POW_2_TIMES_y_TIMES_z_POW_2))) {
    curve.setCoefficient22xPOW2TIMESYTIMESZPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient23x_TIMES_y_POW_2_TIMES_z_POW_2))) {
    curve.setCoefficient23xTIMESYPOW2TIMESZPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient24x_POW_2_TIMES_y_TIMES_z))) {
    curve.setCoefficient24xPOW2TIMESYTIMESZ(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient25x_TIMES_y_POW_2_TIMES_z))) {
    curve.setCoefficient25xTIMESYPOW2TIMESZ(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient26x_TIMES_y_TIMES_z_POW_2))) {
    curve.setCoefficient26xTIMESYTIMESZPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::Coefficient27x_TIMES_y_TIMES_z))) {
    curve.setCoefficient27xTIMESYTIMESZ(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::MinimumValueofx))) {
    curve.setMinimumValueofx(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::MaximumValueofx))) {
    curve.setMaximumValueofx(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::MinimumValueofy))) {
    curve.setMinimumValueofy(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::MaximumValueofy))) {
    curve.setMaximumValueofy(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::MinimumValueofz))) {
    curve.setMinimumValueofz(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::MaximumValueofz))) {
    curve.setMaximumValueofz(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::MinimumCurveOutput))) {
    curve.setMinimumCurveOutput(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_TriquadraticFields::MaximumCurveOutput))) {
    curve.setMaximumCurveOutput(*d);
  }
  if ((s = workspaceObject.getString(Curve_TriquadraticFields::InputUnitTypeforX,false,true))) {
    curve.setInputUnitTypeforX(*s);
  }
  if ((s = workspaceObject.getString(Curve_TriquadraticFields::InputUnitTypeforY,false,true))) {
    curve.setInputUnitTypeforY(*s);
  }
  if ((s = workspaceObject.getString(Curve_TriquadraticFields::InputUnitTypeforZ,false,true))) {
    curve.setInputUnitTypeforZ(*s);
  }
  if ((s = workspaceObject.getString(Curve_TriquadraticFields::OutputUnitType,false,true))) {
    curve.setOutputUnitType(*s);
  }

  return curve;
}
OptionalModelObject ReverseTranslator::translateScheduleTypeLimits( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::ScheduleTypeLimits )
  {
    LOG(Error, "WorkspaceObject is not IddObjectType: ScheduleTypeLimits");
    return boost::none;
  }

  openstudio::model::ScheduleTypeLimits scheduleTypeLimits( m_model );
  OptionalString s = workspaceObject.name();
  if (s) {
    if ((workspaceObject.numFields() == 1u) &&
        (istringEqual(*s,"Any Number") || istringEqual(*s,"Number")))
    {
      // Do not translate ScheduleTypeLimits called "Any Number" or "Number" and
      // with no other fields specified. Instead, let ModelObjects assign more
      // meaningful limits.
      LOG(Info,"The energyplus::ReverseTranslator throws out all 'Any Number' ScheduleTypeLimits "
          << "to leave the OpenStudio model free to apply the appropriate units and limits.");
      return boost::none;
    }
    scheduleTypeLimits.setName(*s);
  }

  OptionalDouble d = workspaceObject.getDouble(ScheduleTypeLimitsFields::LowerLimitValue);
  if (d) {
    scheduleTypeLimits.setLowerLimitValue(*d);
  }

  d = workspaceObject.getDouble(ScheduleTypeLimitsFields::UpperLimitValue);
  if (d) {
    scheduleTypeLimits.setUpperLimitValue(*d);
  }

  s = workspaceObject.getString(ScheduleTypeLimitsFields::NumericType);
  if (s) {
    scheduleTypeLimits.setNumericType(*s);
  }

  s = workspaceObject.getString(ScheduleTypeLimitsFields::UnitType);
  if (s) {
    scheduleTypeLimits.setUnitType(*s);
  }
  else {
    bool test;
    // Attempt to default based on name (many EnergyPlus files do not have this field filled out).
    std::string name = scheduleTypeLimits.name().get();
    if (boost::regex_search(name,boost::regex("[Tt][Ee][Mm][Pp]"))) {
      if (boost::regex_search(name,boost::regex("[Dd][Ee][Ll][Tt][Aa]"))) {
        test = scheduleTypeLimits.setUnitType("DeltaTemperature");
        BOOST_ASSERT(test);
      }
      else {
        test = scheduleTypeLimits.setUnitType("Temperature");
        BOOST_ASSERT(test);
      }
    }
    else if (boost::regex_search(name,boost::regex("[Oo][Nn]")) &&
             boost::regex_search(name,boost::regex("[Oo][Ff][Ff]")))
    {
      test = scheduleTypeLimits.setUnitType("Availability");
      BOOST_ASSERT(test);
    }
    else if (boost::regex_search(name,boost::regex("[Cc][Oo][Nn][Tt][Rr][Oo][Ll]"))) {
      test = scheduleTypeLimits.setUnitType("ControlMode");
      BOOST_ASSERT(test);
    }
  }

  return scheduleTypeLimits;
}
boost::optional<model::ModelObject> ReverseTranslator::translateExteriorLights(
    const WorkspaceObject& workspaceObject)
{
  if (workspaceObject.iddObject().type() != IddObjectType::Exterior_Lights) {
    LOG(Error,"WorkspaceObject " << workspaceObject.briefDescription()
        << " is not of IddObjectType::Exterior_Lights.");
    return boost::none;
  }

  model::ExteriorLightsDefinition definition(m_model);

  OptionalString s;
  OptionalDouble d;

  if ((s = workspaceObject.name())) {
    definition.setName(*s + " Definition");
  }

  if ((d = workspaceObject.getDouble(Exterior_LightsFields::DesignLevel))){
    definition.setDesignLevel(*d);
  }

  model::OptionalExteriorLights exteriorLights;
  model::OptionalSchedule schedule;

  if (OptionalWorkspaceObject target = workspaceObject.getTarget(Exterior_LightsFields::ScheduleName))
  {
    if (model::OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target)) {
      schedule = modelObject->optionalCast<model::Schedule>();
    }
  }

  if (schedule) {
    try {
      exteriorLights = model::ExteriorLights(definition,*schedule);
    }
    catch (std::exception& e) {
      LOG(Warn,"Could not reverse translate " << workspaceObject.briefDescription()
          << " in full, because " << e.what() << ".");
    }
  }
  if (!exteriorLights) {
    exteriorLights = model::ExteriorLights(definition);
  }

  OS_ASSERT(exteriorLights);

  if ((s = workspaceObject.name())) {
    exteriorLights->setName(*s);
  }

  if ((s = workspaceObject.getString(Exterior_LightsFields::ControlOption,false,true))) {
    exteriorLights->setControlOption(*s);
  }

  if ((s = workspaceObject.getString(Exterior_LightsFields::EndUseSubcategory,false,true))) {
    exteriorLights->setEndUseSubcategory(*s);
  }

  return *exteriorLights;
}
OptionalModelObject ReverseTranslator::translateDaylightingControls( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::Daylighting_Controls ){
    LOG(Error, "WorkspaceObject is not IddObjectType: Daylighting:Controls");
    return boost::none;
  }

  DaylightingControl daylightingControl(m_model);

  OptionalThermalZone thermalZone;
  OptionalSpace space;
  OptionalWorkspaceObject target = workspaceObject.getTarget(Daylighting_ControlsFields::ZoneName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<Space>()){
        space = modelObject->cast<Space>();
        thermalZone = space->thermalZone();
      }
    }
  }

  if (space){
    daylightingControl.setSpace(*space);
  }

  if (thermalZone){
    thermalZone->setPrimaryDaylightingControl(daylightingControl);
  }

  OptionalDouble d = workspaceObject.getDouble(Daylighting_ControlsFields::XCoordinateofFirstReferencePoint);
  if (d){
    daylightingControl.setPositionXCoordinate(*d);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::YCoordinateofFirstReferencePoint);
  if (d){
    daylightingControl.setPositionYCoordinate(*d);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::ZCoordinateofFirstReferencePoint);
  if (d){
    daylightingControl.setPositionZCoordinate(*d);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::FractionofZoneControlledbyFirstReferencePoint);
  if (d && thermalZone){
    thermalZone->setFractionofZoneControlledbyPrimaryDaylightingControl(*d);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::IlluminanceSetpointatFirstReferencePoint);
  if (d){
    daylightingControl.setIlluminanceSetpoint(*d);
  }

  OptionalInt i = workspaceObject.getInt(Daylighting_ControlsFields::LightingControlType);
  if (i){
    switch (*i){
      case 1:
        daylightingControl.setLightingControlType("Continuous");
        break;
      case 2:
        daylightingControl.setLightingControlType("Stepped");
        break;
      case 3:
        daylightingControl.setLightingControlType("Continuous/Off");
        break;
      default:
        ;
    }
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::GlareCalculationAzimuthAngleofViewDirectionClockwisefromZoneyAxis);
  if (d){
    daylightingControl.setThetaRotationAroundYAxis( -degToRad(*d) );
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::MaximumAllowableDiscomfortGlareIndex);
  if (d){
    daylightingControl.setMaximumAllowableDiscomfortGlareIndex(*d);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::MinimumInputPowerFractionforContinuousDimmingControl);
  if (d){
    daylightingControl.setMinimumInputPowerFractionforContinuousDimmingControl(*d);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::MinimumLightOutputFractionforContinuousDimmingControl);
  if (d){
    daylightingControl.setMinimumLightOutputFractionforContinuousDimmingControl(*d);
  }

  i = workspaceObject.getInt(Daylighting_ControlsFields::NumberofSteppedControlSteps);
  if (i){
    daylightingControl.setNumberofSteppedControlSteps(*i);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::ProbabilityLightingwillbeResetWhenNeededinManualSteppedControl);
  if (d){
    daylightingControl.setProbabilityLightingwillbeResetWhenNeededinManualSteppedControl(*d);
  }

  i = workspaceObject.getInt(Daylighting_ControlsFields::TotalDaylightingReferencePoints);
  if (i){
    if (*i == 1){
      return daylightingControl;
    }
  }else{
    return daylightingControl;
  }

  DaylightingControl daylightingControl2(m_model);

  if (space){
    daylightingControl2.setSpace(*space);
  }

  if (thermalZone){
    thermalZone->setSecondaryDaylightingControl(daylightingControl2);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::XCoordinateofSecondReferencePoint);
  if (d){
    daylightingControl2.setPositionXCoordinate(*d);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::YCoordinateofSecondReferencePoint);
  if (d){
    daylightingControl2.setPositionYCoordinate(*d);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::ZCoordinateofSecondReferencePoint);
  if (d){
    daylightingControl2.setPositionZCoordinate(*d);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::FractionofZoneControlledbySecondReferencePoint);
  if (d && thermalZone){
    thermalZone->setFractionofZoneControlledbySecondaryDaylightingControl(*d);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::IlluminanceSetpointatSecondReferencePoint);
  if (d){
    daylightingControl2.setIlluminanceSetpoint(*d);
  }

  i = workspaceObject.getInt(Daylighting_ControlsFields::LightingControlType);
  if (i){
    switch (*i){
      case 1:
        daylightingControl2.setLightingControlType("Continuous");
        break;
      case 2:
        daylightingControl2.setLightingControlType("Stepped");
        break;
      case 3:
        daylightingControl2.setLightingControlType("Continuous/Off");
        break;
      default:
        ;
    }
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::GlareCalculationAzimuthAngleofViewDirectionClockwisefromZoneyAxis);
  if (d){
    daylightingControl2.setThetaRotationAroundYAxis( -degToRad(*d) );
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::MaximumAllowableDiscomfortGlareIndex);
  if (d){
    daylightingControl2.setMaximumAllowableDiscomfortGlareIndex(*d);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::MinimumInputPowerFractionforContinuousDimmingControl);
  if (d){
    daylightingControl2.setMinimumInputPowerFractionforContinuousDimmingControl(*d);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::MinimumLightOutputFractionforContinuousDimmingControl);
  if (d){
    daylightingControl2.setMinimumLightOutputFractionforContinuousDimmingControl(*d);
  }

  i = workspaceObject.getInt(Daylighting_ControlsFields::NumberofSteppedControlSteps);
  if (i){
    daylightingControl2.setNumberofSteppedControlSteps(*i);
  }

  d = workspaceObject.getDouble(Daylighting_ControlsFields::ProbabilityLightingwillbeResetWhenNeededinManualSteppedControl);
  if (d){
    daylightingControl2.setProbabilityLightingwillbeResetWhenNeededinManualSteppedControl(*d);
  }

  return daylightingControl;
}
OptionalModelObject ReverseTranslator::translateOutputIlluminanceMap( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::Output_IlluminanceMap ){
    LOG(Error, "WorkspaceObject is not IddObjectType: Output:IlluminanceMap");
    return boost::none;
  }

  IlluminanceMap illuminanceMap( m_model );

  OptionalString s = workspaceObject.name();
  if (s){
    illuminanceMap.setName(*s);
  }

  OptionalWorkspaceObject target = workspaceObject.getTarget(Output_IlluminanceMapFields::ZoneName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<Space>()){
        illuminanceMap.setSpace(modelObject->cast<Space>());
      }
    }
  }

  OptionalDouble d = workspaceObject.getDouble(Output_IlluminanceMapFields::Zheight);
  if (d){
    illuminanceMap.setOriginZCoordinate(*d);
  }

  d = workspaceObject.getDouble(Output_IlluminanceMapFields::XMinimumCoordinate);
  if (d){
    illuminanceMap.setOriginXCoordinate(*d);

    OptionalDouble maxX = workspaceObject.getDouble(Output_IlluminanceMapFields::XMaximumCoordinate);
    if (maxX){
      illuminanceMap.setXLength(*maxX - *d);
    }
  }

  OptionalInt i = workspaceObject.getInt(Output_IlluminanceMapFields::NumberofXGridPoints);
  if (i){
    illuminanceMap.setNumberofXGridPoints(*i);
  }

  d = workspaceObject.getDouble(Output_IlluminanceMapFields::YMinimumCoordinate);
  if (d){
    illuminanceMap.setOriginYCoordinate(*d);

    OptionalDouble maxY = workspaceObject.getDouble(Output_IlluminanceMapFields::YMaximumCoordinate);
    if (maxY){
      illuminanceMap.setYLength(*maxY - *d);
    }
  }

  i = workspaceObject.getInt(Output_IlluminanceMapFields::NumberofYGridPoints);
  if (i){
    illuminanceMap.setNumberofYGridPoints(*i);
  }

  return illuminanceMap;
}
OptionalModelObject ReverseTranslator::translateZoneMixing( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::ZoneMixing ){
    LOG(Error, "WorkspaceObject is not IddObjectType: ZoneMixing");
    return boost::none;
  }

  OptionalWorkspaceObject target = workspaceObject.getTarget(openstudio::ZoneMixingFields::ZoneName);
  OptionalThermalZone zone;
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      zone = modelObject->optionalCast<ThermalZone>();
    }
  }
  
  if (!zone){
    return boost::none;
  }

  openstudio::model::ZoneMixing mixing(*zone);
  
  OptionalString s = workspaceObject.name();
  if(s){
    mixing.setName(*s);
  }

  target = workspaceObject.getTarget(openstudio::ZoneMixingFields::ScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (auto s = modelObject->optionalCast<Schedule>()){
        mixing.setSchedule(s.get());
      }
    }
  }

  s = workspaceObject.getString(openstudio::ZoneMixingFields::DesignFlowRateCalculationMethod, true);
  OS_ASSERT(s);

  OptionalDouble d;
  if (istringEqual("Flow/Zone", *s)){
    d = workspaceObject.getDouble(openstudio::ZoneMixingFields::DesignFlowRate);
    if (d){
      mixing.setDesignFlowRate(*d);
    } else{
      LOG(Error, "Flow/Zone value not found for workspace object " << workspaceObject);
    }
  } else if (istringEqual("Flow/Area", *s)){
    d = workspaceObject.getDouble(openstudio::ZoneMixingFields::FlowRateperZoneFloorArea);
    if (d){
      mixing.setFlowRateperZoneFloorArea(*d);
    } else{
      LOG(Error, "Flow/Area value not found for workspace object " << workspaceObject);
    }
  } else if (istringEqual("Flow/Person", *s)){
    d = workspaceObject.getDouble(openstudio::ZoneMixingFields::FlowRateperPerson);
    if (d){
      mixing.setFlowRateperPerson(*d);
    } else{
      LOG(Error, "Flow/Person value not found for workspace object " << workspaceObject);
    }
  } else if (istringEqual("AirChanges/Hour", *s)){
    d = workspaceObject.getDouble(openstudio::ZoneMixingFields::AirChangesperHour);
    if (d){
      mixing.setAirChangesperHour(*d);
    } else{
      LOG(Error, "AirChanges/Hour value not found for workspace object " << workspaceObject);
    }
  } else{
    LOG(Error, "Unknown DesignFlowRateCalculationMethod value for workspace object" << workspaceObject);
  }

  target = workspaceObject.getTarget(openstudio::ZoneMixingFields::SourceZoneName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ThermalZone>()){
        mixing.setSourceZone(modelObject->cast<ThermalZone>());
      }
    }
  }

  d = workspaceObject.getDouble(openstudio::ZoneMixingFields::DeltaTemperature);
  if (d){
    mixing.setDeltaTemperature(*d);
  }

  target = workspaceObject.getTarget(openstudio::ZoneMixingFields::DeltaTemperatureScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (auto s = modelObject->optionalCast<Schedule>()){
        mixing.setDeltaTemperatureSchedule(s.get());
      }
    }
  }

  target = workspaceObject.getTarget(openstudio::ZoneMixingFields::MinimumZoneTemperatureScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (auto s = modelObject->optionalCast<Schedule>()){
        mixing.setMinimumZoneTemperatureSchedule(s.get());
      }
    }
  }

  target = workspaceObject.getTarget(openstudio::ZoneMixingFields::MaximumZoneTemperatureScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (auto s = modelObject->optionalCast<Schedule>()){
        mixing.setMaximumZoneTemperatureSchedule(s.get());
      }
    }
  }

  target = workspaceObject.getTarget(openstudio::ZoneMixingFields::MinimumSourceZoneTemperatureScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (auto s = modelObject->optionalCast<Schedule>()){
        mixing.setMinimumSourceZoneTemperatureSchedule(s.get());
      }
    }
  }

  target = workspaceObject.getTarget(openstudio::ZoneMixingFields::MaximumSourceZoneTemperatureScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (auto s = modelObject->optionalCast<Schedule>()){
        mixing.setMaximumSourceZoneTemperatureSchedule(s.get());
      }
    }
  }

  target = workspaceObject.getTarget(openstudio::ZoneMixingFields::MinimumOutdoorTemperatureScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (auto s = modelObject->optionalCast<Schedule>()){
        mixing.setMinimumOutdoorTemperatureSchedule(s.get());
      }
    }
  }

  target = workspaceObject.getTarget(openstudio::ZoneMixingFields::MaximumOutdoorTemperatureScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (auto s = modelObject->optionalCast<Schedule>()){
        mixing.setMaximumOutdoorTemperatureSchedule(s.get());
      }
    }
  }

  return mixing;
}
Exemplo n.º 19
0
OptionalModelObject ReverseTranslator::translateZone( const WorkspaceObject & workspaceObject )
{
 if( workspaceObject.iddObject().type() != IddObjectType::Zone ){
    LOG(Error, "WorkspaceObject is not IddObjectType: Zone");
    return boost::none;
  }

  // this function creates a space and a thermal zone, it returns the space.  If you want the 
  // thermal zone you can reliably dereference the result of space.thermalZone().

  openstudio::model::ThermalZone thermalZone( m_model );

  openstudio::model::Space space( m_model );
  space.setThermalZone(thermalZone);

  boost::optional<std::string> idfZoneName;

  OptionalString s = workspaceObject.name();
  if(s){
    space.setName(*s);
    thermalZone.setName(*s + " Thermal Zone");
    idfZoneName = *s;
  }

  OptionalDouble d = workspaceObject.getDouble(ZoneFields::DirectionofRelativeNorth);
  if(d){
    space.setDirectionofRelativeNorth(*d);
  }

  d=workspaceObject.getDouble(ZoneFields::XOrigin);
  if(d){
    space.setXOrigin(*d);
  }

  d=workspaceObject.getDouble(ZoneFields::YOrigin);
  if(d){
    space.setYOrigin(*d);
  }

  d=workspaceObject.getDouble(ZoneFields::ZOrigin);
  if(d){
    space.setZOrigin(*d);
  }

  OptionalInt i = workspaceObject.getInt(ZoneFields::Type);
  if(i){
    // no-op
  }

  i = workspaceObject.getInt(ZoneFields::Multiplier);
  if(i){
    thermalZone.setMultiplier(*i);
  }

  d = workspaceObject.getDouble(ZoneFields::CeilingHeight);
  if(d){
    thermalZone.setCeilingHeight(*d);
  }

  d=workspaceObject.getDouble(ZoneFields::Volume);
  if(d){
    thermalZone.setVolume(*d);
  }

  s = workspaceObject.getString(ZoneFields::ZoneInsideConvectionAlgorithm);
  if(s){
    thermalZone.setZoneInsideConvectionAlgorithm(*s);
  }

  s = workspaceObject.getString(ZoneFields::ZoneOutsideConvectionAlgorithm);
  if(s){
    thermalZone.setZoneOutsideConvectionAlgorithm(*s);
  }

  s = workspaceObject.getString(ZoneFields::PartofTotalFloorArea);
  if(s){
    if(istringEqual("Yes",*s))
    {
      space.setPartofTotalFloorArea(true);
    }
    else
    {
      space.setPartofTotalFloorArea(false);
    }
  }

  // Thermostat

  // If the zone in the idf file does not have a name, there is no use in even trying to find a thermostat
  if( idfZoneName )
  {
    Workspace workspace = workspaceObject.workspace();
    
    std::vector<WorkspaceObject> _zoneControlThermostats;
    _zoneControlThermostats = workspace.getObjectsByType(IddObjectType::ZoneControl_Thermostat);

    for( const auto & _zoneControlThermostat : _zoneControlThermostats )
    {
      if( boost::optional<std::string> zoneName = _zoneControlThermostat.getString( ZoneControl_ThermostatFields::ZoneorZoneListName ) )
      {
        bool zoneControlThermostatfound = false;

        if( zoneName.get() == idfZoneName ) 
        { 
          zoneControlThermostatfound = true; 
        }
        else if( boost::optional<WorkspaceObject> _zoneList = workspace.getObjectByTypeAndName(IddObjectType::ZoneList,zoneName.get()) )
        {
          std::vector<IdfExtensibleGroup> zoneListGroup = _zoneList->extensibleGroups();

          for( const auto & zoneListElem : zoneListGroup )
          {
            boost::optional<std::string> zoneListZoneName = zoneListElem.getString(ZoneListExtensibleFields::ZoneName);
            if( zoneListZoneName )
            {
              if( zoneListZoneName.get() == idfZoneName ) { zoneControlThermostatfound = true; }
              break;
            }
          }
        }
        if( zoneControlThermostatfound )
        {
          std::vector<IdfExtensibleGroup> extensibleGroups = _zoneControlThermostat.extensibleGroups();
          for( const auto & extensibleGroup : extensibleGroups )
          {
            boost::optional<std::string> thermostatType = extensibleGroup.getString(ZoneControl_ThermostatExtensibleFields::ControlObjectType);
            boost::optional<std::string> thermostatName = extensibleGroup.getString(ZoneControl_ThermostatExtensibleFields::ControlName);

            if( thermostatName && thermostatType )
            {
              boost::optional<WorkspaceObject> _thermostat
               = workspace.getObjectByTypeAndName(IddObjectType(thermostatType.get()),thermostatName.get());
              
              if( _thermostat )
              {
                boost::optional<ModelObject> thermostat = translateAndMapWorkspaceObject(_thermostat.get());
                if( thermostat )
                {
                  if( boost::optional<ThermostatSetpointDualSetpoint> thermostatSetpointDualSetpoint
                      = thermostat->optionalCast<ThermostatSetpointDualSetpoint>() )
                  {
                    thermalZone.setThermostatSetpointDualSetpoint(thermostatSetpointDualSetpoint.get());
                  }
                }
              }
            }
          }
          break;
        }
      }
    }
  }

  // Zone Equipment
/*
  if( idfZoneName )
  {
    std::vector<WorkspaceObject> zoneHVACEquipmentConnections;
    zoneHVACEquipmentConnections = workspaceObject.workspace().getObjectsByType(IddObjectType::ZoneHVAC_EquipmentConnections);

    for( std::vector<WorkspaceObject>::iterator it = zoneHVACEquipmentConnections.begin();
         it != zoneHVACEquipmentConnections.end();
         it++ )
    {
      s = it->getString(ZoneHVAC_EquipmentConnectionsFields::ZoneName);

      if( s && istringEqual(s.get(),idfZoneName.get()) )
      {
        boost::optional<WorkspaceObject> _zoneEquipmentList = it->getTarget(ZoneHVAC_EquipmentConnectionsFields::ZoneConditioningEquipmentListName);

        if( _zoneEquipmentList )
        {
          translateAndMapWorkspaceObject(_zoneEquipmentList.get());
        }

        break;
      }
    }
  }
*/

  return space;
}
Exemplo n.º 20
0
TEST_F(IdfFixture, WorkspaceObject_FieldSettingWithHiddenPushes) {
  Workspace scratch(StrictnessLevel::None,IddFileType::EnergyPlus); // Strictness level None

  std::stringstream text;
  text << "ZoneHVAC:HighTemperatureRadiant," << std::endl
       << "  MyRadiantSystem," << std::endl
       << "  MyHVACSchedule," << std::endl
       << "  MyCoreZone," << std::endl
       << "  HeatingDesignCapacity," << std::endl
       << "  Autosize," << std::endl
       << "  ," << std::endl
       << "  ," << std::endl
       << "  Electricity;";
  OptionalIdfObject oObj = IdfObject::load(text.str());
  ASSERT_TRUE(oObj);
  IdfObject idfObject = *oObj;
  OptionalWorkspaceObject w1 = scratch.addObject(idfObject);
  ASSERT_TRUE(w1);
  OptionalWorkspaceObject tObject = scratch.getObject(w1->handle ());
  ASSERT_TRUE(tObject);
  WorkspaceObject object = *tObject;
  EXPECT_EQ(static_cast<unsigned>(8),object.numFields());

  // create schedule object to point to from non-extensible field
  text.str("");
  text << "Schedule:Compact," << std::endl
       << "  AlwaysOn," << std::endl
       << "  ," << std::endl
       << "  For: AllOtherDays," << std::endl
       << "  Until: 24:00," << std::endl
       << "  1.0;";
  oObj = IdfObject::load(text.str());
  ASSERT_TRUE(oObj);
  idfObject = *oObj;
  ASSERT_TRUE(idfObject.iddObject().type() == IddObjectType::Schedule_Compact);
  OptionalWorkspaceObject w2 = scratch.addObject(idfObject);
  ASSERT_TRUE(w2);
  EXPECT_TRUE(object.setPointer(14,w2->handle ()));
  EXPECT_EQ(15u,object.numFields());
  tObject = object.getTarget(14);
  ASSERT_TRUE(tObject);
  EXPECT_TRUE(tObject->handle() == w2->handle());

  // hidden pushing for setting extensible string pointer
  EXPECT_TRUE(object.setString(16,*(tObject->name()))); // should only work at strictness none
  tObject = object.getTarget(16);
  ASSERT_TRUE(tObject);
  EXPECT_TRUE(tObject->handle() == w2->handle());
  EXPECT_EQ(18u,object.numFields());

  // hidden pushing for setting extensible double
  EXPECT_TRUE(object.setDouble(19,0.5));
  EXPECT_EQ(20u,object.numFields());
  OptionalDouble dValue = object.getDouble(19);
  ASSERT_TRUE(dValue);
  EXPECT_NEAR(0.5,*dValue,tol);
  
  // SHOULD NOT BE VALID
  scratch = Workspace(StrictnessLevel::Draft, IddFileType::EnergyPlus); // Non-null data must be valid
  text.str("");
  text << "ZoneHVAC:HighTemperatureRadiant," << std::endl
       << "  MyRadiantSystem," << std::endl
       << "  MyHVACSchedule," << std::endl
       << "  MyCoreZone," << std::endl
       << "  HeatingDesignCapacity," << std::endl
       << "  Autosize," << std::endl
       << "  ," << std::endl
       << "  ," << std::endl
       << "  Electricity;";
  oObj = IdfObject::load(text.str());
  ASSERT_TRUE(oObj);
  idfObject = *oObj;
  w2 = scratch.addObject(idfObject);
  ASSERT_TRUE(w2);
  tObject = scratch.getObject(w2->handle());
  ASSERT_TRUE(tObject);
  object = *tObject;

  // hidden pushing for setting nonextensible double
  EXPECT_FALSE(object.setDouble(9,1.5));
  EXPECT_EQ(8u,object.numFields());
  EXPECT_TRUE(object.setDouble(9,0.6));
  EXPECT_EQ(10u,object.numFields());

  // hidden pushing for setting nonextensible string
  EXPECT_FALSE(object.setString(12,"bad key"));
  EXPECT_EQ(10u,object.numFields());
  EXPECT_TRUE(object.setString(12,"MeanAirTemperature"));
  EXPECT_EQ(13u,object.numFields());

  // hidden pushing for setting nonextensible pointer
  EXPECT_TRUE(object.setString(14,""));
  EXPECT_EQ(15u,object.numFields());

  // hidden pushing for setting extensible string pointer
  EXPECT_FALSE(object.setString(16,"MySurface"));
  EXPECT_EQ(15u,object.numFields());
  EXPECT_TRUE(object.setString(16,""));
  EXPECT_EQ(18u,object.numFields());

  // hidden pushing for setting extensible double
  EXPECT_FALSE(object.setDouble(21,-1.5));
  EXPECT_EQ(18u,object.numFields());
  EXPECT_TRUE(object.setDouble(19,0.5));
  EXPECT_EQ(20u,object.numFields());
}
OptionalModelObject ReverseTranslator::translateGasEquipment( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::GasEquipment ){
    LOG(Error, "WorkspaceObject is not IddObjectType: GasEquipment");
    return boost::none;
  }

  // create the definition
  openstudio::model::GasEquipmentDefinition definition(m_model);
  
  OptionalString s = workspaceObject.name();
  if(s){
    definition.setName(*s + " Definition");
  }

  s = workspaceObject.getString(openstudio::GasEquipmentFields::DesignLevelCalculationMethod, true);
  OS_ASSERT(s);
 
  OptionalDouble d;
  if (istringEqual("EquipmentLevel", *s)){
    d = workspaceObject.getDouble(openstudio::GasEquipmentFields::DesignLevel);
    if (d){
      definition.setDesignLevel(*d);
    }else{
      LOG(Error, "EquipmentLevel value not found for workspace object " << workspaceObject);
    }
  }else if(istringEqual("Watts/Area", *s)){
    d = workspaceObject.getDouble(openstudio::GasEquipmentFields::PowerperZoneFloorArea);
    if (d){
      definition.setWattsperSpaceFloorArea(*d);
    }else{
      LOG(Error, "Watts/Area value not found for workspace object " << workspaceObject);
    }
  }else if(istringEqual("Watts/Person", *s)){
    d = workspaceObject.getDouble(openstudio::GasEquipmentFields::PowerperPerson);
    if (d){
      definition.setWattsperPerson(*d);
    }else{
      LOG(Error, "Watts/Person value not found for workspace object " << workspaceObject);
    }
  }else{
    LOG(Error, "Unknown DesignLevelCalculationMethod value for workspace object" << workspaceObject);
  }

  d = workspaceObject.getDouble(openstudio::GasEquipmentFields::FractionLatent);
  if (d){
    definition.setFractionLatent(*d);
  }

  d = workspaceObject.getDouble(openstudio::GasEquipmentFields::FractionRadiant);
  if (d){
    definition.setFractionRadiant(*d);
  }

  d = workspaceObject.getDouble(openstudio::GasEquipmentFields::FractionLost);
  if (d){
    definition.setFractionLost(*d);
  }

  d = workspaceObject.getDouble(openstudio::GasEquipmentFields::CarbonDioxideGenerationRate);
  if (d){
    definition.setCarbonDioxideGenerationRate(*d);
  }

  // create the instance
  GasEquipment gasEquipment(definition);

  s = workspaceObject.name();
  if(s){
    gasEquipment.setName(*s);
  }

  OptionalWorkspaceObject target = workspaceObject.getTarget(openstudio::GasEquipmentFields::ZoneorZoneListName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<Space>()){
        gasEquipment.setSpace(modelObject->cast<Space>());
      }else if (modelObject->optionalCast<SpaceType>()){
        gasEquipment.setSpaceType(modelObject->cast<SpaceType>());
      }
    }
  }

  target = workspaceObject.getTarget(openstudio::GasEquipmentFields::ScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (OptionalSchedule intermediate = modelObject->optionalCast<Schedule>()){
        Schedule schedule(*intermediate);
        gasEquipment.setSchedule(schedule);
      }
    }
  }

  s = workspaceObject.getString(openstudio::GasEquipmentFields::EndUseSubcategory);
  if(s){
    gasEquipment.setEndUseSubcategory(*s);
  }
       
  return gasEquipment;
}
OptionalModelObject ReverseTranslator::translateBuildingSurfaceDetailed( const WorkspaceObject & workspaceObject )
{
 if( workspaceObject.iddObject().type() != IddObjectType::BuildingSurface_Detailed ){
   LOG(Error, "WorkspaceObject is not IddObjectType: BuildingSurface:Detailed");
    return boost::none;
  }

  openstudio::Point3dVector vertices = getVertices(BuildingSurface_DetailedFields::NumberofVertices + 1, workspaceObject);
 
  boost::optional<Surface> surface;
  try{
    surface = Surface(vertices, m_model);
  }catch(const std::exception&){
    LOG(Error, "Cannot create Surface for object: " << workspaceObject);
    return boost::none;
  }

  OptionalString s = workspaceObject.name();
  if(s) {
    surface->setName(*s);
  }

  OptionalWorkspaceObject target = workspaceObject.getTarget(openstudio::BuildingSurface_DetailedFields::ConstructionName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ConstructionBase>()){
        surface->setConstruction(modelObject->cast<ConstructionBase>());
      }
    }
  }

  target = workspaceObject.getTarget(openstudio::BuildingSurface_DetailedFields::ZoneName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<Space>()){
        surface->setSpace(modelObject->cast<Space>());
      }
    }
  }

  s = workspaceObject.getString(BuildingSurface_DetailedFields::SurfaceType);
  if (s) {
    if (istringEqual("Roof", *s) || istringEqual("Ceiling", *s)){
      s = "RoofCeiling";
    }
    surface->setSurfaceType(*s);
  }
  //std::string surfaceType = surface->surfaceType();

  s = workspaceObject.getString(BuildingSurface_DetailedFields::SunExposure);
  if (s) {
    surface->setSunExposure(*s);
  }

  s = workspaceObject.getString(BuildingSurface_DetailedFields::WindExposure);
  if (s) {
    surface->setWindExposure(*s);
  }

  OptionalDouble d = workspaceObject.getDouble(BuildingSurface_DetailedFields::ViewFactortoGround);
  if (d) {
    surface->setViewFactortoGround(*d);
  }

  target = workspaceObject.getTarget(openstudio::BuildingSurface_DetailedFields::OutsideBoundaryConditionObject);
  if (target){

    if (target->iddObject().type() == IddObjectType::Zone){
      // Zone boundary condition

      OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
      if(modelObject->optionalCast<Space>()){
        Space adjacentSpace = modelObject->cast<Space>();

        if (surface->space()){
          // insert this surface in the map so subsurface translation can find it  
          m_workspaceToModelMap.insert(std::make_pair(workspaceObject.handle(), surface.get()));

          // need to translate all sub surfaces here so they will be in adjacent space
          for (const WorkspaceObject& workspaceSubSurface : workspaceObject.getSources(IddObjectType::FenestrationSurface_Detailed)){
            translateAndMapWorkspaceObject(workspaceSubSurface);
          }

          // create adjacent surface in other space
          surface->createAdjacentSurface(adjacentSpace);
          return surface.get();
        }
      }

    }else if (target->iddObject().type() == IddObjectType::BuildingSurface_Detailed){
      // Surface boundary condition

      // see if we have already mapped other surface, don't do it here because that is circular
      if (target->handle() == workspaceObject.handle() ){
        // these objects are the same, set boundary condition to adiabatic
        surface->setOutsideBoundaryCondition("Adiabatic");
        return surface.get();
      }else{
        auto it = m_workspaceToModelMap.find(target->handle());
        if( it !=  m_workspaceToModelMap.end()){
          if (it->second.optionalCast<Surface>()){
            // this will set other side boundary object on both surfaces
            Surface adjacentSurface = it->second.cast<Surface>();
            surface->setAdjacentSurface(adjacentSurface);
            return surface.get();
          }
        }
      }

    }else{  
      LOG(Error, "OutsideBoundaryConditionObject not yet mapped for object of type " << target->iddObject().name());
    }
  }

  s = workspaceObject.getString(BuildingSurface_DetailedFields::OutsideBoundaryCondition);
  if (s) {
    surface->setOutsideBoundaryCondition(*s);
  }

  return surface.get();
}
OptionalModelObject ReverseTranslator::translateAirTerminalSingleDuctVAVReheat( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::AirTerminal_SingleDuct_VAV_Reheat )
  {
     LOG(Error, "WorkspaceObject is not IddObjectType: AirTerminal_SingleDuct_VAV_Reheat");
     return boost::none;
  }

  boost::optional<WorkspaceObject> wo = workspaceObject.getTarget(AirTerminal_SingleDuct_VAV_ReheatFields::AvailabilityScheduleName);
  boost::optional<Schedule> schedule;
  boost::optional<HVACComponent> coil;
  boost::optional<AirTerminalSingleDuctVAVReheat> airTerminal;

  if( wo )
  {
    boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get());
    if( mo )
    {
      if( ! (schedule = mo->optionalCast<Schedule>()) )
      {
        LOG(Error, workspaceObject.briefDescription() << " does not have an associated availability schedule");

        return boost::none;
      }
    }
  }

  wo = workspaceObject.getTarget(AirTerminal_SingleDuct_VAV_ReheatFields::ReheatCoilName);
  if( wo )
  {
    boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get());
    if( mo )
    {
      if( ! coil )
      {
        coil = mo->optionalCast<CoilHeatingGas>();
      }
    }
  }

  if( schedule && coil )
  {
    airTerminal = AirTerminalSingleDuctVAVReheat( m_model,schedule.get(),coil.get() );
  }

  if( airTerminal )
  {
    boost::optional<double> value;
    boost::optional<std::string> s = workspaceObject.getString(AirTerminal_SingleDuct_VAV_ReheatFields::Name);

    if( s )
    {
      airTerminal->setName(s.get());
    }

    // MaximumAirFlowRate
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_VAV_ReheatFields::MaximumAirFlowRate);
    s = workspaceObject.getString(AirTerminal_SingleDuct_VAV_ReheatFields::MaximumAirFlowRate);
    if( value )
    {
      airTerminal->setMaximumAirFlowRate(value.get());
    }
    else if( s && istringEqual(s.get(),"Autosize") )
    {
      airTerminal->autosizeMaximumAirFlowRate();
    }
    else if( s && istringEqual(s.get(),"Autocalculate") )
    {
      airTerminal->autosizeMaximumAirFlowRate();
    }

    // ZoneMinimumAirFlowInputMethod
    s = workspaceObject.getString(AirTerminal_SingleDuct_VAV_ReheatFields::ZoneMinimumAirFlowInputMethod);
    if( s )
    {
      airTerminal->setZoneMinimumAirFlowMethod(s.get());
    }

    // ConstantMinimumAirFlowFraction
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_VAV_ReheatFields::ConstantMinimumAirFlowFraction);
    if( value )
    {
      airTerminal->setConstantMinimumAirFlowFraction(value.get());
    }

    // FixedMinimumAirFlowRate
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_VAV_ReheatFields::FixedMinimumAirFlowRate);
    if( value )
    {
      airTerminal->setFixedMinimumAirFlowRate(value.get());
    }

    boost::optional<WorkspaceObject> _schedule;

    // MinimumAirFlowFractionScheduleName
    _schedule = workspaceObject.getTarget(AirTerminal_SingleDuct_VAV_ReheatFields::MinimumAirFlowFractionScheduleName);
    if( _schedule )
    {
      boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(_schedule.get());
      if( mo )
      {
        if( boost::optional<Schedule> schedule = mo->optionalCast<Schedule>() )
        {
          airTerminal->setMinimumAirFlowFractionSchedule(schedule.get());
        }
      }
    }
  
    // MaximumHotWaterorSteamFlowRate
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_VAV_ReheatFields::MaximumHotWaterorSteamFlowRate);
    s = workspaceObject.getString(AirTerminal_SingleDuct_VAV_ReheatFields::MaximumHotWaterorSteamFlowRate);
    if( value )
    {
      airTerminal->setMaximumHotWaterOrSteamFlowRate(value.get());
    }
    else if( s && istringEqual(s.get(),"Autosize") )
    {
      airTerminal->autosizeMaximumHotWaterOrSteamFlowRate();
    }
    else if( s && istringEqual(s.get(),"Autocalculate") )
    {
      airTerminal->autosizeMaximumHotWaterOrSteamFlowRate();
    }

    // MinimumHotWaterorSteamFlowRate
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_VAV_ReheatFields::MinimumHotWaterorSteamFlowRate);
    if( value )
    {
      airTerminal->setMinimumHotWaterOrStreamFlowRate(value.get());
    }

    // ConvergenceTolerance
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_VAV_ReheatFields::ConvergenceTolerance);
    if( value )
    {
      airTerminal->setConvergenceTolerance(value.get());
    }

    // DamperHeatingAction
    s = workspaceObject.getString(AirTerminal_SingleDuct_VAV_ReheatFields::DamperHeatingAction);
    if( s )
    {
      airTerminal->setDamperHeatingAction(s.get());
    }

    // MaximumFlowPerZoneFloorAreaDuringReheat
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_VAV_ReheatFields::MaximumFlowperZoneFloorAreaDuringReheat);
    s = workspaceObject.getString(AirTerminal_SingleDuct_VAV_ReheatFields::MaximumFlowperZoneFloorAreaDuringReheat);
    if( value )
    {
      airTerminal->setMaximumFlowPerZoneFloorAreaDuringReheat(value.get());
    }
    else if( s && istringEqual(s.get(),"Autosize") )
    {
      airTerminal->autosizeMaximumFlowPerZoneFloorAreaDuringReheat();
    }
    else if( s && istringEqual(s.get(),"Autocalculate") )
    {
      airTerminal->autosizeMaximumFlowPerZoneFloorAreaDuringReheat();
    }
    
    // MaximumFlowFractionDuringReheat
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_VAV_ReheatFields::MaximumFlowFractionDuringReheat);
    s = workspaceObject.getString(AirTerminal_SingleDuct_VAV_ReheatFields::MaximumFlowFractionDuringReheat);
    if( value )
    {
      airTerminal->setMaximumFlowFractionDuringReheat(value.get());
    }
    else if( s && istringEqual(s.get(),"Autosize") )
    {
      airTerminal->autosizeMaximumFlowFractionDuringReheat();
    }
    else if( s && istringEqual(s.get(),"Autocalculate") )
    {
      airTerminal->autosizeMaximumFlowFractionDuringReheat();
    }

    // MaximumReheatAirTemperature
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_VAV_ReheatFields::MaximumReheatAirTemperature);
    if( value )
    {
      airTerminal->setMaximumReheatAirTemperature(value.get());
    }

    return airTerminal.get();
  }
  else
  {
    LOG(Error, "Unknown error translating " << workspaceObject.briefDescription());

    return boost::none;
  }
}
OptionalModelObject ReverseTranslator::translateGroundHeatExchangerVertical( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::GroundHeatExchanger_Vertical ){
    LOG(Error, "WorkspaceObject is not IddObjectType: GroundHeatExchanger:Vertical");
    return boost::none;
  }

  GroundHeatExchangerVertical ghex = GroundHeatExchangerVertical( m_model );

  boost::optional<double> d;
  boost::optional<std::string> s = workspaceObject.getString(GroundHeatExchanger_VerticalFields::Name);

  if (s) {
    ghex.setName(s.get());
  }

  //TODO: Need to address Inlet Node Name and Outlet Node Name somehow, probably with PlantLoop.

  //Maximum Flow Rate
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::MaximumFlowRate);
  if (d) {
    ghex.setMaximumFlowRate(*d);
  }

  //Number of Bore Holes
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::NumberofBoreHoles);
  if (d) {
    ghex.setNumberofBoreHoles(*d);
  }

  //Bore Hole Length
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::BoreHoleLength);
  if (d) {
    ghex.setBoreHoleLength(*d);
  }

  //Bore Hole Radius
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::BoreHoleRadius);
  if (d) {
    ghex.setBoreHoleRadius(*d);
  }

  //Ground Thermal Conductivity
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::GroundThermalConductivity);
  if (d) {
    ghex.setGroundThermalConductivity(*d);
  }

  //Ground Thermal Heat Capacity
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::GroundThermalHeatCapacity);
  if (d) {
    ghex.setGroundThermalHeatCapacity(*d);
  }

  //Ground Temperature
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::GroundTemperature);
  if (d) {
    ghex.setGroundTemperature(*d);
  }

  //Design Flow Rate
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::DesignFlowRate);
  if (d) {
    ghex.setDesignFlowRate(*d);
  }

  //Grout Thermal Conductivity
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::GroutThermalConductivity);
  if (d) {
      ghex.setGroutThermalConductivity(*d);
  }

  //Pipe Thermal Conductivity
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::PipeThermalConductivity);
  if (d) {
    ghex.setPipeThermalConductivity(*d);
  }

  //Pipe Out Diameter
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::PipeOutDiameter);
  if (d) {
    ghex.setPipeOutDiameter(*d);
  }

  //U-Tube Distance
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::UTubeDistance);
  if (d) {
    ghex.setUTubeDistance(*d);
  }

  //Pipe Thickness
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::PipeThickness);
  if (d) {
    ghex.setPipeThickness(*d);
  }

  //Maximum Length of Simulation
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::MaximumLengthofSimulation);
  if (d) {
    ghex.setMaximumLengthofSimulation(*d);
  }

  //G-Function Reference Ratio
  d = workspaceObject.getDouble(GroundHeatExchanger_VerticalFields::GFunctionReferenceRatio);
  if (d) {
    ghex.setGFunctionReferenceRatio(*d);
  }

  std::vector<IdfExtensibleGroup> groups = workspaceObject.extensibleGroups();
  ghex.removeAllGFunctions();

  for( std::vector<IdfExtensibleGroup>::iterator it = groups.begin();
       it != groups.end();
       it++ )
  {
    ghex.pushExtensibleGroup(it->fields());
  }

  return ghex;
}
boost::optional<ModelObject> ReverseTranslator::translateCurveBicubic(
    const WorkspaceObject& workspaceObject)
{
  CurveBicubic curve(m_model);

  OptionalString s;
  OptionalDouble d;

  if((s = workspaceObject.name())) {
    curve.setName(*s);
  }

  if ((d = workspaceObject.getDouble(Curve_BicubicFields::Coefficient1Constant))) {
    curve.setCoefficient1Constant(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::Coefficient2x))) {
    curve.setCoefficient2x(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::Coefficient3x_POW_2))) {
    curve.setCoefficient3xPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::Coefficient4y))) {
    curve.setCoefficient4y(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::Coefficient5y_POW_2))) {
    curve.setCoefficient5yPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::Coefficient6x_TIMES_y))) {
    curve.setCoefficient6xTIMESY(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::Coefficient7x_POW_3))) {
    curve.setCoefficient7xPOW3(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::Coefficient8y_POW_3))) {
    curve.setCoefficient8yPOW3(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::Coefficient9x_POW_2_TIMES_y))) {
    curve.setCoefficient9xPOW2TIMESY(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::Coefficient10x_TIMES_y_POW_2))) {
    curve.setCoefficient10xTIMESYPOW2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::MinimumValueofx))) {
    curve.setMinimumValueofx(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::MaximumValueofx))) {
    curve.setMaximumValueofx(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::MinimumValueofy))) {
    curve.setMinimumValueofy(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::MaximumValueofy))) {
    curve.setMaximumValueofy(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::MinimumCurveOutput))) {
    curve.setMinimumCurveOutput(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_BicubicFields::MaximumCurveOutput))) {
    curve.setMaximumCurveOutput(*d);
  }
  if ((s = workspaceObject.getString(Curve_BicubicFields::InputUnitTypeforX,false,true))) {
    curve.setInputUnitTypeforX(*s);
  }
  if ((s = workspaceObject.getString(Curve_BicubicFields::InputUnitTypeforY,false,true))) {
    curve.setInputUnitTypeforY(*s);
  }
  if ((s = workspaceObject.getString(Curve_BicubicFields::OutputUnitType,false,true))) {
    curve.setOutputUnitType(*s);
  }

  return curve;
}
OptionalModelObject ReverseTranslator::translateAirTerminalSingleDuctVAVNoReheat( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::AirTerminal_SingleDuct_VAV_NoReheat )
  {
     LOG(Error, "WorkspaceObject is not IddObjectType: AirTerminal_SingleDuct_VAV_NoReheat");
     return boost::none;
  }

  boost::optional<WorkspaceObject> wo = workspaceObject.getTarget(AirTerminal_SingleDuct_VAV_NoReheatFields::AvailabilityScheduleName);
  boost::optional<Schedule> schedule;
  boost::optional<AirTerminalSingleDuctVAVNoReheat> airTerminal;

  if( wo )
  {
    boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get());
    if( mo )
    {
      if( ! (schedule = mo->optionalCast<Schedule>()) )
      {
        LOG(Error, workspaceObject.briefDescription() << " does not have an associated availability schedule");

        return boost::none;
      }
    }
  }

  if( schedule )
  {
    airTerminal = AirTerminalSingleDuctVAVNoReheat( m_model,schedule.get() );
  }

  if( airTerminal )
  {
    boost::optional<double> value;
    boost::optional<std::string> s = workspaceObject.getString(AirTerminal_SingleDuct_VAV_NoReheatFields::Name);

    if( s )
    {
      airTerminal->setName(s.get());
    }

    // MaximumAirFlowRate
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_VAV_NoReheatFields::MaximumAirFlowRate);
    s = workspaceObject.getString(AirTerminal_SingleDuct_VAV_NoReheatFields::MaximumAirFlowRate);
    if( value )
    {
      airTerminal->setMaximumAirFlowRate(value.get());
    }
    else if( s && istringEqual(s.get(),"Autosize") )
    {
      airTerminal->autosizeMaximumAirFlowRate();
    }
    else if( s && istringEqual(s.get(),"Autocalculate") )
    {
      airTerminal->autosizeMaximumAirFlowRate();
    }

    // ZoneMinimumAirFlowInputMethod
    s = workspaceObject.getString(AirTerminal_SingleDuct_VAV_NoReheatFields::ZoneMinimumAirFlowInputMethod);
    if( s )
    {
      airTerminal->setZoneMinimumAirFlowInputMethod(s.get());
    }

    // ConstantMinimumAirFlowFraction
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_VAV_NoReheatFields::ConstantMinimumAirFlowFraction);
    if( value )
    {
      airTerminal->setConstantMinimumAirFlowFraction(value.get());
    }

    // FixedMinimumAirFlowRate
    value = workspaceObject.getDouble(AirTerminal_SingleDuct_VAV_NoReheatFields::FixedMinimumAirFlowRate);
    if( value )
    {
      airTerminal->setFixedMinimumAirFlowRate(value.get());
    }

    boost::optional<WorkspaceObject> _schedule;

    // MinimumAirFlowFractionScheduleName
    _schedule = workspaceObject.getTarget(AirTerminal_SingleDuct_VAV_NoReheatFields::MinimumAirFlowFractionScheduleName);
    if( _schedule )
    {
      boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(_schedule.get());
      if( mo )
      {
        if( boost::optional<Schedule> schedule = mo->optionalCast<Schedule>() )
        {
          airTerminal->setMinimumAirFlowFractionSchedule(schedule.get());
        }
      }
    }

    return airTerminal.get();
  }
  else
  {
    LOG(Error, "Unknown error translating " << workspaceObject.briefDescription());

    return boost::none;
  }
}
OptionalModelObject ReverseTranslator::translateGeneratorMicroTurbine( const WorkspaceObject & workspaceObject )
{

  OptionalModelObject result,temp;
  OptionalDouble d;
  boost::optional<WorkspaceObject> owo;
  OptionalString optS;


  // TODO: The availability schedule is in the ElectricLoadCenter:Generators (list) in E+, here it's carried by the generator itself
  // Should also get the Rated Thermal To Electrical Power Ratio in the list

  //Generator:MicroTurbine,
  //    Capstone C65,            !- Name

  openstudio::model::GeneratorMicroTurbine mchp( m_model );

  // Name
  optS = workspaceObject.name();
  if(optS)
  {
    mchp.setName(*optS);
  }



  //    65000,                   !- Reference Electrical Power Output {W}
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::ReferenceElectricalPowerOutput);
  if(d)
  {
    mchp.setReferenceElectricalPowerOutput(*d);
  }
  //    29900,                   !- Minimum Full Load Electrical Power Output {W}
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::MinimumFullLoadElectricalPowerOutput);
  if(d)
  {
    mchp.setMinimumFullLoadElectricalPowerOutput(*d);
  }
  //    65000,                   !- Maximum Full Load Electrical Power Output {W} setMaximumFullLoadElectricalPowerOutput
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::MaximumFullLoadElectricalPowerOutput);
  if(d)
  {
    mchp.setMaximumFullLoadElectricalPowerOutput(*d);
  }

  //    0.29,                    !- Reference Electrical Efficiency Using Lower Heating Value
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::ReferenceElectricalEfficiencyUsingLowerHeatingValue);
  if(d)
  {
    mchp.setReferenceElectricalEfficiencyUsingLowerHeatingValue(*d);
  }

  //    15.0,                    !- Reference Combustion Air Inlet Temperature {C}
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::ReferenceCombustionAirInletTemperature);
  if(d)
  {
    mchp.setReferenceCombustionAirInletTemperature(*d);
  }

  //    0.00638,                 !- Reference Combustion Air Inlet Humidity Ratio {kgWater/kgDryAir}
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::ReferenceCombustionAirInletHumidityRatio);
  if(d)
  {
    mchp.setReferenceCombustionAirInletHumidityRatio(*d);
  }

  //    0.0,                     !- Reference Elevation {m}
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::MinimumFullLoadElectricalPowerOutput);
  if(d)
  {
    mchp.setMinimumFullLoadElectricalPowerOutput(*d);
  }

  //    Capstone C65 Power_vs_Temp_Elev,  !- Electrical Power Function of Temperature and Elevation Curve Name
  // BiquadraticCurves
  if( (owo = workspaceObject.getTarget(Generator_MicroTurbineFields::ElectricalPowerFunctionofTemperatureandElevationCurveName)) )
    {
      if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
      {
        if( boost::optional<CurveBiquadratic> curve = mo->optionalCast<CurveBiquadratic>() )
        {
          mchp.setElectricalPowerFunctionofTemperatureandElevationCurve(curve.get());
        }
        else
        {
          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Electrical Power Function of Temperature and Elevation Curve Name");
        }
      }
    }

  //    Capstone C65 Efficiency_vs_Temp,  !- Electrical Efficiency Function of Temperature Curve Name
  // QuadraticCubicCurves
  if( (owo = workspaceObject.getTarget(Generator_MicroTurbineFields::ElectricalEfficiencyFunctionofTemperatureCurveName)) )
    {
      if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
      {
        if( boost::optional<CurveQuadratic> curve = mo->optionalCast<CurveQuadratic>() )
        {
          mchp.setElectricalEfficiencyFunctionofTemperatureCurve(curve.get());
        }
        else if( boost::optional<CurveCubic> curve = mo->optionalCast<CurveCubic>() )
        {
          mchp.setElectricalEfficiencyFunctionofTemperatureCurve(curve.get());
        }
        else
        {
          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Electrical Efficiency Function of Temperature Curve Name");
        }
      }
    }


  //    Capstone C65 Efficiency_vs_PLR,  !- Electrical Efficiency Function of Part Load Ratio Curve Name
  // QuadraticCubicCurves
  // setElectricalEfficiencyFunctionofPartLoadRatioCurve
  if( (owo = workspaceObject.getTarget(Generator_MicroTurbineFields::ElectricalEfficiencyFunctionofPartLoadRatioCurveName)) )
    {
      if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
      {
        if( boost::optional<CurveQuadratic> curve = mo->optionalCast<CurveQuadratic>() )
        {
          mchp.setElectricalEfficiencyFunctionofPartLoadRatioCurve(curve.get());
        }
        else if( boost::optional<CurveCubic> curve = mo->optionalCast<CurveCubic>() )
        {
          mchp.setElectricalEfficiencyFunctionofPartLoadRatioCurve(curve.get());
        }
        else
        {
          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Electrical Efficiency Function of Part Load Ratio Curve Name");
        }
      }
    }

  //    NaturalGas,              !- Fuel Type
  optS = workspaceObject.getString(Generator_MicroTurbineFields::FuelType);
  if(optS)
  {
    mchp.setFuelType(*optS);
  }

  //    50000,                   !- Fuel Higher Heating Value {kJ/kg}
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::FuelHigherHeatingValue);
  if(d)
  {
    mchp.setFuelHigherHeatingValue(*d);
  }

  //    45450,                   !- Fuel Lower Heating Value {kJ/kg}
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::FuelLowerHeatingValue);
  if(d)
  {
    mchp.setFuelLowerHeatingValue(*d);
  }

  //    300,                     !- Standby Power {W}
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::StandbyPower);
  if(d)
  {
    mchp.setStandbyPower(*d);
  }

  //    4500,                    !- Ancillary Power {W}
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::AncillaryPower);
  if(d)
  {
    mchp.setAncillaryPower(*d);
  }

  //    ,                        !- Ancillary Power Function of Fuel Input Curve Name
  // QuadraticCurves
  // mchp.setAncillaryPowerFunctionofFuelInputCurve
  if( (owo = workspaceObject.getTarget(Generator_MicroTurbineFields::AncillaryPowerFunctionofFuelInputCurveName)) )
    {
      if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
      {
        if( boost::optional<CurveQuadratic> curve = mo->optionalCast<CurveQuadratic>() )
        {
          mchp.setAncillaryPowerFunctionofFuelInputCurve(curve.get());
        }
        else
        {
          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Ancillary Power Function of Fuel Input Curve Name");
        }
      }
    }


  // Fields in between (in E+.idd) are moved at the end in the Heat Recovery section

  //    Capstone C65 Combustion Air Inlet Node,  !- Combustion Air Inlet Node Name
  //    Capstone C65 Combustion Air Outlet Node,  !- Combustion Air Outlet Node Name


  //    0.489885,                !- Reference Exhaust Air Mass Flow Rate {kg/s}
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::ReferenceExhaustAirMassFlowRate);
  if(d)
  {
    mchp.setReferenceExhaustAirMassFlowRate(*d);
  }

  //    Capstone C65 ExhAirFlowRate_vs_InletTemp,  !- Exhaust Air Flow Rate Function of Temperature Curve Name
  // QuadraticCubicCurves
  // mchp.setExhaustAirFlowRateFunctionofTemperatureCurve
  if( (owo = workspaceObject.getTarget(Generator_MicroTurbineFields::ExhaustAirFlowRateFunctionofTemperatureCurveName)) )
    {
      if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
      {
        if( boost::optional<CurveQuadratic> curve = mo->optionalCast<CurveQuadratic>() )
        {
          mchp.setExhaustAirFlowRateFunctionofTemperatureCurve(curve.get());
        }
        else if( boost::optional<CurveCubic> curve = mo->optionalCast<CurveCubic>() )
        {
          mchp.setExhaustAirFlowRateFunctionofTemperatureCurve(curve.get());
        }
        else
        {
          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Exhaust Air Flow Rate Function of Temperature Curve Name");
        }
      }
    }

  //    Capstone C65 ExhAirFlowRate_vs_PLR,  !- Exhaust Air Flow Rate Function of Part Load Ratio Curve Name
  // QuadraticCubicCurves
  // mchp.setExhaustAirFlowRateFunctionofPartLoadRatioCurve(curve)
  if( (owo = workspaceObject.getTarget(Generator_MicroTurbineFields::ExhaustAirFlowRateFunctionofPartLoadRatioCurveName)) )
    {
      if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
      {
        if( boost::optional<CurveQuadratic> curve = mo->optionalCast<CurveQuadratic>() )
        {
          mchp.setExhaustAirFlowRateFunctionofPartLoadRatioCurve(curve.get());
        }
        else if( boost::optional<CurveCubic> curve = mo->optionalCast<CurveCubic>() )
        {
          mchp.setExhaustAirFlowRateFunctionofPartLoadRatioCurve(curve.get());
        }
        else
        {
          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Exhaust Air Flow Rate Function of Part Load Ratio Curve Name");
        }
      }
    }

  //    308.9,                   !- Nominal Exhaust Air Outlet Temperature
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::NominalExhaustAirOutletTemperature);
  if(d)
  {
    mchp.setNominalExhaustAirOutletTemperature(*d);
  }

  //    Capstone C65 ExhaustTemp_vs_InletTemp,  !- Exhaust Air Temperature Function of Temperature Curve Name
  // QuadraticCubicCurves
  // mchp.setExhaustAirTemperatureFunctionofTemperatureCurve(curve)
  if( (owo = workspaceObject.getTarget(Generator_MicroTurbineFields::ExhaustAirTemperatureFunctionofTemperatureCurveName)) )
    {
      if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
      {
        if( boost::optional<CurveQuadratic> curve = mo->optionalCast<CurveQuadratic>() )
        {
          mchp.setExhaustAirTemperatureFunctionofTemperatureCurve(curve.get());
        }
        else if( boost::optional<CurveCubic> curve = mo->optionalCast<CurveCubic>() )
        {
          mchp.setExhaustAirTemperatureFunctionofTemperatureCurve(curve.get());
        }
        else
        {
          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Exhaust Air Temperature Function of Temperature Curve Name");
        }
      }
    }

  //    Capstone C65 ExhaustTemp_vs_PLR;  !- Exhaust Air Temperature Function of Part Load Ratio Curve Name
  // QuadraticCubicCurves
  // mchp.setExhaustAirTemperatureFunctionofPartLoadRatioCurve(curve)
  if( (owo = workspaceObject.getTarget(Generator_MicroTurbineFields::ExhaustAirTemperatureFunctionofPartLoadRatioCurveName)) )
    {
      if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
      {
        if( boost::optional<CurveQuadratic> curve = mo->optionalCast<CurveQuadratic>() )
        {
          mchp.setExhaustAirTemperatureFunctionofPartLoadRatioCurve(curve.get());
        }
        else if( boost::optional<CurveCubic> curve = mo->optionalCast<CurveCubic>() )
        {
          mchp.setExhaustAirTemperatureFunctionofPartLoadRatioCurve(curve.get());
        }
        else
        {
          LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Exhaust Air Temperature Function of Part Load Ratio Curve Name");
        }
      }
    }


  /// HEAT RECOVERY PORTION

  // Would need to add that to the plantLoop reverse translator
  //    Capstone C65 Heat Recovery Water Inlet Node,  !- Heat Recovery Water Inlet Node Name
  //    Capstone C65 Heat Recovery Water Outlet Node,  !- Heat Recovery Water Outlet Node Name




  // TODO: For now, I trigger the creation is the 'Reference Thermal Efficiency Using Lower Heat Value' is filled.
  // TODO: I should trigger it based on the `Rated Thermal To Electrical Power Ratio in the list`  in the ElectricLoadCenter:Generators (list)
  // TODO: But in order to do that, the ElectricLoadCenter:Distribution & ElectricLoadCenter:Generators need to have a reverse translator

  //    0.4975,                  !- Reference Thermal Efficiency Using Lower Heat Value
  d = workspaceObject.getDouble(Generator_MicroTurbineFields::ReferenceThermalEfficiencyUsingLowerHeatValue);

  if(d)
  {

    // Create a GeneratorMicroTurbineHeatRecovery module, and assign it to the MicroTurbine
    // I've Set the Name in the constructor
    openstudio::model::GeneratorMicroTurbineHeatRecovery mchpHR (m_model, mchp);

    // Assign the Reference Thermal Efficiency Using Lower Heat Value
    mchpHR.setReferenceThermalEfficiencyUsingLowerHeatValue(*d);


    //    60.0,                    !- Reference Inlet Water Temperature {C}
    d = workspaceObject.getDouble(Generator_MicroTurbineFields::ReferenceInletWaterTemperature);
    if(d)
    {
      mchpHR.setReferenceInletWaterTemperature(*d);
    }

    //    PlantControl,            !- Heat Recovery Water Flow Operating Mode
    optS = workspaceObject.getString(Generator_MicroTurbineFields::HeatRecoveryWaterFlowOperatingMode);
    if(optS)
    {
      mchpHR.setHeatRecoveryWaterFlowOperatingMode(*optS);
    }

    //    0.00252362,              !- Reference Heat Recovery Water Flow Rate {m3/s}
    d = workspaceObject.getDouble(Generator_MicroTurbineFields::ReferenceHeatRecoveryWaterFlowRate);
    if(d)
    {
      mchpHR.setReferenceHeatRecoveryWaterFlowRate(*d);
    }

    //    ,                        !- Heat Recovery Water Flow Rate Function of Temperature and Power Curve Name
    // BiquadraticCurves
    // mchpHR.setHeatRecoveryWaterFlowRateFunctionofTemperatureandPowerCurve();
    if( (owo = workspaceObject.getTarget(Generator_MicroTurbineFields::HeatRecoveryWaterFlowRateFunctionofTemperatureandPowerCurveName)) )
      {
        if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
        {
          if( boost::optional<CurveBiquadratic> curve = mo->optionalCast<CurveBiquadratic>() )
          {
            mchpHR.setHeatRecoveryWaterFlowRateFunctionofTemperatureandPowerCurve(curve.get());
          }
          else
          {
            LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Heat Recovery Water Flow Rate Function of Temperature and Power Curve Name");
          }
        }
      }

    //    Capstone C65 ThermalEff_vs_Temp_Elev,  !- Thermal Efficiency Function of Temperature and Elevation Curve Name
    // BicubicBiquadraticCurves
    // mchpHR.setThermalEfficiencyFunctionofTemperatureandElevationCurve();
    if( (owo = workspaceObject.getTarget(Generator_MicroTurbineFields::ThermalEfficiencyFunctionofTemperatureandElevationCurveName)) )
      {
        if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
        {
          if( boost::optional<CurveBicubic> curve = mo->optionalCast<CurveBicubic>() )
          {
            mchpHR.setThermalEfficiencyFunctionofTemperatureandElevationCurve(curve.get());
          }
          else if( boost::optional<CurveBiquadratic> curve = mo->optionalCast<CurveBiquadratic>() )
          {
            mchpHR.setThermalEfficiencyFunctionofTemperatureandElevationCurve(curve.get());
          }
          else
          {
            LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Thermal Efficiency Function of Temperature and Elevation Curve Name");
          }
        }
      }

    //    Capstone C65 HeatRecoveryRate_vs_PLR,  !- Heat Recovery Rate Function of Part Load Ratio Curve Name
    // QuadraticCubicCurves
    // mchpHR.setHeatRecoveryRateFunctionofPartLoadRatioCurve();
    if( (owo = workspaceObject.getTarget(Generator_MicroTurbineFields::HeatRecoveryRateFunctionofPartLoadRatioCurveName)) )
      {
        if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
        {
          if( boost::optional<CurveQuadratic> curve = mo->optionalCast<CurveQuadratic>() )
          {
            mchpHR.setHeatRecoveryRateFunctionofPartLoadRatioCurve(curve.get());
          }
          else if( boost::optional<CurveCubic> curve = mo->optionalCast<CurveCubic>() )
          {
            mchpHR.setHeatRecoveryRateFunctionofPartLoadRatioCurve(curve.get());
          }
          else
          {
            LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Heat Recovery Rate Function of Part Load Ratio Curve Name");
          }
        }
      }

    //    Capstone C65 HeatRecoveryRate_vs_InletTemp,  !- Heat Recovery Rate Function of Inlet Water Temperature Curve Name
    // QuadraticCurves
    // mchpHR.setHeatRecoveryRateFunctionofInletWaterTemperatureCurve();
    if ((owo = workspaceObject.getTarget(Generator_MicroTurbineFields::HeatRecoveryRateFunctionofInletWaterTemperatureCurveName)))
      {
        if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
        {
          if( boost::optional<CurveQuadratic> curve = mo->optionalCast<CurveQuadratic>() )
          {
            mchpHR.setHeatRecoveryRateFunctionofInletWaterTemperatureCurve(curve.get());
          }
          else
          {
            LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Heat Recovery Rate Function of Part Load Ratio Curve Name");
          }
        }
      }

    //    Capstone C65 HeatRecoveryRate_vs_WaterFlow,  !- Heat Recovery Rate Function of Water Flow Rate Curve Name
    // QuadraticCurves
    // mchpHR.setHeatRecoveryRateFunctionofInletWaterFlowRateCurve();
    if( (owo = workspaceObject.getTarget(Generator_MicroTurbineFields::HeatRecoveryRateFunctionofWaterFlowRateCurveName)) )
      {
        if( boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(owo.get()) )
        {
          if( boost::optional<CurveQuadratic> curve = mo->optionalCast<CurveQuadratic>() )
          {
            mchpHR.setHeatRecoveryRateFunctionofWaterFlowRateCurve(curve.get());
          }
          else
          {
            LOG(Warn, workspaceObject.briefDescription() << " has a wrong type curve for field Heat Recovery Rate Function of Water Flow Rate Curve Name");
          }
        }
      }

    //    0.001577263,             !- Minimum Heat Recovery Water Flow Rate {m3/s}
    d = workspaceObject.getDouble(Generator_MicroTurbineFields::MinimumHeatRecoveryWaterFlowRate);
    if(d)
    {
      mchpHR.setMinimumHeatRecoveryWaterFlowRate(*d);
    }

    //    0.003785432,             !- Maximum Heat Recovery Water Flow Rate {m3/s}
    d = workspaceObject.getDouble(Generator_MicroTurbineFields::MaximumHeatRecoveryWaterFlowRate);
    if(d)
    {
      mchpHR.setMaximumHeatRecoveryWaterFlowRate(*d);
    }

    //    82.2,                    !- Maximum Heat Recovery Water Temperature {C}
    d = workspaceObject.getDouble(Generator_MicroTurbineFields::MaximumHeatRecoveryWaterTemperature);
    if(d)
    {
      mchpHR.setMaximumHeatRecoveryWaterTemperature(*d);
    }


  }


  result=mchp;
  return result;
}
OptionalModelObject ReverseTranslator::translateFenestrationSurfaceDetailed( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::FenestrationSurface_Detailed ){
    LOG(Error, "WorkspaceObject is not IddObjectType: Site:FenestrationSurface_Detailed");
    return boost::none;
  }

  openstudio::Point3dVector vertices = getVertices(FenestrationSurface_DetailedFields::NumberofVertices + 1, workspaceObject);
 
  boost::optional<SubSurface> subSurface;
  try{
    subSurface = SubSurface(vertices, m_model);
  }catch(const std::exception&){
    LOG(Error, "Cannot create SubSurface for object: " << workspaceObject);
    return boost::none;
  }

  OptionalString s = workspaceObject.name();
  if(s) {
    subSurface->setName(*s);
  }

  OptionalWorkspaceObject target = workspaceObject.getTarget(openstudio::FenestrationSurface_DetailedFields::ConstructionName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ConstructionBase>()){
        subSurface->setConstruction(modelObject->cast<ConstructionBase>());
      }
    }
  }

  target = workspaceObject.getTarget(openstudio::FenestrationSurface_DetailedFields::BuildingSurfaceName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<Surface>()){
        subSurface->setSurface(modelObject->cast<Surface>());
      }
    }
  }

  // needs to be after .setSurface.
  s = workspaceObject.getString(FenestrationSurface_DetailedFields::SurfaceType);
  if (s) {
    if (istringEqual("Window", *s)){
      s = "FixedWindow";

      boost::optional<Surface> surface = subSurface->surface();
      if (surface){
        if ((surface->surfaceType() == "RoofCeiling") &&
            (surface->outsideBoundaryCondition() == "Outdoors")){
              s = "Skylight";
        }
      }
    }
    subSurface->setSubSurfaceType(*s);
  }

  target = workspaceObject.getTarget(openstudio::FenestrationSurface_DetailedFields::OutsideBoundaryConditionObject);
  if (target){
    if (target->iddObject().type() == IddObjectType::Zone){
      // Zone boundary condition

      OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
      if(modelObject->optionalCast<Space>()){
        Space adjacentSpace = modelObject->cast<Space>();

        OptionalSurface surface = subSurface->surface();
        if (surface && surface->space()){
          Space space = surface->space().get();

          if (surface->adjacentSurface()){
            Surface adjacentSurface = surface->adjacentSurface().get();

            if (adjacentSurface.space() && adjacentSpace.handle() == adjacentSurface.space()->handle()){
              Transformation transformation = adjacentSpace.transformation().inverse()*surface->space()->transformation();

              // duplicate subsurface in other space
              SubSurface adjacentSubSurface = subSurface->clone(m_model).cast<SubSurface>();
              adjacentSubSurface.setName(subSurface->name().get() + " Reversed");
              std::reverse(vertices.begin(), vertices.end());
              adjacentSubSurface.setVertices(transformation*vertices);
              adjacentSubSurface.setSurface(adjacentSurface);
              subSurface->setAdjacentSubSurface(adjacentSubSurface);

              return subSurface.get();
            }
          }
        }
      }

    }else if (target->iddObject().type() == IddObjectType::FenestrationSurface_Detailed){
      // SubSurface boundary condition

      // see if we have already mapped other sub surface, don't do it here because that is circular
      auto it = m_workspaceToModelMap.find(target->handle());
      if( it !=  m_workspaceToModelMap.end()){
        if (it->second.optionalCast<SubSurface>()){
          // this will set other side boundary object on both surfaces
          SubSurface adjacentSubSurface = it->second.cast<SubSurface>();
          subSurface->setAdjacentSubSurface(adjacentSubSurface);
          return subSurface.get();
        }
      }
    }else{  
      LOG(Error, "OutsideBoundaryConditionObject not yet mapped for object of type " << target->iddObject().name());
    }
  }

  // DLM: should these be before control paths that return above?
  OptionalDouble d = workspaceObject.getDouble(FenestrationSurface_DetailedFields::ViewFactortoGround);
  if (d) {
    subSurface->setViewFactortoGround(*d);
  }

  target = workspaceObject.getTarget(openstudio::FenestrationSurface_DetailedFields::ShadingControlName);
  if (target){
    LOG(Warn, "Shading Control Name not yet mapped for FenestrationSurface:Detailed");
  }

  target = workspaceObject.getTarget(openstudio::FenestrationSurface_DetailedFields::FrameandDividerName);
  if (target){
    LOG(Warn, "Frame and Divider Name not yet mapped for FenestrationSurface:Detailed");
  }

  OptionalInt i = workspaceObject.getInt(FenestrationSurface_DetailedFields::Multiplier);
  if (i) {
    subSurface->setMultiplier(*i);
  }

  return subSurface.get();
}
OptionalModelObject ReverseTranslator::translateDesignSpecificationOutdoorAir( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::DesignSpecification_OutdoorAir ){
    LOG(Error, "WorkspaceObject is not IddObjectType: DesignSpecification:OutdoorAir");
    return boost::none;
  }

  OptionalString outdoorAirMethod = workspaceObject.getString(DesignSpecification_OutdoorAirFields::OutdoorAirMethod, true);
  if (!outdoorAirMethod){
    LOG(Error, "No OutdoorAirMethod specified for DesignSpecification:OutdoorAir named '" << workspaceObject.name().get() << "'");
    return boost::none;
  }

  DesignSpecificationOutdoorAir result(m_model);

  OptionalString name = workspaceObject.name();
  if(name){
    result.setName(*name);
  }

  result.setOutdoorAirMethod(*outdoorAirMethod);

  boost::optional<double> flowPerPerson = workspaceObject.getDouble(DesignSpecification_OutdoorAirFields::OutdoorAirFlowperPerson);
  boost::optional<double> flowPerArea = workspaceObject.getDouble(DesignSpecification_OutdoorAirFields::OutdoorAirFlowperZoneFloorArea);
  boost::optional<double> flowPerZone = workspaceObject.getDouble(DesignSpecification_OutdoorAirFields::OutdoorAirFlowperZone);
  boost::optional<double> ach = workspaceObject.getDouble(DesignSpecification_OutdoorAirFields::OutdoorAirFlowAirChangesperHour);

  if (istringEqual(*outdoorAirMethod, "Flow/Person")){
    if (flowPerPerson){
      result.setOutdoorAirFlowperPerson(*flowPerPerson);
    }
  }else if (istringEqual(*outdoorAirMethod, "Flow/Area")){
    if (flowPerArea){
      result.setOutdoorAirFlowperFloorArea(*flowPerArea);
    }
  }else if (istringEqual(*outdoorAirMethod, "Flow/Zone")){
    if (flowPerZone){
      result.setOutdoorAirFlowRate(*flowPerZone);
    }
  }else if (istringEqual(*outdoorAirMethod, "AirChanges/Hour")){
    if (ach){
      result.setOutdoorAirFlowRate(*ach);
    }
  }else if (istringEqual(*outdoorAirMethod, "Sum") || istringEqual(*outdoorAirMethod, "Maximum")){

    if (flowPerPerson){
      result.setOutdoorAirFlowperPerson(*flowPerPerson);
    }
    if (flowPerArea){
      result.setOutdoorAirFlowperFloorArea(*flowPerArea);
    }
    if (flowPerZone){
      result.setOutdoorAirFlowRate(*flowPerZone);
    }
    if (ach){
      result.setOutdoorAirFlowRate(*ach);
    }

  }else{
    LOG(Error, "Unknown OutdoorAirMethod '" << *outdoorAirMethod << "' specified for DesignSpecification:OutdoorAir named '" << workspaceObject.name().get() << "'");
  }

  OptionalWorkspaceObject target = workspaceObject.getTarget(DesignSpecification_OutdoorAirFields::OutdoorAirFlowRateFractionScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (OptionalSchedule intermediate = modelObject->optionalCast<Schedule>()){
        Schedule schedule = *intermediate;
        result.setOutdoorAirFlowRateFractionSchedule(schedule);
      }
    }
  }

  return result;
}
OptionalModelObject ReverseTranslator::translateCoilHeatingGas( const WorkspaceObject & workspaceObject )
{
  OptionalModelObject result,temp;

  OptionalSchedule schedule;

 //get the Schedule
  OptionalWorkspaceObject owo = workspaceObject.getTarget(Coil_Heating_GasFields::AvailabilityScheduleName);
  if(!owo)
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             << " Can't find Schedule.");
    return result;
  }
  temp = translateAndMapWorkspaceObject(*owo);
  if(temp)
  {
    schedule=temp->optionalCast<Schedule>();
  }

  if( !schedule  )
  {
    LOG(Error, "Error importing object: "
             << workspaceObject.briefDescription()
             <<"Failed to convert iddObject (schedule) into ModelObject. Maybe it does not exist in model yet");
    return result;
  }

  try {

    openstudio::model::CoilHeatingGas coil( m_model,
                                            *schedule );
    OptionalString optS = workspaceObject.name();
    if(optS)
    {
      coil.setName(*optS);
    }
    OptionalDouble d;
    d = workspaceObject.getDouble(openstudio::Coil_Heating_GasFields::GasBurnerEfficiency);
    if(d)
    {
      coil.setGasBurnerEfficiency(*d);
    }
    d = workspaceObject.getDouble(openstudio::Coil_Heating_GasFields::NominalCapacity);
    if(d)
    {
      coil.setNominalCapacity(*d);
    }
    //skip inlet and outlet node names. That should be done FOR us by the AirLoop Translator.
    d = workspaceObject.getDouble(openstudio::Coil_Heating_GasFields::GasBurnerEfficiency);
    if(d)
    {
      coil.setGasBurnerEfficiency(*d);
    }

    d = workspaceObject.getDouble(openstudio::Coil_Heating_GasFields::NominalCapacity);
    if(d)
    {
      coil.setNominalCapacity(*d);
    }

    d = workspaceObject.getDouble(openstudio::Coil_Heating_GasFields::ParasiticElectricLoad);
    if(d)
    {
      coil.setParasiticElectricLoad(*d);
    }
    d = workspaceObject.getDouble(openstudio::Coil_Heating_GasFields::ParasiticGasLoad);
    if(d)
    {
      coil.setParasiticGasLoad(*d);
    }
    result = coil;
  }
  catch (std::exception& e) {
    LOG(Error,"Unable to reverse translate " << workspaceObject.briefDescription() << ", because "
        << e.what() << ".");
    return false;
  }

  return result;
}