Class: PeakPeriodSchedulesShift
- Inherits:
-
OpenStudio::Measure::ModelMeasure
- Object
- OpenStudio::Measure::ModelMeasure
- PeakPeriodSchedulesShift
- Defined in:
- lib/measures/PeakPeriodSchedulesShift/measure.rb
Overview
start the measure
Instance Method Summary collapse
-
#arguments(_model) ⇒ Object
define the arguments that the user will input.
-
#description ⇒ Object
human readable description.
- #get_hourly_values(day_schedule) ⇒ Object
- #get_schedule_file_column_names(model) ⇒ Object
- #get_schedule_ruleset_names(model) ⇒ Object
-
#modeler_description ⇒ Object
human readable description of modeling approach.
-
#name ⇒ Object
human readable name.
-
#run(model, runner, user_arguments) ⇒ Object
define what happens when the measure is run.
- #shift_day_schedule(calendar_year, shift_summary, schedule_ruleset_name, schedule_rule, day_schedule, schedule, schedules_peak_period_weekdays_only) ⇒ Object
-
#taxonomy ⇒ Object
used to populate taxonomy in readme.md.
Instance Method Details
#arguments(_model) ⇒ Object
define the arguments that the user will input
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 37 def arguments(_model) args = OpenStudio::Measure::OSArgumentVector.new arg = OpenStudio::Measure::OSArgument.makeStringArgument('schedules_peak_period', true) arg.setDisplayName('Schedules: Peak Period') arg.setDescription('Specifies the peak period. Enter a time like "15 - 18" (start hour can be 0 through 23 and end hour can be 1 through 24).') arg.setDefaultValue('15 - 18') args << arg arg = OpenStudio::Measure::OSArgument.makeIntegerArgument('schedules_peak_period_delay', true) arg.setDisplayName('Schedules: Peak Period Delay') arg.setUnits('hr') arg.setDescription('The number of hours after peak period end.') arg.setDefaultValue(0) args << arg arg = OpenStudio::Measure::OSArgument.makeBoolArgument('schedules_peak_period_allow_stacking', false) arg.setDisplayName('Schedules: Peak Period Allow Stacking') arg.setDescription('Whether schedules can be shifted to periods that already have non-zero schedule values. Defaults to true. Note that the schedule type limits upper value is increased to 2.0 when allowing stacked schedule values.') args << arg arg = OpenStudio::Measure::OSArgument.makeBoolArgument('schedules_peak_period_weekdays_only', false) arg.setDisplayName('Schedules: Peak Period Weekdays Only') arg.setDescription('Whether schedules can be shifted for weekdays only, or weekends as well. Defaults to true.') args << arg arg = OpenStudio::Measure::OSArgument.makeStringArgument('schedules_peak_period_schedule_rulesets_names', false) arg.setDisplayName('Schedules: Peak Period Schedule Rulesets Names') arg.setDescription('Comma-separated list of Schedule:Ruleset object names corresponding to schedules to shift during the specified peak period.') args << arg arg = OpenStudio::Measure::OSArgument.makeStringArgument('schedules_peak_period_schedule_files_column_names', false) arg.setDisplayName('Schedules: Peak Period Schedule Files Column Names') arg.setDescription('Comma-separated list of column names, referenced by Schedule:File objects, corresponding to schedules to shift during the specified peak period.') args << arg return args end |
#description ⇒ Object
human readable description
22 23 24 |
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 22 def description return 'Shifts select weekday (or weekday/weekend) schedules out of a peak period.' end |
#get_hourly_values(day_schedule) ⇒ Object
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 289 def get_hourly_values(day_schedule) times = day_schedule.times values = day_schedule.values hourly_values = [] t0 = 0 times.each_with_index do |_time, i| t1 = times[i].hours t1 = 24 if t1 == 0 hours = t1 - t0 for _v in 0...hours hourly_values << values[i] end t0 = t1 end return hourly_values end |
#get_schedule_file_column_names(model) ⇒ Object
84 85 86 87 88 89 90 91 |
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 84 def get_schedule_file_column_names(model) schedule_file_column_names = [] model.getExternalFiles.each do |external_file| external_file_path = external_file.filePath.to_s schedule_file_column_names += CSV.foreach(external_file_path).first end return schedule_file_column_names.uniq.sort end |
#get_schedule_ruleset_names(model) ⇒ Object
76 77 78 79 80 81 82 |
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 76 def get_schedule_ruleset_names(model) schedule_ruleset_names = [] model.getScheduleRulesets.each do |schedule_ruleset| schedule_ruleset_names << schedule_ruleset.name.to_s end return schedule_ruleset_names.uniq.sort end |
#modeler_description ⇒ Object
human readable description of modeling approach
27 28 29 |
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 27 def modeler_description return 'Enter a peak period window, a delay value, and any applicable ScheduleRuleset or ScheduleFile schedules. Shift all schedule values falling within the peak period to after the end (offset by delay) of the peak period. Optionally prevent stacking of schedule values by only allowing shifts to all-zero periods. Optionally apply schedule shifts to weekend days.' end |
#name ⇒ Object
human readable name
16 17 18 19 |
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 16 def name # Measure name should be the title case of the class name. return 'PeakPeriodSchedulesShift' end |
#run(model, runner, user_arguments) ⇒ Object
define what happens when the measure is run
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 94 def run(model, runner, user_arguments) super(model, runner, user_arguments) # Do **NOT** remove this line # use the built-in error checking if !runner.validateUserArguments(arguments(model), user_arguments) return false end schedules_peak_period = runner.getStringArgumentValue('schedules_peak_period', user_arguments) schedules_peak_period_delay = runner.getIntegerArgumentValue('schedules_peak_period_delay', user_arguments) schedules_peak_period_allow_stacking = runner.getOptionalBoolArgumentValue('schedules_peak_period_allow_stacking', user_arguments) schedules_peak_period_allow_stacking = schedules_peak_period_allow_stacking.is_initialized ? schedules_peak_period_allow_stacking.get : true schedules_peak_period_weekdays_only = runner.getOptionalBoolArgumentValue('schedules_peak_period_weekdays_only', user_arguments) schedules_peak_period_weekdays_only = schedules_peak_period_weekdays_only.is_initialized ? schedules_peak_period_weekdays_only.get : true schedules_peak_period_schedule_rulesets_names = runner.getOptionalStringArgumentValue('schedules_peak_period_schedule_rulesets_names', user_arguments) schedules_peak_period_schedule_rulesets_names = schedules_peak_period_schedule_rulesets_names.is_initialized ? schedules_peak_period_schedule_rulesets_names.get.split(',').map(&:strip) : [] schedules_peak_period_schedule_files_column_names = runner.getOptionalStringArgumentValue('schedules_peak_period_schedule_files_column_names', user_arguments) schedules_peak_period_schedule_files_column_names = schedules_peak_period_schedule_files_column_names.is_initialized ? schedules_peak_period_schedule_files_column_names.get.split(',').map(&:strip) : [] schedule_ruleset_names_enabled = {} get_schedule_ruleset_names(model).each do |schedule_ruleset_name| schedule_ruleset_names_enabled[schedule_ruleset_name] = schedules_peak_period_schedule_rulesets_names.include?(schedule_ruleset_name) end schedule_file_column_names_enabled = {} get_schedule_file_column_names(model).each do |schedule_file_column_name| schedule_file_column_names_enabled[schedule_file_column_name] = schedules_peak_period_schedule_files_column_names.include?(schedule_file_column_name) end if (schedule_ruleset_names_enabled.empty? || schedule_ruleset_names_enabled.values.all? { |value| value == false }) && (schedule_file_column_names_enabled.empty? || schedule_file_column_names_enabled.values.all? { |value| value == false }) runner.registerAsNotApplicable('Did not select any ScheduleRuleset or ScheduleFile objects to shift.') return true end begin_hour, end_hour = Schedules.parse_time_range(schedules_peak_period) if begin_hour >= end_hour runner.registerError("Specified peak period (#{begin_hour} - #{end_hour}) must be at least one hour long.") return false end peak_period_length = end_hour - begin_hour if peak_period_length + schedules_peak_period_delay > 12 runner.registerError("Specified peak period (#{begin_hour} - #{end_hour}), plus the delay (#{schedules_peak_period_delay}), must be no longer than 12 hours.") return false end if peak_period_length + end_hour + schedules_peak_period_delay > 24 runner.registerError('Cannot shift day schedules into the next day.') return false end # get year yd = model.getYearDescription calendar_year = yd.assumedYear calendar_year = yd.calendarYear.get if yd.calendarYear.is_initialized total_days_in_year = Schedules.NumDaysInYear(calendar_year) sim_start_day = DateTime.new(calendar_year, 1, 1) # get steps ts = model.getTimestep ts_per_hour = ts.numberOfTimestepsPerHour steps_in_day = ts_per_hour * 24 # Schedule:Ruleset shift_summary = {} schedule_rulesets = model.getScheduleRulesets schedule_ruleset_names_enabled.each do |schedule_ruleset_name, peak_period_shift_enabled| next if !peak_period_shift_enabled shift_summary[schedule_ruleset_name] = 0 shifted_schedule = false schedule_ruleset = schedule_rulesets.find { |schedule_ruleset| schedule_ruleset.name.to_s == schedule_ruleset_name } schedule_ruleset.scheduleRules.reverse_each do |schedule_rule| if schedules_peak_period_weekdays_only && !(schedule_rule.applyMonday || schedule_rule.applyTuesday || schedule_rule.applyWednesday || schedule_rule.applyThursday || schedule_rule.applyFriday) next # at least one weekday applies end new_schedule_rule = schedule_rule.clone.to_ScheduleRule.get new_schedule_rule.setName("#{schedule_rule.name} Shifted") new_schedule_rule.setApplySunday(schedule_rule.applySunday) new_schedule_rule.setApplySunday(false) if schedules_peak_period_weekdays_only new_schedule_rule.setApplyMonday(schedule_rule.applyMonday) new_schedule_rule.setApplyTuesday(schedule_rule.applyTuesday) new_schedule_rule.setApplyWednesday(schedule_rule.applyWednesday) new_schedule_rule.setApplyThursday(schedule_rule.applyThursday) new_schedule_rule.setApplyFriday(schedule_rule.applyFriday) new_schedule_rule.setApplySaturday(schedule_rule.applySaturday) new_schedule_rule.setApplySaturday(false) if schedules_peak_period_weekdays_only schedule_ruleset.setScheduleRuleIndex(new_schedule_rule, 0) old_day_schedule = schedule_rule.daySchedule new_day_schedule = new_schedule_rule.daySchedule new_day_schedule.setName("#{old_day_schedule.name} Shifted") schedule = get_hourly_values(old_day_schedule) shifted_day_schedule = Schedules.day_peak_shift(schedule, 0, begin_hour, end_hour, schedules_peak_period_delay, schedules_peak_period_allow_stacking, 24) if shifted_day_schedule shift_day_schedule(calendar_year, shift_summary, schedule_ruleset_name, new_schedule_rule, new_day_schedule, schedule, schedules_peak_period_weekdays_only) shifted_schedule = true else new_schedule_rule.remove end end old_default_day_schedule = schedule_ruleset.defaultDaySchedule new_default_schedule_rule = OpenStudio::Model::ScheduleRule.new(schedule_ruleset) new_default_schedule_rule.setName("#{old_default_day_schedule.name} Shifted") new_default_schedule_rule.setApplySunday(false) new_default_schedule_rule.setApplySunday(true) if !schedules_peak_period_weekdays_only new_default_schedule_rule.setApplyMonday(true) new_default_schedule_rule.setApplyTuesday(true) new_default_schedule_rule.setApplyWednesday(true) new_default_schedule_rule.setApplyThursday(true) new_default_schedule_rule.setApplyFriday(true) new_default_schedule_rule.setApplySaturday(false) new_default_schedule_rule.setApplySaturday(true) if !schedules_peak_period_weekdays_only schedule_ruleset.setScheduleRuleIndex(new_default_schedule_rule, 0) new_default_day_schedule = new_default_schedule_rule.daySchedule new_default_day_schedule.setName("#{old_default_day_schedule.name} Shifted") schedule = get_hourly_values(old_default_day_schedule) shifted_day_schedule = Schedules.day_peak_shift(schedule, 0, begin_hour, end_hour, schedules_peak_period_delay, schedules_peak_period_allow_stacking, 24) if shifted_day_schedule shift_day_schedule(calendar_year, shift_summary, schedule_ruleset_name, new_default_schedule_rule, new_default_day_schedule, schedule, schedules_peak_period_weekdays_only) shifted_schedule = true else new_default_schedule_rule.remove end next unless shifted_schedule && schedules_peak_period_allow_stacking new_schedule_type_limits = OpenStudio::Model::ScheduleTypeLimits.new(model) new_schedule_type_limits.setName("#{schedule_ruleset_name} Stacked Limits") new_schedule_type_limits.setLowerLimitValue(0) new_schedule_type_limits.setUpperLimitValue(1) new_schedule_type_limits.setNumericType('Continuous') schedule_ruleset.setScheduleTypeLimits(new_schedule_type_limits) schedule_ruleset.scheduleTypeLimits.get.setUpperLimitValue(2.0) # ScheduleTypeRegistry prevents us from setting ScheduleTypeLimits with invalid limits end shift_summary.each do |schedule_ruleset_name, shifted_days| runner.registerInfo("Out of #{total_days_in_year} total days, #{shifted_days} weekday(s) were shifted for the '#{schedule_ruleset_name}' Schedule:Ruleset.") runner.registerValue("shifted_days_#{schedule_ruleset_name}", shifted_days) end # Schedule:File model.getExternalFiles.each do |external_file| external_file_path = external_file.filePath.to_s schedules = Schedules.new(file_path: external_file_path) schedules.shift_schedules(model, runner, schedule_file_column_names_enabled, begin_hour, end_hour, schedules_peak_period_delay, schedules_peak_period_allow_stacking, total_days_in_year, sim_start_day, steps_in_day, schedules_peak_period_weekdays_only) schedules.export end return true end |
#shift_day_schedule(calendar_year, shift_summary, schedule_ruleset_name, schedule_rule, day_schedule, schedule, schedules_peak_period_weekdays_only) ⇒ Object
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 258 def shift_day_schedule(calendar_year, shift_summary, schedule_ruleset_name, schedule_rule, day_schedule, schedule, schedules_peak_period_weekdays_only) start_date = schedule_rule.startDate.get start_date_month = start_date.monthOfYear.value start_date_day = start_date.dayOfMonth end_date = schedule_rule.endDate.get end_date_month = end_date.monthOfYear.value end_date_day = end_date.dayOfMonth start_date = DateTime.new(calendar_year, start_date_month, start_date_day) end_date = DateTime.new(calendar_year, end_date_month, end_date_day) n_days = (end_date - start_date).to_i + 1 shifted_days = 0 n_days.times do |day| today = start_date + day day_of_week = today.wday shifted_days += 1 if day_of_week == 0 && schedule_rule.applySunday && !schedules_peak_period_weekdays_only shifted_days += 1 if day_of_week == 1 && schedule_rule.applyMonday shifted_days += 1 if day_of_week == 2 && schedule_rule.applyTuesday shifted_days += 1 if day_of_week == 3 && schedule_rule.applyWednesday shifted_days += 1 if day_of_week == 4 && schedule_rule.applyThursday shifted_days += 1 if day_of_week == 5 && schedule_rule.applyFriday shifted_days += 1 if day_of_week == 6 && schedule_rule.applySaturday && !schedules_peak_period_weekdays_only end shift_summary[schedule_ruleset_name] += shifted_days for h in 0..23 time = OpenStudio::Time.new(0, h + 1, 0, 0) day_schedule.addValue(time, schedule[h]) end end |
#taxonomy ⇒ Object
used to populate taxonomy in readme.md
32 33 34 |
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 32 def taxonomy return 'Whole Building.Whole Building Schedules' end |