diff --git a/HPXMLtoOpenStudio/measure.xml b/HPXMLtoOpenStudio/measure.xml
index 6136e50ea4..acf153b252 100644
--- a/HPXMLtoOpenStudio/measure.xml
+++ b/HPXMLtoOpenStudio/measure.xml
@@ -3,8 +3,8 @@
3.1
hpxm_lto_openstudio
b1543b30-9465-45ff-ba04-1d1f85e763bc
- b20ae61b-bf29-4be9-8e25-a44b3b12c232
- 2024-11-16T00:20:48Z
+ 531c1027-0d75-4343-a8ce-6717ad2b9924
+ 2024-11-16T04:46:12Z
D8922A73
HPXMLtoOpenStudio
HPXML to OpenStudio Translator
@@ -393,7 +393,7 @@
hvac_sizing.rb
rb
resource
- FEB17D7B
+ C6F9CE12
internal_gains.rb
@@ -423,7 +423,7 @@
math.rb
rb
resource
- FEB72476
+ CE6D107B
meta_measure.rb
@@ -693,7 +693,7 @@
test_hvac_sizing.rb
rb
test
- 561E6631
+ E1BC3865
test_lighting.rb
diff --git a/HPXMLtoOpenStudio/resources/hvac_sizing.rb b/HPXMLtoOpenStudio/resources/hvac_sizing.rb
index 152ae72d86..408e380b02 100644
--- a/HPXMLtoOpenStudio/resources/hvac_sizing.rb
+++ b/HPXMLtoOpenStudio/resources/hvac_sizing.rb
@@ -4795,15 +4795,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.
@@ -4832,22 +4853,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
diff --git a/HPXMLtoOpenStudio/resources/math.rb b/HPXMLtoOpenStudio/resources/math.rb
index f351ead325..e6d61b5abe 100644
--- a/HPXMLtoOpenStudio/resources/math.rb
+++ b/HPXMLtoOpenStudio/resources/math.rb
@@ -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
@@ -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
@@ -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
#
@@ -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.
#
diff --git a/HPXMLtoOpenStudio/tests/test_hvac_sizing.rb b/HPXMLtoOpenStudio/tests/test_hvac_sizing.rb
index 1fb1b7731f..b04bbcb7f1 100644
--- a/HPXMLtoOpenStudio/tests/test_hvac_sizing.rb
+++ b/HPXMLtoOpenStudio/tests/test_hvac_sizing.rb
@@ -1678,6 +1678,54 @@ def test_manual_j_basement_wall_below_grade_ufactor
end
end
+ def test_foundation_wall_non_integer_values
+ tol = 0.01 # 1%
+
+ # Test wall insulation covering most of above and below-grade portions of wall
+ fwall = HPXML::FoundationWall.new(nil)
+ fwall.height = 5.0
+ fwall.depth_below_grade = 1.5
+ fwall.type = HPXML::FoundationWallTypeSolidConcrete
+ fwall.thickness = 4.0 # in
+ fwall.insulation_interior_r_value = 10.0
+ fwall.insulation_exterior_r_value = 0.0
+ fwall.insulation_interior_distance_to_top = 0.3
+ fwall.insulation_exterior_distance_to_top = 0.0
+ fwall.insulation_interior_distance_to_bottom = 4.9
+ fwall.insulation_exterior_distance_to_bottom = 0.0
+ rvalue = 1.0 / HVACSizing.get_foundation_wall_below_grade_ufactor(fwall, false, nil)
+ assert_in_epsilon(10.25, rvalue, tol)
+ rvalue = 1.0 / HVACSizing.get_foundation_wall_above_grade_ufactor(fwall, true)
+ assert_in_epsilon(9.6, rvalue, tol)
+
+ # Same as above but test exterior wall insulation
+ fwall.insulation_interior_r_value = 0.0
+ fwall.insulation_exterior_r_value = 10.0
+ fwall.insulation_interior_distance_to_top = 0.0
+ fwall.insulation_exterior_distance_to_top = 0.3
+ fwall.insulation_interior_distance_to_bottom = 0.0
+ fwall.insulation_exterior_distance_to_bottom = 4.9
+ rvalue = 1.0 / HVACSizing.get_foundation_wall_below_grade_ufactor(fwall, false, nil)
+ assert_in_epsilon(10.25, rvalue, tol)
+ rvalue = 1.0 / HVACSizing.get_foundation_wall_above_grade_ufactor(fwall, true)
+ assert_in_epsilon(9.6, rvalue, tol)
+
+ # Test small coverage of below-grade portion of wall, no coverage of above-grade
+ fwall.insulation_exterior_distance_to_top = 4.4
+ rvalue = 1.0 / HVACSizing.get_foundation_wall_below_grade_ufactor(fwall, false, nil)
+ assert_in_epsilon(2.7, rvalue, tol)
+ rvalue = 1.0 / HVACSizing.get_foundation_wall_above_grade_ufactor(fwall, true)
+ assert_in_epsilon(1.2, rvalue, tol)
+
+ # Test small coverage of above-grade portion of wall, no coverage of below-grade
+ fwall.insulation_exterior_distance_to_top = 2.3
+ fwall.insulation_exterior_distance_to_bottom = 3.5
+ rvalue = 1.0 / HVACSizing.get_foundation_wall_below_grade_ufactor(fwall, false, nil)
+ assert_in_epsilon(1.0, rvalue, tol)
+ rvalue = 1.0 / HVACSizing.get_foundation_wall_above_grade_ufactor(fwall, true)
+ assert_in_epsilon(2.1, rvalue, tol)
+ end
+
def test_multiple_zones
# Run base-zones-spaces-multiple.xml
args_hash = {}