ModelObject ZoneHVACLowTempRadiantVarFlow_Impl::clone(Model model) const
  {
    ZoneHVACLowTempRadiantVarFlow lowTempRadiantVarFlowClone = ZoneHVACComponent_Impl::clone(model).cast<ZoneHVACLowTempRadiantVarFlow>();

    auto t_coolingCoil = coolingCoil();
    HVACComponent coolingCoilClone = t_coolingCoil.clone(model).cast<HVACComponent>();

    auto t_heatingCoil = heatingCoil();
    HVACComponent heatingCoilClone = t_heatingCoil.clone(model).cast<HVACComponent>();

    lowTempRadiantVarFlowClone.setHeatingCoil(heatingCoilClone);

    lowTempRadiantVarFlowClone.setCoolingCoil(coolingCoilClone);

    if( model == this->model() ) {
      if( auto waterToAirComponent = t_coolingCoil.optionalCast<WaterToAirComponent>() ) {
        if( auto plant = waterToAirComponent->plantLoop() ) {
          plant->addDemandBranchForComponent(coolingCoilClone);
        }
      }
      if( auto waterToAirComponent = t_heatingCoil.optionalCast<WaterToAirComponent>() ) {
        if( auto plant = waterToAirComponent->plantLoop() ) {
          plant->addDemandBranchForComponent(heatingCoilClone);
        }
      }
    }

    return lowTempRadiantVarFlowClone;
  }
TEST_F(ModelFixture,ZoneHVACLowTempRadiantVarFlow_Check_Constructor)
{
    Model model;
    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);

    // Test set and get heating coils
    testRad.setHeatingCoil(testHC1);
    EXPECT_EQ(testRad.heatingCoil(),testHC1);

    testRad.setCoolingCoil(testCC1);
    EXPECT_EQ(testRad.coolingCoil(),testCC1);

    // Test clone
    testRad.setHydronicTubingInsideDiameter(5);

    // Clone into the same model
    ZoneHVACLowTempRadiantVarFlow cloneRad = testRad.clone(model).cast<model::ZoneHVACLowTempRadiantVarFlow>();

    HVACComponent cloneCC1 = cloneRad.coolingCoil();
    HVACComponent cloneHC1 = cloneRad.heatingCoil();

    ASSERT_EQ(testRad.hydronicTubingInsideDiameter(), cloneRad.hydronicTubingInsideDiameter());

    // Clone into another model
    Model model2;
    ZoneHVACLowTempRadiantVarFlow cloneRad2 =   cloneRad.clone(model2).cast<model::ZoneHVACLowTempRadiantVarFlow>();
    ASSERT_EQ(cloneRad.hydronicTubingInsideDiameter(), cloneRad2.hydronicTubingInsideDiameter());

    //test add to and remove from Thermal zone
    ThermalZone thermalZone(model);
    EXPECT_TRUE(testRad.addToThermalZone(thermalZone));
    boost::optional<ThermalZone> testThermalZone = testRad.thermalZone();
    //EXPECT_EQ(*(testThermalZone),testRad.thermalZone());

    testRad.removeFromThermalZone();
    EXPECT_FALSE(testRad.thermalZone());

    // Test set and get radiant surface type

    testRad.setRadiantSurfaceType("Floors");
    boost::optional<std::string> str1 = testRad.radiantSurfaceType();
    EXPECT_EQ(*str1,"Floors");

    testRad.resetRadiantSurfaceType();
    str1 = testRad.radiantSurfaceType();
    EXPECT_EQ(*str1,"Ceilings");

    // Test set and get Hydronic Tubing Inside Diameter
    testRad.setHydronicTubingInsideDiameter(0.01);
    double inDia = testRad.hydronicTubingInsideDiameter();
    EXPECT_EQ(inDia, 0.01);
    EXPECT_FALSE(testRad.isHydronicTubingInsideDiameterDefaulted());

    testRad.resetHydronicTubingInsideDiameter();
    EXPECT_TRUE(testRad.isHydronicTubingInsideDiameterDefaulted());
    double inDia1 = testRad.hydronicTubingInsideDiameter();
    EXPECT_EQ(inDia1,0.013);

    // Test set and get Hydronic Tubing Length
    testRad.setHydronicTubingLength(200);
    boost::optional<double> length = testRad.hydronicTubingLength();
    EXPECT_EQ(*length, 200);
    EXPECT_FALSE(testRad.isHydronicTubingLengthDefaulted());
    EXPECT_FALSE(testRad.isHydronicTubingLengthAutosized());

    testRad.resetHydronicTubingLength();
    EXPECT_TRUE(testRad.isHydronicTubingLengthDefaulted());

    testRad.autosizeHydronicTubingLength();
    EXPECT_TRUE(testRad.isHydronicTubingLengthAutosized());

    // Test set and get Temperature Control Type
    testRad.setTemperatureControlType("OutdoorDryBulbTemperature");
    boost::optional<std::string> str2 = testRad.temperatureControlType();
    EXPECT_EQ(*str2,"OutdoorDryBulbTemperature");
    EXPECT_FALSE(testRad.isTemperatureControlTypeDefaulted());

    testRad.resetTemperatureControlType();
    EXPECT_TRUE(testRad.isTemperatureControlTypeDefaulted());
    boost::optional<std::string> str3 = testRad.temperatureControlType();
    EXPECT_EQ(*str3,"MeanAirTemperature");

    //test number of circuits
    testRad.setNumberofCircuits("CalculateFromCircuitLength");
    std::string numCirc = testRad.numberofCircuits();
    EXPECT_EQ(numCirc,"CalculateFromCircuitLength");

    //test circuit length
    testRad.setCircuitLength(200.0);
    double circLength = testRad.circuitLength();
    EXPECT_EQ(circLength,200.0);

}
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());
            }
        }
    }

}