example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/constructions.rb in urbanopt-cli-0.6.4 vs example_files/resources/hpxml-measures/HPXMLtoOpenStudio/resources/constructions.rb in urbanopt-cli-0.7.0

- old
+ new

@@ -1,41 +1,41 @@ # frozen_string_literal: true class Constructions # Container class for walls, floors/ceilings, roofs, etc. - def self.apply_wood_stud_wall(runner, model, surfaces, wall, constr_name, + def self.apply_wood_stud_wall(runner, model, surfaces, constr_name, cavity_r, install_grade, cavity_depth_in, cavity_filled, - framing_factor, drywall_thick_in, osb_thick_in, - rigid_r, mat_ext_finish, otherside_drywall_thick_in, - inside_film, outside_film) + framing_factor, mat_int_finish, osb_thick_in, + rigid_r, mat_ext_finish, inside_film, outside_film, + solar_absorptance = nil, emittance = nil) return if surfaces.empty? # Define materials if cavity_r > 0 if cavity_filled # Insulation - mat_cavity = Material.new(name = nil, thick_in = cavity_depth_in, mat_base = BaseMaterial.InsulationGenericDensepack, k_in = cavity_depth_in / cavity_r) + mat_cavity = Material.new(thick_in: cavity_depth_in, mat_base: BaseMaterial.InsulationGenericDensepack, k_in: cavity_depth_in / cavity_r) else # Insulation plus air gap when insulation thickness < cavity depth - mat_cavity = Material.new(name = nil, thick_in = cavity_depth_in, mat_base = BaseMaterial.InsulationGenericDensepack, k_in = cavity_depth_in / (cavity_r + Gas.AirGapRvalue)) + mat_cavity = Material.new(thick_in: cavity_depth_in, mat_base: BaseMaterial.InsulationGenericDensepack, k_in: cavity_depth_in / (cavity_r + Gas.AirGapRvalue)) end else # Empty cavity mat_cavity = Material.AirCavityClosed(cavity_depth_in) end - mat_framing = Material.new(name = nil, thick_in = cavity_depth_in, mat_base = BaseMaterial.Wood) + mat_framing = Material.new(thick_in: cavity_depth_in, mat_base: BaseMaterial.Wood) mat_gap = Material.AirCavityClosed(cavity_depth_in) mat_osb = nil if osb_thick_in > 0 - mat_osb = Material.new(name = 'WallSheathing', thick_in = osb_thick_in, mat_base = BaseMaterial.Wood) + mat_osb = Material.OSBSheathing(osb_thick_in) end mat_rigid = nil if rigid_r > 0 rigid_thick_in = rigid_r * BaseMaterial.InsulationRigid.k_in - mat_rigid = Material.new(name = 'WallRigidIns', thick_in = rigid_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = rigid_thick_in / rigid_r) + mat_rigid = Material.new(name: 'wall rigid ins', thick_in: rigid_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: rigid_thick_in / rigid_r) end # Set paths gapFactor = get_gap_factor(install_grade, framing_factor, cavity_r) path_fracs = [framing_factor, 1 - framing_factor - gapFactor, gapFactor] @@ -44,62 +44,64 @@ constr = Construction.new(constr_name, path_fracs) constr.add_layer(outside_film) if not mat_ext_finish.nil? constr.add_layer(mat_ext_finish) end - if otherside_drywall_thick_in > 0 # E.g., interior partition wall - constr.add_layer(Material.GypsumWall(otherside_drywall_thick_in)) - end if not mat_rigid.nil? constr.add_layer(mat_rigid) end if not mat_osb.nil? constr.add_layer(mat_osb) end - constr.add_layer([mat_framing, mat_cavity, mat_gap], 'WallStudAndCavity') - if drywall_thick_in > 0 - constr.add_layer(Material.GypsumWall(drywall_thick_in)) + constr.add_layer([mat_framing, mat_cavity, mat_gap], 'wall stud and cavity') + if not mat_int_finish.nil? + constr.add_layer(mat_int_finish) end constr.add_layer(inside_film) + constr.set_exterior_material_properties(solar_absorptance, emittance) + constr.set_interior_material_properties() + # Create and assign construction to surfaces constr.create_and_assign_constructions(runner, surfaces, model) end - def self.apply_double_stud_wall(runner, model, surfaces, wall, constr_name, + def self.apply_double_stud_wall(runner, model, surfaces, constr_name, cavity_r, install_grade, stud_depth_in, gap_depth_in, framing_factor, framing_spacing, is_staggered, - drywall_thick_in, osb_thick_in, rigid_r, - mat_ext_finish, inside_film, outside_film) + mat_int_finish, osb_thick_in, rigid_r, + mat_ext_finish, inside_film, outside_film, + solar_absorptance = nil, emittance = nil) return if surfaces.empty? # Define materials cavity_depth_in = 2.0 * stud_depth_in + gap_depth_in - mat_ins_inner_outer = Material.new(name = nil, thick_in = stud_depth_in, mat_base = BaseMaterial.InsulationGenericDensepack, k_in = cavity_depth_in / cavity_r) - mat_ins_middle = Material.new(name = nil, thick_in = gap_depth_in, mat_base = BaseMaterial.InsulationGenericDensepack, k_in = cavity_depth_in / cavity_r) - mat_framing_inner_outer = Material.new(name = nil, thick_in = stud_depth_in, mat_base = BaseMaterial.Wood) - mat_framing_middle = Material.new(name = nil, thick_in = gap_depth_in, mat_base = BaseMaterial.Wood) - mat_stud = Material.new(name = nil, thick_in = stud_depth_in, mat_base = BaseMaterial.Wood) + mat_ins_inner_outer = Material.new(thick_in: stud_depth_in, mat_base: BaseMaterial.InsulationGenericDensepack, k_in: cavity_depth_in / cavity_r) + mat_ins_middle = Material.new(thick_in: gap_depth_in, mat_base: BaseMaterial.InsulationGenericDensepack, k_in: cavity_depth_in / cavity_r) + mat_framing_inner_outer = Material.new(thick_in: stud_depth_in, mat_base: BaseMaterial.Wood) + mat_framing_middle = Material.new(thick_in: gap_depth_in, mat_base: BaseMaterial.Wood) + mat_stud = Material.new(thick_in: stud_depth_in, mat_base: BaseMaterial.Wood) mat_gap_total = Material.AirCavityClosed(cavity_depth_in) - mat_gap_inner_outer = Material.new(name = nil, thick_in = stud_depth_in, mat_base = nil, k_in = stud_depth_in / (mat_gap_total.rvalue * stud_depth_in / cavity_depth_in), rho = Gas.Air.rho, cp = Gas.Air.cp) - mat_gap_middle = Material.new(name = nil, thick_in = gap_depth_in, mat_base = nil, k_in = gap_depth_in / (mat_gap_total.rvalue * gap_depth_in / cavity_depth_in), rho = Gas.Air.rho, cp = Gas.Air.cp) + mat_gap_inner_outer = Material.new(thick_in: stud_depth_in, k_in: stud_depth_in / (mat_gap_total.rvalue * stud_depth_in / cavity_depth_in), rho: Gas.Air.rho, cp: Gas.Air.cp) + mat_gap_middle = Material.new(thick_in: gap_depth_in, k_in: gap_depth_in / (mat_gap_total.rvalue * gap_depth_in / cavity_depth_in), rho: Gas.Air.rho, cp: Gas.Air.cp) mat_osb = nil if osb_thick_in > 0 - mat_osb = Material.new(name = 'WallSheathing', thick_in = osb_thick_in, mat_base = BaseMaterial.Wood) + mat_osb = Material.OSBSheathing(osb_thick_in) end mat_rigid = nil if rigid_r > 0 rigid_thick_in = rigid_r * BaseMaterial.InsulationRigid.k_in - mat_rigid = Material.new(name = 'WallRigidIns', thick_in = rigid_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = rigid_thick_in / rigid_r) + mat_rigid = Material.new(name: 'wall rigid ins', thick_in: rigid_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: rigid_thick_in / rigid_r) end # Set paths stud_frac = 1.5 / framing_spacing misc_framing_factor = framing_factor - stud_frac if misc_framing_factor < 0 - fail "Framing Factor (#{framing_factor}) is less than the framing solely provided by the studs (#{stud_frac})." + stud_frac = framing_factor + misc_framing_factor = 0.0 end dsGapFactor = get_gap_factor(install_grade, framing_factor, cavity_r) path_fracs = [misc_framing_factor, stud_frac, stud_frac, dsGapFactor, (1.0 - (2 * stud_frac + misc_framing_factor + dsGapFactor))] @@ -114,56 +116,60 @@ end if not mat_osb.nil? constr.add_layer(mat_osb) end if is_staggered - constr.add_layer([mat_framing_inner_outer, mat_ins_inner_outer, mat_stud, mat_gap_inner_outer, mat_ins_inner_outer], 'WallStudandCavityOuter') + constr.add_layer([mat_framing_inner_outer, mat_ins_inner_outer, mat_stud, mat_gap_inner_outer, mat_ins_inner_outer], 'wall stud and cavity') else - constr.add_layer([mat_framing_inner_outer, mat_stud, mat_ins_inner_outer, mat_gap_inner_outer, mat_ins_inner_outer], 'WallStudandCavityOuter') + constr.add_layer([mat_framing_inner_outer, mat_stud, mat_ins_inner_outer, mat_gap_inner_outer, mat_ins_inner_outer], 'wall stud and cavity') end if gap_depth_in > 0 - constr.add_layer([mat_framing_middle, mat_ins_middle, mat_ins_middle, mat_gap_middle, mat_ins_middle], 'WallCavity') + constr.add_layer([mat_framing_middle, mat_ins_middle, mat_ins_middle, mat_gap_middle, mat_ins_middle], 'wall cavity') end - constr.add_layer([mat_framing_inner_outer, mat_stud, mat_ins_inner_outer, mat_gap_inner_outer, mat_ins_inner_outer], 'WallStudandCavityInner') - if drywall_thick_in > 0 - constr.add_layer(Material.GypsumWall(drywall_thick_in)) + constr.add_layer([mat_framing_inner_outer, mat_stud, mat_ins_inner_outer, mat_gap_inner_outer, mat_ins_inner_outer], 'wall stud and cavity') + if not mat_int_finish.nil? + constr.add_layer(mat_int_finish) end constr.add_layer(inside_film) + constr.set_exterior_material_properties(solar_absorptance, emittance) + constr.set_interior_material_properties() + # Create and assign construction to surfaces constr.create_and_assign_constructions(runner, surfaces, model) end - def self.apply_cmu_wall(runner, model, surfaces, wall, constr_name, + def self.apply_cmu_wall(runner, model, surfaces, constr_name, thick_in, conductivity, density, framing_factor, furring_r, furring_cavity_depth, furring_spacing, - drywall_thick_in, osb_thick_in, rigid_r, - mat_ext_finish, inside_film, outside_film) + mat_int_finish, osb_thick_in, rigid_r, + mat_ext_finish, inside_film, outside_film, + solar_absorptance = nil, emittance = nil) return if surfaces.empty? # Define materials - mat_cmu = Material.new(name = nil, thick_in = thick_in, mat_base = BaseMaterial.Concrete, k_in = conductivity, rho = density) - mat_framing = Material.new(name = nil, thick_in = thick_in, mat_base = BaseMaterial.Wood) + mat_cmu = Material.new(thick_in: thick_in, mat_base: BaseMaterial.Concrete, k_in: conductivity, rho: density) + mat_framing = Material.new(thick_in: thick_in, mat_base: BaseMaterial.Wood) mat_furring = nil mat_furring_cavity = nil if furring_cavity_depth != 0 - mat_furring = Material.new(name = nil, thick_in = furring_cavity_depth, mat_base = BaseMaterial.Wood) + mat_furring = Material.new(thick_in: furring_cavity_depth, mat_base: BaseMaterial.Wood) if furring_r == 0 mat_furring_cavity = Material.AirCavityClosed(furring_cavity_depth) else - mat_furring_cavity = Material.new(name = nil, thick_in = furring_cavity_depth, mat_base = BaseMaterial.InsulationGenericDensepack, k_in = furring_cavity_depth / furring_r) + mat_furring_cavity = Material.new(thick_in: furring_cavity_depth, mat_base: BaseMaterial.InsulationGenericDensepack, k_in: furring_cavity_depth / furring_r) end end mat_osb = nil if osb_thick_in > 0 - mat_osb = Material.new(name = 'WallSheathing', thick_in = osb_thick_in, mat_base = BaseMaterial.Wood) + mat_osb = Material.OSBSheathing(osb_thick_in) end mat_rigid = nil if rigid_r > 0 rigid_thick_in = rigid_r * BaseMaterial.InsulationRigid.k_in - mat_rigid = Material.new(name = 'WallRigidIns', thick_in = rigid_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = rigid_thick_in / rigid_r) + mat_rigid = Material.new(name: 'wall rigid ins', thick_in: rigid_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: rigid_thick_in / rigid_r) end # Set paths if not mat_furring.nil? stud_frac = 1.5 / furring_spacing @@ -184,44 +190,48 @@ end if not mat_osb.nil? constr.add_layer(mat_osb) end if not mat_furring.nil? - constr.add_layer([mat_framing, mat_cmu, mat_cmu], 'WallCMU') - constr.add_layer([mat_furring, mat_furring, mat_furring_cavity], 'WallFurring') + constr.add_layer([mat_framing, mat_cmu, mat_cmu], 'concrete block') + constr.add_layer([mat_furring, mat_furring, mat_furring_cavity], 'furring') else - constr.add_layer([mat_framing, mat_cmu], 'WallCMU') + constr.add_layer([mat_framing, mat_cmu], 'concrete block') end - if drywall_thick_in > 0 - constr.add_layer(Material.GypsumWall(drywall_thick_in)) + if not mat_int_finish.nil? + constr.add_layer(mat_int_finish) end constr.add_layer(inside_film) + constr.set_exterior_material_properties(solar_absorptance, emittance) + constr.set_interior_material_properties() + # Create and assign construction to surfaces constr.create_and_assign_constructions(runner, surfaces, model) end - def self.apply_icf_wall(runner, model, surfaces, wall, constr_name, + def self.apply_icf_wall(runner, model, surfaces, constr_name, icf_r, ins_thick_in, concrete_thick_in, framing_factor, - drywall_thick_in, osb_thick_in, rigid_r, - mat_ext_finish, inside_film, outside_film) + mat_int_finish, osb_thick_in, rigid_r, + mat_ext_finish, inside_film, outside_film, + solar_absorptance = nil, emittance = nil) return if surfaces.empty? # Define materials - mat_ins = Material.new(name = nil, thick_in = ins_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = ins_thick_in / icf_r) - mat_conc = Material.new(name = nil, thick_in = concrete_thick_in, mat_base = BaseMaterial.Concrete) - mat_framing_inner_outer = Material.new(name = nil, thick_in = ins_thick_in, mat_base = BaseMaterial.Wood) - mat_framing_middle = Material.new(name = nil, thick_in = concrete_thick_in, mat_base = BaseMaterial.Wood) + mat_ins = Material.new(thick_in: ins_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: ins_thick_in / icf_r) + mat_conc = Material.new(thick_in: concrete_thick_in, mat_base: BaseMaterial.Concrete) + mat_framing_inner_outer = Material.new(thick_in: ins_thick_in, mat_base: BaseMaterial.Wood) + mat_framing_middle = Material.new(thick_in: concrete_thick_in, mat_base: BaseMaterial.Wood) mat_osb = nil if osb_thick_in > 0 - mat_osb = Material.new(name = 'WallSheathing', thick_in = osb_thick_in, mat_base = BaseMaterial.Wood) + mat_osb = Material.OSBSheathing(osb_thick_in) end mat_rigid = nil if rigid_r > 0 rigid_thick_in = rigid_r * BaseMaterial.InsulationRigid.k_in - mat_rigid = Material.new(name = 'WallRigidIns', thick_in = rigid_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = rigid_thick_in / rigid_r) + mat_rigid = Material.new(name: 'wall rigid ins', thick_in: rigid_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: rigid_thick_in / rigid_r) end # Set paths path_fracs = [framing_factor, 1.0 - framing_factor] @@ -235,46 +245,50 @@ constr.add_layer(mat_rigid) end if not mat_osb.nil? constr.add_layer(mat_osb) end - constr.add_layer([mat_framing_inner_outer, mat_ins], 'WallICFInsFormOuter') - constr.add_layer([mat_framing_middle, mat_conc], 'WallICFConcrete') - constr.add_layer([mat_framing_inner_outer, mat_ins], 'WallICFInsFormInner') - if drywall_thick_in > 0 - constr.add_layer(Material.GypsumWall(drywall_thick_in)) + constr.add_layer([mat_framing_inner_outer, mat_ins], 'wall ins form') + constr.add_layer([mat_framing_middle, mat_conc], 'wall concrete') + constr.add_layer([mat_framing_inner_outer, mat_ins], 'wall ins form') + if not mat_int_finish.nil? + constr.add_layer(mat_int_finish) end constr.add_layer(inside_film) + constr.set_exterior_material_properties(solar_absorptance, emittance) + constr.set_interior_material_properties() + # Create and assign construction to surfaces constr.create_and_assign_constructions(runner, surfaces, model) end - def self.apply_sip_wall(runner, model, surfaces, wall, constr_name, sip_r, + def self.apply_sip_wall(runner, model, surfaces, constr_name, sip_r, sip_thick_in, framing_factor, sheathing_thick_in, - drywall_thick_in, osb_thick_in, rigid_r, - mat_ext_finish, inside_film, outside_film) + mat_int_finish, osb_thick_in, rigid_r, + mat_ext_finish, inside_film, outside_film, + solar_absorptance = nil, emittance = nil) return if surfaces.empty? # Define materials spline_thick_in = 0.5 ins_thick_in = sip_thick_in - (2.0 * spline_thick_in) # in - mat_int_sheath = Material.new(name = 'WallIntSheathing', thick_in = sheathing_thick_in, mat_base = BaseMaterial.Wood) - mat_framing_inner_outer = Material.new(name = nil, thick_in = spline_thick_in, mat_base = BaseMaterial.Wood) - mat_framing_middle = Material.new(name = nil, thick_in = ins_thick_in, mat_base = BaseMaterial.Wood) - mat_spline = Material.new(name = nil, thick_in = spline_thick_in, mat_base = BaseMaterial.Wood) - mat_ins_inner_outer = Material.new(name = nil, thick_in = spline_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = sip_thick_in / sip_r) - mat_ins_middle = Material.new(name = nil, thick_in = ins_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = sip_thick_in / sip_r) + mat_int_sheath = Material.OSBSheathing(sheathing_thick_in) + mat_framing_inner_outer = Material.new(thick_in: spline_thick_in, mat_base: BaseMaterial.Wood) + mat_framing_middle = Material.new(thick_in: ins_thick_in, mat_base: BaseMaterial.Wood) + mat_spline = Material.new(thick_in: spline_thick_in, mat_base: BaseMaterial.Wood) + mat_ins_inner_outer = Material.new(thick_in: spline_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: sip_thick_in / sip_r) + mat_ins_middle = Material.new(thick_in: ins_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: sip_thick_in / sip_r) mat_osb = nil if osb_thick_in > 0 - mat_osb = Material.new(name = 'WallSheathing', thick_in = osb_thick_in, mat_base = BaseMaterial.Wood) + mat_osb = Material.OSBSheathing(osb_thick_in) end mat_rigid = nil if rigid_r > 0 rigid_thick_in = rigid_r * BaseMaterial.InsulationRigid.k_in - mat_rigid = Material.new(name = 'WallRigidIns', thick_in = rigid_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = rigid_thick_in / rigid_r) + mat_rigid = Material.new(name: 'wall rigid ins', thick_in: rigid_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: rigid_thick_in / rigid_r) end # Set paths spline_frac = 4.0 / 48.0 # One 4" spline for every 48" wide panel cavity_frac = 1.0 - (spline_frac + framing_factor) @@ -290,54 +304,58 @@ constr.add_layer(mat_rigid) end if not mat_osb.nil? constr.add_layer(mat_osb) end - constr.add_layer([mat_framing_inner_outer, mat_spline, mat_ins_inner_outer], 'WallSplineLayerOuter') - constr.add_layer([mat_framing_middle, mat_ins_middle, mat_ins_middle], 'WallIns') - constr.add_layer([mat_framing_inner_outer, mat_spline, mat_ins_inner_outer], 'WallSplineLayerInner') + constr.add_layer([mat_framing_inner_outer, mat_spline, mat_ins_inner_outer], 'wall spline layer') + constr.add_layer([mat_framing_middle, mat_ins_middle, mat_ins_middle], 'wall ins layer') + constr.add_layer([mat_framing_inner_outer, mat_spline, mat_ins_inner_outer], 'wall spline layer') constr.add_layer(mat_int_sheath) - if drywall_thick_in > 0 - constr.add_layer(Material.GypsumWall(drywall_thick_in)) + if not mat_int_finish.nil? + constr.add_layer(mat_int_finish) end constr.add_layer(inside_film) + constr.set_exterior_material_properties(solar_absorptance, emittance) + constr.set_interior_material_properties() + # Create and assign construction to surfaces constr.create_and_assign_constructions(runner, surfaces, model) end - def self.apply_steel_stud_wall(runner, model, surfaces, wall, constr_name, + def self.apply_steel_stud_wall(runner, model, surfaces, constr_name, cavity_r, install_grade, cavity_depth, cavity_filled, framing_factor, correction_factor, - drywall_thick_in, osb_thick_in, rigid_r, - mat_ext_finish, inside_film, outside_film) + mat_int_finish, osb_thick_in, rigid_r, + mat_ext_finish, inside_film, outside_film, + solar_absorptance = nil, emittance = nil) return if surfaces.empty? # Define materials eR = cavity_r * correction_factor # The effective R-value of the cavity insulation with steel stud framing if eR > 0 if cavity_filled # Insulation - mat_cavity = Material.new(name = nil, thick_in = cavity_depth, mat_base = BaseMaterial.InsulationGenericDensepack, k_in = cavity_depth / eR) + mat_cavity = Material.new(thick_in: cavity_depth, mat_base: BaseMaterial.InsulationGenericDensepack, k_in: cavity_depth / eR) else # Insulation plus air gap when insulation thickness < cavity depth - mat_cavity = Material.new(name = nil, thick_in = cavity_depth, mat_base = BaseMaterial.InsulationGenericDensepack, k_in = cavity_depth / (eR + Gas.AirGapRvalue)) + mat_cavity = Material.new(thick_in: cavity_depth, mat_base: BaseMaterial.InsulationGenericDensepack, k_in: cavity_depth / (eR + Gas.AirGapRvalue)) end else # Empty cavity mat_cavity = Material.AirCavityClosed(cavity_depth) end mat_gap = Material.AirCavityClosed(cavity_depth) mat_osb = nil if osb_thick_in > 0 - mat_osb = Material.new(name = 'WallSheathing', thick_in = osb_thick_in, mat_base = BaseMaterial.Wood) + mat_osb = Material.OSBSheathing(osb_thick_in) end mat_rigid = nil if rigid_r > 0 rigid_thick_in = rigid_r * BaseMaterial.InsulationRigid.k_in - mat_rigid = Material.new(name = 'WallRigidIns', thick_in = rigid_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = rigid_thick_in / rigid_r) + mat_rigid = Material.new(name: 'wall rigid ins', thick_in: rigid_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: rigid_thick_in / rigid_r) end # Set paths gapFactor = get_gap_factor(install_grade, framing_factor, cavity_r) path_fracs = [1 - gapFactor, gapFactor] @@ -352,24 +370,28 @@ constr.add_layer(mat_rigid) end if not mat_osb.nil? constr.add_layer(mat_osb) end - constr.add_layer([mat_cavity, mat_gap], 'WallStudAndCavity') - if drywall_thick_in > 0 - constr.add_layer(Material.GypsumWall(drywall_thick_in)) + constr.add_layer([mat_cavity, mat_gap], 'wall stud and cavity') + if not mat_int_finish.nil? + constr.add_layer(mat_int_finish) end constr.add_layer(inside_film) + constr.set_exterior_material_properties(solar_absorptance, emittance) + constr.set_interior_material_properties() + # Create and assign construction to surfaces constr.create_and_assign_constructions(runner, surfaces, model) end - def self.apply_generic_layered_wall(runner, model, surfaces, wall, constr_name, + def self.apply_generic_layered_wall(runner, model, surfaces, constr_name, thick_ins, conds, denss, specheats, - drywall_thick_in, osb_thick_in, rigid_r, - mat_ext_finish, inside_film, outside_film) + mat_int_finish, osb_thick_in, rigid_r, + mat_ext_finish, inside_film, outside_film, + solar_absorptance = nil, emittance = nil) return if surfaces.empty? # Validate inputs for idx in 0..4 @@ -378,31 +400,31 @@ end end # Define materials mats = [] - mats << Material.new(name = 'WallLayer1', thick_in = thick_ins[0], mat_base = nil, k_in = conds[0], rho = denss[0], cp = specheats[0]) + mats << Material.new(name: 'wall layer 1', thick_in: thick_ins[0], k_in: conds[0], rho: denss[0], cp: specheats[0]) if not thick_ins[1].nil? - mats << Material.new(name = 'WallLayer2', thick_in = thick_ins[1], mat_base = nil, k_in = conds[1], rho = denss[1], cp = specheats[1]) + mats << Material.new(name: 'wall layer 2', thick_in: thick_ins[1], k_in: conds[1], rho: denss[1], cp: specheats[1]) end if not thick_ins[2].nil? - mats << Material.new(name = 'WallLayer3', thick_in = thick_ins[2], mat_base = nil, k_in = conds[2], rho = denss[2], cp = specheats[2]) + mats << Material.new(name: 'wall layer 3', thick_in: thick_ins[2], k_in: conds[2], rho: denss[2], cp: specheats[2]) end if not thick_ins[3].nil? - mats << Material.new(name = 'WallLayer4', thick_in = thick_ins[3], mat_base = nil, k_in = conds[3], rho = denss[3], cp = specheats[3]) + mats << Material.new(name: 'wall layer 4', thick_in: thick_ins[3], k_in: conds[3], rho: denss[3], cp: specheats[3]) end if not thick_ins[4].nil? - mats << Material.new(name = 'WallLayer5', thick_in = thick_ins[4], mat_base = nil, k_in = conds[4], rho = denss[4], cp = specheats[4]) + mats << Material.new(name: 'wall layer 5', thick_in: thick_ins[4], k_in: conds[4], rho: denss[4], cp: specheats[4]) end mat_osb = nil if osb_thick_in > 0 - mat_osb = Material.new(name = 'WallSheathing', thick_in = osb_thick_in, mat_base = BaseMaterial.Wood) + mat_osb = Material.OSBSheathing(osb_thick_in) end mat_rigid = nil if rigid_r > 0 rigid_thick_in = rigid_r * BaseMaterial.InsulationRigid.k_in - mat_rigid = Material.new(name = 'WallRigidIns', thick_in = rigid_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = rigid_thick_in / rigid_r) + mat_rigid = Material.new(name: 'wall rigid ins', thick_in: rigid_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: rigid_thick_in / rigid_r) end # Set paths path_fracs = [1] @@ -419,48 +441,51 @@ constr.add_layer(mat_osb) end mats.each do |mat| constr.add_layer(mat) end - if drywall_thick_in > 0 - constr.add_layer(Material.GypsumWall(drywall_thick_in)) + if not mat_int_finish.nil? + constr.add_layer(mat_int_finish) end constr.add_layer(inside_film) + constr.set_exterior_material_properties(solar_absorptance, emittance) + constr.set_interior_material_properties() + # Create and assign construction to surfaces constr.create_and_assign_constructions(runner, surfaces, model) end - def self.apply_rim_joist(runner, model, surfaces, rim_joist, constr_name, + def self.apply_rim_joist(runner, model, surfaces, constr_name, cavity_r, install_grade, framing_factor, - drywall_thick_in, osb_thick_in, + mat_int_finish, osb_thick_in, rigid_r, mat_ext_finish, inside_film, - outside_film) + outside_film, solar_absorptance = nil, emittance = nil) return if surfaces.empty? # Define materials rim_joist_thick_in = 1.5 sill_plate_thick_in = 3.5 framing_thick_in = sill_plate_thick_in - rim_joist_thick_in # Extra non-continuous wood beyond rim joist thickness if cavity_r > 0 # Insulation - mat_cavity = Material.new(name = nil, thick_in = framing_thick_in, mat_base = BaseMaterial.InsulationGenericDensepack, k_in = framing_thick_in / cavity_r) + mat_cavity = Material.new(thick_in: framing_thick_in, mat_base: BaseMaterial.InsulationGenericDensepack, k_in: framing_thick_in / cavity_r) else # Empty cavity mat_cavity = Material.AirCavityOpen(framing_thick_in) end - mat_framing = Material.new(name = nil, thick_in = framing_thick_in, mat_base = BaseMaterial.Wood) + mat_framing = Material.new(thick_in: framing_thick_in, mat_base: BaseMaterial.Wood) mat_gap = Material.AirCavityClosed(framing_thick_in) mat_osb = nil if osb_thick_in > 0 - mat_osb = Material.new(name = 'RimJoistSheathing', thick_in = osb_thick_in, mat_base = BaseMaterial.Wood) + mat_osb = Material.OSBSheathing(osb_thick_in) end mat_rigid = nil if rigid_r > 0 rigid_thick_in = rigid_r * BaseMaterial.InsulationRigid.k_in - mat_rigid = Material.new(name = 'RimJoistRigidIns', thick_in = rigid_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = rigid_thick_in / rigid_r) + mat_rigid = Material.new(name: 'rim joist rigid ins', thick_in: rigid_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: rigid_thick_in / rigid_r) end # Set paths gapFactor = get_gap_factor(install_grade, framing_factor, cavity_r) path_fracs = [framing_factor, 1 - framing_factor - gapFactor, gapFactor] @@ -475,26 +500,30 @@ constr.add_layer(mat_rigid) end if not mat_osb.nil? constr.add_layer(mat_osb) end - constr.add_layer([mat_framing, mat_cavity, mat_gap], 'RimJoistStudAndCavity') - if drywall_thick_in > 0 - constr.add_layer(Material.GypsumWall(drywall_thick_in)) + constr.add_layer([mat_framing, mat_cavity, mat_gap], 'rim joist stud and cavity') + if not mat_int_finish.nil? + constr.add_layer(mat_int_finish) end constr.add_layer(inside_film) + constr.set_exterior_material_properties(solar_absorptance, emittance) + constr.set_interior_material_properties() + # Create and assign construction to surfaces constr.create_and_assign_constructions(runner, surfaces, model) end def self.apply_open_cavity_roof(runner, model, surfaces, constr_name, cavity_r, install_grade, cavity_ins_thick_in, framing_factor, framing_thick_in, osb_thick_in, rigid_r, mat_roofing, has_radiant_barrier, - inside_film, outside_film, radiant_barrier_grade) + inside_film, outside_film, radiant_barrier_grade, + solar_absorptance = nil, emittance = nil) return if surfaces.empty? # Define materials roof_ins_thickness_in = [cavity_ins_thick_in, framing_thick_in].max @@ -503,27 +532,27 @@ else cavity_k = cavity_ins_thick_in / cavity_r if cavity_ins_thick_in < framing_thick_in cavity_k = cavity_k * framing_thick_in / cavity_ins_thick_in end - mat_cavity = Material.new(name = nil, thick_in = roof_ins_thickness_in, mat_base = BaseMaterial.InsulationGenericDensepack, k_in = cavity_k) + mat_cavity = Material.new(thick_in: roof_ins_thickness_in, mat_base: BaseMaterial.InsulationGenericDensepack, k_in: cavity_k) end if (cavity_ins_thick_in > framing_thick_in) && (framing_thick_in > 0) wood_k = BaseMaterial.Wood.k_in * cavity_ins_thick_in / framing_thick_in else wood_k = BaseMaterial.Wood.k_in end - mat_framing = Material.new(name = nil, thick_in = roof_ins_thickness_in, mat_base = BaseMaterial.Wood, k_in = wood_k) + mat_framing = Material.new(thick_in: roof_ins_thickness_in, mat_base: BaseMaterial.Wood, k_in: wood_k) mat_gap = Material.AirCavityOpen(roof_ins_thickness_in) mat_osb = nil if osb_thick_in > 0 - mat_osb = Material.new(name = 'RoofSheathing', thick_in = osb_thick_in, mat_base = BaseMaterial.Wood) + mat_osb = Material.OSBSheathing(osb_thick_in) end mat_rigid = nil if rigid_r > 0 rigid_thick_in = rigid_r * BaseMaterial.InsulationRigid.k_in - mat_rigid = Material.new(name = 'RoofRigidIns', thick_in = rigid_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = rigid_thick_in / rigid_r) + mat_rigid = Material.new(name: 'roof rigid ins', thick_in: rigid_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: rigid_thick_in / rigid_r) end mat_rb = nil if has_radiant_barrier mat_rb = Material.RadiantBarrier(radiant_barrier_grade) end @@ -543,52 +572,56 @@ end if not mat_osb.nil? constr.add_layer(mat_osb) end if framing_thick_in > 0 - constr.add_layer([mat_framing, mat_cavity, mat_gap], 'RoofStudAndCavity') + constr.add_layer([mat_framing, mat_cavity, mat_gap], 'roof stud and cavity') end if not mat_rb.nil? constr.add_layer(mat_rb) end constr.add_layer(inside_film) + constr.set_exterior_material_properties(solar_absorptance, emittance) + constr.set_interior_material_properties() unless has_radiant_barrier + # Create and assign construction to roof surfaces constr.create_and_assign_constructions(runner, surfaces, model) end def self.apply_closed_cavity_roof(runner, model, surfaces, constr_name, cavity_r, install_grade, cavity_depth, - filled_cavity, framing_factor, drywall_thick_in, + filled_cavity, framing_factor, mat_int_finish, osb_thick_in, rigid_r, mat_roofing, has_radiant_barrier, - inside_film, outside_film, radiant_barrier_grade) + inside_film, outside_film, radiant_barrier_grade, + solar_absorptance = nil, emittance = nil) return if surfaces.empty? # Define materials if cavity_r > 0 if filled_cavity # Insulation - mat_cavity = Material.new(name = nil, thick_in = cavity_depth, mat_base = BaseMaterial.InsulationGenericDensepack, k_in = cavity_depth / cavity_r) + mat_cavity = Material.new(thick_in: cavity_depth, mat_base: BaseMaterial.InsulationGenericDensepack, k_in: cavity_depth / cavity_r) else # Insulation plus air gap when insulation thickness < cavity depth - mat_cavity = Material.new(name = nil, thick_in = cavity_depth, mat_base = BaseMaterial.InsulationGenericDensepack, k_in = cavity_depth / (cavity_r + Gas.AirGapRvalue)) + mat_cavity = Material.new(thick_in: cavity_depth, mat_base: BaseMaterial.InsulationGenericDensepack, k_in: cavity_depth / (cavity_r + Gas.AirGapRvalue)) end else # Empty cavity mat_cavity = Material.AirCavityClosed(cavity_depth) end - mat_framing = Material.new(name = nil, thick_in = cavity_depth, mat_base = BaseMaterial.Wood) + mat_framing = Material.new(thick_in: cavity_depth, mat_base: BaseMaterial.Wood) mat_gap = Material.AirCavityClosed(cavity_depth) mat_osb = nil if osb_thick_in > 0 - mat_osb = Material.new(name = 'RoofSheathing', thick_in = osb_thick_in, mat_base = BaseMaterial.Wood) + mat_osb = Material.OSBSheathing(osb_thick_in) end mat_rigid = nil if rigid_r > 0 rigid_thick_in = rigid_r * BaseMaterial.InsulationRigid.k_in - mat_rigid = Material.new(name = 'RoofRigidIns', thick_in = rigid_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = rigid_thick_in / rigid_r) + mat_rigid = Material.new(name: 'roof rigid ins', thick_in: rigid_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: rigid_thick_in / rigid_r) end mat_rb = nil if has_radiant_barrier mat_rb = Material.RadiantBarrier(radiant_barrier_grade) end @@ -607,52 +640,49 @@ constr.add_layer(mat_rigid) end if not mat_osb.nil? constr.add_layer(mat_osb) end - constr.add_layer([mat_framing, mat_cavity, mat_gap], 'RoofStudAndCavity') - if drywall_thick_in > 0 - constr.add_layer(Material.GypsumWall(drywall_thick_in)) + constr.add_layer([mat_framing, mat_cavity, mat_gap], 'roof stud and cavity') + if not mat_int_finish.nil? + constr.add_layer(mat_int_finish) end if not mat_rb.nil? constr.add_layer(mat_rb) end constr.add_layer(inside_film) + constr.set_exterior_material_properties(solar_absorptance, emittance) + constr.set_interior_material_properties() unless has_radiant_barrier + # Create and assign construction to surfaces constr.create_and_assign_constructions(runner, surfaces, model) end def self.apply_ceiling(runner, model, surfaces, constr_name, - cavity_r, install_grade, ins_thick_in, + cavity_r, install_grade, addtl_r, framing_factor, joist_height_in, - drywall_thick_in, inside_film, outside_film) + mat_int_finish, inside_film, outside_film) - # Drywall below, open cavity above (e.g., attic floor) + # Interior finish below, open cavity above (e.g., attic floor) return if surfaces.empty? # Define materials mat_addtl_ins = nil - if ins_thick_in >= joist_height_in - # If the ceiling insulation thickness is greater than the joist thickness - cavity_k = ins_thick_in / cavity_r - if ins_thick_in > joist_height_in + if cavity_r == 0 + mat_cavity = Material.AirCavityOpen(joist_height_in) + else + if addtl_r > 0 # If there is additional insulation beyond the rafter height, # these inputs are used for defining an additional layer - mat_addtl_ins = Material.new(name = 'CeilingAdditionalIns', thick_in = (ins_thick_in - joist_height_in), mat_base = BaseMaterial.InsulationGenericLoosefill, k_in = cavity_k) + addtl_thick_in = addtl_r / 3.0 # Assume roughly R-3 per inch of loose-fill above cavity + mat_addtl_ins = Material.new(name: 'ceiling loosefill ins', thick_in: addtl_thick_in, mat_base: BaseMaterial.InsulationGenericLoosefill, k_in: addtl_thick_in / addtl_r) end - mat_cavity = Material.new(name = nil, thick_in = joist_height_in, mat_base = BaseMaterial.InsulationGenericLoosefill, k_in = cavity_k) - else - # Else the joist thickness is greater than the ceiling insulation thickness - if cavity_r == 0 - mat_cavity = Material.AirCavityOpen(joist_height_in) - else - mat_cavity = Material.new(name = nil, thick_in = joist_height_in, mat_base = BaseMaterial.InsulationGenericLoosefill, k_in = joist_height_in / cavity_r) - end + mat_cavity = Material.new(thick_in: joist_height_in, mat_base: BaseMaterial.InsulationGenericLoosefill, k_in: joist_height_in / cavity_r) end - mat_framing = Material.new(name = nil, thick_in = joist_height_in, mat_base = BaseMaterial.Wood) + mat_framing = Material.new(thick_in: joist_height_in, mat_base: BaseMaterial.Wood) mat_gap = Material.AirCavityOpen(joist_height_in) # Set paths gapFactor = get_gap_factor(install_grade, framing_factor, cavity_r) path_fracs = [framing_factor, 1 - framing_factor - gapFactor, gapFactor] @@ -661,16 +691,18 @@ constr = Construction.new(constr_name, path_fracs) constr.add_layer(outside_film) if not mat_addtl_ins.nil? constr.add_layer(mat_addtl_ins) end - constr.add_layer([mat_framing, mat_cavity, mat_gap], 'CeilingStudAndCavity') - if drywall_thick_in > 0 - constr.add_layer(Material.GypsumWall(drywall_thick_in)) + constr.add_layer([mat_framing, mat_cavity, mat_gap], 'ceiling stud and cavity') + if not mat_int_finish.nil? + constr.add_layer(mat_int_finish) end constr.add_layer(inside_film) + constr.set_interior_material_properties(debug: true) + # Create and assign construction to ceiling surfaces constr.create_and_assign_constructions(runner, surfaces, model) end def self.apply_floor(runner, model, surfaces, constr_name, @@ -686,69 +718,69 @@ # Define materials mat_2x = Material.Stud2x(joist_height_in) if cavity_r == 0 mat_cavity = Material.AirCavityOpen(mat_2x.thick_in) else - mat_cavity = Material.new(name = nil, thick_in = mat_2x.thick_in, mat_base = BaseMaterial.InsulationGenericDensepack, k_in = mat_2x.thick_in / cavity_r) + mat_cavity = Material.new(thick_in: mat_2x.thick_in, mat_base: BaseMaterial.InsulationGenericDensepack, k_in: mat_2x.thick_in / cavity_r) end - mat_framing = Material.new(name = nil, thick_in = mat_2x.thick_in, mat_base = BaseMaterial.Wood) + mat_framing = Material.new(thick_in: mat_2x.thick_in, mat_base: BaseMaterial.Wood) mat_gap = Material.AirCavityOpen(joist_height_in) mat_rigid = nil if rigid_r > 0 rigid_thick_in = rigid_r * BaseMaterial.InsulationRigid.k_in - mat_rigid = Material.new(name = 'FloorRigidIns', thick_in = rigid_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = rigid_thick_in / rigid_r) + mat_rigid = Material.new(name: 'floor rigid ins', thick_in: rigid_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: rigid_thick_in / rigid_r) end # Set paths gapFactor = get_gap_factor(install_grade, framing_factor, cavity_r) path_fracs = [framing_factor, 1 - framing_factor - gapFactor, gapFactor] # Define construction constr = Construction.new(constr_name, path_fracs) constr.add_layer(outside_film) - constr.add_layer([mat_framing, mat_cavity, mat_gap], 'FloorStudAndCavity') + constr.add_layer([mat_framing, mat_cavity, mat_gap], 'floor stud and cavity') if not mat_rigid.nil? constr.add_layer(mat_rigid) end if plywood_thick_in > 0 - constr.add_layer(Material.Plywood(plywood_thick_in)) + constr.add_layer(Material.OSBSheathing(plywood_thick_in)) end if not mat_floor_covering.nil? constr.add_layer(mat_floor_covering) end constr.add_layer(inside_film) + constr.set_interior_material_properties() + # Create and assign construction to surfaces constr.create_and_assign_constructions(runner, surfaces, model) end - def self.apply_foundation_wall(runner, model, wall_surfaces, wall_constr_name, + def self.apply_foundation_wall(runner, model, surfaces, constr_name, ext_rigid_ins_offset, int_rigid_ins_offset, ext_rigid_ins_height, - int_rigid_ins_height, ext_rigid_r, int_rigid_r, wall_drywall_thick_in, wall_concrete_thick_in, wall_height_above_grade) + int_rigid_ins_height, ext_rigid_r, int_rigid_r, mat_int_finish, + mat_wall, height_above_grade) # Create Kiva foundation foundation = apply_kiva_walled_foundation(model, ext_rigid_r, int_rigid_r, ext_rigid_ins_offset, int_rigid_ins_offset, ext_rigid_ins_height, - int_rigid_ins_height, wall_height_above_grade, - wall_concrete_thick_in, wall_drywall_thick_in) + int_rigid_ins_height, height_above_grade, + mat_wall.thick_in, mat_int_finish) - # Define materials - mat_concrete = Material.Concrete(wall_concrete_thick_in) - # Define construction - constr = Construction.new(wall_constr_name, [1]) - constr.add_layer(mat_concrete) - if wall_drywall_thick_in > 0 - constr.add_layer(Material.GypsumWall(wall_drywall_thick_in)) + constr = Construction.new(constr_name, [1]) + constr.add_layer(mat_wall) + if not mat_int_finish.nil? + constr.add_layer(mat_int_finish) end # Create and assign construction to surfaces - constr.create_and_assign_constructions(runner, wall_surfaces, model) + constr.create_and_assign_constructions(runner, surfaces, model) # Assign surfaces to Kiva foundation - wall_surfaces.each do |wall_surface| - wall_surface.setAdjacentFoundation(foundation) + surfaces.each do |surface| + surface.setAdjacentFoundation(foundation) end end def self.apply_foundation_slab(runner, model, surface, constr_name, under_r, under_width, gap_r, @@ -765,11 +797,11 @@ gap_r, thick, perimeter_r, perimeter_depth, concrete_thick_in) else # Kiva foundation (for crawlspace/basement) exists if (under_r > 0) && (under_width > 0) - int_horiz_mat = create_insulation_material(model, 'FoundationIntHorizIns', under_r) + int_horiz_mat = create_insulation_material(model, 'interior horizontal ins', under_r) foundation.setInteriorHorizontalInsulationMaterial(int_horiz_mat) foundation.setInteriorHorizontalInsulationDepth(0) foundation.setInteriorHorizontalInsulationWidth(UnitConversions.convert(under_width, 'ft', 'm')) end end @@ -784,11 +816,11 @@ mat_soil = Material.Soil(0.5) end mat_rigid = nil if whole_r > 0 rigid_thick_in = whole_r * BaseMaterial.InsulationRigid.k_in - mat_rigid = Material.new(name = 'SlabRigidIns', thick_in = rigid_thick_in, mat_base = BaseMaterial.InsulationRigid, k_in = rigid_thick_in / whole_r) + mat_rigid = Material.new(name: 'slab rigid ins', thick_in: rigid_thick_in, mat_base: BaseMaterial.InsulationRigid, k_in: rigid_thick_in / whole_r) end # Define construction constr = Construction.new(constr_name, [1.0]) if not mat_rigid.nil? @@ -816,11 +848,11 @@ return if subsurfaces.empty? # Define materials door_Rvalue = 1.0 / ufactor - inside_film.rvalue - outside_film.rvalue door_thickness = 1.75 # in - fin_door_mat = Material.new(name = 'DoorMaterial', thick_in = door_thickness, mat_base = BaseMaterial.Wood, k_in = 1.0 / door_Rvalue * door_thickness) + fin_door_mat = Material.new(name: 'door material', thick_in: door_thickness, mat_base: BaseMaterial.Wood, k_in: 1.0 / door_Rvalue * door_thickness) # Set paths path_fracs = [1] # Define construction @@ -837,59 +869,73 @@ def self.apply_skylight(runner, model, subsurface, constr_name, ufactor, shgc) apply_window_skylight(runner, model, 'Skylight', subsurface, constr_name, ufactor, shgc) end - def self.apply_partition_walls(runner, model, constr_name, drywall_thick_in, frac_of_ffa, + def self.apply_partition_walls(runner, model, constr_name, mat_int_finish, partition_wall_area, basement_frac_of_cfa, cond_base_surfaces, living_space) imdefs = [] # Determine additional partition wall mass required - addtl_surface_area_base = frac_of_ffa * living_space.floorArea * basement_frac_of_cfa - addtl_surface_area_lv = frac_of_ffa * living_space.floorArea * (1.0 - basement_frac_of_cfa) + addtl_surface_area_base = partition_wall_area * basement_frac_of_cfa + addtl_surface_area_lv = partition_wall_area * (1.0 - basement_frac_of_cfa) if addtl_surface_area_lv > 0 # Add remaining partition walls within spaces (those without geometric representation) # as internal mass object. - obj_name = "#{living_space.name} Living Partition" + obj_name = 'partition wall mass above grade' imdef = create_os_int_mass_and_def(model, obj_name, living_space, addtl_surface_area_lv) imdefs << imdef end if addtl_surface_area_base > 0 # Add remaining partition walls within spaces (those without geometric representation) # as internal mass object. - obj_name = "#{living_space.name} Basement Partition" + obj_name = 'partition wall mass below grade' imdef = create_os_int_mass_and_def(model, obj_name, living_space, addtl_surface_area_base) cond_base_surfaces << imdef imdefs << imdef end - apply_wood_stud_wall(runner, model, imdefs, nil, constr_name, + apply_wood_stud_wall(runner, model, imdefs, constr_name, 0, 1, 3.5, false, 0.16, - drywall_thick_in, 0, 0, nil, drywall_thick_in, + mat_int_finish, 0, 0, mat_int_finish, Material.AirFilmVertical, Material.AirFilmVertical) end - def self.apply_furniture(runner, model, mass_lb_per_sqft, density_lb_per_cuft, - mat, basement_frac_of_cfa, cond_base_surfaces, living_space) + def self.apply_furniture(runner, model, furniture_mass, cfa, ubfa, gfa, + basement_frac_of_cfa, cond_base_surfaces, living_space) + if furniture_mass.type == HPXML::FurnitureMassTypeLightWeight + mass_lb_per_sqft = 8.0 + mat = BaseMaterial.FurnitureLightWeight + elsif furniture_mass.type == HPXML::FurnitureMassTypeHeavyWeight + mass_lb_per_sqft = 16.0 + mat = BaseMaterial.FurnitureHeavyWeight + end + # Add user-specified furniture mass model.getSpaces.each do |space| furnAreaFraction = nil # Fraction of conditioned floor area furnConductivity = mat.k_in furnSolarAbsorptance = 0.6 furnSpecHeat = mat.cp - furnDensity = density_lb_per_cuft - if (space == living_space) || Geometry.is_unconditioned_basement(space) - furnAreaFraction = 1.0 + furnDensity = mat.rho + if space == living_space + furnAreaFraction = furniture_mass.area_fraction furnMass = mass_lb_per_sqft + floor_area = cfa + elsif Geometry.is_unconditioned_basement(space) + furnAreaFraction = 0.4 + furnMass = mass_lb_per_sqft + floor_area = ubfa elsif Geometry.is_garage(space) furnAreaFraction = 0.1 furnMass = 2.0 + floor_area = gfa end next if furnAreaFraction.nil? next if furnAreaFraction <= 0 next if space.floorArea <= 0 @@ -899,11 +945,11 @@ mass_obj_name_space = "#{Constants.ObjectNameFurniture} mass #{space.name}" furnThickness = UnitConversions.convert(furnMass / (furnDensity * furnAreaFraction), 'ft', 'in') # Define materials - mat_fm = Material.new(name = mat_obj_name_space, thick_in = furnThickness, mat_base = nil, k_in = furnConductivity, rho = furnDensity, cp = furnSpecHeat, tAbs = 0.9, sAbs = furnSolarAbsorptance, vAbs = 0.1) + mat_fm = Material.new(name: mat_obj_name_space, thick_in: furnThickness, k_in: furnConductivity, rho: furnDensity, cp: furnSpecHeat, tAbs: 0.9, sAbs: furnSolarAbsorptance) # Set paths path_fracs = [1] # Define construction @@ -911,27 +957,27 @@ constr.add_layer(mat_fm) imdefs = [] if space == living_space # if living space, judge if includes conditioned basement, create furniture independently - living_surface_area = furnAreaFraction * space.floorArea * (1 - basement_frac_of_cfa) - base_surface_area = furnAreaFraction * space.floorArea * basement_frac_of_cfa + living_surface_area = furnAreaFraction * floor_area * (1 - basement_frac_of_cfa) + base_surface_area = furnAreaFraction * floor_area * basement_frac_of_cfa # living furniture mass if living_surface_area > 0 - living_obj_name = mass_obj_name_space + ' living' + living_obj_name = mass_obj_name_space + ' above grade' imdef = create_os_int_mass_and_def(model, living_obj_name, space, living_surface_area) imdefs << imdef end # basement furniture mass if base_surface_area > 0 - base_obj_name = mass_obj_name_space + ' basement' + base_obj_name = mass_obj_name_space + ' below grade' imdef = create_os_int_mass_and_def(model, base_obj_name, space, base_surface_area) cond_base_surfaces << imdef imdefs << imdef end else - surface_area = furnAreaFraction * space.floorArea + surface_area = furnAreaFraction * floor_area imdef = create_os_int_mass_and_def(model, mass_obj_name_space, space, surface_area) imdefs << imdef end # Create and assign construction to surfaces constr.create_and_assign_constructions(runner, imdefs, model) @@ -941,11 +987,11 @@ def self.create_os_int_mass_and_def(model, object_name, space, area) # EnergyPlus documentation: If both sides of the surface exchange energy with the zone # then the user should input twice the area when defining the Internal Mass object. imdef = OpenStudio::Model::InternalMassDefinition.new(model) imdef.setName(object_name) - imdef.setSurfaceArea(area) + imdef.setSurfaceArea(UnitConversions.convert(area, 'ft^2', 'm^2')) im = OpenStudio::Model::InternalMass.new(imdef) im.setName(object_name) im.setSpace(space) @@ -984,41 +1030,176 @@ def self.get_default_wall_solar_absorptance(color) map = get_wall_color_and_solar_absorptance_map return map[color] end + def self.get_default_window_skylight_ufactor_shgc(window_or_skylight, type) + if window_or_skylight.glass_layers == HPXML::WindowLayersSinglePane + n_panes = 1 + elsif window_or_skylight.glass_layers == HPXML::WindowLayersDoublePane + n_panes = 2 + elsif window_or_skylight.glass_layers == HPXML::WindowLayersTriplePane + n_panes = 3 + elsif window_or_skylight.glass_layers == HPXML::WindowLayersGlassBlock + return [0.6, 0.6] # From https://www.federalregister.gov/documents/2016/06/17/2016-13547/energy-conservation-standards-for-manufactured-housing + end + + if [HPXML::WindowFrameTypeAluminum, + HPXML::WindowFrameTypeMetal].include? window_or_skylight.frame_type + is_metal_frame = true + elsif [HPXML::WindowFrameTypeWood, + HPXML::WindowFrameTypeVinyl, + HPXML::WindowFrameTypeFiberglass].include? window_or_skylight.frame_type + is_metal_frame = false + else + fail "Unexpected #{type.downcase} frame type." + end + + if window_or_skylight.glass_type.nil? + glass_type = 'clear' + elsif [HPXML::WindowGlassTypeTinted, + HPXML::WindowGlassTypeTintedReflective].include? window_or_skylight.glass_type + glass_type = 'tinted' + elsif [HPXML::WindowGlassTypeLowE].include? window_or_skylight.glass_type + glass_type = 'low_e' + elsif [HPXML::WindowGlassTypeReflective].include? window_or_skylight.glass_type + glass_type = 'reflective' + else + fail "Unexpected #{type.downcase} glass type." + end + + if window_or_skylight.glass_layers == HPXML::WindowLayersSinglePane + gas_fill = 'none' + elsif [HPXML::WindowGasAir].include? window_or_skylight.gas_fill + gas_fill = 'air' + elsif [HPXML::WindowGasArgon, + HPXML::WindowGasKrypton, + HPXML::WindowGasXenon, + HPXML::WindowGasNitrogen, + HPXML::WindowGasOther].include? window_or_skylight.gas_fill + gas_fill = 'gas' + else + fail "Unexpected #{type.downcase} gas type." + end + + # Lookup values + # From http://hes-documentation.lbl.gov/calculation-methodology/calculation-of-energy-consumption/heating-and-cooling-calculation/building-envelope/window-skylight-construction-types + key = [is_metal_frame, window_or_skylight.thermal_break, n_panes, glass_type, gas_fill] + if type.downcase == 'window' + vals = { [true, false, 1, 'clear', 'none'] => [1.27, 0.75], # Single-pane, clear, aluminum frame + [false, nil, 1, 'clear', 'none'] => [0.89, 0.64], # Single-pane, clear, wood or vinyl frame + [true, false, 1, 'tinted', 'none'] => [1.27, 0.64], # Single-pane, tinted, aluminum frame + [false, nil, 1, 'tinted', 'none'] => [0.89, 0.54], # Single-pane, tinted, wood or vinyl frame + [true, false, 2, 'clear', 'air'] => [0.81, 0.67], # Double-pane, clear, aluminum frame + [true, true, 2, 'clear', 'air'] => [0.60, 0.67], # Double-pane, clear, aluminum frame w/ thermal break + [false, nil, 2, 'clear', 'air'] => [0.51, 0.56], # Double-pane, clear, wood or vinyl frame + [true, false, 2, 'tinted', 'air'] => [0.81, 0.55], # Double-pane, tinted, aluminum frame + [true, true, 2, 'tinted', 'air'] => [0.60, 0.55], # Double-pane, tinted, aluminum frame w/ thermal break + [false, nil, 2, 'tinted', 'air'] => [0.51, 0.46], # Double-pane, tinted, wood or vinyl frame + [false, nil, 2, 'low_e', 'air'] => [0.42, 0.52], # Double-pane, insulating low-E, wood or vinyl frame + [true, true, 2, 'low_e', 'gas'] => [0.47, 0.62], # Double-pane, insulating low-E, argon gas fill, aluminum frame w/ thermal break + [false, nil, 2, 'low_e', 'gas'] => [0.39, 0.52], # Double-pane, insulating low-E, argon gas fill, wood or vinyl frame + [true, false, 2, 'reflective', 'air'] => [0.67, 0.37], # Double-pane, solar-control low-E, aluminum frame + [true, true, 2, 'reflective', 'air'] => [0.47, 0.37], # Double-pane, solar-control low-E, aluminum frame w/ thermal break + [false, nil, 2, 'reflective', 'air'] => [0.39, 0.31], # Double-pane, solar-control low-E, wood or vinyl frame + [false, nil, 2, 'reflective', 'gas'] => [0.36, 0.31], # Double-pane, solar-control low-E, argon gas fill, wood or vinyl frame + [false, nil, 3, 'low_e', 'gas'] => [0.27, 0.31] }[key] # Triple-pane, insulating low-E, argon gas fill, wood or vinyl frame + elsif type.downcase == 'skylight' + vals = { [true, false, 1, 'clear', 'none'] => [1.98, 0.75], # Single-pane, clear, aluminum frame + [false, nil, 1, 'clear', 'none'] => [1.47, 0.64], # Single-pane, clear, wood or vinyl frame + [true, false, 1, 'tinted', 'none'] => [1.98, 0.64], # Single-pane, tinted, aluminum frame + [false, nil, 1, 'tinted', 'none'] => [1.47, 0.54], # Single-pane, tinted, wood or vinyl frame + [true, false, 2, 'clear', 'air'] => [1.30, 0.67], # Double-pane, clear, aluminum frame + [true, true, 2, 'clear', 'air'] => [1.10, 0.67], # Double-pane, clear, aluminum frame w/ thermal break + [false, nil, 2, 'clear', 'air'] => [0.84, 0.56], # Double-pane, clear, wood or vinyl frame + [true, false, 2, 'tinted', 'air'] => [1.30, 0.55], # Double-pane, tinted, aluminum frame + [true, true, 2, 'tinted', 'air'] => [1.10, 0.55], # Double-pane, tinted, aluminum frame w/ thermal break + [false, nil, 2, 'tinted', 'air'] => [0.84, 0.46], # Double-pane, tinted, wood or vinyl frame + [false, nil, 2, 'low_e', 'air'] => [0.74, 0.52], # Double-pane, insulating low-E, wood or vinyl frame + [true, true, 2, 'low_e', 'gas'] => [0.95, 0.62], # Double-pane, insulating low-E, argon gas fill, aluminum frame w/ thermal break + [false, nil, 2, 'low_e', 'gas'] => [0.68, 0.52], # Double-pane, insulating low-E, argon gas fill, wood or vinyl frame + [true, false, 2, 'reflective', 'air'] => [1.17, 0.37], # Double-pane, solar-control low-E, aluminum frame + [true, true, 2, 'reflective', 'air'] => [0.98, 0.37], # Double-pane, solar-control low-E, aluminum frame w/ thermal break + [false, nil, 2, 'reflective', 'air'] => [0.71, 0.31], # Double-pane, solar-control low-E, wood or vinyl frame + [false, nil, 2, 'reflective', 'gas'] => [0.65, 0.31], # Double-pane, solar-control low-E, argon gas fill, wood or vinyl frame + [false, nil, 3, 'low_e', 'gas'] => [0.47, 0.31] }[key] # Triple-pane, insulating low-E, argon gas fill, wood or vinyl frame + else + fail 'Unexpected type.' + end + return vals if not vals.nil? + + fail "Could not lookup UFactor and SHGC for #{type.downcase} '#{window_or_skylight.id}'." + end + private def self.get_roof_color_and_solar_absorptance_map - return { [HPXML::ColorDark, HPXML::RoofTypeAsphaltShingles] => 0.92, - [HPXML::ColorMediumDark, HPXML::RoofTypeAsphaltShingles] => 0.89, - [HPXML::ColorMedium, HPXML::RoofTypeAsphaltShingles] => 0.85, - [HPXML::ColorLight, HPXML::RoofTypeAsphaltShingles] => 0.75, - [HPXML::ColorReflective, HPXML::RoofTypeAsphaltShingles] => 0.50, - [HPXML::ColorDark, HPXML::RoofTypeWoodShingles] => 0.92, - [HPXML::ColorMediumDark, HPXML::RoofTypeWoodShingles] => 0.89, - [HPXML::ColorMedium, HPXML::RoofTypeWoodShingles] => 0.85, - [HPXML::ColorLight, HPXML::RoofTypeWoodShingles] => 0.75, - [HPXML::ColorReflective, HPXML::RoofTypeWoodShingles] => 0.50, - [HPXML::ColorDark, HPXML::RoofTypeClayTile] => 0.90, - [HPXML::ColorMediumDark, HPXML::RoofTypeClayTile] => 0.83, - [HPXML::ColorMedium, HPXML::RoofTypeClayTile] => 0.75, - [HPXML::ColorLight, HPXML::RoofTypeClayTile] => 0.60, - [HPXML::ColorReflective, HPXML::RoofTypeClayTile] => 0.30, - [HPXML::ColorDark, HPXML::RoofTypeMetal] => 0.90, - [HPXML::ColorMediumDark, HPXML::RoofTypeMetal] => 0.83, - [HPXML::ColorMedium, HPXML::RoofTypeMetal] => 0.75, - [HPXML::ColorLight, HPXML::RoofTypeMetal] => 0.60, - [HPXML::ColorReflective, HPXML::RoofTypeMetal] => 0.30 } + return { # asphalt or fiberglass shingles + [HPXML::ColorDark, HPXML::RoofTypeAsphaltShingles] => 0.92, + [HPXML::ColorMediumDark, HPXML::RoofTypeAsphaltShingles] => 0.89, + [HPXML::ColorMedium, HPXML::RoofTypeAsphaltShingles] => 0.85, + [HPXML::ColorLight, HPXML::RoofTypeAsphaltShingles] => 0.75, + [HPXML::ColorReflective, HPXML::RoofTypeAsphaltShingles] => 0.50, + # wood shingles or shakes + [HPXML::ColorDark, HPXML::RoofTypeWoodShingles] => 0.92, + [HPXML::ColorMediumDark, HPXML::RoofTypeWoodShingles] => 0.89, + [HPXML::ColorMedium, HPXML::RoofTypeWoodShingles] => 0.85, + [HPXML::ColorLight, HPXML::RoofTypeWoodShingles] => 0.75, + [HPXML::ColorReflective, HPXML::RoofTypeWoodShingles] => 0.50, + # shingles + [HPXML::ColorDark, HPXML::RoofTypeShingles] => 0.92, + [HPXML::ColorMediumDark, HPXML::RoofTypeShingles] => 0.89, + [HPXML::ColorMedium, HPXML::RoofTypeShingles] => 0.85, + [HPXML::ColorLight, HPXML::RoofTypeShingles] => 0.75, + [HPXML::ColorReflective, HPXML::RoofTypeShingles] => 0.50, + # slate or tile shingles + [HPXML::ColorDark, HPXML::RoofTypeClayTile] => 0.90, + [HPXML::ColorMediumDark, HPXML::RoofTypeClayTile] => 0.83, + [HPXML::ColorMedium, HPXML::RoofTypeClayTile] => 0.75, + [HPXML::ColorLight, HPXML::RoofTypeClayTile] => 0.60, + [HPXML::ColorReflective, HPXML::RoofTypeClayTile] => 0.30, + # metal surfacing + [HPXML::ColorDark, HPXML::RoofTypeMetal] => 0.90, + [HPXML::ColorMediumDark, HPXML::RoofTypeMetal] => 0.83, + [HPXML::ColorMedium, HPXML::RoofTypeMetal] => 0.75, + [HPXML::ColorLight, HPXML::RoofTypeMetal] => 0.60, + [HPXML::ColorReflective, HPXML::RoofTypeMetal] => 0.30, + # plastic/rubber/synthetic sheeting + [HPXML::ColorDark, HPXML::RoofTypePlasticRubber] => 0.90, + [HPXML::ColorMediumDark, HPXML::RoofTypePlasticRubber] => 0.83, + [HPXML::ColorMedium, HPXML::RoofTypePlasticRubber] => 0.75, + [HPXML::ColorLight, HPXML::RoofTypePlasticRubber] => 0.60, + [HPXML::ColorReflective, HPXML::RoofTypePlasticRubber] => 0.30, + # expanded polystyrene sheathing + [HPXML::ColorDark, HPXML::RoofTypeEPS] => 0.92, + [HPXML::ColorMediumDark, HPXML::RoofTypeEPS] => 0.89, + [HPXML::ColorMedium, HPXML::RoofTypeEPS] => 0.85, + [HPXML::ColorLight, HPXML::RoofTypeEPS] => 0.75, + [HPXML::ColorReflective, HPXML::RoofTypeEPS] => 0.50, + # concrete + [HPXML::ColorDark, HPXML::RoofTypeConcrete] => 0.90, + [HPXML::ColorMediumDark, HPXML::RoofTypeConcrete] => 0.83, + [HPXML::ColorMedium, HPXML::RoofTypeConcrete] => 0.75, + [HPXML::ColorLight, HPXML::RoofTypeConcrete] => 0.65, + [HPXML::ColorReflective, HPXML::RoofTypeConcrete] => 0.50, + # cool roof + [HPXML::ColorDark, HPXML::RoofTypeCool] => 0.30, + [HPXML::ColorMediumDark, HPXML::RoofTypeCool] => 0.30, + [HPXML::ColorMedium, HPXML::RoofTypeCool] => 0.30, + [HPXML::ColorLight, HPXML::RoofTypeCool] => 0.30, + [HPXML::ColorReflective, HPXML::RoofTypeCool] => 0.30, + } end def self.get_wall_color_and_solar_absorptance_map - return { HPXML::ColorDark => 0.95, - HPXML::ColorMediumDark => 0.85, - HPXML::ColorMedium => 0.70, - HPXML::ColorLight => 0.50, - HPXML::ColorReflective => 0.30 } + return { + HPXML::ColorDark => 0.95, + HPXML::ColorMediumDark => 0.85, + HPXML::ColorMedium => 0.70, + HPXML::ColorLight => 0.50, + HPXML::ColorReflective => 0.30 + } end def self.get_gap_factor(install_grade, framing_factor, cavity_r) if cavity_r <= 0 return 0 # Gap factor only applies when there is cavity insulation @@ -1040,26 +1221,26 @@ # Create the Foundation:Kiva object for slab foundations foundation = OpenStudio::Model::FoundationKiva.new(model) # Interior horizontal insulation if (int_horiz_r > 0) && (int_horiz_width > 0) - int_horiz_mat = create_insulation_material(model, 'FoundationIntHorizIns', int_horiz_r) + int_horiz_mat = create_insulation_material(model, 'interior horizontal ins', int_horiz_r) foundation.setInteriorHorizontalInsulationMaterial(int_horiz_mat) foundation.setInteriorHorizontalInsulationDepth(0) foundation.setInteriorHorizontalInsulationWidth(UnitConversions.convert(int_horiz_width, 'ft', 'm')) end # Interior vertical insulation if int_vert_r > 0 - int_vert_mat = create_insulation_material(model, 'FoundationIntVertIns', int_vert_r) + int_vert_mat = create_insulation_material(model, 'interior vertical ins', int_vert_r) foundation.setInteriorVerticalInsulationMaterial(int_vert_mat) foundation.setInteriorVerticalInsulationDepth(UnitConversions.convert(int_vert_depth, 'ft', 'm')) end # Exterior vertical insulation if (ext_vert_r > 0) && (ext_vert_depth > 0) - ext_vert_mat = create_insulation_material(model, 'FoundationExtVertIns', ext_vert_r) + ext_vert_mat = create_insulation_material(model, 'exterior vertical ins', ext_vert_r) foundation.setExteriorVerticalInsulationMaterial(ext_vert_mat) foundation.setExteriorVerticalInsulationDepth(UnitConversions.convert(ext_vert_depth, 'ft', 'm')) end foundation.setWallHeightAboveGrade(UnitConversions.convert(concrete_thick_in, 'in', 'm')) @@ -1070,30 +1251,31 @@ return foundation end def self.apply_kiva_walled_foundation(model, ext_vert_r, int_vert_r, ext_vert_offset, int_vert_offset, ext_vert_depth, int_vert_depth, - wall_height_above_grade, wall_concrete_thick_in, wall_drywall_thick_in) + wall_height_above_grade, wall_material_thick_in, wall_mat_int_finish) # Create the Foundation:Kiva object for crawl/basement foundations foundation = OpenStudio::Model::FoundationKiva.new(model) # Interior vertical insulation if (int_vert_r > 0) && (int_vert_depth > 0) - int_vert_mat = create_insulation_material(model, 'FoundationIntVertIns', int_vert_r) + int_vert_mat = create_insulation_material(model, 'interior vertical ins', int_vert_r) foundation.addCustomBlock(int_vert_mat, UnitConversions.convert(int_vert_depth, 'ft', 'm'), -int_vert_mat.thickness, UnitConversions.convert(int_vert_offset, 'ft', 'm')) end # Exterior vertical insulation if (ext_vert_r > 0) && (ext_vert_depth > 0) - ext_vert_mat = create_insulation_material(model, 'FoundationExtVertIns', ext_vert_r) + ext_vert_mat = create_insulation_material(model, 'exterior vertical ins', ext_vert_r) + wall_mat_int_finish_thick_in = wall_mat_int_finish.nil? ? 0.0 : wall_mat_int_finish.thick_in foundation.addCustomBlock(ext_vert_mat, UnitConversions.convert(ext_vert_depth, 'ft', 'm'), - UnitConversions.convert(wall_concrete_thick_in + wall_drywall_thick_in, 'in', 'm'), + UnitConversions.convert(wall_material_thick_in + wall_mat_int_finish_thick_in, 'in', 'm'), UnitConversions.convert(ext_vert_offset, 'ft', 'm')) end foundation.setWallHeightAboveGrade(UnitConversions.convert(wall_height_above_grade, 'ft', 'm')) foundation.setWallDepthBelowSlab(UnitConversions.convert(8.0, 'in', 'm')) @@ -1154,11 +1336,11 @@ # vertically mounted products". According to NFRC, "Ratings ... shall be converted to # the 20-deg slope from the vertical position by multiplying the tested value at vertical # by 1.20." Thus we divide by 1.2 to get the vertical position value. ufactor /= 1.2 end - glaz_mat = GlazingMaterial.new("#{type}Material", ufactor, shgc) + glaz_mat = GlazingMaterial.new(name: "#{type}Material", ufactor: ufactor, shgc: shgc) # Set paths path_fracs = [1] # Define construction @@ -1232,143 +1414,154 @@ end def self.calc_non_cavity_r(film_r, constr_set) # Calculate R-value for all non-cavity layers non_cavity_r = film_r - if not constr_set.exterior_material.nil? - non_cavity_r += constr_set.exterior_material.rvalue + if not constr_set.mat_ext_finish.nil? + non_cavity_r += constr_set.mat_ext_finish.rvalue end if not constr_set.rigid_r.nil? non_cavity_r += constr_set.rigid_r end if not constr_set.osb_thick_in.nil? - non_cavity_r += Material.Plywood(constr_set.osb_thick_in).rvalue + non_cavity_r += Material.OSBSheathing(constr_set.osb_thick_in).rvalue end - if not constr_set.drywall_thick_in.nil? - non_cavity_r += Material.GypsumWall(constr_set.drywall_thick_in).rvalue + if not constr_set.mat_int_finish.nil? + non_cavity_r += constr_set.mat_int_finish.rvalue end return non_cavity_r end - def self.apply_wall_construction(runner, model, surfaces, wall, wall_id, wall_type, assembly_r, - drywall_thick_in, inside_film, outside_film, mat_ext_finish) + def self.apply_wall_construction(runner, model, surfaces, wall_id, wall_type, assembly_r, + mat_int_finish, inside_film, outside_film, mat_ext_finish, + solar_absorptance, emittance) film_r = inside_film.rvalue + outside_film.rvalue if mat_ext_finish.nil? fallback_mat_ext_finish = nil else - fallback_mat_ext_finish = Material.ExteriorFinishMaterial(mat_ext_finish.name, mat_ext_finish.tAbs, mat_ext_finish.sAbs, 0.1) + fallback_mat_ext_finish = Material.ExteriorFinishMaterial(mat_ext_finish.name, 0.1) # Try thin material end + if mat_int_finish.nil? + fallback_mat_int_finish = nil + else + fallback_mat_int_finish = Material.InteriorFinishMaterial(mat_int_finish.name, 0.1) # Try thin material + end if wall_type == HPXML::WallTypeWoodStud install_grade = 1 cavity_filled = true constr_sets = [ - WoodStudConstructionSet.new(Material.Stud2x6, 0.20, 20.0, 0.5, drywall_thick_in, mat_ext_finish), # 2x6, 24" o.c. + R20 - WoodStudConstructionSet.new(Material.Stud2x6, 0.20, 10.0, 0.5, drywall_thick_in, mat_ext_finish), # 2x6, 24" o.c. + R10 - WoodStudConstructionSet.new(Material.Stud2x6, 0.20, 0.0, 0.5, drywall_thick_in, mat_ext_finish), # 2x6, 24" o.c. - WoodStudConstructionSet.new(Material.Stud2x4, 0.23, 0.0, 0.5, drywall_thick_in, mat_ext_finish), # 2x4, 16" o.c. - WoodStudConstructionSet.new(Material.Stud2x4, 0.01, 0.0, 0.0, 0.0, fallback_mat_ext_finish), # Fallback + WoodStudConstructionSet.new(Material.Stud2x6, 0.20, 20.0, 0.5, mat_int_finish, mat_ext_finish), # 2x6, 24" o.c. + R20 + WoodStudConstructionSet.new(Material.Stud2x6, 0.20, 10.0, 0.5, mat_int_finish, mat_ext_finish), # 2x6, 24" o.c. + R10 + WoodStudConstructionSet.new(Material.Stud2x6, 0.20, 0.0, 0.5, mat_int_finish, mat_ext_finish), # 2x6, 24" o.c. + WoodStudConstructionSet.new(Material.Stud2x4, 0.23, 0.0, 0.5, mat_int_finish, mat_ext_finish), # 2x4, 16" o.c. + WoodStudConstructionSet.new(Material.Stud2x4, 0.01, 0.0, 0.0, fallback_mat_int_finish, fallback_mat_ext_finish), # Fallback ] match, constr_set, cavity_r = pick_wood_stud_construction_set(assembly_r, constr_sets, inside_film, outside_film, wall_id) - apply_wood_stud_wall(runner, model, surfaces, wall, "#{wall_id} construction", + apply_wood_stud_wall(runner, model, surfaces, "#{wall_id} construction", cavity_r, install_grade, constr_set.stud.thick_in, cavity_filled, constr_set.framing_factor, - constr_set.drywall_thick_in, constr_set.osb_thick_in, - constr_set.rigid_r, constr_set.exterior_material, - 0, inside_film, outside_film) + constr_set.mat_int_finish, constr_set.osb_thick_in, + constr_set.rigid_r, constr_set.mat_ext_finish, + inside_film, outside_film, solar_absorptance, + emittance) elsif wall_type == HPXML::WallTypeSteelStud install_grade = 1 cavity_filled = true corr_factor = 0.45 constr_sets = [ - SteelStudConstructionSet.new(5.5, corr_factor, 0.20, 10.0, 0.5, drywall_thick_in, mat_ext_finish), # 2x6, 24" o.c. + R20 - SteelStudConstructionSet.new(5.5, corr_factor, 0.20, 10.0, 0.5, drywall_thick_in, mat_ext_finish), # 2x6, 24" o.c. + R10 - SteelStudConstructionSet.new(5.5, corr_factor, 0.20, 0.0, 0.5, drywall_thick_in, mat_ext_finish), # 2x6, 24" o.c. - SteelStudConstructionSet.new(3.5, corr_factor, 0.23, 0.0, 0.5, drywall_thick_in, mat_ext_finish), # 2x4, 16" o.c. - SteelStudConstructionSet.new(3.5, 1.0, 0.01, 0.0, 0.0, 0.0, fallback_mat_ext_finish), # Fallback + SteelStudConstructionSet.new(5.5, corr_factor, 0.20, 10.0, 0.5, mat_int_finish, mat_ext_finish), # 2x6, 24" o.c. + R20 + SteelStudConstructionSet.new(5.5, corr_factor, 0.20, 10.0, 0.5, mat_int_finish, mat_ext_finish), # 2x6, 24" o.c. + R10 + SteelStudConstructionSet.new(5.5, corr_factor, 0.20, 0.0, 0.5, mat_int_finish, mat_ext_finish), # 2x6, 24" o.c. + SteelStudConstructionSet.new(3.5, corr_factor, 0.23, 0.0, 0.5, mat_int_finish, mat_ext_finish), # 2x4, 16" o.c. + SteelStudConstructionSet.new(3.5, 1.0, 0.01, 0.0, 0.0, fallback_mat_int_finish, fallback_mat_ext_finish), # Fallback ] match, constr_set, cavity_r = pick_steel_stud_construction_set(assembly_r, constr_sets, inside_film, outside_film, wall_id) - apply_steel_stud_wall(runner, model, surfaces, wall, "#{wall_id} construction", + apply_steel_stud_wall(runner, model, surfaces, "#{wall_id} construction", cavity_r, install_grade, constr_set.cavity_thick_in, cavity_filled, constr_set.framing_factor, - constr_set.corr_factor, constr_set.drywall_thick_in, + constr_set.corr_factor, constr_set.mat_int_finish, constr_set.osb_thick_in, constr_set.rigid_r, - constr_set.exterior_material, inside_film, outside_film) + constr_set.mat_ext_finish, inside_film, outside_film, + solar_absorptance, emittance) elsif wall_type == HPXML::WallTypeDoubleWoodStud install_grade = 1 is_staggered = false constr_sets = [ - DoubleStudConstructionSet.new(Material.Stud2x4, 0.23, 24.0, 0.0, 0.5, drywall_thick_in, mat_ext_finish), # 2x4, 24" o.c. - DoubleStudConstructionSet.new(Material.Stud2x4, 0.01, 16.0, 0.0, 0.0, 0.0, fallback_mat_ext_finish), # Fallback + DoubleStudConstructionSet.new(Material.Stud2x4, 0.23, 24.0, 0.0, 0.5, mat_int_finish, mat_ext_finish), # 2x4, 24" o.c. + DoubleStudConstructionSet.new(Material.Stud2x4, 0.01, 16.0, 0.0, 0.0, fallback_mat_int_finish, fallback_mat_ext_finish), # Fallback ] match, constr_set, cavity_r = pick_double_stud_construction_set(assembly_r, constr_sets, inside_film, outside_film, wall_id) - apply_double_stud_wall(runner, model, surfaces, wall, "#{wall_id} construction", + apply_double_stud_wall(runner, model, surfaces, "#{wall_id} construction", cavity_r, install_grade, constr_set.stud.thick_in, constr_set.stud.thick_in, constr_set.framing_factor, constr_set.framing_spacing, is_staggered, - constr_set.drywall_thick_in, constr_set.osb_thick_in, - constr_set.rigid_r, constr_set.exterior_material, - inside_film, outside_film) + constr_set.mat_int_finish, constr_set.osb_thick_in, + constr_set.rigid_r, constr_set.mat_ext_finish, + inside_film, outside_film, solar_absorptance, + emittance) elsif wall_type == HPXML::WallTypeCMU density = 119.0 # lb/ft^3 furring_r = 0 furring_cavity_depth_in = 0 # in furring_spacing = 0 constr_sets = [ - CMUConstructionSet.new(8.0, 1.4, 0.08, 0.5, drywall_thick_in, mat_ext_finish), # 8" perlite-filled CMU - CMUConstructionSet.new(6.0, 5.29, 0.01, 0.0, 0.0, fallback_mat_ext_finish), # Fallback (6" hollow CMU) + CMUConstructionSet.new(8.0, 1.4, 0.08, 0.5, mat_int_finish, mat_ext_finish), # 8" perlite-filled CMU + CMUConstructionSet.new(6.0, 5.29, 0.01, 0.0, fallback_mat_int_finish, fallback_mat_ext_finish), # Fallback (6" hollow CMU) ] match, constr_set, rigid_r = pick_cmu_construction_set(assembly_r, constr_sets, inside_film, outside_film, wall_id) - apply_cmu_wall(runner, model, surfaces, wall, "#{wall_id} construction", + apply_cmu_wall(runner, model, surfaces, "#{wall_id} construction", constr_set.thick_in, constr_set.cond_in, density, constr_set.framing_factor, furring_r, furring_cavity_depth_in, furring_spacing, - constr_set.drywall_thick_in, constr_set.osb_thick_in, - rigid_r, constr_set.exterior_material, inside_film, - outside_film) + constr_set.mat_int_finish, constr_set.osb_thick_in, + rigid_r, constr_set.mat_ext_finish, inside_film, + outside_film, solar_absorptance, emittance) elsif wall_type == HPXML::WallTypeSIP sheathing_thick_in = 0.44 constr_sets = [ - SIPConstructionSet.new(10.0, 0.16, 0.0, sheathing_thick_in, 0.5, drywall_thick_in, mat_ext_finish), # 10" SIP core - SIPConstructionSet.new(5.0, 0.16, 0.0, sheathing_thick_in, 0.5, drywall_thick_in, mat_ext_finish), # 5" SIP core - SIPConstructionSet.new(1.0, 0.01, 0.0, sheathing_thick_in, 0.0, 0.0, fallback_mat_ext_finish), # Fallback + SIPConstructionSet.new(10.0, 0.16, 0.0, sheathing_thick_in, 0.5, mat_int_finish, mat_ext_finish), # 10" SIP core + SIPConstructionSet.new(5.0, 0.16, 0.0, sheathing_thick_in, 0.5, mat_int_finish, mat_ext_finish), # 5" SIP core + SIPConstructionSet.new(1.0, 0.01, 0.0, sheathing_thick_in, 0.0, fallback_mat_int_finish, fallback_mat_ext_finish), # Fallback ] match, constr_set, cavity_r = pick_sip_construction_set(assembly_r, constr_sets, inside_film, outside_film, wall_id) - apply_sip_wall(runner, model, surfaces, wall, "#{wall_id} construction", + apply_sip_wall(runner, model, surfaces, "#{wall_id} construction", cavity_r, constr_set.thick_in, constr_set.framing_factor, - constr_set.sheath_thick_in, constr_set.drywall_thick_in, + constr_set.sheath_thick_in, constr_set.mat_int_finish, constr_set.osb_thick_in, constr_set.rigid_r, - constr_set.exterior_material, inside_film, outside_film) + constr_set.mat_ext_finish, inside_film, outside_film, + solar_absorptance, emittance) elsif wall_type == HPXML::WallTypeICF constr_sets = [ - ICFConstructionSet.new(2.0, 4.0, 0.08, 0.0, 0.5, drywall_thick_in, mat_ext_finish), # ICF w/4" concrete and 2" rigid ins layers - ICFConstructionSet.new(1.0, 1.0, 0.01, 0.0, 0.0, 0.0, fallback_mat_ext_finish), # Fallback + ICFConstructionSet.new(2.0, 4.0, 0.08, 0.0, 0.5, mat_int_finish, mat_ext_finish), # ICF w/4" concrete and 2" rigid ins layers + ICFConstructionSet.new(1.0, 1.0, 0.01, 0.0, 0.0, fallback_mat_int_finish, fallback_mat_ext_finish), # Fallback ] match, constr_set, icf_r = pick_icf_construction_set(assembly_r, constr_sets, inside_film, outside_film, wall_id) - apply_icf_wall(runner, model, surfaces, wall, "#{wall_id} construction", + apply_icf_wall(runner, model, surfaces, "#{wall_id} construction", icf_r, constr_set.ins_thick_in, constr_set.concrete_thick_in, constr_set.framing_factor, - constr_set.drywall_thick_in, constr_set.osb_thick_in, - constr_set.rigid_r, constr_set.exterior_material, - inside_film, outside_film) + constr_set.mat_int_finish, constr_set.osb_thick_in, + constr_set.rigid_r, constr_set.mat_ext_finish, + inside_film, outside_film, solar_absorptance, + emittance) elsif [HPXML::WallTypeConcrete, HPXML::WallTypeBrick, HPXML::WallTypeAdobe, HPXML::WallTypeStrawBale, HPXML::WallTypeStone, HPXML::WallTypeLog].include? wall_type constr_sets = [ - GenericConstructionSet.new(10.0, 0.5, drywall_thick_in, mat_ext_finish), # w/R-10 rigid - GenericConstructionSet.new(0.0, 0.5, drywall_thick_in, mat_ext_finish), # Standard - GenericConstructionSet.new(0.0, 0.0, 0.0, fallback_mat_ext_finish), # Fallback + GenericConstructionSet.new(10.0, 0.5, mat_int_finish, mat_ext_finish), # w/R-10 rigid + GenericConstructionSet.new(0.0, 0.5, mat_int_finish, mat_ext_finish), # Standard + GenericConstructionSet.new(0.0, 0.0, fallback_mat_int_finish, fallback_mat_ext_finish), # Fallback ] match, constr_set, layer_r = pick_generic_construction_set(assembly_r, constr_sets, inside_film, outside_film, wall_id) if wall_type == HPXML::WallTypeConcrete thick_in = 6.0 @@ -1396,15 +1589,16 @@ conds = [thick_in / layer_r] end denss = [base_mat.rho] specheats = [base_mat.cp] - apply_generic_layered_wall(runner, model, surfaces, wall, "#{wall_id} construction", + apply_generic_layered_wall(runner, model, surfaces, "#{wall_id} construction", thick_ins, conds, denss, specheats, - constr_set.drywall_thick_in, constr_set.osb_thick_in, - constr_set.rigid_r, constr_set.exterior_material, - inside_film, outside_film) + constr_set.mat_int_finish, constr_set.osb_thick_in, + constr_set.rigid_r, constr_set.mat_ext_finish, + inside_film, outside_film, solar_absorptance, + emittance) else fail "Unexpected wall type '#{wall_type}'." end check_surface_assembly_rvalue(runner, surfaces, inside_film, outside_film, assembly_r, match) @@ -1422,11 +1616,11 @@ # Calculate effective cavity R-value # Assumes installation quality 1 cavity_frac = 1.0 - constr_set.framing_factor cavity_r = cavity_frac / (1.0 / assembly_r - constr_set.framing_factor / (constr_set.stud.rvalue + non_cavity_r)) - non_cavity_r - if cavity_r > 0 # Choose this construction set + if cavity_r > 0 && cavity_r < Float::INFINITY # Choose this construction set return true, constr_set, cavity_r end end return false, constr_sets[-1], 0.0 # Pick fallback construction with minimum R-value @@ -1443,11 +1637,11 @@ non_cavity_r = calc_non_cavity_r(film_r, constr_set) # Calculate effective cavity R-value # Assumes installation quality 1 cavity_r = (assembly_r - non_cavity_r) / constr_set.corr_factor - if cavity_r > 0 # Choose this construction set + if cavity_r > 0 && cavity_r < Float::INFINITY # Choose this construction set return true, constr_set, cavity_r end end return false, constr_sets[-1], 0.0 # Pick fallback construction with minimum R-value @@ -1474,11 +1668,11 @@ c = constr_set.stud.rvalue d = non_cavity_r e = misc_framing_factor cavity_r = ((3 * c + d) * Math.sqrt(4 * a**2 * b**2 + 12 * a**2 * b * e + 4 * a**2 * b + 9 * a**2 * e**2 - 6 * a**2 * e + a**2 - 48 * a * b * c - 16 * a * b * d - 36 * a * c * e + 12 * a * c - 12 * a * d * e + 4 * a * d + 36 * c**2 + 24 * c * d + 4 * d**2) + 6 * a * b * c + 2 * a * b * d + 3 * a * c * e + 3 * a * c + 3 * a * d * e + a * d - 18 * c**2 - 18 * c * d - 4 * d**2) / (2 * (-3 * a * e + 9 * c + 3 * d)) cavity_r = 3 * cavity_r - if cavity_r > 0 # Choose this construction set + if cavity_r > 0 && cavity_r < Float::INFINITY # Choose this construction set return true, constr_set, cavity_r end end return false, constr_sets[-1], 0.0 # Pick fallback construction with minimum R-value @@ -1491,18 +1685,18 @@ constr_sets.each do |constr_set| fail 'Unexpected object.' unless constr_set.is_a? SIPConstructionSet film_r = inside_film.rvalue + outside_film.rvalue non_cavity_r = calc_non_cavity_r(film_r, constr_set) - non_cavity_r += Material.new(nil, constr_set.sheath_thick_in, BaseMaterial.Wood).rvalue + non_cavity_r += Material.new(thick_in: constr_set.sheath_thick_in, mat_base: BaseMaterial.Wood).rvalue # Calculate effective SIP core R-value # Solved in Wolfram Alpha: https://www.wolframalpha.com/input/?i=1%2FA+%3D+B%2F(C%2BD)+%2B+E%2F(2*F%2BG%2FH*x%2BD)+%2B+(1-B-E)%2F(x%2BD) spline_thick_in = 0.5 # in ins_thick_in = constr_set.thick_in - (2.0 * spline_thick_in) # in - framing_r = Material.new(nil, constr_set.thick_in, BaseMaterial.Wood).rvalue - spline_r = Material.new(nil, spline_thick_in, BaseMaterial.Wood).rvalue + framing_r = Material.new(thick_in: constr_set.thick_in, mat_base: BaseMaterial.Wood).rvalue + spline_r = Material.new(thick_in: spline_thick_in, mat_base: BaseMaterial.Wood).rvalue spline_frac = 4.0 / 48.0 # One 4" spline for every 48" wide panel cavity_frac = 1.0 - (spline_frac + constr_set.framing_factor) a = assembly_r b = constr_set.framing_factor c = framing_r @@ -1510,11 +1704,11 @@ e = spline_frac f = spline_r g = ins_thick_in h = constr_set.thick_in cavity_r = (Math.sqrt((a * b * c * g - a * b * d * h - 2 * a * b * f * h + a * c * e * g - a * c * e * h - a * c * g + a * d * e * g - a * d * e * h - a * d * g + c * d * g + c * d * h + 2 * c * f * h + d**2 * g + d**2 * h + 2 * d * f * h)**2 - 4 * (-a * b * g + c * g + d * g) * (a * b * c * d * h + 2 * a * b * c * f * h - a * c * d * h + 2 * a * c * e * f * h - 2 * a * c * f * h - a * d**2 * h + 2 * a * d * e * f * h - 2 * a * d * f * h + c * d**2 * h + 2 * c * d * f * h + d**3 * h + 2 * d**2 * f * h)) - a * b * c * g + a * b * d * h + 2 * a * b * f * h - a * c * e * g + a * c * e * h + a * c * g - a * d * e * g + a * d * e * h + a * d * g - c * d * g - c * d * h - 2 * c * f * h - g * d**2 - d**2 * h - 2 * d * f * h) / (2 * (-a * b * g + c * g + d * g)) - if cavity_r > 0 # Choose this construction set + if cavity_r > 0 && cavity_r < Float::INFINITY # Choose this construction set return true, constr_set, cavity_r end end return false, constr_sets[-1], 0.0 # Pick fallback construction with minimum R-value @@ -1533,15 +1727,15 @@ # Calculate effective other CMU R-value # Assumes no furring strips # Solved in Wolfram Alpha: https://www.wolframalpha.com/input/?i=1%2FA+%3D+B%2F(C%2BE%2Bx)+%2B+(1-B)%2F(D%2BE%2Bx) a = assembly_r b = constr_set.framing_factor - c = Material.new(nil, constr_set.thick_in, BaseMaterial.Wood).rvalue # Framing - d = Material.new(nil, constr_set.thick_in, BaseMaterial.Concrete, constr_set.cond_in).rvalue # Concrete + c = Material.new(thick_in: constr_set.thick_in, mat_base: BaseMaterial.Wood).rvalue # Framing + d = Material.new(thick_in: constr_set.thick_in, mat_base: BaseMaterial.Concrete, k_in: constr_set.cond_in).rvalue # Concrete e = non_cavity_r rigid_r = 0.5 * (Math.sqrt(a**2 - 4 * a * b * c + 4 * a * b * d + 2 * a * c - 2 * a * d + c**2 - 2 * c * d + d**2) + a - c - d - 2 * e) - if rigid_r > 0 # Choose this construction set + if rigid_r > 0 && rigid_r < Float::INFINITY # Choose this construction set return true, constr_set, rigid_r end end return false, constr_sets[-1], 0.0 # Pick fallback construction with minimum R-value @@ -1559,15 +1753,15 @@ # Calculate effective ICF rigid ins R-value # Solved in Wolfram Alpha: https://www.wolframalpha.com/input/?i=1%2FA+%3D+B%2F(C%2BE)+%2B+(1-B)%2F(D%2BE%2B2*x) a = assembly_r b = constr_set.framing_factor - c = Material.new(nil, 2 * constr_set.ins_thick_in + constr_set.concrete_thick_in, BaseMaterial.Wood).rvalue # Framing - d = Material.new(nil, constr_set.concrete_thick_in, BaseMaterial.Concrete).rvalue # Concrete + c = Material.new(thick_in: 2 * constr_set.ins_thick_in + constr_set.concrete_thick_in, mat_base: BaseMaterial.Wood).rvalue # Framing + d = Material.new(thick_in: constr_set.concrete_thick_in, mat_base: BaseMaterial.Concrete).rvalue # Concrete e = non_cavity_r icf_r = (a * b * c - a * b * d - a * c - a * e + c * d + c * e + d * e + e**2) / (2 * (a * b - c - e)) - if icf_r > 0 # Choose this construction set + if icf_r > 0 && icf_r < Float::INFINITY # Choose this construction set return true, constr_set, icf_r end end return false, constr_sets[-1], 0.0 # Pick fallback construction with minimum R-value @@ -1583,11 +1777,11 @@ film_r = inside_film.rvalue + outside_film.rvalue non_cavity_r = calc_non_cavity_r(film_r, constr_set) # Calculate effective ins layer R-value layer_r = assembly_r - non_cavity_r - if layer_r > 0 # Choose this construction set + if layer_r > 0 && layer_r < Float::INFINITY # Choose this construction set return true, constr_set, layer_r end end return false, constr_sets[-1], 0.0 # Pick fallback construction with minimum R-value @@ -1711,17 +1905,33 @@ adjacent_surface = surface.adjacentSurface.get adjacent_surface.setConstruction(revconstr) end end + def set_exterior_material_properties(solar_absorptance = 0.75, emittance = 0.9) + @layers_materials[1].each do |exterior_material| + exterior_material.sAbs = solar_absorptance + exterior_material.tAbs = emittance + end + end + + def set_interior_material_properties(solar_absorptance = 0.6, emittance = 0.9, debug: false) + if @layers_materials.size > 3 # Only apply if there is a separate interior material + @layers_materials[-2].each do |interior_material| + interior_material.sAbs = solar_absorptance + interior_material.tAbs = emittance + end + end + end + private def get_parallel_material(curr_layer_num, name) # Returns a Material object with effective properties for the specified # parallel path layer of the construction. - mat = Material.new(name) + mat = Material.new(name: name) curr_layer_materials = @layers_materials[curr_layer_num] r_overall = assembly_rvalue() @@ -1765,10 +1975,16 @@ mat.cp = 0 @path_fracs.each_with_index do |path_frac, path_num| mat.cp += (curr_layer_materials[path_num].cp * curr_layer_materials[path_num].rho * path_frac) / mat.rho end + # Material solar absorptance + mat.sAbs = curr_layer_materials[0].sAbs # All paths have equal solar absorptance + + # Material thermal absorptance + mat.tAbs = curr_layer_materials[0].tAbs # All paths have equal thermal absorptance + return mat end def construct_materials(runner, model) # Create materials @@ -1820,12 +2036,12 @@ end # Check for valid object types @layers_materials.each do |layer_materials| layer_materials.each do |mat| - if (not mat.is_a? SimpleMaterial) && (not mat.is_a? Material) - fail 'Invalid construction: Materials must be instances of SimpleMaterial or Material classes.' + if (not mat.is_a? Material) + fail 'Invalid construction: Materials must be instances of Material classes.' end end end # Check if invalid number of materials in a layer @@ -1833,21 +2049,33 @@ if (layer_materials.size > 1) && (layer_materials.size < @path_fracs.size) fail 'Invalid construction: Layer must either have one material or same number of materials as paths.' end end - # Check if multiple materials in a given layer have differing thicknesses + # Check if multiple materials in a given layer have differing thicknesses/absorptances @layers_materials.each do |layer_materials| next unless layer_materials.size > 1 thick_in = nil + solar_abs = nil + emitt = nil layer_materials.each do |mat| if thick_in.nil? thick_in = mat.thick_in elsif thick_in != mat.thick_in fail 'Invalid construction: Materials in a layer have different thicknesses.' end + if solar_abs.nil? + solar_abs = mat.sAbs + elsif solar_abs != mat.sAbs + fail 'Invalid construction: Materials in a layer have different solar absorptances.' + end + if emitt.nil? + emitt = mat.tAbs + elsif emitt != mat.tAbs + fail 'Invalid construction: Materials in a layer have different thermal absorptances.' + end end end # Check if multiple non-contiguous parallel layers found_parallel = false @@ -1866,56 +2094,46 @@ # Creates (or returns an existing) OpenStudio Material from our own Material object def self.create_os_material(runner, model, material) name = material.name tolerance = 0.0001 - if material.is_a? SimpleMaterial - # Material already exists? - model.getMasslessOpaqueMaterials.each do |mat| - next if mat.roughness.downcase.to_s != 'rough' - next if (mat.thermalResistance - UnitConversions.convert(material.rvalue, 'hr*ft^2*F/Btu', 'm^2*K/W')).abs > tolerance - - return mat - end - # New material - mat = OpenStudio::Model::MasslessOpaqueMaterial.new(model) - mat.setName(name) - mat.setRoughness('Rough') - mat.setThermalResistance(UnitConversions.convert(material.rvalue, 'hr*ft^2*F/Btu', 'm^2*K/W')) - elsif material.is_a? GlazingMaterial + if material.is_a? GlazingMaterial max_ufactor = UnitConversions.convert(7.0, 'W/(m^2*K)', 'Btu/(hr*ft^2*F)') # Max value EnergyPlus allows if material.ufactor > max_ufactor runner.registerWarning("Glazing U-factor (#{material.ufactor}) for '#{material.name}' above maximum expected value. U-factor decreased to #{max_ufactor.round(2)}.") material.ufactor = max_ufactor.round(2) end # Material already exists? model.getSimpleGlazings.each do |mat| + next if !mat.name.to_s.start_with?(material.name) next if (mat.uFactor - UnitConversions.convert(material.ufactor, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)')).abs > tolerance next if (mat.solarHeatGainCoefficient - material.shgc).abs > tolerance return mat end + # New material mat = OpenStudio::Model::SimpleGlazing.new(model) mat.setName(name) mat.setUFactor(UnitConversions.convert(material.ufactor, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)')) mat.setSolarHeatGainCoefficient(material.shgc) else # Material already exists? model.getStandardOpaqueMaterials.each do |mat| + next if !mat.name.to_s.start_with?(material.name) next if mat.roughness.downcase.to_s != 'rough' next if (mat.thickness - UnitConversions.convert(material.thick_in, 'in', 'm')).abs > tolerance next if (mat.conductivity - UnitConversions.convert(material.k, 'Btu/(hr*ft*R)', 'W/(m*K)')).abs > tolerance next if (mat.density - UnitConversions.convert(material.rho, 'lbm/ft^3', 'kg/m^3')).abs > tolerance next if (mat.specificHeat - UnitConversions.convert(material.cp, 'Btu/(lbm*R)', 'J/(kg*K)')).abs > tolerance - next if (not material.tAbs.nil?) && ((mat.thermalAbsorptance - material.tAbs).abs > tolerance) - next if (not material.sAbs.nil?) && ((mat.solarAbsorptance - material.sAbs).abs > tolerance) - next if (not material.vAbs.nil?) && ((mat.visibleAbsorptance - material.vAbs).abs > tolerance) + next if (mat.thermalAbsorptance - material.tAbs.to_f).abs > tolerance + next if (mat.solarAbsorptance - material.sAbs.to_f).abs > tolerance return mat end + # New material mat = OpenStudio::Model::StandardOpaqueMaterial.new(model) mat.setName(name) mat.setRoughness('Rough') mat.setThickness(UnitConversions.convert(material.thick_in, 'in', 'm')) @@ -1925,100 +2143,98 @@ if not material.tAbs.nil? mat.setThermalAbsorptance(material.tAbs) end if not material.sAbs.nil? mat.setSolarAbsorptance(material.sAbs) + mat.setVisibleAbsorptance(material.sAbs) end - if not material.vAbs.nil? - mat.setVisibleAbsorptance(material.vAbs) - end end return mat end end class WoodStudConstructionSet - def initialize(stud, framing_factor, rigid_r, osb_thick_in, drywall_thick_in, exterior_material) + def initialize(stud, framing_factor, rigid_r, osb_thick_in, mat_int_finish, mat_ext_finish) @stud = stud @framing_factor = framing_factor @rigid_r = rigid_r @osb_thick_in = osb_thick_in - @drywall_thick_in = drywall_thick_in - @exterior_material = exterior_material + @mat_int_finish = mat_int_finish + @mat_ext_finish = mat_ext_finish end - attr_accessor(:stud, :framing_factor, :rigid_r, :osb_thick_in, :drywall_thick_in, :exterior_material) + attr_accessor(:stud, :framing_factor, :rigid_r, :osb_thick_in, :mat_int_finish, :mat_ext_finish) end class SteelStudConstructionSet - def initialize(cavity_thick_in, corr_factor, framing_factor, rigid_r, osb_thick_in, drywall_thick_in, exterior_material) + def initialize(cavity_thick_in, corr_factor, framing_factor, rigid_r, osb_thick_in, mat_int_finish, mat_ext_finish) @cavity_thick_in = cavity_thick_in @corr_factor = corr_factor @framing_factor = framing_factor @rigid_r = rigid_r @osb_thick_in = osb_thick_in - @drywall_thick_in = drywall_thick_in - @exterior_material = exterior_material + @mat_int_finish = mat_int_finish + @mat_ext_finish = mat_ext_finish end - attr_accessor(:cavity_thick_in, :corr_factor, :framing_factor, :rigid_r, :osb_thick_in, :drywall_thick_in, :exterior_material) + attr_accessor(:cavity_thick_in, :corr_factor, :framing_factor, :rigid_r, :osb_thick_in, :mat_int_finish, :mat_ext_finish) end class DoubleStudConstructionSet - def initialize(stud, framing_factor, framing_spacing, rigid_r, osb_thick_in, drywall_thick_in, exterior_material) + def initialize(stud, framing_factor, framing_spacing, rigid_r, osb_thick_in, mat_int_finish, mat_ext_finish) @stud = stud @framing_factor = framing_factor @framing_spacing = framing_spacing @rigid_r = rigid_r @osb_thick_in = osb_thick_in - @drywall_thick_in = drywall_thick_in - @exterior_material = exterior_material + @mat_int_finish = mat_int_finish + @mat_ext_finish = mat_ext_finish end - attr_accessor(:stud, :framing_factor, :framing_spacing, :rigid_r, :osb_thick_in, :drywall_thick_in, :exterior_material) + attr_accessor(:stud, :framing_factor, :framing_spacing, :rigid_r, :osb_thick_in, :mat_int_finish, :mat_ext_finish) end class SIPConstructionSet - def initialize(thick_in, framing_factor, rigid_r, sheath_thick_in, osb_thick_in, drywall_thick_in, exterior_material) + def initialize(thick_in, framing_factor, rigid_r, sheath_thick_in, osb_thick_in, mat_int_finish, mat_ext_finish) @thick_in = thick_in @framing_factor = framing_factor @rigid_r = rigid_r @sheath_thick_in = sheath_thick_in @osb_thick_in = osb_thick_in - @drywall_thick_in = drywall_thick_in - @exterior_material = exterior_material + @mat_int_finish = mat_int_finish + @mat_ext_finish = mat_ext_finish end - attr_accessor(:thick_in, :framing_factor, :rigid_r, :sheath_thick_in, :osb_thick_in, :drywall_thick_in, :exterior_material) + attr_accessor(:thick_in, :framing_factor, :rigid_r, :sheath_thick_in, :osb_thick_in, :mat_int_finish, :mat_ext_finish) end class CMUConstructionSet - def initialize(thick_in, cond_in, framing_factor, osb_thick_in, drywall_thick_in, exterior_material) + def initialize(thick_in, cond_in, framing_factor, osb_thick_in, mat_int_finish, mat_ext_finish) @thick_in = thick_in @cond_in = cond_in @framing_factor = framing_factor @osb_thick_in = osb_thick_in - @drywall_thick_in = drywall_thick_in - @exterior_material = exterior_material + @mat_int_finish = mat_int_finish + @mat_ext_finish = mat_ext_finish @rigid_r = nil # solved for end - attr_accessor(:thick_in, :cond_in, :framing_factor, :rigid_r, :osb_thick_in, :drywall_thick_in, :exterior_material) + attr_accessor(:thick_in, :cond_in, :framing_factor, :rigid_r, :osb_thick_in, :mat_int_finish, :mat_ext_finish) end class ICFConstructionSet - def initialize(ins_thick_in, concrete_thick_in, framing_factor, rigid_r, osb_thick_in, drywall_thick_in, exterior_material) + def initialize(ins_thick_in, concrete_thick_in, framing_factor, rigid_r, osb_thick_in, mat_int_finish, mat_ext_finish) @ins_thick_in = ins_thick_in @concrete_thick_in = concrete_thick_in @framing_factor = framing_factor @rigid_r = rigid_r @osb_thick_in = osb_thick_in - @drywall_thick_in = drywall_thick_in - @exterior_material = exterior_material + @mat_int_finish = mat_int_finish + @mat_ext_finish = mat_ext_finish end - attr_accessor(:ins_thick_in, :concrete_thick_in, :framing_factor, :rigid_r, :osb_thick_in, :drywall_thick_in, :exterior_material) + attr_accessor(:ins_thick_in, :concrete_thick_in, :framing_factor, :rigid_r, :osb_thick_in, :mat_int_finish, :mat_ext_finish) end class GenericConstructionSet - def initialize(rigid_r, osb_thick_in, drywall_thick_in, exterior_material) + def initialize(rigid_r, osb_thick_in, mat_int_finish, mat_ext_finish) @rigid_r = rigid_r @osb_thick_in = osb_thick_in - @drywall_thick_in = drywall_thick_in - @exterior_material = exterior_material + @mat_int_finish = mat_int_finish + @mat_ext_finish = mat_ext_finish end - attr_accessor(:rigid_r, :osb_thick_in, :drywall_thick_in, :exterior_material) + attr_accessor(:rigid_r, :osb_thick_in, :mat_int_finish, :mat_ext_finish) end