# frozen_string_literal: true # ******************************************************************************* # 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. # ******************************************************************************* # Start the measure class CreateBaselineBuilding < OpenStudio::Measure::ModelMeasure require 'openstudio-standards' # Define the name of the Measure. def name return 'Create Baseline Building' end # Human readable description def description return 'Creates the Performance Rating Method baseline building. For 90.1, this is the Appendix G aka LEED Baseline. For India ECBC, this is the Appendix D Baseline. Note: for 90.1, this model CANNOT be used for code compliance; it is not the same as the Energy Cost Budget baseline.' end # Human readable description of modeling approach def modeler_description return '' end # Define the arguments that the user will input. def arguments(model) args = OpenStudio::Measure::OSArgumentVector.new # Make an argument for the standard standard_chs = OpenStudio::StringVector.new # standard_chs << '90.1-2004' standard_chs << '90.1-2007 BETA' # 1.13.1 onward supports 90.1-2010 if model.version > OpenStudio::VersionString.new('1.13.0') standard_chs << '90.1-2010 BETA' end standard_chs << '90.1-2013' # standard_chs << 'India ECBC 2007' standard = OpenStudio::Measure::OSArgument.makeChoiceArgument('standard', standard_chs, true) standard.setDisplayName('Standard') standard.setDefaultValue('90.1-2013') args << standard # Make an argument for the building type building_type_chs = OpenStudio::StringVector.new building_type_chs << 'MidriseApartment' building_type_chs << 'SecondarySchool' building_type_chs << 'PrimarySchool' building_type_chs << 'SmallOffice' building_type_chs << 'MediumOffice' building_type_chs << 'LargeOffice' building_type_chs << 'SmallHotel' building_type_chs << 'LargeHotel' building_type_chs << 'Warehouse' building_type_chs << 'RetailStandalone' building_type_chs << 'RetailStripmall' building_type_chs << 'QuickServiceRestaurant' building_type_chs << 'FullServiceRestaurant' building_type_chs << 'Hospital' building_type_chs << 'Outpatient' building_type = OpenStudio::Measure::OSArgument.makeChoiceArgument('building_type', building_type_chs, true) building_type.setDisplayName('Building Type.') building_type.setDefaultValue('SmallOffice') args << building_type # Make an argument for the climate zone climate_zone_chs = OpenStudio::StringVector.new climate_zone_chs << 'ASHRAE 169-2013-1A' climate_zone_chs << 'ASHRAE 169-2013-2A' climate_zone_chs << 'ASHRAE 169-2013-2B' climate_zone_chs << 'ASHRAE 169-2013-3A' climate_zone_chs << 'ASHRAE 169-2013-3B' climate_zone_chs << 'ASHRAE 169-2013-3C' climate_zone_chs << 'ASHRAE 169-2013-4A' climate_zone_chs << 'ASHRAE 169-2013-4B' climate_zone_chs << 'ASHRAE 169-2013-4C' climate_zone_chs << 'ASHRAE 169-2013-5A' climate_zone_chs << 'ASHRAE 169-2013-5B' climate_zone_chs << 'ASHRAE 169-2013-6A' climate_zone_chs << 'ASHRAE 169-2013-6B' climate_zone_chs << 'ASHRAE 169-2013-7A' climate_zone_chs << 'ASHRAE 169-2013-8A' # climate_zone_chs << 'India ECBC Composite' # climate_zone_chs << 'India ECBC Hot and Dry' # climate_zone_chs << 'India ECBC Warm and Humid' # climate_zone_chs << 'India ECBC Moderate' # climate_zone_chs << 'India ECBC Cold' climate_zone = OpenStudio::Measure::OSArgument.makeChoiceArgument('climate_zone', climate_zone_chs, true) climate_zone.setDisplayName('Climate Zone.') climate_zone.setDefaultValue('ASHRAE 169-2013-2A') args << climate_zone # Make an argument for the customization custom_chs = OpenStudio::StringVector.new custom_chs << 'Xcel Energy CO EDA' custom_chs << '*None*' custom = OpenStudio::Measure::OSArgument.makeChoiceArgument('custom', custom_chs, true) custom.setDisplayName('Customization') custom.setDescription('If selected, some of the standard process will be replaced by custom logic specific to particular programs. If these do not apply to you, select None.') custom.setDefaultValue('*None*') args << custom # 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 that can be accessed across the measure building_type = runner.getStringArgumentValue('building_type', user_arguments) standard = runner.getStringArgumentValue('standard', user_arguments) climate_zone = runner.getStringArgumentValue('climate_zone', user_arguments) custom = runner.getStringArgumentValue('custom', user_arguments) debug = runner.getBoolArgumentValue('debug', user_arguments) # Convert custom to nil if necessary if custom == '*None*' custom = nil end # Strip BETA from the standard choice if standard.include?(' BETA') runner.registerWarning("You have chosen #{standard}, which is still under development. It should generally be correct, but has not been heavily tested. Please review the output messages closely.") standard = standard.gsub(' BETA', '') end # Open a channel to log info/warning/error messages @msg_log = OpenStudio::StringStreamLogSink.new if debug @msg_log.setLogLevel(OpenStudio::Debug) else @msg_log.setLogLevel(OpenStudio::Info) end @start_time = Time.new @runner = runner # Contact info for where to report issues contact = "While this Measure aims to be comprehensive and was tested against a suite of models of actual building designs, there are bound to be situations that it will not handle correctly. It is your responsibility as a modeler to review the results of this Measure and adjust accordingly. If you find issues (beyond those listed below), please report them here. Please include a detailed description, the proposed model, and references to the pertinent sections of 90.1, ASHRAE interpretations, or LEED interpretations." OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', contact) # List of unsupported things us = [] us << 'Lighting controls (occ/vac sensors) are assumed to already be present in proposed lighting schedules, and will not be added or removed' us << 'Exterior lighting in the baseline model is left as found in proposed' us << 'Optimal start of HVAC systems is not supported' us << 'Skylights are not added to model, but existing skylights are scaled per Appendix G skylight-to-roof areas' us << 'Changing baseline glazing types based on WWR and orientation' if standard == '90.1-2004' us << 'No fan power allowances for MERV filters or ducted supply/return present in proposed model HVAC' us << 'Laboratory-specific ventilation is not handled' us << 'Kitchen ventilation is not handled; exhaust fans left as found in proposed' us << 'Commercial refrigeration equipment is left as found in proposed' us << 'Transformers are not added to the baseline model' us << 'System types 11 (for data centers) and 12/13 (for public assembly buildings)' if standard == '90.1-2013' us << 'Zone humidity control present in the proposed model HVAC systems is not added to baseline HVAC' # Report out to users OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', '*** Currently unsupported ***') us.each do |msg| OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', msg) end # List of known issues or limitations issues = [] issues << 'Some control and efficiency determinations do not scale capacities/flow rates down to reflect zone multipliers' issues << 'Daylighting control illuminance setpoint does not vary based on space type' issues << 'Daylighting area calcs do not include windows in non-vertical walls' issues << 'Daylighting area calcs do not include skylights in non-horizontal roofs' # Report out to users OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', '*** Known issues ***') issues.each do |msg| OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', msg) end # Make a directory to save the resulting models for debugging build_dir = "#{Dir.pwd}/output" if !Dir.exist?(build_dir) Dir.mkdir(build_dir) end # Versions of OpenStudio greater than 2.4.0 use a modified version of # openstudio-standards with different method calls. if OpenStudio::VersionString.new(OpenStudio.openStudioVersion) < OpenStudio::VersionString.new('2.4.3') success = model.create_prm_baseline_building(building_type, standard, climate_zone, custom, build_dir, debug) else std = Standard.build(standard) std.model_create_prm_baseline_building(model, building_type, climate_zone, custom, build_dir, debug) end log_msgs(debug) return success end # end the run method # Get all the log messages and put into output # for users to see. def log_msgs(debug) # Log the messages to file for easier review log_name = 'create_baseline.log' log_file_path = "#{Dir.pwd}/#{log_name}" messages = log_messages_to_file(log_file_path, debug) @runner.registerFinalCondition("Messages below saved to #{log_name}.") @msg_log.logMessages.each do |msg| # DLM: you can filter on log channel here for now if /openstudio.*/.match?(msg.logChannel) # /openstudio\.model\..*/ # Skip certain messages that are irrelevant/misleading next if msg.logMessage.include?('Skipping layer') || # Annoying/bogus "Skipping layer" warnings msg.logChannel.include?('runmanager') || # RunManager messages msg.logChannel.include?('setFileExtension') || # .ddy extension unexpected msg.logChannel.include?('Translator') || # Forward translator and geometry translator msg.logMessage.include?('UseWeatherFile') || # 'UseWeatherFile' is not yet a supported option for YearDescription msg.logMessage.include?('has multiple parents') # Object of type 'OS:Curve:Cubic' and named 'VSD-TWR-FAN-FPLR' has multiple parents. Returning the first. # Report the message in the correct way if msg.logLevel == OpenStudio::Info @runner.registerInfo(msg.logMessage) elsif msg.logLevel == OpenStudio::Warn @runner.registerWarning(msg.logMessage.to_s) elsif msg.logLevel == OpenStudio::Error @runner.registerError(msg.logMessage.to_s) elsif msg.logLevel == OpenStudio::Debug && debug @runner.registerInfo("DEBUG - #{msg.logMessage}") end end end @runner.registerInfo("Total Time = #{(Time.new - @start_time).round}sec.") end end # end the measure # this allows the measure to be use by the application CreateBaselineBuilding.new.registerWithApplication