void SiteWaterMainsTemperature_Impl::populateValidityReport(ValidityReport& report,bool checkNames) const {
    // Inherit lower-level errors
    ModelObject_Impl::populateValidityReport(report,checkNames);

    if (report.level() > StrictnessLevel::Draft) {
        boost::optional<IddKey> key = iddObject().getField(OS_Site_WaterMainsTemperatureFields::CalculationMethod).get().getKey(calculationMethod());
        OS_ASSERT(key);
        if (key->name() == "Schedule") {
            if (!temperatureSchedule()) {
                report.insertError(DataError(OS_Site_WaterMainsTemperatureFields::TemperatureScheduleName,
                                             getObject<ModelObject>(),
                                             DataErrorType::NullAndRequired));
            }
        }
        else {
            // Correlation
            if (!annualAverageOutdoorAirTemperature()) {
                report.insertError(DataError(OS_Site_WaterMainsTemperatureFields::AnnualAverageOutdoorAirTemperature,
                                             getObject<ModelObject>(),
                                             DataErrorType::NullAndRequired));
            }
            if (!maximumDifferenceInMonthlyAverageOutdoorAirTemperatures()) {
                report.insertError(DataError(OS_Site_WaterMainsTemperatureFields::MaximumDifferenceInMonthlyAverageOutdoorAirTemperatures,
                                             getObject<ModelObject>(),
                                             DataErrorType::NullAndRequired));
            }
        }
    }
}
 bool SetpointManagerScheduled_Impl::setControlVariableAndSchedule(
        const std::string& controlVariable,
        Schedule& schedule)
 {
   bool result(false);
   if (OptionalIddKey key = iddObject().getField(OS_SetpointManager_ScheduledFields::ControlVariable).get().getKey(controlVariable)) {
     result = ModelObject_Impl::setSchedule(OS_SetpointManager_ScheduledFields::ScheduleName,
                                            "SetpointManagerScheduled",
                                            scheduleDisplayName(key->name()),
                                            schedule);
     if (result) {
       result = setString(OS_SetpointManager_ScheduledFields::ControlVariable,key->name());
       OS_ASSERT(result);
     }
   }
   return result;
 }
boost::optional<IdfObject> ForwardTranslator::translatePlantEquipmentOperationOutdoorDewpointDifference( PlantEquipmentOperationOutdoorDewpointDifference & modelObject )
{
  IdfObject idfObject(IddObjectType::PlantEquipmentOperation_OutdoorDewpointDifference);
  m_idfObjects.push_back(idfObject);

  // Name
  auto name = modelObject.name().get();
  idfObject.setName(name);

  // ReferenceTemperatureNodeName
  if( const auto & node = modelObject.referenceTemperatureNode() ) {
    idfObject.setString(PlantEquipmentOperation_OutdoorDewpointDifferenceFields::ReferenceTemperatureNodeName,node->name().get());
  }

  double lowerLimit = modelObject.minimumLowerLimit();
  int i = 1;
  for( auto upperLimit : modelObject.loadRangeUpperLimits() ) {
    auto equipment = modelObject.equipment(upperLimit);
    if( ! equipment.empty() ) {
      auto eg = idfObject.pushExtensibleGroup();
      eg.setDouble(PlantEquipmentOperation_OutdoorDewpointDifferenceExtensibleFields::DewpointTemperatureDifferenceRangeLowerLimit,lowerLimit);
      eg.setDouble(PlantEquipmentOperation_OutdoorDewpointDifferenceExtensibleFields::DewpointTemperatureDifferenceRangeUpperLimit,upperLimit);

      IdfObject equipmentList(IddObjectType::PlantEquipmentList);
      m_idfObjects.push_back(equipmentList);
      auto equipmentListName = name + " equipment list " + std::to_string(i);
      equipmentList.setName(equipmentListName);
      eg.setString(PlantEquipmentOperation_OutdoorDewpointDifferenceExtensibleFields::RangeEquipmentListName,equipmentListName);

      for( auto component : equipment ) {
        auto eg2 = equipmentList.pushExtensibleGroup();
        auto idf_component = translateAndMapModelObject(component);
        OS_ASSERT(idf_component);
        eg2.setString(PlantEquipmentListExtensibleFields::EquipmentObjectType,idf_component->iddObject().name());
        eg2.setString(PlantEquipmentListExtensibleFields::EquipmentName,idf_component->name().get());
      }
    }

    lowerLimit = upperLimit;
    ++i;
  }

  return idfObject;
}
boost::optional<IdfObject> ForwardTranslator::translatePlantEquipmentOperationSchemes( PlantLoop & plantLoop )
{
  IdfObject operationSchemes(IddObjectType::PlantEquipmentOperationSchemes);
  m_idfObjects.push_back(operationSchemes);

  operationSchemes.setName(plantLoop.name().get() + " Operation Schemes");

  // Lambda does what the name suggests, create setpoint operation schemes.
  // This is for any component that has a setpoint manager on its outlet node
  auto createSetpointOperationScheme = [&](PlantLoop & plantLoop) {
    const auto & t_setpointComponents = setpointComponents(plantLoop);
    if( ! t_setpointComponents.empty() ) {
      Schedule alwaysOn = plantLoop.model().alwaysOnDiscreteSchedule();

      IdfObject setpointOperation(IddObjectType::PlantEquipmentOperation_ComponentSetpoint);
      setpointOperation.setName(plantLoop.name().get() + " Setpoint Operation Scheme");
      m_idfObjects.push_back(setpointOperation);
      setpointOperation.clearExtensibleGroups();

      IdfExtensibleGroup eg = operationSchemes.pushExtensibleGroup();
      eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeObjectType,setpointOperation.iddObject().name());
      eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeName,setpointOperation.name().get());
      eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeScheduleName,alwaysOn.name().get());

      for( auto setpointComponent : t_setpointComponents )
      {
        boost::optional<IdfObject> _idfObject = translateAndMapModelObject(setpointComponent);
        OS_ASSERT(_idfObject);

        IdfExtensibleGroup eg = setpointOperation.pushExtensibleGroup();
        eg.setString(PlantEquipmentOperation_ComponentSetpointExtensibleFields::EquipmentObjectType,_idfObject->iddObject().name());
        eg.setString(PlantEquipmentOperation_ComponentSetpointExtensibleFields::EquipmentName,_idfObject->name().get());
        if( const auto & t_inletNode = inletNode(plantLoop,setpointComponent) ) {
          eg.setString(PlantEquipmentOperation_ComponentSetpointExtensibleFields::DemandCalculationNodeName,t_inletNode->name().get());
        }
        if( const auto & t_outletNode = outletNode(plantLoop,setpointComponent) ) {
          eg.setString(PlantEquipmentOperation_ComponentSetpointExtensibleFields::SetpointNodeName,t_outletNode->name().get());
        }
        if( auto value = flowrate(setpointComponent) ) {
          eg.setDouble(PlantEquipmentOperation_ComponentSetpointExtensibleFields::ComponentFlowRate,value.get());
        } else {
          eg.setString(PlantEquipmentOperation_ComponentSetpointExtensibleFields::ComponentFlowRate,"Autosize");
        }
        auto t_componentType = componentType(setpointComponent);
        switch(t_componentType)
        {
          case ComponentType::HEATING :
            eg.setString(PlantEquipmentOperation_ComponentSetpointExtensibleFields::OperationType,"Heating");
            break;
          case ComponentType::COOLING :
            eg.setString(PlantEquipmentOperation_ComponentSetpointExtensibleFields::OperationType,"Cooling");
            break;
          default :
            eg.setString(PlantEquipmentOperation_ComponentSetpointExtensibleFields::OperationType,"Dual");
            break;
        }
      }
    }
  };

  Schedule alwaysOn = plantLoop.model().alwaysOnDiscreteSchedule();
  bool applyDefault = true;

  // If any operation schemes are defined in the model then don't apply default operation schemes

  if( auto coolingLoadScheme = plantLoop.plantEquipmentOperationCoolingLoad() ) {
    auto _scheme = translateAndMapModelObject(coolingLoadScheme.get());
    OS_ASSERT(_scheme);
    auto eg = operationSchemes.pushExtensibleGroup();
    eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeObjectType,_scheme->iddObject().name());
    eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeName,_scheme->name().get());
    eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeScheduleName,alwaysOn.name().get());

    applyDefault = false;
  } 

  if( auto heatingLoadScheme = plantLoop.plantEquipmentOperationHeatingLoad() ) {
    auto _scheme = translateAndMapModelObject(heatingLoadScheme.get());
    OS_ASSERT(_scheme);
    auto eg = operationSchemes.pushExtensibleGroup();
    eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeObjectType,_scheme->iddObject().name());
    eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeName,_scheme->name().get());
    eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeScheduleName,alwaysOn.name().get());

    applyDefault = false;
  }

  if( auto primaryScheme = plantLoop.primaryPlantEquipmentOperationScheme() ) {
    auto _scheme = translateAndMapModelObject(primaryScheme.get());
    OS_ASSERT(_scheme);
    auto eg = operationSchemes.pushExtensibleGroup();
    eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeObjectType,_scheme->iddObject().name());
    eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeName,_scheme->name().get());
    eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeScheduleName,alwaysOn.name().get());

    createSetpointOperationScheme(plantLoop);
    applyDefault = false;
  }

  if( applyDefault ) {
    // If we get here then there must not be any operation schemes defined in the model 
    // and we should go ahead and create default schemes.
    const auto & t_heatingComponents = heatingComponents( plantLoop );
    if( ! t_heatingComponents.empty() ) {
      IdfObject heatingOperation(IddObjectType::PlantEquipmentOperation_HeatingLoad);
      heatingOperation.setName(plantLoop.name().get() + " Heating Operation Scheme");
      m_idfObjects.push_back(heatingOperation);
      heatingOperation.clearExtensibleGroups();

      IdfObject plantEquipmentList(IddObjectType::PlantEquipmentList);
      plantEquipmentList.setName(plantLoop.name().get() + " Heating Equipment List");
      plantEquipmentList.clearExtensibleGroups();
      m_idfObjects.push_back(plantEquipmentList);

      IdfExtensibleGroup eg = heatingOperation.pushExtensibleGroup();
      eg.setDouble(PlantEquipmentOperation_HeatingLoadExtensibleFields::LoadRangeLowerLimit,0.0);
      eg.setDouble(PlantEquipmentOperation_HeatingLoadExtensibleFields::LoadRangeUpperLimit,1E9);
      eg.setString(PlantEquipmentOperation_HeatingLoadExtensibleFields::RangeEquipmentListName,plantEquipmentList.name().get());

      eg = operationSchemes.pushExtensibleGroup();
      eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeObjectType,heatingOperation.iddObject().name());
      eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeName,heatingOperation.name().get());
      eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeScheduleName,alwaysOn.name().get());

      for( auto heatingComponent : t_heatingComponents ) {
        if( const auto & idfObject = translateAndMapModelObject(heatingComponent) ) {
          IdfExtensibleGroup eg = plantEquipmentList.pushExtensibleGroup();
          eg.setString(PlantEquipmentListExtensibleFields::EquipmentObjectType,idfObject->iddObject().name());
          eg.setString(PlantEquipmentListExtensibleFields::EquipmentName,idfObject->name().get());
        }
      }
    }

    const auto & t_coolingComponents = coolingComponents( plantLoop );
    if( ! t_coolingComponents.empty() ) {
      IdfObject coolingOperation(IddObjectType::PlantEquipmentOperation_CoolingLoad);
      coolingOperation.setName(plantLoop.name().get() + " Cooling Operation Scheme");
      m_idfObjects.push_back(coolingOperation);
      coolingOperation.clearExtensibleGroups();

      IdfObject plantEquipmentList(IddObjectType::PlantEquipmentList);
      plantEquipmentList.setName(plantLoop.name().get() + " Cooling Equipment List");
      plantEquipmentList.clearExtensibleGroups();
      m_idfObjects.push_back(plantEquipmentList);

      IdfExtensibleGroup eg = coolingOperation.pushExtensibleGroup();
      eg.setDouble(PlantEquipmentOperation_CoolingLoadExtensibleFields::LoadRangeLowerLimit,0.0);
      eg.setDouble(PlantEquipmentOperation_CoolingLoadExtensibleFields::LoadRangeUpperLimit,1E9);
      eg.setString(PlantEquipmentOperation_CoolingLoadExtensibleFields::RangeEquipmentListName,plantEquipmentList.name().get());

      eg = operationSchemes.pushExtensibleGroup();
      eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeObjectType,coolingOperation.iddObject().name());
      eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeName,coolingOperation.name().get());
      eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeScheduleName,alwaysOn.name().get());

      for( auto coolingComponent : t_coolingComponents ) {
        if( const auto & idfObject = translateAndMapModelObject(coolingComponent) ) {
          IdfExtensibleGroup eg = plantEquipmentList.pushExtensibleGroup();
          eg.setString(PlantEquipmentListExtensibleFields::EquipmentObjectType,idfObject->iddObject().name());
          eg.setString(PlantEquipmentListExtensibleFields::EquipmentName,idfObject->name().get());
        }
      }
    }

    const auto & t_uncontrolledComponents = uncontrolledComponents( plantLoop );
    if( ! t_uncontrolledComponents.empty() ) {

      IdfObject uncontrolledOperation(IddObjectType::PlantEquipmentOperation_Uncontrolled);
      uncontrolledOperation.setName(plantLoop.name().get() + " Uncontrolled Operation Scheme");
      m_idfObjects.push_back(uncontrolledOperation);
      uncontrolledOperation.clearExtensibleGroups();

      IdfObject plantEquipmentList(IddObjectType::PlantEquipmentList);
      plantEquipmentList.setName(plantLoop.name().get() + " Uncontrolled Equipment List");
      plantEquipmentList.clearExtensibleGroups();
      m_idfObjects.push_back(plantEquipmentList);

      uncontrolledOperation.setString(PlantEquipmentOperation_UncontrolledFields::EquipmentListName,plantEquipmentList.name().get());

      auto eg = operationSchemes.pushExtensibleGroup();
      eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeObjectType,uncontrolledOperation.iddObject().name());
      eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeName,uncontrolledOperation.name().get());
      eg.setString(PlantEquipmentOperationSchemesExtensibleFields::ControlSchemeScheduleName,alwaysOn.name().get());

      for( auto uncontrolledComponent : t_uncontrolledComponents ) {
        if( const auto & idfObject = translateAndMapModelObject(uncontrolledComponent) ) {
          IdfExtensibleGroup eg = plantEquipmentList.pushExtensibleGroup();
          eg.setString(PlantEquipmentListExtensibleFields::EquipmentObjectType,idfObject->iddObject().name());
          eg.setString(PlantEquipmentListExtensibleFields::EquipmentName,idfObject->name().get());
        }
      }
    }

    createSetpointOperationScheme(plantLoop);
  }

  return operationSchemes;
}
boost::optional<IdfObject> ForwardTranslator::translateAirLoopHVACOutdoorAirSystem( AirLoopHVACOutdoorAirSystem & modelObject )
{
  OptionalString s;
  IdfObject idfObject(IddObjectType::AirLoopHVAC_OutdoorAirSystem);

  m_idfObjects.push_back(idfObject);

  // Name
  std::string name = modelObject.name().get();
  idfObject.setString(openstudio::AirLoopHVAC_OutdoorAirSystemFields::Name,name);
 

  // Controller List
  IdfObject _controllerList(IddObjectType::AirLoopHVAC_ControllerList);
  _controllerList.setName(name + " Controller List");
  _controllerList.clearExtensibleGroups();
  m_idfObjects.push_back(_controllerList);

  ControllerOutdoorAir controllerOutdoorAir = modelObject.getControllerOutdoorAir();
  boost::optional<IdfObject> _controllerOutdoorAir = translateAndMapModelObject(controllerOutdoorAir);
  OS_ASSERT(_controllerOutdoorAir);

  idfObject.setString(openstudio::AirLoopHVAC_OutdoorAirSystemFields::ControllerListName,_controllerList.name().get());

  IdfExtensibleGroup eg = _controllerList.pushExtensibleGroup();
  eg.setString(AirLoopHVAC_ControllerListExtensibleFields::ControllerObjectType,_controllerOutdoorAir->iddObject().name());
  eg.setString(AirLoopHVAC_ControllerListExtensibleFields::ControllerName,_controllerOutdoorAir->name().get());

  std::vector<ModelObject> controllers;
  auto components = modelObject.components();
  for( const auto & component : components ) {
    boost::optional<ControllerWaterCoil> controller;

    if( auto coil = component.optionalCast<CoilCoolingWater>() ) {
      controller = coil->controllerWaterCoil();
    } else if ( auto coil = component.optionalCast<CoilHeatingWater>() ) {
      controller = coil->controllerWaterCoil();
    }

    if( controller ) {
      controllers.push_back(controller.get());
    }
  } 
  
  for( auto & controller: controllers ) {
    auto _controller = translateAndMapModelObject(controller);
    if( _controller ) {
      IdfExtensibleGroup eg = _controllerList.pushExtensibleGroup();
      eg.setString(AirLoopHVAC_ControllerListExtensibleFields::ControllerObjectType,_controller->iddObject().name());
      eg.setString(AirLoopHVAC_ControllerListExtensibleFields::ControllerName,_controller->name().get());
    }
  }

  // Field: Availability Manager List Name //////////////////////////////////
  IdfObject availabilityManagerListIdf(IddObjectType::AvailabilityManagerAssignmentList);
  availabilityManagerListIdf.setName(name + " Availability Manager List");
  m_idfObjects.push_back(availabilityManagerListIdf);

  IdfObject availabilityManagerScheduledIdf = IdfObject(openstudio::IddObjectType::AvailabilityManager_Scheduled);
  availabilityManagerScheduledIdf.setName(name + " Availability Manager");
  m_idfObjects.push_back(availabilityManagerScheduledIdf);

  Schedule alwaysOn = modelObject.model().alwaysOnDiscreteSchedule();
  IdfObject alwaysOnIdf = translateAndMapModelObject(alwaysOn).get();

  s = availabilityManagerListIdf.getString(openstudio::AvailabilityManagerAssignmentListFields::Name);
  if(s)
  {
    idfObject.setString(openstudio::AirLoopHVAC_OutdoorAirSystemFields::AvailabilityManagerListName,*s);
  }

  availabilityManagerListIdf.setString(1 + openstudio::AvailabilityManagerAssignmentListExtensibleFields::AvailabilityManagerObjectType,
                                       availabilityManagerScheduledIdf.iddObject().name());
  availabilityManagerListIdf.setString(1 + openstudio::AvailabilityManagerAssignmentListExtensibleFields::AvailabilityManagerName,
                                       availabilityManagerScheduledIdf.name().get());
  availabilityManagerScheduledIdf.setString(openstudio::AvailabilityManager_ScheduledFields::ScheduleName,alwaysOnIdf.name().get());

  // OA Node List
  s = modelObject.outboardOANode()->name();
  IdfObject oaNodeListIdf(openstudio::IddObjectType::OutdoorAir_NodeList);
  if(s)
  {
    oaNodeListIdf.setString(0,*s);
  }
  m_idfObjects.push_back(oaNodeListIdf);

  ///////////////////////////////////////////////////////////////////////////
  // Field: Outdoor Air Equipment List Name /////////////////////////////////
  IdfObject equipmentListIdf(IddObjectType::AirLoopHVAC_OutdoorAirSystem_EquipmentList);
  equipmentListIdf.setName(name + " Equipment List");

  m_idfObjects.push_back(equipmentListIdf);

  IdfObject outdoorAirMixerIdf(IddObjectType::OutdoorAir_Mixer);
  outdoorAirMixerIdf.setName(name + " Outdoor Air Mixer");
  m_idfObjects.push_back(outdoorAirMixerIdf);

  s = modelObject.mixedAirModelObject()->name();
  if(s)
  {
    outdoorAirMixerIdf.setString(OutdoorAir_MixerFields::MixedAirNodeName,*s);
  }
  s = modelObject.outdoorAirModelObject()->name();
  if(s)
  {
    outdoorAirMixerIdf.setString(OutdoorAir_MixerFields::OutdoorAirStreamNodeName,*s);
  }

  s = modelObject.reliefAirModelObject()->name();
  if(s)
  {
    outdoorAirMixerIdf.setString(OutdoorAir_MixerFields::ReliefAirStreamNodeName,*s);
  }

  s = modelObject.returnAirModelObject()->name();
  if(s)
  {
    outdoorAirMixerIdf.setString(OutdoorAir_MixerFields::ReturnAirStreamNodeName,*s);
  }

  s = outdoorAirMixerIdf.iddObject().name();
  equipmentListIdf.setString(1,*s);
  s = outdoorAirMixerIdf.name();
  equipmentListIdf.setString(2,*s);

  unsigned i = 3;
  ModelObjectVector oaModelObjects = modelObject.oaComponents();
  for( ModelObjectVector::iterator oaIt = oaModelObjects.begin();
       oaIt != oaModelObjects.end();
       ++oaIt )
  {
    if( ! oaIt->optionalCast<Node>() )
    {
      if( boost::optional<IdfObject> idfObject = translateAndMapModelObject(*oaIt) )
      {
        equipmentListIdf.setString(i,idfObject->iddObject().name());
        i++;
        equipmentListIdf.setString(i,idfObject->name().get());
        i++;
      }
    }
  }

  ModelObjectVector reliefModelObjects = modelObject.reliefComponents();
  for( ModelObjectVector::iterator reliefIt = reliefModelObjects.begin();
       reliefIt != reliefModelObjects.end();
       ++reliefIt )
  {
    if( (! reliefIt->optionalCast<Node>()) && (! reliefIt->optionalCast<AirToAirComponent>()) )
    {
      if( boost::optional<IdfObject> idfObject = translateAndMapModelObject(*reliefIt) )
      {
        equipmentListIdf.setString(i,idfObject->iddObject().name());
        i++;
        equipmentListIdf.setString(i,idfObject->name().get());
        i++;
      }
    }
  }

  s = equipmentListIdf.name();
  if(s)
  {
    idfObject.setString(openstudio::AirLoopHVAC_OutdoorAirSystemFields::OutdoorAirEquipmentListName,*s);
  }

  return boost::optional<IdfObject>(idfObject);
}
IddObjectType GenericModelObject_Impl::iddObjectType() const
{
  IddObjectType retVal(iddObject().type());
  return retVal;
}
boost::optional<IdfObject> ForwardTranslator::translateThermalStorageIceDetailed( 
    ThermalStorageIceDetailed & modelObject)
{
  IdfObject idfObject(IddObjectType::ThermalStorage_Ice_Detailed);
  m_idfObjects.push_back(idfObject);

  // Name
  if( auto s = modelObject.name() ) {
    idfObject.setName(*s);
  }

  // InletNodeName
  if( auto mo = modelObject.inletModelObject() ) {
    if( auto node = mo->optionalCast<Node>() ) {
      idfObject.setString(ThermalStorage_Ice_DetailedFields::InletNodeName,node->name().get());
    }
  }

  // OutletNodeName
  if( auto mo = modelObject.outletModelObject() ) {
    if( auto node = mo->optionalCast<Node>() ) {
      idfObject.setString(ThermalStorage_Ice_DetailedFields::OutletNodeName,node->name().get());
    }
  }

  // AvailabilityScheduleName
  if( auto schedule = modelObject.availabilitySchedule() ) {
    idfObject.setString(ThermalStorage_Ice_DetailedFields::AvailabilityScheduleName,schedule->name().get());
  }

  // Capacity
  {
    auto value = modelObject.capacity();
    idfObject.setDouble(ThermalStorage_Ice_DetailedFields::Capacity,value);
  }

  // DischargingCurveObjectType
  // DischargingCurveName
  {
    auto curve = modelObject.dischargingCurve();
    auto idf = translateAndMapModelObject(curve);
    OS_ASSERT(idf);
    auto type = idf->iddObject().type();
    if( type == IddObjectType::Curve_QuadraticLinear ) {
      idfObject.setString(ThermalStorage_Ice_DetailedFields::DischargingCurveObjectType,"QuadraticLinear");
    } else if( type == IddObjectType::Curve_CubicLinear ) {
      idfObject.setString(ThermalStorage_Ice_DetailedFields::DischargingCurveObjectType,"CubicLinear");
    }
    idfObject.setString(ThermalStorage_Ice_DetailedFields::DischargingCurveName,idf->name().get());
  }

  // ChargingCurveObjectType
  // ChargingCurveName
  {
    auto curve = modelObject.chargingCurve();
    auto idf = translateAndMapModelObject(curve);
    OS_ASSERT(idf);
    auto type = idf->iddObject().type();
    if( type == IddObjectType::Curve_QuadraticLinear ) {
      idfObject.setString(ThermalStorage_Ice_DetailedFields::ChargingCurveObjectType,"QuadraticLinear");
    } else if( type == IddObjectType::Curve_CubicLinear ) {
      idfObject.setString(ThermalStorage_Ice_DetailedFields::ChargingCurveObjectType,"CubicLinear");
    }
    idfObject.setString(ThermalStorage_Ice_DetailedFields::ChargingCurveName,idf->name().get());
  }

  // TimestepoftheCurveData
  {
    auto value = modelObject.timestepoftheCurveData();
    idfObject.setDouble(ThermalStorage_Ice_DetailedFields::TimestepoftheCurveData,value);
  }

  // ParasiticElectricLoadDuringDischarging
  {
    auto value = modelObject.parasiticElectricLoadDuringDischarging();
    idfObject.setDouble(ThermalStorage_Ice_DetailedFields::ParasiticElectricLoadDuringDischarging,value);
  }

  // ParasiticElectricLoadDuringCharging
  {
    auto value = modelObject.parasiticElectricLoadDuringCharging();
    idfObject.setDouble(ThermalStorage_Ice_DetailedFields::ParasiticElectricLoadDuringCharging,value);
  }

  // TankLossCoefficient
  {
    auto value = modelObject.tankLossCoefficient();
    idfObject.setDouble(ThermalStorage_Ice_DetailedFields::TankLossCoefficient,value);
  }

  // FreezingTemperatureofStorageMedium
  {
    auto value = modelObject.freezingTemperatureofStorageMedium();
    idfObject.setDouble(ThermalStorage_Ice_DetailedFields::FreezingTemperatureofStorageMedium,value);
  }

  // ThawProcessIndicator
  {
    auto value = modelObject.thawProcessIndicator();
    idfObject.setString(ThermalStorage_Ice_DetailedFields::ThawProcessIndicator,value);
  }

  return idfObject;
}
boost::optional<IdfObject> ForwardTranslator::translateAirTerminalSingleDuctVAVHeatAndCoolReheat( AirTerminalSingleDuctVAVHeatAndCoolReheat & modelObject )
{
  OptionalModelObject temp;
  OptionalString optS;
  boost::optional<std::string> s;
  boost::optional<double> value;

  std::string baseName = modelObject.name().get();

  IdfObject _airDistributionUnit(openstudio::IddObjectType::ZoneHVAC_AirDistributionUnit);
  _airDistributionUnit.setName("ADU " + baseName ); //ADU: Air Distribution Unit

  IdfObject idfObject(openstudio::IddObjectType::AirTerminal_SingleDuct_VAV_HeatAndCool_Reheat);
  idfObject.setName(baseName);

  m_idfObjects.push_back(_airDistributionUnit);
  m_idfObjects.push_back(idfObject);

  auto coil = modelObject.reheatCoil();
  auto _coil = translateAndMapModelObject(coil);


  boost::optional<std::string> inletNodeName;
  boost::optional<std::string> outletNodeName;

  if( boost::optional<ModelObject> inletModelObject = modelObject.inletModelObject() )
  {
    if( boost::optional<Node> inletNode = inletModelObject->optionalCast<Node>() )
    {
      inletNodeName = inletNode->name().get();
    }
  }

  if( boost::optional<ModelObject> outletModelObject = modelObject.outletModelObject() )
  {
    if( boost::optional<Node> outletNode = outletModelObject->optionalCast<Node>() )
    {
      outletNodeName = outletNode->name().get();
    }
  }

  std::string damperOutletNodeName = baseName + " Damper Outlet Node";

  if( outletNodeName && inletNodeName )
  {
    if( _coil ) {
      if( _coil->iddObject().type() == IddObjectType::Coil_Heating_Gas )
      {
        _coil->setString(Coil_Heating_GasFields::AirInletNodeName,damperOutletNodeName);
        _coil->setString(Coil_Heating_GasFields::AirOutletNodeName,outletNodeName.get());
      }
      else if( _coil->iddObject().type() == IddObjectType::Coil_Heating_Electric )
      {
        _coil->setString(Coil_Heating_ElectricFields::AirInletNodeName,damperOutletNodeName);
        _coil->setString(Coil_Heating_ElectricFields::AirOutletNodeName,outletNodeName.get());
      }
      else if( _coil->iddObject().type() == IddObjectType::Coil_Heating_Water )
      {
        _coil->setString(Coil_Heating_WaterFields::AirInletNodeName,damperOutletNodeName);
        _coil->setString(Coil_Heating_WaterFields::AirOutletNodeName,outletNodeName.get());
      }
    }

    idfObject.setString(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::AirOutletNodeName,outletNodeName.get());
    idfObject.setString(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::AirInletNodeName,inletNodeName.get());
  }

  // AvailabilityScheduleName
  if( auto schedule = modelObject.availabilitySchedule() ) {
    if( auto _schedule = translateAndMapModelObject(schedule.get()) ) {
      idfObject.setString(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::AvailabilityScheduleName,_schedule->name().get());
    }
  }

  // DamperAirOutletNodeName
  idfObject.setString(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::DamperAirOutletNodeName,damperOutletNodeName);

  // AirInletNodeName
  if( auto node = modelObject.inletModelObject() ) {
    idfObject.setString(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::AirInletNodeName,node->name().get());
  }

  // MaximumAirFlowRate
  if( modelObject.isMaximumAirFlowRateAutosized() ) {
    idfObject.setString(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::MaximumAirFlowRate,"AutoSize");
  } else if( (value = modelObject.maximumAirFlowRate()) ) {
    idfObject.setDouble(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::MaximumAirFlowRate,value.get());
  }

  // ZoneMinimumAirFlowFraction
  if( (value = modelObject.zoneMinimumAirFlowFraction()) ) {
    idfObject.setDouble(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::ZoneMinimumAirFlowFraction,value.get());
  }

  if( _coil ) {
    // ReheatCoilObjectType
    idfObject.setString(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::ReheatCoilObjectType,_coil->iddObject().name());

    // ReheatCoilName
    idfObject.setString(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::ReheatCoilName,_coil->name().get());
  }

  // MaximumHotWaterorSteamFlowRate
  if( modelObject.isMaximumHotWaterorSteamFlowRateAutosized() ) {
    idfObject.setString(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::MaximumHotWaterorSteamFlowRate,"AutoSize");
  } else if( (value = modelObject.maximumHotWaterorSteamFlowRate()) ) {
    idfObject.setDouble(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::MaximumHotWaterorSteamFlowRate,value.get());
  }

  // MinimumHotWaterorSteamFlowRate
  if( (value = modelObject.minimumHotWaterorSteamFlowRate()) ) {
    idfObject.setDouble(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::MinimumHotWaterorSteamFlowRate,value.get());
  }

  // AirOutletNodeName
  if( auto node = modelObject.outletModelObject() ) {
    idfObject.setString(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::AirOutletNodeName,node->name().get());
  }

  // ConvergenceTolerance
  if( (value = modelObject.convergenceTolerance()) ) {
    idfObject.setDouble(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::ConvergenceTolerance,value.get());
  }

  // MaximumReheatAirTemperature
  if( (value = modelObject.maximumReheatAirTemperature()) ) {
    idfObject.setDouble(AirTerminal_SingleDuct_VAV_HeatAndCool_ReheatFields::MaximumReheatAirTemperature,value.get());
  }

  // Populate fields for AirDistributionUnit
  if( boost::optional<ModelObject> outletNode = modelObject.outletModelObject() )
  {
    _airDistributionUnit.setString(ZoneHVAC_AirDistributionUnitFields::AirDistributionUnitOutletNodeName,outletNode->name().get());
  }
  _airDistributionUnit.setString(ZoneHVAC_AirDistributionUnitFields::AirTerminalObjectType,idfObject.iddObject().name());
  _airDistributionUnit.setString(ZoneHVAC_AirDistributionUnitFields::AirTerminalName,idfObject.name().get());

  return _airDistributionUnit;
}