boost::optional<model::ModelObject> ReverseTranslator::translateShadowCalculation(
    const WorkspaceObject& workspaceObject)
{
  OS_ASSERT(workspaceObject.iddObject().type() == IddObjectType::ShadowCalculation);

  ShadowCalculation shadowCalculation = m_model.getUniqueModelObject<ShadowCalculation>();

  OptionalInt i = workspaceObject.getInt(ShadowCalculationFields::CalculationFrequency);
  if (i) {
    shadowCalculation.setCalculationFrequency(*i);
  }

  i = workspaceObject.getInt(ShadowCalculationFields::MaximumFiguresinShadowOverlapCalculations);
  if (i) {
    shadowCalculation.setMaximumFiguresInShadowOverlapCalculations(*i);
  }

  OptionalString s = workspaceObject.getString(ShadowCalculationFields::PolygonClippingAlgorithm);
  if (s && !s->empty()) {
    shadowCalculation.setPolygonClippingAlgorithm(*s);
  }

  s = workspaceObject.getString(ShadowCalculationFields::SkyDiffuseModelingAlgorithm);
  if (s && !s->empty()) {
    shadowCalculation.setSkyDiffuseModelingAlgorithm(*s);
  }

  return shadowCalculation.cast<ModelObject>();
}
OptionalModelObject ReverseTranslator::translateSizingParameters( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::Sizing_Parameters )
  {
     LOG(Error, "WorkspaceObject is not IddObjectType: Sizing_Parameters");
     return boost::none;
  }

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

  boost::optional<double> value = workspaceObject.getDouble(Sizing_ParametersFields::HeatingSizingFactor);
  if( value )
  {
    mo.setHeatingSizingFactor(value.get());
  }

  value = workspaceObject.getDouble(Sizing_ParametersFields::CoolingSizingFactor);
  if( value )
  {
    mo.setCoolingSizingFactor(value.get());
  }

  boost::optional<int> i = workspaceObject.getInt(Sizing_ParametersFields::TimestepsinAveragingWindow);
  if( i )
  {
    mo.setTimestepsinAveragingWindow(i.get());
  }

  return mo;
}
TEST_F(EnergyPlusFixture,ForwardTranslator_Building3)
{
  Model model;

  Building building = model.getUniqueModelObject<Building>();
  building.setName("Building");
  building.setNorthAxis(20);
  building.setNominalFloortoFloorHeight(5);

  Site site = model.getUniqueModelObject<Site>();
  site.setTerrain("Ocean");

  SimulationControl simulationControl = model.getUniqueModelObject<SimulationControl>();
  simulationControl.setLoadsConvergenceToleranceValue(0.2);
  simulationControl.setTemperatureConvergenceToleranceValue(0.2);
  simulationControl.setSolarDistribution("FullInteriorAndExteriorWithReflections");
  simulationControl.setMaximumNumberofWarmupDays(2);

  ForwardTranslator forwardTranslator;
  Workspace workspace = forwardTranslator.translateModel(model);

  ASSERT_EQ(1u, workspace.getObjectsByType(IddObjectType::Building).size());
  ASSERT_EQ(1u, workspace.getObjectsByType(IddObjectType::Site_Location).size());
  ASSERT_EQ(1u, workspace.getObjectsByType(IddObjectType::SimulationControl).size());

  WorkspaceObject object = workspace.getObjectsByType(IddObjectType::Building)[0];
  ASSERT_TRUE(object.getString(BuildingFields::Name));
  EXPECT_EQ("Building", object.getString(BuildingFields::Name).get());
  ASSERT_TRUE(object.getDouble(BuildingFields::NorthAxis));
  EXPECT_EQ(20, object.getDouble(BuildingFields::NorthAxis).get());
  ASSERT_TRUE(object.getString(BuildingFields::Terrain));
  EXPECT_EQ("Ocean", object.getString(BuildingFields::Terrain).get());
  ASSERT_TRUE(object.getDouble(BuildingFields::LoadsConvergenceToleranceValue));
  EXPECT_EQ(0.2, object.getDouble(BuildingFields::LoadsConvergenceToleranceValue).get());
  ASSERT_TRUE(object.getDouble(BuildingFields::TemperatureConvergenceToleranceValue));
  EXPECT_EQ(0.2, object.getDouble(BuildingFields::TemperatureConvergenceToleranceValue).get());
  ASSERT_TRUE(object.getString(BuildingFields::SolarDistribution));
  EXPECT_EQ("FullInteriorAndExteriorWithReflections", object.getString(BuildingFields::SolarDistribution).get());
  ASSERT_TRUE(object.getInt(BuildingFields::MaximumNumberofWarmupDays));
  EXPECT_EQ(2, object.getInt(BuildingFields::MaximumNumberofWarmupDays).get());
}
OptionalModelObject ReverseTranslator::translateTimestep( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::Timestep )
  {
     LOG(Error, "WorkspaceObject is not IddObjectType: Timestep");
     return boost::none;
  }

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

  boost::optional<int> i = workspaceObject.getInt(TimestepFields::NumberofTimestepsperHour);
  if( i )
  {
    mo.setInt(OS_TimestepFields::NumberofTimestepsperHour,i.get());
  } 

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

  boost::optional<std::string> s = workspaceObject.getString(RunPeriodControl_SpecialDaysFields::StartDate);
  if( !s )
  {
    LOG(Error, "No start date specified for RunPeriodControl:SpecialDays");
    return boost::none;
  }

  boost::optional<RunPeriodControlSpecialDays> mo;
  try{
    mo = RunPeriodControlSpecialDays(*s, m_model);
  }catch(...){
    LOG(Error, "'" << *s << "'  is not a correct date specification");
    return boost::none;
  }

  s = workspaceObject.getString(RunPeriodControl_SpecialDaysFields::Name);
  if( s )
  {
    mo->setName(s.get());
  }

  boost::optional<int> i = workspaceObject.getInt(RunPeriodControl_SpecialDaysFields::Duration);
  if( i )
  {
    mo->setDuration(i.get());
  }

  s = workspaceObject.getString(RunPeriodControl_SpecialDaysFields::SpecialDayType);
  if( s )
  {
    mo->setString(OS_RunPeriodControl_SpecialDaysFields::SpecialDayType,s.get());
  }

  return *mo;
}
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::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::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::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::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;
}
TEST_F(EnergyPlusFixture,ForwardTranslator_TableMultiVariableLookup)
{
  {
    Model m;
    TableMultiVariableLookup table(m,1);

    ASSERT_TRUE(table.addPoint(70,0.1));
    ASSERT_TRUE(table.addPoint(72,0.3));
    ASSERT_TRUE(table.addPoint(74,0.5));
    ASSERT_TRUE(table.addPoint(76,0.7));
    ASSERT_TRUE(table.addPoint(78,0.9));

    ForwardTranslator ft;
    Workspace workspace = ft.translateModel(m);

    std::vector<WorkspaceObject> tableObjects = workspace.getObjectsByType(IddObjectType::Table_MultiVariableLookup);
    ASSERT_EQ(1u, tableObjects.size());

    WorkspaceObject idfTable = tableObjects.front();

    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InterpolationMethod).get(),"LagrangeInterpolationLinearExtrapolation");
    ASSERT_EQ(idfTable.getInt(Table_MultiVariableLookupFields::NumberofInterpolationPoints).get(),3);
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::TableDataFormat).get(),"SingleLineIndependentVariableWithMatrix");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::X1SortOrder).get(),"Ascending");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::X2SortOrder).get(),"Ascending");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX1).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX2).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX3).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX4).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX5).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::OutputUnitType).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getInt(Table_MultiVariableLookupFields::NumberofIndependentVariables).get(),1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(0).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(1).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),70);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(2).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),72);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(3).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),74);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(4).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),76);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(5).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),78);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(6).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(7).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.3);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(8).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(9).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.7);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(10).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.9);
  }

  {
    Model m;
    TableMultiVariableLookup table(m,2);

    ASSERT_TRUE(table.addPoint(70,32,0.1));
    ASSERT_TRUE(table.addPoint(72,32,0.3));
    ASSERT_TRUE(table.addPoint(74,32,0.5));
    ASSERT_TRUE(table.addPoint(76,32,0.7));
    ASSERT_TRUE(table.addPoint(78,32,0.9));

    ASSERT_TRUE(table.addPoint(70,45,0.2));
    ASSERT_TRUE(table.addPoint(72,45,0.4));
    ASSERT_TRUE(table.addPoint(74,45,0.6));
    ASSERT_TRUE(table.addPoint(76,45,0.8));
    ASSERT_TRUE(table.addPoint(78,45,1.0));

    ASSERT_TRUE(table.addPoint(70,68,0.3));
    ASSERT_TRUE(table.addPoint(72,68,0.5));
    ASSERT_TRUE(table.addPoint(74,68,0.7));
    ASSERT_TRUE(table.addPoint(76,68,0.9));
    ASSERT_TRUE(table.addPoint(78,68,1.1));

    ASSERT_TRUE(table.addPoint(70,81,0.4));
    ASSERT_TRUE(table.addPoint(72,81,0.6));
    ASSERT_TRUE(table.addPoint(74,81,0.8));
    ASSERT_TRUE(table.addPoint(76,81,1.0));
    ASSERT_TRUE(table.addPoint(78,81,1.2));

    ASSERT_TRUE(table.addPoint(70,94,0.5));
    ASSERT_TRUE(table.addPoint(72,94,0.7));
    ASSERT_TRUE(table.addPoint(74,94,0.9));
    ASSERT_TRUE(table.addPoint(76,94,1.1));
    ASSERT_TRUE(table.addPoint(78,94,1.3));

    ASSERT_TRUE(table.addPoint(70,107,0.6));
    ASSERT_TRUE(table.addPoint(72,107,0.8));
    ASSERT_TRUE(table.addPoint(74,107,1.0));
    ASSERT_TRUE(table.addPoint(76,107,1.2));
    ASSERT_TRUE(table.addPoint(78,107,1.4));

    ForwardTranslator ft;
    Workspace workspace = ft.translateModel(m);

    std::vector<WorkspaceObject> tableObjects = workspace.getObjectsByType(IddObjectType::Table_MultiVariableLookup);
    ASSERT_EQ(1u, tableObjects.size());

    WorkspaceObject idfTable = tableObjects.front();
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InterpolationMethod).get(),"LagrangeInterpolationLinearExtrapolation");
    ASSERT_EQ(idfTable.getInt(Table_MultiVariableLookupFields::NumberofInterpolationPoints).get(),3);
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::TableDataFormat).get(),"SingleLineIndependentVariableWithMatrix");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::X1SortOrder).get(),"Ascending");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::X2SortOrder).get(),"Ascending");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX1).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX2).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX3).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX4).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX5).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::OutputUnitType).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getInt(Table_MultiVariableLookupFields::NumberofIndependentVariables).get(),2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(0).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(1).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),6);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(2).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),70);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(3).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),72);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(4).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),74);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(5).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),76);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(6).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),78);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(7).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),32);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(8).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),45);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(9).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),68);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(10).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),81);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(11).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),94);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(12).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),107);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(13).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(14).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.3);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(15).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(16).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.7);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(17).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.9);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(18).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(19).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.4);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(20).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.6);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(21).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.8);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(22).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(23).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.3);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(24).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(25).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.7);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(26).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.9);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(27).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1.1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(28).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.4);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(29).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.6);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(30).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.8);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(31).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(32).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1.2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(33).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(34).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.7);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(35).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.9);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(36).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1.1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(37).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1.3);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(38).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.6);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(39).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.8);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(40).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(41).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1.2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(42).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1.4);
  }

  {
    Model m;
    TableMultiVariableLookup table(m,3);

    ASSERT_TRUE(table.addPoint(70,32,1,0.1));
    ASSERT_TRUE(table.addPoint(72,32,1,0.3));
    ASSERT_TRUE(table.addPoint(74,32,1,0.5));
    ASSERT_TRUE(table.addPoint(76,32,1,0.7));
    ASSERT_TRUE(table.addPoint(78,32,1,0.9));

    ASSERT_TRUE(table.addPoint(70,45,1,0.2));
    ASSERT_TRUE(table.addPoint(72,45,1,0.4));
    ASSERT_TRUE(table.addPoint(74,45,1,0.6));
    ASSERT_TRUE(table.addPoint(76,45,1,0.8));
    ASSERT_TRUE(table.addPoint(78,45,1,1.0));

    ASSERT_TRUE(table.addPoint(70,68,1,0.3));
    ASSERT_TRUE(table.addPoint(72,68,1,0.5));
    ASSERT_TRUE(table.addPoint(74,68,1,0.7));
    ASSERT_TRUE(table.addPoint(76,68,1,0.9));
    ASSERT_TRUE(table.addPoint(78,68,1,1.1));

    ASSERT_TRUE(table.addPoint(70,81,1,0.4));
    ASSERT_TRUE(table.addPoint(72,81,1,0.6));
    ASSERT_TRUE(table.addPoint(74,81,1,0.8));
    ASSERT_TRUE(table.addPoint(76,81,1,1.0));
    ASSERT_TRUE(table.addPoint(78,81,1,1.2));

    ASSERT_TRUE(table.addPoint(70,94,1,0.5));
    ASSERT_TRUE(table.addPoint(72,94,1,0.7));
    ASSERT_TRUE(table.addPoint(74,94,1,0.9));
    ASSERT_TRUE(table.addPoint(76,94,1,1.1));
    ASSERT_TRUE(table.addPoint(78,94,1,1.3));

    ASSERT_TRUE(table.addPoint(70,107,1,0.6));
    ASSERT_TRUE(table.addPoint(72,107,1,0.8));
    ASSERT_TRUE(table.addPoint(74,107,1,1.0));
    ASSERT_TRUE(table.addPoint(76,107,1,1.2));
    ASSERT_TRUE(table.addPoint(78,107,1,1.4));

    ASSERT_TRUE(table.addPoint(70,32,2,10.1));
    ASSERT_TRUE(table.addPoint(72,32,2,10.3));
    ASSERT_TRUE(table.addPoint(74,32,2,10.5));
    ASSERT_TRUE(table.addPoint(76,32,2,10.7));
    ASSERT_TRUE(table.addPoint(78,32,2,10.9));

    ASSERT_TRUE(table.addPoint(70,45,2,10.2));
    ASSERT_TRUE(table.addPoint(72,45,2,10.4));
    ASSERT_TRUE(table.addPoint(74,45,2,10.6));
    ASSERT_TRUE(table.addPoint(76,45,2,10.8));
    ASSERT_TRUE(table.addPoint(78,45,2,11.0));

    ASSERT_TRUE(table.addPoint(70,68,2,10.3));
    ASSERT_TRUE(table.addPoint(72,68,2,10.5));
    ASSERT_TRUE(table.addPoint(74,68,2,10.7));
    ASSERT_TRUE(table.addPoint(76,68,2,10.9));
    ASSERT_TRUE(table.addPoint(78,68,2,11.1));

    ASSERT_TRUE(table.addPoint(70,81,2,10.4));
    ASSERT_TRUE(table.addPoint(72,81,2,10.6));
    ASSERT_TRUE(table.addPoint(74,81,2,10.8));
    ASSERT_TRUE(table.addPoint(76,81,2,11.0));
    ASSERT_TRUE(table.addPoint(78,81,2,11.2));

    ASSERT_TRUE(table.addPoint(70,94,2,10.5));
    ASSERT_TRUE(table.addPoint(72,94,2,10.7));
    ASSERT_TRUE(table.addPoint(74,94,2,10.9));
    ASSERT_TRUE(table.addPoint(76,94,2,11.1));
    ASSERT_TRUE(table.addPoint(78,94,2,11.3));

    ASSERT_TRUE(table.addPoint(70,107,2,10.6));
    ASSERT_TRUE(table.addPoint(72,107,2,10.8));
    ASSERT_TRUE(table.addPoint(74,107,2,11.0));
    ASSERT_TRUE(table.addPoint(76,107,2,11.2));
    ASSERT_TRUE(table.addPoint(78,107,2,11.4));

    ForwardTranslator ft;
    Workspace workspace = ft.translateModel(m);

    std::vector<WorkspaceObject> tableObjects = workspace.getObjectsByType(IddObjectType::Table_MultiVariableLookup);
    ASSERT_EQ(1u, tableObjects.size());

    WorkspaceObject idfTable = tableObjects.front();
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InterpolationMethod).get(),"LagrangeInterpolationLinearExtrapolation");
    ASSERT_EQ(idfTable.getInt(Table_MultiVariableLookupFields::NumberofInterpolationPoints).get(),3);
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::TableDataFormat).get(),"SingleLineIndependentVariableWithMatrix");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::X1SortOrder).get(),"Ascending");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::X2SortOrder).get(),"Ascending");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX1).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX2).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX3).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX4).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::InputUnitTypeforX5).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getString(Table_MultiVariableLookupFields::OutputUnitType).get(),"Dimensionless");
    ASSERT_EQ(idfTable.getInt(Table_MultiVariableLookupFields::NumberofIndependentVariables).get(),3);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(0).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(1).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),6);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(2).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(3).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),70);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(4).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),72);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(5).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),74);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(6).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),76);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(7).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),78);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(8).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),32);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(9).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),45);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(10).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),68);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(11).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),81);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(12).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),94);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(13).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),107);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(14).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(15).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(16).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(17).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(18).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.3);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(19).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(20).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.7);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(21).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.9);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(22).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(23).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.4);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(24).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.6);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(25).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.8);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(26).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(27).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.3);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(28).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(29).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.7);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(30).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.9);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(31).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1.1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(32).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.4);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(33).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.6);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(34).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.8);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(35).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(36).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1.2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(37).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(38).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.7);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(39).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.9);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(40).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1.1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(41).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1.3);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(42).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.6);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(43).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),0.8);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(44).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(45).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1.2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(46).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),1.4);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(47).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(48).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(49).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.3);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(50).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(51).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.7);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(52).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.9);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(53).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(54).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.4);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(55).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.6);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(56).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.8);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(57).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),11);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(58).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.3);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(59).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(60).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.7);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(61).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.9);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(62).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),11.1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(63).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.4);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(64).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.6);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(65).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.8);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(66).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),11);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(67).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),11.2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(68).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.5);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(69).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.7);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(70).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.9);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(71).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),11.1);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(72).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),11.3);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(73).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.6);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(74).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),10.8);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(75).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),11);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(76).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),11.2);
    ASSERT_DOUBLE_EQ(idfTable.getExtensibleGroup(77).getDouble(Table_MultiVariableLookupExtensibleFields::Data).get(),11.4);
  }
}
OptionalModelObject ReverseTranslator::translateRunPeriod( const WorkspaceObject & workspaceObject )
{
  OptionalModelObject result;
  openstudio::model::RunPeriod runPeriod = m_model.getUniqueModelObject<openstudio::model::RunPeriod>();
  OptionalString optS = workspaceObject.name();
  if(optS)
  {
    runPeriod.setName(*optS);
  }
  OptionalInt i;

  i = workspaceObject.getInt(openstudio::RunPeriodFields::BeginMonth);
  if( i )
  {
    runPeriod.setBeginMonth( *i );
  }

  i = workspaceObject.getInt(openstudio::RunPeriodFields::BeginDayofMonth);
  if( i )
  {
    runPeriod.setBeginDayOfMonth( *i );
  }

  i = workspaceObject.getInt(openstudio::RunPeriodFields::EndMonth);
  if( i )
  {
    runPeriod.setEndMonth( *i );
  }

  i = workspaceObject.getInt(openstudio::RunPeriodFields::EndDayofMonth);
  if( i )
  {
    runPeriod.setEndDayOfMonth( *i );
  }

  optS = workspaceObject.getString(RunPeriodFields::DayofWeekforStartDay);
  if(optS)
  {
    boost::optional<model::YearDescription> yd = runPeriod.model().getOptionalUniqueModelObject<model::YearDescription>();
    if (yd){
      if (!istringEqual(*optS, yd->dayofWeekforStartDay())){
        LOG(Warn, "Multiple values detected for dayofWeekforStartDay, using " << yd->dayofWeekforStartDay());
      }
    }else{
      // create a year description
      yd = runPeriod.model().getUniqueModelObject<model::YearDescription>();
      yd->setDayofWeekforStartDay(*optS);
    }

  }//if(optS)

  optS = workspaceObject.getString(RunPeriodFields::UseWeatherFileHolidaysandSpecialDays);
  if(optS)
  {
    std::string temp=*optS;
    boost::to_lower(temp);
    if( temp == "no")
    {
      runPeriod.setUseWeatherFileHolidays(false);
    }
    else
    {runPeriod.setUseWeatherFileHolidays(true);
    }
  }
  optS = workspaceObject.getString(RunPeriodFields::UseWeatherFileDaylightSavingPeriod);
  if(optS)
  {
    std::string temp=*optS;
    boost::to_lower(temp);
    if( temp == "no")
    {
      runPeriod.setUseWeatherFileDaylightSavings(false);
    }
    else
    {
      runPeriod.setUseWeatherFileDaylightSavings(true);
    }
  }
  optS = workspaceObject.getString(RunPeriodFields::ApplyWeekendHolidayRule);
  if(optS)
  {
    std::string temp=*optS;
    boost::to_lower(temp);
    if( temp == "no")
    {
      runPeriod.setApplyWeekendHolidayRule(false);
    }
    else
    {
      runPeriod.setApplyWeekendHolidayRule(true);
    }
  }
  optS = workspaceObject.getString(RunPeriodFields::UseWeatherFileRainIndicators);
  if(optS)
  {
    std::string temp=*optS;
    boost::to_lower(temp);
    if( temp == "no")
    {
      runPeriod.setUseWeatherFileRainInd(false);
    }
    else
    {
      runPeriod.setUseWeatherFileRainInd(true);
    }
  }
  optS = workspaceObject.getString(RunPeriodFields::UseWeatherFileSnowIndicators);
  if(optS)
  {
    std::string temp=*optS;
    boost::to_lower(temp);
    if( temp == "no")
    {
      runPeriod.setUseWeatherFileSnowInd(false);
    }
    else
    {
      runPeriod.setUseWeatherFileSnowInd(true);
    }
  }

  auto beginYear = workspaceObject.getInt(openstudio::RunPeriodFields::BeginYear);
  auto endYear = workspaceObject.getInt(openstudio::RunPeriodFields::EndYear);

  if ( beginYear ) {
    auto yd = runPeriod.model().getUniqueModelObject<model::YearDescription>();
    yd.setCalendarYear(beginYear.get());

    if ( endYear ) {
      runPeriod.setNumTimePeriodRepeats(endYear.get() - beginYear.get());
    }
  }

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

  // ensure that site and simulation control have been mapped
  for (const WorkspaceObject& siteObject : m_workspace.getObjectsByType(IddObjectType::Site_Location)){
    translateAndMapWorkspaceObject(siteObject);
  }

  for (const WorkspaceObject& simControlObject : m_workspace.getObjectsByType(IddObjectType::SimulationControl)){
    translateAndMapWorkspaceObject(simControlObject);
  }

  // create the building
  openstudio::model::Building building = m_model.getUniqueModelObject<Building>();
  
  OptionalString s = workspaceObject.name();
  if(s){
    building.setName(*s);
  }

  OptionalDouble d = workspaceObject.getDouble(openstudio::BuildingFields::NorthAxis);
  if( d ){
    building.setNorthAxis(*d);
  }

  // fields that go to site
  s = workspaceObject.getString(openstudio::BuildingFields::Terrain);
  if (s){
    boost::optional<Site> site = m_model.getOptionalUniqueModelObject<Site>();
    if (site){
      site->setTerrain(*s);
    }
  }

  // fields that go to simulation control
  d = workspaceObject.getDouble(openstudio::BuildingFields::LoadsConvergenceToleranceValue);
  if(d){
    boost::optional<SimulationControl> simulationControl = m_model.getUniqueModelObject<SimulationControl>();
    if (simulationControl){
      simulationControl->setLoadsConvergenceToleranceValue(*d);
    }
  }

  d = workspaceObject.getDouble(openstudio::BuildingFields::TemperatureConvergenceToleranceValue);
  if(d){
    boost::optional<SimulationControl> simulationControl = m_model.getUniqueModelObject<SimulationControl>();
    if (simulationControl){
      simulationControl->setTemperatureConvergenceToleranceValue(*d);
    }
  }

  s = workspaceObject.getString(openstudio::BuildingFields::SolarDistribution);
  if(s){
    boost::optional<SimulationControl> simulationControl = m_model.getUniqueModelObject<SimulationControl>();
    if (simulationControl){
      simulationControl->setSolarDistribution(*s);
    }
  }

  OptionalInt i = workspaceObject.getInt(openstudio::BuildingFields::MaximumNumberofWarmupDays);
  if(i){
    boost::optional<SimulationControl> simulationControl = m_model.getUniqueModelObject<SimulationControl>();
    if (simulationControl){
      simulationControl->setMaximumNumberofWarmupDays(*i);
    }
  }

  i = workspaceObject.getInt(openstudio::BuildingFields::MinimumNumberofWarmupDays);
  if (i) {
    boost::optional<SimulationControl> simulationControl = m_model.getUniqueModelObject<SimulationControl>();
    if (simulationControl){
      simulationControl->setMinimumNumberofWarmupDays(*i);
    }
  }

  return building;
}