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

  openstudio::model::SpaceType spaceType( m_model );

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

  for (const IdfExtensibleGroup& idfGroup : workspaceObject.extensibleGroups()){
    WorkspaceExtensibleGroup workspaceGroup = idfGroup.cast<WorkspaceExtensibleGroup>();
    
    OptionalWorkspaceObject target = workspaceGroup.getTarget(0);
    if (target){
      OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
      if (modelObject){
        if (modelObject->optionalCast<Space>()){
          Space space = modelObject->cast<Space>();

          if (space.spaceType()){
            LOG(Warn, "Overriding previously assigned SpaceType for Space '" << space.name().get() << "'");
          }

          space.setSpaceType(spaceType);

        }
      }
    }
  }

  return spaceType;
}
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::translateSizingPeriodDesignDay( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::SizingPeriod_DesignDay )
  {
     LOG(Error, "WorkspaceObject is not IddObjectType: SizingPeriod_DesignDay");
     return boost::none;
  }

  DesignDay designDay(m_model);

  // Name
  boost::optional<std::string> s = workspaceObject.getString(SizingPeriod_DesignDayFields::Name);
  if( s ){
    designDay.setName(s.get());
  }else{
    LOG(Error, "SizingPeriod:DesignDay missing required field Name");
  }

  // Month
  boost::optional<int> i = workspaceObject.getInt(SizingPeriod_DesignDayFields::Month);
  if( i ){
    designDay.setMonth( i.get() );
  }else{
    LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Month");
  }

  // Day of Month
  i = workspaceObject.getInt(SizingPeriod_DesignDayFields::DayofMonth);
  if( i ){
    designDay.setDayOfMonth(i.get());
  }else{
    LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Day of Month");
  }

  // Day Type
  s = workspaceObject.getString(SizingPeriod_DesignDayFields::DayType);
  if( s ){
    designDay.setDayType(s.get());
  }else{
    LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Day Type");
  }

  // Maximum Dry-Bulb Temperature
  boost::optional<double> value = workspaceObject.getDouble(SizingPeriod_DesignDayFields::MaximumDryBulbTemperature);
  if( value ){
    designDay.setMaximumDryBulbTemperature(value.get());
  }else{
    LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Maximum Dry Bulb Temperature");
  }

  // Dry-Bulb Temperature Range Modifier Type
  s = workspaceObject.getString(SizingPeriod_DesignDayFields::DryBulbTemperatureRangeModifierType);
  if( s ){
    designDay.setDryBulbTemperatureRangeModifierType(s.get());
  }
  std::string dryBulbTemperatureRangeModifierType = designDay.dryBulbTemperatureRangeModifierType();

  // Daily Dry-Bulb Temperature Range
  if (!istringEqual(dryBulbTemperatureRangeModifierType, "DifferenceSchedule")){
    value = workspaceObject.getDouble(SizingPeriod_DesignDayFields::DailyDryBulbTemperatureRange);
    if( value ){
      designDay.setDailyDryBulbTemperatureRange(value.get()); 
    }
  }

  // Dry-Bulb Temperature Range Modifier Schedule Name
  if (istringEqual(dryBulbTemperatureRangeModifierType, "MultiplierSchedule") || istringEqual(dryBulbTemperatureRangeModifierType, "DifferenceSchedule")){
    boost::optional<WorkspaceObject> wo = workspaceObject.getTarget(SizingPeriod_DesignDayFields::DryBulbTemperatureRangeModifierDayScheduleName);
    if( wo ){
      boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get());
      if( mo ){
        if(boost::optional<ScheduleDay> schedule = mo->optionalCast<ScheduleDay>()){
          designDay.setDryBulbTemperatureRangeModifierSchedule(*schedule);
        }
      }
    }

    if (!designDay.dryBulbTemperatureRangeModifierSchedule()){
      LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Maximum Dry Bulb Temperature");
    }
  }

  // Humidity Condition Type
  s = workspaceObject.getString(SizingPeriod_DesignDayFields::HumidityConditionType);
  if( s ){
    if (istringEqual(*s, "RelativeHumiditySchedule")){
      s = "Schedule";
    }
    designDay.setHumidityIndicatingType(s.get());
  }
  std::string humidityIndicatingType = designDay.humidityIndicatingType();

  // Wetbulb or DewPoint at Maximum Dry-Bulb
  if (istringEqual(humidityIndicatingType, "Wetbulb") ||
      istringEqual(humidityIndicatingType, "Dewpoint") ||
      istringEqual(humidityIndicatingType, "WetBulbProfileMultiplierSchedule") ||
      istringEqual(humidityIndicatingType, "WetBulbProfileDifferenceSchedule") ||
      istringEqual(humidityIndicatingType, "WetBulbProfileDefaultMultipliers")){
    value = workspaceObject.getDouble(SizingPeriod_DesignDayFields::WetbulborDewPointatMaximumDryBulb);
    if( value ){
      // units for this field are C
      designDay.setHumidityIndicatingConditionsAtMaximumDryBulb(value.get());
    }else{
      LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Wetbulb or Dew Point at Maximum Dry Bulb");
    }
  }

  // Humidity Condition Day Schedule Name
  if (istringEqual(humidityIndicatingType, "RelativeHumiditySchedule") ||
      istringEqual(humidityIndicatingType, "WetBulbProfileMultiplierSchedule") ||
      istringEqual(humidityIndicatingType, "WetBulbProfileDifferenceSchedule") ||
      istringEqual(humidityIndicatingType, "RelativeHumiditySchedule")){
    
    boost::optional<WorkspaceObject> wo = workspaceObject.getTarget(SizingPeriod_DesignDayFields::HumidityConditionDayScheduleName);
    if( wo ){
      boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get());
      if( mo ){
        boost::optional<ScheduleDay> schedule = mo->optionalCast<ScheduleDay>();
        if( schedule ){
          designDay.setHumidityIndicatingDaySchedule(schedule.get());
        }
      }
    }

    if (!designDay.humidityIndicatingDaySchedule()){
      LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Humidity Indicating Day Schedule Name");
    }
  }

  // Humidity Ratio at Maximum Dry-Bulb
  if (istringEqual(humidityIndicatingType, "HumidityRatio")){
    // units for this field are kgWater/kgDryAir
    value = workspaceObject.getDouble(SizingPeriod_DesignDayFields::HumidityRatioatMaximumDryBulb);
    if( value ){
      designDay.setHumidityIndicatingConditionsAtMaximumDryBulb(value.get());
    }else{
      LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Humidity Ratio at Maximum Dry Bulb");
    }
  }

  // Enthalpy at Maximum Dry-Bulb
  if (istringEqual(humidityIndicatingType, "Enthalpy")){
    // units for this field are J/kg
    value = workspaceObject.getDouble(SizingPeriod_DesignDayFields::EnthalpyatMaximumDryBulb);
    if( value ){
      designDay.setHumidityIndicatingConditionsAtMaximumDryBulb(value.get());
    }else{
      LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Enthalpy at Maximum Dry Bulb");
    }
  }

  // Daily Wet-Bulb Temperature Range
  if (istringEqual(humidityIndicatingType, "WetbulbProfileMultiplierSchedule") ||
      istringEqual(humidityIndicatingType, "WetBulbProfileDefaultMultipliers")){
    value = workspaceObject.getDouble(SizingPeriod_DesignDayFields::DailyWetBulbTemperatureRange);
    if (value) {
      designDay.setDailyWetBulbTemperatureRange(*value);
    }else{
      LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Daily Wet Bulb Temperature Range");
    }
  }

  // Barometric Pressure
  value = workspaceObject.getDouble(SizingPeriod_DesignDayFields::BarometricPressure);
  if( value ){
    designDay.setBarometricPressure(value.get());
  }

  // Site Wind Speed
  value = workspaceObject.getDouble(SizingPeriod_DesignDayFields::WindSpeed);
  if( value ){
    designDay.setWindSpeed(value.get());
  }else{
    LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Site Wind Speed");
  }

  // Site Wind Direction
  value = workspaceObject.getDouble(SizingPeriod_DesignDayFields::WindDirection);
  if( value ){
    designDay.setWindDirection(value.get());
  }else{
    LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Site Wind Direction");
  }

  // Rain Indicator
  s = workspaceObject.getString(SizingPeriod_DesignDayFields::RainIndicator);
  if( s ){
    if( istringEqual(*s, "Yes") ){
      designDay.setRainIndicator(true);
    }else{
      designDay.setRainIndicator(false);
    }
  }

  // Snow Indicator
  s = workspaceObject.getString(SizingPeriod_DesignDayFields::SnowIndicator);
  if( s ){
    if( istringEqual(*s, "Yes") ){
      designDay.setSnowIndicator(true);
    }else{
      designDay.setSnowIndicator(false);
    }
  }

  // Site Daylight Saving Time Status
  s = workspaceObject.getString(SizingPeriod_DesignDayFields::DaylightSavingTimeIndicator);
  if( s ){
    if( istringEqual(*s, "Yes") ){
      designDay.setDaylightSavingTimeIndicator(true);
    }else{
      designDay.setDaylightSavingTimeIndicator(false);
    }
  }

  // Solar Model Indicator
  s = workspaceObject.getString(SizingPeriod_DesignDayFields::SolarModelIndicator);
  if( s ){
    designDay.setSolarModelIndicator(s.get());
  }
  std::string solarModelIndicator = designDay.solarModelIndicator();

  // Beam Solar Day Schedule Name and Site Diffuse Solar Radiation Rate per Area Radiation Rate per Area Day Schedule Name
  if (istringEqual(solarModelIndicator, "Schedule")){

    // Beam Solar Day Schedule Name
    boost::optional<WorkspaceObject> wo = workspaceObject.getTarget(SizingPeriod_DesignDayFields::BeamSolarDayScheduleName);
    if( wo ){
      boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get());
      if( mo ){
        boost::optional<ScheduleDay> schedule = mo->optionalCast<ScheduleDay>();
        if( schedule ){
          designDay.setBeamSolarDaySchedule(schedule.get());
        }
      }
    }
    if (!designDay.beamSolarDaySchedule()){
      LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Beam Solar Day Schedule Name");
    }

    // Site Diffuse Solar Radiation Rate per Area Radiation Rate per Area Day Schedule Name
    wo = workspaceObject.getTarget(SizingPeriod_DesignDayFields::DiffuseSolarDayScheduleName);
    if( wo ){
      boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get());
      if( mo ){
        boost::optional<ScheduleDay> schedule = mo->optionalCast<ScheduleDay>();
        if( schedule ){
          designDay.setDiffuseSolarDaySchedule(schedule.get());
        }
      }
    }
    if (!designDay.diffuseSolarDaySchedule()){
      LOG(Error, "SizingPeriod:DesignDay " << designDay.name().get() << " missing required field Diffuse Solar Schedule Name");
    }
  }

  if (istringEqual(solarModelIndicator, "ASHRAETau")){
    //  ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub)
    value = workspaceObject.getDouble(SizingPeriod_DesignDayFields::ASHRAEClearSkyOpticalDepthforBeamIrradiance_taub_);
    if (value) {
      designDay.setAshraeTaub(*value);
    }

    // ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud)
    value = workspaceObject.getDouble(SizingPeriod_DesignDayFields::ASHRAEClearSkyOpticalDepthforDiffuseIrradiance_taud_);
    if (value) {
      designDay.setAshraeTaud(*value);
    }
  }

  // Sky Clearness
  if (istringEqual(solarModelIndicator, "ASHRAEClearSky") || istringEqual(solarModelIndicator, "ZhangHuang")){
    value = workspaceObject.getDouble(SizingPeriod_DesignDayFields::SkyClearness);
    if( value ){
      designDay.setSkyClearness(value.get());
    }
  }

  return designDay;
}
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::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::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::translateEnergyManagementSystemSubroutine(const WorkspaceObject & workspaceObject)
{
  if (workspaceObject.iddObject().type() != IddObjectType::EnergyManagementSystem_Subroutine) {
    LOG(Error, "WorkspaceObject is not IddObjectType: EnergyManagementSystem_Subroutine");
    return boost::none;
  }

  OptionalString s = workspaceObject.getString(EnergyManagementSystem_SubroutineFields::Name);
  if (!s) {
    LOG(Error, "WorkspaceObject EnergyManagementSystem_Subroutine has no Name");
    return boost::none;
  }

  // Make sure we translate the objects that can be referenced here
  for (const WorkspaceObject& workspaceObject : m_workspace.objects()) {

    // Note: JM 2018-08-17
    // I think an EMS:Subroutine can reference another EMS:Subroutine, we might get problems from that:
    // The one that is being referenced would need be translated before the one that references before the name/uuid substitution happen.
    // But it's harder to control that order*, and this is really an edge case though, so not handling it.
    // * Can't add this condition without getting into a loop:
    // (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_Subroutine)
    if (
        // These I'm sure we do need.
        (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_Actuator)
        || (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_Sensor)
        || (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_ConstructionIndexVariable)
        || (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_CurveOrTableIndexVariable)
        || (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_GlobalVariable)
        || (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_InternalVariable)
        || (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_TrendVariable)
       ) {
      translateAndMapWorkspaceObject(workspaceObject);
    }
  }
  openstudio::model::EnergyManagementSystemSubroutine emsProgram(m_model);
  emsProgram.setName(*s);

  // Get all model objects that can be referenced int he EMS Program so we can do name / uid substitution
  const std::vector<IddObjectType> validIddObjectTypes{
    IddObjectType::OS_EnergyManagementSystem_Subroutine,
    IddObjectType::OS_EnergyManagementSystem_Actuator,
    IddObjectType::OS_EnergyManagementSystem_Sensor,
    IddObjectType::OS_EnergyManagementSystem_ConstructionIndexVariable,
    IddObjectType::OS_EnergyManagementSystem_CurveOrTableIndexVariable,
    IddObjectType::OS_EnergyManagementSystem_GlobalVariable,
    IddObjectType::OS_EnergyManagementSystem_InternalVariable,
    IddObjectType::OS_EnergyManagementSystem_TrendVariable
  };

  std::vector<model::ModelObject> modelObjects;
  for (const model::ModelObject& mo: m_model.modelObjects()) {
    if( std::find(validIddObjectTypes.begin(), validIddObjectTypes.end(), mo.iddObjectType()) != validIddObjectTypes.end() ) {
      modelObjects.push_back(mo);
    }
  }


  // Now, we should do the actual name/uid substitution on all lines of the program

  size_t pos, len;
  std::string newline, uid;

  unsigned n = workspaceObject.numExtensibleGroups();
  OptionalString line;

  // Loop on each line of the program
  for (unsigned i = 0; i < n; ++i) {
    line = workspaceObject.getExtensibleGroup(i).cast<WorkspaceExtensibleGroup>().getString(EnergyManagementSystem_SubroutineExtensibleFields::ProgramLine);
    if (line) {
      newline = line.get();

      // Split line to get 'tokens' and look for ModelObject names
      // splitEMSLineToTokens returns already sanitized tokens (excludes reserved keywords, blank ones, functions, removes parenthesis, etc)
      std::vector<std::string> tokens = splitEMSLineToTokens(newline);

      for (std::string& token: tokens) {
        for (const model::ModelObject& mo: modelObjects) {
          // Check if program item is the name of a model object
          boost::optional<std::string> _name = mo.name();
          if ( _name && (_name.get() == token) ) {
            // replace model object's name with its handle
            pos = newline.find(token);
            len = token.length();
            uid = toString(mo.handle());
            newline.replace(pos, len, uid);
            // Now that we have done the replacement, no need to keep looping.
            // Plus, we should break out of the nested loop and go to the next "j"
            // Otherwise pos could become giberish if there's another object named the same
            // since it won't be able to find the already-replaced string (this shouldn't happen though)
            break;
          }
        } // end loop on all modelObjects

      } // end loop on all results in line
      emsProgram.addLine(newline);
    } // end if(line)
  } // End loop on each line of the program

  return emsProgram;

}
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::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;
}
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::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;
  }
}
boost::optional<ModelObject> ReverseTranslator::translateAndMapWorkspaceObject(const WorkspaceObject & workspaceObject)
{
  auto i = m_workspaceToModelMap.find(workspaceObject.handle());

  boost::optional<ModelObject> modelObject;

  if( i !=  m_workspaceToModelMap.end())
  {
    return boost::optional<ModelObject>(i->second);
  }

  LOG(Trace,"Translating " << workspaceObject.briefDescription() << ".");

  // DLM: the scope of this translator is being changed, we now only import objects from idf
  // in the geometry, loads, resources, and general simulation control portions of the model.
  // Users can add idf objects to their model using idf measures.  Only objects viewable in the
  // current GUIs should be imported, I am making an exception for curves.

  bool addToUntranslated = true;

  switch(workspaceObject.iddObject().type().value())
  {
  case openstudio::IddObjectType::AirLoopHVAC :
    {
      //modelObject = translateAirLoopHVAC(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::AirLoopHVAC_ControllerList :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::AirLoopHVAC_OutdoorAirSystem :
    {
      //modelObject = translateAirLoopHVACOutdoorAirSystem(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::AirLoopHVAC_OutdoorAirSystem_EquipmentList :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::AirLoopHVAC_ReturnPath :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::CoilSystem_Cooling_DX :
    {
      //modelObject = translateCoilSystemCoolingDX(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::AirLoopHVAC_ZoneSplitter :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::AirTerminal_SingleDuct_ConstantVolume_Reheat :
    {
      modelObject = translateAirTerminalSingleDuctConstantVolumeReheat(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::AirTerminal_SingleDuct_Uncontrolled :
    {
      //modelObject = translateAirTerminalSingleDuctUncontrolled(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::AirTerminal_SingleDuct_VAV_NoReheat :
    {
      modelObject = translateAirTerminalSingleDuctVAVNoReheat(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::AirTerminal_SingleDuct_VAV_Reheat :
    {
      //modelObject = translateAirTerminalSingleDuctVAVReheat(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::AvailabilityManagerAssignmentList :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::Branch :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::BranchList :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::BuildingSurface_Detailed :
    {
      modelObject = translateBuildingSurfaceDetailed(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::Building :
    {
      modelObject = translateBuilding(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::Coil_Heating_Fuel :
    {
      //modelObject = translateCoilHeatingGas(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::Coil_Cooling_DX_SingleSpeed :
    {
      //modelObject = translateCoilCoolingDXSingleSpeed(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::CommentOnly :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::ComponentCost_LineItem :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::Connector_Mixer :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::Connector_Splitter :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::ConnectorList :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::Construction :
    {
      modelObject = translateConstruction(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Controller_OutdoorAir :
    {
      //modelObject = translateControllerOutdoorAir(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::ConvergenceLimits :
    {
      modelObject = translateConvergenceLimits(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_Bicubic :
    {
      modelObject = translateCurveBicubic(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_Biquadratic :
    {
      modelObject = translateCurveBiquadratic(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_Cubic :
    {
      modelObject = translateCurveCubic(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_DoubleExponentialDecay :
    {
      modelObject = translateCurveDoubleExponentialDecay(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_ExponentialSkewNormal :
    {
      modelObject = translateCurveExponentialSkewNormal(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_FanPressureRise :
    {
      modelObject = translateCurveFanPressureRise(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_Functional_PressureDrop :
    {
      modelObject = translateCurveFunctionalPressureDrop(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_Linear :
    {
      modelObject = translateCurveLinear(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_Quadratic :
    {
      modelObject = translateCurveQuadratic(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_QuadraticLinear :
    {
      modelObject = translateCurveQuadraticLinear(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_Quartic :
    {
      modelObject = translateCurveQuartic(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_RectangularHyperbola1 :
    {
      modelObject = translateCurveRectangularHyperbola1(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_RectangularHyperbola2 :
    {
      modelObject = translateCurveRectangularHyperbola2(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_Sigmoid :
    {
      modelObject = translateCurveSigmoid(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Curve_Triquadratic :
    {
      modelObject = translateCurveTriquadratic(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Daylighting_Controls :
    {
      modelObject = translateDaylightingControls(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::DesignSpecification_OutdoorAir :
    {
      // Call this directly because we don't want to translate all of them
      // only those that are connected to the SizingZone object
      //modelObject = translateDesignSpecificationOutdoorAir(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::ElectricEquipment :
    {
      modelObject = translateElectricEquipment(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::Exterior_Lights :
    {
      //modelObject = translateExteriorLights(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::ElectricLoadCenter_Storage_Simple :
    {
      modelObject = translateElectricLoadCenterStorageSimple(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::ElectricLoadCenter_Storage_Converter :
    {
      modelObject = translateElectricLoadCenterStorageConverter(workspaceObject);
      break;
    }  
  case openstudio::IddObjectType::EvaporativeCooler_Direct_ResearchSpecial :
    {
      //modelObject = translateEvaporativeCoolerDirectResearchSpecial(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::EvaporativeFluidCooler_SingleSpeed :
    {
      modelObject = translateEvaporativeFluidCoolerSingleSpeed(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Fan_ConstantVolume :
    {
      //modelObject = translateFanConstantVolume(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::FenestrationSurface_Detailed :
    {
      modelObject = translateFenestrationSurfaceDetailed(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Generator_MicroTurbine :
    {
      modelObject = translateGeneratorMicroTurbine(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::GlobalGeometryRules :
    {
      // added by geometry translator, do not add to untranslated objects
      addToUntranslated = false;
      break; // no-op
    }
  case openstudio::IddObjectType::GasEquipment :
    {
      modelObject = translateGasEquipment(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::GroundHeatExchanger_Vertical :
    {
      //modelObject = translateGroundHeatExchangerVertical(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::HeatBalanceAlgorithm :
    {
      modelObject = translateHeatBalanceAlgorithm(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::HotWaterEquipment :
    {
      modelObject = translateHotWaterEquipment(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::HVACTemplate_Thermostat :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::InternalMass :
    {
      modelObject = translateInternalMass(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::Lights :
    {
      modelObject = translateLights(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::Material :
    {
      modelObject = translateMaterial(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Material_AirGap :
    {
      modelObject = translateMaterialAirGap(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Material_NoMass :
    {
      modelObject = translateMaterialNoMass(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Meter_Custom :
    {
      modelObject = translateMeterCustom(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Meter_CustomDecrement :
    {
      modelObject = translateMeterCustomDecrement(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::OtherEquipment :
    {
      modelObject = translateOtherEquipment(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::OutdoorAir_Mixer :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::OutdoorAir_Node :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::OutdoorAir_NodeList :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::Output_IlluminanceMap :
    {
      modelObject = translateOutputIlluminanceMap(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Output_Meter :
    {
      modelObject = translateOutputMeter(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Output_Meter_Cumulative :
    {
      modelObject = translateOutputMeterCumulative(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Output_Meter_Cumulative_MeterFileOnly :
    {
      modelObject = translateOutputMeterCumulativeMeterFileOnly(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Output_Meter_MeterFileOnly :
    {
      modelObject = translateOutputMeterMeterFileOnly(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Output_SQLite :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::Output_Table_Monthly :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::Output_Table_SummaryReports :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::Output_Variable :
    {
      modelObject = translateOutputVariable(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::OutputControl_Table_Style :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::People :
    {
      modelObject = translatePeople(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Refrigeration_Case :
    {
      // modelObject = translateRefrigerationCase(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Refrigeration_Compressor :
    {
      // modelObject = translateRefrigerationCompressor(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::RunPeriod :
    {
      modelObject = translateRunPeriod(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::RunPeriodControl_DaylightSavingTime :
    {
      modelObject = translateRunPeriodControlDaylightSavingTime(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::RunPeriodControl_SpecialDays :
    {
      //modelObject = translateRunPeriodControlSpecialDays(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Schedule_Compact :
    {
      modelObject = translateScheduleCompact(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Schedule_Constant :
    {
      modelObject = translateScheduleConstant(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Schedule_Day_Hourly :
    {
      modelObject = translateScheduleDayHourly(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Schedule_Day_Interval :
    {
      modelObject = translateScheduleDayInterval(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::ScheduleTypeLimits :
    {
      modelObject = translateScheduleTypeLimits(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Schedule_Week_Daily :
    {
      modelObject = translateScheduleWeekDaily(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Schedule_Year :
    {
      modelObject = translateScheduleYear(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::SetpointManager_MixedAir :
    {
      //modelObject = translateSetpointManagerMixedAir(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::SetpointManager_Scheduled :
    {
      //modelObject = translateSetpointManagerScheduled(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::SetpointManager_SingleZone_Reheat :
    {
      //modelObject = translateSetpointManagerSingleZoneReheat(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Shading_Building_Detailed :
    {
      modelObject = translateShadingBuildingDetailed(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Shading_Site_Detailed :
    {
      modelObject = translateShadingSiteDetailed(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Shading_Zone_Detailed :
    {
      modelObject = translateShadingZoneDetailed(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::ShadowCalculation :
    {
      modelObject = translateShadowCalculation(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::SimulationControl :
    {
      modelObject = translateSimulationControl(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::Site_Location :
    {
      modelObject = translateSiteLocation(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Site_GroundReflectance :
    {
      //modelObject = translateSiteGroundReflectance(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Site_GroundTemperature_BuildingSurface :
    {
      //modelObject = translateSiteGroundTemperatureBuildingSurface(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Site_WaterMainsTemperature :
    {
      //modelObject = translateSiteWaterMainsTemperature(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Sizing_Parameters :
    {
      modelObject = translateSizingParameters(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::SizingPeriod_DesignDay :
    {
      modelObject = translateSizingPeriodDesignDay(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::Sizing_System :
    {
      //modelObject = translateSizingSystem(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::Sizing_Zone :
    {
      modelObject = translateSizingZone(workspaceObject );
      break;
    }
  case openstudio::IddObjectType::SteamEquipment :
    {
      modelObject = translateSteamEquipment(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::SurfaceConvectionAlgorithm_Inside :
    {
      //modelObject = translateSurfaceConvectionAlgorithmInside(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::SurfaceConvectionAlgorithm_Outside :
    {
      //modelObject = translateSurfaceConvectionAlgorithmOutside(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::ThermostatSetpoint_DualSetpoint :
    {
      modelObject = translateThermostatSetpointDualSetpoint(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::Timestep :
    {
      modelObject = translateTimestep(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::UtilityCost_Charge_Simple :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::UtilityCost_Qualify :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::Version :
   {
     modelObject = translateVersion(workspaceObject );
     break;
   }
  case openstudio::IddObjectType::WindowMaterial_Gas:
    {
      modelObject = translateWindowMaterialGas(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::WindowMaterial_Glazing:
    {
      modelObject = translateWindowMaterialGlazing(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::WindowMaterial_SimpleGlazingSystem:
    {
      modelObject = translateWindowMaterialSimpleGlazingSystem(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::WindowProperty_FrameAndDivider:
  {
    modelObject = translateWindowPropertyFrameAndDivider(workspaceObject);
    break;
  }
  case openstudio::IddObjectType::Zone:
    {
      modelObject = translateZone(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::ZoneAirHeatBalanceAlgorithm:
    {
      // DLM: why is this commented out?
      //modelObject = translateZoneAirHeatBalanceAlgorithm(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::ZoneAirMassFlowConservation:
  {
    modelObject = translateZoneAirMassFlowConservation(workspaceObject);
    break;
  }
  case openstudio::IddObjectType::ZoneControl_Thermostat :
    {
      break; // no-op
    }
  case openstudio::IddObjectType::ZoneCrossMixing:
  {
    modelObject = translateZoneCrossMixing(workspaceObject);
    break;
  }
  case openstudio::IddObjectType::ZoneHVAC_EquipmentList :
    {
      //modelObject = translateZoneHVACEquipmentList(workspaceObject);
      break; 
    }
  case openstudio::IddObjectType::ZoneHVAC_IdealLoadsAirSystem :
    {
      //modelObject = translateZoneHVACIdealLoadsAirSystem(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::ZoneInfiltration_DesignFlowRate :
    {
      modelObject = translateZoneInfiltrationDesignFlowRate(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::ZoneInfiltration_EffectiveLeakageArea :
  {
      modelObject = translateZoneInfiltrationEffectiveLeakageArea(workspaceObject);
      break;
  }
  case openstudio::IddObjectType::ZoneList:
    {
      modelObject = translateZone(workspaceObject);
      break;
    }
  case openstudio::IddObjectType::ZoneMixing:
  {
    modelObject = translateZoneMixing(workspaceObject);
    break;
  }
  case openstudio::IddObjectType::ZoneVentilation_DesignFlowRate :
    {
      modelObject = translateZoneVentilationDesignFlowRate(workspaceObject);
      break;
    }
  default:
    {
      break; // no-op
    }
  }

  if( modelObject )
  {
    LOG(Trace,"Adding " << modelObject.get().briefDescription() << " to map.");
    m_workspaceToModelMap.insert(make_pair(workspaceObject.handle(), modelObject.get()));
  }else{
    if (addToUntranslated){
      if (std::find_if(m_untranslatedIdfObjects.begin(), m_untranslatedIdfObjects.end(), IdfObjectEqual(workspaceObject.idfObject())) == m_untranslatedIdfObjects.end()){
        LOG(Trace,"Ignoring " << workspaceObject.briefDescription() << ".");
        m_untranslatedIdfObjects.push_back(workspaceObject.idfObject());
      }
    }
  }

  if (m_progressBar){
    m_progressBar->setValue(m_untranslatedIdfObjects.size() + m_workspaceToModelMap.size());
  }

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

  Construction construction(m_model);
  OS_ASSERT(construction.numLayers() == 0u);
  OptionalString optS = workspaceObject.name();
  if (optS) {
    construction.setName(*optS);
  }

  unsigned n = workspaceObject.numExtensibleGroups();
  // now we get the workspace objects and try to find them and place them in the model object
  // Loop over all the fields except the first, which is the name
  OptionalWorkspaceObject owo;
  OptionalModelObject temp;
  for( unsigned i = 0; i < n; ++i) {
    owo = workspaceObject.getExtensibleGroup(i).cast<WorkspaceExtensibleGroup>().getTarget(ConstructionExtensibleFields::Layer);
    if( owo ) {
      temp = translateAndMapWorkspaceObject( *owo );
    }
    if( ! (owo && temp) )
    {
      LOG(Error, "Finding Construction Layer in workspace failed.");
      construction.remove();
      return boost::none;
    }
    // Assuming names of materials are unique
    OptionalMaterial mat = temp->optionalCast<Material>();

    bool inserted(false);
    if (mat) {
      OptionalOpaqueMaterial opaqueMaterial = mat->optionalCast<OpaqueMaterial>();
      if(opaqueMaterial) {
        inserted = construction.insertLayer(i, *opaqueMaterial);
      }
      else {
        OptionalFenestrationMaterial fenestrationMaterial = mat->optionalCast<FenestrationMaterial>();
        if (fenestrationMaterial) {
          inserted = construction.insertLayer(i, *fenestrationMaterial );
        }
        else {
          OptionalModelPartitionMaterial modelPartitionMaterial = mat->optionalCast<ModelPartitionMaterial>();
          if (modelPartitionMaterial) {
            if (construction.numLayers() == 0u) {
              inserted = construction.setLayer(*modelPartitionMaterial);
            }
          }
        }
      }
    }

    if( !inserted ) {
      LOG(Error, "Insertion of Construction Layer failed.");
      construction.remove();
      return boost::none;
    }
  }

  return construction;
}
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;
  }
}
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;
}
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;
}
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::translateSetpointManagerScheduled( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::SetpointManager_Scheduled )
  {
     LOG(Error, "WorkspaceObject is not IddObjectType: SetpointManager_Scheduled");
     return boost::none;
  }

  boost::optional<WorkspaceObject> wo = workspaceObject.getTarget(SetpointManager_ScheduledFields::ScheduleName);
  boost::optional<Schedule> schedule;

  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 schedule");

        return boost::none;
      }
    }
  }

  bool nodeFound = false;

  if( boost::optional<std::string> setpointNodeName = workspaceObject.getString(SetpointManager_ScheduledFields::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;
  }

  if( schedule )
  {
    SetpointManagerScheduled mo(m_model,schedule.get());

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

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

    // Control Variable
    s = workspaceObject.getString(SetpointManager_ScheduledFields::ControlVariable);
    if( s )
    {
      mo.setControlVariable(s.get());
    }

    if( mo.setpointNode() )
    {
      return mo;
    }
    else
    {
      return boost::none;
    }
  }
  else
  {
    return boost::none;
  }
}
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::translateScheduleWeekDaily(const WorkspaceObject & workspaceObject){
  if (workspaceObject.iddObject().type() != IddObjectType::Schedule_Week_Daily){
    LOG(Error, "WorkspaceObject is not IddObjectType: Schedule:Week");
    return boost::none;
  }

  // create the schedule
  ScheduleWeek scheduleWeek(m_model);

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

  OptionalWorkspaceObject target = workspaceObject.getTarget(Schedule_Week_DailyFields::SundaySchedule_DayName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ScheduleDay>()){
        scheduleWeek.setSundaySchedule(modelObject->cast<ScheduleDay>());
      }
    }
  }

  target = workspaceObject.getTarget(Schedule_Week_DailyFields::MondaySchedule_DayName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ScheduleDay>()){
        scheduleWeek.setMondaySchedule(modelObject->cast<ScheduleDay>());
      }
    }
  }

  target = workspaceObject.getTarget(Schedule_Week_DailyFields::TuesdaySchedule_DayName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ScheduleDay>()){
        scheduleWeek.setTuesdaySchedule(modelObject->cast<ScheduleDay>());
      }
    }
  }

  target = workspaceObject.getTarget(Schedule_Week_DailyFields::WednesdaySchedule_DayName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ScheduleDay>()){
        scheduleWeek.setWednesdaySchedule(modelObject->cast<ScheduleDay>());
      }
    }
  }
  
  target = workspaceObject.getTarget(Schedule_Week_DailyFields::ThursdaySchedule_DayName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ScheduleDay>()){
        scheduleWeek.setThursdaySchedule(modelObject->cast<ScheduleDay>());
      }
    }
  }

  target = workspaceObject.getTarget(Schedule_Week_DailyFields::FridaySchedule_DayName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ScheduleDay>()){
        scheduleWeek.setFridaySchedule(modelObject->cast<ScheduleDay>());
      }
    }
  }

  target = workspaceObject.getTarget(Schedule_Week_DailyFields::SaturdaySchedule_DayName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ScheduleDay>()){
        scheduleWeek.setSaturdaySchedule(modelObject->cast<ScheduleDay>());
      }
    }
  }

  target = workspaceObject.getTarget(Schedule_Week_DailyFields::HolidaySchedule_DayName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ScheduleDay>()){
        scheduleWeek.setHolidaySchedule(modelObject->cast<ScheduleDay>());
      }
    }
  }

  target = workspaceObject.getTarget(Schedule_Week_DailyFields::SummerDesignDaySchedule_DayName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ScheduleDay>()){
        scheduleWeek.setSummerDesignDaySchedule(modelObject->cast<ScheduleDay>());
      }
    }
  }

  target = workspaceObject.getTarget(Schedule_Week_DailyFields::WinterDesignDaySchedule_DayName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ScheduleDay>()){
        scheduleWeek.setWinterDesignDaySchedule(modelObject->cast<ScheduleDay>());
      }
    }
  }

  target = workspaceObject.getTarget(Schedule_Week_DailyFields::CustomDay1Schedule_DayName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ScheduleDay>()){
        scheduleWeek.setCustomDay1Schedule(modelObject->cast<ScheduleDay>());
      }
    }
  }

  target = workspaceObject.getTarget(Schedule_Week_DailyFields::CustomDay2Schedule_DayName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<ScheduleDay>()){
        scheduleWeek.setCustomDay2Schedule(modelObject->cast<ScheduleDay>());
      }
    }
  }

  return scheduleWeek;
}
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::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::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::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::translateZoneVentilationDesignFlowRate( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::ZoneVentilation_DesignFlowRate ){
    LOG(Error, "WorkspaceObject is not IddObjectType: ZoneVentilation:DesignFlowRate");
    return boost::none;
  }

  return boost::none;

/*
  openstudio::model::SpaceVentilationDesignFlowRate ventilation(m_model);
  
  OptionalString s = workspaceObject.name();
  if(s){
    ventilation.setName(*s);
  }

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

  target = workspaceObject.getTarget(openstudio::ZoneVentilation_DesignFlowRateFields::ScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<Schedule>()){
        ventilation.setSchedule(modelObject->cast<Schedule>());
      }
    }
  }

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

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

  s = workspaceObject.getString(openstudio::ZoneVentilation_DesignFlowRateFields::VentilationType);
  if (s){
    ventilation.setVentilationType(*s);
  }

  d = workspaceObject.getDouble(openstudio::ZoneVentilation_DesignFlowRateFields::FanPressureRise);
  if (d){
    ventilation.setFanPressureRise(*d);
  }
    
  d = workspaceObject.getDouble(openstudio::ZoneVentilation_DesignFlowRateFields::FanTotalEfficiency);
  if (d){
    ventilation.setFanTotalEfficiency(*d);
  }

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

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

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

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

  d = workspaceObject.getDouble(openstudio::ZoneVentilation_DesignFlowRateFields::MinimumIndoorTemperature);
  if (d){
    ventilation.setMinimumIndoorTemperature(*d);
  }

  target = workspaceObject.getTarget(openstudio::ZoneVentilation_DesignFlowRateFields::MinimumIndoorTemperatureScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<Schedule>()){
        ventilation.setMinimumIndoorTemperatureSchedule(modelObject->cast<Schedule>());
      }
    }
  }

  d = workspaceObject.getDouble(openstudio::ZoneVentilation_DesignFlowRateFields::MaximumIndoorTemperature);
  if (d){
    ventilation.setMaximumIndoorTemperature(*d);
  }

  target = workspaceObject.getTarget(openstudio::ZoneVentilation_DesignFlowRateFields::MaximumIndoorTemperatureScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<Schedule>()){
        ventilation.setMaximumIndoorTemperatureSchedule(modelObject->cast<Schedule>());
      }
    }
  }

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

  target = workspaceObject.getTarget(openstudio::ZoneVentilation_DesignFlowRateFields::DeltaTemperatureScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<Schedule>()){
        ventilation.setDeltaTemperatureSchedule(modelObject->cast<Schedule>());
      }
    }
  }

  d = workspaceObject.getDouble(openstudio::ZoneVentilation_DesignFlowRateFields::MinimumOutdoorTemperature);
  if (d){
    ventilation.setMinimumOutdoorTemperature(*d);
  }

  target = workspaceObject.getTarget(openstudio::ZoneVentilation_DesignFlowRateFields::MinimumOutdoorTemperatureScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<Schedule>()){
        ventilation.setMinimumOutdoorTemperatureSchedule(modelObject->cast<Schedule>());
      }
    }
  }

  d = workspaceObject.getDouble(openstudio::ZoneVentilation_DesignFlowRateFields::MaximumOutdoorTemperature);
  if (d){
    ventilation.setMaximumOutdoorTemperature(*d);
  }

  target = workspaceObject.getTarget(openstudio::ZoneVentilation_DesignFlowRateFields::MaximumOutdoorTemperatureScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (modelObject->optionalCast<Schedule>()){
        ventilation.setMaximumOutdoorTemperatureSchedule(modelObject->cast<Schedule>());
      }
    }
  }

  d = workspaceObject.getDouble(openstudio::ZoneVentilation_DesignFlowRateFields::MaximumWindSpeed);
  if (d){
    ventilation.setMaximumWindSpeed(*d);
  }

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

  //make sure all other objects are translated first except below
  for (const WorkspaceObject& workspaceObject : m_workspace.objects()) {
    if ((workspaceObject.iddObject().type() != IddObjectType::EnergyManagementSystem_Program)
      && (workspaceObject.iddObject().type() != IddObjectType::EnergyManagementSystem_Subroutine)
      && (workspaceObject.iddObject().type() != IddObjectType::EnergyManagementSystem_ProgramCallingManager)
      && (workspaceObject.iddObject().type() != IddObjectType::EnergyManagementSystem_MeteredOutputVariable)
      && (workspaceObject.iddObject().type() != IddObjectType::EnergyManagementSystem_OutputVariable)) {
      translateAndMapWorkspaceObject(workspaceObject);
    }
  }

  OptionalString s = workspaceObject.getString(EnergyManagementSystem_OutputVariableFields::Name);
  if (!s) {
    LOG(Error, "EnergyManagementSystem_OutputVariable has no Name");
    return boost::none;
  }
  openstudio::model::EnergyManagementSystemOutputVariable emsOutputVariable(m_model);
  emsOutputVariable.setName(*s);

  s = workspaceObject.getString(EnergyManagementSystem_OutputVariableFields::EMSVariableName);
  if (!s) {
    LOG(Error, emsOutputVariable.nameString() + ": EMSVariableName not set");
    return boost::none;
  } else {
    Workspace workspace = workspaceObject.workspace();
    //look for GlobalVariables, translate and check if there is a name match since GV's dont have name field.
    boost::optional<WorkspaceObject> wsObject = workspace.getObjectByTypeAndName(IddObjectType::EnergyManagementSystem_GlobalVariable, *s);
    //for (WorkspaceObject& wsObject : workspace.getObjectsByType(IddObjectType::EnergyManagementSystem_GlobalVariable)) {
    if (wsObject) {
      boost::optional<model::ModelObject> modelObject = translateAndMapWorkspaceObject(wsObject.get());
      if (modelObject) {
        if (modelObject.get().cast<EnergyManagementSystemGlobalVariable>().name() == s) {
          emsOutputVariable.setEMSVariableName(*s);
        }
      }
    }
    //look for name match on other (EMS) objects.
    for (WorkspaceObject& wsObject : workspace.getObjectsByName(*s)) {
      boost::optional<model::ModelObject> modelObject = translateAndMapWorkspaceObject(wsObject);
      if (modelObject) {
        emsOutputVariable.setEMSVariableName(*s);
        break;
      }
    }
  }

  s = workspaceObject.getString(EnergyManagementSystem_OutputVariableFields::UpdateFrequency);
  if (!s) {
    LOG(Error, emsOutputVariable.nameString() + ": UpdateFrequency not set");
    return boost::none;
  } else {
    emsOutputVariable.setUpdateFrequency(*s);
  }

  s = workspaceObject.getString(EnergyManagementSystem_OutputVariableFields::TypeofDatainVariable);
  if (!s) {
    LOG(Error, emsOutputVariable.nameString() + ": TypeofDatainVariable not set");
    return boost::none;
  } else {
    emsOutputVariable.setTypeOfDataInVariable(*s);
  }

  s = workspaceObject.getString(EnergyManagementSystem_OutputVariableFields::Units);
  if (s) {
    emsOutputVariable.setUnits(*s);
  }

  s = workspaceObject.getString(EnergyManagementSystem_OutputVariableFields::EMSProgramorSubroutineName);
  if (s) {
    Workspace workspace = workspaceObject.workspace();
    for (WorkspaceObject& wsObject : workspace.getObjectsByName(*s)) {
      boost::optional<model::ModelObject> modelObject = translateAndMapWorkspaceObject(wsObject);
      if (modelObject) {
        if (modelObject.get().iddObjectType() == IddObjectType::OS_EnergyManagementSystem_Program) {
          emsOutputVariable.setEMSProgramOrSubroutineName(modelObject.get().cast<EnergyManagementSystemProgram>());
        } else if (modelObject.get().iddObjectType() == IddObjectType::OS_EnergyManagementSystem_Subroutine) {
          emsOutputVariable.setEMSProgramOrSubroutineName(modelObject.get().cast<EnergyManagementSystemSubroutine>());
        }
        return emsOutputVariable;
      }
    }
  }

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

  Workspace _workspace = workspaceObject.workspace();

  boost::optional<WorkspaceObject> _controllerList;
  boost::optional<WorkspaceObject> _controllerOutdoorAir;
  boost::optional<std::string> controllerName;
  boost::optional<std::string> controllerType;
  boost::optional<ControllerOutdoorAir> oaController;

  _controllerList = workspaceObject.getTarget(AirLoopHVAC_OutdoorAirSystemFields::ControllerListName);

  if( _controllerList )
  {
    for( int i = 1;
         _controllerList->getString(i);
         i = i + 2 )
    {
      controllerType = _controllerList->getString(i);
      controllerName = _controllerList->getString(i + 1);
      if( controllerType )
      {
        if( istringEqual(controllerType.get(),"Controller:OutdoorAir") )
        {
          break;
        }
      }
    }
  }

  if( controllerName && controllerType )
  {
    boost::optional<WorkspaceObject> wo = _workspace.getObjectByTypeAndName(IddObjectType(controllerType.get()),controllerName.get()); 
    if( wo )
    {
      boost::optional<ModelObject> mo = translateAndMapWorkspaceObject(wo.get());
      if( mo )
      {
        oaController = mo->optionalCast<ControllerOutdoorAir>();
      }
    }
  }

  if( oaController )
  {
    AirLoopHVACOutdoorAirSystem mo(m_model,oaController.get());

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

    Node outboardOANode = mo.outboardOANode().get();

    boost::optional<WorkspaceObject> _oaEquipmentList;
    boost::optional<WorkspaceObject> _outdoorAirMixer;
    std::vector<WorkspaceObject> equipmentVector;
    _oaEquipmentList = workspaceObject.getTarget(AirLoopHVAC_OutdoorAirSystemFields::OutdoorAirEquipmentListName);

    if( _oaEquipmentList )
    {
      for( int i = 1;
           _oaEquipmentList->getString(i);
           i = i + 2 )
      {
        boost::optional<std::string> equipmentName;
        boost::optional<std::string> equipmentType;

        equipmentType = _oaEquipmentList->getString(i);
        equipmentName = _oaEquipmentList->getString(i + 1);

        if( equipmentName && equipmentType )
        {
          boost::optional<WorkspaceObject> wo = _workspace.getObjectByTypeAndName(IddObjectType(equipmentType.get()),equipmentName.get());
          if( wo )
          {
            equipmentVector.push_back(wo.get());

            if( wo->iddObject().type() == IddObjectType::OutdoorAir_Mixer )
            {
              _outdoorAirMixer = wo;
            }
          }
        }
      }
      if( _outdoorAirMixer )
      {
        boost::optional<std::string> mixerOAInletNodeName = _outdoorAirMixer->getString(OutdoorAir_MixerFields::OutdoorAirStreamNodeName);
        boost::optional<std::string> mixerOAReliefNodeName = _outdoorAirMixer->getString(OutdoorAir_MixerFields::ReliefAirStreamNodeName);
        if( mixerOAInletNodeName ) { mo.outdoorAirModelObject()->cast<Node>().setName(mixerOAInletNodeName.get()); }
        if( mixerOAReliefNodeName ) { mo.reliefAirModelObject()->cast<Node>().setName(mixerOAReliefNodeName.get()); }

        boost::optional<std::string> oaStreamInletNodeName;
        boost::optional<std::string> oaStreamOutletNodeName;

        oaStreamInletNodeName = _outdoorAirMixer->getString(OutdoorAir_MixerFields::OutdoorAirStreamNodeName);

        while( oaStreamInletNodeName )
        {
          boost::optional<ModelObject> oaComponentModelObject;
          boost::optional<std::string> newOAStreamInletNodeName;

          for( std::vector<WorkspaceObject>::iterator it = equipmentVector.begin();
               it < equipmentVector.end();
               it++ )
          {
            switch(it->iddObject().type().value())
            {
              case openstudio::IddObjectType::EvaporativeCooler_Direct_ResearchSpecial :
              {
                oaStreamOutletNodeName = it->getString(EvaporativeCooler_Direct_ResearchSpecialFields::AirOutletNodeName);
                if( oaStreamOutletNodeName )
                {
                  if( istringEqual(oaStreamOutletNodeName.get(),oaStreamInletNodeName.get()) )
                  {
                    newOAStreamInletNodeName = it->getString(EvaporativeCooler_Direct_ResearchSpecialFields::AirInletNodeName);

                    oaComponentModelObject = translateAndMapWorkspaceObject(*it);
                  }
                }
                break;
              }
              default :
              {
                break;
              }
            }
            if( newOAStreamInletNodeName )
            {
              break;
            }
          }

          oaStreamInletNodeName = newOAStreamInletNodeName;

          if( oaComponentModelObject )
          {
            bool success = false;

            if( boost::optional<HVACComponent> hvacComponent = oaComponentModelObject->optionalCast<HVACComponent>() )
            {
              success = hvacComponent->addToNode(outboardOANode);

              if( success )
              {
                if( boost::optional<StraightComponent> straightComponent = hvacComponent->optionalCast<StraightComponent>() )
                {
                  if( oaStreamInletNodeName )
                  {
                    straightComponent->inletModelObject()->cast<Node>().setName(oaStreamInletNodeName.get());
                  }
                  if( oaStreamOutletNodeName )
                  {
                    straightComponent->outletModelObject()->cast<Node>().setName(oaStreamOutletNodeName.get());
                  }
                }
              }
            }

            if( ! success )
            {
              oaComponentModelObject->remove();
            }
          }
        }
      }
    }

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

  bool nodeFound = false;

  if( boost::optional<std::string> setpointNodeName = workspaceObject.getString(SetpointManager_MixedAirFields::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;
  }

  SetpointManagerMixedAir mo(m_model);

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

  s = workspaceObject.getString(SetpointManager_MixedAirFields::ReferenceSetpointNodeName);
  if( s )
  {
    boost::optional<Node> node = m_model.getModelObjectByName<Node>(s.get());

    if( node )
    {
      mo.setReferenceSetpointNode(node.get());
    }
  }

  s = workspaceObject.getString(SetpointManager_MixedAirFields::FanInletNodeName);
  if( s )
  {
    boost::optional<Node> node = m_model.getModelObjectByName<Node>(s.get());

    if( node )
    {
      mo.setFanInletNode(node.get());
    }
  }

  s = workspaceObject.getString(SetpointManager_MixedAirFields::FanOutletNodeName);
  if( s )
  {
    boost::optional<Node> node = m_model.getModelObjectByName<Node>(s.get());

    if( node )
    {
      mo.setFanOutletNode(node.get());
    }
  }

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

  if( mo.setpointNode() )
  {
    return mo;
  }
  else
  {
    return boost::none;
  }
}
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;
  }
}