Class: Schedules

Inherits:
Object
  • Object
show all
Defined in:
lib/measures/PeakPeriodSchedulesShift/measure.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file_path:) ⇒ Schedules

Returns a new instance of Schedules.



309
310
311
312
313
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 309

def initialize(file_path:)
  @file_path = file_path

  import
end

Class Method Details

.day_peak_shift(schedule, day, begin_hour, end_hour, delay, allow_stacking, steps_in_day) ⇒ Object



377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 377

def self.day_peak_shift(schedule, day, begin_hour, end_hour, delay, allow_stacking, steps_in_day)
  steps_in_hour = steps_in_day / 24
  period = (end_hour - begin_hour) * steps_in_hour # n steps

  # peak period
  peak_begin_ix = day * steps_in_day + (begin_hour * steps_in_hour)
  peak_end_ix = peak_begin_ix + period

  # new period
  new_begin_ix = peak_end_ix + (delay * steps_in_hour)
  new_end_ix = new_begin_ix + period

  shifted = false
  if !allow_stacking && schedule[new_begin_ix...new_end_ix].any? { |x| x > 0 }
    return shifted # prevent stacking
  end

  shifted = true if schedule[peak_begin_ix...peak_end_ix].any? { |x| x > 0 } # schedule was actually moved
  schedule[new_begin_ix...new_end_ix] = [schedule[new_begin_ix...new_end_ix], schedule[peak_begin_ix...peak_end_ix]].transpose.map(&:sum)
  schedule[peak_begin_ix...peak_end_ix] = [0] * period

  return shifted
end

.NumDaysInMonths(year) ⇒ Object



433
434
435
436
437
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 433

def self.NumDaysInMonths(year)
  num_days_in_months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
  num_days_in_months[1] += 1 if Date.leap?(year)
  return num_days_in_months
end

.NumDaysInYear(year) ⇒ Object



427
428
429
430
431
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 427

def self.NumDaysInYear(year)
  num_days_in_months = NumDaysInMonths(year)
  num_days_in_year = num_days_in_months.sum
  return num_days_in_year
end

.parse_time_range(time_range) ⇒ Object



415
416
417
418
419
420
421
422
423
424
425
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 415

def self.parse_time_range(time_range)
  begin_end_times = time_range.split('-').map(&:strip)
  if begin_end_times.size != 2
    raise "Invalid time format specified for '#{time_range}'."
  end

  begin_hour = begin_end_times[0].strip.to_i
  end_hour = begin_end_times[1].strip.to_i

  return begin_hour, end_hour
end

Instance Method Details

#exportObject



401
402
403
404
405
406
407
408
409
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 401

def export
  CSV.open(@file_path, 'wb') do |csv|
    csv << @schedules.keys
    rows = @schedules.values.transpose
    rows.each do |row|
      csv << row
    end
  end
end

#importObject



315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 315

def import
  @schedules = {}
  columns = CSV.read(@file_path).transpose
  columns.each do |col|
    col_name = col[0]

    values = col[1..].reject(&:nil?)

    begin
      values = values.map { |v| Float(v) }
    rescue ArgumentError
      raise "Schedule value must be numeric for column '#{col_name}'. [context: #{schedules_path}]"
    end

    @schedules[col_name] = values
  end
end

#schedulesObject



411
412
413
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 411

def schedules
  return @schedules
end

#shift_schedules(model, runner, schedule_file_column_names_enabled, begin_hour, end_hour, delay, allow_stacking, total_days_in_year, sim_start_day, steps_in_day, schedules_peak_period_weekdays_only) ⇒ Object



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/measures/PeakPeriodSchedulesShift/measure.rb', line 333

def shift_schedules(model, runner, schedule_file_column_names_enabled, begin_hour, end_hour, delay, allow_stacking, total_days_in_year, sim_start_day, steps_in_day, schedules_peak_period_weekdays_only)
  shift_summary = {}
  schedule_file_column_names_enabled.each do |schedule_file_column_name, peak_period_shift_enabled|
    schedule_file = model.getScheduleFiles.find { |schedule_file| schedule_file.name.to_s == schedule_file_column_name }

    next if schedule_file.nil?
    next if !@schedules.key?(schedule_file_column_name)
    next if !peak_period_shift_enabled

    schedule = @schedules[schedule_file_column_name]
    shift_summary[schedule_file_column_name] = 0
    next if schedule.nil?

    shifted_schedule = false
    total_days_in_year.times do |day|
      today = sim_start_day + day
      day_of_week = today.wday
      next if [0, 6].include?(day_of_week) && schedules_peak_period_weekdays_only

      shifted_day_schedule = Schedules.day_peak_shift(schedule, day, begin_hour, end_hour, delay, allow_stacking, steps_in_day)
      if shifted_day_schedule
        shift_summary[schedule_file_column_name] += 1
        shifted_schedule = true
      end
    end

    next unless shifted_schedule && allow_stacking

    new_schedule_type_limits = OpenStudio::Model::ScheduleTypeLimits.new(model)
    new_schedule_type_limits.setName("#{schedule_file_column_name} Stacked Limits")
    new_schedule_type_limits.setLowerLimitValue(0)
    new_schedule_type_limits.setUpperLimitValue(1)
    new_schedule_type_limits.setNumericType('Continuous')

    schedule_file.setScheduleTypeLimits(new_schedule_type_limits)
    schedule_file.scheduleTypeLimits.get.setUpperLimitValue(2.0) # ScheduleTypeRegistry prevents us from setting ScheduleTypeLimits with invalid limits
  end

  shift_summary.each do |schedule_file_column_name, shifted_days|
    runner.registerInfo("Out of #{total_days_in_year} total days, #{shifted_days} weekday(s) were shifted for the '#{schedule_file_column_name}' Schedule:File.")
    runner.registerValue("shifted_days_#{schedule_file_column_name}", shifted_days)
  end
end