Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions BuildResidentialHPXML/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Path to the EPW file. Either this or the Zip Code input above must be provided.

**Location: Site Type**

The terrain/shielding of the home, for the infiltration model. Defaults to 'Suburban, Normal' for single-family detached and manufactured home and 'Suburban, Well-Shielded' for single-family attached and apartment units.
The terrain/shielding of the home, for the infiltration model.

- **Name:** ``location_site_type``
- **Type:** ``Choice``
Expand Down Expand Up @@ -209,7 +209,7 @@ The number of bedrooms in the unit.

**Geometry: Unit Number of Bathrooms**

The number of bathrooms in the unit. Defaults to NumberofBedrooms/2 + 0.5.
The number of bathrooms in the unit.

- **Name:** ``geometry_unit_num_bathrooms``
- **Type:** ``Choice``
Expand Down
4 changes: 2 additions & 2 deletions BuildResidentialHPXML/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument

arg = OpenStudio::Measure::OSArgument.makeChoiceArgument('location_site_type', choices[:location_site_type], false)
arg.setDisplayName('Location: Site Type')
arg.setDescription("The terrain/shielding of the home, for the infiltration model. Defaults to 'Suburban, Normal' for single-family detached and manufactured home and 'Suburban, Well-Shielded' for single-family attached and apartment units.")
arg.setDescription('The terrain/shielding of the home, for the infiltration model.')
arg.setDefaultValue('Default')
args << arg

Expand Down Expand Up @@ -136,7 +136,7 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument

arg = OpenStudio::Measure::OSArgument.makeChoiceArgument('geometry_unit_num_bathrooms', choices[:geometry_unit_num_bathrooms], false)
arg.setDisplayName('Geometry: Unit Number of Bathrooms')
arg.setDescription('The number of bathrooms in the unit. Defaults to NumberofBedrooms/2 + 0.5.')
arg.setDescription('The number of bathrooms in the unit.')
arg.setDefaultValue('Default')
args << arg

Expand Down
12 changes: 6 additions & 6 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>f4f37f65-5e30-41a0-b3dc-7a4a1fa57f44</version_id>
<version_modified>2026-05-22T21:28:29Z</version_modified>
<version_id>8c6a6855-95e8-491e-8fb6-6820b622531e</version_id>
<version_modified>2026-07-17T21:33:32Z</version_modified>
<xml_checksum>2C38F48B</xml_checksum>
<class_name>BuildResidentialHPXML</class_name>
<display_name>HPXML Builder</display_name>
Expand Down Expand Up @@ -108,7 +108,7 @@
<argument>
<name>location_site_type</name>
<display_name>Location: Site Type</display_name>
<description>The terrain/shielding of the home, for the infiltration model. Defaults to 'Suburban, Normal' for single-family detached and manufactured home and 'Suburban, Well-Shielded' for single-family attached and apartment units.</description>
<description>The terrain/shielding of the home, for the infiltration model.</description>
<type>Choice</type>
<required>false</required>
<model_dependent>false</model_dependent>
Expand Down Expand Up @@ -595,7 +595,7 @@
<argument>
<name>geometry_unit_num_bathrooms</name>
<display_name>Geometry: Unit Number of Bathrooms</display_name>
<description>The number of bathrooms in the unit. Defaults to NumberofBedrooms/2 + 0.5.</description>
<description>The number of bathrooms in the unit.</description>
<type>Choice</type>
<required>false</required>
<model_dependent>false</model_dependent>
Expand Down Expand Up @@ -11433,7 +11433,7 @@
<filename>README.md</filename>
<filetype>md</filetype>
<usage_type>readme</usage_type>
<checksum>40789597</checksum>
<checksum>E343E87E</checksum>
</file>
<file>
<filename>README.md.erb</filename>
Expand All @@ -11450,7 +11450,7 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>E3E200DA</checksum>
<checksum>93E3B4F6</checksum>
</file>
<file>
<filename>constants.rb</filename>
Expand Down
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ __Bugfixes__
- **Breaking change**: HPWH `EnergyFactor`/`UniformEnergyFactor` must now be >= 1.45 (previously > 1).
- Fixes ERV supply outlet enthalpy calculation used to calculate latent effectiveness.
- Removes duplicated ceiling/floor internal mass surfaces between conditioned stories.
- Fixes error if `NumberofBedrooms=0` and `NumberofBathrooms` is omitted.

## OpenStudio-HPXML v1.12.0

Expand Down
8 changes: 4 additions & 4 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>hpxml_to_openstudio</name>
<uid>b1543b30-9465-45ff-ba04-1d1f85e763bc</uid>
<version_id>b5a80774-bddd-4161-b29c-68607900018d</version_id>
<version_modified>2026-07-16T19:57:35Z</version_modified>
<version_id>4cdd2955-f813-462c-8e3a-0a9db87b2626</version_id>
<version_modified>2026-07-17T21:51:12Z</version_modified>
<xml_checksum>D8922A73</xml_checksum>
<class_name>HPXMLToOpenStudio</class_name>
<display_name>HPXML to OpenStudio Translator</display_name>
Expand Down Expand Up @@ -367,7 +367,7 @@
<filename>defaults.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>4350A1B4</checksum>
<checksum>41261A50</checksum>
</file>
<file>
<filename>electric_panel.rb</filename>
Expand Down Expand Up @@ -751,7 +751,7 @@
<filename>test_defaults.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>2C65B351</checksum>
<checksum>F470D66D</checksum>
</file>
<file>
<filename>test_electric_panel.rb</filename>
Expand Down
37 changes: 21 additions & 16 deletions HPXMLtoOpenStudio/resources/defaults.rb
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ def self.apply_building_construction(hpxml_header, hpxml_bldg)
hpxml_bldg.building_construction.conditioned_building_volume_isdefaulted = true
end
if hpxml_bldg.building_construction.number_of_bathrooms.nil?
hpxml_bldg.building_construction.number_of_bathrooms = Float(get_num_bathrooms(nbeds)).to_i
hpxml_bldg.building_construction.number_of_bathrooms = get_num_bathrooms(nbeds)
hpxml_bldg.building_construction.number_of_bathrooms_isdefaulted = true
end
if hpxml_bldg.building_construction.number_of_units.nil?
Expand Down Expand Up @@ -2820,7 +2820,7 @@ def self.apply_hvac_control(hpxml_bldg, schedules_file, eri_version)
schedules_file_includes_cooling_setpoint_temp = (schedules_file.nil? ? false : schedules_file.includes_col_name(SchedulesFile::Columns[:CoolingSetpoint].name))
if hvac_control.cooling_setpoint_temp.nil? && hvac_control.weekday_cooling_setpoints.nil? && !schedules_file_includes_cooling_setpoint_temp
# No cooling setpoints; set a default cooling setpoint for, e.g., natural ventilation
clg_weekday_setpoints, clg_weekend_setpoints = Defaults.get_cooling_setpoint(HPXML::HVACControlTypeManual, eri_version)
clg_weekday_setpoints, clg_weekend_setpoints = get_cooling_setpoint(HPXML::HVACControlTypeManual, eri_version)
if clg_weekday_setpoints.split(', ').uniq.size == 1 && clg_weekend_setpoints.split(', ').uniq.size == 1 && clg_weekday_setpoints.split(', ').uniq == clg_weekend_setpoints.split(', ').uniq
hvac_control.cooling_setpoint_temp = clg_weekend_setpoints.split(', ').uniq[0].to_f
else
Expand Down Expand Up @@ -4603,7 +4603,7 @@ def self.apply_ceiling_fans(hpxml_bldg, weather, schedules_file)
ceiling_fan.weekend_fractions_isdefaulted = true
end
if ceiling_fan.monthly_multipliers.nil? && !schedules_file_includes_ceiling_fan
ceiling_fan.monthly_multipliers = Defaults.get_ceiling_fan_months(weather).join(', ')
ceiling_fan.monthly_multipliers = get_ceiling_fan_months(weather).join(', ')
ceiling_fan.monthly_multipliers_isdefaulted = true
end
end
Expand Down Expand Up @@ -5483,10 +5483,15 @@ def self.lookup_weather_data_from_wmo(wmo)
# Gets the default number of bathrooms in the dwelling unit.
#
# @param nbeds [Integer] Number of bedrooms in the dwelling unit
# @return [Double] Number of bathrooms
# @return [Integer] Number of bathrooms
def self.get_num_bathrooms(nbeds)
nbaths = nbeds / 2.0 + 0.5 # From BA HSP
return nbaths

# Ensure at least 1 bathroom (which the HPXML schema requires).
# Even a studio apartment w/ zero bedrooms would have a bathroom.
nbaths = [nbaths, 1].max

return nbaths.to_i
end

# Gets the default properties for cooking ranges/ovens.
Expand Down Expand Up @@ -6145,7 +6150,7 @@ def self.get_water_heater_performance_adjustment(water_heating_system)
# @return [Double] Water heater heating capacity (Btu/hr)
def self.get_water_heater_heating_capacity(fuel, nbeds, num_water_heaters, nbaths = nil)
if nbaths.nil?
nbaths = Defaults.get_num_bathrooms(nbeds)
nbaths = get_num_bathrooms(nbeds)
end

# Adjust the heating capacity if there are multiple water heaters in the home
Expand Down Expand Up @@ -6196,7 +6201,7 @@ def self.get_water_heater_tank_volume(fuel, is_hpwh, nbeds, nbaths, n_occ)
# FUTURE: Incorporate number of occupants for conventional elec/gas storage WHs.

if nbaths.nil?
nbaths = Defaults.get_num_bathrooms(nbeds)
nbaths = get_num_bathrooms(nbeds)
end

if is_hpwh && !n_occ.nil? # Heat pump water heater
Expand Down Expand Up @@ -7555,7 +7560,7 @@ def self.get_pool_pump_annual_energy(cfa, nbeds, n_occ, unit_type)
return 0.0
end

nbeds_eq = Defaults.get_equivalent_nbeds(nbeds, n_occ, unit_type)
nbeds_eq = get_equivalent_nbeds(nbeds, n_occ, unit_type)

return 158.6 / 0.070 * (0.5 + 0.25 * nbeds_eq / 3.0 + 0.25 * cfa / 1920.0)
end
Expand All @@ -7569,7 +7574,7 @@ def self.get_pool_pump_annual_energy(cfa, nbeds, n_occ, unit_type)
# @param type [String] Type of heater (HPXML::HeaterTypeXXX)
# @return [Array<String, Double>] Energy units (HPXML::UnitsXXX), annual energy use (kWh/yr or therm/yr)
def self.get_pool_heater_annual_energy(cfa, nbeds, n_occ, unit_type, type)
nbeds_eq = Defaults.get_equivalent_nbeds(nbeds, n_occ, unit_type)
nbeds_eq = get_equivalent_nbeds(nbeds, n_occ, unit_type)

load_units = nil
load_value = nil
Expand Down Expand Up @@ -7609,7 +7614,7 @@ def self.get_permanent_spa_pump_annual_energy(cfa, nbeds, n_occ, unit_type)
return 0.0
end

nbeds_eq = Defaults.get_equivalent_nbeds(nbeds, n_occ, unit_type)
nbeds_eq = get_equivalent_nbeds(nbeds, n_occ, unit_type)

return 59.5 / 0.059 * (0.5 + 0.25 * nbeds_eq / 3.0 + 0.25 * cfa / 1920.0) # kWh/yr
end
Expand All @@ -7623,7 +7628,7 @@ def self.get_permanent_spa_pump_annual_energy(cfa, nbeds, n_occ, unit_type)
# @param type [String] Type of heater (HPXML::HeaterTypeXXX)
# @return [Array<String, Double>] Energy units (HPXML::UnitsXXX), annual energy use (kWh/yr or therm/yr)
def self.get_permanent_spa_heater_annual_energy(cfa, nbeds, n_occ, unit_type, type)
nbeds_eq = Defaults.get_equivalent_nbeds(nbeds, n_occ, unit_type)
nbeds_eq = get_equivalent_nbeds(nbeds, n_occ, unit_type)

load_units = nil
load_value = nil
Expand Down Expand Up @@ -7683,7 +7688,7 @@ def self.get_default_well_pump_annual_energy(cfa, nbeds, n_occ, unit_type)
return 0.0
end

nbeds_eq = Defaults.get_equivalent_nbeds(nbeds, n_occ, unit_type)
nbeds_eq = get_equivalent_nbeds(nbeds, n_occ, unit_type)

return 50.8 / 0.127 * (0.5 + 0.25 * nbeds_eq / 3.0 + 0.25 * cfa / 1920.0)
end
Expand All @@ -7701,7 +7706,7 @@ def self.get_gas_grill_annual_energy(cfa, nbeds, n_occ, unit_type)
return 0.0
end

nbeds_eq = Defaults.get_equivalent_nbeds(nbeds, n_occ, unit_type)
nbeds_eq = get_equivalent_nbeds(nbeds, n_occ, unit_type)

return 0.87 / 0.029 * (0.5 + 0.25 * nbeds_eq / 3.0 + 0.25 * cfa / 1920.0)
end
Expand All @@ -7719,7 +7724,7 @@ def self.get_default_gas_lighting_annual_energy(cfa, nbeds, n_occ, unit_type)
return 0.0
end

nbeds_eq = Defaults.get_equivalent_nbeds(nbeds, n_occ, unit_type)
nbeds_eq = get_equivalent_nbeds(nbeds, n_occ, unit_type)

return 0.22 / 0.012 * (0.5 + 0.25 * nbeds_eq / 3.0 + 0.25 * cfa / 1920.0)
end
Expand All @@ -7737,7 +7742,7 @@ def self.get_gas_fireplace_annual_energy(cfa, nbeds, n_occ, unit_type)
return 0.0
end

nbeds_eq = Defaults.get_equivalent_nbeds(nbeds, n_occ, unit_type)
nbeds_eq = get_equivalent_nbeds(nbeds, n_occ, unit_type)

return 1.95 / 0.032 * (0.5 + 0.25 * nbeds_eq / 3.0 + 0.25 * cfa / 1920.0)
end
Expand All @@ -7755,7 +7760,7 @@ def self.get_water_use_internal_gains(nbeds, n_occ, unit_type, general_water_use
return 0.0, 0.0
end

nbeds_eq = Defaults.get_equivalent_nbeds(nbeds, n_occ, unit_type)
nbeds_eq = get_equivalent_nbeds(nbeds, n_occ, unit_type)

# ANSI/RESNET/ICC 301 - Table 4.2.2(3). Internal Gains for Reference Homes
sens_gains = (-1227.0 - 409.0 * nbeds_eq) * general_water_use_usage_multiplier # Btu/day
Expand Down
6 changes: 6 additions & 0 deletions HPXMLtoOpenStudio/tests/test_defaults.rb
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,12 @@ def test_building_construction
_default_hpxml, default_hpxml_bldg = _test_measure()
_test_default_building_construction_values(default_hpxml_bldg, 21600, 8.0, 2, 1, -7)

# Test defaults w/ zero bedrooms
hpxml_bldg.building_construction.number_of_bedrooms = 0
XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path)
_default_hpxml, default_hpxml_bldg = _test_measure()
_test_default_building_construction_values(default_hpxml_bldg, 21600, 8.0, 1, 1, -7)

# Test defaults w/ belly-and-wing foundation
hpxml, hpxml_bldg = _create_hpxml('base-foundation-belly-wing-skirt.xml')
hpxml_bldg.building_construction.conditioned_building_volume = nil
Expand Down
2 changes: 1 addition & 1 deletion docs/source/workflow_inputs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ Building construction is entered in ``/HPXML/Building/BuildingDetails/BuildingSu

.. [#] If AverageCeilingHeight not provided, defaults to (ConditionedBuildingVolume - ConditionedCrawlspaceVolume) / ConditionedFloorArea if ConditionedBuildingVolume is provided.
If ConditionedBuildingVolume not provided, AverageCeilingHeight defaults to 8.0 ft (unless there is a cathedral ceiling, in which case the value is adjusted).
.. [#] If NumberofBathrooms not provided, calculated as NumberofBedrooms/2 + 0.5 based on the `2010 BAHSP <https://www1.eere.energy.gov/buildings/publications/pdfs/building_america/house_simulation.pdf>`_.
.. [#] If NumberofBathrooms not provided, calculated as NumberofBedrooms/2 + 0.5 (rounded down, with a minimum of 1) based on the `2010 BAHSP <https://www1.eere.energy.gov/buildings/publications/pdfs/building_america/house_simulation.pdf>`_.
Comment thread
shorowit marked this conversation as resolved.
.. [#] If ConditionedBuildingVolume not provided, defaults to ConditionedFloorArea * AverageCeilingHeight + ConditionedCrawlspaceVolume.

HPXML Schedules
Expand Down
5 changes: 5 additions & 0 deletions workflow/hpxml_inputs.json
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,11 @@
"enclosure_floor_over_garage": "Wood Frame, R-38",
"enclosure_carpet": "80% Carpet"
},
"sample_files/base-enclosure-beds-0.xml": {
"parent_hpxml": "sample_files/base.xml",
"geometry_unit_num_bedrooms": "0",
"geometry_unit_num_bathrooms": "Default"
},
"sample_files/base-enclosure-beds-1.xml": {
"parent_hpxml": "sample_files/base.xml",
"geometry_unit_num_bedrooms": "1",
Expand Down
Loading