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
2 changes: 2 additions & 0 deletions lib/BOSS/boss.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ def write_baseline_osw(xml_file_path, output_dir, epw_file_path, standard_to_be_

OSWArgPopulator::populate_set_lighting_loads_by_LPD_args(baseline_osw, bsync_reader)
OSWArgPopulator::populate_set_electric_equipment_loads_by_epd_args(baseline_osw, bsync_reader)
OSWArgPopulator::populate_replace_baseline_windows_args(baseline_osw, bsync_reader)

OSWArgPopulator::populate_openstudio_results_args(baseline_osw, bsync_reader)

# Gather extension-derived paths (typically gem-based measures/files) from ObjectSpace.
Expand Down
47 changes: 47 additions & 0 deletions lib/BOSS/buildingsync_reader/buildingsync_reader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -310,5 +310,52 @@ def get_total_weighted_average_load
return nil if !all_weighted_average_loads.all?
return all_weighted_average_loads.map {|s| s.to_f}.sum
end

# first valid window that has all mappable fields
def get_window_data
# if no windows, return nil
fenestration_systems = @facility_xml.elements.each("#{@ns}Systems/#{@ns}FenestrationSystems/#{@ns}FenestrationSystem") {|s| s}
return nil if fenestration_systems.nil?

# get all windows
windows = fenestration_systems.select {|fs| fs.elements["#{@ns}FenestrationType/#{@ns}Window"] }
return nil if windows.empty?

# iter through windows until we get one with all the required fields
windows.each do |window|
# get data
fenestration_frame_material = window.elements["#{@ns}FenestrationFrameMaterial"]&.text
glass_type = window.elements["#{@ns}GlassType"]&.text
fenestration_glass_layers = window.elements["#{@ns}FenestrationGlassLayers"]&.text
solar_heat_gain_coefficient = window.elements["#{@ns}SolarHeatGainCoefficient"]&.text
visible_transmittance = window.elements["#{@ns}VisibleTransmittance"]&.text

# We only need one of fenestration_u_factor/fenestration_r_value
fenestration_u_factor = window.elements["#{@ns}FenestrationUFactor"]&.text
if fenestration_u_factor.nil?
fenestration_r_value = window.elements["#{@ns}FenestrationRValue"]&.text
if !fenestration_r_value.nil? then fenestration_u_factor = 1 / fenestration_r_value end
end

# map data
os_fenestration_frame_material = BuildingSyncToOSSystemMaps.get_frame_material_map[fenestration_frame_material.to_s]
os_glass_type = BuildingSyncToOSSystemMaps.get_glass_type_map[glass_type.to_s]
os_fenestration_glass_layers = BuildingSyncToOSSystemMaps.get_glass_layers_map[fenestration_glass_layers.to_s]

# return if we can use this one
if (
!os_fenestration_frame_material.nil? &&
!os_glass_type.nil? &&
!os_fenestration_glass_layers.nil? &&
!fenestration_u_factor.nil? &&
!solar_heat_gain_coefficient.nil? &&
!visible_transmittance.nil?
)
window_pane_type = [os_fenestration_glass_layers, os_glass_type, os_fenestration_frame_material].join(' - ')
return window_pane_type, fenestration_u_factor, solar_heat_gain_coefficient, visible_transmittance
end
end
return nil
end
end
end
38 changes: 38 additions & 0 deletions lib/BOSS/buildingsync_reader/systems_map.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,42 @@ def self.get_hvac_map
"Other" => ""
}
end

def self.get_glass_layers_map
return {
"Single pane" => "Single",
"Double pane" => "Double",
"Triple pane" => "Triple",
"Single paned with storm panel" => "Single",
}
end

def self.get_glass_type_map
return {
"Clear uncoated" => "No LowE - Clear",
"Low e" => "LowE - Clear",
"Tinted" => "No LowE - Tinted/Reflective",
"Tinted plus low e" => "LowE - Tinted/Reflective",
"Reflective" => "No LowE - Tinted/Reflective",
"Reflective on tint" => "No LowE - Tinted/Reflective",
"High performance tint" => "LowE - Tinted/Reflective",
"Sunbelt low E low SHGC" => "LowE - Tinted/Reflective",
# "Suspended film" => "",
# "Plastic" => "",
}
end

def self.get_frame_material_map
return {
"Aluminum uncategorized" => "Aluminum",
"Aluminum no thermal break" => "Aluminum",
"Aluminum thermal break" => "Thermally Broken Aluminum",
# "Clad" => "",
# "Composite" => "",
# "Fiberglass" => "",
# "Steel" => "",
# "Vinyl" => "",
"Wood" => "Wood",
}
end
end
22 changes: 22 additions & 0 deletions lib/BOSS/osw_arg_populator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,28 @@ def self.populate_set_electric_equipment_loads_by_epd_args(osw, bsync_reader)
# om_frequency
end

def self.populate_replace_baseline_windows_args(osw, bsync_reader)
osw[:steps].append({"measure_dir_name": "replace_baseline_windows", "arguments": {}})
set_measure_argument = lambda {| key, value | OpenStudio::Extension.set_measure_argument(osw, "replace_baseline_windows", key, value) }

# skip if no window_data
window_data = bsync_reader.get_window_data
if window_data.nil?
set_measure_argument.call("__SKIP__", true)
return
end
window_pane_type, fenestration_u_factor, solar_heat_gain_coefficient, visible_transmittance = window_data

# Add args
# - __SKIP__
set_measure_argument.call("__SKIP__", false)
set_measure_argument.call("window_pane_type", window_pane_type)
set_measure_argument.call("u_value_ip", fenestration_u_factor)
set_measure_argument.call("shgc", solar_heat_gain_coefficient)
set_measure_argument.call("vlt", visible_transmittance)

end

def self.populate_openstudio_results_args(osw, bsync_reader)
osw[:steps].append({"measure_dir_name": "openstudio_results", "arguments": {}})
set_measure_argument = lambda {| key, value | OpenStudio::Extension.set_measure_argument(osw, "openstudio_results", key, value) }
Expand Down
166 changes: 148 additions & 18 deletions spec/tests/unit/buildingsync_reader_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ def wrap_in_site(xml)
XML
end

def wrap_in_systems(xml)
<<~XML
<BuildingSync>
<Facilities>
<Facility>
<Sites>
<Site>
</Site>
</Sites>
<Systems>
#{xml}
</Systems>
</Facility>
</Facilities>
</BuildingSync>
XML
end

RSpec.describe 'BuildingSyncReader' do
describe 'get_climate_zone should' do
it "get from site" do
Expand Down Expand Up @@ -334,24 +352,6 @@ def wrap_in_systems(xml)
end

describe 'get_total_weighted_average_load should' do
def wrap_in_systems(xml)
<<~XML
<BuildingSync>
<Facilities>
<Facility>
<Sites>
<Site>
</Site>
</Sites>
<Systems>
#{xml}
</Systems>
</Facility>
</Facilities>
</BuildingSync>
XML
end

it "sum weighted average load" do
# Set Up
doc = REXML::Document.new wrap_in_systems(<<~XML)
Expand Down Expand Up @@ -423,4 +423,134 @@ def wrap_in_systems(xml)
expect(buidingsync_reader.get_total_weighted_average_load).to eq nil
end
end

describe 'get_window_data should' do
good_window = <<~XML
<FenestrationSystem ID='1' xmlns:auc=\"http://buildingsync.net/schemas/bedes-auc/2019\">
<FenestrationType>
<Window/>
</FenestrationType>
<FenestrationFrameMaterial>Aluminum no thermal break</FenestrationFrameMaterial>
<FenestrationOperation>false</FenestrationOperation>
<TightnessFitCondition>Average</TightnessFitCondition>
<GlassType>Clear uncoated</GlassType>
<FenestrationGlassLayers>Single pane</FenestrationGlassLayers>
<SolarHeatGainCoefficient>0.391000</SolarHeatGainCoefficient>
<VisibleTransmittance>0.391000</VisibleTransmittance>
<FenestrationUFactor>3.241000</FenestrationUFactor>
</FenestrationSystem>
XML
invalid_window = <<~XML
<FenestrationSystem ID='2' xmlns:auc=\"http://buildingsync.net/schemas/bedes-auc/2019\">
<FenestrationType>
<Window/>
</FenestrationType>
<FenestrationFrameMaterial>Fiberglass</FenestrationFrameMaterial>
<FenestrationOperation>false</FenestrationOperation>
<TightnessFitCondition>Average</TightnessFitCondition>
<GlassType>Clear uncoated</GlassType>
<FenestrationGlassLayers>Single pane</FenestrationGlassLayers>
<SolarHeatGainCoefficient>0.391000</SolarHeatGainCoefficient>
<VisibleTransmittance>0.391000</VisibleTransmittance>
<FenestrationUFactor>3.241000</FenestrationUFactor>
</FenestrationSystem>
XML
door = <<~XML
<FenestrationSystem ID=\"FenestrationSystemType-45021100\">
<FenestrationType>
<Door>
<ExteriorDoorType>Uninsulated metal</ExteriorDoorType>
</Door>
</FenestrationType>
</FenestrationSystem>
XML

it "work in happy case" do
# Set Up
doc = REXML::Document.new wrap_in_systems(<<~XML)
<FenestrationSystems>
#{good_window}
</FenestrationSystems>
XML

# Action
buidingsync_reader = BOSS::BuildingSyncReader.new(doc, nil, ASHRAE90_1)
window_pane_type, fenestration_u_factor, solar_heat_gain_coefficient, visible_transmittance = buidingsync_reader.get_window_data

# Assertion
expect(window_pane_type).to eq "Single - No LowE - Clear - Aluminum"
expect(fenestration_u_factor).to eq "3.241000"
expect(solar_heat_gain_coefficient).to eq "0.391000"
expect(visible_transmittance).to eq "0.391000"
end

it "ignore doors and skylights" do
# Set Up
doc = REXML::Document.new wrap_in_systems(<<~XML)
<FenestrationSystems>
#{door}
#{good_window}
</FenestrationSystems>
XML

# Action
buidingsync_reader = BOSS::BuildingSyncReader.new(doc, nil, ASHRAE90_1)
window_pane_type, fenestration_u_factor, solar_heat_gain_coefficient, visible_transmittance = buidingsync_reader.get_window_data

# Assertion
expect(window_pane_type).to eq "Single - No LowE - Clear - Aluminum"
expect(fenestration_u_factor).to eq "3.241000"
expect(solar_heat_gain_coefficient).to eq "0.391000"
expect(visible_transmittance).to eq "0.391000"
end

it "work if first window is invalid but second isnt" do
# Set Up
doc = REXML::Document.new wrap_in_systems(<<~XML)
<FenestrationSystems>
#{invalid_window}
#{good_window}
</FenestrationSystems>
XML

# Action
buidingsync_reader = BOSS::BuildingSyncReader.new(doc, nil, ASHRAE90_1)
window_pane_type, fenestration_u_factor, solar_heat_gain_coefficient, visible_transmittance = buidingsync_reader.get_window_data

# Assertion
expect(window_pane_type).to eq "Single - No LowE - Clear - Aluminum"
expect(fenestration_u_factor).to eq "3.241000"
expect(solar_heat_gain_coefficient).to eq "0.391000"
expect(visible_transmittance).to eq "0.391000"
end

it "return nil if there are no windows" do
# Set Up
doc = REXML::Document.new wrap_in_systems("")

# Action
buidingsync_reader = BOSS::BuildingSyncReader.new(doc, nil, ASHRAE90_1)
window_pane_type, fenestration_u_factor, solar_heat_gain_coefficient, visible_transmittance = buidingsync_reader.get_window_data

# Assertion
expect(window_pane_type).to eq nil
end

# warn not error
it "return nil if all windows are invalid" do
# Set Up
doc = REXML::Document.new wrap_in_systems(<<~XML)
<FenestrationSystems>
#{invalid_window}
</FenestrationSystems>
XML

# Action
buidingsync_reader = BOSS::BuildingSyncReader.new(doc, nil, ASHRAE90_1)
window_pane_type, fenestration_u_factor, solar_heat_gain_coefficient, visible_transmittance = buidingsync_reader.get_window_data

# Assertion
expect(window_pane_type).to eq nil
end
end
end
Loading