# ******************************************************************************* # OpenStudio(R), Copyright (c) 2008-2020, 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. # ******************************************************************************* # see the URL below for information on how to write OpenStudio measures # http://openstudio.nrel.gov/openstudio-measure-writing-guide # see the URL below for information on using life cycle cost objects in OpenStudio # http://openstudio.nrel.gov/openstudio-life-cycle-examples # see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects) # http://openstudio.nrel.gov/sites/openstudio.nrel.gov/files/nv_data/cpp_documentation_it/model/html/namespaces.html # load OpenStudio measure libraries from openstudio-extension gem require 'openstudio-extension' require 'openstudio/extension/core/os_lib_helper_methods' require 'openstudio/extension/core/os_lib_geometry.rb' # load OpenStudio measure libraries require "#{File.dirname(__FILE__)}/resources/os_lib_cofee" # start the measure class BarAspectRatioSlicedBySpaceType < OpenStudio::Measure::ModelMeasure # define the name that a user will see, this method may be deprecated as # the display name in PAT comes from the name field in measure.xml def name return 'BarAspectRatioSlicedBySpaceType' end # define the arguments that the user will input def arguments(model) args = OpenStudio::Measure::OSArgumentVector.new # make an argument for total floor area total_bldg_area_ip = OpenStudio::Measure::OSArgument.makeDoubleArgument('total_bldg_area_ip', true) total_bldg_area_ip.setDisplayName('Total Building Floor Area (ft^2).') total_bldg_area_ip.setDefaultValue(10000.0) args << total_bldg_area_ip # make an argument for aspect ratio ns_to_ew_ratio = OpenStudio::Measure::OSArgument.makeDoubleArgument('ns_to_ew_ratio', true) ns_to_ew_ratio.setDisplayName('Ratio of North/South Facade Length Relative to East/West Facade Length.') ns_to_ew_ratio.setDefaultValue(2.0) args << ns_to_ew_ratio # make an argument for number of floors num_floors = OpenStudio::Measure::OSArgument.makeIntegerArgument('num_floors', true) num_floors.setDisplayName('Number of Floors.') num_floors.setDefaultValue(2) args << num_floors # make an argument for floor height floor_to_floor_height_ip = OpenStudio::Measure::OSArgument.makeDoubleArgument('floor_to_floor_height_ip', true) floor_to_floor_height_ip.setDisplayName('Floor to Floor Height (ft).') floor_to_floor_height_ip.setDefaultValue(10.0) args << floor_to_floor_height_ip # make an argument for the meter name spaceTypeHashString = OpenStudio::Measure::OSArgument.makeStringArgument('spaceTypeHashString', true) spaceTypeHashString.setDisplayName('Hash of Space Types with Name as Key and Fraction as value.') args << spaceTypeHashString return args end # define what happens when the measure is run 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 total_bldg_area_ip = runner.getDoubleArgumentValue('total_bldg_area_ip', user_arguments) ns_to_ew_ratio = runner.getDoubleArgumentValue('ns_to_ew_ratio', user_arguments) num_floors = runner.getIntegerArgumentValue('num_floors', user_arguments) floor_to_floor_height_ip = runner.getDoubleArgumentValue('floor_to_floor_height_ip', user_arguments) spaceTypeHashString = runner.getStringArgumentValue('spaceTypeHashString', user_arguments) # test for positive inputs if total_bldg_area_ip <= 0 runner.registerError('Enter a total building area greater than 0.') end if ns_to_ew_ratio <= 0 runner.registerError('Enter ratio grater than 0.') end if num_floors <= 0 runner.registerError('Enter a number of stories 1 or greater.') end if floor_to_floor_height_ip <= 0 runner.registerError('Enter a positive floor height.') end if 1 == 1 # TODO: - add test for spaceTypeHashString argument end # calculate needed variables total_bldg_area_si = OpenStudio.convert(total_bldg_area_ip, 'ft^2', 'm^2').get footprint_ip = total_bldg_area_ip / num_floors footprint_si = OpenStudio.convert(footprint_ip, 'ft^2', 'm^2').get floor_to_floor_height = OpenStudio.convert(floor_to_floor_height_ip, 'ft', 'm').get # variables from original rectangle script not exposed in this measure width = Math.sqrt(footprint_si / ns_to_ew_ratio) length = footprint_si / width # reporting initial condition of model starting_spaces = model.getSpaces runner.registerInitialCondition("The building started with #{starting_spaces.size} spaces.") # convert string argument to hash spaceTypeHashName = {} spaceTypeHashString[1..-2].split(/, /).each { |entry| entryMap = entry.split(/=>/); value_str = entryMap[1]; spaceTypeHashName[entryMap[0].strip[1..-1].to_s] = value_str.nil? ? '' : value_str.strip[1..-2].to_f } # sum of hash values hashValues = 0 spaceTypeHash = {} model.getSpaceTypes.each do |spaceType| if spaceTypeHashName.include?(spaceType.name.to_s) spaceTypeHash[spaceType] = spaceTypeHashName[spaceType.name.to_s] * total_bldg_area_si # converting fractional value to area value to pass into method hashValues += spaceTypeHashName[spaceType.name.to_s] end end if hashValues != 1.0 runner.registerWarning('Fractional hash values do not add up to one. Resulting geometry may not have expected area.') end # see which path to take midFloorMultiplier = 1 # show as 1 even on 1 and 2 story buildings where there is no mid floor, in addition to 3 story building if num_floors > 3 # use floor multiplier version. Set mid floor multiplier, use adibatic floors/ceilings and set constructions, raise up building midFloorMultiplier = num_floors - 2 end # run method to create envelope bar_AspectRatio = OsLib_Cofee.createBar(model, spaceTypeHash, length, width, total_bldg_area_si, num_floors, midFloorMultiplier, 0.0, 0.0, length, width, 0.0, floor_to_floor_height * num_floors, true) puts "building area #{model.getBuilding.floorArea}" # reporting final condition of model finishing_spaces = model.getSpaces runner.registerFinalCondition("The building finished with #{finishing_spaces.size} spaces.") return true end end # this allows the measure to be use by the application BarAspectRatioSlicedBySpaceType.new.registerWithApplication