boost::optional<IdfObject> ForwardTranslator::translateZoneHVACLowTempRadiantVarFlow(ZoneHVACLowTempRadiantVarFlow& modelObject)
{
  boost::optional<std::string> s;
  boost::optional<double> value;
  boost::optional<ModelObject> temp;

  IdfObject idfObject(IddObjectType::ZoneHVAC_LowTemperatureRadiant_VariableFlow);
  m_idfObjects.push_back(idfObject);

  //Name
  std::string baseName = modelObject.name().get();
  idfObject.setName(baseName);

  // AvailabilityScheduleName
  if( boost::optional<Schedule> schedule = modelObject.availabilitySchedule() )
  {
    if( boost::optional<IdfObject> _schedule = translateAndMapModelObject(schedule.get()) )
    {
      idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::AvailabilityScheduleName,_schedule->name().get());
    }
  }

  //field Zone Name
  boost::optional<std::string> thermalZoneName;
  if( boost::optional<ThermalZone> zone = modelObject.thermalZone() )
  {
    if( (s = zone->name()) )
    {
      thermalZoneName = s;

      idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::ZoneName,thermalZoneName.get());
    }
  }

  //field Surface Name or Radiant Surface Type

  //create a new surface group object
  IdfObject _surfaceGroup(IddObjectType::ZoneHVAC_LowTemperatureRadiant_SurfaceGroup);

  //create a name for the surface group
  std::string sname = baseName + "" + modelObject.radiantSurfaceType().get();
  _surfaceGroup.setName(sname);

  //attach the surface group to the zone low temp radiant object
  idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::SurfaceNameorRadiantSurfaceGroupName,sname);

  //get rid of any existing surface (just to be safe)
  idfObject.clearExtensibleGroups();

  //aggregator for total area; will be used to create weighted area
  double totalAreaOfSurfaces = 0;

  //loop through all surfaces, adding up their area
  for (const Surface& surface : modelObject.surfaces()){
    totalAreaOfSurfaces = totalAreaOfSurfaces + surface.grossArea();
  }

  //loop through all the surfaces, adding them and their flow fractions (weighted per-area)
  for (const Surface& surface : modelObject.surfaces()){
    IdfExtensibleGroup group = _surfaceGroup.pushExtensibleGroup();
    OS_ASSERT(group.numFields() == 2);
    group.setString(0, surface.name().get());
    group.setDouble(1, (surface.grossArea()/totalAreaOfSurfaces) );
  }

  //add the surface group to the list of idf objects
  m_idfObjects.push_back(_surfaceGroup);


  //field Hydronic Tubing Inside Diameter
  if( (value = modelObject.hydronicTubingInsideDiameter()) )
  {
    idfObject.setDouble(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::HydronicTubingInsideDiameter,value.get());
  }

  //field Hydronic Tubing Length
  if( modelObject.isHydronicTubingLengthAutosized() )
  {
    idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::HydronicTubingLength,"Autosize");
  }
  else if( (value = modelObject.hydronicTubingLength()) )
  {
    idfObject.setDouble(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::HydronicTubingLength,value.get());
  }

  //field Temperature Control Type
  if(boost::optional<std::string> tempCtrlType= modelObject.temperatureControlType() )
  {
    idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::TemperatureControlType,tempCtrlType.get());
  }

  // Heating Coil
  HVACComponent heatingCoil = modelObject.heatingCoil();
  boost::optional<CoilHeatingLowTempRadiantVarFlow>  coilOptionalHeating = heatingCoil.optionalCast<CoilHeatingLowTempRadiantVarFlow>();

  if (coilOptionalHeating)
  {
    CoilHeatingLowTempRadiantVarFlow coilHeat = *coilOptionalHeating;

    // Heating Design Capacity Method - introduced in 8.2.0 and not yet supported in OS
    idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::HeatingDesignCapacityMethod,"HeatingDesignCapacity");

    // Heating Design Capacity - introduced in 8.2.0 and not yet supported in OS
    idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::HeatingDesignCapacity,"Autosize");
    
    // field Maximum Hot Water Flow
    if( coilHeat.isMaximumHotWaterFlowAutosized() )
    {
        idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::MaximumHotWaterFlow,"Autosize");
    }
    else if( (value = coilHeat.maximumHotWaterFlow()) )
    {
        idfObject.setDouble(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::MaximumHotWaterFlow,value.get());
    }

    // field Heating Water Inlet Node Name
    temp = coilHeat.inletModelObject();
    if(temp)
    {
      s = temp->name();
      if(s)
      {
        idfObject.setString(openstudio::ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::HeatingWaterInletNodeName,*s);
      }
    }

    //field Heating Water Outlet Node Name
    temp = coilHeat.outletModelObject();
    if(temp)
    {
      s = temp->name();
      if(s)
      {
        idfObject.setString(openstudio::ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::HeatingWaterOutletNodeName,*s);
      }
    }

    //field Heating Control Throttling Range
    if( (value = coilHeat.heatingControlThrottlingRange()) )
    {
        idfObject.setDouble(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::HeatingControlThrottlingRange,value.get());
    }

    //field Heating Control Temperature Schedule Name
    if( boost::optional<Schedule> schedule = coilHeat.heatingControlTemperatureSchedule() )
    {
      if( boost::optional<IdfObject> _schedule = translateAndMapModelObject(schedule.get()) )
      {
        idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::HeatingControlTemperatureScheduleName,_schedule->name().get());
      }
    }
  }

  // Cooling Coil
  HVACComponent coolingCoil = modelObject.coolingCoil();
  boost::optional<CoilCoolingLowTempRadiantVarFlow>  coilOptionalCooling = coolingCoil.optionalCast<CoilCoolingLowTempRadiantVarFlow>();

  if (coilOptionalCooling)
  {
    CoilCoolingLowTempRadiantVarFlow coilCool = *coilOptionalCooling;

    // Cooling Design Capacity Method - introduced in 8.2.0 and not yet supported in OS
    idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::CoolingDesignCapacityMethod,"CoolingDesignCapacity");

    // Cooling Design Capacity - introduced in 8.2.0 and not yet supported in OS
    idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::CoolingDesignCapacity,"Autosize");

    // Field Maximum Cold Water Flow
    if( coilCool.isMaximumColdWaterFlowAutosized() )
    {
      idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::MaximumColdWaterFlow,"Autosize");
    }
    else if( (value = coilCool.maximumColdWaterFlow()) )
    {
      idfObject.setDouble(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::MaximumColdWaterFlow,value.get());
    }

    // field Cooling Water Inlet Node Name
    temp = coilCool.inletModelObject();
    if(temp)
    {
      s = temp->name();
      if(s)
      {
        idfObject.setString(openstudio::ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::CoolingWaterInletNodeName,*s);
      }
    }

    //field Cooling Water Outlet Node Name
    temp = coilCool.outletModelObject();
    if(temp)
    {
      s = temp->name();
      if(s)
      {
        idfObject.setString(openstudio::ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::CoolingWaterOutletNodeName,*s);
      }
    }

    //field Cooling Control Throttling Range

    if( (value = coilCool.coolingControlThrottlingRange()) )
    {
      idfObject.setDouble(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::CoolingControlThrottlingRange,value.get());
    }

    //field Cooling Control Temperature Schedule Name
    if( boost::optional<Schedule> schedule = coilCool.coolingControlTemperatureSchedule() )
    {
      if( boost::optional<IdfObject> _schedule = translateAndMapModelObject(schedule.get()) )
      {
        idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::CoolingControlTemperatureScheduleName,_schedule->name().get());
      }
    }

    //field Condensation Control Type
    idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::CondensationControlType,coilCool.condensationControlType());

    //field Condensation Control Dewpoint Offset
    if( (value = coilCool.condensationControlDewpointOffset()) )
    {
      idfObject.setDouble(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::CondensationControlDewpointOffset,value.get());
    }
  }

  //field Number of Circuits
  idfObject.setString(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::NumberofCircuits,modelObject.numberofCircuits());

  //field Circuit Length
  idfObject.setDouble(ZoneHVAC_LowTemperatureRadiant_VariableFlowFields::CircuitLength,modelObject.circuitLength());

  return idfObject;
}
TEST_F(ModelFixture,ZoneHVACLowTempRadiantVarFlow_Set_Flow_Fractions)
{
    //make the example model
    Model model = model::exampleModel();

    //loop through all zones and add a radiant system to each one
    for (ThermalZone thermalZone : model.getModelObjects<ThermalZone>()) {
        //make a variable flow radiant unit
        ScheduleConstant availabilitySched(model);
        ScheduleConstant coolingControlTemperatureSchedule(model);
        ScheduleConstant heatingControlTemperatureSchedule(model);

        availabilitySched.setValue(1.0);
        coolingControlTemperatureSchedule.setValue(15.0);
        heatingControlTemperatureSchedule.setValue(10.0);

        CoilCoolingLowTempRadiantVarFlow testCC(model,coolingControlTemperatureSchedule);
        CoilHeatingLowTempRadiantVarFlow testHC(model,heatingControlTemperatureSchedule);

        HVACComponent testCC1 = testCC.cast<HVACComponent>();
        HVACComponent testHC1 = testHC.cast<HVACComponent>();

        ZoneHVACLowTempRadiantVarFlow testRad(model,availabilitySched,testHC1,testCC1);

        //set the coils
        testRad.setHeatingCoil(testHC1);
        testRad.setCoolingCoil(testCC1);

        //add it to the thermal zone
        testRad.addToThermalZone(thermalZone);

        //attach to ceilings
        testRad.setRadiantSurfaceType("Ceilings");

        //test that "surfaces" method returns 0 since no
        //ceilings have an internal source construction
        EXPECT_EQ(0,testRad.surfaces().size());

    }

    // Create some materials and make an internal source construction
    StandardOpaqueMaterial exterior(model);
    StandardOpaqueMaterial interior(model);
    OpaqueMaterialVector layers;
    layers.push_back(exterior);
    layers.push_back(interior);
    ConstructionWithInternalSource construction(layers);
    //construction.setLayers(layers);

    //set building's default ceiling construction to internal source construction
    DefaultConstructionSet defConSet = model.getModelObjects<DefaultConstructionSet>()[0];
    defConSet.defaultExteriorSurfaceConstructions()->setRoofCeilingConstruction(construction);

    //loop through all zones and check the flow fraction for each surface in the surface group.  it should be 0.25
    for (ThermalZone thermalZone : model.getModelObjects<ThermalZone>()) {

        //get the radiant zone equipment
        for (const ModelObject& equipment : thermalZone.equipment()) {
            if (equipment.optionalCast<ZoneHVACLowTempRadiantVarFlow>()) {
                ZoneHVACLowTempRadiantVarFlow testRad = equipment.optionalCast<ZoneHVACLowTempRadiantVarFlow>().get();
                EXPECT_EQ(4,testRad.surfaces().size());
            }
        }
    }

}