# ******************************************************************************* # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC. # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # (1) Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # (2) Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # (3) Neither the name of the copyright holder nor the names of any contributors # may be used to endorse or promote products derived from this software without # specific prior written permission from the respective party. # # (4) Other than as required in clauses (1) and (2), distributions in any form # of modifications or other derivative works may not use the "OpenStudio" # trademark, "OS", "os", or any other confusingly similar designation without # specific prior written permission from Alliance for Sustainable Energy, LLC. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE # UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF # THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ******************************************************************************* module OsLib_Cofee # create def to use later to make bar def self.createBar(model, spaceTypeHash, lengthXTarget, lengthYTarget, totalFloorArea, numStories, midFloorMultiplier, xmin, ymin, lengthX, lengthY, zmin, zmax, endZones) # floor to floor height floor_to_floor_height = (zmax - zmin) / numStories # perimeter depth perimeterDepth = OpenStudio.convert(12, 'ft', 'm').get perimeterBufferFactor = 1.5 # this is a margin below which I won't bother splitting the two largest spaces # create an array to control sort order of spaces in bar customSpaceTypeBar = [] counter = 0 spaceTypeHash.sort_by { |key, value| value }.reverse_each do |k, v| next if v == 0 # this line adds support for fractional values of 0 if counter == 1 if (lengthXTarget * (v / totalFloorArea) > perimeterDepth * perimeterBufferFactor) && endZones customSpaceTypeBar << [k, totalFloorArea * (perimeterDepth / lengthXTarget)] customSpaceTypeBar << [k, v - (totalFloorArea * (perimeterDepth / lengthXTarget))] else customSpaceTypeBar << [k, v] end elsif counter > 1 customSpaceTypeBar << [k, v] end counter += 1 end # add the largest space type to the end counter = 0 spaceTypeHash.sort_by { |key, value| value }.reverse_each do |k, v| if counter == 0 # if width is greater than 1.5x perimeter depth then split in half if (lengthXTarget * (v / totalFloorArea) > perimeterDepth * perimeterBufferFactor) && endZones customSpaceTypeBar << [k, v - (totalFloorArea * (perimeterDepth / lengthXTarget))] customSpaceTypeBar << [k, totalFloorArea * (perimeterDepth / lengthXTarget)] else customSpaceTypeBar << [k, v] end end break end # starting z level z = zmin storyCounter = 0 barSpaceArray = [] # create new stories and then add spaces [numStories, 3].min.times do # no more than tree loops through this story = OpenStudio::Model::BuildingStory.new(model) story.setNominalFloortoFloorHeight(floor_to_floor_height) story.setNominalZCoordinate(z) # starting position for first space x = (lengthX - lengthXTarget) * 0.5 + xmin y = (lengthY - lengthYTarget) * 0.5 + ymin # temp array of spaces (this is to change floor boundary when there is mid floor multiplier) tempSpaceArray = [] # loop through space types making diagram and spaces. # spaceTypeHash.sort_by {|key, value| value}.reverse.each do |k,v| customSpaceTypeBar.each do |object| # get values from what was hash k = object[0] v = object[1] # get proper zone multiplier value if (storyCounter == 1) && (midFloorMultiplier > 1) thermalZoneMultiplier = midFloorMultiplier else thermalZoneMultiplier = 1 end options = { 'name' => nil, 'spaceType' => k, 'story' => story, 'makeThermalZone' => true, 'thermalZone' => nil, 'thermalZoneMultiplier' => thermalZoneMultiplier, 'floor_to_floor_height' => floor_to_floor_height } # three paths for spaces depending upon building depth (3, 2 or one cross slices) if lengthYTarget > perimeterDepth * 3 # slice into core and perimeter # perimeter polygon a perim_polygon_a = OpenStudio::Point3dVector.new perim_origin_a = OpenStudio::Point3d.new(x, y, z) perim_polygon_a << perim_origin_a perim_polygon_a << OpenStudio::Point3d.new(x, y + perimeterDepth, z) perim_polygon_a << OpenStudio::Point3d.new(x + lengthXTarget * (v / totalFloorArea), y + perimeterDepth, z) perim_polygon_a << OpenStudio::Point3d.new(x + lengthXTarget * (v / totalFloorArea), y, z) # create core polygon core_polygon = OpenStudio::Point3dVector.new core_origin = OpenStudio::Point3d.new(x, y + perimeterDepth, z) core_polygon << core_origin core_polygon << OpenStudio::Point3d.new(x, y + lengthYTarget - perimeterDepth, z) core_polygon << OpenStudio::Point3d.new(x + lengthXTarget * (v / totalFloorArea), y + lengthYTarget - perimeterDepth, z) core_polygon << OpenStudio::Point3d.new(x + lengthXTarget * (v / totalFloorArea), y + perimeterDepth, z) # perimeter polygon b w perim_polygon_b = OpenStudio::Point3dVector.new perim_origin_b = OpenStudio::Point3d.new(x, y + lengthYTarget - perimeterDepth, z) perim_polygon_b << perim_origin_b perim_polygon_b << OpenStudio::Point3d.new(x, y + lengthYTarget, z) perim_polygon_b << OpenStudio::Point3d.new(x + lengthXTarget * (v / totalFloorArea), y + lengthYTarget, z) perim_polygon_b << OpenStudio::Point3d.new(x + lengthXTarget * (v / totalFloorArea), y + lengthYTarget - perimeterDepth, z) # run method to make spaces tempSpaceArray << OsLib_Geometry.makeSpaceFromPolygon(model, perim_origin_a, perim_polygon_a, options) # model, origin, polygon, options tempSpaceArray << OsLib_Geometry.makeSpaceFromPolygon(model, core_origin, core_polygon, options) # model, origin, polygon, options tempSpaceArray << OsLib_Geometry.makeSpaceFromPolygon(model, perim_origin_b, perim_polygon_b, options) # model, origin, polygon, options elsif lengthYTarget > perimeterDepth * 2 # slice into two peremeter zones but no core # perimeter polygon a perim_polygon_a = OpenStudio::Point3dVector.new perim_origin_a = OpenStudio::Point3d.new(x, y, z) perim_polygon_a << perim_origin_a perim_polygon_a << OpenStudio::Point3d.new(x, y + lengthYTarget / 2, z) perim_polygon_a << OpenStudio::Point3d.new(x + lengthXTarget * (v / totalFloorArea), y + lengthYTarget / 2, z) perim_polygon_a << OpenStudio::Point3d.new(x + lengthXTarget * (v / totalFloorArea), y, z) # perimeter polygon b perim_polygon_b = OpenStudio::Point3dVector.new perim_origin_b = OpenStudio::Point3d.new(x, y + lengthYTarget / 2, z) perim_polygon_b << perim_origin_b perim_polygon_b << OpenStudio::Point3d.new(x, y + lengthYTarget, z) perim_polygon_b << OpenStudio::Point3d.new(x + lengthXTarget * (v / totalFloorArea), y + lengthYTarget, z) perim_polygon_b << OpenStudio::Point3d.new(x + lengthXTarget * (v / totalFloorArea), y + lengthYTarget / 2, z) # run method to make spaces tempSpaceArray << OsLib_Geometry.makeSpaceFromPolygon(model, perim_origin_a, perim_polygon_a, options) # model, origin, polygon, options tempSpaceArray << OsLib_Geometry.makeSpaceFromPolygon(model, perim_origin_b, perim_polygon_b, options) # model, origin, polygon, options else # don't slice into core and perimeter # create polygon core_polygon = OpenStudio::Point3dVector.new core_origin = OpenStudio::Point3d.new(x, y, z) core_polygon << core_origin core_polygon << OpenStudio::Point3d.new(x, y + lengthYTarget, z) core_polygon << OpenStudio::Point3d.new(x + lengthXTarget * (v / totalFloorArea), y + lengthYTarget, z) core_polygon << OpenStudio::Point3d.new(x + lengthXTarget * (v / totalFloorArea), y, z) # run method to make space tempSpaceArray << OsLib_Geometry.makeSpaceFromPolygon(model, core_origin, core_polygon, options) # model, origin, polygon, options end # update points for next run x += lengthXTarget * (v / totalFloorArea) end # set flags for adiabatic surfaces floorAdiabatic = false ceilingAdiabatic = false # update z if midFloorMultiplier == 1 z += floor_to_floor_height else z += floor_to_floor_height * midFloorMultiplier - floor_to_floor_height case storyCounter when 0 ceilingAdiabatic = true when 1 floorAdiabatic = true ceilingAdiabatic = true else floorAdiabatic = true end # alter surfaces boundary conditions and constructions as described above tempSpaceArray.each do |space| space.surfaces.each do |surface| if (surface.surfaceType == 'RoofCeiling') && ceilingAdiabatic construction = surface.construction # TODO: - this isn't really the construction I want since it wasn't an interior one, but will work for now surface.setOutsideBoundaryCondition('Adiabatic') if !construction.empty? surface.setConstruction(construction.get) end end if (surface.surfaceType == 'Floor') && floorAdiabatic construction = surface.construction # TODO: - this isn't really the construction I want since it wasn't an interior one, but will work for now surface.setOutsideBoundaryCondition('Adiabatic') if !construction.empty? surface.setConstruction(construction.get) end end end end # populate bar space array from temp array barSpaceArray << tempSpaceArray end # update storyCounter storyCounter += 1 end # surface matching (seems more complex than necessary) spaces = OpenStudio::Model::SpaceVector.new model.getSpaces.each do |space| spaces << space end OpenStudio::Model.matchSurfaces(spaces) result = barSpaceArray return result end end