Module: BTAP::Resources::Envelope::Constructions
- Defined in:
- lib/openstudio-standards/btap/envelope.rb
Overview
This module contains methods dealing with the creation and modification of constructions.
Defined Under Namespace
Classes: ConstructionsTests
Class Method Summary collapse
-
.adjust_opaque_construction(construction:, req_conductance:) ⇒ <String]OpenStudio::Model::getConstructionByName
This removes construction layers if the required conductance for a construction is higher than the maximum conductance that construction can have.
-
.create_construction(model, name, materials, insulationLayer = nil) ⇒ String
This will create construction model.
-
.customize_fenestration_construction(model, construction, conductance = nil, solarTransmittanceatNormalIncidence = nil, visibleTransmittance = nil, at_temperature_c = 0.0) ⇒ String
This will customize fenestration construction.
-
.customize_opaque_construction(model, construction, conductance) ⇒ <String]OpenStudio::Model::getConstructionByName
This method will create a new construction based on self and a new conductance value.
-
.deep_copy(model, construction) ⇒ String
This will create a deep copy of the construction.
-
.find_and_set_insulation_layer(model, constructions_array) ⇒ String
This method will search through the layers and find the layer with the lowest conductance and set that as the insulation layer.
-
.get_conductance(construction, at_temperature_c = 0.0) ⇒ Double
this method will get the conductance (metric) of the construction.
-
.get_rsi(construction, at_temperature_c = 0.0) ⇒ Double
this method will get the rsi (metric) of the construction.
-
.get_shgc(model, construction) ⇒ Float
This model gets tsol.
-
.get_tvis(model, construction) ⇒ Float
This model gets tvis.
-
.should_modify_layer(mat_resistance:, total_conductance:, req_conductance:) ⇒ <Fixnum>
This checks if the construction layer can be modified to set thermal resistance of the whole construction to be less than the required resistance.
Class Method Details
.adjust_opaque_construction(construction:, req_conductance:) ⇒ <String]OpenStudio::Model::getConstructionByName
This removes construction layers if the required conductance for a construction is higher than the maximum conductance that construction can have. Otherwise it modifies existing layers to set their thickness or resistance values (depending on what is in the layer) to achieve the required conductance.
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 |
# File 'lib/openstudio-standards/btap/envelope.rb', line 650 def self.adjust_opaque_construction(construction:, req_conductance:) layer_comp = [] # Extract the thickness, conductivity, resistance of each layer of the construction. If the material is # "No Mass", or "Air gap" set the conductivity (how well the material conducts heat) and conductance (how well # the material with a given thickness conducts heat) to the inverse of the resistance. This is because # No Mass and Air gap materials do not have a thickness value. Also, include which layer index the material # has and the material object itself. construction.layers.each_with_index do |layer, layer_index| mat_type = layer.iddObjectType.valueName.to_s case mat_type when "OS_Material" mat_layer = layer.to_StandardOpaqueMaterial.get layer_comp << { thickness_m: mat_layer.thickness.to_f, conductivity_SI: mat_layer.conductivity.to_f, conductance_SI: (mat_layer.conductivity.to_f / mat_layer.thickness.to_f), resistance_SI: (mat_layer.thickness.to_f / mat_layer.conductivity.to_f), construction_index: layer_index, layer_object: mat_layer } when "OS_Material_NoMass" mat_layer = layer.to_MasslessOpaqueMaterial.get layer_comp << { thickness_m: 0, conductivity_SI: 1.0 / mat_layer.thermalResistance.to_f, conductance_SI: 1.0 / mat_layer.thermalResistance.to_f, resistance_SI: mat_layer.thermalResistance.to_f, construction_index: layer_index, layer_object: mat_layer } when "OS_Material_AirGap" mat_layer = layer.to_AirGap.get layer_comp << { thickness_m: 0, conductivity_SI: 1.0 / mat_layer.thermalResistance.to_f, conductance_SI: 1.0 / mat_layer.thermalResistance.to_f, resistance_SI: mat_layer.thermalResistance.to_f, construction_index: layer_index, layer_object: mat_layer } end end # Sort the above layers by the conductivity of the layers. The lowest conductivity layers first followed by # layers with progressively higher conductivities. sorted_layers = layer_comp.sort { |a, b| b[:conductivity_SI] <=> a[:conductivity_SI] } index = 0 total_conductance = construction.thermalConductance.to_f # The following loop steps through the array of layers, sorted form highest conductivity to lowest. It # deletes a layer in the construction if the conductance for the layer is not enough to reach the total # conductance for the construction that we are trying to reach. If modifies the thickness or resistance # (depending on the layer material type) of a layer if doing so will reach the overall construction # conductance target. The total conductance of the construction is rounded because the conductance never seems # to be set precisely enough. while total_conductance.round(4) < req_conductance # There are too indicies that are tracked: # index: The index of the element in the sorted array of layers that we are currently considering # const_index: The index of the layer we are currently considering in the construction # Note that both the construction array and sorted array contain the same elements. However these elements # may be in a different order. Thus, the index and const_index may be different. They will both indicate # the same layer. However, they may differ because the sorted array is sorted by conductivity while the # construction array is ordered with the first layer outside (a given space) and the final layer inside (a # given space). const_index = sorted_layers[index][:construction_index] # Check if modifying the resistance of the currently layer will be enough to reach our total construction # conductance goal. If it will, modify the layer. If it will not, delete the layer. if sorted_layers[index][:resistance_SI] > ((1.0 / total_conductance) - (1.0 / req_conductance)) # If the current layer is a NoMass or AirGap material its thickness is zero so we set the resistance. if sorted_layers[index][:thickness_m] == 0 # Determine the resistance we want to set the layer to. res_mod = sorted_layers[index][:resistance_SI] - ((1.0 / total_conductance) - (1.0 / req_conductance)) # Find out if the layer is an AirGap or NoMass and set the resistance for the layer with the right # command systax. mat_type = construction.layers[const_index].iddObjectType.valueName.to_s case mat_type when "OS_Material_NoMass" construction.layers[const_index].to_MasslessOpaqueMaterial.get.setThermalResistance(res_mod) when "OS_Material_AirGap" construction.layers[const_index].to_AirGap.get.setThermalResistance(res_mod) end else # The the current layer is a regular opaque material it has a thickness so we set that to reach the # desired resistance for that layer. # Determine the thickness we want to set the layer. thick_mod = (sorted_layers[index][:resistance_SI] - ((1.0 / total_conductance) - (1.0 / req_conductance))) * (sorted_layers[index][:conductivity_SI]) # Set the thickness of the layer. construction.layers[const_index].to_StandardOpaqueMaterial.get.setThickness(thick_mod) end # Step the index of the sorted array forward by 1. We should be able to leave the loop now because the # construction should have the conductance we want now. But you never know. index += 1 else # There the layer could not be adjusted to reach the desired conductance for the construction so get rid # of the layer. # If this is the only layer then we cannot get rid of it so throw an error. This should never happen but # you never know. if sorted_layers.size == 1 raise ("Could not set conductance of construction #{construction.name.to_s} to #{req_conductance} because existing layers make this impossible. Could not automatically change the constructions. Change the construction to allow for this conductance to be set.") return construction end # Delete the layer from the construction. construction.eraseLayer(const_index) # Delete the layer from the sorted set of layers (so that both the construction array and sorted array # continue to contain the same layers). sorted_layers.delete_at(index) # Go through the sorted array and change the construction indicies so that they continue to point to the # correct layers of the construction array. Note that index is not increased. This is because the element # we were looking at just got removed so its index will be the same as that of what would have been the # next element. sorted_layers.each do |sorted_layer| if sorted_layer[:construction_index] > (const_index - 1) sorted_layer[:construction_index] -= 1 end end end # Get the revised conductance for the construction now that it has been modified (by either removing or # modifying layers). total_conductance = construction.thermalConductance.to_f # Check if we have anything left to modify. If yes, then keep going. If not, then if we have done enough # we can stop and return the revised construction, otherwise throw an error. if construction.layers.size < index + 1 if total_conductance.round(4) >= req_conductance return construction else raise ("Could not set conductance of construction #{construction.name.to_s} from the current conductance of #{total_conductance} to #{req_conductance} because existing layers make this impossible. Change the construction to allow for this conductance to be set.") return construction end end end # We have achieved our goal, return the revised construction. return construction end |
.create_construction(model, name, materials, insulationLayer = nil) ⇒ String
This will create construction model
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 |
# File 'lib/openstudio-standards/btap/envelope.rb', line 896 def self.create_construction(model, name, materials, insulationLayer = nil) construction = OpenStudio::Model::Construction.new(model) construction.setName(name) #check to see if they are all Fenestation or Opaque. Can't mix and match. is_fenestration = false is_opaque = false #check to see if materials are all the same type. materials.each do |material| is_fenestration = true unless material.to_FenestrationMaterial.empty? is_opaque = true unless material.to_OpaqueMaterial.empty? end raise ("Materials Passed are not valid. Either they are mixed Opaque/Fenestration or invalid materials") if (is_fenestration and is_opaque) or (not is_fenestration and not is_opaque) construction.setLayers(materials) construction.setInsulation(insulationLayer) unless nil == insulationLayer or is_fenestration return construction end |
.customize_fenestration_construction(model, construction, conductance = nil, solarTransmittanceatNormalIncidence = nil, visibleTransmittance = nil, at_temperature_c = 0.0) ⇒ String
This will customize fenestration construction
922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 |
# File 'lib/openstudio-standards/btap/envelope.rb', line 922 def self.customize_fenestration_construction( model, construction, conductance = nil, solarTransmittanceatNormalIncidence = nil, visibleTransmittance = nil, at_temperature_c = 0.0) construction = OpenStudio::Model::getConstructionByName(model, construction.name.to_s).get raise ("This is not a fenestration!") unless construction.isFenestration #get equivilant values for tsol, tvis, and conductances. #TSol in this case is SHGC solarTransmittanceatNormalIncidence = self.get_shgc(model, construction) if solarTransmittanceatNormalIncidence.nil? visibleTransmittance = self.get_tvis(model, construction) if visibleTransmittance == nil conductance = self.get_conductance(construction) if conductance == nil frontSideSolarReflectanceatNormalIncidence = 1.0 - solarTransmittanceatNormalIncidence backSideSolarReflectanceatNormalIncidence = 1.0 - solarTransmittanceatNormalIncidence frontSideVisibleReflectanceatNormalIncidence = 0.081000 backSideVisibleReflectanceatNormalIncidence = 0.081000 infraredTransmittanceatNormalIncidence = 0.0 frontSideInfraredHemisphericalEmissivity = 0.84 backSideInfraredHemisphericalEmissivity = 0.84 #store part of fenestation in array bins. glazing_array = Array.new() shading_material_array = Array.new() gas_array = Array.new() construction.layers.each do |material| glazing_array << material unless material.to_Glazing.empty? shading_material_array << material unless material.to_ShadingMaterial.empty? gas_array << material unless material.to_GasLayer.empty? end #set value of fictious glazing based on the fenestrations front and back if available unless glazing_array.first.to_StandardGlazing.empty? frontSideSolarReflectanceatNormalIncidence = glazing_array.first.to_StandardGlazing.get.frontSideSolarReflectanceatNormalIncidence frontSideVisibleReflectanceatNormalIncidence = glazing_array.first.to_StandardGlazing.get.frontSideVisibleReflectanceatNormalIncidence frontSideInfraredHemisphericalEmissivity = glazing_array.first.to_StandardGlazing.get.frontSideInfraredHemisphericalEmissivity end unless glazing_array.last.to_StandardGlazing.empty? backSideSolarReflectanceatNormalIncidence = glazing_array.last.to_StandardGlazing.get.backSideSolarReflectanceatNormalIncidence backSideVisibleReflectanceatNormalIncidence = glazing_array.last.to_StandardGlazing.get.backSideVisibleReflectanceatNormalIncidence backSideInfraredHemisphericalEmissivity = glazing_array.last.to_StandardGlazing.get.backSideInfraredHemisphericalEmissivity end #create fictious glazing. #assume a thickness of 0.10m thickness = 0.10 #calculate conductivity conductivity = conductance * thickness data_name_suffix = "U=#{("%.3f" % conductivity).to_s} SHGC=#{("%.3f" % solarTransmittanceatNormalIncidence).to_s}" base_cons_name = construction.name.to_s if match = construction.name.to_s.match(/(.*)?:(.*)?/) base_cons_name = match.captures[0] end cons_name = "#{base_cons_name}:" + data_name_suffix glazing_name = "SimpleGlazing:" + data_name_suffix #Search to prevent the massive duplication that may ensue. return model.getConstructionByName(cons_name).get unless model.getConstructionByName(cons_name).empty? #fix for Simple glazing glazing_name = "SimpleGlazing:" + data_name_suffix glazing = nil if model.getSimpleGlazingByName(glazing_name).empty? glazing_name = "SimpleGlazing:" + data_name_suffix glazing = OpenStudio::Model::SimpleGlazing.new(construction.model) glazing.setSolarHeatGainCoefficient(solarTransmittanceatNormalIncidence) glazing.setUFactor(conductance) glazing.setThickness(0.21) glazing.setVisibleTransmittance(visibleTransmittance) glazing.setName(glazing_name) else glazing = model.getSimpleGlazingByName(glazing_name).get end #add the glazing and any shading materials to the array and create construction based on this. new_materials_array = Array.new() new_materials_array << glazing new_materials_array.concat(shading_material_array) unless shading_material_array.empty? #puts new_materials_array.size return self.create_construction(construction.model, cons_name, new_materials_array) end |
.customize_opaque_construction(model, construction, conductance) ⇒ <String]OpenStudio::Model::getConstructionByName
This method will create a new construction based on self and a new conductance value. It will check to see if a similar construction has already been created by this method if so it will return the existing construction. If you wish to keep some of the properties, enter the string “default” instead of a numerical value.
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 |
# File 'lib/openstudio-standards/btap/envelope.rb', line 595 def self.customize_opaque_construction(model, construction, conductance) #Will convert from a string identifier to an object if required. construction = BTAP::Common::validate_array(model, construction, "Construction").first #If it is Opaque raise ("This construction is not opaque :#{construction.name}") unless (construction.isOpaque) minimum_resistance = 0 base_cons_name = construction.name.to_s if match = construction.name.to_s.match(/(.*)?:(.*)?/) base_cons_name = match.captures[0] end name_prefix = "#{base_cons_name}:U-#{conductance}" #Check to see if we already made one like this. existing_construction = OpenStudio::Model::getConstructionByName(construction.model, name_prefix) if not existing_construction.empty? # if so, return existing construction return existing_construction.get end #create a copy new_construction = self.deep_copy(model, construction) #Change Construction name in clone new_construction.setName(name_prefix) if conductance.kind_of?(Float) #re-find insulation layer find_and_set_insulation_layer(model, new_construction) #Determine how low the resistance can be set. Subtract exisiting insulation #Values from the total resistance to see how low we can go. minimum_resistance = (1 / new_construction.thermalConductance.to_f) - (1.0 / new_construction.insulation.get.thermalConductance.to_f) #Check if the requested resistance is smaller than the minimum # resistance. If so, revise the construction layers. if minimum_resistance > (1 / conductance) # Changing the insulation layer will not be enough so either start removing layers or modify them to get # to the required conductance. new_construction = adjust_opaque_construction(construction: new_construction, req_conductance: conductance.to_f) else unless new_construction.setConductance(conductance) raise("could not set conductance of construction #{new_construction.name.to_s}") end end end return new_construction end |
.deep_copy(model, construction) ⇒ String
This will create a deep copy of the construction
876 877 878 879 880 881 882 883 884 885 886 887 |
# File 'lib/openstudio-standards/btap/envelope.rb', line 876 def self.deep_copy(model, construction) construction = BTAP::Common::validate_array(model, construction, "Construction").first new_construction = construction.clone.to_Construction.get #interating through layers." (0..new_construction.layers.length - 1).each do |layernumber| #cloning material" cloned_layer = new_construction.getLayer(layernumber).clone.to_Material.get #"setting material to new construction." new_construction.setLayer(layernumber, cloned_layer) end return new_construction end |
.find_and_set_insulation_layer(model, constructions_array) ⇒ String
This method will search through the layers and find the layer with the lowest conductance and set that as the insulation layer. Note: Concrete walls or slabs with no insulation layer but with a carper will see the carpet as the insulation layer.
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
# File 'lib/openstudio-standards/btap/envelope.rb', line 547 def self.find_and_set_insulation_layer(model, constructions_array) constructions_array = BTAP::Common::validate_array(model, constructions_array, "Construction") insulating_layers = Array.new() constructions_array.each do |construction| return_material = "" #skip if already has an insulation layer set. next unless construction.insulation.empty? #set insulation layer. #find insulation layer min_conductance = 100.0 #loop through Layers construction.layers.each do |layer| #try casting the layer to an OpaqueMaterial. material = nil material = layer.to_OpaqueMaterial.get unless layer.to_OpaqueMaterial.empty? material = layer.to_FenestrationMaterial.get unless layer.to_FenestrationMaterial.empty? #check if the cast was successful, then find the insulation layer. unless nil == material if BTAP::Resources::Envelope::Materials::get_conductance(material) < min_conductance #Keep track of the highest thermal resistance value. min_conductance = BTAP::Resources::Envelope::Materials::get_conductance(material) return_material = material unless material.to_OpaqueMaterial.empty? construction.setInsulation(material) end end end end if construction.insulation.empty? and construction.isOpaque raise ("construction #{construction.name.get.to_s} insulation layer could not be set!. This occurs when a insulation layer is duplicated in the construction.") end insulating_layers << return_material end return insulating_layers end |
.get_conductance(construction, at_temperature_c = 0.0) ⇒ Double
this method will get the conductance (metric) of the construction.
850 851 852 853 854 855 856 857 858 859 |
# File 'lib/openstudio-standards/btap/envelope.rb', line 850 def self.get_conductance(construction, at_temperature_c = 0.0) #if , by accidnet a construction base was passed...convert it to a construction object. construction = OpenStudio::Model::getConstructionByName(construction.model, construction.name.to_s).get unless construction.to_ConstructionBase.empty? total = 0.0 construction.layers.each do |material| total = total + 1.0 / BTAP::Resources::Envelope::Materials::get_conductance(material, at_temperature_c) end return 1.0 / total end |
.get_rsi(construction, at_temperature_c = 0.0) ⇒ Double
this method will get the rsi (metric) of the construction.
866 867 868 |
# File 'lib/openstudio-standards/btap/envelope.rb', line 866 def self.get_rsi(construction, at_temperature_c = 0.0) return 1.0 / self.get_conductance(construction, at_temperature_c) end |
.get_shgc(model, construction) ⇒ Float
This model gets tsol
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 |
# File 'lib/openstudio-standards/btap/envelope.rb', line 809 def self.get_shgc(model, construction) construction = BTAP::Common::validate_array(model, construction, "Construction").first construction = OpenStudio::Model::getConstructionByName(model, construction.name.to_s).get tsol = 1.0 if construction.isFenestration construction.layers.each do |layer| #check to see if it is a simple glazing. If so use the SHGC method. tsol = tsol * layer.to_SimpleGlazing.get.solarHeatGainCoefficient unless layer.to_SimpleGlazing.empty? #check to see if it is a standard glazing. If so use the solar transmittance method. tsol = tsol * layer.to_StandardGlazing.get.solarTransmittance unless layer.to_StandardGlazing.empty? end end return tsol end |
.get_tvis(model, construction) ⇒ Float
This model gets tvis
830 831 832 833 834 835 836 837 838 839 840 841 842 843 |
# File 'lib/openstudio-standards/btap/envelope.rb', line 830 def self.get_tvis(model, construction) construction = BTAP::Common::validate_array(model, construction, "Construction").first construction = OpenStudio::Model::getConstructionByName(model, construction.name.to_s).get tvis = 1.0 if construction.isFenestration construction.layers.each do |layer| #check to see if it is a simple glazing. If so use the SHGC method. tvis = tvis * layer.to_SimpleGlazing.get.visibleTransmittance.get unless layer.to_SimpleGlazing.empty? || layer.to_SimpleGlazing.get.visibleTransmittance.empty? #check to see if it is a standard glazing. If so use the solar transmittance method. tvis = tvis * layer.to_StandardGlazing.get.visibleTransmittanceatNormalIncidence.get unless layer.to_StandardGlazing.empty? || layer.to_StandardGlazing.get.visibleTransmittanceatNormalIncidence.empty? end end return tvis end |
.should_modify_layer(mat_resistance:, total_conductance:, req_conductance:) ⇒ <Fixnum>
This checks if the construction layer can be modified to set thermal resistance of the whole construction to be less than the required resistance
790 791 792 793 794 795 796 797 798 799 800 801 802 |
# File 'lib/openstudio-standards/btap/envelope.rb', line 790 def self.should_modify_layer(mat_resistance:, total_conductance:, req_conductance:) # Determine if the amount of resistance you can modify in this layer is greater than the amount of resistance # you have to change. if mat_resistance > ((1.0 / total_conductance) - (1.0 / req_conductance)) # If yes, determine what the resistance for this layer should be to meet the required resistance of the # entire assembly. Then return the new resistance value. target_res = mat_resistance - ((1.0 / total_conductance) - (1.0 / req_conductance)) return target_res else # If no, then return an unambiguous no. return -999 end end |