Class: SetSpaceInfiltrationByExteriorSurfaceArea
- Inherits:
-
OpenStudio::Measure::ModelMeasure
- Object
- OpenStudio::Measure::ModelMeasure
- SetSpaceInfiltrationByExteriorSurfaceArea
- Defined in:
- lib/measures/SetSpaceInfiltrationByExteriorSurfaceArea/measure.rb
Overview
start the measure
Instance Method Summary collapse
-
#arguments(model) ⇒ Object
define the arguments that the user will input.
-
#name ⇒ Object
define the name that a user will see.
-
#neat_numbers(number, roundto = 2) ⇒ Object
short def to make numbers pretty (converts 4125001.25641 to 4,125,001.26 or 4,125,001).
-
#run(model, runner, user_arguments) ⇒ Object
define what happens when the measure is run.
-
#unit_helper(number, from_unit_string, to_unit_string) ⇒ Object
helper to make it easier to do unit conversions on the fly.
Instance Method Details
#arguments(model) ⇒ Object
define the arguments that the user will input
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/measures/SetSpaceInfiltrationByExteriorSurfaceArea/measure.rb', line 14 def arguments(model) args = OpenStudio::Measure::OSArgumentVector.new # make an argument for infiltration infiltration_ip = OpenStudio::Measure::OSArgument.makeDoubleArgument('infiltration_ip', true) infiltration_ip.setDisplayName('Space Infiltration Flow per Exterior Envelope Surface Area (cfm/ft^2).') # (ft^3/min)/(ft^2) = (ft/min) infiltration_ip.setDefaultValue(0.05) args << infiltration_ip # make an argument for material and installation cost material_cost_ip = OpenStudio::Measure::OSArgument.makeDoubleArgument('material_cost_ip', true) material_cost_ip.setDisplayName('Increase in Material and Installation Costs for Building per Exterior Envelope Area ($/ft^2).') material_cost_ip.setDefaultValue(0.0) args << material_cost_ip # make an argument for o&m cost om_cost_ip = OpenStudio::Measure::OSArgument.makeDoubleArgument('om_cost_ip', true) om_cost_ip.setDisplayName('O & M Costs for Construction per Area Used ($/ft^2).') om_cost_ip.setDefaultValue(0.0) args << om_cost_ip # make an argument for o&m frequency om_frequency = OpenStudio::Measure::OSArgument.makeIntegerArgument('om_frequency', true) om_frequency.setDisplayName('O & M Frequency (whole years).') om_frequency.setDefaultValue(1) args << om_frequency return args end |
#name ⇒ Object
define the name that a user will see
9 10 11 |
# File 'lib/measures/SetSpaceInfiltrationByExteriorSurfaceArea/measure.rb', line 9 def name return 'Set Space Infiltration by Exterior Surface Area' end |
#neat_numbers(number, roundto = 2) ⇒ Object
short def to make numbers pretty (converts 4125001.25641 to 4,125,001.26 or 4,125,001). The definition be called through this measure
71 72 73 74 75 76 77 78 79 |
# File 'lib/measures/SetSpaceInfiltrationByExteriorSurfaceArea/measure.rb', line 71 def neat_numbers(number, roundto = 2) # round to 0 or 2) if roundto == 2 number = format '%.2f', number else number = number.round end # regex to add commas number.to_s.reverse.gsub(/([0-9]{3}(?=([0-9])))/, '\\1,').reverse end |
#run(model, runner, user_arguments) ⇒ Object
define what happens when the measure is run
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/measures/SetSpaceInfiltrationByExteriorSurfaceArea/measure.rb', line 45 def run(model, runner, user_arguments) super(model, runner, user_arguments) # use the built-in error checking if !runner.validateUserArguments(arguments(model), user_arguments) return false end # assign the user inputs to variables infiltration_ip = runner.getDoubleArgumentValue('infiltration_ip', user_arguments) material_cost_ip = runner.getDoubleArgumentValue('material_cost_ip', user_arguments) years_until_costs_start = 0 # removed user argument and set it to 0. For this measure it should always be 0 om_cost_ip = runner.getDoubleArgumentValue('om_cost_ip', user_arguments) om_frequency = runner.getIntegerArgumentValue('om_frequency', user_arguments) # check infiltration for reasonableness if infiltration_ip < 0 runner.registerError("The requested space infiltration flow rate of #{infiltration_ip} cfm/ft^2 was below the measure limit. Choose a positive number.") return false elsif infiltration_ip == 0.001 # put more thought into best warning trigger value runner.registerWarning("The requested space infiltration flow rate of #{infiltration_ip} cfm/ft^2 seems abnormally low.") elsif infiltration_ip > 1.0 # put more thought into best warning trigger value runner.registerWarning("The requested space infiltration flow rate of #{infiltration_ip} cfm/ft^2 seems abnormally high.") end # short def to make numbers pretty (converts 4125001.25641 to 4,125,001.26 or 4,125,001). The definition be called through this measure def neat_numbers(number, roundto = 2) # round to 0 or 2) if roundto == 2 number = format '%.2f', number else number = number.round end # regex to add commas number.to_s.reverse.gsub(/([0-9]{3}(?=([0-9])))/, '\\1,').reverse end # helper to make it easier to do unit conversions on the fly def unit_helper(number, from_unit_string, to_unit_string) converted_number = OpenStudio.convert(OpenStudio::Quantity.new(number, OpenStudio.createUnit(from_unit_string).get), OpenStudio.createUnit(to_unit_string).get).get.value end # get space infiltration objects used in the model space_infiltration_objects = model.getSpaceInfiltrationDesignFlowRates # reporting initial condition of model if !space_infiltration_objects.empty? runner.registerInitialCondition("The initial model contained #{space_infiltration_objects.size} space infiltration objects.") else runner.registerInitialCondition('The initial model did not contain any space infiltration objects.') end # remove space infiltration objects number_removed = 0 number_left = 0 space_infiltration_objects.each do |space_infiltration_object| opt_space_type = space_infiltration_object.spaceType if opt_space_type.empty? space_infiltration_object.remove number_removed += 1 elsif !opt_space_type.get.spaces.empty? space_infiltration_object.remove number_removed += 1 else number_left += 1 end end if number_removed > 0 runner.registerInfo("#{number_removed} infiltration objects were removed.") end if number_left > 0 runner.registerInfo("#{number_left} infiltration objects in unused space types were left in the model. They will not be altered.") end # if no default space type then add an empty one (to hold new space infiltration object) building = model.getBuilding if building.spaceType.empty? new_default = OpenStudio::Model::SpaceType.new(model) new_default.setName('Building Default Space Type') building.setSpaceType(new_default) runner.registerInfo("Adding a building default space type to hold space infiltration for spaces that previously didn't have a space type.") end # si units for infiltration argument infiltration_si = unit_helper(infiltration_ip, 'ft/min', 'm/s') # loop through spacetypes used in the model adding space infiltration objects space_types = model.getSpaceTypes space_types.each do |space_type| if !space_type.spaces.empty? new_space_type_infil = OpenStudio::Model::SpaceInfiltrationDesignFlowRate.new(model) new_space_type_infil.setFlowperExteriorSurfaceArea(infiltration_si) new_space_type_infil.setSpaceType(space_type) if new_space_type_infil.schedule.empty? # TODO: - check if the warning below is falsely triggering when it does not need to. runner.registerWarning("The new infiltration object for space type '#{space_type.name}' does not have a schedule. Assigning a default schedule set including an infiltration schedule to the space type or the building will address this.") end end end # get area of surfaces with outdoor boundary condition. Take zone multipliers into account surfaces = model.getSurfaces exterior_surface_gross_area = 0 space_warning_issued = [] surfaces.each do |s| next if s.outsideBoundaryCondition != 'Outdoors' # get surface area adjusting for zone multiplier space = s.space if !space.empty? zone = space.get.thermalZone end if !zone.empty? zone_multiplier = zone.get.multiplier if (zone_multiplier > 1) && !space_warning_issued.include?(space.get.name.to_s) runner.registerInfo("Space #{space.get.name} in thermal zone #{zone.get.name} has a zone multiplier of #{zone_multiplier}. Adjusting area calculations.") space_warning_issued << space.get.name.to_s end else zone_multiplier = 1 # space is not in a thermal zone runner.registerWarning("Space #{space.get.name} is not in a thermal zone and won't be included in in the simulation. For area calculations in this measure a zone multiplier of 1 will be assumed.") end exterior_surface_gross_area += s.grossArea * zone_multiplier end # ip exterior surface area for reporting and building lifeCycleCostObject exterior_surface_gross_area_ip = unit_helper(exterior_surface_gross_area, 'm^2', 'ft^2') # only add LifeCyCyleCostItem if the user entered some non 0 cost values if (material_cost_ip != 0) || (om_cost_ip != 0) material_cost_si = unit_helper(material_cost_ip, '1/ft^2', '1/m^2') om_cost_si = unit_helper(om_cost_ip, '1/ft^2', '1/m^2') lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost('LCC_Mat - Cost to Adjust Infiltration', building, exterior_surface_gross_area * material_cost_si, 'CostPerEach', 'Construction', 0, years_until_costs_start) # 0 for expected life will result infinite expected life lcc_om = OpenStudio::Model::LifeCycleCost.createLifeCycleCost('LCC_OM - Cost to Adjust Infiltration', building, exterior_surface_gross_area * om_cost_si, 'CostPerEach', 'Maintenance', om_frequency, years_until_costs_start) # o&m costs start after at sane time that material and installation costs occur runner.registerInfo("Costs related to the change in infiltration are attached to the building object. Any subsequent measures that may affect infiltration won't affect these costs.") else runner.registerInfo('Cost arguments were not provided, no cost objects were added to the model.') end # reporting final condition of model if !lcc_mat.nil? cost_per_area_ip = lcc_mat.get.totalCost / exterior_surface_gross_area_ip else cost_per_area_ip = 0 end runner.registerFinalCondition("The final model has an infiltration rate of #{neat_numbers(infiltration_ip)} (cfm/ft^2). The material and installation cost increase resulting from this measure is $#{neat_numbers(cost_per_area_ip)} ($/ft^2) over #{neat_numbers(exterior_surface_gross_area_ip, 0)} (ft^2) of exterior envelope.") return true end |
#unit_helper(number, from_unit_string, to_unit_string) ⇒ Object
helper to make it easier to do unit conversions on the fly
82 83 84 |
# File 'lib/measures/SetSpaceInfiltrationByExteriorSurfaceArea/measure.rb', line 82 def unit_helper(number, from_unit_string, to_unit_string) converted_number = OpenStudio.convert(OpenStudio::Quantity.new(number, OpenStudio.createUnit(from_unit_string).get), OpenStudio.createUnit(to_unit_string).get).get.value end |