# insert your copyright here # see the URL below for information on how to write OpenStudio measures # http://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/ # start the measure require 'openstudio/extension/core/os_lib_helper_methods' require 'openstudio/extension/core/os_lib_schedules' class AddExteriorBlindsAndControl < OpenStudio::Measure::ModelMeasure include OsLib_HelperMethods include OsLib_Schedules # human readable name def name # Measure name should be the title case of the class name. return 'add_exterior_blinds_and_control' end # human readable description def description return 'This measure add shading control with exterior blinds to all exterior windows of the building. ' end # human readable description of modeling approach def modeler_description return 'The measure will create a new exterior blinds shading control object for each space, and apply that shading control object to all exterior windows within that space. A new shading schedule will be created and applied to all shading control objects based on the active time provided in user inputs.' end # define the arguments that the user will input def arguments(model) args = OpenStudio::Measure::OSArgumentVector.new start_time = OpenStudio::Measure::OSArgument.makeStringArgument('start_time', false) start_time.setDisplayName('Start Time for Shading') start_time.setDescription('In HH:MM:SS format') start_time.setDefaultValue('12:00:00') args << start_time # make an argument for the end time of the reduction end_time = OpenStudio::Measure::OSArgument.makeStringArgument('end_time', false) end_time.setDisplayName('End Time for Shading') end_time.setDescription('In HH:MM:SS format') end_time.setDefaultValue('15:00:00') args << end_time # make an argument for the start date of the reduction start_date = OpenStudio::Ruleset::OSArgument.makeStringArgument('start_date', false) start_date.setDisplayName('Start date for Shading') start_date.setDescription('In MM-DD format') start_date.setDefaultValue('07-01') args << start_date # make an argument for the end date of the reduction end_date = OpenStudio::Ruleset::OSArgument.makeStringArgument('end_date', false) end_date.setDisplayName('End date for Shading') end_date.setDescription('In MM-DD format') end_date.setDefaultValue('08-30') args << end_date 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 start_time = runner.getStringArgumentValue('start_time', user_arguments) end_time = runner.getStringArgumentValue('end_time', user_arguments) start_date = runner.getStringArgumentValue('start_date', user_arguments) end_date = runner.getStringArgumentValue('end_date', user_arguments) unless /(\d\d):(\d\d):(\d\d)/.match(start_time) runner.registerError('Start time must be in HH-MM-SS format.') return false end unless /(\d\d):(\d\d):(\d\d)/.match(end_time) runner.registerError('End time must be in HH-MM-SS format.') return false end if start_time.to_f > end_time.to_f runner.registerError('The start time cannot be later than the end time.') return false end start_month = nil start_day = nil md = /(\d\d)-(\d\d)/.match(start_date) if md start_month = md[1].to_i start_day = md[2].to_i else runner.registerError('Start date must be in MM-DD format.') return false end end_month = nil end_day = nil md = /(\d\d)-(\d\d)/.match(end_date) if md end_month = md[1].to_i end_day = md[2].to_i else runner.registerError('End date must be in MM-DD format.') return false end # create a shading control for each space # All windows using one shading control object will cause duplicated objects (with the same zone name) when translated into idf, # which may crash EP windows_applied = 0 # All shading control objects share one schedule global_shading_schedule = nil model.getSpaces.each do |space| # One shading control object for each space if it has any exterior windows space_shading_control = nil space.surfaces.each do |surface| surface.subSurfaces.each do |sub_surface| if (sub_surface.outsideBoundaryCondition == 'Outdoors') && (sub_surface.subSurfaceType.include?'Window') # create schedule and shading control object only if an exterior window is found # (avoid any modifications if no exterior window exists in the model) unless global_shading_schedule # create a new shading schedule normal_day_data_pairs = [[24, 0]] h, m, s = start_time.split(':') start_hour = h.to_i + m.to_i/60 h, m, s = end_time.split(':') end_hour = h.to_i + m.to_i/60 adjusted_day_data_pairs = [[start_hour, 0], [end_hour, 1], [24, 0]] options = { 'name' => "Exterior blinds schedule", 'winter_design_day' => normal_day_data_pairs, 'summer_design_day' => normal_day_data_pairs, 'default_day' => ["default day"] + normal_day_data_pairs, 'rules' => [['Adjusted days', "#{start_month}/#{start_day}-#{end_month}/#{end_day}", 'Sun/Mon/Tue/Wed/Thu/Fri/Sat'] + adjusted_day_data_pairs] } global_shading_schedule = OsLib_Schedules.createComplexSchedule(model, options) runner.registerInfo("A new schedule 'Exterior blinds schedule' has been created for new shading control objects.") end unless space_shading_control shading_material = OpenStudio::Model::Blind.new(model) # create shading control object space_shading_control = OpenStudio::Model::ShadingControl.new(shading_material) space_shading_control.setShadingType("ExteriorBlind") space_shading_control.setName("#{space.name} exterior blinds shading control") space_shading_control.setShadingControlType('OnIfScheduleAllows') space_shading_control.setSchedule(global_shading_schedule) end sub_surface.setShadingControl(space_shading_control) runner.registerInfo("Exterior blinds shading '#{space_shading_control.name}' has been added to window #{sub_surface.name}.") windows_applied += 1 end end end end if windows_applied == 0 runner.registerAsNotApplicable("There's no exterior window in the model, so the measure didn't make any change.") else runner.registerFinalCondition("In total #{windows_applied} exterior windows have been applied with exterior blinds shading.") end return true end end # register the measure to be used by the application AddExteriorBlindsAndControl.new.registerWithApplication