# Custom changes for the LargeOffice prototype. # These are changes that are inconsistent with other prototype # building types. module LargeOffice def model_custom_hvac_tweaks(building_type, climate_zone, prototype_input, model) # add transformer transformer_efficiency = nil case template when '90.1-2004', '90.1-2007' transformer_efficiency = 0.979 when '90.1-2010', '90.1-2013' transformer_efficiency = 0.987 end return true unless !transformer_efficiency.nil? # rename datacenter plug loads sub categories, there should be 2 data center plug load objects in large office model.getElectricEquipments.sort.each do |item| if item.nameString.include? 'Data Center' item.setEndUseSubcategory('DataCenterPlugLoads') end end model_add_transformer(model, wired_lighting_frac: 0.0281, transformer_size: 500000, transformer_efficiency: transformer_efficiency, excluded_interiorequip_meter: 'DataCenterPlugLoads:InteriorEquipment:Electricity') system_to_space_map = define_hvac_system_map(building_type, climate_zone) system_to_space_map.each do |system| # find all zones associated with these spaces thermal_zones = [] system['space_names'].each do |space_name| space = model.getSpaceByName(space_name) if space.empty? OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "No space called #{space_name} was found in the model") return false end space = space.get zone = space.thermalZone if zone.empty? OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "No thermal zone was created for the space called #{space_name}") return false end thermal_zones << zone.get end return_plenum = nil unless system['return_plenum'].nil? return_plenum_space = model.getSpaceByName(system['return_plenum']) if return_plenum_space.empty? OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "No space called #{system['return_plenum']} was found in the model") return false end return_plenum_space = return_plenum_space.get return_plenum = return_plenum_space.thermalZone if return_plenum.empty? OpenStudio.logFree(OpenStudio::Error, 'openstudio.model.Model', "No thermal zone was created for the space called #{system['return_plenum']}") return false end return_plenum = return_plenum.get end end # TODO: replace CoolingTowerTwoSpeed with a FluidCoolerTwoSpeed once the simulation failures are resolved # set infiltration schedule for plenums # @todo remove once infil_sch in Standards.Space pulls from default building infiltration schedule model.getSpaces.each do |space| next unless space.name.get.to_s.include? 'Plenum' # add infiltration if DOE Ref vintage if template == 'DOE Ref 1980-2004' || template == 'DOE Ref Pre-1980' # Create an infiltration rate object for this space infiltration = OpenStudio::Model::SpaceInfiltrationDesignFlowRate.new(space.model) infiltration.setName("#{space.name} Infiltration") all_ext_infil_m3_per_s_per_m2 = OpenStudio.convert(0.2232, 'ft^3/min*ft^2', 'm^3/s*m^2').get infiltration.setFlowperExteriorSurfaceArea(all_ext_infil_m3_per_s_per_m2) infiltration.setSchedule(model_add_schedule(model, 'Large Office Infil Quarter On')) infiltration.setConstantTermCoefficient(1.0) infiltration.setTemperatureTermCoefficient(0.0) infiltration.setVelocityTermCoefficient(0.0) infiltration.setVelocitySquaredTermCoefficient(0.0) infiltration.setSpace(space) else space.spaceInfiltrationDesignFlowRates.each do |infiltration_object| infiltration_object.setSchedule(model_add_schedule(model, 'OfficeLarge INFIL_SCH_PNNL')) end end end model.getPlantLoops.sort.each do |plant_loop| if plant_loop.name.to_s == 'Heat Pump Loop' plant_loop.setFluidType('EthyleneGlycol') plant_loop.setGlycolConcentration(40) end end return true end def model_custom_daylighting_tweaks(building_type, climate_zone, prototype_input, model) OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Adjusting daylight sensor positions and fractions') adjustments = [ { '90.1-2010' => { 'Perimeter_bot_ZN_1' => { 'sensor_1_frac' => 0.05, 'sensor_2_frac' => 0.51, 'sensor_1_xyz' => [3.1242, 1.6764, 0.762], 'sensor_2_xyz' => [36.5536, 1.6764, 0.762], }, 'Perimeter_bot_ZN_2' => { 'sensor_1_frac' => 0.49, 'sensor_2_frac' => 0.08, 'sensor_1_xyz' => [71.4308, 24.3691, 0.762], 'sensor_2_xyz' => [71.4308, 3.1242, 0.762], }, 'Perimeter_bot_ZN_3' => { 'sensor_1_frac' => 0.51, 'sensor_2_frac' => 0.05, 'sensor_1_xyz' => [36.5536, 47.0617, 0.762], 'sensor_2_xyz' => [70.0034, 47.0617, 0.762], }, 'Perimeter_bot_ZN_4' => { 'sensor_1_frac' => 0.49, 'sensor_2_frac' => 0.08, 'sensor_1_xyz' => [1.6764, 24.3691, 0.762], 'sensor_2_xyz' => [1.6764, 45.6194, 0.762], }, 'Perimeter_mid_ZN_1' => { 'sensor_1_frac' => 0.05, 'sensor_2_frac' => 0.51, 'sensor_1_xyz' => [3.1242, 1.6764, 17.526], 'sensor_2_xyz' => [36.5536, 1.6764, 17.526], }, 'Perimeter_mid_ZN_2' => { 'sensor_1_frac' => 0.49, 'sensor_2_frac' => 0.08, 'sensor_1_xyz' => [71.4308, 24.3691, 17.526], 'sensor_2_xyz' => [71.4308, 3.1242, 17.526], }, 'Perimeter_mid_ZN_3' => { 'sensor_1_frac' => 0.51, 'sensor_2_frac' => 0.05, 'sensor_1_xyz' => [36.5536, 47.0617, 17.526], 'sensor_2_xyz' => [70.0034, 47.0617, 17.526], }, 'Perimeter_mid_ZN_4' => { 'sensor_1_frac' => 0.49, 'sensor_2_frac' => 0.08, 'sensor_1_xyz' => [1.6764, 24.3691, 17.526], 'sensor_2_xyz' => [1.6764, 45.6194, 17.526], }, 'Perimeter_top_ZN_1' => { 'sensor_1_frac' => 0.05, 'sensor_2_frac' => 0.51, 'sensor_1_xyz' => [3.1242, 1.6764, 34.29], 'sensor_2_xyz' => [36.5536, 1.6764, 34.29], }, 'Perimeter_top_ZN_2' => { 'sensor_1_frac' => 0.49, 'sensor_2_frac' => 0.08, 'sensor_1_xyz' => [71.4308, 24.3691, 34.29], 'sensor_2_xyz' => [71.4308, 3.1242, 34.29], }, 'Perimeter_top_ZN_3' => { 'sensor_1_frac' => 0.51, 'sensor_2_frac' => 0.05, 'sensor_1_xyz' => [36.5536, 47.0617, 34.29], 'sensor_2_xyz' => [70.0034, 47.0617, 34.29], }, 'Perimeter_top_ZN_4' => { 'sensor_1_frac' => 0.49, 'sensor_2_frac' => 0.08, 'sensor_1_xyz' => [1.6764, 24.3691, 34.29], 'sensor_2_xyz' => [1.6764, 45.6194, 34.29], }, }, '90.1-2013' => { 'Perimeter_bot_ZN_1' => { 'sensor_1_frac' => 0.3857, 'sensor_2_frac' => 0.1385, 'sensor_1_xyz' => [36.576, 1.6764, 0.762], 'sensor_2_xyz' => [36.576, 3.3528, 0.762], }, 'Perimeter_bot_ZN_2' => { 'sensor_1_frac' => 0.3857, 'sensor_2_frac' => 0.1385, 'sensor_1_xyz' => [71.4308, 24.384, 0.762], 'sensor_2_xyz' => [69.7544, 24.384, 0.762], }, 'Perimeter_bot_ZN_3' => { 'sensor_1_frac' => 0.3857, 'sensor_2_frac' => 0.1385, 'sensor_1_xyz' => [36.576, 47.0617, 0.762], 'sensor_2_xyz' => [36.576, 45.3847, 0.762], }, 'Perimeter_bot_ZN_4' => { 'sensor_1_frac' => 0.3857, 'sensor_2_frac' => 0.1385, 'sensor_1_xyz' => [1.6764, 24.384, 0.762], 'sensor_2_xyz' => [3.3528, 24.384, 0.762], }, 'Perimeter_mid_ZN_1' => { 'sensor_1_frac' => 0.3857, 'sensor_2_frac' => 0.1385, 'sensor_1_xyz' => [36.576, 1.6764, 17.526], 'sensor_2_xyz' => [36.576, 3.3528, 17.526], }, 'Perimeter_mid_ZN_2' => { 'sensor_1_frac' => 0.3857, 'sensor_2_frac' => 0.1385, 'sensor_1_xyz' => [71.4308, 24.384, 17.526], 'sensor_2_xyz' => [69.7544, 24.384, 17.526], }, 'Perimeter_mid_ZN_3' => { 'sensor_1_frac' => 0.3857, 'sensor_2_frac' => 0.1385, 'sensor_1_xyz' => [36.576, 47.0617, 17.526], 'sensor_2_xyz' => [36.576, 45.3847, 17.526], }, 'Perimeter_mid_ZN_4' => { 'sensor_1_frac' => 0.3857, 'sensor_2_frac' => 0.1385, 'sensor_1_xyz' => [1.6764, 24.384, 17.526], 'sensor_2_xyz' => [3.3528, 24.384, 17.526], }, 'Perimeter_top_ZN_1' => { 'sensor_1_frac' => 0.3857, 'sensor_2_frac' => 0.1385, 'sensor_1_xyz' => [36.576, 1.6764, 34.29], 'sensor_2_xyz' => [36.576, 3.3528, 34.29], }, 'Perimeter_top_ZN_2' => { 'sensor_1_frac' => 0.3857, 'sensor_2_frac' => 0.1385, 'sensor_1_xyz' => [71.4308, 24.384, 34.29], 'sensor_2_xyz' => [69.7544, 24.384, 34.29], }, 'Perimeter_top_ZN_3' => { 'sensor_1_frac' => 0.3857, 'sensor_2_frac' => 0.1385, 'sensor_1_xyz' => [36.576, 47.0617, 34.29], 'sensor_2_xyz' => [36.576, 45.3847, 34.29], }, 'Perimeter_top_ZN_4' => { 'sensor_1_frac' => 0.3857, 'sensor_2_frac' => 0.1385, 'sensor_1_xyz' => [1.6764, 24.384, 34.29], 'sensor_2_xyz' => [3.3528, 24.384, 34.29], }, }, } ] # Adjust daylight sensors in each space model.getSpaces.each do |space| if adjustments[0].keys.include? (template) if adjustments[0][template].keys.include? (space.name.to_s) adj = adjustments[0][template][space.name.to_s] next if space.thermalZone.empty? zone = space.thermalZone.get next if space.spaceType.empty? spc_type = space.spaceType.get next if spc_type.standardsSpaceType.empty? stds_spc_type = spc_type.standardsSpaceType.get # Adjust the primary sensor if adj['sensor_1_frac'] && zone.primaryDaylightingControl.is_initialized OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "For #{zone.name}: Adjusting primary daylight sensor to control #{adj['sensor_1_frac']} of the lighting.") zone.setFractionofZoneControlledbyPrimaryDaylightingControl(adj['sensor_1_frac']) pri_ctrl = zone.primaryDaylightingControl.get if adj['sensor_1_xyz'] x = adj['sensor_1_xyz'][0] y = adj['sensor_1_xyz'][1] z = adj['sensor_1_xyz'][2] OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "For #{zone.name}: Adjusting primary daylight sensor position to [#{x}, #{y}, #{z}].") pri_ctrl.setPositionXCoordinate(x) pri_ctrl.setPositionYCoordinate(y) pri_ctrl.setPositionZCoordinate(z) end end # Adjust the secondary sensor if adj['sensor_2_frac'] # Create second sensor if it doesn't exist if !zone.secondaryDaylightingControl.is_initialized sensor_2 = OpenStudio::Model::DaylightingControl.new(space.model) sensor_2.setName("#{space.name} Daylt Sensor 2") sensor_2.setSpace(space) sensor_2.setIlluminanceSetpoint(375) sensor_2.setLightingControlType('Stepped') sensor_2.setNumberofSteppedControlSteps(3) # all sensors 3-step per design sensor_2.setMinimumInputPowerFractionforContinuousDimmingControl(0.3) sensor_2.setMinimumLightOutputFractionforContinuousDimmingControl(0.2) sensor_2.setProbabilityLightingwillbeResetWhenNeededinManualSteppedControl(1.0) sensor_2.setMaximumAllowableDiscomfortGlareIndex(22.0) zone.setSecondaryDaylightingControl(sensor_2) end OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "For #{zone.name}: Adjusting secondary daylight sensor to control #{adj['sensor_2_frac']} of the lighting.") zone.setFractionofZoneControlledbySecondaryDaylightingControl(adj['sensor_2_frac']) sec_ctrl = zone.secondaryDaylightingControl.get if adj['sensor_2_xyz'] x = adj['sensor_2_xyz'][0] y = adj['sensor_2_xyz'][1] z = adj['sensor_2_xyz'][2] OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', "For #{zone.name}: Adjusting secondary daylight sensor position to [#{x}, #{y}, #{z}].") sec_ctrl.setPositionXCoordinate(x) sec_ctrl.setPositionYCoordinate(y) sec_ctrl.setPositionZCoordinate(z) end end end end end return true end def model_custom_swh_tweaks(model, building_type, climate_zone, prototype_input) return true end def model_custom_geometry_tweaks(building_type, climate_zone, prototype_input, model) return true end def air_terminal_single_duct_vav_reheat_apply_initial_prototype_damper_position(air_terminal_single_duct_vav_reheat, zone_oa_per_area) min_damper_position = template == '90.1-2010' || template == '90.1-2013' ? 0.2 : 0.3 # Set the minimum flow fraction air_terminal_single_duct_vav_reheat.setConstantMinimumAirFlowFraction(min_damper_position) return true end end