Skip to content
Merged
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
10 changes: 5 additions & 5 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>5a120116-1373-4af0-a27c-7cc4e9baa6ed</version_id>
<version_modified>2026-02-10T22:02:46Z</version_modified>
<version_id>f10d160e-01f4-4406-9b7f-8b0242583c06</version_id>
<version_modified>2026-02-23T17:34:34Z</version_modified>
<xml_checksum>D8922A73</xml_checksum>
<class_name>HPXMLtoOpenStudio</class_name>
<display_name>HPXML to OpenStudio Translator</display_name>
Expand Down Expand Up @@ -451,7 +451,7 @@
<filename>lighting.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>4D031B7F</checksum>
<checksum>A01BFB31</checksum>
</file>
<file>
<filename>location.rb</filename>
Expand Down Expand Up @@ -493,7 +493,7 @@
<filename>model.rb</filename>
<filetype>rb</filetype>
<usage_type>resource</usage_type>
<checksum>632A2E7B</checksum>
<checksum>51B1D207</checksum>
</file>
<file>
<filename>output.rb</filename>
Expand Down Expand Up @@ -793,7 +793,7 @@
<filename>test_lighting.rb</filename>
<filetype>rb</filetype>
<usage_type>test</usage_type>
<checksum>7EA417E4</checksum>
<checksum>207E7273</checksum>
</file>
<file>
<filename>test_location.rb</filename>
Expand Down
24 changes: 17 additions & 7 deletions HPXMLtoOpenStudio/resources/lighting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ module Lighting
def self.apply(runner, model, spaces, hpxml_bldg, hpxml_header, schedules_file)
lighting_groups = hpxml_bldg.lighting_groups
lighting = hpxml_bldg.lighting
unit_multiplier = hpxml_bldg.building_construction.number_of_units
cfa = hpxml_bldg.building_construction.conditioned_floor_area
eri_version = hpxml_header.eri_calculation_versions[0]
n_occ = hpxml_bldg.building_occupancy.number_of_residents
Expand Down Expand Up @@ -53,7 +52,6 @@ def self.apply(runner, model, spaces, hpxml_bldg, hpxml_header, schedules_file)
end
ext_kwh = 0.0 if ext_kwh.nil? || n_occ == 0
ext_kwh *= lighting.exterior_usage_multiplier unless lighting.exterior_usage_multiplier.nil?
ext_kwh *= unit_multiplier # Not in a thermal zone, so needs to be explicitly multiplied

# Calculate garage lighting kWh/yr
gfa = 0 # Garage floor area
Expand Down Expand Up @@ -159,12 +157,18 @@ def self.apply(runner, model, spaces, hpxml_bldg, hpxml_header, schedules_file)
runner.registerWarning("Both '#{exterior_col_name}' schedule file and monthly multipliers provided; the latter will be ignored.") if !lighting.exterior_monthly_multipliers.nil?
end

Model.add_lights(
# Note: We use ElectricEquipment instead of ExteriorLights so we can
# associate exterior lights with individual dwelling units for reporting.
# See https://github.com/NatLabRockies/OpenStudio-HPXML/pull/2163
Model.add_electric_equipment(
model,
name: exterior_obj_name,
end_use: exterior_obj_name,
space: nil,
space: spaces[HPXML::LocationConditionedSpace],
design_level: design_level,
frac_radiant: 0,
frac_latent: 0,
frac_lost: 1,
schedule: exterior_sch
)
end
Expand All @@ -176,7 +180,7 @@ def self.apply(runner, model, spaces, hpxml_bldg, hpxml_header, schedules_file)
exterior_holiday_sch = nil
exterior_holiday_col_name = SchedulesFile::Columns[:LightingExteriorHoliday].name
exterior_holiday_obj_name = Constants::ObjectTypeLightingExteriorHoliday
exterior_holiday_kwh_per_day = lighting.holiday_kwh_per_day * unit_multiplier
exterior_holiday_kwh_per_day = lighting.holiday_kwh_per_day
if not schedules_file.nil?
design_level = schedules_file.calc_design_level_from_daily_kwh(col_name: exterior_holiday_col_name, daily_kwh: exterior_holiday_kwh_per_day)
exterior_holiday_sch = schedules_file.create_schedule_file(model, col_name: exterior_holiday_col_name)
Expand All @@ -192,12 +196,18 @@ def self.apply(runner, model, spaces, hpxml_bldg, hpxml_header, schedules_file)
runner.registerWarning("Both '#{exterior_holiday_col_name}' schedule file and monthly multipliers provided; the latter will be ignored.") if !lighting.exterior_monthly_multipliers.nil?
end

Model.add_lights(
# Note: We use ElectricEquipment instead of ExteriorLights so we can
# associate exterior lights with individual dwelling units for reporting.
# See https://github.com/NatLabRockies/OpenStudio-HPXML/pull/2163
Model.add_electric_equipment(
model,
name: exterior_holiday_obj_name,
end_use: exterior_holiday_obj_name,
space: nil,
space: spaces[HPXML::LocationConditionedSpace],
design_level: design_level,
frac_radiant: 0,
frac_latent: 0,
frac_lost: 1,
schedule: exterior_holiday_sch
)
end
Expand Down
28 changes: 11 additions & 17 deletions HPXMLtoOpenStudio/resources/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -222,31 +222,25 @@ def self.add_other_equipment(model, name:, end_use:, space:, design_level:, frac
return oe
end

# Adds a Lights or ExteriorLights object to the OpenStudio model.
# Adds a Lights object to the OpenStudio model.
#
# The Lights/ExteriorLights objects model electric lighting in a zone or outside.
# The Lights object models electric lighting in a zone.
#
# @param model [OpenStudio::Model::Model] OpenStudio Model object
# @param name [String] Name for the OpenStudio object
# @param end_use [String] Name of the end use subcategory for output processing
# @param space [OpenStudio::Model::Space] The space the object is added to, or nil if exterior lighting
# @param space [OpenStudio::Model::Space] The space the object is added to
# @param design_level [Double] Maximum electrical power input (W)
# @param schedule [OpenStudio::Model::Schedule] Schedule fraction (or multiplier) that applies to the design level
# @return [OpenStudio::Model::Lights or OpenStudio::Model::ExteriorLights] The model object
# @return [OpenStudio::Model::Lights] The model object
def self.add_lights(model, name:, end_use:, space:, design_level:, schedule:)
if space.nil?
ltg_def = OpenStudio::Model::ExteriorLightsDefinition.new(model)
ltg = OpenStudio::Model::ExteriorLights.new(ltg_def)
ltg_def.setDesignLevel(design_level)
else
ltg_def = OpenStudio::Model::LightsDefinition.new(model)
ltg = OpenStudio::Model::Lights.new(ltg_def)
ltg.setSpace(space)
ltg_def.setLightingLevel(design_level)
ltg_def.setFractionRadiant(0.6)
ltg_def.setFractionVisible(0.2)
ltg_def.setReturnAirFraction(0.0)
end
ltg_def = OpenStudio::Model::LightsDefinition.new(model)
ltg = OpenStudio::Model::Lights.new(ltg_def)
ltg.setSpace(space)
ltg_def.setLightingLevel(design_level)
ltg_def.setFractionRadiant(0.6)
ltg_def.setFractionVisible(0.2)
ltg_def.setReturnAirFraction(0.0)
ltg.setName(name)
ltg.setEndUseSubcategory(end_use)
ltg.setSchedule(schedule)
Expand Down
7 changes: 0 additions & 7 deletions HPXMLtoOpenStudio/tests/test_lighting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,6 @@ def get_kwh_per_year(model, name)
kwh_yr = UnitConversions.convert(hrs * ltg.lightingLevel.get * ltg.multiplier * ltg.space.get.multiplier, 'Wh', 'kWh')
return kwh_yr
end
model.getExteriorLightss.each do |ltg|
next unless ltg.name.to_s == name

hrs = Schedule.annual_equivalent_full_load_hrs(model.yearDescription.get.assumedYear, ltg.schedule.get)
kwh_yr = UnitConversions.convert(hrs * ltg.exteriorLightsDefinition.designLevel * ltg.multiplier, 'Wh', 'kWh')
return kwh_yr
end
model.getElectricEquipments.each do |ee|
next unless ee.name.to_s.include?(name)

Expand Down
36 changes: 17 additions & 19 deletions ReportSimulationOutput/measure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3027,15 +3027,15 @@ def get_object_outputs_by_key(model, object, class_type)
fuel = object.to_WaterHeaterStratified.get.heaterFuelType
return { [to_ft[fuel], EUT::HotWater] => ["Water Heater #{fuel} Energy", 'Water Heater Off Cycle Parasitic Electricity Energy', 'Water Heater On Cycle Parasitic Electricity Energy'] }

elsif object.to_ExteriorLights.is_initialized
subcategory = object.to_ExteriorLights.get.endUseSubcategory
return { [FT::Elec, EUT::LightsExterior] => ["#{subcategory}:ExteriorLights:Electricity"] }

elsif object.to_Lights.is_initialized
subcategory = object.to_Lights.get.endUseSubcategory
object = object.to_Lights.get
subcategory = object.endUseSubcategory
end_use = { Constants::ObjectTypeLightingInterior => EUT::LightsInterior,
Constants::ObjectTypeLightingGarage => EUT::LightsGarage }[subcategory]
return { [FT::Elec, end_use] => ["#{subcategory}:InteriorLights:Electricity"] }
fail 'Unexpected error: InteriorLights:Electricity without a space.' unless object.space.is_initialized

zone_name = object.space.get.thermalZone.get.name.to_s.upcase
return { [FT::Elec, end_use] => ["#{subcategory}:InteriorLights:Electricity:Zone:#{zone_name}"] }

elsif object.to_ElectricLoadCenterInverterPVWatts.is_initialized
return { [FT::Elec, EUT::PV] => ['Inverter Conversion Loss Decrement Energy'] }
Expand Down Expand Up @@ -3078,7 +3078,9 @@ def get_object_outputs_by_key(model, object, class_type)
Constants::ObjectTypeMiscPermanentSpaHeater => EUT::PermanentSpaHeater,
Constants::ObjectTypeMiscPermanentSpaPump => EUT::PermanentSpaPump,
Constants::ObjectTypeMiscElectricVehicleCharging => EUT::Vehicle,
Constants::ObjectTypeMiscWellPump => EUT::WellPump }.each do |obj_name, eut|
Constants::ObjectTypeMiscWellPump => EUT::WellPump,
Constants::ObjectTypeLightingExterior => EUT::LightsExterior,
Constants::ObjectTypeLightingExteriorHoliday => EUT::LightsExterior }.each do |obj_name, eut|
next unless subcategory.start_with? obj_name
fail 'Unexpected error: multiple matches.' unless end_use.nil?

Expand All @@ -3087,12 +3089,10 @@ def get_object_outputs_by_key(model, object, class_type)

if not end_use.nil?
# Use Output:Meter instead of Output:Variable because they incorporate thermal zone multipliers
if object.space.is_initialized
zone_name = object.space.get.thermalZone.get.name.to_s.upcase
return { [FT::Elec, end_use] => ["#{subcategory}:InteriorEquipment:Electricity:Zone:#{zone_name}"] }
else
return { [FT::Elec, end_use] => ["#{subcategory}:InteriorEquipment:Electricity"] }
end
fail 'Unexpected error: InteriorEquipment:Electricity without a space.' unless object.space.is_initialized

zone_name = object.space.get.thermalZone.get.name.to_s.upcase
return { [FT::Elec, end_use] => ["#{subcategory}:InteriorEquipment:Electricity:Zone:#{zone_name}"] }
end

elsif object.to_OtherEquipment.is_initialized
Expand Down Expand Up @@ -3121,12 +3121,10 @@ def get_object_outputs_by_key(model, object, class_type)

if not end_use.nil?
# Use Output:Meter instead of Output:Variable because they incorporate thermal zone multipliers
if object.space.is_initialized
zone_name = object.space.get.thermalZone.get.name.to_s.upcase
return { [to_ft[fuel], end_use] => ["#{subcategory}:InteriorEquipment:#{fuel}:Zone:#{zone_name}"] }
else
return { [to_ft[fuel], end_use] => ["#{subcategory}:InteriorEquipment:#{fuel}"] }
end
fail "Unexpected error: InteriorEquipment:#{fuel} without a space." unless object.space.is_initialized

zone_name = object.space.get.thermalZone.get.name.to_s.upcase
return { [to_ft[fuel], end_use] => ["#{subcategory}:InteriorEquipment:#{fuel}:Zone:#{zone_name}"] }
end

elsif object.to_ZoneHVACDehumidifierDX.is_initialized
Expand Down
6 changes: 3 additions & 3 deletions ReportSimulationOutput/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>report_simulation_output</name>
<uid>df9d170c-c21a-4130-866d-0d46b06073fd</uid>
<version_id>d76d957c-7907-4943-8c57-e95fddc1327e</version_id>
<version_modified>2026-02-05T20:24:39Z</version_modified>
<version_id>6fd7c052-cf6c-4e9a-ab39-130c58f76864</version_id>
<version_modified>2026-02-16T17:51:26Z</version_modified>
<xml_checksum>9BF1E6AC</xml_checksum>
<class_name>ReportSimulationOutput</class_name>
<display_name>HPXML Simulation Output Report</display_name>
Expand Down Expand Up @@ -1991,7 +1991,7 @@
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>583EF2A9</checksum>
<checksum>96158F61</checksum>
</file>
<file>
<filename>test_report_sim_output.rb</filename>
Expand Down