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

  OptionalModelObject result;
  boost::optional<double> val;
  boost::optional<std::string> optionalString;
  Workspace _workspace = workspaceObject.workspace();

  openstudio::model::AirLoopHVAC airLoopHVAC( m_model );

  boost::optional<std::string> supplyInletNodeName = workspaceObject.getString(AirLoopHVACFields::SupplySideInletNodeName);
  boost::optional<std::string> supplyOutletNodeName = workspaceObject.getString(AirLoopHVACFields::SupplySideOutletNodeNames);
  boost::optional<std::string> demandInletNodeName = workspaceObject.getString(AirLoopHVACFields::DemandSideInletNodeNames);
  boost::optional<std::string> demandOutletNodeName = workspaceObject.getString(AirLoopHVACFields::DemandSideOutletNodeName);

  Node supplyInletNode = airLoopHVAC.supplyInletNode();
  Node supplyOutletNode = airLoopHVAC.supplyOutletNode();
  Node demandInletNode = airLoopHVAC.demandInletNode();
  Node demandOutletNode = airLoopHVAC.demandOutletNode();

  if( supplyInletNodeName ) { supplyInletNode.setName(supplyInletNodeName.get()); }
  if( supplyOutletNodeName ) { supplyOutletNode.setName(supplyOutletNodeName.get()); }
  if( demandInletNodeName ) { demandInletNode.setName(demandInletNodeName.get()); }
  if( demandOutletNodeName ) { demandOutletNode.setName(demandOutletNodeName.get()); }

  optionalString = workspaceObject.getString(AirLoopHVACFields::Name);
  if( optionalString )
  {
    airLoopHVAC.setName(optionalString.get());
  }

  optionalString = workspaceObject.getString(AirLoopHVACFields::DesignSupplyAirFlowRate);
  if( optionalString && istringEqual(optionalString.get(),"AutoSize") )
  {
    airLoopHVAC.autosizeDesignSupplyAirFlowRate();
  }
  else if( (val = workspaceObject.getDouble(AirLoopHVACFields::DesignSupplyAirFlowRate)) )
  {
    airLoopHVAC.setDesignSupplyAirFlowRate(val.get());
  }

  // Go find the supply branch.
  // Currently only supporting one supply branch.
  // Dual ducts are not supported.
  OptionalWorkspaceObject _supplyBranchList;
  OptionalWorkspaceObject _supplyBranch;

  _supplyBranchList = workspaceObject.getTarget(AirLoopHVACFields::BranchListName);
  if( _supplyBranchList )
  {
    _supplyBranch = _supplyBranchList->getExtensibleGroup(0).cast<WorkspaceExtensibleGroup>().getTarget(BranchListExtensibleFields::BranchName);
    if( ! _supplyBranch )
    {
      LOG(Error, _supplyBranchList->briefDescription() << ": Missing supply branch");
    }
    else
    {
      // March through the equipment on the supply branch and convert them.
      for( unsigned i = 0; ! _supplyBranch->getExtensibleGroup(i).empty(); i++ )
      {
        WorkspaceExtensibleGroup eg = _supplyBranch->getExtensibleGroup(i).cast<WorkspaceExtensibleGroup>();
        boost::optional<std::string> componentName = eg.getString(BranchExtensibleFields::ComponentName);
        boost::optional<std::string> componentType = eg.getString(BranchExtensibleFields::ComponentObjectType);
        boost::optional<std::string> componentInletNodeName = eg.getString(BranchExtensibleFields::ComponentInletNodeName);
        boost::optional<std::string> componentOutletNodeName = eg.getString(BranchExtensibleFields::ComponentOutletNodeName);
        boost::optional<WorkspaceObject> wo;
        OptionalNode node;
        OptionalModelObject targetModelObject;

        if( componentName && (componentName.get() != "") && componentType && (componentType.get() != "") )
        {
          IddObjectType iddType(componentType.get());
          wo = _workspace.getObjectByTypeAndName(iddType,componentName.get());
        }

        if( wo )
        {
          targetModelObject = translateAndMapWorkspaceObject( wo.get() );
          if( !targetModelObject)
          {
            LOG(Error, "Error importing object: " << wo->briefDescription() );
            continue;
          }

          if( OptionalHVACComponent hvacComponent = targetModelObject->optionalCast<HVACComponent>() )
          {
            Node node = airLoopHVAC.supplyOutletNode();
            if( hvacComponent->addToNode(node) )
            {
              if( boost::optional<StraightComponent> straightComponent = hvacComponent->optionalCast<StraightComponent>() )
              {
                Node outletNode = straightComponent->outletModelObject()->cast<Node>();
                Node inletNode = straightComponent->inletModelObject()->cast<Node>();
                if( componentOutletNodeName )
                {
                  outletNode.setName(componentOutletNodeName.get());
                }
                if( componentInletNodeName )
                {
                  inletNode.setName(componentInletNodeName.get());
                }
              }
              else if( boost::optional<AirLoopHVACOutdoorAirSystem> oaSystem = hvacComponent->optionalCast<AirLoopHVACOutdoorAirSystem>() )
              {
                Node outletNode = oaSystem->mixedAirModelObject()->cast<Node>();
                Node inletNode = oaSystem->returnAirModelObject()->cast<Node>();
                if( componentOutletNodeName )
                {
                  outletNode.setName(componentOutletNodeName.get());
                }
                if( componentInletNodeName )
                {
                  inletNode.setName(componentInletNodeName.get());
                }
              }
            }
          }
        }
        else
        {
          LOG(Error, _supplyBranch->briefDescription() << ": Missing object listed at ComponentName " << i);
        }
      }
    }
  }
  else
  {
    LOG( Error, workspaceObject.briefDescription() << ": Missing supply branch list, "
              << "Supply equipment will be incomplete");
  }

  // March through the zone on the demand side and add branches for them.
  if( demandOutletNodeName )
  {
    // Find the zone mixer for this air loop
    std::vector<WorkspaceObject> _airLoopHVACZoneMixers;
    _airLoopHVACZoneMixers = workspaceObject.workspace().getObjectsByType(IddObjectType::AirLoopHVAC_ZoneMixer);

    boost::optional<WorkspaceObject> _airLoopHVACZoneMixer;
    for( const auto & elem : _airLoopHVACZoneMixers )
    {
      boost::optional<std::string> mixerOutletNodeName;
      mixerOutletNodeName = elem.getString(AirLoopHVAC_ZoneMixerFields::OutletNodeName);

      if( mixerOutletNodeName && mixerOutletNodeName.get() == demandOutletNodeName.get() )
      {
        _airLoopHVACZoneMixer = elem;
        break;
      }
    }
    if( _airLoopHVACZoneMixer )
    {
      for( int i = 2;
           _airLoopHVACZoneMixer->getString(i);
           i++ )
      {

        std::vector<WorkspaceObject> _zoneHVACEquipmentConnections;

        std::string mixerInletNodeName = _airLoopHVACZoneMixer->getString(i).get();

        _zoneHVACEquipmentConnections = _workspace.getObjectsByType(IddObjectType::ZoneHVAC_EquipmentConnections);

        for( const auto & _zoneHVACEquipmentConnection : _zoneHVACEquipmentConnections )
        {

          OptionalString returnAirNodeName = _zoneHVACEquipmentConnection.getString(ZoneHVAC_EquipmentConnectionsFields::ZoneReturnAirNodeName);
          OptionalString inletAirNodeName = _zoneHVACEquipmentConnection.getString(ZoneHVAC_EquipmentConnectionsFields::ZoneAirInletNodeorNodeListName);
          OptionalString zoneName = _zoneHVACEquipmentConnection.getString(ZoneHVAC_EquipmentConnectionsFields::ZoneName);
          OptionalString zoneEquipListName = _zoneHVACEquipmentConnection.getString(ZoneHVAC_EquipmentConnectionsFields::ZoneConditioningEquipmentListName);

          OptionalWorkspaceObject _zone;
          OptionalWorkspaceObject _zoneEquipmentList;
          OptionalWorkspaceObject _zoneEquipment;
          OptionalWorkspaceObject _airTerminal; 

          if( returnAirNodeName &&
              returnAirNodeName.get() == mixerInletNodeName &&
              zoneName &&
              zoneEquipListName )
          {
            _zone = _workspace.getObjectByTypeAndName(IddObjectType::Zone,*zoneName);

            _zoneEquipmentList = _workspace.getObjectByTypeAndName(IddObjectType::ZoneHVAC_EquipmentList,zoneEquipListName.get());

            if( ! _zone )
            {
              LOG( Error, 
                  airLoopHVAC.briefDescription()
                  << " is connected to a zone that does not exist." );

              break;
            }

            if( ! _zoneEquipmentList )
            {
              LOG( Error, 
                  _zone->briefDescription()
                  << " does not have a zone equipment list, but it is attached to a loop." );

              break;
            }

            for( int j = 1; (optionalString = _zoneEquipmentList->getString(j)); j = j + 4 )
            {
              boost::optional<std::string> zoneEquipmentName = _zoneEquipmentList->getString(j+1) ;
              // Possible Zone Equipment
              //
              // ZoneHVAC:AirDistributionUnit
              // AirTerminal:SingleDuct:Uncontrolled
              // ZoneHVAC:EnergyRecoveryVentilator
              // ZoneHVAC:FourPipeFanCoil
              // ZoneHVAC:OutdoorAirUnit
              // ZoneHVAC:PackagedTerminalAirConditioner
              // ZoneHVAC:PackagedTerminalHeatPump
              // ZoneHVAC:UnitHeater
              // ZoneHVAC:UnitVentilator
              // ZoneHVAC:VentilatedSlab
              // ZoneHVAC:WaterToAirHeatPump
              // ZoneHVAC:WindowAirConditioner
              // ZoneHVAC:Baseboard:RadiantConvective:Electric
              // ZoneHVAC:Baseboard:RadiantConvective:Water
              // ZoneHVAC:Baseboard:RadiantConvective:Steam
              // ZoneHVAC:Baseboard:Convective:Electric
              // ZoneHVAC:Baseboard:Convective:Water
              // ZoneHVAC:HighTemperatureRadiant
              // ZoneHVAC:LowTemperatureRadiant:VariableFlow
              // ZoneHVAC:LowTemperatureRadiant:ConstantFlow
              // ZoneHVAC:LowTemperatureRadiant:Electric
              // ZoneHVAC:Dehumidifier:DX
              // ZoneHVAC:IdealLoadsAirSystem
              // Fan:ZoneExhaust
              // WaterHeater:HeatPump
              //
              if( zoneEquipmentName )
              {
                if( istringEqual(optionalString.get(),"AirTerminal:SingleDuct:Uncontrolled") )
                {
                  _airTerminal = _workspace.getObjectByTypeAndName(IddObjectType::AirTerminal_SingleDuct_Uncontrolled,zoneEquipmentName.get());

                  break;
                }
                else if( istringEqual(optionalString.get(),"ZoneHVAC:AirDistributionUnit") )
                {
                  boost::optional<WorkspaceObject> _airDistributionUnit = 
                    _workspace.getObjectByTypeAndName(IddObjectType::ZoneHVAC_AirDistributionUnit,zoneEquipmentName.get());

                  if( _airDistributionUnit )
                  {
                    boost::optional<std::string> airUnitName;
                    boost::optional<std::string> airUnitType;

                    airUnitType = _airDistributionUnit->getString(ZoneHVAC_AirDistributionUnitFields::AirTerminalObjectType);
                    airUnitName = _airDistributionUnit->getString(ZoneHVAC_AirDistributionUnitFields::AirTerminalName);

                    if( airUnitName && airUnitType )
                    {
                      _airTerminal = _workspace.getObjectByTypeAndName(IddObjectType(airUnitType.get()),airUnitName.get());
                    }
                  }

                  break;
                }
              }
            }

            OptionalModelObject airTerminalModelObject;
            OptionalSpace space;
            OptionalStraightComponent straightComponent;
            OptionalThermalZone thermalZone;

            if( _airTerminal )
            {
              airTerminalModelObject = translateAndMapWorkspaceObject( _airTerminal.get() );
            }

            if( _zone )
            {
              if( OptionalModelObject mo = translateAndMapWorkspaceObject( _zone.get() ) )
              {
                space = mo->optionalCast<Space>();
              }
            }

            if( space )
            {
              thermalZone = space->thermalZone();
            }

            if( airTerminalModelObject )
            {
              straightComponent = airTerminalModelObject->optionalCast<StraightComponent>();
            }

            bool success = false;

            if( straightComponent && thermalZone )
            {
              success = airLoopHVAC.addBranchForZone(thermalZone.get(),straightComponent.get());
            }
            else if( thermalZone )
            {
              Model m;

              success = airLoopHVAC.addBranchForZone(thermalZone.get(),boost::none);
            }

            if( success )
            {
              if( inletAirNodeName ) { thermalZone->inletPortList().airLoopHVACModelObject()->cast<Node>().setName(inletAirNodeName.get()); }
              if( returnAirNodeName ) { thermalZone->returnAirModelObject()->cast<Node>().setName(returnAirNodeName.get()); }
            }
          }
        }
      }
    }
  }

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

  LOG(Info,"OtherEquipment is an internal load separate from any other system, and not "
      << "associated with an end use subcategory. Use with caution.");

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

  s = workspaceObject.getString(openstudio::OtherEquipmentFields::DesignLevelCalculationMethod, true);
  OS_ASSERT(s);

  OptionalDouble d;
  if (istringEqual("EquipmentLevel", *s)){
    d = workspaceObject.getDouble(openstudio::OtherEquipmentFields::DesignLevel);
    if (d){
      if (d.get() < 0.0) {
        LOG(Warn,"OtherEquipment has negative energy use. Advanced feature--use with caution.");
      }
      definition.setDesignLevel(*d);
    }else{
      LOG(Error, "EquipmentLevel value not found for workspace object " << workspaceObject);
    }
  }else if(istringEqual("Watts/Area", *s)){
    d = workspaceObject.getDouble(openstudio::OtherEquipmentFields::PowerperZoneFloorArea);
    if (d){
      if (d.get() < 0.0) {
        LOG(Warn,"OtherEquipment has negative energy use. Advanced feature--use with caution.");
      }
      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::OtherEquipmentFields::PowerperPerson);
    if (d){
      if (d.get() < 0.0) {
        LOG(Warn,"OtherEquipment has negative energy use. Advanced feature--use with caution.");
      }
      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::OtherEquipmentFields::FractionLatent);
  if (d){
    definition.setFractionLatent(*d);
  }

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

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

  // create the instance
  OtherEquipment otherEquipment(definition);

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

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

  target = workspaceObject.getTarget(openstudio::OtherEquipmentFields::ScheduleName);
  if (target){
    OptionalModelObject modelObject = translateAndMapWorkspaceObject(*target);
    if (modelObject){
      if (OptionalSchedule intermediate = modelObject->optionalCast<Schedule>()){
        Schedule schedule(*intermediate);
        otherEquipment.setSchedule(schedule);
      }
    }
  }
       
  return otherEquipment;
}
OptionalModelObject ReverseTranslator::translateZoneHVACEquipmentList( const WorkspaceObject & workspaceObject )
{
  if(workspaceObject.iddObject().type() != IddObjectType::ZoneHVAC_EquipmentList){
    LOG(Error, "WorkspaceObject is not IddObjectType: ZoneHVAC:EquipmentList");
     return boost::none;
  }

  boost::optional<openstudio::model::ThermalZone> thermalZone;

  std::vector<WorkspaceObject> zoneHVACEquipmentConnections = workspaceObject.getSources(IddObjectType::ZoneHVAC_EquipmentConnections);
  if (zoneHVACEquipmentConnections.size() == 0){
    LOG(Error,"No ZoneHVAC:EquipmentConnections object associated with a zone. Check that IDF file is correct.");
    return boost::none;
  }else if (zoneHVACEquipmentConnections.size() > 1){
    LOG(Error,"More than 1 ZoneHVAC:EquipmentConnections objects associated with a zone. Check that IDF file is correct.");
    return boost::none;
  }

  for( const auto & zoneHVACEquipmentConnection : zoneHVACEquipmentConnections )
  {
    if( boost::optional<std::string> name = zoneHVACEquipmentConnection.getString(ZoneHVAC_EquipmentConnectionsFields::ZoneName) )
    {
      boost::optional<model::Space> space = m_model.getModelObjectByName<model::Space>(name.get());

      if( space )
      {
        thermalZone = space->thermalZone();
      }
    }
  }

  // get extensible groups for zone HVAC equipment list
  std::vector<IdfExtensibleGroup> extensibleGroups = workspaceObject.extensibleGroups();

  // loop over extensible groups
  unsigned n = extensibleGroups.size();
  for (unsigned i = 0; i < n; ++i){
    // define variables
    boost::optional<openstudio::model::ZoneHVACComponent> zoneHVACComponent;
    // get zone equipment object type and zone equipment object name from extensible group
    boost::optional<std::string> zoneEquipmentObjectType = extensibleGroups[i].getString(ZoneHVAC_EquipmentListExtensibleFields::ZoneEquipmentObjectType);
    boost::optional<std::string> zoneEquipmentName = extensibleGroups[i].getString(ZoneHVAC_EquipmentListExtensibleFields::ZoneEquipmentName);
    // get zone equipment workspace object by type and name
    if (zoneEquipmentObjectType && zoneEquipmentName){
      OptionalWorkspaceObject zoneEquipmentWorkspaceObject = workspaceObject.workspace().getObjectByTypeAndName(IddObjectType(*zoneEquipmentObjectType),*zoneEquipmentName);
      // translate zone equipment workspace object
      if (zoneEquipmentWorkspaceObject){
        OptionalModelObject zoneEquipmentModelObject = translateAndMapWorkspaceObject(*zoneEquipmentWorkspaceObject);
        // cast zone equipment model object to zone HVAC component
        if (zoneEquipmentModelObject){
          zoneHVACComponent = zoneEquipmentModelObject->optionalCast<ZoneHVACComponent>();
        }
      }
    }
    // add to thermal zone
    if (zoneHVACComponent && thermalZone){
      zoneHVACComponent->addToThermalZone(*thermalZone);
    }
  }

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

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

  boost::optional<double> value = workspaceObject.getDouble(Site_GroundTemperature_BuildingSurfaceFields::JanuaryGroundTemperature);
  if( value )
  {
    mo.setJanuaryGroundTemperature(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundTemperature_BuildingSurfaceFields::FebruaryGroundTemperature);
  if( value )
  {
    mo.setFebruaryGroundTemperature(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundTemperature_BuildingSurfaceFields::MarchGroundTemperature);
  if( value )
  {
    mo.setMarchGroundTemperature(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundTemperature_BuildingSurfaceFields::AprilGroundTemperature);
  if( value )
  {
    mo.setAprilGroundTemperature(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundTemperature_BuildingSurfaceFields::MayGroundTemperature);
  if( value )
  {
    mo.setMayGroundTemperature(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundTemperature_BuildingSurfaceFields::JuneGroundTemperature);
  if( value )
  {
    mo.setJuneGroundTemperature(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundTemperature_BuildingSurfaceFields::JulyGroundTemperature);
  if( value )
  {
    mo.setJulyGroundTemperature(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundTemperature_BuildingSurfaceFields::AugustGroundTemperature);
  if( value )
  {
    mo.setAugustGroundTemperature(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundTemperature_BuildingSurfaceFields::SeptemberGroundTemperature);
  if( value )
  {
    mo.setSeptemberGroundTemperature(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundTemperature_BuildingSurfaceFields::OctoberGroundTemperature);
  if( value )
  {
    mo.setOctoberGroundTemperature(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundTemperature_BuildingSurfaceFields::NovemberGroundTemperature);
  if( value )
  {
    mo.setNovemberGroundTemperature(value.get());
  }

  value = workspaceObject.getDouble(Site_GroundTemperature_BuildingSurfaceFields::DecemberGroundTemperature);
  if( value )
  {
    mo.setDecemberGroundTemperature(value.get());
  }

  return mo;

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

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

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

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

  temp= translateAndMapWorkspaceObject( *owo );

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

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


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

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

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


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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    result=coil;

  }
  catch (std::exception& e) {
    LOG(Error,"Could not reverse translate " << workspaceObject.briefDescription()
        << ", because " << e.what() << ".");
  }
  return result;
}
boost::optional<ModelObject> ReverseTranslator::translateCurveDoubleExponentialDecay( 
    const WorkspaceObject& workspaceObject )
{
  CurveDoubleExponentialDecay curve(m_model);

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

  if ((d = workspaceObject.getDouble(Curve_DoubleExponentialDecayFields::Coefficient1C1))) {
    curve.setCoefficient1C1(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_DoubleExponentialDecayFields::Coefficient2C2))) {
    curve.setCoefficient2C2(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_DoubleExponentialDecayFields::Coefficient3C3))) {
    curve.setCoefficient3C3(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_DoubleExponentialDecayFields::Coefficient3C4))) {
    curve.setCoefficient3C4(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_DoubleExponentialDecayFields::Coefficient3C5))) {
    curve.setCoefficient3C5(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_DoubleExponentialDecayFields::MinimumValueofx))) {
    curve.setMinimumValueofx(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_DoubleExponentialDecayFields::MaximumValueofx))) {
    curve.setMaximumValueofx(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_DoubleExponentialDecayFields::MinimumCurveOutput))) {
    curve.setMinimumCurveOutput(*d);
  }
  if ((d = workspaceObject.getDouble(Curve_DoubleExponentialDecayFields::MaximumCurveOutput))) {
    curve.setMaximumCurveOutput(*d);
  }
  if ((s = workspaceObject.getString(Curve_DoubleExponentialDecayFields::InputUnitTypeforx,false,true))) {
    curve.setInputUnitTypeforx(*s);
  }
  if ((s = workspaceObject.getString(Curve_DoubleExponentialDecayFields::OutputUnitType,false,true))) {
    curve.setOutputUnitType(*s);
  }

  return curve;
}
void WorkspaceWatcher::onObjectRemove(const WorkspaceObject& removedObject)
{
  OS_ASSERT(removedObject.initialized());
  OS_ASSERT(removedObject.workspace().isMember(removedObject.handle()));
}
void WorkspaceWatcher::onObjectAdd(const WorkspaceObject& addedObject)
{
  OS_ASSERT(addedObject.initialized());
  OS_ASSERT(addedObject.workspace().isMember(addedObject.handle()));
}
OptionalModelObject ReverseTranslator::translateSizingSystem( const WorkspaceObject & workspaceObject )
{
  boost::optional<WorkspaceObject> _airLoopHVAC = workspaceObject.getTarget(Sizing_SystemFields::AirLoopName);

  boost::optional<AirLoopHVAC> airLoopHVAC;

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

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

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

    return boost::none;
  }

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

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

  // TypeofLoadtoSizeOn

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

  // DesignOutdoorAirFlowRate

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

  // MinimumSystemAirFlowRatio

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

  // PreheatDesignTemperature

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

  // PreheatDesignHumidityRatio

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

  // PrecoolDesignTemperature

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

  // PrecoolDesignHumidityRatio

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

  // CentralCoolingDesignSupplyAirTemperature

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

  // CentralHeatingDesignSupplyAirTemperature

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

  // SizingOption

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

  // AllOutdoorAirinCooling

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

  // AllOutdoorAirinHeating

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

  // CentralCoolingDesignSupplyAirHumidityRatio

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

  // CentralHeatingDesignSupplyAirHumidityRatio

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

  // CoolingDesignAirFlowMethod

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

  // CoolingDesignAirFlowRate

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

  // HeatingDesignAirFlowMethod

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

  // HeatingDesignAirFlowRate

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

  // SystemOutdoorAirMethod

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

  return sizingSystem;
}