openstudio-standards 0.2.12.rc4 → 0.2.12.rc5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/data/standards/OpenStudio_Standards-ashrae_90_1(space_types).xlsx +0 -0
- data/data/standards/OpenStudio_Standards-ashrae_90_1.xlsx +0 -0
- data/data/standards/test_performance_expected_dd_results.csv +950 -950
- data/lib/openstudio-standards.rb +8 -1
- data/lib/openstudio-standards/btap/btap.model.rb +1 -1
- data/lib/openstudio-standards/btap/economics.rb +14 -11
- data/lib/openstudio-standards/btap/envelope.rb +185 -257
- data/lib/openstudio-standards/btap/fileio.rb +1 -0
- data/lib/openstudio-standards/btap/geometry.rb +21 -1
- data/lib/openstudio-standards/btap/measures.rb +12 -11
- data/lib/openstudio-standards/btap/schedules.rb +3 -12
- data/lib/openstudio-standards/hvac_sizing/Siz.AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.rb +178 -0
- data/lib/openstudio-standards/hvac_sizing/Siz.CoilCoolingDXMultiSpeed.rb +8 -8
- data/lib/openstudio-standards/hvac_sizing/Siz.Model.rb +3 -0
- data/lib/openstudio-standards/prototypes/common/objects/Prototype.hvac_systems.rb +3 -3
- data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +25 -23
- data/lib/openstudio-standards/standards/Standards.CoilCoolingDXMultiSpeed.rb +91 -0
- data/lib/openstudio-standards/standards/Standards.CoilDX.rb +20 -2
- data/lib/openstudio-standards/standards/Standards.CoilHeatingGasMultiStage.rb +39 -0
- data/lib/openstudio-standards/standards/Standards.Model.rb +29 -0
- data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +37 -4
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2004/data/ashrae_90_1_2004.unitary_acs.json +15 -15
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2007/data/ashrae_90_1_2007.unitary_acs.json +15 -15
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2010/data/ashrae_90_1_2010.unitary_acs.json +5 -5
- data/lib/openstudio-standards/standards/ashrae_90_1/ashrae_90_1_2013/data/ashrae_90_1_2013.unitary_acs.json +15 -15
- data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_1980_2004/data/doe_ref_1980_2004.spc_typ.json +5963 -2723
- data/lib/openstudio-standards/standards/ashrae_90_1/doe_ref_pre_1980/data/doe_ref_pre_1980.spc_typ.json +5917 -2697
- data/lib/openstudio-standards/standards/ashrae_90_1/nrel_zne_ready_2017/data/nrel_zne_ready_2017.spc_typ.json +2011 -1112
- data/lib/openstudio-standards/standards/ashrae_90_1/ze_aedg_multifamily/data/ze_aedg_multifamily.spc_typ.json +1946 -1106
- data/lib/openstudio-standards/standards/necb/BTAP1980TO2010/btap_1980to2010.rb +2 -18
- data/lib/openstudio-standards/standards/necb/BTAP1980TO2010/data/space_types.json +1677 -1005
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/btap_pre1980.rb +64 -13
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/building_envelope.rb +31 -19
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/curves.json +75 -0
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/heat_pumps.json +16 -16
- data/lib/openstudio-standards/standards/necb/BTAPPRE1980/data/space_types.json +1677 -1005
- data/lib/openstudio-standards/standards/necb/ECMS/data/boiler_set.json +29 -0
- data/lib/openstudio-standards/standards/necb/ECMS/data/curves.json +913 -0
- data/lib/openstudio-standards/standards/necb/ECMS/data/equip_eff_lim.json +52 -0
- data/lib/openstudio-standards/standards/necb/ECMS/data/erv.json +105 -0
- data/lib/openstudio-standards/standards/necb/ECMS/data/furnace_set.json +23 -0
- data/lib/openstudio-standards/standards/necb/ECMS/data/heat_pumps.json +803 -0
- data/lib/openstudio-standards/standards/necb/ECMS/data/heat_pumps_heating.json +787 -0
- data/lib/openstudio-standards/standards/necb/ECMS/data/shw_set.json +29 -0
- data/lib/openstudio-standards/standards/necb/ECMS/ecms.rb +87 -0
- data/lib/openstudio-standards/standards/necb/ECMS/erv.rb +22 -0
- data/lib/openstudio-standards/standards/necb/ECMS/hvac_systems.rb +1593 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/autozone.rb +68 -33
- data/lib/openstudio-standards/standards/necb/NECB2011/beps_compliance_path.rb +24 -13
- data/lib/openstudio-standards/standards/necb/NECB2011/building_envelope.rb +104 -99
- data/lib/openstudio-standards/standards/necb/NECB2011/data/constants.json +24 -24
- data/lib/openstudio-standards/standards/necb/NECB2011/data/curves.json +50 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/data/erv.json +31 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/data/led_lighting_data.json +2028 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/data/space_types.json +1745 -1297
- data/lib/openstudio-standards/standards/necb/NECB2011/daylighting_control.md +70 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/demand_controlled_ventilation.md +46 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_multi_speed.rb +69 -107
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_1_single_speed.rb +24 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_multi_speed.rb +139 -141
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_system_3_and_8_single_speed.rb +24 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/hvac_systems.rb +344 -234
- data/lib/openstudio-standards/standards/necb/NECB2011/led_lighting.md +51 -0
- data/lib/openstudio-standards/standards/necb/NECB2011/lighting.rb +57 -9
- data/lib/openstudio-standards/standards/necb/NECB2011/necb_2011.rb +1060 -34
- data/lib/openstudio-standards/standards/necb/NECB2011/qaqc/necb_qaqc.rb +9 -1
- data/lib/openstudio-standards/standards/necb/NECB2011/service_water_heating.rb +1 -1
- data/lib/openstudio-standards/standards/necb/NECB2015/data/led_lighting_data.json +2883 -0
- data/lib/openstudio-standards/standards/necb/NECB2015/data/space_types.json +2554 -1916
- data/lib/openstudio-standards/standards/necb/NECB2015/necb_2015.rb +32 -1
- data/lib/openstudio-standards/standards/necb/NECB2017/data/led_lighting_data.json +2883 -0
- data/lib/openstudio-standards/standards/necb/NECB2017/data/space_types.json +2554 -1916
- data/lib/openstudio-standards/standards/necb/NECB2017/necb_2017.rb +29 -0
- data/lib/openstudio-standards/version.rb +1 -1
- metadata +21 -2
@@ -0,0 +1,29 @@
|
|
1
|
+
{
|
2
|
+
"tables": {
|
3
|
+
"shw_eff_ecm": {
|
4
|
+
"refs": [
|
5
|
+
"assumption"
|
6
|
+
],
|
7
|
+
"table": [
|
8
|
+
{
|
9
|
+
"name": "NECB_Default",
|
10
|
+
"efficiency": null,
|
11
|
+
"part_load_curve": null,
|
12
|
+
"notes": "Do nothing."
|
13
|
+
},
|
14
|
+
{
|
15
|
+
"name": "Natural Gas Power Vent with Electric Ignition",
|
16
|
+
"efficiency": 0.94,
|
17
|
+
"part_load_curve": "SWH-EFFFPLR-NECB2011",
|
18
|
+
"notes": "From AHRI."
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"name": "Natural Gas Direct Vent with Electric Ignition",
|
22
|
+
"efficiency": 0.91,
|
23
|
+
"part_load_curve": "SWH-EFFFPLR-NECB2011",
|
24
|
+
"notes": "From AHRI."
|
25
|
+
}
|
26
|
+
]
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
@@ -0,0 +1,87 @@
|
|
1
|
+
class ECMS < NECB2011
|
2
|
+
|
3
|
+
@template = self.new.class.name
|
4
|
+
register_standard(@template)
|
5
|
+
|
6
|
+
# Combine the data from the JSON files into a single hash
|
7
|
+
# Load JSON files differently depending on whether loading from
|
8
|
+
# the OpenStudio CLI embedded filesystem or from typical gem installation
|
9
|
+
def load_standards_database_new()
|
10
|
+
@standards_data = {}
|
11
|
+
@standards_data["tables"] = {}
|
12
|
+
|
13
|
+
if __dir__[0] == ':' # Running from OpenStudio CLI
|
14
|
+
embedded_files_relative('data/', /.*\.json/).each do |file|
|
15
|
+
data = JSON.parse(EmbeddedScripting.getFileAsString(file))
|
16
|
+
if not data["tables"].nil? and data["tables"].first["data_type"] == "table"
|
17
|
+
@standards_data["tables"] << data["tables"].first
|
18
|
+
else
|
19
|
+
@standards_data[data.keys.first] = data[data.keys.first]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
else
|
23
|
+
files = Dir.glob("#{File.dirname(__FILE__)}/data/*.json").select { |e| File.file? e }
|
24
|
+
files.each do |file|
|
25
|
+
data = JSON.parse(File.read(file))
|
26
|
+
if not data["tables"].nil?
|
27
|
+
@standards_data["tables"] = [*@standards_data["tables"], *data["tables"]].to_h
|
28
|
+
else
|
29
|
+
@standards_data[data.keys.first] = data[data.keys.first]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
return @standards_data
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
super()
|
39
|
+
@template = self.class.name
|
40
|
+
@standards_data = self.load_standards_database_new()
|
41
|
+
@standards_data['curves'] = standards_data['tables']["curves"]['table']
|
42
|
+
end
|
43
|
+
|
44
|
+
def apply_system_ecm(model:, ecm_system_name: nil, template_standard:, runner: nil)
|
45
|
+
# Do nothing if nil or other usual suspects.. covering all bases for now.
|
46
|
+
return if ecm_system_name.nil? || ecm_system_name == 'none' || ecm_system_name == 'NECB_Default'
|
47
|
+
|
48
|
+
ecm_std = Standard.build("ECMS")
|
49
|
+
systems = model.getAirLoopHVACs
|
50
|
+
map_system_to_zones, system_doas_flags = ecm_std.get_map_systems_to_zones(systems)
|
51
|
+
zone_clg_eqpt_type = ecm_std.get_zone_clg_eqpt_type(model)
|
52
|
+
# when the ecm is associated with adding a new HVAC system, then remove existing system components and loops
|
53
|
+
ecm_add_method_name = "add_ecm_#{ecm_system_name.downcase}"
|
54
|
+
|
55
|
+
raise("the method #{ecm_add_method_name} does not exist in the ECM class. Please verify that this should be called.") unless ecm_std.respond_to? ecm_add_method_name
|
56
|
+
|
57
|
+
ecm_std.remove_all_zone_eqpt(systems)
|
58
|
+
ecm_std.remove_air_loops(model)
|
59
|
+
ecm_std.remove_hw_loops(model)
|
60
|
+
ecm_std.remove_chw_loops(model)
|
61
|
+
ecm_std.remove_cw_loops(model)
|
62
|
+
ecm_std.send(ecm_add_method_name,
|
63
|
+
model: model,
|
64
|
+
system_zones_map: map_system_to_zones,
|
65
|
+
system_doas_flags: system_doas_flags,
|
66
|
+
zone_clg_eqpt_type: zone_clg_eqpt_type,
|
67
|
+
standard: template_standard)
|
68
|
+
#ecm_std.add_ecm_hs09_ccashpsys(model:model,system_zones_map:,system_doas_flags:,zone_clg_eqpt_type: nil,standard:,baseboard_flag: true)
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
def apply_system_efficiencies_ecm(model:, ecm_system_name: nil)
|
73
|
+
# Do nothing if nil.
|
74
|
+
return if ecm_system_name.nil? || ecm_system_name == 'none' || ecm_system_name == 'NECB_Default'
|
75
|
+
ecm_std = Standard.build("ECMS")
|
76
|
+
# Get method name that should be present in the ECM class.
|
77
|
+
ecm_apply_eff_method_name = "apply_efficiency_ecm_#{ecm_system_name.downcase}"
|
78
|
+
# Raise exception if method does not exists.
|
79
|
+
raise("the method #{ecm_apply_eff_method_name} does not exist in the ECM class. Please verify that this should be called.") unless ecm_std.respond_to?(ecm_apply_eff_method_name)
|
80
|
+
|
81
|
+
# apply system eff method.
|
82
|
+
ecm_std.send(ecm_apply_eff_method_name, model: model, ecm_name: ecm_system_name)
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class ECMS
|
2
|
+
# This method will add a skeleton erv to all air loops.
|
3
|
+
def apply_erv_ecm(model:, erv_package: nil)
|
4
|
+
# If erv is nil.. do nothing.
|
5
|
+
return if erv_package.nil? || erv_package == 'none' || erv_package == 'NECB_Default'
|
6
|
+
|
7
|
+
model.getAirLoopHVACs.each do |air_loop|
|
8
|
+
# Adds default erv to all air_loops
|
9
|
+
air_loop_hvac_apply_energy_recovery_ventilator(air_loop, nil)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# This method will set the properties of the ERV that was added above. Must be run after the standard efficiency is complete as this will overwrite
|
14
|
+
# those values. See data/erv.json to view/add different erv packages.
|
15
|
+
def apply_erv_ecm_efficiency(model:, erv_package: nil)
|
16
|
+
# If erv is nil.. do nothing.
|
17
|
+
return if erv_package.nil? || erv_package == 'none' || erv_package == 'NECB_Default'
|
18
|
+
|
19
|
+
# This calls the NECB2011 implementation of the method.
|
20
|
+
model.getHeatExchangerAirToAirSensibleAndLatents.each { |erv| heat_exchanger_air_to_air_sensible_and_latent_apply_efficiency(erv, erv_package) }
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,1593 @@
|
|
1
|
+
class ECMS
|
2
|
+
|
3
|
+
# =============================================================================================================================
|
4
|
+
# Remove existing zone equipment
|
5
|
+
def remove_all_zone_eqpt(sys_objs)
|
6
|
+
sys_objs.each do |isys|
|
7
|
+
isys.thermalZones.each do |izone|
|
8
|
+
if(izone.equipment.empty?) then next end
|
9
|
+
izone.equipment.each {|icomp| icomp.remove}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# =============================================================================================================================
|
15
|
+
# Remove hot-water plant loops
|
16
|
+
def remove_hw_loops(model)
|
17
|
+
model.getPlantLoops.each do |iloop|
|
18
|
+
hw_loop = false
|
19
|
+
iloop.supplyComponents.each do |icomp|
|
20
|
+
if(icomp.to_BoilerHotWater.is_initialized)
|
21
|
+
hw_loop = true
|
22
|
+
break
|
23
|
+
end
|
24
|
+
end
|
25
|
+
if hw_loop then iloop.remove end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# =============================================================================================================================
|
30
|
+
# Remove chilled-water plant loops
|
31
|
+
def remove_chw_loops(model)
|
32
|
+
model.getPlantLoops.each do |iloop|
|
33
|
+
chw_loop = false
|
34
|
+
iloop.supplyComponents.each do |icomp|
|
35
|
+
if(icomp.to_ChillerElectricEIR.is_initialized)
|
36
|
+
chw_loop = true
|
37
|
+
break
|
38
|
+
end
|
39
|
+
end
|
40
|
+
if chw_loop then iloop.remove end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# =============================================================================================================================
|
45
|
+
# Remove condenser-water plant loops
|
46
|
+
def remove_cw_loops(model)
|
47
|
+
model.getPlantLoops.each do |iloop|
|
48
|
+
cw_loop = false
|
49
|
+
iloop.supplyComponents.each do |icomp|
|
50
|
+
if(icomp.to_CoolingTowerSingleSpeed.is_initialized)
|
51
|
+
cw_loop = true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
if cw_loop then iloop.remove end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# =============================================================================================================================
|
59
|
+
# Remove air loops
|
60
|
+
def remove_air_loops(model)
|
61
|
+
# remove air loops
|
62
|
+
model.getAirLoopHVACs.each do |iloop|
|
63
|
+
iloop.remove
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# =============================================================================================================================
|
68
|
+
# Return map of systems to zones and set flag for dedicated outdoor air unit for each system
|
69
|
+
def get_map_systems_to_zones(systems)
|
70
|
+
map_systems_to_zones = {}
|
71
|
+
system_doas_flags = {}
|
72
|
+
systems.each do |system|
|
73
|
+
zones = system.thermalZones
|
74
|
+
map_systems_to_zones[system.name.to_s] = zones
|
75
|
+
if system.sizingSystem.typeofLoadtoSizeOn.to_s == "VentilationRequirement"
|
76
|
+
system_doas_flags[system.name.to_s] = true
|
77
|
+
else
|
78
|
+
system_doas_flags[system.name.to_s] = false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
return map_systems_to_zones,system_doas_flags
|
82
|
+
end
|
83
|
+
|
84
|
+
# =============================================================================================================================
|
85
|
+
# Return hash of zone and cooling equipment type in the zone
|
86
|
+
def get_zone_clg_eqpt_type(model)
|
87
|
+
zone_clg_eqpt_type = {}
|
88
|
+
model.getThermalZones.each do |zone|
|
89
|
+
zone.equipment.each do |eqpt|
|
90
|
+
if eqpt.to_ZoneHVACPackagedTerminalAirConditioner.is_initialized
|
91
|
+
zone_clg_eqpt_type[zone.name.to_s] = "ZoneHVACPackagedTerminalAirConditioner"
|
92
|
+
break
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
return zone_clg_eqpt_type
|
97
|
+
end
|
98
|
+
|
99
|
+
# =============================================================================================================================
|
100
|
+
# Return hash of flags for whether storey is conditioned and average ceiling z-coordinates of building storeys.
|
101
|
+
def get_storey_avg_clg_zcoords(model)
|
102
|
+
storey_avg_clg_zcoords = {}
|
103
|
+
model.getBuildingStorys.each do |storey|
|
104
|
+
storey_avg_clg_zcoords[storey] = []
|
105
|
+
storey_cond = false
|
106
|
+
total_area = 0.0
|
107
|
+
sum = 0.0
|
108
|
+
storey.spaces.each do |space|
|
109
|
+
# Determine if any of the spaces/zones of the storey are conditioned? If yes then the floor is considered to be conditioned
|
110
|
+
if space.thermalZone.is_initialized
|
111
|
+
zone = space.thermalZone.get
|
112
|
+
if zone.thermostat.is_initialized
|
113
|
+
if zone.thermostat.get.to_ThermostatSetpointDualSetpoint.is_initialized
|
114
|
+
if zone.thermostat.get.to_ThermostatSetpointDualSetpoint.get.heatingSetpointTemperatureSchedule.is_initialized ||
|
115
|
+
zone.thermostat.get.to_ThermostatSetpointDualSetpoint.get.coolingSetpointTemperatureSchedule.is_initialized
|
116
|
+
storey_cond = true
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
# Find average height of z-coordinates of ceiling/roof of floor
|
122
|
+
space.surfaces.each do |surf|
|
123
|
+
if (surf.surfaceType.to_s.upcase == "ROOFCEILING")
|
124
|
+
sum += (surf.centroid.z.to_f + space.zOrigin.to_f) * surf.grossArea.to_f
|
125
|
+
total_area += surf.grossArea.to_f
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
storey_avg_clg_zcoords[storey] << storey_cond
|
130
|
+
storey_avg_clg_zcoords[storey] << (sum / total_area)
|
131
|
+
end
|
132
|
+
|
133
|
+
return storey_avg_clg_zcoords
|
134
|
+
end
|
135
|
+
|
136
|
+
# =============================================================================================================================
|
137
|
+
# Return x,y,z coordinates of exterior wall with largest area on the lowest floor
|
138
|
+
def get_lowest_floor_ext_wall_centroid_coords(storeys_clg_zcoords)
|
139
|
+
ext_wall,ext_wall_x,ext_wall_y,ext_wall_z = nil,nil,nil,nil
|
140
|
+
storeys_clg_zcoords.keys.each do |storey|
|
141
|
+
max_area = 0.0
|
142
|
+
sorted_spaces = storey.spaces.sort_by {|space| space.name.to_s}
|
143
|
+
sorted_spaces.each do |space|
|
144
|
+
ext_walls = space.surfaces.select {|surf| (surf.surfaceType.to_s.upcase == "WALL") && (surf.outsideBoundaryCondition.to_s.upcase == "OUTDOORS")}
|
145
|
+
ext_walls = ext_walls.sort_by {|wall| wall.grossArea.to_f}
|
146
|
+
if not ext_walls.empty?
|
147
|
+
if ext_walls.last.grossArea.to_f > max_area
|
148
|
+
max_area = ext_walls.last.grossArea.to_f
|
149
|
+
ext_wall_x = ext_walls.last.centroid.x.to_f + space.xOrigin.to_f
|
150
|
+
ext_wall_y = ext_walls.last.centroid.y.to_f + space.yOrigin.to_f
|
151
|
+
ext_wall_z = ext_walls.last.centroid.z.to_f + space.zOrigin.to_f
|
152
|
+
ext_wall = ext_walls.last
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
break unless not ext_wall
|
157
|
+
end
|
158
|
+
if not ext_wall
|
159
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudiostandards.get_lowest_floor_ext_wall_centroid_coords','Did not find an exteior wall in the building!')
|
160
|
+
end
|
161
|
+
|
162
|
+
return ext_wall_x,ext_wall_y,ext_wall_z
|
163
|
+
end
|
164
|
+
|
165
|
+
# =============================================================================================================================
|
166
|
+
# Return x,y,z coordinates of space centroid
|
167
|
+
def get_space_centroid_coords(space)
|
168
|
+
total_area = 0.0
|
169
|
+
sum_x,sum_y,sum_z = 0.0,0.0,0.0
|
170
|
+
space.surfaces.each do |surf|
|
171
|
+
total_area += surf.grossArea.to_f
|
172
|
+
sum_x += (surf.centroid.x.to_f + space.xOrigin.to_f) * surf.grossArea.to_f
|
173
|
+
sum_y += (surf.centroid.y.to_f + space.yOrigin.to_f) * surf.grossArea.to_f
|
174
|
+
sum_z += (surf.centroid.z.to_f + space.zOrigin.to_f) * surf.grossArea.to_f
|
175
|
+
end
|
176
|
+
space_centroid_x = sum_x / total_area
|
177
|
+
space_centroid_y = sum_y / total_area
|
178
|
+
space_centroid_z = sum_z / total_area
|
179
|
+
|
180
|
+
return space_centroid_x,space_centroid_y,space_centroid_z
|
181
|
+
end
|
182
|
+
|
183
|
+
# =============================================================================================================================
|
184
|
+
# Return x,y,z coordinates of the centroid of the roof of the storey
|
185
|
+
def get_roof_centroid_coords(storey)
|
186
|
+
sum_x,sum_y,sum_z,total_area = 0.0,0.0,0.0,0.0
|
187
|
+
cent_x,cent_y,cent_z = nil,nil,nil
|
188
|
+
storey.spaces.each do |space|
|
189
|
+
roof_surfaces = space.surfaces.select {|surf| (surf.surfaceType.to_s.upcase == "ROOFCEILING") && (surf.outsideBoundaryCondition.to_s.upcase == "OUTDOORS")}
|
190
|
+
roof_surfaces.each do |surf|
|
191
|
+
sum_x += (surf.centroid.x.to_f + space.xOrigin.to_f) * surf.grossArea.to_f
|
192
|
+
sum_y += (surf.centroid.y.to_f + space.yOrigin.to_f) * surf.grossArea.to_f
|
193
|
+
sum_z += (surf.centroid.z.to_f + space.zOrigin.to_f) * surf.grossArea.to_f
|
194
|
+
total_area += surf.grossArea.to_f
|
195
|
+
end
|
196
|
+
end
|
197
|
+
if total_area > 0.0
|
198
|
+
cent_x = sum_x / total_area
|
199
|
+
cent_y = sum_y / total_area
|
200
|
+
cent_z = sum_z / total_area
|
201
|
+
else
|
202
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudiostandards.get_roof_centroid_coords','Did not find a roof on the top floor!')
|
203
|
+
end
|
204
|
+
|
205
|
+
return cent_x,cent_y,cent_z
|
206
|
+
end
|
207
|
+
|
208
|
+
# =============================================================================================================================
|
209
|
+
# Determine maximum equivalent and net vertical pipe runs for VRF model
|
210
|
+
def get_max_vrf_pipe_lengths(model)
|
211
|
+
# Get and sort floors average ceilings z-coordinates hash
|
212
|
+
storeys_clg_zcoords = get_storey_avg_clg_zcoords(model)
|
213
|
+
storeys_clg_zcoords = storeys_clg_zcoords.sort_by {|key,value| value[1]}.to_h # sort storeys hash based on ceiling/roof z-coordinate
|
214
|
+
if storeys_clg_zcoords.values.last[0]
|
215
|
+
# If the top floor is conditioned, then assume the top floor is not an attic floor and place the VRF outdoor unit at the roof centroid
|
216
|
+
location_cent_x,location_cent_y,location_cent_z = get_roof_centroid_coords(storeys_clg_zcoords.keys.last)
|
217
|
+
else
|
218
|
+
# If the top floor is not conditioned, then assume it's an attic floor. In this case place the VRF outdoor unit next to the centroid
|
219
|
+
# of the exterior wall with the largest area on the lowest floor.
|
220
|
+
location_cent_x,location_cent_y,location_cent_z = get_lowest_floor_ext_wall_centroid_coords(storeys_clg_zcoords)
|
221
|
+
end
|
222
|
+
# Initialize distances
|
223
|
+
max_equiv_distance = 0.0
|
224
|
+
max_vert_distance = 0.0
|
225
|
+
min_vert_distance = 0.0
|
226
|
+
storeys_clg_zcoords.keys.each do |storey|
|
227
|
+
next unless storeys_clg_zcoords[storey][0]
|
228
|
+
storey.spaces.each do |space|
|
229
|
+
# Is there a VRF terminal unit in the space/zone?
|
230
|
+
vrf_term_units = []
|
231
|
+
if space.thermalZone.is_initialized
|
232
|
+
vrf_term_units = space.thermalZone.get.equipment.select {|eqpt| eqpt.to_ZoneHVACTerminalUnitVariableRefrigerantFlow.is_initialized}
|
233
|
+
end
|
234
|
+
next unless not vrf_term_units.empty?
|
235
|
+
space_centroid_x,space_centroid_y,space_centroid_z = get_space_centroid_coords(space)
|
236
|
+
# Update max horizontal and vertical distances if needed
|
237
|
+
equiv_distance = (location_cent_x.to_f - space_centroid_x.to_f).abs +
|
238
|
+
(location_cent_y.to_f - space_centroid_y.to_f).abs +
|
239
|
+
(location_cent_z.to_f - space_centroid_z.to_f).abs
|
240
|
+
if equiv_distance > max_equiv_distance then max_equiv_distance = equiv_distance end
|
241
|
+
pos_vert_distance = [space_centroid_z.to_f-location_cent_z.to_f,0.0].max
|
242
|
+
if pos_vert_distance > max_vert_distance then max_vert_distance = pos_vert_distance end
|
243
|
+
neg_vert_distance = [space_centroid_z.to_f-location_cent_z.to_f,0.0].min
|
244
|
+
if neg_vert_distance < min_vert_distance then min_vert_distance = neg_vert_distance end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
max_net_vert_distance = max_vert_distance + min_vert_distance
|
248
|
+
max_net_vert_distance = [max_net_vert_distance,0.000001].max
|
249
|
+
|
250
|
+
return max_equiv_distance,max_net_vert_distance
|
251
|
+
end
|
252
|
+
|
253
|
+
# =============================================================================================================================
|
254
|
+
# Add an outdoor VRF unit
|
255
|
+
def add_outdoor_vrf_unit(model:,ecm_name: nil,condenser_type: "AirCooled")
|
256
|
+
outdoor_vrf_unit = OpenStudio::Model::AirConditionerVariableRefrigerantFlow.new(model)
|
257
|
+
outdoor_vrf_unit.setName("VRF Outdoor Unit")
|
258
|
+
outdoor_vrf_unit.setHeatPumpWasteHeatRecovery(true)
|
259
|
+
outdoor_vrf_unit.setRatedHeatingCOP(4.0)
|
260
|
+
outdoor_vrf_unit.setRatedCoolingCOP(4.0)
|
261
|
+
outdoor_vrf_unit.setMinimumOutdoorTemperatureinHeatingMode(-25.0)
|
262
|
+
outdoor_vrf_unit.setHeatingPerformanceCurveOutdoorTemperatureType("WetBulbTemperature")
|
263
|
+
outdoor_vrf_unit.setMasterThermostatPriorityControlType("ThermostatOffsetPriority")
|
264
|
+
outdoor_vrf_unit.setDefrostControl('OnDemand')
|
265
|
+
outdoor_vrf_unit.setDefrostStrategy('ReverseCycle')
|
266
|
+
outdoor_vrf_unit.autosizeResistiveDefrostHeaterCapacity
|
267
|
+
outdoor_vrf_unit.setPipingCorrectionFactorforHeightinHeatingModeCoefficient(-0.00019231)
|
268
|
+
outdoor_vrf_unit.setPipingCorrectionFactorforHeightinCoolingModeCoefficient(-0.00019231)
|
269
|
+
outdoor_vrf_unit.setMinimumOutdoorTemperatureinHeatRecoveryMode(-5.0)
|
270
|
+
outdoor_vrf_unit.setMaximumOutdoorTemperatureinHeatRecoveryMode(26.2)
|
271
|
+
outdoor_vrf_unit.setInitialHeatRecoveryCoolingCapacityFraction(0.5)
|
272
|
+
outdoor_vrf_unit.setHeatRecoveryCoolingCapacityTimeConstant(0.15)
|
273
|
+
outdoor_vrf_unit.setInitialHeatRecoveryCoolingEnergyFraction(1.0)
|
274
|
+
outdoor_vrf_unit.setHeatRecoveryCoolingEnergyTimeConstant(0.0)
|
275
|
+
outdoor_vrf_unit.setInitialHeatRecoveryHeatingCapacityFraction(1.0)
|
276
|
+
outdoor_vrf_unit.setHeatRecoveryHeatingCapacityTimeConstant(0.15)
|
277
|
+
outdoor_vrf_unit.setInitialHeatRecoveryHeatingEnergyFraction(1.0)
|
278
|
+
outdoor_vrf_unit.setHeatRecoveryCoolingEnergyTimeConstant(0.0)
|
279
|
+
outdoor_vrf_unit.setMinimumHeatPumpPartLoadRatio(0.5)
|
280
|
+
outdoor_vrf_unit.setCondenserType(condenser_type)
|
281
|
+
outdoor_vrf_unit.setCrankcaseHeaterPowerperCompressor(0.001)
|
282
|
+
heat_defrost_eir_ft = nil
|
283
|
+
if ecm_name
|
284
|
+
search_criteria = coil_dx_find_search_criteria(outdoor_vrf_unit)
|
285
|
+
props = model_find_object(standards_data['tables']["heat_pumps_heating_ecm_#{ecm_name.downcase}"]['table'], search_criteria, 1.0, Date.today)
|
286
|
+
heat_defrost_eir_ft = model_add_curve(model, props['heat_defrost_eir_ft'])
|
287
|
+
end
|
288
|
+
if heat_defrost_eir_ft
|
289
|
+
outdoor_vrf_unit.setDefrostEnergyInputRatioModifierFunctionofTemperatureCurve(heat_defrost_eir_ft)
|
290
|
+
else
|
291
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{outdoor_vrf_unit.name}, cannot find heat_defrost_eir_ft curve, will not be set.")
|
292
|
+
end
|
293
|
+
|
294
|
+
return outdoor_vrf_unit
|
295
|
+
end
|
296
|
+
|
297
|
+
# =============================================================================================================================
|
298
|
+
# Add indoor VRF units and update horizontal and vertical pipe runs for outdoor VRF unit
|
299
|
+
def add_indoor_vrf_units(model:,system_zones_map:,outdoor_vrf_unit:)
|
300
|
+
always_on = model.alwaysOnDiscreteSchedule
|
301
|
+
always_off = model.alwaysOffDiscreteSchedule
|
302
|
+
system_zones_map.sort.each do |sname,zones|
|
303
|
+
zones.sort.each do |izone|
|
304
|
+
zone_vrf_fan = OpenStudio::Model::FanOnOff.new(model, always_on)
|
305
|
+
zone_vrf_fan.setName("#{izone.name} VRF Fan")
|
306
|
+
zone_vrf_clg_coil = OpenStudio::Model::CoilCoolingDXVariableRefrigerantFlow.new(model)
|
307
|
+
zone_vrf_clg_coil.setName("#{izone.name} VRF Clg Coil")
|
308
|
+
zone_vrf_htg_coil = OpenStudio::Model::CoilHeatingDXVariableRefrigerantFlow.new(model)
|
309
|
+
zone_vrf_htg_coil.setName("#{izone.name} VRF Htg Coil")
|
310
|
+
zone_vrf_unit = OpenStudio::Model::ZoneHVACTerminalUnitVariableRefrigerantFlow.new(model,zone_vrf_clg_coil,zone_vrf_htg_coil,zone_vrf_fan)
|
311
|
+
zone_vrf_unit.setName("#{izone.name} VRF Indoor Unit")
|
312
|
+
zone_vrf_unit.setOutdoorAirFlowRateDuringCoolingOperation(0.000001)
|
313
|
+
zone_vrf_unit.setOutdoorAirFlowRateDuringHeatingOperation(0.000001)
|
314
|
+
zone_vrf_unit.setOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(0.000001)
|
315
|
+
zone_vrf_unit.setZoneTerminalUnitOffParasiticElectricEnergyUse(0.000001)
|
316
|
+
zone_vrf_unit.setZoneTerminalUnitOnParasiticElectricEnergyUse(0.000001)
|
317
|
+
zone_vrf_unit.setSupplyAirFanOperatingModeSchedule(always_off)
|
318
|
+
zone_vrf_unit.setRatedTotalHeatingCapacitySizingRatio(1.3)
|
319
|
+
zone_vrf_unit.addToThermalZone(izone)
|
320
|
+
outdoor_vrf_unit.addTerminal(zone_vrf_unit)
|
321
|
+
# VRF terminal unit does not have a backup coil, use a unit heater as backup coil
|
322
|
+
zone_unitheater_fan = OpenStudio::Model::FanConstantVolume.new(model, always_on) # OS does not support an OnOff fan for unit heaters
|
323
|
+
zone_unitheater_fan.setName("#{izone.name} Unit Heater Fan")
|
324
|
+
zone_unitheater_htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model, always_on)
|
325
|
+
zone_unitheater_htg_coil.setName("#{izone.name} Unit Heater Htg Coil")
|
326
|
+
zone_unit_heater = OpenStudio::Model::ZoneHVACUnitHeater.new(model,always_on,zone_unitheater_fan,zone_unitheater_htg_coil)
|
327
|
+
zone_unit_heater.setName("#{izone.name} Unit Heater")
|
328
|
+
zone_unit_heater.setFanControlType("OnOff")
|
329
|
+
zone_unit_heater.addToThermalZone(izone)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
# Now we can find and apply maximum horizontal and vertical distances between outdoor vrf unit and zones with vrf terminal units
|
333
|
+
max_hor_pipe_length,max_vert_pipe_length = get_max_vrf_pipe_lengths(model)
|
334
|
+
#raise("test1:#{max_hor_pipe_length},#{max_vert_pipe_length}")
|
335
|
+
outdoor_vrf_unit.setEquivalentPipingLengthusedforPipingCorrectionFactorinCoolingMode(max_hor_pipe_length)
|
336
|
+
outdoor_vrf_unit.setEquivalentPipingLengthusedforPipingCorrectionFactorinHeatingMode(max_hor_pipe_length)
|
337
|
+
outdoor_vrf_unit.setVerticalHeightusedforPipingCorrectionFactor(max_vert_pipe_length)
|
338
|
+
end
|
339
|
+
|
340
|
+
# =============================================================================================================================
|
341
|
+
# Add a dedicated outside air loop with cold-climate heat pump with electric backup
|
342
|
+
# Add cold-climate zonal terminal VRF units
|
343
|
+
def add_ecm_hs08_vrfzonal(model:,system_zones_map:,system_doas_flags:,zone_clg_eqpt_type:, standard:)
|
344
|
+
# Update system doas flags
|
345
|
+
system_doas_flags.keys.each {|sname| system_doas_flags[sname] = true}
|
346
|
+
# Add doas with cold-climate air-source heat pump and electric backup
|
347
|
+
add_ecm_hs09_ccashpsys(model: model,system_zones_map: system_zones_map,system_doas_flags: system_doas_flags,standard: standard,baseboard_flag: false)
|
348
|
+
# Add outdoor VRF unit
|
349
|
+
outdoor_vrf_unit = add_outdoor_vrf_unit(model: model,ecm_name: "hs08_vrfzonal")
|
350
|
+
# Add indoor VRF terminal units
|
351
|
+
add_indoor_vrf_units(model: model,system_zones_map: system_zones_map,outdoor_vrf_unit: outdoor_vrf_unit)
|
352
|
+
end
|
353
|
+
|
354
|
+
# =============================================================================================================================
|
355
|
+
# Apply efficiencies and performance curves for ECM 'hs08_vrfzonal'
|
356
|
+
def apply_efficiency_ecm_hs08_vrfzonal(model:,ecm_name:)
|
357
|
+
# Use same performance data as ECM "hs09_ccashpsys" for air system
|
358
|
+
apply_efficiency_ecm_hs09_ccashpsys(model: model,ecm_name: "hs09_ccashpsys")
|
359
|
+
# Apply efficiency and curves for VRF units
|
360
|
+
model.getAirConditionerVariableRefrigerantFlows.sort.each do |vrf_unit|
|
361
|
+
airconditioner_variablerefrigerantflow_cooling_apply_efficiency_and_curves(vrf_unit,ecm_name)
|
362
|
+
airconditioner_variablerefrigerantflow_heating_apply_efficiency_and_curves(vrf_unit,ecm_name)
|
363
|
+
end
|
364
|
+
# Set fan size of VRF terminal units
|
365
|
+
fan_power_per_flow_rate = 150.0 # based on Mitsubishi data: 100 low and 200 high (W-s/m3)
|
366
|
+
model.getZoneHVACTerminalUnitVariableRefrigerantFlows.each do |iunit|
|
367
|
+
fan = iunit.supplyAirFan.to_FanOnOff.get
|
368
|
+
fan_pr_rise = fan_power_per_flow_rate*(fan.fanEfficiency*fan.motorEfficiency)
|
369
|
+
fan.setPressureRise(fan_pr_rise)
|
370
|
+
end
|
371
|
+
# Set fan size of unit heaters
|
372
|
+
model.getZoneHVACUnitHeaters.each do |iunit|
|
373
|
+
fan = iunit.supplyAirFan.to_FanConstantVolume.get
|
374
|
+
fan_pr_rise = fan_power_per_flow_rate*(fan.fanEfficiency*fan.motorEfficiency)
|
375
|
+
fan.setPressureRise(fan_pr_rise)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
# =============================================================================================================================
|
380
|
+
# Add air loops with cold-climate heat pump with electric backup coil.
|
381
|
+
# Add zone electric baseboards
|
382
|
+
def add_ecm_hs09_ccashpsys(model:,system_zones_map:,system_doas_flags:,zone_clg_eqpt_type: nil,standard:,baseboard_flag: true)
|
383
|
+
always_on = model.alwaysOnDiscreteSchedule
|
384
|
+
always_off = model.alwaysOffDiscreteSchedule
|
385
|
+
systems = []
|
386
|
+
system_zones_map.sort.each do |sys_name,zones|
|
387
|
+
system_data = {}
|
388
|
+
system_data[:PreheatDesignTemperature] = 7.0
|
389
|
+
system_data[:PreheatDesignHumidityRatio] = 0.008
|
390
|
+
system_data[:PrecoolDesignTemperature] = 13.0
|
391
|
+
system_data[:PrecoolDesignHumidityRatio] = 0.008
|
392
|
+
system_data[:SizingOption] = 'NonCoincident'
|
393
|
+
system_data[:CoolingDesignAirFlowMethod] = 'DesignDay'
|
394
|
+
system_data[:CoolingDesignAirFlowRate] = 0.0
|
395
|
+
system_data[:HeatingDesignAirFlowMethod] = 'DesignDay'
|
396
|
+
system_data[:HeatingDesignAirFlowRate] = 0.0
|
397
|
+
system_data[:SystemOutdoorAirMethod] = 'ZoneSum'
|
398
|
+
system_data[:CentralCoolingDesignSupplyAirHumidityRatio] = 0.0085
|
399
|
+
system_data[:CentralHeatingDesignSupplyAirHumidityRatio] = 0.0080
|
400
|
+
system_data[:MinimumSystemAirFlowRatio] = 1.0
|
401
|
+
system_data[:system_supply_air_temperature] = 20.0
|
402
|
+
system_data[:ZoneCoolingDesignSupplyAirTemperature] = 13.0
|
403
|
+
system_data[:ZoneHeatingDesignSupplyAirTemperature] = 43.0
|
404
|
+
system_data[:ZoneCoolingSizingFactor] = 1.1
|
405
|
+
system_data[:ZoneHeatingSizingFactor] = 1.3
|
406
|
+
if system_doas_flags[sys_name.to_s]
|
407
|
+
system_data[:name] = "CCASHP Makeup Air Unit"
|
408
|
+
system_data[:AllOutdoorAirinCooling] = true
|
409
|
+
system_data[:AllOutdoorAirinHeating] = true
|
410
|
+
system_data[:TypeofLoadtoSizeOn] = 'VentilationRequirement'
|
411
|
+
system_data[:CentralCoolingDesignSupplyAirTemperature] = 19.9
|
412
|
+
system_data[:CentralHeatingDesignSupplyAirTemperature] = 20.0
|
413
|
+
sat_sch = OpenStudio::Model::ScheduleRuleset.new(model)
|
414
|
+
sat_sch.setName('Makeup-Air Unit Supply Air Temp')
|
415
|
+
sat_sch.defaultDaySchedule.setName('Makeup Air Unit Supply Air Temp Default')
|
416
|
+
sat_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), system_data[:system_supply_air_temperature])
|
417
|
+
setpoint_mgr = OpenStudio::Model::SetpointManagerScheduled.new(model, sat_sch)
|
418
|
+
else
|
419
|
+
system_data[:name] = "CCASHP System"
|
420
|
+
system_data[:AllOutdoorAirinCooling] = false
|
421
|
+
system_data[:AllOutdoorAirinHeating] = false
|
422
|
+
system_data[:TypeofLoadtoSizeOn] = 'Sensible'
|
423
|
+
system_data[:CentralCoolingDesignSupplyAirTemperature] = 13.0
|
424
|
+
system_data[:CentralHeatingDesignSupplyAirTemperature] = 43.0
|
425
|
+
if zones.size == 1
|
426
|
+
setpoint_mgr = OpenStudio::Model::SetpointManagerSingleZoneReheat.new(model)
|
427
|
+
setpoint_mgr.setControlZone(zones[0])
|
428
|
+
setpoint_mgr.setMinimumSupplyAirTemperature(13.0)
|
429
|
+
setpoint_mgr.setMaximumSupplyAirTemperature(43.0)
|
430
|
+
else
|
431
|
+
setpoint_mgr = OpenStudio::Model::SetpointManagerWarmest.new(model)
|
432
|
+
setpoint_mgr.setMinimumSetpointTemperature(13.0)
|
433
|
+
setpoint_mgr.setMaximumSetpointTemperature(43.0)
|
434
|
+
end
|
435
|
+
end
|
436
|
+
airloop = standard.common_air_loop(model: model, system_data: system_data)
|
437
|
+
# Fan
|
438
|
+
if system_doas_flags[sys_name.to_s] || zones.size == 1
|
439
|
+
sys_supply_fan = OpenStudio::Model::FanConstantVolume.new(model)
|
440
|
+
else
|
441
|
+
sys_supply_fan = OpenStudio::Model::FanVariableVolume.new(model)
|
442
|
+
sys_return_fan = OpenStudio::Model::FanVariableVolume.new(model)
|
443
|
+
sys_return_fan.setName("System Return Fan")
|
444
|
+
end
|
445
|
+
sys_supply_fan.setName("System Supply Fan")
|
446
|
+
# Cooling coil
|
447
|
+
sys_clg_coil = OpenStudio::Model::CoilCoolingDXVariableSpeed.new(model)
|
448
|
+
sys_clg_coil.setName("CCASHP DX Clg Coil")
|
449
|
+
sys_clg_coil_speeddata1 = OpenStudio::Model::CoilCoolingDXVariableSpeedSpeedData.new(model)
|
450
|
+
sys_clg_coil.addSpeed(sys_clg_coil_speeddata1)
|
451
|
+
sys_clg_coil.setNominalSpeedLevel(1)
|
452
|
+
# Electric supplemental heating coil
|
453
|
+
sys_elec_htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model, always_on)
|
454
|
+
sys_elec_htg_coil.setName("CCASHP Elec Htg Coil")
|
455
|
+
# DX heating coil
|
456
|
+
sys_dx_htg_coil = OpenStudio::Model::CoilHeatingDXVariableSpeed.new(model)
|
457
|
+
sys_dx_htg_coil.setName("CCASHP DX Htg Coil")
|
458
|
+
sys_dx_htg_coil_speed1 = OpenStudio::Model::CoilHeatingDXVariableSpeedSpeedData.new(model)
|
459
|
+
sys_dx_htg_coil.addSpeed(sys_dx_htg_coil_speed1)
|
460
|
+
sys_dx_htg_coil.setNominalSpeedLevel(1)
|
461
|
+
sys_dx_htg_coil.setMinimumOutdoorDryBulbTemperatureforCompressorOperation(-25.0)
|
462
|
+
sys_dx_htg_coil.setDefrostStrategy("ReverseCycle")
|
463
|
+
#sys_dx_htg_coil.setDefrostStrategy("Resistive")
|
464
|
+
#sys_dx_htg_coil.setResistiveDefrostHeaterCapacity(0.001)
|
465
|
+
sys_dx_htg_coil.setDefrostControl("OnDemand")
|
466
|
+
sys_dx_htg_coil.setCrankcaseHeaterCapacity(0.001)
|
467
|
+
search_criteria = coil_dx_find_search_criteria(sys_dx_htg_coil)
|
468
|
+
props = model_find_object(standards_data['tables']["heat_pumps_heating_ecm_hs09_ccashpsys"]['table'], search_criteria, 1.0, Date.today)
|
469
|
+
heat_defrost_eir_ft = model_add_curve(model, props['heat_defrost_eir_ft'])
|
470
|
+
# This defrost curve has to be assigned here before sizing
|
471
|
+
if heat_defrost_eir_ft
|
472
|
+
sys_dx_htg_coil.setDefrostEnergyInputRatioFunctionofTemperatureCurve(heat_defrost_eir_ft)
|
473
|
+
else
|
474
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingDXVariableSpeed', "For #{sys_dx_htg_coil.name}, cannot find heat_defrost_eir_ft curve, will not be set.")
|
475
|
+
end
|
476
|
+
sys_clg_coil.addToNode(airloop.supplyOutletNode)
|
477
|
+
sys_dx_htg_coil.addToNode(airloop.supplyOutletNode)
|
478
|
+
sys_elec_htg_coil.addToNode(airloop.supplyOutletNode)
|
479
|
+
sys_supply_fan.addToNode(airloop.supplyOutletNode)
|
480
|
+
setpoint_mgr.addToNode(airloop.supplyOutletNode)
|
481
|
+
# OA controller
|
482
|
+
oa_controller = OpenStudio::Model::ControllerOutdoorAir.new(model)
|
483
|
+
oa_controller.autosizeMinimumOutdoorAirFlowRate
|
484
|
+
oa_system = OpenStudio::Model::AirLoopHVACOutdoorAirSystem.new(model, oa_controller)
|
485
|
+
oa_system.addToNode(airloop.supplyInletNode)
|
486
|
+
zones.each do |zone|
|
487
|
+
zone.sizingZone.setZoneCoolingDesignSupplyAirTemperature(13.0)
|
488
|
+
zone.sizingZone.setZoneHeatingDesignSupplyAirTemperature(43.0)
|
489
|
+
zone.sizingZone.setZoneCoolingSizingFactor(1.1)
|
490
|
+
zone.sizingZone.setZoneHeatingSizingFactor(1.3)
|
491
|
+
if zone_clg_eqpt_type
|
492
|
+
case zone_clg_eqpt_type[zone.name.to_s]
|
493
|
+
when "ZoneHVACPackagedTerminalAirConditioner"
|
494
|
+
standard.add_ptac_dx_cooling(model,zone,true)
|
495
|
+
end
|
496
|
+
end
|
497
|
+
if system_doas_flags[sys_name.to_s] || zones.size == 1
|
498
|
+
diffuser = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, always_on)
|
499
|
+
else
|
500
|
+
reheat_coil = OpenStudio::Model::CoilHeatingElectric.new(model, always_on)
|
501
|
+
diffuser = OpenStudio::Model::AirTerminalSingleDuctVAVReheat.new(model, always_on, reheat_coil)
|
502
|
+
sys_return_fan.addToNode(airloop.returnAirNode.get)
|
503
|
+
diffuser.setFixedMinimumAirFlowRate(0.002 * zone.floorArea )
|
504
|
+
diffuser.setMaximumReheatAirTemperature(43.0)
|
505
|
+
diffuser.setDamperHeatingAction('Normal')
|
506
|
+
end
|
507
|
+
airloop.removeBranchForZone(zone)
|
508
|
+
airloop.addBranchForZone(zone, diffuser.to_StraightComponent)
|
509
|
+
if baseboard_flag then standard.add_zone_baseboards(baseboard_type: 'Electric', hw_loop: nil, model: model, zone: zone) end
|
510
|
+
end
|
511
|
+
systems << airloop
|
512
|
+
end
|
513
|
+
|
514
|
+
return systems
|
515
|
+
end
|
516
|
+
|
517
|
+
# =============================================================================================================================
|
518
|
+
# Apply efficiencies and performance curves for ECM 'hs09_ccashpsys'
|
519
|
+
def apply_efficiency_ecm_hs09_ccashpsys(model:,ecm_name:)
|
520
|
+
# fraction of electric backup heating coil capacity assigned to dx heating coil
|
521
|
+
fr_backup_coil_cap_as_dx_coil_cap = 0.5
|
522
|
+
model.getAirLoopHVACs.each do |isys|
|
523
|
+
clg_dx_coil = nil
|
524
|
+
htg_dx_coil = nil
|
525
|
+
backup_coil = nil
|
526
|
+
fans = []
|
527
|
+
# Find the components on the air loop
|
528
|
+
isys.supplyComponents.each do |icomp|
|
529
|
+
if icomp.to_CoilCoolingDXVariableSpeed.is_initialized
|
530
|
+
clg_dx_coil = icomp.to_CoilCoolingDXVariableSpeed.get
|
531
|
+
elsif icomp.to_CoilHeatingDXVariableSpeed.is_initialized
|
532
|
+
htg_dx_coil = icomp.to_CoilHeatingDXVariableSpeed.get
|
533
|
+
elsif icomp.to_CoilHeatingElectric.is_initialized
|
534
|
+
backup_coil = icomp.to_CoilHeatingElectric.get
|
535
|
+
elsif icomp.to_FanConstantVolume.is_initialized
|
536
|
+
fans << icomp.to_FanConstantVolume.get
|
537
|
+
elsif icomp.to_FanVariableVolume.is_initialized
|
538
|
+
fans << icomp.to_FanVariableVolume.get
|
539
|
+
end
|
540
|
+
end
|
541
|
+
if clg_dx_coil && htg_dx_coil && backup_coil
|
542
|
+
clg_dx_coil_cap = clg_dx_coil.autosizedGrossRatedTotalCoolingCapacityAtSelectedNominalSpeedLevel.to_f
|
543
|
+
htg_dx_coil_cap = htg_dx_coil.autosizedRatedHeatingCapacityAtSelectedNominalSpeedLevel.to_f
|
544
|
+
backup_coil_cap = backup_coil.autosizedNominalCapacity.to_f
|
545
|
+
fan_power = 0.0
|
546
|
+
fans.each do |ifan|
|
547
|
+
fan_power += ifan.pressureRise.to_f*ifan.autosizedMaximumFlowRate.to_f/ifan.fanEfficiency.to_f
|
548
|
+
end
|
549
|
+
# Set the DX capacities to the maximum of the fraction of the backup coil capacity or the cooling capacity needed
|
550
|
+
dx_cap = fr_backup_coil_cap_as_dx_coil_cap*backup_coil_cap
|
551
|
+
if dx_cap < (clg_dx_coil_cap+fan_power) then dx_cap = clg_dx_coil_cap+fan_power end
|
552
|
+
clg_dx_coil.setGrossRatedTotalCoolingCapacityAtSelectedNominalSpeedLevel(dx_cap)
|
553
|
+
htg_dx_coil.setRatedHeatingCapacityAtSelectedNominalSpeedLevel(dx_cap)
|
554
|
+
end
|
555
|
+
end
|
556
|
+
# Assign performance curves and COPs
|
557
|
+
model.getCoilCoolingDXVariableSpeeds.sort.each {|coil| coil_cooling_dx_variable_speed_apply_efficiency_and_curves(coil,ecm_name)}
|
558
|
+
model.getCoilHeatingDXVariableSpeeds.sort.each {|coil| coil_heating_dx_variable_speed_apply_efficiency_and_curves(coil,ecm_name)}
|
559
|
+
end
|
560
|
+
|
561
|
+
# =============================================================================================================================
|
562
|
+
# Applies the standard efficiency ratings and typical performance curves "CoilCoolingDXVariableSpeed" object.
|
563
|
+
def coil_cooling_dx_variable_speed_apply_efficiency_and_curves(coil_cooling_dx_variable_speed,ecm_name)
|
564
|
+
successfully_set_all_properties = true
|
565
|
+
|
566
|
+
# Get the search criteria
|
567
|
+
search_criteria = coil_dx_find_search_criteria(coil_cooling_dx_variable_speed)
|
568
|
+
|
569
|
+
# Get the capacity
|
570
|
+
capacity_w = coil_cooling_dx_variable_speed_find_capacity(coil_cooling_dx_variable_speed)
|
571
|
+
capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get
|
572
|
+
capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get
|
573
|
+
|
574
|
+
# Lookup efficiencies depending on whether it is a unitary AC or a heat pump
|
575
|
+
ac_props = if coil_dx_heat_pump?(coil_cooling_dx_variable_speed)
|
576
|
+
model_find_object(standards_data['tables']["heat_pumps_ecm_#{ecm_name.downcase}"]['table'], search_criteria, capacity_btu_per_hr, Date.today)
|
577
|
+
else
|
578
|
+
model_find_object(standards_data['tables']["unitary_acs_ecm_#{ecm_name.downcase}"]['table'], search_criteria, capacity_btu_per_hr, Date.today)
|
579
|
+
end
|
580
|
+
|
581
|
+
# Check to make sure properties were found
|
582
|
+
if ac_props.nil?
|
583
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standard.CoilCoolingDXVariableSpeed', "For #{coil_cooling_dx_single_speed.name}, cannot find efficiency info using #{search_criteria}, cannot apply efficiency.")
|
584
|
+
successfully_set_all_properties = false
|
585
|
+
end
|
586
|
+
|
587
|
+
# Make the COOL-CAP-FT curve
|
588
|
+
cool_cap_ft = model_add_curve(coil_cooling_dx_variable_speed.model, ac_props['cool_cap_ft'])
|
589
|
+
if cool_cap_ft
|
590
|
+
coil_cooling_dx_variable_speed.speeds.each {|speed| speed.setTotalCoolingCapacityFunctionofTemperatureCurve(cool_cap_ft)}
|
591
|
+
else
|
592
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standard.CoilCoolingDXVariableSpeed', "For #{coil_cooling_dx_variable_speed.name}, cannot find cool_cap_ft curve, will not be set.")
|
593
|
+
successfully_set_all_properties = false
|
594
|
+
end
|
595
|
+
|
596
|
+
# Make the COOL-CAP-FFLOW curve
|
597
|
+
cool_cap_fflow = model_add_curve(coil_cooling_dx_variable_speed.model, ac_props['cool_cap_fflow'])
|
598
|
+
if cool_cap_fflow
|
599
|
+
coil_cooling_dx_variable_speed.speeds.each {|speed| speed.setTotalCoolingCapacityFunctionofAirFlowFractionCurve(cool_cap_fflow)}
|
600
|
+
else
|
601
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standard.CoilCoolingDXVariableSpeed', "For #{coil_cooling_dx_variable_speed.name}, cannot find cool_cap_fflow curve, will not be set.")
|
602
|
+
successfully_set_all_properties = false
|
603
|
+
end
|
604
|
+
|
605
|
+
# Make the COOL-EIR-FT curve
|
606
|
+
cool_eir_ft = model_add_curve(coil_cooling_dx_variable_speed.model, ac_props['cool_eir_ft'])
|
607
|
+
if cool_eir_ft
|
608
|
+
coil_cooling_dx_variable_speed.speeds.each {|speed| speed.setEnergyInputRatioFunctionofTemperatureCurve(cool_eir_ft)}
|
609
|
+
else
|
610
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXVariableSpeed', "For #{coil_cooling_dx_variable_speed.name}, cannot find cool_eir_ft curve, will not be set.")
|
611
|
+
successfully_set_all_properties = false
|
612
|
+
end
|
613
|
+
|
614
|
+
# Make the COOL-EIR-FFLOW curve
|
615
|
+
cool_eir_fflow = model_add_curve(coil_cooling_dx_variable_speed.model, ac_props['cool_eir_fflow'])
|
616
|
+
if cool_eir_fflow
|
617
|
+
coil_cooling_dx_variable_speed.speeds.each {|speed| speed.setEnergyInputRatioFunctionofAirFlowFractionCurve(cool_eir_fflow)}
|
618
|
+
else
|
619
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXVariableSpeed', "For #{coil_cooling_dx_variable_speed.name}, cannot find cool_eir_fflow curve, will not be set.")
|
620
|
+
successfully_set_all_properties = false
|
621
|
+
end
|
622
|
+
|
623
|
+
# Make the COOL-PLF-FPLR curve
|
624
|
+
cool_plf_fplr = model_add_curve(coil_cooling_dx_variable_speed.model, ac_props['cool_plf_fplr'])
|
625
|
+
if cool_plf_fplr
|
626
|
+
coil_cooling_dx_variable_speed.setEnergyPartLoadFractionCurve(cool_plf_fplr)
|
627
|
+
else
|
628
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXVariableSpeed', "For #{coil_cooling_dx_variable_speed.name}, cannot find cool_plf_fplr curve, will not be set.")
|
629
|
+
successfully_set_all_properties = false
|
630
|
+
end
|
631
|
+
|
632
|
+
# Find the minimum COP and rename with efficiency rating
|
633
|
+
cop = coil_cooling_dx_variable_speed_standard_minimum_cop(coil_cooling_dx_variable_speed, true,ecm_name)
|
634
|
+
|
635
|
+
# Set the efficiency values
|
636
|
+
unless cop.nil?
|
637
|
+
coil_cooling_dx_variable_speed.speeds.each {|speed| speed.setReferenceUnitGrossRatedCoolingCOP(cop.to_f)}
|
638
|
+
end
|
639
|
+
|
640
|
+
end
|
641
|
+
|
642
|
+
# =============================================================================================================================
|
643
|
+
# Applies the standard efficiency ratings and typical performance curves to "CoilHeatingVariableSpeed" object.
|
644
|
+
def coil_heating_dx_variable_speed_apply_efficiency_and_curves(coil_heating_dx_variable_speed,ecm_name)
|
645
|
+
successfully_set_all_properties = true
|
646
|
+
|
647
|
+
# Get the search criteria
|
648
|
+
search_criteria = coil_dx_find_search_criteria(coil_heating_dx_variable_speed)
|
649
|
+
|
650
|
+
# Get the capacity
|
651
|
+
capacity_w = coil_heating_dx_variable_speed_find_capacity(coil_heating_dx_variable_speed)
|
652
|
+
capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get
|
653
|
+
capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get
|
654
|
+
|
655
|
+
# Lookup efficiencies
|
656
|
+
props = model_find_object(standards_data['tables']["heat_pumps_heating_ecm_#{ecm_name.downcase}"]['table'], search_criteria, capacity_btu_per_hr, Date.today)
|
657
|
+
|
658
|
+
# Check to make sure properties were found
|
659
|
+
if props.nil?
|
660
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingDXVariableSpeed', "For #{coil_heating_dx_single_speed.name}, cannot find efficiency info using #{search_criteria}, cannot apply efficiency standard.")
|
661
|
+
successfully_set_all_properties = false
|
662
|
+
end
|
663
|
+
|
664
|
+
# Make the HEAT-CAP-FT curve
|
665
|
+
heat_cap_ft = model_add_curve(coil_heating_dx_variable_speed.model, props['heat_cap_ft'])
|
666
|
+
if heat_cap_ft
|
667
|
+
coil_heating_dx_variable_speed.speeds.each {|speed| speed.setHeatingCapacityFunctionofTemperatureCurve(heat_cap_ft)}
|
668
|
+
else
|
669
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingDXVariableSpeed', "For #{coil_heating_dx_variable_speed.name}, cannot find heat_cap_ft curve, will not be set.")
|
670
|
+
successfully_set_all_properties = false
|
671
|
+
end
|
672
|
+
|
673
|
+
# Make the HEAT-CAP-FFLOW curve
|
674
|
+
heat_cap_fflow = model_add_curve(coil_heating_dx_variable_speed.model, props['heat_cap_fflow'])
|
675
|
+
if heat_cap_fflow
|
676
|
+
coil_heating_dx_variable_speed.speeds.each {|speed| speed.setTotalHeatingCapacityFunctionofAirFlowFractionCurve(heat_cap_fflow)}
|
677
|
+
else
|
678
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingDXVariableSpeed', "For #{coil_heating_dx_variable_speed.name}, cannot find heat_cap_fflow curve, will not be set.")
|
679
|
+
successfully_set_all_properties = false
|
680
|
+
end
|
681
|
+
|
682
|
+
# Make the HEAT-EIR-FT curve
|
683
|
+
heat_eir_ft = model_add_curve(coil_heating_dx_variable_speed.model, props['heat_eir_ft'])
|
684
|
+
if heat_eir_ft
|
685
|
+
coil_heating_dx_variable_speed.speeds.each {|speed| speed.setEnergyInputRatioFunctionofTemperatureCurve(heat_eir_ft)}
|
686
|
+
else
|
687
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingDXVariableSingleSpeed', "For #{coil_heating_dx_variable_speed.name}, cannot find heat_eir_ft curve, will not be set.")
|
688
|
+
successfully_set_all_properties = false
|
689
|
+
end
|
690
|
+
|
691
|
+
# Make the HEAT-EIR-FFLOW curve
|
692
|
+
heat_eir_fflow = model_add_curve(coil_heating_dx_variable_speed.model, props['heat_eir_fflow'])
|
693
|
+
if heat_eir_fflow
|
694
|
+
coil_heating_dx_variable_speed.speeds.each {|speed| speed.setEnergyInputRatioFunctionofAirFlowFractionCurve(heat_eir_fflow)}
|
695
|
+
else
|
696
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingDXVariableSpeed', "For #{coil_heating_dx_variable_speed.name}, cannot find heat_eir_fflow curve, will not be set.")
|
697
|
+
successfully_set_all_properties = false
|
698
|
+
end
|
699
|
+
|
700
|
+
# Make the HEAT-PLF-FPLR curve
|
701
|
+
heat_plf_fplr = model_add_curve(coil_heating_dx_variable_speed.model, props['heat_plf_fplr'])
|
702
|
+
if heat_plf_fplr
|
703
|
+
coil_heating_dx_variable_speed.setEnergyPartLoadFractionCurve(heat_plf_fplr)
|
704
|
+
else
|
705
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingDXVariableSpeed', "For #{coil_heating_dx_variable_speed.name}, cannot find heat_plf_fplr curve, will not be set.")
|
706
|
+
successfully_set_all_properties = false
|
707
|
+
end
|
708
|
+
|
709
|
+
# Find the minimum COP and rename with efficiency rating
|
710
|
+
cop = coil_heating_dx_variable_speed_standard_minimum_cop(coil_heating_dx_variable_speed, true,ecm_name)
|
711
|
+
|
712
|
+
# Set the efficiency values
|
713
|
+
unless cop.nil?
|
714
|
+
coil_heating_dx_variable_speed.speeds.each {|speed| speed.setReferenceUnitGrossRatedHeatingCOP(cop.to_f)}
|
715
|
+
end
|
716
|
+
|
717
|
+
end
|
718
|
+
|
719
|
+
# =============================================================================================================================
|
720
|
+
# Applies the standard cooling efficiency ratings and typical performance curves to "AirConditionerVariableRefrigerantFlow" object.
|
721
|
+
def airconditioner_variablerefrigerantflow_cooling_apply_efficiency_and_curves(airconditioner_variablerefrigerantflow,ecm_name)
|
722
|
+
successfully_set_all_properties = true
|
723
|
+
|
724
|
+
# Get the search criteria
|
725
|
+
search_criteria = coil_dx_find_search_criteria(airconditioner_variablerefrigerantflow)
|
726
|
+
|
727
|
+
# Get the capacity
|
728
|
+
capacity_w = airconditioner_variablerefrigerantflow_cooling_find_capacity(airconditioner_variablerefrigerantflow)
|
729
|
+
capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get
|
730
|
+
capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get
|
731
|
+
|
732
|
+
# Lookup efficiencies
|
733
|
+
props = model_find_object(standards_data['tables']["heat_pumps_ecm_#{ecm_name.downcase}"]['table'], search_criteria, capacity_btu_per_hr, Date.today)
|
734
|
+
|
735
|
+
# Check to make sure properties were found
|
736
|
+
if props.nil?
|
737
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standard.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find efficiency info using #{search_criteria}, cannot apply efficiency.")
|
738
|
+
successfully_set_all_properties = false
|
739
|
+
end
|
740
|
+
|
741
|
+
# Make the COOL-CAP-FT Low curve
|
742
|
+
cool_cap_ft_low = model_add_curve(airconditioner_variablerefrigerantflow.model, props['cool_cap_ft_low'])
|
743
|
+
if cool_cap_ft_low
|
744
|
+
airconditioner_variablerefrigerantflow.setCoolingCapacityRatioModifierFunctionofLowTemperatureCurve(cool_cap_ft_low)
|
745
|
+
else
|
746
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standard.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_cap_ft_low curve, will not be set.")
|
747
|
+
successfully_set_all_properties = false
|
748
|
+
end
|
749
|
+
|
750
|
+
# Make the COOL-CAP-FT boundary curve
|
751
|
+
cool_cap_ft_boundary = model_add_curve(airconditioner_variablerefrigerantflow.model, props['cool_cap_ft_boundary'])
|
752
|
+
if cool_cap_ft_boundary
|
753
|
+
airconditioner_variablerefrigerantflow.setCoolingCapacityRatioBoundaryCurve(cool_cap_ft_boundary)
|
754
|
+
else
|
755
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standard.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_cap_ft_boundary curve, will not be set.")
|
756
|
+
successfully_set_all_properties = false
|
757
|
+
end
|
758
|
+
|
759
|
+
# Make the COOL-CAP-FT high curve
|
760
|
+
cool_cap_ft_high = model_add_curve(airconditioner_variablerefrigerantflow.model, props['cool_cap_ft_high'])
|
761
|
+
if cool_cap_ft_high
|
762
|
+
airconditioner_variablerefrigerantflow.setCoolingCapacityRatioModifierFunctionofHighTemperatureCurve(cool_cap_ft_high)
|
763
|
+
else
|
764
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_cap_ft_high curve, will not be set.")
|
765
|
+
successfully_set_all_properties = false
|
766
|
+
end
|
767
|
+
|
768
|
+
# Make the COOL-EIR-FT low curve
|
769
|
+
cool_eir_ft_low = model_add_curve(airconditioner_variablerefrigerantflow.model, props['cool_eir_ft_low'])
|
770
|
+
if cool_eir_ft_low
|
771
|
+
airconditioner_variablerefrigerantflow.setCoolingEnergyInputRatioModifierFunctionofLowTemperatureCurve(cool_eir_ft_low)
|
772
|
+
else
|
773
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_eir_ft_low curve, will not be set.")
|
774
|
+
successfully_set_all_properties = false
|
775
|
+
end
|
776
|
+
|
777
|
+
# Make the COOL-EIR-FT boundary curve
|
778
|
+
cool_eir_ft_boundary = model_add_curve(airconditioner_variablerefrigerantflow.model, props['cool_eir_ft_boundary'])
|
779
|
+
if cool_eir_ft_boundary
|
780
|
+
airconditioner_variablerefrigerantflow.setCoolingEnergyInputRatioBoundaryCurve(cool_eir_ft_boundary)
|
781
|
+
else
|
782
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_eir_ft_boundary curve, will not be set.")
|
783
|
+
successfully_set_all_properties = false
|
784
|
+
end
|
785
|
+
|
786
|
+
# Make the COOL-EIR-FT high curve
|
787
|
+
cool_eir_ft_high = model_add_curve(airconditioner_variablerefrigerantflow.model, props['cool_eir_ft_high'])
|
788
|
+
if cool_eir_ft_high
|
789
|
+
airconditioner_variablerefrigerantflow.setCoolingEnergyInputRatioModifierFunctionofHighTemperatureCurve(cool_eir_ft_high)
|
790
|
+
else
|
791
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_eir_ft_high curve, will not be set.")
|
792
|
+
successfully_set_all_properties = false
|
793
|
+
end
|
794
|
+
|
795
|
+
# Make the COOL-EIR-FPLR low curve
|
796
|
+
cool_eir_fplr_low = model_add_curve(airconditioner_variablerefrigerantflow.model, props['cool_eir_fplr_low'])
|
797
|
+
if cool_eir_fplr_low
|
798
|
+
airconditioner_variablerefrigerantflow.setCoolingEnergyInputRatioModifierFunctionofLowPartLoadRatioCurve(cool_eir_fplr_low)
|
799
|
+
else
|
800
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_eir_fplr_low curve, will not be set.")
|
801
|
+
successfully_set_all_properties = false
|
802
|
+
end
|
803
|
+
|
804
|
+
# Make the COOL-EIR-FPLR high curve
|
805
|
+
cool_eir_fplr_high = model_add_curve(airconditioner_variablerefrigerantflow.model, props['cool_eir_fplr_high'])
|
806
|
+
if cool_eir_fplr_high
|
807
|
+
airconditioner_variablerefrigerantflow.setCoolingEnergyInputRatioModifierFunctionofHighPartLoadRatioCurve(cool_eir_fplr_high)
|
808
|
+
else
|
809
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_eir_fplr_high curve, will not be set.")
|
810
|
+
successfully_set_all_properties = false
|
811
|
+
end
|
812
|
+
|
813
|
+
# Make the COOL-CCR curve
|
814
|
+
cool_ccr = model_add_curve(airconditioner_variablerefrigerantflow.model, props['cool_ccr'])
|
815
|
+
if cool_ccr
|
816
|
+
airconditioner_variablerefrigerantflow.setCoolingCombinationRatioCorrectionFactorCurve(cool_ccr)
|
817
|
+
else
|
818
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_ccr curve, will not be set.")
|
819
|
+
successfully_set_all_properties = false
|
820
|
+
end
|
821
|
+
|
822
|
+
# Make the COOL-PLF-FPLR curve
|
823
|
+
cool_plf_fplr = model_add_curve(airconditioner_variablerefrigerantflow.model, props['cool_plf_fplr'])
|
824
|
+
if cool_plf_fplr
|
825
|
+
airconditioner_variablerefrigerantflow.setCoolingPartLoadFractionCorrelationCurve(cool_plf_fplr)
|
826
|
+
else
|
827
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_plf_fplr curve, will not be set.")
|
828
|
+
successfully_set_all_properties = false
|
829
|
+
end
|
830
|
+
|
831
|
+
# Make the COOL-PLF-FPLR curve
|
832
|
+
cool_plf_fplr = model_add_curve(airconditioner_variablerefrigerantflow.model, props['cool_plf_fplr'])
|
833
|
+
if cool_plf_fplr
|
834
|
+
airconditioner_variablerefrigerantflow.setCoolingPartLoadFractionCorrelationCurve(cool_plf_fplr)
|
835
|
+
else
|
836
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_plf_fplr curve, will not be set.")
|
837
|
+
successfully_set_all_properties = false
|
838
|
+
end
|
839
|
+
|
840
|
+
# Make the COOL-CAP-FPL curve
|
841
|
+
cool_cap_fpl = model_add_curve(airconditioner_variablerefrigerantflow.model, props['cool_cap_fpl'])
|
842
|
+
if cool_cap_fpl
|
843
|
+
airconditioner_variablerefrigerantflow.setPipingCorrectionFactorforLengthinCoolingModeCurve(cool_cap_fpl)
|
844
|
+
else
|
845
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_cap_fpl curve, will not be set.")
|
846
|
+
successfully_set_all_properties = false
|
847
|
+
end
|
848
|
+
|
849
|
+
# Find the minimum COP
|
850
|
+
cop = airconditioner_variablerefrigerantflow_cooling_standard_minimum_cop(airconditioner_variablerefrigerantflow, false, ecm_name)
|
851
|
+
|
852
|
+
# Set the efficiency values
|
853
|
+
unless cop.nil?
|
854
|
+
airconditioner_variablerefrigerantflow.setRatedCoolingCOP(cop.to_f)
|
855
|
+
end
|
856
|
+
|
857
|
+
end
|
858
|
+
|
859
|
+
# =============================================================================================================================
|
860
|
+
# Applies the standard heating efficiency ratings and typical performance curves to "AirConditionerVariableRefrigerantFlow" object.
|
861
|
+
def airconditioner_variablerefrigerantflow_heating_apply_efficiency_and_curves(airconditioner_variablerefrigerantflow,ecm_name)
|
862
|
+
successfully_set_all_properties = true
|
863
|
+
|
864
|
+
# Get the search criteria
|
865
|
+
search_criteria = coil_dx_find_search_criteria(airconditioner_variablerefrigerantflow)
|
866
|
+
|
867
|
+
# Get the capacity
|
868
|
+
capacity_w = airconditioner_variablerefrigerantflow_heating_find_capacity(airconditioner_variablerefrigerantflow)
|
869
|
+
capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get
|
870
|
+
capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get
|
871
|
+
|
872
|
+
# Lookup efficiencies
|
873
|
+
props = model_find_object(standards_data['tables']["heat_pumps_heating_ecm_#{ecm_name.downcase}"]['table'], search_criteria, capacity_btu_per_hr, Date.today)
|
874
|
+
|
875
|
+
# Check to make sure properties were found
|
876
|
+
if props.nil?
|
877
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standard.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find heating efficiency info using #{search_criteria}, cannot apply efficiency.")
|
878
|
+
successfully_set_all_properties = false
|
879
|
+
end
|
880
|
+
|
881
|
+
# Make the HEAT-CAP-FT Low curve
|
882
|
+
heat_cap_ft_low = model_add_curve(airconditioner_variablerefrigerantflow.model, props['heat_cap_ft_low'])
|
883
|
+
if heat_cap_ft_low
|
884
|
+
airconditioner_variablerefrigerantflow.setHeatingCapacityRatioModifierFunctionofLowTemperatureCurve(heat_cap_ft_low)
|
885
|
+
else
|
886
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standard.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find heat_cap_ft_low curve, will not be set.")
|
887
|
+
successfully_set_all_properties = false
|
888
|
+
end
|
889
|
+
|
890
|
+
# Make the HEAT-CAP-FT boundary curve
|
891
|
+
heat_cap_ft_boundary = model_add_curve(airconditioner_variablerefrigerantflow.model, props['heat_cap_ft_boundary'])
|
892
|
+
if heat_cap_ft_boundary
|
893
|
+
airconditioner_variablerefrigerantflow.setHeatingCapacityRatioBoundaryCurve(heat_cap_ft_boundary)
|
894
|
+
else
|
895
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standard.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find heat_cap_ft_boundary curve, will not be set.")
|
896
|
+
successfully_set_all_properties = false
|
897
|
+
end
|
898
|
+
|
899
|
+
# Make the HEAT-CAP-FT high curve
|
900
|
+
heat_cap_ft_high = model_add_curve(airconditioner_variablerefrigerantflow.model, props['heat_cap_ft_high'])
|
901
|
+
if heat_cap_ft_high
|
902
|
+
airconditioner_variablerefrigerantflow.setHeatingCapacityRatioModifierFunctionofHighTemperatureCurve(heat_cap_ft_high)
|
903
|
+
else
|
904
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find heat_cap_ft_high curve, will not be set.")
|
905
|
+
successfully_set_all_properties = false
|
906
|
+
end
|
907
|
+
|
908
|
+
# Make the HEAT-EIR-FT low curve
|
909
|
+
heat_eir_ft_low = model_add_curve(airconditioner_variablerefrigerantflow.model, props['heat_eir_ft_low'])
|
910
|
+
if heat_eir_ft_low
|
911
|
+
airconditioner_variablerefrigerantflow.setHeatingEnergyInputRatioModifierFunctionofLowTemperatureCurve(heat_eir_ft_low)
|
912
|
+
else
|
913
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find heat_eir_ft_low curve, will not be set.")
|
914
|
+
successfully_set_all_properties = false
|
915
|
+
end
|
916
|
+
|
917
|
+
# Make the HEAT-EIR-FT boundary curve
|
918
|
+
heat_eir_ft_boundary = model_add_curve(airconditioner_variablerefrigerantflow.model, props['heat_eir_ft_boundary'])
|
919
|
+
if heat_eir_ft_boundary
|
920
|
+
airconditioner_variablerefrigerantflow.setHeatingEnergyInputRatioBoundaryCurve(heat_eir_ft_boundary)
|
921
|
+
else
|
922
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find heat_eir_ft_boundary curve, will not be set.")
|
923
|
+
successfully_set_all_properties = false
|
924
|
+
end
|
925
|
+
|
926
|
+
# Make the HEAT-EIR-FT high curve
|
927
|
+
heat_eir_ft_high = model_add_curve(airconditioner_variablerefrigerantflow.model, props['heat_eir_ft_high'])
|
928
|
+
if heat_eir_ft_high
|
929
|
+
airconditioner_variablerefrigerantflow.setHeatingEnergyInputRatioModifierFunctionofHighTemperatureCurve(heat_eir_ft_high)
|
930
|
+
else
|
931
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find heat_eir_ft_high curve, will not be set.")
|
932
|
+
successfully_set_all_properties = false
|
933
|
+
end
|
934
|
+
|
935
|
+
# Make the HEAT-EIR-FPLR low curve
|
936
|
+
heat_eir_fplr_low = model_add_curve(airconditioner_variablerefrigerantflow.model, props['heat_eir_fplr_low'])
|
937
|
+
if heat_eir_fplr_low
|
938
|
+
airconditioner_variablerefrigerantflow.setHeatingEnergyInputRatioModifierFunctionofLowPartLoadRatioCurve(heat_eir_fplr_low)
|
939
|
+
else
|
940
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find heat_eir_fplr_low curve, will not be set.")
|
941
|
+
successfully_set_all_properties = false
|
942
|
+
end
|
943
|
+
|
944
|
+
# Make the HEAT-EIR-FPLR high curve
|
945
|
+
heat_eir_fplr_high = model_add_curve(airconditioner_variablerefrigerantflow.model, props['heat_eir_fplr_high'])
|
946
|
+
if heat_eir_fplr_high
|
947
|
+
airconditioner_variablerefrigerantflow.setHeatingEnergyInputRatioModifierFunctionofHighPartLoadRatioCurve(heat_eir_fplr_high)
|
948
|
+
else
|
949
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find heat_eir_fplr_high curve, will not be set.")
|
950
|
+
successfully_set_all_properties = false
|
951
|
+
end
|
952
|
+
|
953
|
+
# Make the HEAT-HCR curve
|
954
|
+
heat_hcr = model_add_curve(airconditioner_variablerefrigerantflow.model, props['heat_hcr'])
|
955
|
+
if heat_hcr
|
956
|
+
airconditioner_variablerefrigerantflow.setHeatingCombinationRatioCorrectionFactorCurve(heat_hcr)
|
957
|
+
else
|
958
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find heat_hcr curve, will not be set.")
|
959
|
+
successfully_set_all_properties = false
|
960
|
+
end
|
961
|
+
|
962
|
+
# Make the HEAT-PLF-FPLR curve
|
963
|
+
heat_plf_fplr = model_add_curve(airconditioner_variablerefrigerantflow.model, props['heat_plf_fplr'])
|
964
|
+
if heat_plf_fplr
|
965
|
+
airconditioner_variablerefrigerantflow.setHeatingPartLoadFractionCorrelationCurve(heat_plf_fplr)
|
966
|
+
else
|
967
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find cool_plf_fplr curve, will not be set.")
|
968
|
+
successfully_set_all_properties = false
|
969
|
+
end
|
970
|
+
|
971
|
+
# Make the HEAT-CAP-FPL curve
|
972
|
+
heat_cap_fpl = model_add_curve(airconditioner_variablerefrigerantflow.model, props['heat_cap_fpl'])
|
973
|
+
if heat_cap_fpl
|
974
|
+
airconditioner_variablerefrigerantflow.setPipingCorrectionFactorforLengthinHeatingModeCurve(heat_cap_fpl)
|
975
|
+
else
|
976
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find heat_cap_fpl curve, will not be set.")
|
977
|
+
successfully_set_all_properties = false
|
978
|
+
end
|
979
|
+
|
980
|
+
# Find the minimum COP and rename with efficiency rating
|
981
|
+
cop = airconditioner_variablerefrigerantflow_heating_standard_minimum_cop(airconditioner_variablerefrigerantflow, true, ecm_name)
|
982
|
+
|
983
|
+
# Set the efficiency values
|
984
|
+
unless cop.nil?
|
985
|
+
airconditioner_variablerefrigerantflow.setRatedHeatingCOP(cop.to_f)
|
986
|
+
end
|
987
|
+
|
988
|
+
end
|
989
|
+
|
990
|
+
# =============================================================================================================================
|
991
|
+
# Find minimum efficiency for "CoilCoolingDXVariableSpeed" object
|
992
|
+
def coil_cooling_dx_variable_speed_standard_minimum_cop(coil_cooling_dx_variable_speed, rename = false,ecm_name)
|
993
|
+
search_criteria = coil_dx_find_search_criteria(coil_cooling_dx_variable_speed)
|
994
|
+
cooling_type = search_criteria['cooling_type']
|
995
|
+
heating_type = search_criteria['heating_type']
|
996
|
+
sub_category = search_criteria['subcategory']
|
997
|
+
capacity_w = coil_cooling_dx_variable_speed_find_capacity(coil_cooling_dx_variable_speed)
|
998
|
+
capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get
|
999
|
+
capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get
|
1000
|
+
|
1001
|
+
# Look up the efficiency characteristics
|
1002
|
+
ac_props = if coil_dx_heat_pump?(coil_cooling_dx_variable_speed)
|
1003
|
+
model_find_object(standards_data['tables']["heat_pumps_ecm_#{ecm_name.downcase}"]['table'], search_criteria, capacity_btu_per_hr, Date.today)
|
1004
|
+
else
|
1005
|
+
model_find_object(standards_data['tables']["unitary_acs_ecm_#{ecm_name.downcase}"]['table'], search_criteria, capacity_btu_per_hr, Date.today)
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
# Check to make sure properties were found
|
1009
|
+
if ac_props.nil?
|
1010
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXVariableSpeed', "For #{coil_cooling_dx_variable_speed.name}, cannot find efficiency info using #{search_criteria}, cannot apply efficiency standard.")
|
1011
|
+
successfully_set_all_properties = false
|
1012
|
+
return successfully_set_all_properties
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
# Get the minimum efficiency standards
|
1016
|
+
cop = nil
|
1017
|
+
|
1018
|
+
# If specified as SEER
|
1019
|
+
unless ac_props['minimum_seasonal_energy_efficiency_ratio'].nil?
|
1020
|
+
min_seer = ac_props['minimum_seasonal_energy_efficiency_ratio']
|
1021
|
+
cop = seer_to_cop_cooling_with_fan(min_seer)
|
1022
|
+
new_comp_name = "#{coil_cooling_dx_variable_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_seer}SEER"
|
1023
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilCoolingDXVariableSpeed', "For #{template}: #{coil_cooling_dx_variable_speed.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; SEER = #{min_seer}")
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
# If specified as EER
|
1027
|
+
unless ac_props['minimum_energy_efficiency_ratio'].nil?
|
1028
|
+
min_eer = ac_props['minimum_energy_efficiency_ratio']
|
1029
|
+
cop = eer_to_cop(min_eer)
|
1030
|
+
new_comp_name = "#{coil_cooling_dx_variable_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_eer}EER"
|
1031
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilCoolingDXVariableSpeed', "For #{template}: #{coil_cooling_dx_variable_speed.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
# if specified as SEER (heat pump)
|
1035
|
+
unless ac_props['minimum_seasonal_efficiency'].nil?
|
1036
|
+
min_seer = ac_props['minimum_seasonal_efficiency']
|
1037
|
+
cop = seer_to_cop_cooling_with_fan(min_seer)
|
1038
|
+
new_comp_name = "#{coil_cooling_dx_variable_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_seer}SEER"
|
1039
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilCoolingDXVariableSpeed', "For #{template}: #{coil_cooling_dx_variable_speed.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; SEER = #{min_seer}")
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
# If specified as EER (heat pump)
|
1043
|
+
unless ac_props['minimum_full_load_efficiency'].nil?
|
1044
|
+
min_eer = ac_props['minimum_full_load_efficiency']
|
1045
|
+
cop = eer_to_cop(min_eer)
|
1046
|
+
new_comp_name = "#{coil_cooling_dx_variable_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_eer}EER"
|
1047
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilCoolingDXVariableSpeed', "For #{template}: #{coil_cooling_dx_variable_speed.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
|
1048
|
+
end
|
1049
|
+
|
1050
|
+
# If specified as COP
|
1051
|
+
unless ac_props['minimum_coefficient_of_performance_cooling'].nil?
|
1052
|
+
cop = ac_props['minimum_coefficient_of_performance_cooling']
|
1053
|
+
new_comp_name = "#{coil_cooling_dx_variable_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{cop}COP"
|
1054
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilCoolingDXVariableSpeed', "For #{template}: #{coil_cooling_dx_variable_speed.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; COP = #{cop}")
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
# Rename
|
1058
|
+
if rename
|
1059
|
+
coil_cooling_dx_variable_speed.setName(new_comp_name)
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
return cop
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
# =============================================================================================================================
|
1066
|
+
# Find minimum efficiency for "CoilHeatingDXVariableSingleSpeed" object
|
1067
|
+
def coil_heating_dx_variable_speed_standard_minimum_cop(coil_heating_dx_variable_speed, rename = false,ecm_name)
|
1068
|
+
search_criteria = coil_dx_find_search_criteria(coil_heating_dx_variable_speed)
|
1069
|
+
cooling_type = search_criteria['cooling_type']
|
1070
|
+
heating_type = search_criteria['heating_type']
|
1071
|
+
sub_category = search_criteria['subcategory']
|
1072
|
+
capacity_w = coil_heating_dx_variable_speed_find_capacity(coil_heating_dx_variable_speed)
|
1073
|
+
capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get
|
1074
|
+
capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get
|
1075
|
+
|
1076
|
+
# Look up the efficiency characteristics
|
1077
|
+
props = model_find_object(standards_data['tables']["heat_pumps_heating_ecm_#{ecm_name.downcase}"], search_criteria, capacity_btu_per_hr, Date.today)
|
1078
|
+
|
1079
|
+
# Check to make sure properties were found
|
1080
|
+
if props.nil?
|
1081
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingDXVariableSpeed', "For #{coil_heating_dx_variable_speed.name}, cannot find efficiency info using #{search_criteria}, cannot apply efficiency standard.")
|
1082
|
+
successfully_set_all_properties = false
|
1083
|
+
return successfully_set_all_properties
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
# Get the minimum efficiency standards
|
1087
|
+
cop = nil
|
1088
|
+
|
1089
|
+
# If specified as EER
|
1090
|
+
unless props['minimum_energy_efficiency_ratio'].nil?
|
1091
|
+
min_eer = props['minimum_energy_efficiency_ratio']
|
1092
|
+
cop = eer_to_cop(min_eer)
|
1093
|
+
new_comp_name = "#{coil_heating_dx_variable_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_eer}EER"
|
1094
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilHeatingDXVariableSpeed', "For #{template}: #{coil_heating_dx_variable_speed.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
# if specified as HSPF (heat pump)
|
1098
|
+
unless props['minimum_heating_seasonal_performance_factor'].nil?
|
1099
|
+
min_hspf = props['minimum_heating_seasonal_performance_factor']
|
1100
|
+
cop = hspf_to_cop_heating_with_fan(min_hspf)
|
1101
|
+
new_comp_name = "#{coil_heating_dx_variable_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_seer}HSPF"
|
1102
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilHeatingDXVariableSpeed', "For #{template}: #{coil_heating_dx_variable_speed.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; SEER = #{min_seer}")
|
1103
|
+
end
|
1104
|
+
|
1105
|
+
# If specified as EER (heat pump)
|
1106
|
+
unless props['minimum_full_load_efficiency'].nil?
|
1107
|
+
min_eer = props['minimum_full_load_efficiency']
|
1108
|
+
cop = eer_to_cop(min_eer)
|
1109
|
+
new_comp_name = "#{coil_heating_dx_variable_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_eer}EER"
|
1110
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilHeatingDXVariableSpeed', "For #{template}: #{coil_heating_dx_variable_speed.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
|
1111
|
+
end
|
1112
|
+
|
1113
|
+
# If specified as COP
|
1114
|
+
unless props['minimum_coefficient_of_performance_heating'].nil?
|
1115
|
+
cop = props['minimum_coefficient_of_performance_heating']
|
1116
|
+
new_comp_name = "#{coil_heating_dx_variable_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{cop}COP"
|
1117
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilHeatingDXVariableSpeed', "For #{template}: #{coil_heating_dx_variable_speed.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
|
1118
|
+
end
|
1119
|
+
|
1120
|
+
# Rename
|
1121
|
+
if rename
|
1122
|
+
coil_heating_dx_variable_speed.setName(new_comp_name)
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
return cop
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
# =============================================================================================================================
|
1129
|
+
# Find minimum cooling efficiency for "AirConditionerVariableRefrigerantFlow" object
|
1130
|
+
def airconditioner_variablerefrigerantflow_cooling_standard_minimum_cop(airconditioner_variablerefrigerantflow, rename = false, ecm_name)
|
1131
|
+
search_criteria = coil_dx_find_search_criteria(airconditioner_variablerefrigerantflow)
|
1132
|
+
cooling_type = search_criteria['cooling_type']
|
1133
|
+
heating_type = search_criteria['heating_type']
|
1134
|
+
sub_category = search_criteria['subcategory']
|
1135
|
+
capacity_w = airconditioner_variablerefrigerantflow_cooling_find_capacity(airconditioner_variablerefrigerantflow)
|
1136
|
+
capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get
|
1137
|
+
capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get
|
1138
|
+
|
1139
|
+
# Look up the efficiency characteristics
|
1140
|
+
props = model_find_object(standards_data['tables']["heat_pumps_ecm_#{ecm_name.downcase}"], search_criteria, capacity_btu_per_hr, Date.today)
|
1141
|
+
|
1142
|
+
# Check to make sure properties were found
|
1143
|
+
if props.nil?
|
1144
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find efficiency info using #{search_criteria}, cannot apply efficiency standard.")
|
1145
|
+
successfully_set_all_properties = false
|
1146
|
+
return successfully_set_all_properties
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
# Get the minimum efficiency standards
|
1150
|
+
cop = nil
|
1151
|
+
|
1152
|
+
# If specified as EER
|
1153
|
+
unless props['minimum_energy_efficiency_ratio'].nil?
|
1154
|
+
min_eer = props['minimum_energy_efficiency_ratio']
|
1155
|
+
cop = eer_to_cop(min_eer)
|
1156
|
+
new_comp_name = "#{airconditioner_variablerefrigerantflow.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_eer}EER"
|
1157
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{template}: #{airconditioner_variablerefrigerantflow.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
# if specified as HSPF (heat pump)
|
1161
|
+
unless props['minimum_heating_seasonal_performance_factor'].nil?
|
1162
|
+
min_hspf = props['minimum_heating_seasonal_performance_factor']
|
1163
|
+
cop = hspf_to_cop_heating_with_fan(min_hspf)
|
1164
|
+
new_comp_name = "#{coil_heating_dx_variable_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_seer}HSPF"
|
1165
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{template}: #{airconditioner_variablerefrigerantflow.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; SEER = #{min_seer}")
|
1166
|
+
end
|
1167
|
+
|
1168
|
+
# If specified as EER (heat pump)
|
1169
|
+
unless props['minimum_full_load_efficiency'].nil?
|
1170
|
+
min_eer = props['minimum_full_load_efficiency']
|
1171
|
+
cop = eer_to_cop(min_eer)
|
1172
|
+
new_comp_name = "#{airconditioner_variablerefrigerantflow.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_eer}EER"
|
1173
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{template}: #{airconditioner_variablerefrigerantflow.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
|
1174
|
+
end
|
1175
|
+
|
1176
|
+
# If specified as COP
|
1177
|
+
unless props['minimum_coefficient_of_performance_cooling'].nil?
|
1178
|
+
cop = props['minimum_coefficient_of_performance_cooling']
|
1179
|
+
new_comp_name = "#{airconditioner_variablerefrigerantflow.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{cop}COP"
|
1180
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{template}: #{airconditioner_variablerefrigerantflow.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
# Rename
|
1184
|
+
if rename
|
1185
|
+
airconditioner_variablerefrigerantflow.setName(new_comp_name)
|
1186
|
+
end
|
1187
|
+
|
1188
|
+
return cop
|
1189
|
+
end
|
1190
|
+
|
1191
|
+
# =============================================================================================================================
|
1192
|
+
# Find minimum heating efficiency for "AirConditionerVariableRefrigerantFlow" object
|
1193
|
+
def airconditioner_variablerefrigerantflow_heating_standard_minimum_cop(airconditioner_variablerefrigerantflow, rename = false, ecm_name)
|
1194
|
+
search_criteria = coil_dx_find_search_criteria(airconditioner_variablerefrigerantflow)
|
1195
|
+
cooling_type = search_criteria['cooling_type']
|
1196
|
+
heating_type = search_criteria['heating_type']
|
1197
|
+
sub_category = search_criteria['subcategory']
|
1198
|
+
capacity_w = airconditioner_variablerefrigerantflow_heating_find_capacity(airconditioner_variablerefrigerantflow)
|
1199
|
+
capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get
|
1200
|
+
capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get
|
1201
|
+
|
1202
|
+
# Look up the efficiency characteristics
|
1203
|
+
props = model_find_object(standards_data['tables']["heat_pumps_heating_ecm_#{ecm_name.downcase}"], search_criteria, capacity_btu_per_hr, Date.today)
|
1204
|
+
|
1205
|
+
# Check to make sure properties were found
|
1206
|
+
if props.nil?
|
1207
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name}, cannot find heating efficiency info using #{search_criteria}, cannot apply efficiency standard.")
|
1208
|
+
successfully_set_all_properties = false
|
1209
|
+
return successfully_set_all_properties
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
# Get the minimum efficiency standards
|
1213
|
+
cop = nil
|
1214
|
+
|
1215
|
+
# If specified as EER
|
1216
|
+
unless props['minimum_energy_efficiency_ratio'].nil?
|
1217
|
+
min_eer = props['minimum_energy_efficiency_ratio']
|
1218
|
+
cop = eer_to_cop(min_eer)
|
1219
|
+
new_comp_name = "#{airconditioner_variablerefrigerantflow.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_eer}EER"
|
1220
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{template}: #{airconditioner_variablerefrigerantflow.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
|
1221
|
+
end
|
1222
|
+
|
1223
|
+
# if specified as HSPF (heat pump)
|
1224
|
+
unless props['minimum_heating_seasonal_performance_factor'].nil?
|
1225
|
+
min_hspf = props['minimum_heating_seasonal_performance_factor']
|
1226
|
+
cop = hspf_to_cop_heating_with_fan(min_hspf)
|
1227
|
+
new_comp_name = "#{coil_heating_dx_variable_speed.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_seer}HSPF"
|
1228
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{template}: #{airconditioner_variablerefrigerantflow.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; SEER = #{min_seer}")
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
# If specified as EER (heat pump)
|
1232
|
+
unless props['minimum_full_load_efficiency'].nil?
|
1233
|
+
min_eer = props['minimum_full_load_efficiency']
|
1234
|
+
cop = eer_to_cop(min_eer)
|
1235
|
+
new_comp_name = "#{airconditioner_variablerefrigerantflow.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_eer}EER"
|
1236
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{template}: #{airconditioner_variablerefrigerantflow.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
|
1237
|
+
end
|
1238
|
+
|
1239
|
+
# If specified as COP
|
1240
|
+
unless props['minimum_coefficient_of_performance_heating'].nil?
|
1241
|
+
cop = props['minimum_coefficient_of_performance_heating']
|
1242
|
+
new_comp_name = "#{airconditioner_variablerefrigerantflow.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{cop}COP"
|
1243
|
+
OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{template}: #{airconditioner_variablerefrigerantflow.name}: #{cooling_type} #{heating_type} #{sub_category} Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; EER = #{min_eer}")
|
1244
|
+
end
|
1245
|
+
|
1246
|
+
# Rename
|
1247
|
+
if rename
|
1248
|
+
airconditioner_variablerefrigerantflow.setName(new_comp_name)
|
1249
|
+
end
|
1250
|
+
|
1251
|
+
return cop
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
# =============================================================================================================================
|
1255
|
+
# Find cooling capacity for "CoilCoolingDXVariableSpeed" object
|
1256
|
+
def coil_cooling_dx_variable_speed_find_capacity(coil_cooling_dx_variable_speed)
|
1257
|
+
capacity_w = nil
|
1258
|
+
if coil_cooling_dx_variable_speed.grossRatedTotalCoolingCapacityAtSelectedNominalSpeedLevel.is_initialized
|
1259
|
+
capacity_w = coil_cooling_dx_variable_speed.grossRatedTotalCoolingCapacityAtSelectedNominalSpeedLevel.get
|
1260
|
+
elsif coil_cooling_dx_variable_speed.autosizedGrossRatedTotalCoolingCapacityAtSelectedNominalSpeedLevel.is_initialized
|
1261
|
+
capacity_w = coil_cooling_dx_variable_speed.autosizedGrossRatedTotalCoolingCapacityAtSelectedNominalSpeedLevel.get
|
1262
|
+
else
|
1263
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXVariableSpeed', "For #{coil_cooling_dx_variable_speed.name} capacity is not available, cannot apply efficiency standard.")
|
1264
|
+
return 0.0
|
1265
|
+
end
|
1266
|
+
|
1267
|
+
return capacity_w
|
1268
|
+
end
|
1269
|
+
|
1270
|
+
# =============================================================================================================================
|
1271
|
+
# Find heating capacity for "CoilHeatingDXVariableSpeed" object
|
1272
|
+
def coil_heating_dx_variable_speed_find_capacity(coil_heating_dx_variable_speed)
|
1273
|
+
capacity_w = nil
|
1274
|
+
if coil_heating_dx_variable_speed.ratedHeatingCapacityAtSelectedNominalSpeedLevel.is_initialized
|
1275
|
+
capacity_w = coil_heating_dx_variable_speed.ratedHeatingCapacityAtSelectedNominalSpeedLevel.get
|
1276
|
+
elsif coil_heating_dx_variable_speed.autosizedRatedHeatingCapacityAtSelectedNominalSpeedLevel.is_initialized
|
1277
|
+
capacity_w = coil_heating_dx_variable_speed.autosizedRatedHeatingCapacityAtSelectedNominalSpeedLevel.get
|
1278
|
+
else
|
1279
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingDXVariableSpeed', "For #{coil_heating_dx_variable_speed.name} capacity is not available, cannot apply efficiency standard.")
|
1280
|
+
return 0.0
|
1281
|
+
end
|
1282
|
+
|
1283
|
+
return capacity_w
|
1284
|
+
end
|
1285
|
+
|
1286
|
+
# =============================================================================================================================
|
1287
|
+
# Find cooling capacity for "AirConditionerVariableRefrigerantFlow" object
|
1288
|
+
def airconditioner_variablerefrigerantflow_cooling_find_capacity(airconditioner_variablerefrigerantflow)
|
1289
|
+
capacity_w = nil
|
1290
|
+
if airconditioner_variablerefrigerantflow.ratedTotalCoolingCapacity.is_initialized
|
1291
|
+
capacity_w = airconditioner_variablerefrigerantflow.ratedTotalCoolingCapacity.get
|
1292
|
+
elsif airconditioner_variablerefrigerantflow.autosizedRatedTotalCoolingCapacity.is_initialized
|
1293
|
+
capacity_w = airconditioner_variablerefrigerantflow.autosizedRatedTotalCoolingCapacity.get
|
1294
|
+
airconditioner_variablerefrigerantflow.setRatedTotalCoolingCapacity(capacity_w)
|
1295
|
+
else
|
1296
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name} cooling capacity is not available, cannot apply efficiency standard.")
|
1297
|
+
return 0.0
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
return capacity_w
|
1301
|
+
end
|
1302
|
+
|
1303
|
+
# =============================================================================================================================
|
1304
|
+
# Find heating capacity for "AirConditionerVariableRefrigerantFlow" object
|
1305
|
+
def airconditioner_variablerefrigerantflow_heating_find_capacity(airconditioner_variablerefrigerantflow)
|
1306
|
+
capacity_w = nil
|
1307
|
+
if airconditioner_variablerefrigerantflow.ratedTotalHeatingCapacity.is_initialized
|
1308
|
+
capacity_w = airconditioner_variablerefrigerantflow.ratedTotalHeatingCapacity.get
|
1309
|
+
elsif airconditioner_variablerefrigerantflow.autosizedRatedTotalHeatingCapacity.is_initialized
|
1310
|
+
capacity_w = airconditioner_variablerefrigerantflow.autosizedRatedTotalHeatingCapacity.get
|
1311
|
+
airconditioner_variablerefrigerantflow.setRatedTotalHeatingCapacity(capacity_w)
|
1312
|
+
else
|
1313
|
+
OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.AirConditionerVariableRefrigerantFlow', "For #{airconditioner_variablerefrigerantflow.name} heating capacity is not available, cannot apply efficiency standard.")
|
1314
|
+
return 0.0
|
1315
|
+
end
|
1316
|
+
|
1317
|
+
return capacity_w
|
1318
|
+
end
|
1319
|
+
|
1320
|
+
# ============================================================================================================================
|
1321
|
+
# Apply boiler efficiency
|
1322
|
+
# This model takes an OS model and a boiler efficiency string or hash sent to it with the following form:
|
1323
|
+
# "boiler_eff": {
|
1324
|
+
# "name" => "NECB 88% Efficient Condensing Boiler",
|
1325
|
+
# "efficiency" => 0.88,
|
1326
|
+
# "part_load_curve" => "BOILER-EFFPLR-COND-NECB2011",
|
1327
|
+
# "notes" => "From NECB 2011."
|
1328
|
+
# }
|
1329
|
+
# If boiler_eff is nill then it does nothing. If both "efficiency" and "part_load_curve" are nil then it does
|
1330
|
+
# nothing. If a boiler_eff is passed as a string and not a hash then it looks for a "name" field in the
|
1331
|
+
# boiler_set.json file that matches boiler_eff and gets the associated boiler performance details from the file.
|
1332
|
+
# If an efficiency is set but is not between 0.01 and 1.0 it returns an error. Otherwise, it looks for plant loop
|
1333
|
+
# supply components that match the "OS_BoilerHotWater" type. If it finds one it then calls the
|
1334
|
+
# "reset_boiler_efficiency method which resets the the boiler efficiency and looks for the part load efficiency curve
|
1335
|
+
# in the curves.json file. If it finds a curve it sets the part load curve to that, otherwise it returns an error.
|
1336
|
+
# It also renames the boiler to include the "boiler_eff"["name"].
|
1337
|
+
def modify_boiler_efficiency(model:, boiler_eff: nil)
|
1338
|
+
return if boiler_eff.nil?
|
1339
|
+
# If boiler_eff is a string rather than a hash then assume it is the name of a boiler efficiency package and look
|
1340
|
+
# for a package with that name in boiler_set.json.
|
1341
|
+
if boiler_eff.is_a?(String)
|
1342
|
+
eff_packages = @standards_data['tables']['boiler_eff_ecm']['table']
|
1343
|
+
eff_package = eff_packages.select{|eff_pack_info| eff_pack_info["name"] == boiler_eff}
|
1344
|
+
if eff_package.empty?
|
1345
|
+
raise "Cannot not find #{boiler_eff} in the ECMS boiler_set.json file. Please check that the name is correctly spelled in the ECMS class boiler_set.json and in the code calling (directly or through another method) the ECMS class modify_boiler_efficiency method."
|
1346
|
+
elsif eff_package.size > 1
|
1347
|
+
raise "More than one boiler efficiency package with the name #{boiler_eff} was found. Please check the ECMS class boiler_set.json file and make sure that each boiler efficiency package has a unique name."
|
1348
|
+
else
|
1349
|
+
ecm_name = boiler_eff
|
1350
|
+
boiler_eff = {
|
1351
|
+
"name" => ecm_name,
|
1352
|
+
"efficiency" => eff_package[0]['efficiency'],
|
1353
|
+
"part_load_curve" => eff_package[0]['part_load_curve']
|
1354
|
+
}
|
1355
|
+
end
|
1356
|
+
end
|
1357
|
+
# If nothing is passed in the boiler_eff hash then assume this was not supposed to be used and return without doing
|
1358
|
+
# anything.
|
1359
|
+
return if boiler_eff["name"].nil? && boiler_eff["efficiency"].nil? && boiler_eff["part_load_curve"].nil?
|
1360
|
+
# If no efficiency or partload curve are found (either passed directly or via the boiler_set.json file) then assume
|
1361
|
+
# that the current SHW setting should not be changed. Return without changing anything.
|
1362
|
+
return if boiler_eff["efficiency"].nil? && boiler_eff["part_load_curve"].nil?
|
1363
|
+
raise "You attempted to set the efficiency of boilers in this model to nil. Please check the ECMS class boiler_set.json and make sure the efficiency is properly set" if boiler_eff["efficiency"].nil?
|
1364
|
+
raise "You attempted to set the efficiency of boilers in this model to: #{boiler_eff['efficiency']}. Please check the ECMS class boiler_set.json and make sure the efficiency you set is between 0.01 and 1.0." if (boiler_eff['efficiency'] < 0.01 || boiler_eff['efficiency'] > 1.0)
|
1365
|
+
raise "You attempted to set the part load curve of boilers in this model to nil. Please check the ECMS class boiler_set.json file and ensure that both the efficiency and part load curve are set." if boiler_eff['part_load_curve'].nil?
|
1366
|
+
model.getBoilerHotWaters.sort.each do |mod_boiler|
|
1367
|
+
reset_boiler_efficiency(model: model, component: mod_boiler.to_BoilerHotWater.get, eff: boiler_eff)
|
1368
|
+
end
|
1369
|
+
end
|
1370
|
+
|
1371
|
+
# This method takes an OS model, a "OS_BoilerHotWater" type compenent, condensing efficiency limit and an efficiency
|
1372
|
+
# hash which looks like:
|
1373
|
+
# "eff": {
|
1374
|
+
# "name": "NECB 88% Efficient Condensing Boiler",
|
1375
|
+
# "efficiency" => 0.88,
|
1376
|
+
# "part_load_curve" => "BOILER-EFFPLR-COND-NECB2011",
|
1377
|
+
# "notes" => "From NECB 2011."
|
1378
|
+
# }
|
1379
|
+
# This method sets efficiency of the boiler to whatever is entered in eff["efficiency"]. It then looks for the
|
1380
|
+
# "part_load_curve" value in the curves.json file. If it does not find one it returns an error. If it finds one it
|
1381
|
+
# reset the part load curve to whatever was found. It then determines the nominal capacity of the boiler. If the
|
1382
|
+
# nominal capacity is greater than 1W the boiler is considered a primary boiler (for the name only) if the capacity is
|
1383
|
+
# less than 1W the boiler is considered a secondary boiler (for the name only). It then renames the boiler according
|
1384
|
+
# to the following pattern:
|
1385
|
+
# "Primary/Secondary eff["name"] capacity kBtu/hr".
|
1386
|
+
def reset_boiler_efficiency(model:, component:, eff:)
|
1387
|
+
component.setNominalThermalEfficiency(eff['efficiency'])
|
1388
|
+
part_load_curve_name = eff["part_load_curve"].to_s
|
1389
|
+
existing_curve = @standards_data['curves'].select { |curve| curve['name'] == part_load_curve_name }
|
1390
|
+
raise "No boiler with the name #{part_load_curve_name} could be found in the ECMS class curves.json file. Please check both the ECMS class boiler_set.json and class curves.json files to ensure the curve is entered and referenced correctly." if existing_curve.empty?
|
1391
|
+
part_load_curve_data = (@standards_data["curves"].select { |curve| curve['name'] == part_load_curve_name })[0]
|
1392
|
+
if part_load_curve_data['independent_variable_1'].to_s.upcase == 'TEnteringBoiler'.upcase || part_load_curve_data['independent_variable_2'].to_s.upcase == 'TEnteringBoiler'.upcase
|
1393
|
+
component.setEfficiencyCurveTemperatureEvaluationVariable('EnteringBoiler')
|
1394
|
+
elsif part_load_curve_data['independent_variable_1'].to_s.upcase == 'TLeavingBoiler'.upcase || part_load_curve_data['independent_variable_2'].to_s.upcase == 'TLeavingBoiler'.upcase
|
1395
|
+
component.setEfficiencyCurveTemperatureEvaluationVariable('LeavingBoiler')
|
1396
|
+
end
|
1397
|
+
part_load_curve = model_add_curve(model, part_load_curve_name)
|
1398
|
+
if part_load_curve
|
1399
|
+
component.setNormalizedBoilerEfficiencyCurve(part_load_curve)
|
1400
|
+
if component.isNominalCapacityAutosized
|
1401
|
+
boiler_size_W = model.getAutosizedValue(component, 'Design Size Nominal Capacity', 'W').to_f
|
1402
|
+
else
|
1403
|
+
boiler_size_W = component.nominalCapacity.to_f
|
1404
|
+
end
|
1405
|
+
boiler_size_kbtu_per_hour = (OpenStudio.convert(boiler_size_W, 'W', 'kBtu/h').get)
|
1406
|
+
boiler_primacy = 'Primary '
|
1407
|
+
if boiler_size_W < 1.0
|
1408
|
+
boiler_primacy = 'Secondary '
|
1409
|
+
end
|
1410
|
+
if eff['name'].nil?
|
1411
|
+
eff_measure_name = "Revised Performance Boiler"
|
1412
|
+
else
|
1413
|
+
eff_measure_name = eff['name']
|
1414
|
+
end
|
1415
|
+
new_boiler_name = boiler_primacy + eff_measure_name + " #{boiler_size_kbtu_per_hour.round(0)}kBtu/hr #{component.nominalThermalEfficiency} Thermal Eff"
|
1416
|
+
component.setName(new_boiler_name)
|
1417
|
+
else
|
1418
|
+
raise "There was a problem setting the boiler part load curve named #{part_load_curve_name} for #{component.name}. Please ensure that the curve is entered and referenced correctly in the ECMS class curves.json and boiler_set.json files."
|
1419
|
+
end
|
1420
|
+
end
|
1421
|
+
|
1422
|
+
# ============================================================================================================================
|
1423
|
+
# Apply Furnace efficiency
|
1424
|
+
# This model takes an OS model and a furnace efficiency string or hash sent to it with the following form:
|
1425
|
+
# "furnace_eff": {
|
1426
|
+
# "name" => "NECB 85% Efficient Condensing Furnace",
|
1427
|
+
# "efficiency" => 0.85,
|
1428
|
+
# "part_load_curve" => "FURNACE-EFFPLR-COND-NECB2011",
|
1429
|
+
# "notes" => "From NECB 2011."
|
1430
|
+
# }
|
1431
|
+
# If furnace_eff is nil then it does nothing. If both "efficiency" and "part_load_curve" are nil then it does
|
1432
|
+
# nothing. If a furnace_eff is a string it looks for furnace_eff as a "name" in the furnace_set.json file to find
|
1433
|
+
# the performance details. If an efficiency is set but is not between 0.01 and 1.0 it returns an error. Otherwise,
|
1434
|
+
# it looks for air loop supply components that match the "OS_CoilHeatingGas" type. If it finds one it then calls the
|
1435
|
+
# reset_furnace_efficiency method which resets the the furnace efficiency and looks for the part load efficiency curve
|
1436
|
+
# in the curves.json file. If it finds a curve it sets the part load curve to that, otherwise it returns an error. It
|
1437
|
+
# also renames the furnace to include the "furnace_eff"["name"].
|
1438
|
+
def modify_furnace_efficiency(model:, furnace_eff: nil)
|
1439
|
+
return if furnace_eff.nil?
|
1440
|
+
# If furnace_eff is a string rather than a hash then assume it is the name of a furnace efficiency package and look
|
1441
|
+
# for a package with that name in furnace_set.json.
|
1442
|
+
if furnace_eff.is_a?(String)
|
1443
|
+
eff_packages = @standards_data['tables']['furnace_eff_ecm']['table']
|
1444
|
+
eff_package = eff_packages.select{|eff_pack_info| eff_pack_info["name"] == furnace_eff}
|
1445
|
+
if eff_package.empty?
|
1446
|
+
raise "Cannot not find #{furnace_eff} in the ECMS furnace_set.json file. Please check that the name is correctly spelled in the ECMS class furnace_set.json and in the code calling (directly or through another method) the ECMS class modify_furnace_efficiency method."
|
1447
|
+
elsif eff_package.size > 1
|
1448
|
+
raise "More than one furnace efficiency package with the name #{furnace_eff} was found. Please check the ECMS class furnace_set.json file and make sure that each furnace efficiency package has a unique name."
|
1449
|
+
else
|
1450
|
+
ecm_name = furnace_eff
|
1451
|
+
furnace_eff = {
|
1452
|
+
"name" => ecm_name,
|
1453
|
+
"efficiency" => eff_package[0]['efficiency'],
|
1454
|
+
"part_load_curve" => eff_package[0]['part_load_curve']
|
1455
|
+
}
|
1456
|
+
end
|
1457
|
+
end
|
1458
|
+
# If nothing is passed in the furnace_eff hash then assume this was not supposed to be used and return without doing
|
1459
|
+
# anything.
|
1460
|
+
return if furnace_eff["name"].nil? && furnace_eff["efficiency"].nil? && furnace_eff["part_load_curve"].nil?
|
1461
|
+
# If no efficiency or partload curve are found (either passed directly or via the furnace_set.json file) then assume
|
1462
|
+
# that the current furance performance settings should not be changed. Return without changing anything.
|
1463
|
+
return if furnace_eff["efficiency"].nil? && furnace_eff["part_load_curve"].nil?
|
1464
|
+
raise "You attempted to set the efficiency of furnaces in this model to nil. Please check the ECMS class furnace_set.json file and make sure the efficiency is set" if furnace_eff["efficiency"].nil?
|
1465
|
+
raise "You attempted to set the efficiency of furnaces in this model to: #{furnace_eff['efficiency']}. Please check the ECMS class furnace_set.json file and make sure the efficiency you set is between 0.01 and 1.0." if (furnace_eff['efficiency'] < 0.01 || furnace_eff['efficiency'] > 1.0)
|
1466
|
+
raise "You attempted to set the part load curve of furnaces in this model to nil. Please check the ECMS class furnace_set.json file and ensure that both the efficiency and part load curve are set." if furnace_eff['part_load_curve'].nil?
|
1467
|
+
model.getCoilHeatingGass.sort.each do |mod_furnace|
|
1468
|
+
reset_furnace_efficiency(model: model, component: mod_furnace.to_CoilHeatingGas.get, eff: furnace_eff)
|
1469
|
+
end
|
1470
|
+
end
|
1471
|
+
|
1472
|
+
# This method takes an OS model, a "OS_CoilHeatingGas" type compenent, and an efficiency hash which looks like:
|
1473
|
+
# "eff": {
|
1474
|
+
# "name": "NECB 85% Efficient Condensing Furnace",
|
1475
|
+
# "efficiency" => 0.85,
|
1476
|
+
# "part_load_curve" => "FURNACE-EFFPLR-COND-NECB2011",
|
1477
|
+
# "notes" => "From NECB 2011."
|
1478
|
+
# }
|
1479
|
+
# This method sets the efficiency of the furnace to whatever is entered in eff["efficiency"]. It then looks for the
|
1480
|
+
# "part_load_curve" value in the curves.json file. If it does not find one it returns an error. If it finds one it
|
1481
|
+
# reset the part load curve to whatever was found. It then renames the furnace according to the following pattern:
|
1482
|
+
# "eff["name"] + <furnace number (whatever was there before)>".
|
1483
|
+
def reset_furnace_efficiency(model:, component:, eff:)
|
1484
|
+
component.setGasBurnerEfficiency(eff['efficiency'])
|
1485
|
+
part_load_curve_name = eff["part_load_curve"].to_s
|
1486
|
+
existing_curve = @standards_data['curves'].select { |curve| curve['name'] == part_load_curve_name }
|
1487
|
+
raise "No furnace part load curve with the name #{part_load_curve_name} could be found in the ECMS class curves.json file. Please check both the ECMS class curves.json and the measure furnace_set.json files to ensure the curve is entered and referenced correctly." if existing_curve.empty?
|
1488
|
+
part_load_curve = model_add_curve(model, part_load_curve_name)
|
1489
|
+
raise "There was a problem setting the furnace part load curve named #{part_load_curve_name} for #{component.name}. Please ensure that the curve is entered and referenced correctly in the ECMS class curves.json or measure furnace_set.json files." unless part_load_curve
|
1490
|
+
component.setPartLoadFractionCorrelationCurve(part_load_curve)
|
1491
|
+
if eff['name'].nil?
|
1492
|
+
ecm_package_name = "Revised Performance Furnace"
|
1493
|
+
else
|
1494
|
+
ecm_package_name = eff['name']
|
1495
|
+
end
|
1496
|
+
furnace_num = component.name.to_s.gsub(/[^0-9]/, '')
|
1497
|
+
new_furnace_name = ecm_package_name + " #{furnace_num}"
|
1498
|
+
component.setName(new_furnace_name)
|
1499
|
+
end
|
1500
|
+
|
1501
|
+
# ============================================================================================================================
|
1502
|
+
# Apply shw efficiency
|
1503
|
+
# This model takes an OS model and a shw efficiency string or hash sent to it with the following form:
|
1504
|
+
# "shw_eff": {
|
1505
|
+
# "name" => "Natural Gas Power Vent with Electric Ignition",
|
1506
|
+
# "efficiency" => 0.94,
|
1507
|
+
# "part_load_curve" => "SWH-EFFFPLR-NECB2011"
|
1508
|
+
# "notes" => "From NECB 2011."
|
1509
|
+
# }
|
1510
|
+
# If shw_eff is nil then it does nothing. If both "efficiency" and "part_load_curve" are nil then it does nothing.
|
1511
|
+
# If shw_eff is a string then it looks for shw_eff as a "name" in the shw_set.json file for the details on the tank.
|
1512
|
+
# If an efficiency is set but is not between 0.01 and 1.0 it returns an error. Otherwise, it looks for mixed water
|
1513
|
+
# heaters. If it finds any it then calls the reset_shw_efficiency method which resets the the shw efficiency and the
|
1514
|
+
# part load curve. It also renames the shw tank with the following pattern:
|
1515
|
+
# {valume}Gal {eff_name} Water Heater - {Capacity}kBtu/hr {efficiency} Therm Eff
|
1516
|
+
def modify_shw_efficiency(model:, shw_eff: nil)
|
1517
|
+
return if shw_eff.nil?
|
1518
|
+
# If shw_eff is a string rather than a hash then assume it is the name of a shw efficiency package and look
|
1519
|
+
# for a package with that name in shw_set.json.
|
1520
|
+
if shw_eff.is_a?(String)
|
1521
|
+
eff_packages = @standards_data['tables']['shw_eff_ecm']['table']
|
1522
|
+
eff_package = eff_packages.select{|eff_pack_info| eff_pack_info["name"] == shw_eff}
|
1523
|
+
if eff_package.empty?
|
1524
|
+
raise "Cannot not find #{shw_eff} in the ECMS shw_set.json file. Please check that the name is correctly spelled in the ECMS class shw_set.json and in the code calling (directly or through another method) the ECMS class modify_shw_efficiency method."
|
1525
|
+
elsif eff_package.size > 1
|
1526
|
+
raise "More than one shw tank efficiency package with the name #{shw_eff} was found. Please check the ECMS class shw_set.json file and make sure that each shw tank efficiency package has a unique name."
|
1527
|
+
else
|
1528
|
+
ecm_name = shw_eff
|
1529
|
+
shw_eff = {
|
1530
|
+
"name" => ecm_name,
|
1531
|
+
"efficiency" => eff_package[0]['efficiency'],
|
1532
|
+
"part_load_curve" => eff_package[0]['part_load_curve']
|
1533
|
+
}
|
1534
|
+
end
|
1535
|
+
end
|
1536
|
+
# If nothing is passed in the shw_eff hash then assume this was not supposed to be used and return without doing
|
1537
|
+
# anything.
|
1538
|
+
return if shw_eff["name"].nil? && shw_eff["efficiency"].nil? && shw_eff["part_load_curve"].nil?
|
1539
|
+
# If no efficiency or partload curve are found (either passed directly or via the shw_set.json file) then assume
|
1540
|
+
# that the current shw performance settings should not be changed. Return without changing anything.
|
1541
|
+
return if shw_eff["efficiency"].nil? && shw_eff["part_load_curve"].nil?
|
1542
|
+
raise "You attempted to set the efficiency of shw tanks in this model to nil. Please check the ECMS class shw_set.json file and make sure the efficiency is set" if shw_eff["efficiency"].nil?
|
1543
|
+
raise "You attempted to set the efficiency of shw tanks in this model to: #{shw_eff['efficiency']}. Please check the ECMS class shw_set.json and make sure the efficiency you set is between 0.01 and 1.0." if (shw_eff['efficiency'] < 0.01 || shw_eff['efficiency'] > 1.0)
|
1544
|
+
raise "You attempted to set the part load curve of shw tanks in this model to nil. Please check the ECMS class shw_set.json file and ensure that both the efficiency and part load curve are set." if shw_eff['part_load_curve'].nil?
|
1545
|
+
model.getWaterHeaterMixeds.sort.each do |shw_mod|
|
1546
|
+
reset_shw_efficiency(model: model, component: shw_mod, eff: shw_eff)
|
1547
|
+
end
|
1548
|
+
end
|
1549
|
+
|
1550
|
+
# This method takes an OS model, a "OS_WaterHeaterMixed" type compenent, and an efficiency hash which looks like:
|
1551
|
+
# "eff": {
|
1552
|
+
# "name": "Natural Gas Power Vent with Electric Ignition",
|
1553
|
+
# "efficiency" => 0.94,
|
1554
|
+
# "part_load_curve" => "SWH-EFFFPLR-NECB2011",
|
1555
|
+
# "notes" => "From NECB 2011."
|
1556
|
+
# }
|
1557
|
+
# This method sets the efficiency of the shw heater to whatever is entered in eff["efficiency"]. It then looks for the
|
1558
|
+
# "part_load_curve" value in the curves.json file. If it does not find one it returns an error. If it finds one it
|
1559
|
+
# resets the part load curve to whatever was found. It then renames the shw tank according to the following pattern:
|
1560
|
+
# {valume}Gal {eff_name} Water Heater - {Capacity}kBtu/hr {efficiency} Therm Eff
|
1561
|
+
def reset_shw_efficiency(model:, component:, eff:)
|
1562
|
+
return if component.heaterFuelType.to_s.upcase == 'ELECTRICITY'
|
1563
|
+
eff_result = component.setHeaterThermalEfficiency(eff['efficiency'].to_f)
|
1564
|
+
raise "There was a problem setting the efficiency of the SHW #{component.name.to_s}. Please check the ECMS class shw_set.json file or the model." unless eff_result
|
1565
|
+
part_load_curve_name = eff["part_load_curve"].to_s
|
1566
|
+
existing_curve = @standards_data['curves'].select { |curve| curve['name'] == part_load_curve_name }
|
1567
|
+
raise "No shw tank part load curve with the name #{part_load_curve_name} could be found in the ECMS class curves.json file. Please check both the ECMS class curves.json and the measure shw_set.json files to ensure the curve is entered and referenced correctly." if existing_curve.empty?
|
1568
|
+
part_load_curve = model_add_curve(model, part_load_curve_name)
|
1569
|
+
raise "There was a problem setting the shw tank part load curve named #{part_load_curve_name} for #{component.name}. Please ensure that the curve is entered and referenced correctly in the ECMS class curves.json and shw_set.json files." unless part_load_curve
|
1570
|
+
component.setPartLoadFactorCurve(part_load_curve)
|
1571
|
+
#Get the volume and capacity of the SHW tank.
|
1572
|
+
if component.isTankVolumeAutosized
|
1573
|
+
shw_vol_gal = "auto_size"
|
1574
|
+
else
|
1575
|
+
shw_vol_m3 = component.tankVolume.to_f
|
1576
|
+
shw_vol_gal = (OpenStudio.convert(shw_vol_m3, 'm^3', 'gal').get).to_f.round(0)
|
1577
|
+
end
|
1578
|
+
if component.isHeaterMaximumCapacityAutosized
|
1579
|
+
shw_capacity_kBtu_hr = "auto_cap"
|
1580
|
+
else
|
1581
|
+
shw_capacity_W = component.heaterMaximumCapacity.to_f
|
1582
|
+
shw_capacity_kBtu_hr = (OpenStudio.convert(shw_capacity_W, 'W', 'kBtu/h').get).to_f.round(0)
|
1583
|
+
end
|
1584
|
+
# Set a default revised shw tank name if no name is present in the eff hash.
|
1585
|
+
if eff["name"].nil?
|
1586
|
+
shw_ecm_package_name = "Revised"
|
1587
|
+
else
|
1588
|
+
shw_ecm_package_name = eff["name"]
|
1589
|
+
end
|
1590
|
+
shw_name = "#{shw_vol_gal} Gal #{shw_ecm_package_name} Water Heater - #{shw_capacity_kBtu_hr}kBtu/hr #{eff["efficiency"]} Therm Eff"
|
1591
|
+
component.setName(shw_name)
|
1592
|
+
end
|
1593
|
+
end
|