# *******************************************************************************
# OpenStudio(R), Copyright (c) 2008-2019, 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_ModelGeneration
  # simple list of building types that are valid for get_space_types_from_building_type
  def get_building_types
    array = OpenStudio::StringVector.new
    array << 'SecondarySchool'
    array << 'PrimarySchool'
    array << 'SmallOffice'
    array << 'MediumOffice'
    array << 'LargeOffice'
    array << 'SmallHotel'
    array << 'LargeHotel'
    array << 'Warehouse'
    array << 'RetailStandalone'
    array << 'RetailStripmall'
    array << 'QuickServiceRestaurant'
    array << 'FullServiceRestaurant'
    array << 'MidriseApartment'
    array << 'HighriseApartment'
    array << 'Hospital'
    array << 'Outpatient'
    array << 'SuperMarket'

    return array
  end

  # simple list of templates that are valid for get_space_types_from_building_type
  def get_templates
    array = OpenStudio::StringVector.new
    array << 'DOE Ref Pre-1980'
    array << 'DOE Ref 1980-2004'
    array << '90.1-2004'
    array << '90.1-2007'
    # array << '189.1-2009' # if turn this on need to update space_type_array for RetailStripmall
    array << '90.1-2010'
    array << '90.1-2013'
    array << 'NREL ZNE Ready 2017'

    return array
  end

  # calculate aspect ratio from area and perimeter
  def calc_aspect_ratio(a, p)
    l = 0.25 * (p + Math.sqrt(p**2 - 16 * a))
    w = 0.25 * (p - Math.sqrt(p**2 - 16 * a))
    aspect_ratio = l / w

    return aspect_ratio
  end

  # Building Form Defaults from Table 4.2 in Achieving the 30% Goal: Energy and Cost Savings Analysis of ASHRAE Standard 90.1-2010
  # aspect ratio for NA replaced with floor area to perimeter ratio from prototype model
  def building_form_defaults(building_type)
    hash = {}

    # calculate aspect ratios not represented on Table 4.2
    primary_aspet_ratio = calc_aspect_ratio(73958.0, 2060.0)
    secondary_aspet_ratio = calc_aspect_ratio(128112.0, 2447.0)
    outpatient_aspet_ratio = calc_aspect_ratio(14782.0, 588.0)
    supermarket_a = 45001.0
    supermarket_p = 866.0
    supermarket_wwr = 1880.0 / (supermarket_p * 20.0)
    supermarket_aspet_ratio = calc_aspect_ratio(supermarket_a, supermarket_p)

    hash['SmallOffice'] = { aspect_ratio: 1.5, wwr: 0.15, typical_story: 10.0 }
    hash['MediumOffice'] = { aspect_ratio: 1.5, wwr: 0.33, typical_story: 13.0 }
    hash['LargeOffice'] = { aspect_ratio: 1.5, wwr: 0.15, typical_story: 13.0 }
    hash['RetailStandalone'] = { aspect_ratio: 1.28, wwr: 0.07, typical_story: 20.0 }
    hash['RetailStripmall'] = { aspect_ratio: 4.0, wwr: 0.11, typical_story: 17.0 }
    hash['PrimarySchool'] = { aspect_ratio: primary_aspet_ratio.round(1), wwr: 0.35, typical_story: 13.0 }
    hash['SecondarySchool'] = { aspect_ratio: secondary_aspet_ratio.round(1), wwr: 0.33, typical_story: 13.0 }
    hash['Outpatient'] = { aspect_ratio: outpatient_aspet_ratio.round(1), wwr: 0.20, typical_story: 10.0 }
    hash['Hospital'] = { aspect_ratio: 1.33, wwr: 0.16, typical_story: 14.0 }
    hash['SmallHotel'] = { aspect_ratio: 3.0, wwr: 0.11, typical_story: 9.0, first_story: 11.0 }
    hash['LargeHotel'] = { aspect_ratio: 5.1, wwr: 0.27, typical_story: 10.0, first_story: 13.0 }

    # code in get_space_types_from_building_type is used to override building wwr with space type specific wwr
    hash['Warehouse'] = { aspect_ratio: 2.2, wwr: 0.0, typical_story: 28.0 }

    hash['QuickServiceRestaurant'] = { aspect_ratio: 1.0, wwr: 0.14, typical_story: 10.0 }
    hash['FullServiceRestaurant'] = { aspect_ratio: 1.0, wwr: 0.18, typical_story: 10.0 }
    hash['QuickServiceRestaurant'] = { aspect_ratio: 1.0, wwr: 0.18, typical_story: 10.0 }
    hash['MidriseApartment'] = { aspect_ratio: 2.75, wwr: 0.15, typical_story: 10.0 }
    hash['HighriseApartment'] = { aspect_ratio: 2.75, wwr: 0.15, typical_story: 10.0 }
    # SuperMarket inputs come from prototype model
    hash['SuperMarket'] = { aspect_ratio: supermarket_aspet_ratio.round(1), wwr: supermarket_wwr.round(2), typical_story: 20.0 }

    return hash[building_type]
  end

  # create hash of space types and generic ratios of building floor area
  def get_space_types_from_building_type(building_type, template, whole_building = true)
    hash = {}

    # TODO: - Confirm that these work for all standards

    if building_type == 'SecondarySchool'
      hash['Auditorium'] = { ratio: 0.0504, space_type_gen: true, default: false }
      hash['Cafeteria'] = { ratio: 0.0319, space_type_gen: true, default: false }
      hash['Classroom'] = { ratio: 0.3528, space_type_gen: true, default: true }
      hash['Corridor'] = { ratio: 0.2144, space_type_gen: true, default: false }
      hash['Gym'] = { ratio: 0.1646, space_type_gen: true, default: false }
      hash['Kitchen'] = { ratio: 0.0110, space_type_gen: true, default: false }
      hash['Library'] = { ratio: 0.0429, space_type_gen: true, default: false } # not in prototype
      hash['Lobby'] = { ratio: 0.0214, space_type_gen: true, default: false }
      hash['Mechanical'] = { ratio: 0.0349, space_type_gen: true, default: false }
      hash['Office'] = { ratio: 0.0543, space_type_gen: true, default: false }
      hash['Restroom'] = { ratio: 0.0214, space_type_gen: true, default: false }
    elsif building_type == 'PrimarySchool'
      hash['Cafeteria'] = { ratio: 0.0458, space_type_gen: true, default: false }
      hash['Classroom'] = { ratio: 0.5610, space_type_gen: true, default: true }
      hash['Corridor'] = { ratio: 0.1633, space_type_gen: true, default: false }
      hash['Gym'] = { ratio: 0.0520, space_type_gen: true, default: false }
      hash['Kitchen'] = { ratio: 0.0244, space_type_gen: true, default: false }
      # TODO: - confirm if Library is 0.0 for all templates
      hash['Library'] = { ratio: 0.0, space_type_gen: true, default: false }
      hash['Lobby'] = { ratio: 0.0249, space_type_gen: true, default: false }
      hash['Mechanical'] = { ratio: 0.0367, space_type_gen: true, default: false }
      hash['Office'] = { ratio: 0.0642, space_type_gen: true, default: false }
      hash['Restroom'] = { ratio: 0.0277, space_type_gen: true, default: false }
    elsif building_type == 'SmallOffice'
      # TODO: - populate Small, Medium, and Large office for whole_building false
      if whole_building
        hash['WholeBuilding - Sm Office'] = { ratio: 1.0, space_type_gen: true, default: true }
      else
        hash['SmallOffice - Breakroom'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['SmallOffice - ClosedOffice'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['SmallOffice - Conference'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['SmallOffice - Corridor'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['SmallOffice - Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['SmallOffice - Lobby'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['SmallOffice - OpenOffice'] = { ratio: 0.99, space_type_gen: true, default: true }
        hash['SmallOffice - Restroom'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['SmallOffice - Stair'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['SmallOffice - Storage'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['SmallOffice - Classroom'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['SmallOffice - Dining'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['WholeBuilding - Sm Office'] = { ratio: 0.0, space_type_gen: true, default: false }
      end
    elsif building_type == 'MediumOffice'
      if whole_building
        hash['WholeBuilding - Md Office'] = { ratio: 1.0, space_type_gen: true, default: true }
      else
        hash['MediumOffice - Breakroom'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['MediumOffice - ClosedOffice'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['MediumOffice - Conference'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['MediumOffice - Corridor'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['MediumOffice - Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['MediumOffice - Lobby'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['MediumOffice - OpenOffice'] = { ratio: 0.99, space_type_gen: true, default: true }
        hash['MediumOffice - Restroom'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['MediumOffice - Stair'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['MediumOffice - Storage'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['MediumOffice - Classroom'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['MediumOffice - Dining'] = { ratio: 0.99, space_type_gen: true, default: false }
        hash['WholeBuilding - Md Office'] = { ratio: 0.0, space_type_gen: true, default: false }
      end
    elsif building_type == 'LargeOffice'
      if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004'].include?(template)
        if whole_building
          hash['WholeBuilding - Lg Office'] = { ratio: 1.0, space_type_gen: true, default: true }
        else
          hash['BreakRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['ClosedOffice'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Conference'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Corridor'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['IT_Room'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Lobby'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['OpenOffice'] = { ratio: 0.99, space_type_gen: true, default: true }
          hash['PrintRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Restroom'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Stair'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Storage'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Vending'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['WholeBuilding - Lg Office'] = { ratio: 0.0, space_type_gen: true, default: false }
        end
      else
        if whole_building
          hash['WholeBuilding - Lg Office'] = { ratio: 0.9737, space_type_gen: true, default: true }
          hash['OfficeLarge Data Center'] = { ratio: 0.0094, space_type_gen: true, default: false }
          hash['OfficeLarge Main Data Center'] = { ratio: 0.0169, space_type_gen: true, default: false }
        else
          hash['BreakRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['ClosedOffice'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Conference'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Corridor'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['IT_Room'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Lobby'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['OpenOffice'] = { ratio: 0.99, space_type_gen: true, default: true }
          hash['PrintRoom'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Restroom'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Stair'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Storage'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['Vending'] = { ratio: 0.99, space_type_gen: true, default: false }
          hash['WholeBuilding - Lg Office'] = { ratio: 0.0, space_type_gen: true, default: false }
          hash['OfficeLarge Data Center'] = { ratio: 0.0, space_type_gen: true, default: false }
          hash['OfficeLarge Main Data Center'] = { ratio: 0.0, space_type_gen: true, default: false }
        end
      end
    elsif building_type == 'SmallHotel'
      if ['DOE Ref Pre-1980', 'DOE Ref 1980-2004'].include?(template)
        hash['Corridor'] = { ratio: 0.1313, space_type_gen: true, default: false }
        hash['Elec/MechRoom'] = { ratio: 0.0038, space_type_gen: true, default: false }
        hash['ElevatorCore'] = { ratio: 0.0113, space_type_gen: true, default: false }
        hash['Exercise'] = { ratio: 0.0081, space_type_gen: true, default: false }
        hash['GuestLounge'] = { ratio: 0.0406, space_type_gen: true, default: false }
        hash['GuestRoom'] = { ratio: 0.6313, space_type_gen: true, default: true }
        hash['Laundry'] = { ratio: 0.0244, space_type_gen: true, default: false }
        hash['Mechanical'] = { ratio: 0.0081, space_type_gen: true, default: false }
        hash['Meeting'] = { ratio: 0.0200, space_type_gen: true, default: false }
        hash['Office'] = { ratio: 0.0325, space_type_gen: true, default: false }
        hash['PublicRestroom'] = { ratio: 0.0081, space_type_gen: true, default: false }
        hash['StaffLounge'] = { ratio: 0.0081, space_type_gen: true, default: false }
        hash['Stair'] = { ratio: 0.0400, space_type_gen: true, default: false }
        hash['Storage'] = { ratio: 0.0325, space_type_gen: true, default: false }
      else
        hash['Corridor'] = { ratio: 0.1313, space_type_gen: true, default: false }
        hash['Elec/MechRoom'] = { ratio: 0.0038, space_type_gen: true, default: false }
        hash['ElevatorCore'] = { ratio: 0.0113, space_type_gen: true, default: false }
        hash['Exercise'] = { ratio: 0.0081, space_type_gen: true, default: false }
        hash['GuestLounge'] = { ratio: 0.0406, space_type_gen: true, default: false }
        hash['GuestRoom123Occ'] = { ratio: 0.4081, space_type_gen: true, default: true }
        hash['GuestRoom123Vac'] = { ratio: 0.2231, space_type_gen: true, default: false }
        hash['Laundry'] = { ratio: 0.0244, space_type_gen: true, default: false }
        hash['Mechanical'] = { ratio: 0.0081, space_type_gen: true, default: false }
        hash['Meeting'] = { ratio: 0.0200, space_type_gen: true, default: false }
        hash['Office'] = { ratio: 0.0325, space_type_gen: true, default: false }
        hash['PublicRestroom'] = { ratio: 0.0081, space_type_gen: true, default: false }
        hash['StaffLounge'] = { ratio: 0.0081, space_type_gen: true, default: false }
        hash['Stair'] = { ratio: 0.0400, space_type_gen: true, default: false }
        hash['Storage'] = { ratio: 0.0325, space_type_gen: true, default: false }
      end
    elsif building_type == 'LargeHotel'
      hash['Banquet'] = { ratio: 0.0585, space_type_gen: true, default: false }
      hash['Basement'] = { ratio: 0.1744, space_type_gen: false, default: false }
      hash['Cafe'] = { ratio: 0.0166, space_type_gen: true, default: false }
      hash['Corridor'] = { ratio: 0.1736, space_type_gen: true, default: false }
      hash['GuestRoom'] = { ratio: 0.4099, space_type_gen: true, default: true }
      hash['Kitchen'] = { ratio: 0.0091, space_type_gen: true, default: false }
      hash['Laundry'] = { ratio: 0.0069, space_type_gen: true, default: false }
      hash['Lobby'] = { ratio: 0.1153, space_type_gen: true, default: false }
      hash['Mechanical'] = { ratio: 0.0145, space_type_gen: true, default: false }
      hash['Retail'] = { ratio: 0.0128, space_type_gen: true, default: false }
      hash['Storage'] = { ratio: 0.0084, space_type_gen: true, default: false }
    elsif building_type == 'Warehouse'
      hash['Bulk'] = { ratio: 0.6628, space_type_gen: true, default: true }
      hash['Fine'] = { ratio: 0.2882, space_type_gen: true, default: false }
      hash['Office'] = { ratio: 0.0490, space_type_gen: true, default: false, wwr: 0.71 }
    elsif building_type == 'RetailStandalone'
      hash['Back_Space'] = { ratio: 0.1656, space_type_gen: true, default: false }
      hash['Entry'] = { ratio: 0.0052, space_type_gen: true, default: false }
      hash['Point_of_Sale'] = { ratio: 0.0657, space_type_gen: true, default: false }
      hash['Retail'] = { ratio: 0.7635, space_type_gen: true, default: true }
    elsif building_type == 'RetailStripmall'
      hash['Strip mall - type 1'] = { ratio: 0.25, space_type_gen: true, default: false }
      hash['Strip mall - type 2'] = { ratio: 0.25, space_type_gen: true, default: false }
      hash['Strip mall - type 3'] = { ratio: 0.50, space_type_gen: true, default: true }
    elsif building_type == 'QuickServiceRestaurant'
      hash['Dining'] = { ratio: 0.5, space_type_gen: true, default: true }
      hash['Kitchen'] = { ratio: 0.5, space_type_gen: true, default: false }
    elsif building_type == 'FullServiceRestaurant'
      hash['Dining'] = { ratio: 0.7272, space_type_gen: true, default: true }
      hash['Kitchen'] = { ratio: 0.2728, space_type_gen: true, default: false }
    elsif building_type == 'MidriseApartment'
      hash['Apartment'] = { ratio: 0.8727, space_type_gen: true, default: true }
      hash['Corridor'] = { ratio: 0.0991, space_type_gen: true, default: false }
      hash['Office'] = { ratio: 0.0282, space_type_gen: true, default: false }
    elsif building_type == 'HighriseApartment'
      hash['Apartment'] = { ratio: 0.8896, space_type_gen: true, default: true }
      hash['Corridor'] = { ratio: 0.0991, space_type_gen: true, default: false }
      hash['Office'] = { ratio: 0.0113, space_type_gen: true, default: false }
    elsif building_type == 'Hospital'
      hash['Basement'] = { ratio: 0.1667, space_type_gen: false, default: false }
      hash['Corridor'] = { ratio: 0.1741, space_type_gen: true, default: false }
      hash['Dining'] = { ratio: 0.0311, space_type_gen: true, default: false }
      hash['ER_Exam'] = { ratio: 0.0099, space_type_gen: true, default: false }
      hash['ER_NurseStn'] = { ratio: 0.0551, space_type_gen: true, default: false }
      hash['ER_Trauma'] = { ratio: 0.0025, space_type_gen: true, default: false }
      hash['ER_Triage'] = { ratio: 0.0050, space_type_gen: true, default: false }
      hash['ICU_NurseStn'] = { ratio: 0.0298, space_type_gen: true, default: false }
      hash['ICE_Open'] = { ratio: 0.0275, space_type_gen: true, default: false }
      hash['ICU_PatRm'] = { ratio: 0.0115, space_type_gen: true, default: false }
      hash['Kitchen'] = { ratio: 0.0414, space_type_gen: true, default: false }
      hash['Lab'] = { ratio: 0.0236, space_type_gen: true, default: false }
      hash['Lobby'] = { ratio: 0.0657, space_type_gen: true, default: false }
      hash['NurseStn'] = { ratio: 0.1723, space_type_gen: true, default: false }
      hash['Office'] = { ratio: 0.0286, space_type_gen: true, default: false }
      hash['OR'] = { ratio: 0.0273, space_type_gen: true, default: false }
      hash['PatCorridor'] = { ratio: 0.0, space_type_gen: true, default: false } # not in prototype
      hash['PatRoom'] = { ratio: 0.0845, space_type_gen: true, default: true }
      hash['PhysTherapy'] = { ratio: 0.0217, space_type_gen: true, default: false }
      hash['Radiology'] = { ratio: 0.0217, space_type_gen: true, default: false }
    elsif building_type == 'Outpatient'
      hash['Anesthesia'] = { ratio: 0.0026, space_type_gen: true, default: false }
      hash['BioHazard'] = { ratio: 0.0014, space_type_gen: true, default: false }
      hash['Cafe'] = { ratio: 0.0103, space_type_gen: true, default: false }
      hash['CleanWork'] = { ratio: 0.0071, space_type_gen: true, default: false }
      hash['Conference'] = { ratio: 0.0082, space_type_gen: true, default: false }
      hash['DresingRoom'] = { ratio: 0.0021, space_type_gen: true, default: false }
      hash['Elec/MechRoom'] = { ratio: 0.0109, space_type_gen: true, default: false }
      hash['ElevatorPumpRoom'] = { ratio: 0.0022, space_type_gen: true, default: false }
      hash['Exam'] = { ratio: 0.1029, space_type_gen: true, default: true }
      hash['Hall'] = { ratio: 0.1924, space_type_gen: true, default: false }
      hash['IT_Room'] = { ratio: 0.0027, space_type_gen: true, default: false }
      hash['Janitor'] = { ratio: 0.0672, space_type_gen: true, default: false }
      hash['Lobby'] = { ratio: 0.0152, space_type_gen: true, default: false }
      hash['LockerRoom'] = { ratio: 0.0190, space_type_gen: true, default: false }
      hash['Lounge'] = { ratio: 0.0293, space_type_gen: true, default: false }
      hash['MedGas'] = { ratio: 0.0014, space_type_gen: true, default: false }
      hash['MRI'] = { ratio: 0.0107, space_type_gen: true, default: false }
      hash['MRI_Control'] = { ratio: 0.0041, space_type_gen: true, default: false }
      hash['NurseStation'] = { ratio: 0.0189, space_type_gen: true, default: false }
      hash['Office'] = { ratio: 0.1828, space_type_gen: true, default: false }
      hash['OR'] = { ratio: 0.0346, space_type_gen: true, default: false }
      hash['PACU'] = { ratio: 0.0232, space_type_gen: true, default: false }
      hash['PhysicalTherapy'] = { ratio: 0.0462, space_type_gen: true, default: false }
      hash['PreOp'] = { ratio: 0.0129, space_type_gen: true, default: false }
      hash['ProcedureRoom'] = { ratio: 0.0070, space_type_gen: true, default: false }
      hash['Reception'] = { ratio: 0.0365, space_type_gen: true, default: false }
      hash['Soil Work'] = { ratio: 0.0088, space_type_gen: true, default: false }
      hash['Stair'] = { ratio: 0.0146, space_type_gen: true, default: false }
      hash['Toilet'] = { ratio: 0.0193, space_type_gen: true, default: false }
      hash['Undeveloped'] = { ratio: 0.0835, space_type_gen: false, default: false }
      hash['Xray'] = { ratio: 0.0220, space_type_gen: true, default: false }
    elsif building_type == 'SuperMarket'
      # TODO: - populate ratios for SuperMarket
      hash['Bakery'] = { ratio: 0.99, space_type_gen: true, default: false }
      hash['Deli'] = { ratio: 0.99, space_type_gen: true, default: false }
      hash['DryStorage'] = { ratio: 0.99, space_type_gen: true, default: false }
      hash['Office'] = { ratio: 0.99, space_type_gen: true, default: false }
      hash['Produce'] = { ratio: 0.99, space_type_gen: true, default: true }
      hash['Sales'] = { ratio: 0.99, space_type_gen: true, default: true }
      hash['Corridor'] = { ratio: 0.99, space_type_gen: true, default: true }
      hash['Dining'] = { ratio: 0.99, space_type_gen: true, default: true }
      hash['Elec/MechRoom'] = { ratio: 0.99, space_type_gen: true, default: true }
      hash['Meeting'] = { ratio: 0.99, space_type_gen: true, default: true }
      hash['Restroom'] = { ratio: 0.99, space_type_gen: true, default: true }
      hash['Vestibule'] = { ratio: 0.99, space_type_gen: true, default: true }
    else
      return false
    end

    return hash
  end

  # remove existing non resource objects from the model
  # technically thermostats and building stories are resources but still want to remove them.
  def remove_non_resource_objects(runner, model, options = nil)
    if options.nil?
      options = {}
      options[:remove_building_stories] = true
      options[:remove_thermostats] = true
      options[:remove_air_loops] = true
      options[:remove_non_swh_plant_loops] = true

      # leave these in by default unless requsted when method called
      options[:remove_swh_plant_loops] = false
      options[:remove_exterior_lights] = false
      options[:remove_site_shading] = false
    end

    num_model_objects = model.objects.size

    # remove non-resource objects not removed by removing the building
    if options[:remove_building_stories] then model.getBuildingStorys.each(&:remove) end
    if options[:remove_thermostats] then model.getThermostats.each(&:remove) end
    if options[:remove_air_loops] then model.getAirLoopHVACs.each(&:remove) end
    if options[:remove_exterior_lights] then model.getFacility.exteriorLights.each(&:remove) end
    if options[:remove_site_shading] then model.getSite.shadingSurfaceGroups.each(&:remove) end

    # see if plant loop is swh or not and take proper action (booter loop doesn't have water use equipment)
    model.getPlantLoops.each do |plant_loop|
      is_swh_loop = false
      plant_loop.supplyComponents.each do |component|
        if component.to_WaterHeaterMixed.is_initialized
          is_swh_loop = true
          next
        end
      end

      if is_swh_loop
        if options[:remove_swh_plant_loops] then plant_loop.remove end
      else
        if options[:remove_non_swh_plant_loops] then plant_loop.remove end
      end
    end

    # remove water use connections (may be removed when loop is removed)
    if options[:remove_swh_plant_loops] then model.getWaterConnectionss.each(&:remove) end
    if options[:remove_swh_plant_loops] then model.getWaterUseEquipments.each(&:remove) end

    # remove building but reset fields on new building object.
    building_fields = []
    building = model.getBuilding
    num_fields = building.numFields
    num_fields.times.each do |i|
      building_fields << building.getString(i).get
    end
    # removes spaces, space's child objects, thermal zones, zone equipment, non site surfaces, building stories and water use connections.
    model.getBuilding.remove
    building = model.getBuilding
    num_fields.times.each do |i|
      next if i == 0 # don't try and set handle
      building_fields << building.setString(i, building_fields[i])
    end

    # other than optionally site shading and exterior lights not messing with site characteristics

    if num_model_objects - model.objects.size > 0
      runner.registerInfo("Removed #{num_model_objects - model.objects.size} non resource objects from the model.")
    end

    return true
  end

  # create_bar(runner,model,bar_hash)
  # measures using this method should include OsLibGeometry and OsLibHelperMethods
  def create_bar(runner, model, bar_hash, story_multiplier_method = 'Basements Ground Mid Top')
    # warn about site shading
    if !model.getSite.shadingSurfaceGroups.empty?
      runner.registerWarning('The model has one or more site shading surafces. New geometry may not be positioned where expected, it will be centered over the center of the original geometry.')
    end

    # make custom story hash when number of stories below grade > 0
    # todo - update this so have option basements are not below 0? (useful for simplifying existing model and maintaining z position relative to site shading)
    story_hash = {}
    eff_below = bar_hash[:num_stories_below_grade]
    eff_above = bar_hash[:num_stories_above_grade]
    footprint_origin = bar_hash[:center_of_footprint]
    typical_story_height = bar_hash[:floor_height]

    # flatten story_hash out to individual stories included in building area
    stories_flat = []
    stories_flat_counter = 0
    bar_hash[:stories].each_with_index do |(k, v), i|
      # k is invalid in some cases, old story object that has been removed, should be from low to high including basement
      # skip if source story insn't included in building area
      if v[:story_included_in_building_area].nil? || (v[:story_included_in_building_area] == true)

        # add to counter
        stories_flat_counter += v[:story_min_multiplier]

        flat_hash = {}
        flat_hash[:story_party_walls] = v[:story_party_walls]
        flat_hash[:below_partial_story] = v[:below_partial_story]
        flat_hash[:bottom_story_ground_exposed_floor] = v[:bottom_story_ground_exposed_floor]
        flat_hash[:top_story_exterior_exposed_roof] = v[:top_story_exterior_exposed_roof]
        if i < eff_below
          flat_hash[:story_type] = 'B'
          flat_hash[:multiplier] = 1
        elsif i == eff_below
          flat_hash[:story_type] = 'Ground'
          flat_hash[:multiplier] = 1
        elsif stories_flat_counter == eff_below + eff_above.ceil
          flat_hash[:story_type] = 'Top'
          flat_hash[:multiplier] = 1
        else
          flat_hash[:story_type] = 'Mid'
          flat_hash[:multiplier] = v[:story_min_multiplier]
        end

        compare_hash = {}
        if !stories_flat.empty?
          stories_flat.last.each { |k, v| compare_hash[k] = flat_hash[k] if flat_hash[k] != v }
        end
        if (story_multiplier_method != 'None' && stories_flat.last == flat_hash) || (story_multiplier_method != 'None' && compare_hash.size == 1 && compare_hash.include?(:multiplier))
          stories_flat.last[:multiplier] += v[:story_min_multiplier]
        else
          stories_flat << flat_hash
        end
      end
    end

    if bar_hash[:num_stories_below_grade] > 0

      # add in below grade levels (may want to add below grade multipliers at some point if we start running deep basements)
      eff_below.times do |i|
        story_hash["B#{i + 1}"] = { space_origin_z: footprint_origin.z - typical_story_height * (i + 1), space_height: typical_story_height, multiplier: 1 }
      end
    end

    # add in above grade levels
    if eff_above > 2
      story_hash['Ground'] = { space_origin_z: footprint_origin.z, space_height: typical_story_height, multiplier: 1 }

      footprint_counter = 0
      effective_stories_counter = 1
      stories_flat.each do |hash|
        next if hash[:story_type] != 'Mid'
        if footprint_counter == 0
          string = 'Mid'
        else
          string = "Mid#{footprint_counter + 1}"
        end
        story_hash[string] = { space_origin_z: footprint_origin.z + typical_story_height * effective_stories_counter + typical_story_height * (hash[:multiplier] - 1) / 2.0, space_height: typical_story_height, multiplier: hash[:multiplier] }
        footprint_counter += 1
        effective_stories_counter += hash[:multiplier]
      end

      story_hash['Top'] = { space_origin_z: footprint_origin.z + typical_story_height * (eff_above.ceil - 1), space_height: typical_story_height, multiplier: 1 }
    elsif eff_above > 1
      story_hash['Ground'] = { space_origin_z: footprint_origin.z, space_height: typical_story_height, multiplier: 1 }
      story_hash['Top'] = { space_origin_z: footprint_origin.z + typical_story_height * (eff_above.ceil - 1), space_height: typical_story_height, multiplier: 1 }
    else # one story only
      story_hash['Ground'] = { space_origin_z: footprint_origin.z, space_height: typical_story_height, multiplier: 1 }
    end

    # create footprints
    if bar_hash[:bar_division_method] == 'Multiple Space Types - Simple Sliced'
      footprints = []
      story_hash.size.times do |i|
        # adjust size of bar of top story is not a full story
        if i + 1 == story_hash.size
          area_multiplier = (1.0 - bar_hash[:num_stories_above_grade].ceil + bar_hash[:num_stories_above_grade])
          edge_multiplier = Math.sqrt(area_multiplier)
          length = bar_hash[:length] * edge_multiplier
          width = bar_hash[:width] * edge_multiplier
        else
          length = bar_hash[:length]
          width = bar_hash[:width]
        end
        footprints << OsLib_Geometry.make_sliced_bar_simple_polygons(runner, bar_hash[:space_types], length, width, bar_hash[:center_of_footprint])
      end

    elsif bar_hash[:bar_division_method] == 'Multiple Space Types - Individual Stories Sliced'

      # update story_hash for partial_story_above
      story_hash.each_with_index do |(k, v), i|
        # adjust size of bar of top story is not a full story
        if i + 1 == story_hash.size
          story_hash[k][:partial_story_multiplier] = (1.0 - bar_hash[:num_stories_above_grade].ceil + bar_hash[:num_stories_above_grade])
        end
      end

      footprints = OsLib_Geometry.make_sliced_bar_multi_polygons(runner, bar_hash[:space_types], bar_hash[:length], bar_hash[:width], bar_hash[:center_of_footprint], story_hash)

    else
      footprints = []
      story_hash.size.times do |i|
        # adjust size of bar of top story is not a full story
        if i + 1 == story_hash.size
          area_multiplier = (1.0 - bar_hash[:num_stories_above_grade].ceil + bar_hash[:num_stories_above_grade])
          edge_multiplier = Math.sqrt(area_multiplier)
          length = bar_hash[:length] * edge_multiplier
          width = bar_hash[:width] * edge_multiplier
        else
          length = bar_hash[:length]
          width = bar_hash[:width]
        end
        footprints << OsLib_Geometry.make_core_and_perimeter_polygons(runner, length, width, bar_hash[:center_of_footprint]) # perimeter defaults to 15'
      end

      # set primary space type to building default space type
      space_types = bar_hash[:space_types].sort_by { |k, v| v[:floor_area] }
      model.getBuilding.setSpaceType(space_types.last.first)

    end

    # makeSpacesFromPolygons
    OsLib_Geometry.makeSpacesFromPolygons(runner, model, footprints, bar_hash[:floor_height], bar_hash[:num_stories], bar_hash[:center_of_footprint], story_hash)

    # put all of the spaces in the model into a vector for intersection and surface matching
    spaces = OpenStudio::Model::SpaceVector.new
    model.getSpaces.sort.each do |space|
      spaces << space
    end

    # only intersect if make_mid_story_surfaces_adiabatic false
    if !(bar_hash[:make_mid_story_surfaces_adiabatic])
      # intersect surfaces
      # (when bottom floor has many space types and one above doesn't will end up with heavily subdivided floor. Maybe use adiabatic and don't intersect floor/ceilings)
      intersect_surfaces = true
      if intersect_surfaces
        OpenStudio::Model.intersectSurfaces(spaces)
        runner.registerInfo('Intersecting surfaces, this will create additional geometry.')
      end
    end

    # match surfaces for each space in the vector
    OpenStudio::Model.matchSurfaces(spaces)

    # set boundary conditions if not already set when geometry was created
    # todo - update this to use space original z value vs. story name
    if bar_hash[:num_stories_below_grade] > 0
      model.getBuildingStorys.each do |story|
        next if !story.name.to_s.include?('Story B')
        story.spaces.each do |space|
          space.surfaces.each do |surface|
            next if surface.surfaceType != 'Wall'
            next if surface.outsideBoundaryCondition != 'Outdoors'
            surface.setOutsideBoundaryCondition('Ground')
          end
        end
      end
    end

    # sort stories (by name for now but need better way)
    # todo - need to change this so doesn't create issues when models have existing stories and spaces. Should be able to run it multiple times
    sorted_stories = {}
    model.getBuildingStorys.each do |story|
      sorted_stories[story.name.to_s] = story
    end

    # flag space types that have wwr overrides
    space_type_wwr_overrides = {}

    # loop through building stories, spaces, and surfaces
    sorted_stories.sort.each_with_index do |(key, story), i|
      # flag for adiabatic floor if building doesn't have ground exposed floor
      if stories_flat[i][:bottom_story_ground_exposed_floor] == false
        adiabatic_floor = true
      end
      # flag for adiabatic roof if building doesn't have exterior exposed roof
      if stories_flat[i][:top_story_exterior_exposed_roof] == false
        adiabatic_ceiling = true
      end

      # make all mid story floor and celings adiabiatc if requested
      if bar_hash[:make_mid_story_surfaces_adiabatic]
        if i > 0
          adiabatic_floor = true
        end
        if i < sorted_stories.size - 1
          adiabatic_ceiling = true
        end
      end

      # flag orientations for this story to recieve party walls
      party_wall_facades = stories_flat[i][:story_party_walls]

      story.spaces.each do |space|
        space.surfaces. each do |surface|
          # set floor to adiabatic if requited
          if adiabatic_floor && surface.surfaceType == 'Floor'
            make_surfaces_adiabatic([surface])
          elsif adiabatic_ceiling && surface.surfaceType == 'RoofCeiling'
            make_surfaces_adiabatic([surface])
          end

          # skip of not exterior wall
          next if surface.surfaceType != 'Wall'
          next if surface.outsideBoundaryCondition != 'Outdoors'

          # get the absoluteAzimuth for the surface so we can categorize it
          absoluteAzimuth = OpenStudio.convert(surface.azimuth, 'rad', 'deg').get + surface.space.get.directionofRelativeNorth + model.getBuilding.northAxis
          absoluteAzimuth = absoluteAzimuth % 360.0 # should result in value between 0 and 360
          absoluteAzimuth = absoluteAzimuth.round(5) # this was creating issues at 45 deg angles with opposing facades

          # target wwr values that may be changed for specific space types
          wwr_n = bar_hash[:building_wwr_n]
          wwr_e = bar_hash[:building_wwr_e]
          wwr_s = bar_hash[:building_wwr_s]
          wwr_w = bar_hash[:building_wwr_w]

          # look for space type specific wwr values
          if surface.space.is_initialized && surface.space.get.spaceType.is_initialized
            space_type = surface.space.get.spaceType.get

            # see if space type has wwr value
            bar_hash[:space_types].each do |k, v|
              if v.key?(:space_type) && space_type == v[:space_type]

                # if matching space type specifies a wwr then override the orientaiton specific recommendations for this surface.
                if v.key?(:wwr)
                  wwr_n = v[:wwr]
                  wwr_e = v[:wwr]
                  wwr_s = v[:wwr]
                  wwr_w = v[:wwr]
                  space_type_wwr_overrides[space_type] = v[:wwr]
                end
              end
            end
          end

          # add fenestration (wwr for now, maybe overhang and overhead doors later)
          if (absoluteAzimuth >= 315.0) || (absoluteAzimuth < 45.0)
            if party_wall_facades.include?('north')
              make_surfaces_adiabatic([surface])
            else
              surface.setWindowToWallRatio(wwr_n)
            end
          elsif (absoluteAzimuth >= 45.0) && (absoluteAzimuth < 135.0)
            if party_wall_facades.include?('east')
              make_surfaces_adiabatic([surface])
            else
              surface.setWindowToWallRatio(wwr_e)
            end
          elsif (absoluteAzimuth >= 135.0) && (absoluteAzimuth < 225.0)
            if party_wall_facades.include?('south')
              make_surfaces_adiabatic([surface])
            else
              surface.setWindowToWallRatio(wwr_s)
            end
          elsif (absoluteAzimuth >= 225.0) && (absoluteAzimuth < 315.0)
            if party_wall_facades.include?('west')
              make_surfaces_adiabatic([surface])
            else
              surface.setWindowToWallRatio(wwr_w)
            end
          else
            runner.registerError('Unexpected value of facade: ' + absoluteAzimuth + '.')
            return false
          end
        end
      end
    end

    # report space types with custom wwr values
    space_type_wwr_overrides.each do |space_type, wwr|
      runner.registerInfo("For #{space_type.name} the default building wwr was replaced with a space type specifc value of #{wwr}")
    end

    final_floor_area_ip = OpenStudio.convert(model.getBuilding.floorArea, 'm^2', 'ft^2').get
    runner.registerInfo("Created Bar envlope with floor area of #{OpenStudio.toNeatString(final_floor_area_ip, 0, true)} (ft^2)")
  end

  # make selected surfaces adiabatic
  def make_surfaces_adiabatic(surfaces)
    surfaces.each do |surface|
      if surface.construction.is_initialized
        surface.setConstruction(surface.construction.get)
      end
      surface.setOutsideBoundaryCondition('Adiabatic')
    end
  end

  # get length and width of rectangle matching bounding box aspect ratio will maintaining proper floor area
  def calc_bar_reduced_bounding_box(envelope_data_hash)
    bar = {}

    bounding_length = envelope_data_hash[:building_max_xyz][0] - envelope_data_hash[:building_min_xyz][0]
    bounding_width = envelope_data_hash[:building_max_xyz][1] - envelope_data_hash[:building_min_xyz][1]
    bounding_area = bounding_length * bounding_width
    footprint_area = envelope_data_hash[:building_floor_area] / envelope_data_hash[:effective__num_stories].to_f
    area_multiplier = footprint_area / bounding_area
    edge_multiplier = Math.sqrt(area_multiplier)
    bar[:length] = bounding_length * edge_multiplier
    bar[:width] = bounding_width * edge_multiplier

    return bar
  end

  # get length and width of rectangle matching longer of two edges, and reducing the other way until floor area matches
  def calc_bar_reduced_width(envelope_data_hash)
    bar = {}

    bounding_length = envelope_data_hash[:building_max_xyz][0] - envelope_data_hash[:building_min_xyz][0]
    bounding_width = envelope_data_hash[:building_max_xyz][1] - envelope_data_hash[:building_min_xyz][1]
    footprint_area = envelope_data_hash[:building_floor_area] / envelope_data_hash[:effective__num_stories].to_f

    if bounding_length >= bounding_width
      bar[:length] = bounding_length
      bar[:width] = footprint_area / bounding_length
    else
      bar[:width] = bounding_width
      bar[:length] = footprint_area / bounding_width
    end

    return bar
  end

  # get length and width of rectangle by stretching it until both floor area and exterior wall area or perimeter match
  def calc_bar_stretched(envelope_data_hash)
    bar = {}

    bounding_length = envelope_data_hash[:building_max_xyz][0] - envelope_data_hash[:building_min_xyz][0]
    bounding_width = envelope_data_hash[:building_max_xyz][1] - envelope_data_hash[:building_min_xyz][1]
    a = envelope_data_hash[:building_floor_area] / envelope_data_hash[:effective__num_stories].to_f
    p = envelope_data_hash[:building_perimeter]

    if bounding_length >= bounding_width
      bar[:length] = 0.25 * (p + Math.sqrt(p**2 - 16 * a))
      bar[:width] = 0.25 * (p - Math.sqrt(p**2 - 16 * a))
    else
      bar[:length] = 0.25 * (p - Math.sqrt(p**2 - 16 * a))
      bar[:width] = 0.25 * (p + Math.sqrt(p**2 - 16 * a))
    end

    return bar
  end
end