# ********************************************************************* # * Copyright (c) 2008-2015, Natural Resources Canada # * All rights reserved. # * # * This library is free software; you can redistribute it and/or # * modify it under the terms of the GNU Lesser General Public # * License as published by the Free Software Foundation; either # * version 2.1 of the License, or (at your option) any later version. # * # * This library is distributed in the hope that it will be useful, # * but WITHOUT ANY WARRANTY; without even the implied warranty of # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # * Lesser General Public License for more details. # * # * You should have received a copy of the GNU Lesser General Public # * License along with this library; if not, write to the Free Software # * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # **********************************************************************/ require "#{File.dirname(__FILE__)}/btap" module OsLib_Schedules #This method creates a simple schedule and returns a ruleset schedule with a basic profile. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param options [String] #@return [OpenStudio::Model::ScheduleRuleset] the schedule ruleset def OsLib_Schedules.createSimpleSchedule(model, options = {}) defaults = { "name" => nil, "winterTimeValuePairs" => {24.0 => 0.0}, "summerTimeValuePairs" => {24.0 => 1.0}, "defaultTimeValuePairs" => {24.0 => 1.0}, } # merge user inputs with defaults options = defaults.merge(options) #ScheduleRuleset sch_ruleset = OpenStudio::Model::ScheduleRuleset.new(model) if name sch_ruleset.setName(options["name"]) end #Winter Design Day winter_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setWinterDesignDaySchedule(winter_dsn_day) winter_dsn_day = sch_ruleset.winterDesignDaySchedule winter_dsn_day.setName("#{sch_ruleset.name} Winter Design Day") options["winterTimeValuePairs"].each do |k,v| hour = k.truncate min = ((k - hour)*60).to_i winter_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0),v) end #Summer Design Day summer_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setSummerDesignDaySchedule(summer_dsn_day) summer_dsn_day = sch_ruleset.summerDesignDaySchedule summer_dsn_day.setName("#{sch_ruleset.name} Summer Design Day") options["summerTimeValuePairs"].each do |k,v| hour = k.truncate min = ((k - hour)*60).to_i summer_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0),v) end #All Days default_day = sch_ruleset.defaultDaySchedule default_day.setName("#{sch_ruleset.name} Schedule Week Day") options["defaultTimeValuePairs"].each do |k,v| hour = k.truncate min = ((k - hour)*60).to_i default_day.addValue(OpenStudio::Time.new(0, hour, min, 0),v) end result = sch_ruleset return result end #end of OsLib_Schedules.createSimpleSchedule #This method finds the maximum profile value for a schedule and returns a min and max value. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param schedule [Object] #@return [Hash] a hash of min an max values "min":5.0, "max":3.0 def OsLib_Schedules.getMinMaxAnnualProfileValue(model, schedule) # gather profiles profiles = [] defaultProfile = schedule.to_ScheduleRuleset.get.defaultDaySchedule profiles << defaultProfile rules = schedule.scheduleRules rules.each do |rule| profiles << rule.daySchedule end # test profiles min = nil max = nil profiles.each do |profile| profile.values.each do |value| if min.nil? min = value else if min > value then min = value end end if max.nil? max = value else if max < value then max = value end end end end result = {"min" => min, "max" => max} # this doesn't include summer and winter design day return result end #end of OsLib_Schedules.getMaxAnnualProfileValue #This method finds the maximum profile value for a schedule and returns the schedule. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param schedule [Object] #@param double [Float] #@param modificationType [String] #@return [Object] a schedule def OsLib_Schedules.simpleScheduleValueAdjust(model,schedule,double, modificationType = "Multiplier")# can increase/decrease by percentage or static value # todo - add in design days, maybe as optional argument # give option to clone or not # gather profiles profiles = [] defaultProfile = schedule.to_ScheduleRuleset.get.defaultDaySchedule profiles << defaultProfile rules = schedule.scheduleRules rules.each do |rule| profiles << rule.daySchedule end # alter profiles profiles.each do |profile| times = profile.times i = 0 profile.values.each do |value| if modificationType == "Multiplier" or modificationType == "Percentage" # percentage was used early on but Multiplier is preferable profile.addValue(times[i],value*double) end if modificationType == "Sum" or modificationType == "Value" # value was used early on but Sum is preferable profile.addValue(times[i],value+double) end i += 1 end end result = schedule return result end #end of OsLib_Schedules.getMaxAnnualProfileValue #This method finds the maximum profile value for a schedule and returns a schedule . #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param schedule [Object] #@param valueTestDouble [Float] #@param passDouble [Float] #@param failDouble [Float] #@param floorDouble [Float] #@param modificationType [String] #@return [Object] a schedule def OsLib_Schedules.conditionalScheduleValueAdjust(model,schedule,valueTestDouble,passDouble,failDouble, floorDouble,modificationType = "Multiplier")# can increase/decrease by percentage or static value # todo - add in design days, maybe as optional argument # give option to clone or not # gather profiles profiles = [] defaultProfile = schedule.to_ScheduleRuleset.get.defaultDaySchedule profiles << defaultProfile rules = schedule.scheduleRules rules.each do |rule| profiles << rule.daySchedule end # alter profiles profiles.each do |profile| times = profile.times i = 0 profile.values.each do |value| # run test on this value if value < valueTestDouble double = passDouble else double = failDouble end # skip if value is floor or less next if value <= floorDouble if modificationType == "Multiplier" profile.addValue(times[i],[value*double,floorDouble].max) #take the max of the floor or resulting value end if modificationType == "Sum" profile.addValue(times[i],[value+double,floorDouble].max) #take the max of the floor or resulting value end i += 1 end end result = schedule return result end #end of OsLib_Schedules.getMaxAnnualProfileValue #This method merges multiple schedules into one using load or other value to weight each schedules influence on the merge and returns a Merge schedule or denominator. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param scheduleWeighHash [String] #@return [Hash] a hash of the mergedSchedule [Object] and denominator [Object] "mergedSchedule":sch_ruleset, "denominator":denominator def OsLib_Schedules.weightedMergeScheduleRulesets(model, scheduleWeighHash) # WARNING NOT READY FOR GENERAL USE YET - this doesn't do anything with rules yet, just winter, summer, and default profile # get denominator for weight denominator = 0 scheduleWeighHash.each do |schedule,weight| denominator += weight end # create new schedule sch_ruleset = OpenStudio::Model::ScheduleRuleset.new(model) sch_ruleset.setName("Merged Schedule") # todo - make this optional user argument # create winter design day profile winter_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setWinterDesignDaySchedule(winter_dsn_day) winter_dsn_day = sch_ruleset.winterDesignDaySchedule winter_dsn_day.setName("#{sch_ruleset.name} Winter Design Day") # create summer design day profile summer_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setSummerDesignDaySchedule(summer_dsn_day) summer_dsn_day = sch_ruleset.summerDesignDaySchedule summer_dsn_day.setName("#{sch_ruleset.name} Summer Design Day") # create default profile default_day = sch_ruleset.defaultDaySchedule default_day.setName("#{sch_ruleset.name} Schedule Week Day") # hash of schedule rules rulesHash = {} # mon, tue, wed, thur, fri, sat, sun, startDate, endDate # to avoid stacking order issues across schedules, I may need to make a rule for each day of the week for each date range scheduleWeighHash.each do |schedule,weight| # populate winter design day profile oldWinterProfile = schedule.to_ScheduleRuleset.get.winterDesignDaySchedule times_final = summer_dsn_day.times i = 0 valueUpdatedArray = [] # loop through times already in profile and update values until i > times_final.size - 1 value = oldWinterProfile.getValue(times_final[i])*weight/denominator starting_value = winter_dsn_day.getValue(times_final[i]) winter_dsn_day.addValue(times_final[i],value + starting_value) valueUpdatedArray << times_final[i] i += 1 end # loop through any new times unique to the current old profile to be merged j = 0 times = oldWinterProfile.times values = oldWinterProfile.values until j > times.size - 1 if not valueUpdatedArray.include? times[j] value = values[j]*weight/denominator starting_value = winter_dsn_day.getValue(times[j]) winter_dsn_day.addValue(times[j],value+starting_value) end j += 1 end # populate summer design day profile oldSummerProfile = schedule.to_ScheduleRuleset.get.summerDesignDaySchedule times_final = summer_dsn_day.times i = 0 valueUpdatedArray = [] # loop through times already in profile and update values until i > times_final.size - 1 value = oldSummerProfile.getValue(times_final[i])*weight/denominator starting_value = summer_dsn_day.getValue(times_final[i]) summer_dsn_day.addValue(times_final[i],value + starting_value) valueUpdatedArray << times_final[i] i += 1 end # loop through any new times unique to the current old profile to be merged j = 0 times = oldSummerProfile.times values = oldSummerProfile.values until j > times.size - 1 if not valueUpdatedArray.include? times[j] value = values[j]*weight/denominator starting_value = summer_dsn_day.getValue(times[j]) summer_dsn_day.addValue(times[j],value+starting_value) end j += 1 end # populate default profile oldDefaultProfile = schedule.to_ScheduleRuleset.get.defaultDaySchedule times_final = default_day.times i = 0 valueUpdatedArray = [] # loop through times already in profile and update values until i > times_final.size - 1 value = oldDefaultProfile.getValue(times_final[i])*weight/denominator starting_value = default_day.getValue(times_final[i]) default_day.addValue(times_final[i],value + starting_value) valueUpdatedArray << times_final[i] i += 1 end # loop through any new times unique to the current old profile to be merged j = 0 times = oldDefaultProfile.times values = oldDefaultProfile.values until j > times.size - 1 if not valueUpdatedArray.include? times[j] value = values[j]*weight/denominator starting_value = default_day.getValue(times[j]) default_day.addValue(times[j],value+starting_value) end j += 1 end # create rules # gather data for rule profiles # populate rule profiles end result = {"mergedSchedule" => sch_ruleset, "denominator" => denominator} return result end #end of OsLib_Schedules.weightedMergeScheduleRulesets #This method will create a new schedule using absolute velocity of existing schedule and returns a new schedule. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param schedule [Object] #@return [Object] NewSchedule def OsLib_Schedules.scheduleFromRateOfChange(model, schedule) # clone source schedule newSchedule = schedule.clone(model) newSchedule.setName("#{schedule.name} - Rate of Change") newSchedule = newSchedule.to_ScheduleRuleset.get # create array of all profiles to change. This includes summer, winter, default, and rules profiles = [] profiles << newSchedule.winterDesignDaySchedule profiles << newSchedule.summerDesignDaySchedule profiles << newSchedule.defaultDaySchedule # time values may need endProfileTime = OpenStudio::Time.new(0, 24, 0, 0) hourBumpTime = OpenStudio::Time.new(0, 1, 0, 0) oneHourLeftTime = OpenStudio::Time.new(0, 23, 0, 0) rules = newSchedule.scheduleRules rules.each do |rule| profiles << rule.daySchedule end profiles.uniq.each do |profile| times = profile.times values = profile.values i = 0 valuesIntermediate = [] timesIntermediate = [] until i == (values.size) if i == 0 valuesIntermediate << 0.0 if times[i] > hourBumpTime timesIntermediate << times[i] - hourBumpTime if times[i+1].nil? timeStepValue = endProfileTime.hours + endProfileTime.minutes/60 - times[i].hours - times[i].minutes/60 else timeStepValue = times[i+1].hours + times[i+1].minutes/60 - times[i].hours - times[i].minutes/60 end valuesIntermediate << (values[i+1].to_f - values[i].to_f ).abs/(timeStepValue*2) end timesIntermediate << times[i] elsif i == (values.size - 1) if times[times.size - 2] < oneHourLeftTime timesIntermediate << times[times.size - 2] + hourBumpTime# this should be the second to last time timeStepValue = times[i-1].hours + times[i-1].minutes/60 - times[i-2].hours - times[i-2].minutes/60 valuesIntermediate << (values[i-1].to_f - values[i-2].to_f ).abs/(timeStepValue*2) end valuesIntermediate << 0.0 timesIntermediate << times[i] # this should be the last time else # get value multiplier based on how many hours it is spread over timeStepValue = times[i].hours + times[i].minutes/60 - times[i-1].hours - times[i-1].minutes/60 valuesIntermediate << (values[i].to_f - values[i - 1].to_f ).abs/timeStepValue timesIntermediate << times[i] end i += 1 end # delete all profile values profile.clearValues i = 0 until i == (timesIntermediate.size) if i == (timesIntermediate.size - 1) profile.addValue(timesIntermediate[i],valuesIntermediate[i].to_f) else profile.addValue(timesIntermediate[i],valuesIntermediate[i].to_f) end i += 1 end end # fix velocity so it isn't fraction change per step, but per hour (I need to count hours between times and divide value by this) result = newSchedule return result end #end of OsLib_Schedules.createSimpleSchedule # create a complex ruleset schedule #This method will take 4 variables and return them as an array. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param options [Object] #@return [Object] schedule ruleset def OsLib_Schedules.createComplexSchedule(model, options = {}) defaults = { "name" => nil, "default_day" => ["always_on",[24.0,1.0]] } # merge user inputs with defaults options = defaults.merge(options) #ScheduleRuleset sch_ruleset = OpenStudio::Model::ScheduleRuleset.new(model) if name sch_ruleset.setName(options["name"]) end #Winter Design Day unless options["winter_design_day"].nil? winter_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setWinterDesignDaySchedule(winter_dsn_day) winter_dsn_day = sch_ruleset.winterDesignDaySchedule winter_dsn_day.setName("#{sch_ruleset.name} Winter Design Day") options["winter_design_day"].each do |data_pair| hour = data_pair[0].truncate min = ((data_pair[0] - hour)*60).to_i winter_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0),data_pair[1]) end end #Summer Design Day unless options["summer_design_day"].nil? summer_dsn_day = OpenStudio::Model::ScheduleDay.new(model) sch_ruleset.setSummerDesignDaySchedule(summer_dsn_day) summer_dsn_day = sch_ruleset.summerDesignDaySchedule summer_dsn_day.setName("#{sch_ruleset.name} Summer Design Day") options["summer_design_day"].each do |data_pair| hour = data_pair[0].truncate min = ((data_pair[0] - hour)*60).to_i summer_dsn_day.addValue(OpenStudio::Time.new(0, hour, min, 0),data_pair[1]) end end #Default Day default_day = sch_ruleset.defaultDaySchedule default_day.setName("#{sch_ruleset.name} #{options["default_day"][0]}") default_data_array = options["default_day"] default_data_array.delete_at(0) default_data_array.each do |data_pair| hour = data_pair[0].truncate min = ((data_pair[0] - hour)*60).to_i default_day.addValue(OpenStudio::Time.new(0, hour, min, 0),data_pair[1]) end #Rules unless options["rules"].nil? options["rules"].each do |data_array| rule = OpenStudio::Model::ScheduleRule.new(sch_ruleset) rule.setName("#{sch_ruleset.name} #{data_array[0]} Rule") date_range = data_array[1].split("-") start_date = date_range[0].split("/") end_date = date_range[1].split("/") rule.setStartDate(model.getYearDescription.makeDate(start_date[0].to_i,start_date[1].to_i)) rule.setEndDate(model.getYearDescription.makeDate(end_date[0].to_i,end_date[1].to_i)) days = data_array[2].split("/") rule.setApplySunday(true) if days.include? "Sun" rule.setApplyMonday(true) if days.include? "Mon" rule.setApplyTuesday(true) if days.include? "Tue" rule.setApplyWednesday(true) if days.include? "Wed" rule.setApplyThursday(true) if days.include? "Thu" rule.setApplyFriday(true) if days.include? "Fri" rule.setApplySaturday(true) if days.include? "Sat" day_schedule = rule.daySchedule day_schedule.setName("#{sch_ruleset.name} #{data_array[0]}") data_array.delete_at(0) data_array.delete_at(0) data_array.delete_at(0) data_array.each do |data_pair| hour = data_pair[0].truncate min = ((data_pair[0] - hour)*60).to_i day_schedule.addValue(OpenStudio::Time.new(0, hour, min, 0),data_pair[1]) end end end result = sch_ruleset return result end #end of OsLib_Schedules.createComplexSchedule #This method will add schedule type limits and return limit types. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@return [type_limits<Float>] def OsLib_Schedules.addScheduleTypeLimits(model) # todo - make sure to add this new method to cofee when done type_limits = {} lightsScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) lightsScheduleTypeLimits.setName("Lights Schedule Type Limits") lightsScheduleTypeLimits.setLowerLimitValue(0.0) lightsScheduleTypeLimits.setUpperLimitValue(1.0) lightsScheduleTypeLimits.setNumericType("Continuous") lightsScheduleTypeLimits.setUnitType("Dimensionless") type_limits["Lights"] = lightsScheduleTypeLimits occupancyScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) occupancyScheduleTypeLimits.setName("Occupancy Schedule Type Limits") occupancyScheduleTypeLimits.setLowerLimitValue(0.0) occupancyScheduleTypeLimits.setUpperLimitValue(1.0) occupancyScheduleTypeLimits.setNumericType("Continuous") occupancyScheduleTypeLimits.setUnitType("Dimensionless") type_limits["Occupancy"] = occupancyScheduleTypeLimits peopleActivityScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) peopleActivityScheduleTypeLimits.setName("People Activity Type Limits") peopleActivityScheduleTypeLimits.setLowerLimitValue(0.0) #peopleActivityScheduleTypeLimits.setUpperLimitValue(1500.0) peopleActivityScheduleTypeLimits.setNumericType("Continuous") peopleActivityScheduleTypeLimits.setUnitType("ActivityLevel") type_limits["People Activity"] = peopleActivityScheduleTypeLimits equipmentScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) equipmentScheduleTypeLimits.setName("Equipment Schedule Type Limits") equipmentScheduleTypeLimits.setLowerLimitValue(0.0) equipmentScheduleTypeLimits.setUpperLimitValue(1.0) equipmentScheduleTypeLimits.setNumericType("Continuous") equipmentScheduleTypeLimits.setUnitType("Dimensionless") type_limits["Equipment"] = equipmentScheduleTypeLimits waterUseScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) waterUseScheduleTypeLimits.setName("Water Use Schedule Type Limits") waterUseScheduleTypeLimits.setLowerLimitValue(0.0) waterUseScheduleTypeLimits.setUpperLimitValue(1.0) waterUseScheduleTypeLimits.setNumericType("Continuous") waterUseScheduleTypeLimits.setUnitType("Dimensionless") type_limits["Water Use"] = waterUseScheduleTypeLimits elevatorsScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) elevatorsScheduleTypeLimits.setName("Elevators Schedule Type Limits") elevatorsScheduleTypeLimits.setLowerLimitValue(0.0) elevatorsScheduleTypeLimits.setUpperLimitValue(1.0) elevatorsScheduleTypeLimits.setNumericType("Continuous") elevatorsScheduleTypeLimits.setUnitType("Dimensionless") type_limits["Elevators"] = elevatorsScheduleTypeLimits processLoadsScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) processLoadsScheduleTypeLimits.setName("Process Loads Schedule Type Limits") processLoadsScheduleTypeLimits.setLowerLimitValue(0.0) processLoadsScheduleTypeLimits.setUpperLimitValue(1.0) processLoadsScheduleTypeLimits.setNumericType("Continuous") processLoadsScheduleTypeLimits.setUnitType("Dimensionless") type_limits["Process Load"] = elevatorsScheduleTypeLimits thermostatHeatingScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) thermostatHeatingScheduleTypeLimits.setName("Thermostat Heating Setpoint Schedule Type Limits") thermostatHeatingScheduleTypeLimits.setLowerLimitValue(0.0) thermostatHeatingScheduleTypeLimits.setUpperLimitValue(100.0) thermostatHeatingScheduleTypeLimits.setNumericType("Continuous") thermostatHeatingScheduleTypeLimits.setUnitType("Temperature") type_limits["Thermostat Heating Setpoint"] = thermostatHeatingScheduleTypeLimits temperatureScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) temperatureScheduleTypeLimits.setName("Thermostat Cooling Setpoint Schedule Type Limits") temperatureScheduleTypeLimits.setLowerLimitValue(0.0) temperatureScheduleTypeLimits.setUpperLimitValue(100.0) temperatureScheduleTypeLimits.setNumericType("Continuous") temperatureScheduleTypeLimits.setUnitType("Temperature") type_limits["Thermostat Cooling Setpoint"] = temperatureScheduleTypeLimits hvacOperationScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) hvacOperationScheduleTypeLimits.setName("HVAC Operation Schedule Type Limits") hvacOperationScheduleTypeLimits.setLowerLimitValue(0) hvacOperationScheduleTypeLimits.setUpperLimitValue(1) hvacOperationScheduleTypeLimits.setNumericType("Discrete") hvacOperationScheduleTypeLimits.setUnitType("Availability") type_limits["HVAC Operation"] = hvacOperationScheduleTypeLimits temperatureScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) temperatureScheduleTypeLimits.setName("Temperature Schedule Type Limits") temperatureScheduleTypeLimits.setNumericType("Continuous") temperatureScheduleTypeLimits.setUnitType("Temperature") type_limits["Temperature"] = temperatureScheduleTypeLimits fractionScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) fractionScheduleTypeLimits.setName("Fraction Schedule Type Limits") fractionScheduleTypeLimits.setLowerLimitValue(0.0) fractionScheduleTypeLimits.setUpperLimitValue(1.0) fractionScheduleTypeLimits.setNumericType("Continuous") fractionScheduleTypeLimits.setUnitType("Dimensionless") type_limits["Fraction"] = fractionScheduleTypeLimits dimensionlessScheduleTypeLimits = OpenStudio::Model::ScheduleTypeLimits.new(model) dimensionlessScheduleTypeLimits.setName("Dimensionless Schedule Type Limits") dimensionlessScheduleTypeLimits.setNumericType("Continuous") dimensionlessScheduleTypeLimits.setUnitType("Dimensionless") type_limits["Dimensionless"] = dimensionlessScheduleTypeLimits return type_limits end #This method creates TimeSeries from ScheduleRuleset. #@author phylroy.lopez@nrcan.gc.ca #@param model [OpenStudio::model::Model] A model object #@param schedule_ruleset [Object] def OsLib_Schedules.create_timeseries_from_schedule_ruleset(model,schedule_ruleset) yd = model.getYearDescription start_date = yd.makeDate(1,1) end_date = yd.makeDate(12,31) values = OpenStudio::DoubleVector.new day = OpenStudio::Time.new(1.0) interval = OpenStudio::Time.new(1.0/48.0) day_schedules = schedule_ruleset.to_ScheduleRuleset.get.getDaySchedules(start_date,end_date) day_schedules.each do |day_schedule| time = interval while time < day values << day_schedule.getValue(time) time += interval end end time_series = OpenStudio::TimeSeries.new(start_date, interval, OpenStudio::createVector(values), "") end # create ScheduleVariableInterval from TimeSeries def OsLib_Schedules.create_schedule_variable_interval_from_time_series(model,time_series) result = OpenStudio::Model::ScheduleInterval.fromTimeSeries(time_series, model).get end end