Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/NREL/OpenStudio-HPXML int…
Browse files Browse the repository at this point in the history
…o whole_building_common_spaces
  • Loading branch information
yzhou601 committed Nov 19, 2024
2 parents 0e2fe3d + a2d97ef commit cf686cc
Show file tree
Hide file tree
Showing 26 changed files with 214 additions and 118 deletions.
7 changes: 7 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## OpenStudio-HPXML v1.10.0

__New Features__

__Bugfixes__

## OpenStudio-HPXML v1.9.0

__New Features__
Expand Down Expand Up @@ -57,6 +63,7 @@ __Bugfixes__
- Fixes default CFIS fan power during ventilation only mode.
- Fixes a bug that potentially oversizes heat pumps when detailed performance capacity fractions are provided.
- For a CFIS system with a supplemental fan, fixes supplemental fan runtime when using sub-hourly timesteps.
- Fixes GSHP rated fan/pump powers in net to gross calculations and improves default modeled pump power (W/ton).

## OpenStudio-HPXML v1.8.1

Expand Down
20 changes: 10 additions & 10 deletions HPXMLtoOpenStudio/measure.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<schema_version>3.1</schema_version>
<name>hpxm_lto_openstudio</name>
<uid>b1543b30-9465-45ff-ba04-1d1f85e763bc</uid>
<version_id>7b63d546-cd90-4b05-b424-6d6a9edc84f3</version_id>
<version_modified>2024-11-19T01:11:11Z</version_modified>
<version_id>2bb7d5cd-06e3-406b-9eb0-96dfe7e2c6d2</version_id>
<version_modified>2024-11-19T01:12:59Z</version_modified>
<xml_checksum>D8922A73</xml_checksum>
<class_name>HPXMLtoOpenStudio</class_name>
<display_name>HPXML to OpenStudio Translator</display_name>
Expand Down Expand Up @@ -327,7 +327,7 @@
<filename>defaults.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>3FDD009D</checksum>
<checksum>515B05C5</checksum>
</file>
<file>
<filename>energyplus.rb</filename>
Expand Down Expand Up @@ -387,13 +387,13 @@
<filename>hvac.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>C389F8A8</checksum>
<checksum>0DF759D2</checksum>
</file>
<file>
<filename>hvac_sizing.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>FAB29D98</checksum>
<checksum>44304F84</checksum>
</file>
<file>
<filename>internal_gains.rb</filename>
Expand Down Expand Up @@ -423,7 +423,7 @@
<filename>math.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>FEB72476</checksum>
<checksum>CE6D107B</checksum>
</file>
<file>
<filename>meta_measure.rb</filename>
Expand Down Expand Up @@ -621,7 +621,7 @@
<filename>version.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>CB4D15AB</checksum>
<checksum>FB92922A</checksum>
</file>
<file>
<filename>waterheater.rb</filename>
Expand Down Expand Up @@ -663,7 +663,7 @@
<filename>test_defaults.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>1531AC7C</checksum>
<checksum>1004443C</checksum>
</file>
<file>
<filename>test_enclosure.rb</filename>
Expand All @@ -687,13 +687,13 @@
<filename>test_hvac.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>F7B1BA82</checksum>
<checksum>994A2553</checksum>
</file>
<file>
<filename>test_hvac_sizing.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>2F80916F</checksum>
<checksum>E1BC3865</checksum>
</file>
<file>
<filename>test_lighting.rb</filename>
Expand Down
5 changes: 2 additions & 3 deletions HPXMLtoOpenStudio/resources/defaults.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5409,12 +5409,11 @@ def self.get_duct_outside_fraction(ncfl_ag)
return f_out
end

# Gets the default pump power for a ground-source heat pump.
# Gets the default pump power for a closed loop ground-source heat pump.
#
# @return [Double] Pump power (W/ton)
def self.get_gshp_pump_power()
# ANSI/RESNET/ICC 301-2019 Section 4.4.5 (closed loop)
return 30.0
return 80.0 # Rough estimate based on a literature review of different studies/websites
end

# Gets the default Electric Auxiliary Energy (EAE) for a boiler.
Expand Down
13 changes: 8 additions & 5 deletions HPXMLtoOpenStudio/resources/hvac.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2021,11 +2021,14 @@ def self.set_curves_gshp(heat_pump)
hp_ap.heat_power_curve_spec = [[-8.4754723813072, 8.10952801956388, 1.38771494628738, -0.33766445915032, 0.0223085217874051]]

# Fan/pump adjustments calculations
power_f = heat_pump.fan_watts_per_cfm * 400.0 / UnitConversions.convert(1.0, 'ton', 'Btu/hr') * UnitConversions.convert(1.0, 'W', 'kW') # 400 cfm/ton, result is in kW per Btu/hr of capacity
power_p = heat_pump.pump_watts_per_ton / UnitConversions.convert(1.0, 'ton', 'Btu/hr') * UnitConversions.convert(1.0, 'W', 'kW') # result is in kW per Btu/hr of capacity

cool_eir = (1 - UnitConversions.convert(power_f, 'Wh', 'Btu')) / UnitConversions.convert(heat_pump.cooling_efficiency_eer, 'Btu', 'Wh') - power_f - power_p
heat_eir = (1 + UnitConversions.convert(power_f, 'Wh', 'Btu')) / heat_pump.heating_efficiency_cop - power_f - power_p
# Fan power to overcome the static pressure adjustment
rated_fan_watts_per_cfm = 0.5 * heat_pump.fan_watts_per_cfm # Calculate rated fan power by assuming the power to overcome the ductwork is approximately 50% of the total fan power (ANSI/RESNET/ICC 301 says 0.2 W/cfm is the fan power associated with ductwork, but we don't know if that was a PSC or BPM fan)
power_f = rated_fan_watts_per_cfm * 400.0 / UnitConversions.convert(1.0, 'ton', 'Btu/hr') # 400 cfm/ton, result is in W per Btu/hr of capacity
rated_pump_watts_per_ton = 30.0 # ANSI/RESNET/ICC 301, estimated pump power required to overcome the internal resistance of the ground-water heat exchanger under AHRI test conditions for a closed loop system
power_p = rated_pump_watts_per_ton / UnitConversions.convert(1.0, 'ton', 'Btu/hr') # result is in W per Btu/hr of capacity

cool_eir = UnitConversions.convert(((1 - UnitConversions.convert(power_f, 'Wh', 'Btu')) / heat_pump.cooling_efficiency_eer - power_f - power_p), 'Wh', 'Btu')
heat_eir = (1 + UnitConversions.convert(power_f, 'Wh', 'Btu')) / heat_pump.heating_efficiency_cop - UnitConversions.convert(power_f + power_p, 'Wh', 'Btu')

hp_ap.cool_rated_cops = [1.0 / cool_eir]
hp_ap.heat_rated_cops = [1.0 / heat_eir]
Expand Down
66 changes: 46 additions & 20 deletions HPXMLtoOpenStudio/resources/hvac_sizing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4806,15 +4806,36 @@ def self.get_foundation_wall_above_grade_ufactor(foundation_wall, include_insula

assembly_r = Material.FoundationWallMaterial(foundation_wall.type, foundation_wall.thickness).rvalue
assembly_r += Material.AirFilmVertical.rvalue + Material.AirFilmOutside.rvalue
if include_insulation_layers
if foundation_wall.insulation_interior_distance_to_top == 0 && foundation_wall.insulation_interior_distance_to_bottom > 0
assembly_r += foundation_wall.insulation_interior_r_value
end
if foundation_wall.insulation_exterior_distance_to_top == 0 && foundation_wall.insulation_exterior_distance_to_bottom > 0
assembly_r += foundation_wall.insulation_exterior_r_value
end
if not include_insulation_layers
return 1.0 / assembly_r
end

ag_depth = foundation_wall.height - foundation_wall.depth_below_grade
wall_ins_dist_bottom_to_grade_int = ag_depth - foundation_wall.insulation_interior_distance_to_bottom
wall_ins_dist_top_to_grade_int = ag_depth - foundation_wall.insulation_interior_distance_to_top
wall_ins_dist_bottom_to_grade_ext = ag_depth - foundation_wall.insulation_exterior_distance_to_bottom
wall_ins_dist_top_to_grade_ext = ag_depth - foundation_wall.insulation_exterior_distance_to_top
# Perform calculation for each 1ft bin of above grade depth
sum_u_wall = 0.0
for distance_to_grade in 1..ag_depth.ceil
r_wall = assembly_r

bin_dist_top_to_grade = [distance_to_grade, ag_depth].min
bin_dist_bottom_to_grade = distance_to_grade - 1
bin_size = bin_dist_top_to_grade - bin_dist_bottom_to_grade # Last bin may be less than 1 ft

# Add interior insulation R-value at this depth?
bin_frac_insulated_int = MathTools.overlap(bin_dist_bottom_to_grade, bin_dist_top_to_grade, wall_ins_dist_bottom_to_grade_int, wall_ins_dist_top_to_grade_int) / bin_size
r_wall += foundation_wall.insulation_interior_r_value * bin_frac_insulated_int # Interior insulation at this depth, add R-value

# Add exterior insulation R-value at this depth?
bin_frac_insulated_ext = MathTools.overlap(bin_dist_bottom_to_grade, bin_dist_top_to_grade, wall_ins_dist_bottom_to_grade_ext, wall_ins_dist_top_to_grade_ext) / bin_size
r_wall += foundation_wall.insulation_exterior_r_value * bin_frac_insulated_ext # Exterior insulation at this depth, add R-value

sum_u_wall += (1.0 / r_wall) * bin_size
end
return 1.0 / assembly_r
u_wall = sum_u_wall / ag_depth
return u_wall
end

# Calculates the foundation wall below grade effective U-factor according to Manual J Section A12-4.
Expand Down Expand Up @@ -4843,22 +4864,27 @@ def self.get_foundation_wall_below_grade_ufactor(foundation_wall, include_soil,

# Perform calculation for each 1ft bin of below grade depth
sum_u_wall = 0.0
wall_depth_above_grade = foundation_wall.depth_below_grade.ceil
for distance_to_grade in 1..wall_depth_above_grade
for distance_to_grade in 1..foundation_wall.depth_below_grade.ceil
# Calculate R-wall at this depth
r_wall = wall_constr_rvalue - Material.AirFilmOutside.rvalue
bin_distance_to_grade = distance_to_grade - 0.5 # Use e.g. 2.5 ft for the 2ft-3ft bin
r_soil = (Math::PI * bin_distance_to_grade / 2.0) / ground_conductivity
if (distance_to_grade > wall_ins_dist_top_to_grade_int) && (distance_to_grade <= wall_ins_dist_bottom_to_grade_int)
r_wall += wall_ins_rvalue_int # Interior insulation at this depth, add R-value
end
if (distance_to_grade > wall_ins_dist_top_to_grade_ext) && (distance_to_grade <= wall_ins_dist_bottom_to_grade_ext)
r_wall += wall_ins_rvalue_ext # Exterior insulation at this depth, add R-value
end
bin_dist_top_to_grade = distance_to_grade - 1
bin_dist_bottom_to_grade = [distance_to_grade, foundation_wall.depth_below_grade].min
bin_size = bin_dist_bottom_to_grade - bin_dist_top_to_grade # Last bin may be less than 1 ft
bin_avg_dist_to_grade = (bin_dist_top_to_grade + bin_dist_bottom_to_grade) / 2.0

# Add interior insulation R-value at this depth?
bin_frac_insulated_int = MathTools.overlap(bin_dist_top_to_grade, bin_dist_bottom_to_grade, wall_ins_dist_top_to_grade_int, wall_ins_dist_bottom_to_grade_int) / bin_size
r_wall += wall_ins_rvalue_int * bin_frac_insulated_int

# Add exterior insulation R-value at this depth?
bin_frac_insulated_ext = MathTools.overlap(bin_dist_top_to_grade, bin_dist_bottom_to_grade, wall_ins_dist_top_to_grade_ext, wall_ins_dist_bottom_to_grade_ext) / bin_size
r_wall += wall_ins_rvalue_ext * bin_frac_insulated_ext # Exterior insulation at this depth, add R-value

if include_soil
sum_u_wall += 1.0 / (r_soil + r_wall)
r_soil = (Math::PI * bin_avg_dist_to_grade / 2.0) / ground_conductivity
sum_u_wall += (1.0 / (r_soil + r_wall)) * bin_size
else
sum_u_wall += 1.0 / r_wall
sum_u_wall += (1.0 / r_wall) * bin_size
end
end
u_wall = sum_u_wall / foundation_wall.depth_below_grade
Expand Down
19 changes: 15 additions & 4 deletions HPXMLtoOpenStudio/resources/math.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def self.interp4(x, y, x1, x2, y1, y2, fx1y1, fx1y2, fx2y1, fx2y2)
+ (fx2y2 / ((x2 - x1) * (y2 - y1))) * (x - x1) * (y - y1)
end

# Calculate the result of a biquadratic polynomial with independent variables.
# Calculates the result of a biquadratic polynomial with independent variables.
# x and y, and a list of coefficients, c:
#
# z = c[1] + c[2]*x + c[3]*x**2 + c[4]*y + c[5]*y**2 + c[6]*x*y
Expand All @@ -52,7 +52,7 @@ def self.biquadratic(x, y, c)
return z
end

# Calculate the result of a quadratic polynomial with independent variable.
# Calculates the result of a quadratic polynomial with independent variable.
# x and a list of coefficients, c:
#
# y = c[1] + c[2]*x + c[3]*x**2
Expand All @@ -70,9 +70,9 @@ def self.quadratic(x, c)
return y
end

# Calculate the result of a bicubic polynomial with independent variables.
# Calculates the result of a bicubic polynomial with independent variables.
# x and y, and a list of coefficients, c:

#
# z = c[1] + c[2]*x + c[3]*y + c[4]*x**2 + c[5]*x*y + c[6]*y**2 + \
# c[7]*x**3 + c[8]*y*x**2 + c[9]*x*y**2 + c[10]*y**3
#
Expand All @@ -91,6 +91,17 @@ def self.bicubic(x, y, c)
return z
end

# Calculates the overlap distance of two 1D line segments.
#
# @param min1 [Double] min value of line 1
# @param max1 [Double] max value of line 1
# @param min2 [Double] min value of line 2
# @param max2 [Double] max value of line 2
# @return [Double] overlap distance
def self.overlap(min1, max1, min2, max2)
return [0.0, [max1, max2].min - [min1, min2].max].max
end

# Determine if a guess is within tolerance for convergence.
# If not, output a new guess using the Newton-Raphson method.
#
Expand Down
2 changes: 1 addition & 1 deletion HPXMLtoOpenStudio/resources/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Collection of methods related to software versions.
module Version
OS_HPXML_Version = '1.9.0' # Version of the OS-HPXML workflow
OS_HPXML_Version = '1.10.0' # Version of the OS-HPXML workflow
OS_Version = '3.9.0' # Required version of OpenStudio (can be 'X.X' or 'X.X.X')
HPXML_Version = '4.0' # HPXML schemaVersion

Expand Down
2 changes: 1 addition & 1 deletion HPXMLtoOpenStudio/tests/test_defaults.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2306,7 +2306,7 @@ def test_ground_source_heat_pumps
hpxml_bldg.heat_pumps[0].backup_heating_capacity = nil
XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path)
_default_hpxml, default_hpxml_bldg = _test_measure()
_test_default_ground_to_air_heat_pump_values(default_hpxml_bldg.heat_pumps[0], 30.0, 0.375, nil, nil, 0, nil, nil, nil)
_test_default_ground_to_air_heat_pump_values(default_hpxml_bldg.heat_pumps[0], 80.0, 0.375, nil, nil, 0, nil, nil, nil)
end

def test_geothermal_loops
Expand Down
13 changes: 7 additions & 6 deletions HPXMLtoOpenStudio/tests/test_hvac.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def setup

def teardown
File.delete(@tmp_hpxml_path) if File.exist? @tmp_hpxml_path
File.delete(File.join(File.dirname(__FILE__), 'in.schedules.csv')) if File.exist? File.join(File.dirname(__FILE__), 'in.schedules.csv')
File.delete(File.join(File.dirname(__FILE__), 'results_annual.csv')) if File.exist? File.join(File.dirname(__FILE__), 'results_annual.csv')
File.delete(File.join(File.dirname(__FILE__), 'results_design_load_details.csv')) if File.exist? File.join(File.dirname(__FILE__), 'results_design_load_details.csv')
end
Expand Down Expand Up @@ -1051,13 +1052,13 @@ def test_ground_to_air_heat_pump
# Check cooling coil
assert_equal(1, model.getCoilCoolingWaterToAirHeatPumpEquationFits.size)
clg_coil = model.getCoilCoolingWaterToAirHeatPumpEquationFits[0]
assert_in_epsilon(4.87, clg_coil.ratedCoolingCoefficientofPerformance, 0.01)
assert_in_epsilon(5.84, clg_coil.ratedCoolingCoefficientofPerformance, 0.01)
assert_in_epsilon(clg_capacity, clg_coil.ratedTotalCoolingCapacity.get, 0.01)

# Check heating coil
assert_equal(1, model.getCoilHeatingWaterToAirHeatPumpEquationFits.size)
htg_coil = model.getCoilHeatingWaterToAirHeatPumpEquationFits[0]
assert_in_epsilon(3.6, htg_coil.ratedHeatingCoefficientofPerformance, 0.01)
assert_in_epsilon(3.94, htg_coil.ratedHeatingCoefficientofPerformance, 0.01)
assert_in_epsilon(htg_capacity, htg_coil.ratedHeatingCapacity.get, 0.01)

# Check EMS
Expand Down Expand Up @@ -1098,13 +1099,13 @@ def test_ground_to_air_heat_pump_integrated_backup
# Check cooling coil
assert_equal(1, model.getCoilCoolingWaterToAirHeatPumpEquationFits.size)
clg_coil = model.getCoilCoolingWaterToAirHeatPumpEquationFits[0]
assert_in_epsilon(4.87, clg_coil.ratedCoolingCoefficientofPerformance, 0.01)
assert_in_epsilon(5.84, clg_coil.ratedCoolingCoefficientofPerformance, 0.01)
assert_in_epsilon(clg_capacity, clg_coil.ratedTotalCoolingCapacity.get, 0.01)

# Check heating coil
assert_equal(1, model.getCoilHeatingWaterToAirHeatPumpEquationFits.size)
htg_coil = model.getCoilHeatingWaterToAirHeatPumpEquationFits[0]
assert_in_epsilon(3.6, htg_coil.ratedHeatingCoefficientofPerformance, 0.01)
assert_in_epsilon(3.94, htg_coil.ratedHeatingCoefficientofPerformance, 0.01)
assert_in_epsilon(htg_capacity, htg_coil.ratedHeatingCapacity.get, 0.01)

# Check supp heating coil
Expand Down Expand Up @@ -1316,13 +1317,13 @@ def test_shared_ground_loop_ground_to_air_heat_pump
# Check cooling coil
assert_equal(1, model.getCoilCoolingWaterToAirHeatPumpEquationFits.size)
clg_coil = model.getCoilCoolingWaterToAirHeatPumpEquationFits[0]
assert_in_epsilon(4.87, clg_coil.ratedCoolingCoefficientofPerformance, 0.01)
assert_in_epsilon(5.84, clg_coil.ratedCoolingCoefficientofPerformance, 0.01)
assert_in_epsilon(clg_capacity, clg_coil.ratedTotalCoolingCapacity.get, 0.01)

# Check heating coil
assert_equal(1, model.getCoilHeatingWaterToAirHeatPumpEquationFits.size)
htg_coil = model.getCoilHeatingWaterToAirHeatPumpEquationFits[0]
assert_in_epsilon(3.6, htg_coil.ratedHeatingCoefficientofPerformance, 0.01)
assert_in_epsilon(3.94, htg_coil.ratedHeatingCoefficientofPerformance, 0.01)
assert_in_epsilon(htg_capacity, htg_coil.ratedHeatingCapacity.get, 0.01)
end

Expand Down
Loading

0 comments on commit cf686cc

Please sign in to comment.