Created
June 18, 2021 20:08
-
-
Save omarh119/3b6e9dc9f2035ec6216fb9591b215a4a to your computer and use it in GitHub Desktop.
Create Geometry
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ******************************************************************************* | |
# 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 | |
# start the measure | |
class BarAspectRatioStudy < 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 "Bar Aspect Ratio Study" | |
end | |
# define the arguments that the user will input | |
def arguments(model) | |
args = OpenStudio::Measure::OSArgumentVector.new | |
# Main Building Params | |
#-------------------------------------------------------------------------------------------------------------- | |
# make an argument for Building Long Dimension | |
bldg_long_len_ip = OpenStudio::Measure::OSArgument.makeDoubleArgument('bldg_long_len_ip', true) | |
bldg_long_len_ip.setDisplayName('Building Long Dimension') | |
bldg_long_len_ip.setUnits('ft') | |
bldg_long_len_ip.setDefaultValue(600.0) | |
args << bldg_long_len_ip | |
# make an argument for Building Short Dimension | |
bldg_short_len_ip = OpenStudio::Measure::OSArgument.makeDoubleArgument('bldg_short_len_ip', true) | |
bldg_short_len_ip.setDisplayName('Building Short Dimension') | |
bldg_short_len_ip.setUnits('ft') | |
bldg_short_len_ip.setDefaultValue(200.0) | |
args << bldg_short_len_ip | |
# 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') | |
floor_to_floor_height_ip.setUnits('ft') | |
floor_to_floor_height_ip.setDefaultValue(30.0) | |
args << floor_to_floor_height_ip | |
# North Fenestrations | |
#-------------------------------------------------------------------------------------------------------------- | |
# make an argument for Man Door Area | |
mandoor_north_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('mandoor_north_area', true) | |
mandoor_north_area.setDisplayName('North Man Door Area') | |
mandoor_north_area.setUnits('ft^2') | |
mandoor_north_area.setDefaultValue(160.0) | |
args << mandoor_north_area | |
# make an argument for Overhead Door Area | |
overheadDoor_north_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('overheadDoor_north_area', true) | |
overheadDoor_north_area.setDisplayName('North Overhead Door Area') | |
overheadDoor_north_area.setUnits('ft^2') | |
overheadDoor_north_area.setDefaultValue(2400.0) | |
args << overheadDoor_north_area | |
# make an argument for Window Area | |
window_north_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('window_north_area', true) | |
window_north_area.setDisplayName('North Window Area') | |
window_north_area.setUnits('ft^2') | |
window_north_area.setDefaultValue(100.0) | |
args << window_north_area | |
# South Fenestrations | |
#-------------------------------------------------------------------------------------------------------------- | |
# make an argument for Man Door Area | |
mandoor_south_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('mandoor_south_area', true) | |
mandoor_south_area.setDisplayName('South Man Door Area') | |
mandoor_south_area.setUnits('ft^2') | |
mandoor_south_area.setDefaultValue(160.0) | |
args << mandoor_south_area | |
# make an argument for Overhead Door Area | |
overheadDoor_south_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('overheadDoor_south_area', true) | |
overheadDoor_south_area.setDisplayName('South Overhead Door Area') | |
overheadDoor_south_area.setUnits('ft^2') | |
overheadDoor_south_area.setDefaultValue(2400.0) | |
args << overheadDoor_south_area | |
# make an argument for Window Area | |
window_south_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('window_south_area', true) | |
window_south_area.setDisplayName('South Window Area') | |
window_south_area.setUnits('ft^2') | |
window_south_area.setDefaultValue(100.0) | |
args << window_south_area | |
# East Fenestrations | |
#-------------------------------------------------------------------------------------------------------------- | |
# make an argument for Man Door Area | |
mandoor_east_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('mandoor_east_area', true) | |
mandoor_east_area.setDisplayName('East Man Door Area') | |
mandoor_east_area.setUnits('ft^2') | |
mandoor_east_area.setDefaultValue(160.0) | |
args << mandoor_east_area | |
# make an argument for Overhead Door Area | |
overheadDoor_east_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('overheadDoor_east_area', true) | |
overheadDoor_east_area.setDisplayName('East Overhead Door Area') | |
overheadDoor_east_area.setUnits('ft^2') | |
overheadDoor_east_area.setDefaultValue(2400.0) | |
args << overheadDoor_east_area | |
# make an argument for Window Area | |
window_east_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('window_east_area', true) | |
window_east_area.setDisplayName('East Window Area') | |
window_east_area.setUnits('ft^2') | |
window_east_area.setDefaultValue(100.0) | |
args << window_east_area | |
# West Fenestrations | |
#-------------------------------------------------------------------------------------------------------------- | |
# make an argument for Man Door Area | |
mandoor_west_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('mandoor_west_area', true) | |
mandoor_west_area.setDisplayName('West Man Door Area') | |
mandoor_west_area.setUnits('ft^2') | |
mandoor_west_area.setDefaultValue(160.0) | |
args << mandoor_west_area | |
# make an argument for Overhead Door Area | |
overheadDoor_west_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('overheadDoor_west_area', true) | |
overheadDoor_west_area.setDisplayName('West Overhead Door Area') | |
overheadDoor_west_area.setUnits('ft^2') | |
overheadDoor_west_area.setDefaultValue(2400.0) | |
args << overheadDoor_west_area | |
# make an argument for Window Area | |
window_west_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('window_west_area', true) | |
window_west_area.setDisplayName('West Window Area') | |
window_west_area.setUnits('ft^2') | |
window_west_area.setDefaultValue(100.0) | |
args << window_west_area | |
# Misc Params | |
#-------------------------------------------------------------------------------------------------------------- | |
# make an argument to surface match | |
surface_matching = OpenStudio::Measure::OSArgument.makeBoolArgument('surface_matching', true) | |
surface_matching.setDisplayName('Surface Matching?') | |
surface_matching.setDefaultValue(true) | |
args << surface_matching | |
# make an argument to create zones from spaces | |
make_zones = OpenStudio::Measure::OSArgument.makeBoolArgument('make_zones', true) | |
make_zones.setDisplayName('Make Thermal Zones from Spaces?') | |
make_zones.setDefaultValue(true) | |
args << make_zones | |
# Make an argument for enabling debug messages | |
debug = OpenStudio::Measure::OSArgument.makeBoolArgument('debug', true) | |
debug.setDisplayName('Show debug messages?') | |
debug.setDefaultValue(false) | |
args << debug | |
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 | |
bldg_long_len_ip = runner.getDoubleArgumentValue('bldg_long_len_ip', user_arguments) | |
bldg_short_len_ip = runner.getDoubleArgumentValue('bldg_short_len_ip', user_arguments) | |
total_bldg_area_ip = bldg_long_len_ip * bldg_short_len_ip | |
ns_to_ew_ratio = bldg_long_len_ip/bldg_short_len_ip | |
num_floors = 1 | |
floor_to_floor_height_ip = runner.getDoubleArgumentValue('floor_to_floor_height_ip', user_arguments) | |
surface_matching = runner.getBoolArgumentValue('surface_matching', user_arguments) | |
make_zones = runner.getBoolArgumentValue('make_zones', user_arguments) | |
# North fenestrations | |
mandoor_north_area_ip = runner.getDoubleArgumentValue('mandoor_north_area', user_arguments) | |
overheadDoor_north_area_ip = runner.getDoubleArgumentValue('overheadDoor_north_area', user_arguments) | |
window_north_area_ip = runner.getDoubleArgumentValue('window_north_area', user_arguments) | |
# South Fenestrations | |
mandoor_south_area_ip = runner.getDoubleArgumentValue('mandoor_south_area', user_arguments) | |
overheadDoor_south_area_ip = runner.getDoubleArgumentValue('overheadDoor_south_area', user_arguments) | |
window_south_area_ip = runner.getDoubleArgumentValue('window_south_area', user_arguments) | |
# East Fenestrations | |
mandoor_east_area_ip = runner.getDoubleArgumentValue('mandoor_east_area', user_arguments) | |
overheadDoor_east_area_ip = runner.getDoubleArgumentValue('overheadDoor_east_area', user_arguments) | |
window_east_area_ip = runner.getDoubleArgumentValue('window_east_area', user_arguments) | |
# West Fenestrations | |
mandoor_west_area_ip = runner.getDoubleArgumentValue('mandoor_west_area', user_arguments) | |
overheadDoor_west_area_ip = runner.getDoubleArgumentValue('overheadDoor_west_area', user_arguments) | |
window_west_area_ip = runner.getDoubleArgumentValue('window_west_area', 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 | |
# helper 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. The definition be called through this measure. | |
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 | |
# calculate needed variables | |
footprint_ip = total_bldg_area_ip / num_floors | |
footprint_si = unit_helper(footprint_ip, 'ft^2', 'm^2') | |
floor_to_floor_height = unit_helper(floor_to_floor_height_ip, 'ft', 'm') | |
mandoor_north_area_si = unit_helper(mandoor_north_area_ip,'ft^2','m^2') | |
overheadDoor_north_area_si = unit_helper(overheadDoor_north_area_ip,'ft^2','m^2') | |
window_north_area_si = unit_helper(window_north_area_ip,'ft^2','m^2') | |
mandoor_south_area_si = unit_helper(mandoor_south_area_ip,'ft^2','m^2') | |
overheadDoor_south_area_si = unit_helper(overheadDoor_south_area_ip,'ft^2','m^2') | |
window_south_area_si = unit_helper(window_south_area_ip,'ft^2','m^2') | |
mandoor_east_area_si = unit_helper(mandoor_east_area_ip,'ft^2','m^2') | |
overheadDoor_east_area_si = unit_helper(overheadDoor_east_area_ip,'ft^2','m^2') | |
window_east_area_si = unit_helper(window_east_area_ip,'ft^2','m^2') | |
mandoor_west_area_si = unit_helper(mandoor_west_area_ip,'ft^2','m^2') | |
overheadDoor_west_area_si = unit_helper(overheadDoor_west_area_ip,'ft^2','m^2') | |
window_west_area_si = unit_helper(window_west_area_ip,'ft^2','m^2') | |
# variables from original rectangle script not exposed in this measure | |
width = Math.sqrt(footprint_si / ns_to_ew_ratio) | |
length = footprint_si / width | |
plenum_height = 0 # this doesn't look like it is used anywhere | |
# determine if core and perimeter zoning can be used | |
perimeter_zone_depth = 0 | |
# reporting initial condition of model | |
starting_spaces = model.getSpaces | |
runner.registerInitialCondition("The building started with #{starting_spaces.size} spaces.") | |
# Delete current model | |
model.getSpaces.each do |space| | |
space.remove() | |
end | |
# Loop through the number of floors | |
for floor in (0..num_floors - 1) | |
z = floor_to_floor_height * floor | |
# Create a new story within the building | |
story = OpenStudio::Model::BuildingStory.new(model) | |
story.setNominalFloortoFloorHeight(floor_to_floor_height) | |
story.setName("Story #{floor + 1}") | |
nw_point = OpenStudio::Point3d.new(0, width, z) | |
ne_point = OpenStudio::Point3d.new(length, width, z) | |
se_point = OpenStudio::Point3d.new(length, 0, z) | |
sw_point = OpenStudio::Point3d.new(0, 0, z) | |
# Identity matrix for setting space origins | |
m = OpenStudio::Matrix.new(4, 4, 0) | |
m[0, 0] = 1 | |
m[1, 1] = 1 | |
m[2, 2] = 1 | |
m[3, 3] = 1 | |
# Define polygons for a rectangular building | |
core_polygon = OpenStudio::Point3dVector.new | |
core_polygon << sw_point | |
core_polygon << nw_point | |
core_polygon << ne_point | |
core_polygon << se_point | |
core_space = OpenStudio::Model::Space.fromFloorPrint(core_polygon, floor_to_floor_height, model) | |
core_space = core_space.get | |
m[0, 3] = sw_point.x | |
m[1, 3] = sw_point.y | |
m[2, 3] = sw_point.z | |
core_space.changeTransformation(OpenStudio::Transformation.new(m)) | |
core_space.setBuildingStory(story) | |
core_space.setName("Story #{floor + 1} Core Space") | |
# Set vertical story position | |
story.setNominalZCoordinate(z) | |
end | |
# Helper to get Bounding Coordinates of a surface | |
def GetBoundingCoordinates(surface) | |
maxX = 0 | |
maxY = 0 | |
minX = 0 | |
minY = 0 | |
counter = 0 | |
surface.vertices.each do |v| | |
if counter == 0 | |
minX = v.x | |
minY = v.y | |
maxX = v.x | |
maxY = v.y | |
else | |
minX = v.x < minX ? v.x : minX | |
minY = v.y < minY ? v.y : minY | |
maxX = v.x > maxX ? v.x : maxX | |
maxY = v.y > maxY ? v.y : maxY | |
end | |
counter += 1 | |
end | |
boundingConditions = {} | |
boundingConditions = { | |
"minX" => minX, | |
"minY" => minY, | |
"maxX" => maxX, | |
"maxY" => maxY, | |
} | |
return boundingConditions | |
end | |
# Create a Point3D Vector and push the subsurface vertices into an array of arrays | |
subs = [] # this will hold 'x' amount of subsurfaces | |
pts = [] # this will hold the subsurface vertices | |
pts.push(OpenStudio::Point3d.new(36, 0, 1)) | |
pts.push(OpenStudio::Point3d.new(36, 0, 5)) | |
pts.push(OpenStudio::Point3d.new(20, 0, 1)) | |
pts.push(OpenStudio::Point3d.new(20, 0, 5)) | |
subs.push(pts) | |
# put all of the spaces in the model into a vector | |
spaces = OpenStudio::Model::SpaceVector.new | |
model.getSpaces.each do |space| | |
# Find the appropriate surfaces to apply sub-surfaces too | |
space.surfaces.each do |surface| | |
puts surface.name | |
boundingCoords = GetBoundingCoordinates(surface) | |
# Determine which surface it is | |
if boundingCoords["minX"] == boundingCoords["maxX"] | |
# This is East or West | |
if boundingCoords["minX"] == 0 | |
# This is West Wall | |
surface.setWindowToWallRatio(window_west_area_si / surface.grossArea()) | |
else | |
# This is East Wall | |
surface.setWindowToWallRatio(window_east_area_si / surface.grossArea()) | |
end | |
elsif boundingCoords["minY"] == boundingCoords["maxY"] | |
# This is North or South | |
if boundingCoords["minY"] == 0 | |
# This is South Wall | |
surface.setWindowToWallRatio(window_south_area_si / surface.grossArea()) | |
# surface.createSubSurfaces(subs,0.1) # this errors out for some reason... | |
else | |
# This is North Wall | |
surface.setWindowToWallRatio(window_north_area_si / surface.grossArea()) | |
end | |
end | |
end | |
spaces << space | |
if make_zones | |
# create zones | |
new_zone = OpenStudio::Model::ThermalZone.new(model) | |
space.setThermalZone(new_zone) | |
zone_name = space.name.get.gsub('Space', 'Zone') | |
new_zone.setName(zone_name) | |
end | |
space.surfaces.each do |surface| | |
puts surface.subSurfaces | |
end | |
end | |
# the struggle to determine if im providing the correct params to createSubSurfaces by seeing what GenerateSkylights provides | |
mObjs = model.getModelObjects | |
mObjs.each do |obj| | |
nm = obj.name.to_s | |
if nm.include? "Building" | |
bldg = obj | |
bldg = bldg.to_Building.get | |
puts bldg.class | |
pattern = bldg.generateSkylightPattern(0.2,1.5,1) | |
#puts pattern.class | |
#puts pattern | |
#puts pattern[0].class | |
#puts pattern[0] | |
#puts pattern[0][0].class | |
#puts pattern[0][0] | |
end | |
end | |
if surface_matching | |
# match surfaces for each space in the vector | |
OpenStudio::Model.matchSurfaces(spaces) | |
end | |
# 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 | |
BarAspectRatioStudy.new.registerWithApplication |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment