Skip to content

Commit 2b0d89b

Browse files
committed
Fix possible incorrect value for system use, bug introduced in #1456. Adds error-checking to prevent this going forward. Some other minor misc cleanup.
1 parent 9cd53e4 commit 2b0d89b

File tree

7 files changed

+151
-122
lines changed

7 files changed

+151
-122
lines changed

HPXMLtoOpenStudio/measure.rb

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,25 +1839,14 @@ def add_lighting(runner, model, epw_file, spaces)
18391839
end
18401840

18411841
def add_pools_and_permanent_spas(runner, model, spaces)
1842-
@hpxml_bldg.pools.each do |pool|
1843-
next if pool.type == HPXML::TypeNone
1842+
(@hpxml_bldg.pools + @hpxml_bldg.permanent_spas).each do |pool_or_spa|
1843+
next if pool_or_spa.type == HPXML::TypeNone
18441844

1845-
MiscLoads.apply_pool_or_permanent_spa_heater(runner, model, pool, Constants.ObjectNameMiscPoolHeater, spaces[HPXML::LocationConditionedSpace],
1845+
MiscLoads.apply_pool_or_permanent_spa_heater(runner, model, pool_or_spa, Constants.ObjectNameMiscPoolHeater, spaces[HPXML::LocationConditionedSpace],
18461846
@schedules_file, @hpxml_header.unavailable_periods)
1847-
next if pool.pump_type == HPXML::TypeNone
1847+
next if pool_or_spa.pump_type == HPXML::TypeNone
18481848

1849-
MiscLoads.apply_pool_or_permanent_spa_pump(runner, model, pool, Constants.ObjectNameMiscPoolPump, spaces[HPXML::LocationConditionedSpace],
1850-
@schedules_file, @hpxml_header.unavailable_periods)
1851-
end
1852-
1853-
@hpxml_bldg.permanent_spas.each do |spa|
1854-
next if spa.type == HPXML::TypeNone
1855-
1856-
MiscLoads.apply_pool_or_permanent_spa_heater(runner, model, spa, Constants.ObjectNameMiscPermanentSpaHeater, spaces[HPXML::LocationConditionedSpace],
1857-
@schedules_file, @hpxml_header.unavailable_periods)
1858-
next if spa.pump_type == HPXML::TypeNone
1859-
1860-
MiscLoads.apply_pool_or_permanent_spa_pump(runner, model, spa, Constants.ObjectNameMiscPermanentSpaPump, spaces[HPXML::LocationConditionedSpace],
1849+
MiscLoads.apply_pool_or_permanent_spa_pump(runner, model, pool_or_spa, Constants.ObjectNameMiscPoolPump, spaces[HPXML::LocationConditionedSpace],
18611850
@schedules_file, @hpxml_header.unavailable_periods)
18621851
end
18631852
end

HPXMLtoOpenStudio/measure.xml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
<schema_version>3.1</schema_version>
44
<name>hpxm_lto_openstudio</name>
55
<uid>b1543b30-9465-45ff-ba04-1d1f85e763bc</uid>
6-
<version_id>3fd0d61d-6deb-439c-8f45-a807ea2095fd</version_id>
7-
<version_modified>2023-11-03T01:16:16Z</version_modified>
6+
<version_id>080307ba-bc1e-402e-9033-82830e43b579</version_id>
7+
<version_modified>2023-11-03T20:34:45Z</version_modified>
88
<xml_checksum>D8922A73</xml_checksum>
99
<class_name>HPXMLtoOpenStudio</class_name>
1010
<display_name>HPXML to OpenStudio Translator</display_name>
@@ -142,13 +142,13 @@
142142
<filename>measure.rb</filename>
143143
<filetype>rb</filetype>
144144
<usage_type>script</usage_type>
145-
<checksum>5BFBE071</checksum>
145+
<checksum>58A2987F</checksum>
146146
</file>
147147
<file>
148148
<filename>airflow.rb</filename>
149149
<filetype>rb</filetype>
150150
<usage_type>resource</usage_type>
151-
<checksum>72035A85</checksum>
151+
<checksum>83E00DDE</checksum>
152152
</file>
153153
<file>
154154
<filename>battery.rb</filename>
@@ -168,6 +168,12 @@
168168
<usage_type>resource</usage_type>
169169
<checksum>E7E0949D</checksum>
170170
</file>
171+
<file>
172+
<filename>data/Xing_okstate_0664D_13659_Table_A-3 - Copy.csv</filename>
173+
<filetype>csv</filetype>
174+
<usage_type>resource</usage_type>
175+
<checksum>50B7055C</checksum>
176+
</file>
171177
<file>
172178
<filename>data/ashrae_622_wsf.csv</filename>
173179
<filetype>csv</filetype>
@@ -328,7 +334,7 @@
328334
<filename>misc_loads.rb</filename>
329335
<filetype>rb</filetype>
330336
<usage_type>resource</usage_type>
331-
<checksum>AF5961B5</checksum>
337+
<checksum>F8595E25</checksum>
332338
</file>
333339
<file>
334340
<filename>output.rb</filename>
@@ -502,7 +508,7 @@
502508
<filename>waterheater.rb</filename>
503509
<filetype>rb</filetype>
504510
<usage_type>resource</usage_type>
505-
<checksum>C162FE36</checksum>
511+
<checksum>B6B9743C</checksum>
506512
</file>
507513
<file>
508514
<filename>weather.rb</filename>

HPXMLtoOpenStudio/resources/airflow.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,7 +1711,9 @@ def self.calculate_precond_loads(model, infil_program, vent_mech_preheat, vent_m
17111711
end
17121712
vent_mech_preheat.each_with_index do |f_preheat, i|
17131713
infil_program.addLine("If (OASupInTemp < HtgStp) && (#{clg_ssn_sensor.name} < 1)")
1714-
htg_energy_actuator = create_other_equipment_object_and_actuator(model: model, name: "shared mech vent preheating energy #{i}", space: @conditioned_space, frac_lat: 0.0, frac_lost: 1.0, hpxml_fuel_type: f_preheat.preheating_fuel, end_use: Constants.ObjectNameMechanicalVentilationPreheating)
1714+
cnt = model.getOtherEquipments.select { |oe| oe.endUseSubcategory.start_with? Constants.ObjectNameMechanicalVentilationPreheating }.size # Ensure unique meter for each water heater
1715+
htg_energy_actuator = create_other_equipment_object_and_actuator(model: model, name: "shared mech vent preheating energy #{i}", space: @conditioned_space, frac_lat: 0.0, frac_lost: 1.0, hpxml_fuel_type: f_preheat.preheating_fuel, end_use: "#{Constants.ObjectNameMechanicalVentilationPreheating}#{cnt}")
1716+
htg_energy_actuator.actuatedComponent.get.additionalProperties.setFeature('HPXML_ID', f_preheat.id) # Used by reporting measure
17151717
infil_program.addLine(" Set Qpreheat = #{UnitConversions.convert(f_preheat.average_oa_unit_flow_rate, 'cfm', 'm^3/s').round(4)}")
17161718
if [HPXML::MechVentTypeERV, HPXML::MechVentTypeHRV].include? f_preheat.fan_type
17171719
vent_mech_erv_hrv_tot = [f_preheat]
@@ -1735,7 +1737,9 @@ def self.calculate_precond_loads(model, infil_program, vent_mech_preheat, vent_m
17351737
end
17361738
vent_mech_precool.each_with_index do |f_precool, i|
17371739
infil_program.addLine("If (OASupInTemp > ClgStp) && (#{clg_ssn_sensor.name} > 0)")
1738-
clg_energy_actuator = create_other_equipment_object_and_actuator(model: model, name: "shared mech vent precooling energy #{i}", space: @conditioned_space, frac_lat: 0.0, frac_lost: 1.0, hpxml_fuel_type: f_precool.precooling_fuel, end_use: Constants.ObjectNameMechanicalVentilationPrecooling)
1740+
cnt = model.getOtherEquipments.select { |oe| oe.endUseSubcategory.start_with? Constants.ObjectNameMechanicalVentilationPrecooling }.size # Ensure unique meter for each water heater
1741+
clg_energy_actuator = create_other_equipment_object_and_actuator(model: model, name: "shared mech vent precooling energy #{i}", space: @conditioned_space, frac_lat: 0.0, frac_lost: 1.0, hpxml_fuel_type: f_precool.precooling_fuel, end_use: "#{Constants.ObjectNameMechanicalVentilationPrecooling}#{cnt}")
1742+
clg_energy_actuator.actuatedComponent.get.additionalProperties.setFeature('HPXML_ID', f_precool.id) # Used by reporting measure
17391743
infil_program.addLine(" Set Qprecool = #{UnitConversions.convert(f_precool.average_oa_unit_flow_rate, 'cfm', 'm^3/s').round(4)}")
17401744
if [HPXML::MechVentTypeERV, HPXML::MechVentTypeHRV].include? f_precool.fan_type
17411745
vent_mech_erv_hrv_tot = [f_precool]

HPXMLtoOpenStudio/resources/misc_loads.rb

Lines changed: 63 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -61,37 +61,36 @@ def self.apply_plug(model, runner, plug_load, obj_name, conditioned_space, apply
6161

6262
def self.apply_fuel(model, runner, fuel_load, obj_name, conditioned_space, schedules_file, unavailable_periods)
6363
therm = 0
64-
6564
if not fuel_load.nil?
6665
therm = fuel_load.therm_per_year * fuel_load.usage_multiplier
67-
68-
# Create schedule
69-
sch = nil
70-
if fuel_load.fuel_load_type == HPXML::FuelLoadTypeGrill
71-
col_name = SchedulesFile::ColumnFuelLoadsGrill
72-
elsif fuel_load.fuel_load_type == HPXML::FuelLoadTypeLighting
73-
col_name = SchedulesFile::ColumnFuelLoadsLighting
74-
elsif fuel_load.fuel_load_type == HPXML::FuelLoadTypeFireplace
75-
col_name = SchedulesFile::ColumnFuelLoadsFireplace
76-
end
77-
if not schedules_file.nil?
78-
space_design_level = schedules_file.calc_design_level_from_annual_therm(col_name: col_name, annual_therm: therm)
79-
sch = schedules_file.create_schedule_file(model, col_name: col_name)
80-
end
81-
if sch.nil?
82-
col_unavailable_periods = Schedule.get_unavailable_periods(runner, col_name, unavailable_periods)
83-
sch = MonthWeekdayWeekendSchedule.new(model, obj_name + ' schedule', fuel_load.weekday_fractions, fuel_load.weekend_fractions, fuel_load.monthly_multipliers, Constants.ScheduleTypeLimitsFraction, unavailable_periods: col_unavailable_periods)
84-
space_design_level = sch.calc_design_level_from_daily_therm(therm / 365.0)
85-
sch = sch.schedule
86-
else
87-
runner.registerWarning("Both '#{col_name}' schedule file and weekday fractions provided; the latter will be ignored.") if !fuel_load.weekday_fractions.nil?
88-
runner.registerWarning("Both '#{col_name}' schedule file and weekend fractions provided; the latter will be ignored.") if !fuel_load.weekend_fractions.nil?
89-
runner.registerWarning("Both '#{col_name}' schedule file and monthly multipliers provided; the latter will be ignored.") if !fuel_load.monthly_multipliers.nil?
90-
end
9166
end
9267

9368
return if therm <= 0
9469

70+
# Create schedule
71+
sch = nil
72+
if fuel_load.fuel_load_type == HPXML::FuelLoadTypeGrill
73+
col_name = SchedulesFile::ColumnFuelLoadsGrill
74+
elsif fuel_load.fuel_load_type == HPXML::FuelLoadTypeLighting
75+
col_name = SchedulesFile::ColumnFuelLoadsLighting
76+
elsif fuel_load.fuel_load_type == HPXML::FuelLoadTypeFireplace
77+
col_name = SchedulesFile::ColumnFuelLoadsFireplace
78+
end
79+
if not schedules_file.nil?
80+
space_design_level = schedules_file.calc_design_level_from_annual_therm(col_name: col_name, annual_therm: therm)
81+
sch = schedules_file.create_schedule_file(model, col_name: col_name)
82+
end
83+
if sch.nil?
84+
col_unavailable_periods = Schedule.get_unavailable_periods(runner, col_name, unavailable_periods)
85+
sch = MonthWeekdayWeekendSchedule.new(model, obj_name + ' schedule', fuel_load.weekday_fractions, fuel_load.weekend_fractions, fuel_load.monthly_multipliers, Constants.ScheduleTypeLimitsFraction, unavailable_periods: col_unavailable_periods)
86+
space_design_level = sch.calc_design_level_from_daily_therm(therm / 365.0)
87+
sch = sch.schedule
88+
else
89+
runner.registerWarning("Both '#{col_name}' schedule file and weekday fractions provided; the latter will be ignored.") if !fuel_load.weekday_fractions.nil?
90+
runner.registerWarning("Both '#{col_name}' schedule file and weekend fractions provided; the latter will be ignored.") if !fuel_load.weekend_fractions.nil?
91+
runner.registerWarning("Both '#{col_name}' schedule file and monthly multipliers provided; the latter will be ignored.") if !fuel_load.monthly_multipliers.nil?
92+
end
93+
9594
sens_frac = fuel_load.frac_sensible
9695
lat_frac = fuel_load.frac_latent
9796

@@ -115,28 +114,29 @@ def self.apply_pool_or_permanent_spa_heater(runner, model, pool_or_spa, obj_name
115114

116115
heater_kwh = 0
117116
heater_therm = 0
118-
119-
# Create schedule
120-
heater_sch = nil
121-
col_name = (obj_name.include?('pool') ? 'pool_heater' : 'permanent_spa_heater')
122-
if not schedules_file.nil?
123-
heater_sch = schedules_file.create_schedule_file(model, col_name: col_name)
124-
end
125-
if heater_sch.nil?
126-
col_unavailable_periods = Schedule.get_unavailable_periods(runner, col_name, unavailable_periods)
127-
heater_sch = MonthWeekdayWeekendSchedule.new(model, obj_name + ' schedule', pool_or_spa.heater_weekday_fractions, pool_or_spa.heater_weekend_fractions, pool_or_spa.heater_monthly_multipliers, Constants.ScheduleTypeLimitsFraction, unavailable_periods: col_unavailable_periods)
128-
else
129-
runner.registerWarning("Both '#{col_name}' schedule file and weekday fractions provided; the latter will be ignored.") if !pool_or_spa.heater_weekday_fractions.nil?
130-
runner.registerWarning("Both '#{col_name}' schedule file and weekend fractions provided; the latter will be ignored.") if !pool_or_spa.heater_weekend_fractions.nil?
131-
runner.registerWarning("Both '#{col_name}' schedule file and monthly multipliers provided; the latter will be ignored.") if !pool_or_spa.heater_monthly_multipliers.nil?
132-
end
133-
134117
if pool_or_spa.heater_load_units == HPXML::UnitsKwhPerYear
135118
heater_kwh = pool_or_spa.heater_load_value * pool_or_spa.heater_usage_multiplier
136119
elsif pool_or_spa.heater_load_units == HPXML::UnitsThermPerYear
137120
heater_therm = pool_or_spa.heater_load_value * pool_or_spa.heater_usage_multiplier
138121
end
139122

123+
if heater_kwh > 0 || heater_therm > 0
124+
# Create schedule
125+
heater_sch = nil
126+
col_name = (obj_name.include?('pool') ? 'pool_heater' : 'permanent_spa_heater')
127+
if not schedules_file.nil?
128+
heater_sch = schedules_file.create_schedule_file(model, col_name: col_name)
129+
end
130+
if heater_sch.nil?
131+
col_unavailable_periods = Schedule.get_unavailable_periods(runner, col_name, unavailable_periods)
132+
heater_sch = MonthWeekdayWeekendSchedule.new(model, obj_name + ' schedule', pool_or_spa.heater_weekday_fractions, pool_or_spa.heater_weekend_fractions, pool_or_spa.heater_monthly_multipliers, Constants.ScheduleTypeLimitsFraction, unavailable_periods: col_unavailable_periods)
133+
else
134+
runner.registerWarning("Both '#{col_name}' schedule file and weekday fractions provided; the latter will be ignored.") if !pool_or_spa.heater_weekday_fractions.nil?
135+
runner.registerWarning("Both '#{col_name}' schedule file and weekend fractions provided; the latter will be ignored.") if !pool_or_spa.heater_weekend_fractions.nil?
136+
runner.registerWarning("Both '#{col_name}' schedule file and monthly multipliers provided; the latter will be ignored.") if !pool_or_spa.heater_monthly_multipliers.nil?
137+
end
138+
end
139+
140140
if heater_kwh > 0
141141
if not schedules_file.nil?
142142
space_design_level = schedules_file.calc_design_level_from_annual_kwh(col_name: col_name, annual_kwh: heater_kwh)
@@ -185,6 +185,11 @@ def self.apply_pool_or_permanent_spa_heater(runner, model, pool_or_spa, obj_name
185185

186186
def self.apply_pool_or_permanent_spa_pump(runner, model, pool_or_spa, obj_name, conditioned_space, schedules_file, unavailable_periods)
187187
pump_kwh = 0
188+
if not pool_or_spa.pump_kwh_per_year.nil?
189+
pump_kwh = pool_or_spa.pump_kwh_per_year * pool_or_spa.pump_usage_multiplier
190+
end
191+
192+
return if pump_kwh <= 0
188193

189194
# Create schedule
190195
pump_sch = nil
@@ -201,31 +206,25 @@ def self.apply_pool_or_permanent_spa_pump(runner, model, pool_or_spa, obj_name,
201206
runner.registerWarning("Both '#{col_name}' schedule file and monthly multipliers provided; the latter will be ignored.") if !pool_or_spa.pump_monthly_multipliers.nil?
202207
end
203208

204-
if not pool_or_spa.pump_kwh_per_year.nil?
205-
pump_kwh = pool_or_spa.pump_kwh_per_year * pool_or_spa.pump_usage_multiplier
209+
if not schedules_file.nil?
210+
space_design_level = schedules_file.calc_design_level_from_annual_kwh(col_name: col_name, annual_kwh: pump_kwh)
206211
end
207-
208-
if pump_kwh > 0
209-
if not schedules_file.nil?
210-
space_design_level = schedules_file.calc_design_level_from_annual_kwh(col_name: col_name, annual_kwh: pump_kwh)
211-
end
212-
if space_design_level.nil?
213-
space_design_level = pump_sch.calc_design_level_from_daily_kwh(pump_kwh / 365.0)
214-
pump_sch = pump_sch.schedule
215-
end
216-
217-
mel_def = OpenStudio::Model::ElectricEquipmentDefinition.new(model)
218-
mel = OpenStudio::Model::ElectricEquipment.new(mel_def)
219-
mel.setName(obj_name)
220-
mel.setEndUseSubcategory(obj_name)
221-
mel.setSpace(conditioned_space) # no heat gain, so assign the equipment to an arbitrary space
222-
mel_def.setName(obj_name)
223-
mel_def.setDesignLevel(space_design_level)
224-
mel_def.setFractionRadiant(0)
225-
mel_def.setFractionLatent(0)
226-
mel_def.setFractionLost(1)
227-
mel.setSchedule(pump_sch)
212+
if space_design_level.nil?
213+
space_design_level = pump_sch.calc_design_level_from_daily_kwh(pump_kwh / 365.0)
214+
pump_sch = pump_sch.schedule
228215
end
216+
217+
mel_def = OpenStudio::Model::ElectricEquipmentDefinition.new(model)
218+
mel = OpenStudio::Model::ElectricEquipment.new(mel_def)
219+
mel.setName(obj_name)
220+
mel.setEndUseSubcategory(obj_name)
221+
mel.setSpace(conditioned_space) # no heat gain, so assign the equipment to an arbitrary space
222+
mel_def.setName(obj_name)
223+
mel_def.setDesignLevel(space_design_level)
224+
mel_def.setFractionRadiant(0)
225+
mel_def.setFractionLatent(0)
226+
mel_def.setFractionLost(1)
227+
mel.setSchedule(pump_sch)
229228
end
230229

231230
private

HPXMLtoOpenStudio/resources/waterheater.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1363,7 +1363,9 @@ def self.add_ec_adj(model, heater, ec_adj, loc_space, water_heating_system, unit
13631363
end
13641364

13651365
# Add an other equipment object for water heating that will get actuated, has a small initial load but gets overwritten by EMS
1366-
ec_adj_object = HotWaterAndAppliances.add_other_equipment(model, Constants.ObjectNameWaterHeaterAdjustment, loc_space, 0.01, 0, 0, model.alwaysOnDiscreteSchedule, fuel_type)
1366+
cnt = model.getOtherEquipments.select { |oe| oe.endUseSubcategory.start_with? Constants.ObjectNameWaterHeaterAdjustment }.size # Ensure unique meter for each water heater
1367+
ec_adj_object = HotWaterAndAppliances.add_other_equipment(model, "#{Constants.ObjectNameWaterHeaterAdjustment}#{cnt}", loc_space, 0.01, 0, 0, model.alwaysOnDiscreteSchedule, fuel_type)
1368+
ec_adj_object.additionalProperties.setFeature('HPXML_ID', water_heating_system.id) # Used by reporting measure
13671369

13681370
# EMS for calculating the EC_adj
13691371

0 commit comments

Comments
 (0)