Class: AirWallZoneMixing
- Inherits:
-
OpenStudio::Measure::ModelMeasure
- Object
- OpenStudio::Measure::ModelMeasure
- AirWallZoneMixing
- Defined in:
- lib/measures/air_wall_zone_mixing/measure.rb
Overview
start the measure
Instance Method Summary collapse
-
#arguments(model) ⇒ Object
define the arguments that the user will input.
-
#description ⇒ Object
human readable description.
-
#modeler_description ⇒ Object
human readable description of modeling approach.
-
#name ⇒ Object
human readable name.
-
#run(model, runner, user_arguments) ⇒ Object
define what happens when the measure is run.
Instance Method Details
#arguments(model) ⇒ Object
define the arguments that the user will input
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/measures/air_wall_zone_mixing/measure.rb', line 32 def arguments(model) args = OpenStudio::Measure::OSArgumentVector.new # the name of the space to add to the model zone_mixing_coef = OpenStudio::Measure::OSArgument.makeDoubleArgument('zone_mixing_coef', true) zone_mixing_coef.setDisplayName('Cross Mixing Coefficient') zone_mixing_coef.setDescription('Cross Mixing flow rate = zone mixing coefficient * zone volume/sqrt(thermal zone volume/(air wall area*zone height))') zone_mixing_coef.setDefaultValue(1.0) args << zone_mixing_coef # the name of the space to add to the model add_zone_mixing_variables = OpenStudio::Measure::OSArgument.makeBoolArgument('add_zone_mixing_variables', true) add_zone_mixing_variables.setDisplayName('Add Zone Mixing Output Variable Requests') add_zone_mixing_variables.setDefaultValue(true) args << add_zone_mixing_variables return args end |
#description ⇒ Object
human readable description
19 20 21 |
# File 'lib/measures/air_wall_zone_mixing/measure.rb', line 19 def description return "This measure replaces conductive heat transfer with zone mixing wherever air walls are used on matched surfaces or sub-surfaces for walls. A user argument is exposed for a coefficient that represents a target air changes per hour (ACH) for a room where the zone volume/the air wall surface area is the same as its zone height. As the room gets deeper the additional airflow per unit of depth decreases. If two zones have different mixing estimates, the lower will be used. If a smaller portion of an inter-zone wall is an air wall, that will also decrease zone mixing airflow. A construction will be hard assigned to the matched surfaces using the air wall, and the then boundary condition will be changed to adiabatic. This will avoid including both air mixing and conductive transfer across zones. Zone mixing objects will also be made for sub-surface air walls, but they can't be made adiabatic unless their base surface also is. A warning will be issued if that happens" end |
#modeler_description ⇒ Object
human readable description of modeling approach
24 25 26 27 28 |
# File 'lib/measures/air_wall_zone_mixing/measure.rb', line 24 def modeler_description return "The formula used to determine the design flow rate is the zone mixing coefficient * zone volume/sqrt(zone volume / (air wall area * zone height). Zone mixing will only be added where there is an air wall and where the matched surfaces belong to spaces in different thermal zones and the base surface type is a wall. Currently floors are not addressed by this measure. Air walls in spaces that are part of the same thermal zone will be left alone. The intended use case is a single base surface that spans the room or one or more sub-surface that spans a portion of it. If you have multiple air wall base surfaces matched between the same zones you may get higher than expected zone mixing." end |
#name ⇒ Object
human readable name
14 15 16 |
# File 'lib/measures/air_wall_zone_mixing/measure.rb', line 14 def name return 'Air Wall Zone Mixing' end |
#run(model, runner, user_arguments) ⇒ Object
define what happens when the measure is run
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 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/measures/air_wall_zone_mixing/measure.rb', line 52 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 zone_mixing_coef = runner.getDoubleArgumentValue('zone_mixing_coef', user_arguments) add_zone_mixing_variables = runner.getBoolArgumentValue('add_zone_mixing_variables', user_arguments) # report initial condition of model runner.registerInitialCondition("The building started with #{model.getZoneMixings.size} Zone Mixing Objects.") # array of surfaces and sub-surfaces already processed processed_surfaces = [] processed_sub_surfaces = [] # populate a hash of zone volumes ahead of time zone_volumes = {} zone_heights = {} model.getThermalZones.sort.each do |zone| volume_counter = 0 max_space_height = 0 zone.spaces.each do |space| volume_counter += space.volume min_space_zvalue = OpenstudioStandards::Geometry.surfaces_get_z_values(space.surfaces).sort.first # this expects an array of surfaces max_space_zvalue = OpenstudioStandards::Geometry.surfaces_get_z_values(space.surfaces).sort.last # this expects an array of surfaces if max_space_zvalue - min_space_zvalue > max_space_height max_space_height = max_space_zvalue - min_space_zvalue end end zone_volumes[zone] = volume_counter zone_heights[zone] = max_space_height puts "volume of #{zone.name} is #{volume_counter}" end model.getThermalZones.sort.each do |zone| zone.spaces.each do |space| space.surfaces.each do |surface| next if processed_surfaces.include? surface next if surface.surfaceType != 'Wall' next if surface.adjacentSurface.is_initialized != true adiabatic = false boundary_surface = surface.adjacentSurface.get processed_surfaces << surface processed_surfaces << boundary_surface if boundary_surface.space.is_initialized && boundary_surface.space.get.thermalZone.is_initialized boundary_object_zone = boundary_surface.space.get.thermalZone.get if zone.multiplier != boundary_object_zone.multiplier runner.registerWarning("#{zone.name} and #{boundary_object_zone.name} don't have the same multiplier. Won't alter surfaces or add zone mixing for this pair of zones") next end if boundary_object_zone != zone # check surface constructions if surface.isAirWall air_wall_area = surface.grossArea zone_a_volume = zone_volumes[zone] zone_a_height = zone_heights[zone] zone_b_volume = zone_volumes[boundary_object_zone] zone_b_height = zone_heights[boundary_object_zone] if zone_a_volume <= zone_b_volume zone_volume = zone_a_volume zone_height = zone_a_height else zone_volume = zone_b_volume zone_height = zone_b_height end # calculate target zone mixing values # zone_mixing_coef * zone_volume m^3 / (Math.sqrt(zone_volume m^3/ air_wall_area m^2 * zone_height m)) target_zone_mixing_hour_si = zone_mixing_coef * zone_volume / Math.sqrt(zone_volume / (air_wall_area * zone_height)) target_zone_mixing_si = target_zone_mixing_hour_si / 3600.0 zone_mixing_a = OpenStudio::Model::ZoneMixing.new(zone) zone_mixing_a.setSourceZone(boundary_object_zone) zone_mixing_a.setDesignFlowRate(target_zone_mixing_si) zone_mixing_a.setDeltaTemperature(0.0) zone_mixing_b = OpenStudio::Model::ZoneMixing.new(boundary_object_zone) zone_mixing_b.setSourceZone(zone) zone_mixing_b.setDesignFlowRate(target_zone_mixing_si) zone_mixing_b.setDeltaTemperature(0.0) target_zone_mixing_ip = OpenStudio.convert(target_zone_mixing_si, 'm^3/s', 'cfm').get runner.registerInfo("Add zone mixing between #{zone.name} and #{boundary_object_zone.name} with flowrate of #{target_zone_mixing_ip.round(2)} cfm") adiabatic = true end # check sub_surfaces constructions surface.subSurfaces.each do |sub_surface| next if sub_surface.adjacentSubSurface.is_initialized != true boundary_sub_surface = sub_surface.adjacentSubSurface.get processed_sub_surfaces << sub_surface processed_sub_surfaces << boundary_sub_surface if sub_surface.isAirWall air_wall_area = surface.grossArea zone_a_volume = zone_volumes[zone] zone_a_height = zone_heights[zone] zone_b_volume = zone_volumes[boundary_object_zone] zone_b_height = zone_heights[boundary_object_zone] if zone_a_volume <= zone_b_volume zone_volume = zone_a_volume zone_height = zone_a_height else zone_volume = zone_b_volume zone_height = zone_b_height end # calculate target zone mixing values # zone_mixing_coef * zone_volume m^3 / (Math.sqrt(zone_volume m^3/ air_wall_area m^2 * zone_height m)) target_zone_mixing_hour_si = zone_mixing_coef * zone_volume / Math.sqrt(zone_volume / (air_wall_area * zone_height)) target_adjusted_sub_surface_fraction = target_zone_mixing_hour_si * sub_surface.grossArea / surface.grossArea target_zone_mixing_si = target_adjusted_sub_surface_fraction / 3600.0 zone_mixing_a = OpenStudio::Model::ZoneMixing.new(zone) zone_mixing_a.setSourceZone(boundary_object_zone) zone_mixing_a.setDesignFlowRate(target_zone_mixing_si) zone_mixing_a.setDeltaTemperature(0.0) zone_mixing_b = OpenStudio::Model::ZoneMixing.new(boundary_object_zone) zone_mixing_b.setSourceZone(zone) zone_mixing_b.setDesignFlowRate(target_zone_mixing_si) zone_mixing_b.setDeltaTemperature(0.0) target_zone_mixing_ip = OpenStudio.convert(target_zone_mixing_si, 'm^3/s', 'cfm').get runner.registerInfo("Add zone mixing between #{zone.name} and #{boundary_object_zone.name} with flowrate of #{target_zone_mixing_ip.round(2)} cfm") sub_surface.setConstruction(sub_surface.construction.get) # is there an easier way to set to air wall boundary_sub_surface.setConstruction(boundary_sub_surface.construction.get) # is there an easier way to set to air wall if !surface.isAirWall runner.registerWarning("Sub-surfaces shared with #{zone.name} and #{boundary_object_zone.name} can't be made adiabatic. Conductive heat transfer will remain in the model for these sub-surfaces.") end end end if adiabatic # moved this later to handle air wall sub-surface hosted by air wall base surface surface.setConstruction(surface.construction.get) # is there an easier way to set to air wall boundary_surface.setConstruction(boundary_surface.construction.get) # is there an easier way to set to air wall surface.setOutsideBoundaryCondition('Adiabatic') boundary_surface.setOutsideBoundaryCondition('Adiabatic') end end else runner.registerWarning("didn't find thermal zone for #{boundary_surface.name}") end end end end # add output reports if add_zone_mixing_variables OpenStudio::Model::OutputVariable.new('Zone Mixing Volume', model) OpenStudio::Model::OutputVariable.new('Zone Mixing Current Density Air Volume Flow Rate', model) OpenStudio::Model::OutputVariable.new('Zone Mixing Standard Density Air Volume Flow Rate', model) OpenStudio::Model::OutputVariable.new('Zone Mixing Mass Flow Rate', model) OpenStudio::Model::OutputVariable.new('Zone Mixing Receiving Air Mass Flow Rate', model) OpenStudio::Model::OutputVariable.new('Zone Mixing Source Air Mass Flow Rate', model) end # report final condition of model runner.registerFinalCondition("The building finished with #{model.getZoneMixings.size} Zone Mixing Objects.") return true end |