Skip to content

Commit

Permalink
Merge pull request #1705 from NREL/zone_design_loads
Browse files Browse the repository at this point in the history
Zone design loads
  • Loading branch information
shorowit committed May 15, 2024
2 parents 08a26bf + 1206d19 commit 32f5187
Show file tree
Hide file tree
Showing 34 changed files with 2,069 additions and 1,381 deletions.
106 changes: 50 additions & 56 deletions BuildResidentialHPXML/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4954,7 +4954,7 @@ def self.set_windows(hpxml_bldg, model, args, sorted_subsurfaces)
exterior_shading_factor_winter: args[:window_exterior_shading_winter],
exterior_shading_factor_summer: args[:window_exterior_shading_summer],
fraction_operable: args[:window_fraction_operable],
wall_idref: wall_idref)
attached_to_wall_idref: wall_idref)
end
end

Expand All @@ -4970,13 +4970,21 @@ def self.set_skylights(hpxml_bldg, args, sorted_subsurfaces)
roof_idref = @surface_ids[surface.name.to_s]
next if roof_idref.nil?

roof = hpxml_bldg.roofs.find { |roof| roof.id == roof_idref }
if roof.interior_adjacent_to != HPXML::LocationConditionedSpace
# This is the roof of an attic, so the skylight must have a shaft; attach it to the attic floor as well.
floor = hpxml_bldg.floors.find { |floor| floor.interior_adjacent_to == HPXML::LocationConditionedSpace && floor.exterior_adjacent_to == roof.interior_adjacent_to }
floor_idref = floor.id
end

hpxml_bldg.skylights.add(id: "Skylight#{hpxml_bldg.skylights.size + 1}",
area: UnitConversions.convert(sub_surface.grossArea, 'm^2', 'ft^2'),
azimuth: azimuth,
ufactor: args[:skylight_ufactor],
shgc: args[:skylight_shgc],
storm_type: args[:skylight_storm_type],
roof_idref: roof_idref)
attached_to_roof_idref: roof_idref,
attached_to_floor_idref: floor_idref)
end
end

Expand All @@ -4997,7 +5005,7 @@ def self.set_doors(hpxml_bldg, model, args, sorted_subsurfaces)
next if wall_idref.nil?

hpxml_bldg.doors.add(id: "Door#{hpxml_bldg.doors.size + 1}",
wall_idref: wall_idref,
attached_to_wall_idref: wall_idref,
area: UnitConversions.convert(sub_surface.grossArea, 'm^2', 'ft^2'),
azimuth: args[:geometry_unit_orientation],
r_value: args[:door_rvalue])
Expand Down Expand Up @@ -6554,72 +6562,58 @@ def self.collapse_surfaces(hpxml_bldg, args)
end

# After surfaces are collapsed, round all areas
(hpxml_bldg.roofs +
hpxml_bldg.rim_joists +
hpxml_bldg.walls +
hpxml_bldg.foundation_walls +
hpxml_bldg.floors +
hpxml_bldg.slabs +
hpxml_bldg.windows +
hpxml_bldg.skylights +
hpxml_bldg.doors).each do |s|
(hpxml_bldg.surfaces + hpxml_bldg.subsurfaces).each do |s|
s.area = s.area.round(1)
end
end

def self.renumber_hpxml_ids(hpxml_bldg)
# Renumber surfaces
{ hpxml_bldg.walls => 'Wall',
hpxml_bldg.foundation_walls => 'FoundationWall',
hpxml_bldg.rim_joists => 'RimJoist',
hpxml_bldg.floors => 'Floor',
hpxml_bldg.roofs => 'Roof',
hpxml_bldg.slabs => 'Slab',
hpxml_bldg.windows => 'Window',
hpxml_bldg.doors => 'Door',
hpxml_bldg.skylights => 'Skylight' }.each do |surfs, surf_name|
surfs.each_with_index do |surf, i|
(hpxml_bldg.attics + hpxml_bldg.foundations).each do |attic_or_fnd|
if attic_or_fnd.respond_to?(:attached_to_roof_idrefs) && !attic_or_fnd.attached_to_roof_idrefs.nil? && !attic_or_fnd.attached_to_roof_idrefs.delete(surf.id).nil?
attic_or_fnd.attached_to_roof_idrefs << "#{surf_name}#{i + 1}"
end
if attic_or_fnd.respond_to?(:attached_to_wall_idrefs) && !attic_or_fnd.attached_to_wall_idrefs.nil? && !attic_or_fnd.attached_to_wall_idrefs.delete(surf.id).nil?
attic_or_fnd.attached_to_wall_idrefs << "#{surf_name}#{i + 1}"
end
if attic_or_fnd.respond_to?(:attached_to_rim_joist_idrefs) && !attic_or_fnd.attached_to_rim_joist_idrefs.nil? && !attic_or_fnd.attached_to_rim_joist_idrefs.delete(surf.id).nil?
attic_or_fnd.attached_to_rim_joist_idrefs << "#{surf_name}#{i + 1}"
end
if attic_or_fnd.respond_to?(:attached_to_floor_idrefs) && !attic_or_fnd.attached_to_floor_idrefs.nil? && !attic_or_fnd.attached_to_floor_idrefs.delete(surf.id).nil?
attic_or_fnd.attached_to_floor_idrefs << "#{surf_name}#{i + 1}"
end
if attic_or_fnd.respond_to?(:attached_to_slab_idrefs) && !attic_or_fnd.attached_to_slab_idrefs.nil? && !attic_or_fnd.attached_to_slab_idrefs.delete(surf.id).nil?
attic_or_fnd.attached_to_slab_idrefs << "#{surf_name}#{i + 1}"
end
if attic_or_fnd.respond_to?(:attached_to_foundation_wall_idrefs) && !attic_or_fnd.attached_to_foundation_wall_idrefs.nil? && !attic_or_fnd.attached_to_foundation_wall_idrefs.delete(surf.id).nil?
attic_or_fnd.attached_to_foundation_wall_idrefs << "#{surf_name}#{i + 1}"
end
indexes = {}
(hpxml_bldg.surfaces + hpxml_bldg.subsurfaces).each do |surf|
surf_name = surf.class.to_s.gsub('HPXML::', '')
indexes[surf_name] = 0 if indexes[surf_name].nil?
indexes[surf_name] += 1
(hpxml_bldg.attics + hpxml_bldg.foundations).each do |attic_or_fnd|
if attic_or_fnd.respond_to?(:attached_to_roof_idrefs) && !attic_or_fnd.attached_to_roof_idrefs.nil? && !attic_or_fnd.attached_to_roof_idrefs.delete(surf.id).nil?
attic_or_fnd.attached_to_roof_idrefs << "#{surf_name}#{indexes[surf_name]}"
end
(hpxml_bldg.windows + hpxml_bldg.doors).each do |subsurf|
if subsurf.respond_to?(:wall_idref) && (subsurf.wall_idref == surf.id)
subsurf.wall_idref = "#{surf_name}#{i + 1}"
end
if attic_or_fnd.respond_to?(:attached_to_wall_idrefs) && !attic_or_fnd.attached_to_wall_idrefs.nil? && !attic_or_fnd.attached_to_wall_idrefs.delete(surf.id).nil?
attic_or_fnd.attached_to_wall_idrefs << "#{surf_name}#{indexes[surf_name]}"
end
hpxml_bldg.skylights.each do |subsurf|
if subsurf.respond_to?(:roof_idref) && (subsurf.roof_idref == surf.id)
subsurf.roof_idref = "#{surf_name}#{i + 1}"
end
if attic_or_fnd.respond_to?(:attached_to_rim_joist_idrefs) && !attic_or_fnd.attached_to_rim_joist_idrefs.nil? && !attic_or_fnd.attached_to_rim_joist_idrefs.delete(surf.id).nil?
attic_or_fnd.attached_to_rim_joist_idrefs << "#{surf_name}#{indexes[surf_name]}"
end
if attic_or_fnd.respond_to?(:attached_to_floor_idrefs) && !attic_or_fnd.attached_to_floor_idrefs.nil? && !attic_or_fnd.attached_to_floor_idrefs.delete(surf.id).nil?
attic_or_fnd.attached_to_floor_idrefs << "#{surf_name}#{indexes[surf_name]}"
end
surf.id = "#{surf_name}#{i + 1}"
if surf.respond_to? :insulation_id
surf.insulation_id = "#{surf_name}#{i + 1}Insulation"
if attic_or_fnd.respond_to?(:attached_to_slab_idrefs) && !attic_or_fnd.attached_to_slab_idrefs.nil? && !attic_or_fnd.attached_to_slab_idrefs.delete(surf.id).nil?
attic_or_fnd.attached_to_slab_idrefs << "#{surf_name}#{indexes[surf_name]}"
end
if surf.respond_to? :perimeter_insulation_id
surf.perimeter_insulation_id = "#{surf_name}#{i + 1}PerimeterInsulation"
if attic_or_fnd.respond_to?(:attached_to_foundation_wall_idrefs) && !attic_or_fnd.attached_to_foundation_wall_idrefs.nil? && !attic_or_fnd.attached_to_foundation_wall_idrefs.delete(surf.id).nil?
attic_or_fnd.attached_to_foundation_wall_idrefs << "#{surf_name}#{indexes[surf_name]}"
end
end
(hpxml_bldg.windows + hpxml_bldg.doors).each do |subsurf|
if subsurf.respond_to?(:attached_to_wall_idref) && (subsurf.attached_to_wall_idref == surf.id)
subsurf.attached_to_wall_idref = "#{surf_name}#{indexes[surf_name]}"
end
if surf.respond_to? :under_slab_insulation_id
surf.under_slab_insulation_id = "#{surf_name}#{i + 1}UnderSlabInsulation"
end
hpxml_bldg.skylights.each do |subsurf|
if subsurf.respond_to?(:attached_to_roof_idref) && (subsurf.attached_to_roof_idref == surf.id)
subsurf.attached_to_roof_idref = "#{surf_name}#{indexes[surf_name]}"
end
end
surf.id = "#{surf_name}#{indexes[surf_name]}"
if surf.respond_to? :insulation_id
surf.insulation_id = "#{surf_name}#{indexes[surf_name]}Insulation"
end
if surf.respond_to? :perimeter_insulation_id
surf.perimeter_insulation_id = "#{surf_name}#{indexes[surf_name]}PerimeterInsulation"
end
if surf.respond_to? :under_slab_insulation_id
surf.under_slab_insulation_id = "#{surf_name}#{indexes[surf_name]}UnderSlabInsulation"
end
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions BuildResidentialHPXML/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>build_residential_hpxml</name>
<uid>a13a8983-2b01-4930-8af2-42030b6e4233</uid>
<version_id>b0604dc5-b6a6-4e72-b423-b3c4e25ae1fc</version_id>
<version_modified>2024-05-07T13:37:00Z</version_modified>
<version_id>89391782-f408-4b0e-9801-b5f67d0f8241</version_id>
<version_modified>2024-05-15T20:26:57Z</version_modified>
<xml_checksum>2C38F48B</xml_checksum>
<class_name>BuildResidentialHPXML</class_name>
<display_name>HPXML Builder</display_name>
Expand Down Expand Up @@ -7342,7 +7342,7 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>58EF2442</checksum>
<checksum>8BEED0CA</checksum>
</file>
<file>
<filename>geometry.rb</filename>
Expand Down
3 changes: 2 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ __New Features__
- Allows optional ground diffusivity input.
- Updates to using G-Functions from the [G-Function Library for Modeling Vertical Bore Ground Heat Exchanger](https://gdr.openei.org/submissions/1325).
- Updated heating/cooling performance curves to reflect newer equipment.
- Skylights with shafts or sun tunnels should include the `Skylight/AttachedToFloor` element.
- Allows optional `Ducts/DuctShape` and `Ducts/DuctFractionRectangular` inputs, which affect duct effective R-value used for modeling.
- Allows optional `HeatingAutosizingFactor`, `CoolingAutosizingFactor`, `BackupHeatingAutosizingFactor` inputs to scale HVAC capacities for autosized equipment.
- Allows optional `HeatingAutosizingLimit`, `CoolingAutosizingLimit`, `BackupHeatingAutosizingLimit` inputs to set maximum HVAC capacities ceiling for autosized equipment.
Expand All @@ -51,8 +52,8 @@ __New Features__
- HVAC Manual J design load calculations:
- **Breaking change**: Outputs for "Infiltration/Ventilation" category disaggregated into "Infiltration" and "Ventilation".
- **Breaking change**: Outputs for "Windows" category no longer includes AED excursion; now a separate "AED Excursion" category.
- Allows optional zone-level and space-level design load calculations using HPXML `Zones/Zone[ZoneType="conditioned"]/Spaces/Space` elements.
- Allows additional outdoor design condition inputs: `DailyTemperatureRange` and `HumidityDifference`.
- Allows optional room-by-room design load calculations using HPXML `Space` elements.
- Adds a new detailed output file with block/space load details by surface, AED curves, etc.
- Miscellaneous improvements.
- Improves heating/cooling component loads; for timesteps where there is no heating/cooling load, assigns heat transfer to heating or cooling by comparing indoor temperature to the average of heating/cooling setpoints.
Expand Down
18 changes: 12 additions & 6 deletions HPXMLtoOpenStudio/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ def run(model, runner, user_arguments)
unavailable_periods: hpxml.header.unavailable_periods,
output_path: File.join(args[:output_dir], in_schedules_csv))
HPXMLDefaults.apply(runner, hpxml, hpxml_bldg, eri_version, weather, epw_file: epw_file, schedules_file: schedules_file,
design_load_details_output_file_path: design_load_details_output_file_path,
output_format: args[:output_format])
design_load_details_output_file_path: design_load_details_output_file_path,
output_format: args[:output_format])
hpxml_sch_map[hpxml_bldg] = schedules_file
end
validate_emissions_files(hpxml.header)
Expand Down Expand Up @@ -474,7 +474,7 @@ def create_unit_model(hpxml, hpxml_bldg, runner, model, epw_path, epw_file, weat
add_foundation_walls_slabs(runner, model, weather, spaces)
add_windows(model, spaces)
add_doors(model, spaces)
add_skylights(model, spaces)
add_skylights(runner, model, spaces)
add_conditioned_floor_area(model, spaces)
add_thermal_mass(model, spaces)
Geometry.set_zone_volumes(spaces, @hpxml_bldg, @apply_ashrae140_assumptions)
Expand Down Expand Up @@ -867,7 +867,9 @@ def add_rim_joists(runner, model, spaces)

def add_floors(runner, model, spaces)
@hpxml_bldg.floors.each do |floor|
area = floor.area
next if floor.net_area < 1.0 # skip modeling net surface area for surfaces comprised entirely of subsurface area

area = floor.net_area
width = Math::sqrt(area)
length = area / width
if floor.interior_adjacent_to.include?('attic') || floor.exterior_adjacent_to.include?('attic')
Expand Down Expand Up @@ -1402,11 +1404,15 @@ def add_windows(model, spaces)
apply_adiabatic_construction(model, surfaces, 'wall')
end

def add_skylights(model, spaces)
def add_skylights(runner, model, spaces)
surfaces = []
shading_schedules = {}

@hpxml_bldg.skylights.each do |skylight|
if not skylight.is_conditioned
runner.registerWarning("Skylight '#{skylight.id}' not connected to conditioned space; if it's a skylight with a shaft or sun tunnel, use AttachedToFloor to connect it to conditioned space.")
end

tilt = skylight.roof.pitch / 12.0
width = Math::sqrt(skylight.area)
length = skylight.area / width
Expand All @@ -1424,7 +1430,7 @@ def add_skylights(model, spaces)
surface.additionalProperties.setFeature('SurfaceType', 'Skylight')
surface.setName("surface #{skylight.id}")
surface.setSurfaceType('RoofCeiling')
surface.setSpace(create_or_get_space(model, spaces, HPXML::LocationConditionedSpace)) # Ensures it is included in Manual J sizing
surface.setSpace(create_or_get_space(model, spaces, skylight.roof.interior_adjacent_to))
surface.setOutsideBoundaryCondition('Outdoors') # cannot be adiabatic because subsurfaces won't be created
surfaces << surface

Expand Down

0 comments on commit 32f5187

Please sign in to comment.