Skip to content

Commit

Permalink
Update validator and indicate defaulted panel load types.
Browse files Browse the repository at this point in the history
  • Loading branch information
joseph-robertson committed Oct 28, 2024
1 parent 0e260bf commit 5530301
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 38 deletions.
12 changes: 6 additions & 6 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>1fcd16f3-4b2f-4f92-adb9-9c693a36555e</version_id>
<version_modified>2024-10-25T22:48:31Z</version_modified>
<version_id>8b94d1c4-cade-4be1-ba4e-4a47853194c6</version_id>
<version_modified>2024-10-28T16:53:14Z</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>4A568B89</checksum>
<checksum>39AE738F</checksum>
</file>
<file>
<filename>electric_panel.rb</filename>
Expand Down Expand Up @@ -363,7 +363,7 @@
<filename>hpxml.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>99438361</checksum>
<checksum>3D6FDD59</checksum>
</file>
<file>
<filename>hpxml_schema/HPXML.xsd</filename>
Expand All @@ -381,7 +381,7 @@
<filename>hpxml_schematron/EPvalidator.xml</filename>
<filetype>xml</filetype>
<usage_type>resource</usage_type>
<checksum>83B9D350</checksum>
<checksum>9D8A62DF</checksum>
</file>
<file>
<filename>hpxml_schematron/iso-schematron.xsd</filename>
Expand Down Expand Up @@ -645,7 +645,7 @@
<filename>xmlhelper.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>DA4456A1</checksum>
<checksum>C3112FAC</checksum>
</file>
<file>
<filename>xmlvalidator.rb</filename>
Expand Down
97 changes: 74 additions & 23 deletions HPXMLtoOpenStudio/resources/defaults.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3184,94 +3184,122 @@ def self.apply_electric_panels(hpxml_bldg, unit_num)
next if !heating_system.panel_loads.nil?

panel_loads.add(type: HPXML::ElectricPanelLoadTypeHeating,
system_idrefs: [heating_system.id])
type_isdefaulted: true,
system_idrefs: [heating_system.id],
system_idrefs_isdefaulted: true)
end

hpxml_bldg.cooling_systems.each do |cooling_system|
next if !cooling_system.panel_loads.nil?

panel_loads.add(type: HPXML::ElectricPanelLoadTypeCooling,
system_idrefs: [cooling_system.id])
type_isdefaulted: true,
system_idrefs: [cooling_system.id],
system_idrefs_isdefaulted: true)
end

hpxml_bldg.heat_pumps.each do |heat_pump|
next if !heat_pump.panel_loads.nil?

panel_loads.add(type: HPXML::ElectricPanelLoadTypeHeating,
system_idrefs: [heat_pump.id])
type_isdefaulted: true,
system_idrefs: [heat_pump.id],
system_idrefs_isdefaulted: true)
panel_loads.add(type: HPXML::ElectricPanelLoadTypeCooling,
system_idrefs: [heat_pump.id])
type_isdefaulted: true,
system_idrefs: [heat_pump.id],
system_idrefs_isdefaulted: true)
end

hpxml_bldg.water_heating_systems.each do |water_heating_system|
next if !water_heating_system.panel_loads.nil?
next if water_heating_system.fuel_type != HPXML::FuelTypeElectricity

panel_loads.add(type: HPXML::ElectricPanelLoadTypeWaterHeater,
system_idrefs: [water_heating_system.id])
type_isdefaulted: true,
system_idrefs: [water_heating_system.id],
system_idrefs_isdefaulted: true)
end

hpxml_bldg.clothes_dryers.each do |clothes_dryer|
next if !clothes_dryer.panel_loads.nil?
next if clothes_dryer.fuel_type != HPXML::FuelTypeElectricity

panel_loads.add(type: HPXML::ElectricPanelLoadTypeClothesDryer,
system_idrefs: [clothes_dryer.id])
type_isdefaulted: true,
system_idrefs: [clothes_dryer.id],
system_idrefs_isdefaulted: true)
end

hpxml_bldg.dishwashers.each do |dishwasher|
next if !dishwasher.panel_loads.nil?

panel_loads.add(type: HPXML::ElectricPanelLoadTypeDishwasher,
system_idrefs: [dishwasher.id])
type_isdefaulted: true,
system_idrefs: [dishwasher.id],
system_idrefs_isdefaulted: true)
end

hpxml_bldg.cooking_ranges.each do |cooking_range|
next if !cooking_range.panel_loads.nil?
next if cooking_range.fuel_type != HPXML::FuelTypeElectricity

panel_loads.add(type: HPXML::ElectricPanelLoadTypeRangeOven,
system_idrefs: [cooking_range.id])
type_isdefaulted: true,
system_idrefs: [cooking_range.id],
system_idrefs_isdefaulted: true)
end

hpxml_bldg.permanent_spas.each do |permanent_spa|
next if !permanent_spa.panel_loads.nil?

panel_loads.add(type: HPXML::ElectricPanelLoadTypePermanentSpaPump,
system_idrefs: [permanent_spa.pump_id])
type_isdefaulted: true,
system_idrefs: [permanent_spa.pump_id],
system_idrefs_isdefaulted: true)

next if ![HPXML::HeaterTypeElectricResistance, HPXML::HeaterTypeHeatPump].include?(permanent_spa.heater_type)

panel_loads.add(type: HPXML::ElectricPanelLoadTypePermanentSpaHeater,
system_idrefs: [permanent_spa.heater_id])
type_isdefaulted: true,
system_idrefs: [permanent_spa.heater_id],
system_idrefs_isdefaulted: true)
end

hpxml_bldg.pools.each do |pool|
next if !pool.panel_loads.nil?

panel_loads.add(type: HPXML::ElectricPanelLoadTypePoolPump,
system_idrefs: [pool.pump_id])
type_isdefaulted: true,
system_idrefs: [pool.pump_id],
system_idrefs_isdefaulted: true)

next if ![HPXML::HeaterTypeElectricResistance, HPXML::HeaterTypeHeatPump].include?(pool.heater_type)

panel_loads.add(type: HPXML::ElectricPanelLoadTypePoolHeater,
system_idrefs: [pool.heater_id])
type_isdefaulted: true,
system_idrefs: [pool.heater_id],
system_idrefs_isdefaulted: true)
end

hpxml_bldg.plug_loads.each do |plug_load|
next if !plug_load.panel_loads.nil?
next if plug_load.plug_load_type != HPXML::PlugLoadTypeWellPump

panel_loads.add(type: HPXML::ElectricPanelLoadTypeWellPump,
system_idrefs: [plug_load.id])
type_isdefaulted: true,
system_idrefs: [plug_load.id],
system_idrefs_isdefaulted: true)
end

hpxml_bldg.plug_loads.each do |plug_load|
next if !plug_load.panel_loads.nil?
next if plug_load.plug_load_type != HPXML::PlugLoadTypeElectricVehicleCharging

panel_loads.add(type: HPXML::ElectricPanelLoadTypeElectricVehicleCharging,
system_idrefs: [plug_load.id])
type_isdefaulted: true,
system_idrefs: [plug_load.id],
system_idrefs_isdefaulted: true)
end

ventilation_fan_ids = []
Expand All @@ -3283,20 +3311,27 @@ def self.apply_electric_panels(hpxml_bldg, unit_num)
end
if not ventilation_fan_ids.empty?
panel_loads.add(type: HPXML::ElectricPanelLoadTypeOther,
system_idrefs: ventilation_fan_ids)
type_isdefaulted: true,
system_idrefs: ventilation_fan_ids,
system_idrefs_isdefaulted: true)
end

if panel_loads.count { |pl| pl.type == HPXML::ElectricPanelLoadTypeOther && pl.system_idrefs.empty? } == 0
panel_loads.add(type: HPXML::ElectricPanelLoadTypeOther, system_idrefs: []) # for garbage disposal and garage door opener
panel_loads.add(type: HPXML::ElectricPanelLoadTypeOther,
type_isdefaulted: true,
system_idrefs: []) # for garbage disposal and garage door opener
end
if panel_loads.count { |pl| pl.type == HPXML::ElectricPanelLoadTypeLighting } == 0
electric_panel.panel_loads.add(type: HPXML::ElectricPanelLoadTypeLighting)
electric_panel.panel_loads.add(type: HPXML::ElectricPanelLoadTypeLighting,
type_isdefaulted: true)
end
if panel_loads.count { |pl| pl.type == HPXML::ElectricPanelLoadTypeKitchen } == 0
electric_panel.panel_loads.add(type: HPXML::ElectricPanelLoadTypeKitchen)
electric_panel.panel_loads.add(type: HPXML::ElectricPanelLoadTypeKitchen,
type_isdefaulted: true)
end
if panel_loads.count { |pl| pl.type == HPXML::ElectricPanelLoadTypeLaundry } == 0
electric_panel.panel_loads.add(type: HPXML::ElectricPanelLoadTypeLaundry)
electric_panel.panel_loads.add(type: HPXML::ElectricPanelLoadTypeLaundry,
type_isdefaulted: true)
end

panel_loads.each do |panel_load|
Expand Down Expand Up @@ -5793,6 +5828,17 @@ def self.get_breaker_spaces_from_heating_capacity(capacity)
return (UnitConversions.convert(capacity, 'btu/hr', 'kw') / 12.0).ceil * 2.0 + 2
end

# TODO
def self.heat_pump_backup_simultaneous_operation(heat_pump)
if !heat_pump.compressor_lockout_temp.nil? &&
!heat_pump.backup_heating_lockout_temp.nil? &&
(heat_pump.backup_heating_lockout_temp > heat_pump.compressor_lockout_temp)
return true
end

return false
end

# TODO
def self.get_breaker_spaces_from_backup_heating_capacity(capacity)
if UnitConversions.convert(capacity, 'btu/hr', 'kw') <= 10
Expand Down Expand Up @@ -5887,11 +5933,12 @@ def self.get_panel_load_watts_breaker_spaces_values(hpxml_bldg, panel_load)

distribution_system = heat_pump.distribution_system
if heat_pump.backup_type == HPXML::HeatPumpBackupTypeIntegrated
if !heat_pump.backup_heating_switchover_temp.nil? # max
watts += [get_dx_coil_load_from_capacity(UnitConversions.convert(heat_pump.heating_capacity, 'btu/hr', 'kbtu/hr')), UnitConversions.convert(heat_pump.backup_heating_capacity, 'btu/hr', 'w')].max
else # sum

if heat_pump_backup_simultaneous_operation(heat_pump) # sum
watts += get_dx_coil_load_from_capacity(UnitConversions.convert(heat_pump.heating_capacity, 'btu/hr', 'kbtu/hr'))
watts += UnitConversions.convert(heat_pump.backup_heating_capacity, 'btu/hr', 'w')
else # max
watts += [get_dx_coil_load_from_capacity(UnitConversions.convert(heat_pump.heating_capacity, 'btu/hr', 'kbtu/hr')), UnitConversions.convert(heat_pump.backup_heating_capacity, 'btu/hr', 'w')].max
end
if heat_pump.backup_heating_fuel == HPXML::FuelTypeElectricity
if !distribution_system.nil?
Expand Down Expand Up @@ -5920,7 +5967,9 @@ def self.get_panel_load_watts_breaker_spaces_values(hpxml_bldg, panel_load)
watts += get_dx_coil_load_from_capacity(UnitConversions.convert(cooling_system.cooling_capacity, 'btu/hr', 'kbtu/hr'))
if !distribution_system.nil?
heating_system = cooling_system.attached_heating_system
if !heating_system.nil? && (heating_system.heating_system_fuel != HPXML::FuelTypeElectricity)
if !heating_system.nil? &&
(((heating_system.is_a? HPXML::HeatingSystem) && (heating_system.heating_system_fuel != HPXML::FuelTypeElectricity)) ||
((heating_system.is_a? HPXML::HeatPump) && (heating_system.heat_pump_fuel != HPXML::FuelTypeElectricity)))
watts += get_120v_air_handler_load_from_capacity(UnitConversions.convert(cooling_system.cooling_capacity, 'btu/hr', 'kbtu/hr'))
breaker_spaces += 1
else
Expand Down Expand Up @@ -6085,8 +6134,10 @@ def self.get_panel_load_watts_breaker_spaces_values(hpxml_bldg, panel_load)
end
elsif type == HPXML::ElectricPanelLoadTypeLighting
watts += 3 * hpxml_bldg.building_construction.conditioned_floor_area
breaker_spaces += 0
elsif type == HPXML::ElectricPanelLoadTypeKitchen
watts += 3000
breaker_spaces += 0
elsif type == HPXML::ElectricPanelLoadTypeLaundry
watts = + 1500
breaker_spaces += 1
Expand Down
2 changes: 1 addition & 1 deletion HPXMLtoOpenStudio/resources/hpxml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9425,7 +9425,7 @@ def to_doc(electric_panel)
if (not @system_idrefs.nil?) && (not @system_idrefs.empty?)
@system_idrefs.each do |system_idref|
system = XMLHelper.add_element(panel_load, 'System')
XMLHelper.add_attribute(system, 'idref', system_idref)
XMLHelper.add_attribute(system, 'idref', system_idref, @system_idrefs_isdefaulted)
end
end
end
Expand Down
11 changes: 7 additions & 4 deletions HPXMLtoOpenStudio/resources/hpxml_schematron/EPvalidator.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2463,20 +2463,23 @@

<sch:pattern>
<sch:title>[PanelLoads]</sch:title>
<sch:rule context='/h:HPXML/h:Building/h:BuildingDetails/h:Systems/h:ElectricPanels/*/extension/h:PanelLoads'>
<sch:rule context='/h:HPXML/h:Building/h:BuildingDetails/h:Systems/h:ElectricPanels/*/h:extension/h:PanelLoads'>
<sch:assert role='ERROR' test='count(h:PanelLoad) &gt;= 1'>Expected 1 or more element(s) for xpath: PanelLoad</sch:assert> <!-- See [PanelLoad] -->
</sch:rule>
</sch:pattern>

<sch:pattern>
<sch:title>[PanelLoad]</sch:title>
<sch:rule context='/h:HPXML/h:Building/h:BuildingDetails/h:Systems/h:ElectricPanels/*/extension/*/h:PanelLoad'>
<sch:assert role='ERROR' test='count(h:Type[text()="Heating" or text()="Cooling" or text()="Hot Water" or text()="Clothes Dryer" or text()="Dishwasher" or text()="Range/Oven" or text()="Permanent Spa Heater" or text()="Permanent Spa Pump" or text()="Pool Heater" or text()="Pool Pump" or text()="Well Pump" or text()="Electric Vehicle Charging"]) = 1'>Expected 1 element(s) for xpath: Type[text()="Heating" or text()="Cooling" or text()="Hot Water" or text()="Clothes Dryer"]</sch:assert>
<sch:rule context='/h:HPXML/h:Building/h:BuildingDetails/h:Systems/h:ElectricPanels/*/h:extension/*/h:PanelLoad'>
<sch:assert role='ERROR' test='count(h:Type) = 1'>Expected 1 element(s) for xpath: Type</sch:assert>
<sch:assert role='ERROR' test='count(h:Type[text()="Heating" or text()="Cooling" or text()="Hot Water" or text()="Clothes Dryer" or text()="Dishwasher" or text()="Range/Oven" or text()="Permanent Spa Heater" or text()="Permanent Spa Pump" or text()="Pool Heater" or text()="Pool Pump" or text()="Well Pump" or text()="Electric Vehicle Charging" or text()="Other"]) = 1'>Expected 1 element(s) for xpath: Type[text()="Heating" or text()="Cooling" or text()="Hot Water" or text()="Clothes Dryer"]</sch:assert>
<sch:assert role='ERROR' test='count(h:Watts) &lt;= 1'>Expected 0 or 1 element(s) for xpath: Watts</sch:assert>
<sch:assert role='ERROR' test='count(h:Voltage) &lt;= 1'>Expected 0 or 1 element(s) for xpath: Voltage</sch:assert>
<sch:assert role='ERROR' test='h:Voltage[text()="120" or text()="240"] or not(h:Voltage)'>Expected Voltage to be '120' or '240'</sch:assert>
<sch:assert role='ERROR' test='count(h:Addition) &lt;= 1'>Expected 0 or 1 element(s) for xpath: Addition</sch:assert>
<sch:assert role='ERROR' test='h:Addition[text()="false" or text()="true"]'>Expected Addition to be 'false' or 'true'</sch:assert>
<sch:assert role='ERROR' test='h:Addition[text()="false" or text()="true"] or not(h:Addition)'>Expected Addition to be 'false' or 'true'</sch:assert>
<sch:assert role='ERROR' test='count(h:System) &gt;= 0'>Expected 0 or more element(s) for xpath: System</sch:assert>
<sch:assert role='ERROR' test='count(h:Type[text()="Heating" or text()="Cooling" or text()="Hot Water" or text()="Clothes Dryer" or text()="Dishwasher" or text()="Range/Oven" or text()="Permanent Spa Heater" or text()="Permanent Spa Pump" or text()="Pool Heater" or text()="Pool Pump" or text()="Well Pump" or text()="Electric Vehicle Charging"]) + count(h:System) = 2 or count(h:Type[text()="Other"]) = 1'>Expected 1 element(s) for xpath: System</sch:assert>
</sch:rule>
</sch:pattern>

Expand Down
5 changes: 4 additions & 1 deletion HPXMLtoOpenStudio/resources/xmlhelper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,11 @@ def self.has_element(parent, element_name)
# @param attr_name [String] Name of the attribute
# @param attr_val [*] Value for the attribute
# @return [nil]
def self.add_attribute(element, attr_name, attr_val)
def self.add_attribute(element, attr_name, attr_val, defaulted = false)
element.set(attr_name, attr_val)
if defaulted
XMLHelper.add_attribute(element, 'dataSource', 'software')
end
end

# Gets the value of the specified attribute for the given element.
Expand Down
7 changes: 4 additions & 3 deletions docs/source/workflow_inputs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4626,10 +4626,10 @@ Individual panel loads entered in ``extension/PanelLoads/PanelLoad``.
``Voltage`` string V See [#]_ No See [#]_
``BreakerSpaces`` integer No See [#]_
``Addition`` boolean No false
``System`` idref See [#]_ No See [#]_ Can reference one or more systems
``System`` idref See [#]_ See [#]_ See [#]_ Can reference one or more systems
============================================== ======== ============== =========== ======== ========= ==========================================

.. [#] Type choices are "Heating", "Cooling", "Hot Water", "Clothes Dryer", "Dishwasher", "Range/Oven", "Permanent Spa Heater", "Permanent Spa Pump", "Pool Heater", "Pool Pump", "Well Pump", and "Electric Vehicle Charging".
.. [#] Type choices are "Heating", "Cooling", "Hot Water", "Clothes Dryer", "Dishwasher", "Range/Oven", "Permanent Spa Heater", "Permanent Spa Pump", "Pool Heater", "Pool Pump", "Well Pump", "Electric Vehicle Charging", and "Other".
.. [#] If Watts not provided, defaults as follows:

\- **Heating**: TODO
Expand Down Expand Up @@ -4667,7 +4667,7 @@ Individual panel loads entered in ``extension/PanelLoads/PanelLoad``.
.. [#] Voltage choices are "120" or "240".
.. [#] If Voltage not provided, defaults as follows:

\- **Heating, Cooling, Hot Water, Clothes Dryer, Range/Oven, Permanent Spa Heater, Pool Heater**: 240
\- **Heating, Cooling, Hot Water, Clothes Dryer, Range/Oven, Permanent Spa Heater, Pool Heater**: 240 (120 if Cooling references a room air conditioner)

\- **Dishwasher, Permanent Spa Pump, Pool Pump, Well Pump, Electric Vehicle Charging, Lighting, Kitchen, Laundry, Other**: 120

Expand All @@ -4678,6 +4678,7 @@ Individual panel loads entered in ``extension/PanelLoads/PanelLoad``.
\- **Heating, Cooling, Hot Water, Clothes Dryer, Dishwasher, Range/Oven, Permanent Spa Heater, Permanent Spa Pump, Pool Heater, Pool Pump, Well Pump, Electric Vehicle Charging, Other**: 120=1, 240=2

.. [#] System must reference a ``HeatingSystem``, ``CoolingSystem``, ``HeatPump``, ``WaterHeatingSystem``, ``ClothesDryer``, ``Dishwasher``, ``CookingRange``, ``PermanentSpa/Heater``, ``PermanentSpa/Pumps/Pump``, ``Pool/Heater``, ``Pool/Pump``, ``PlugLoad``, or ``VentilationFan``.
.. [#] Not required if Type is "Other"; otherwise, required.
.. [#] A panel load is created for any system not already referenced by a panel load.

.. _hpxml_batteries:
Expand Down

0 comments on commit 5530301

Please sign in to comment.