Class: ReduceExteriorLightingLoads
- Inherits:
-
OpenStudio::Measure::ModelMeasure
- Object
- OpenStudio::Measure::ModelMeasure
- ReduceExteriorLightingLoads
- Defined in:
- lib/measures/reduce_exterior_lighting_loads/measure.rb
Overview
start the measure
Instance Method Summary collapse
- #add_event_to_sch(model, runner, sch, on_frac_in_defined_period, start_time, end_time) ⇒ Object
-
#arguments(model) ⇒ Object
define the arguments that the user will input.
-
#description ⇒ Object
human readable description.
-
#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.
- #updateDaySchedule(sch_day, vec_time, vec_value, time_begin, time_end, new_value) ⇒ Object
Instance Method Details
#add_event_to_sch(model, runner, sch, on_frac_in_defined_period, start_time, end_time) ⇒ Object
253 254 255 256 257 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 288 |
# File 'lib/measures/reduce_exterior_lighting_loads/measure.rb', line 253 def add_event_to_sch(model, runner, sch, on_frac_in_defined_period, start_time, end_time) new_sch = sch.get.clone(model) new_sch = new_sch.to_Schedule.get new_sch.setName("#{sch.get.name.to_s} add user defined event") # make cooling schedule adjustments and rename. Put in check to skip and warn if schedule not ruleset if !new_sch.to_ScheduleRuleset.empty? schedule = new_sch.to_ScheduleRuleset.get default_rule = schedule.defaultDaySchedule rules = schedule.scheduleRules # update default day schedule default_day_time_vector = default_rule.times default_day_value_vector = default_rule.values default_rule.clearValues updateDaySchedule(default_rule, default_day_time_vector, default_day_value_vector, start_time, end_time, on_frac_in_defined_period) # update all schedule rules if rules.length > 0 rules.each do |rule| day_sch = rule.daySchedule day_time_vector = day_sch.times day_value_vector = day_sch.values day_sch.clearValues updateDaySchedule(day_sch, day_time_vector, day_value_vector, start_time, end_time, on_frac_in_defined_period) end else runner.registerWarning("Exterior light schedule '#{sch.get.name.to_s}' is a ScheduleRuleSet, but has no ScheduleRules associated. It won't be altered by this measure.") end else runner.registerWarning("Schedule '#{sch.get.name.to_s}' isn't a ScheduleRuleset object and won't be altered by this measure.") new_sch.remove # remove un-used clone end return new_sch end |
#arguments(model) ⇒ Object
define the arguments that the user will input
32 33 34 35 36 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 75 76 77 |
# File 'lib/measures/reduce_exterior_lighting_loads/measure.rb', line 32 def arguments(model) args = OpenStudio::Measure::OSArgumentVector.new # design level value reduction percentage specified by user, default is 0 design_val_reduce_percent = OpenStudio::Measure::OSArgument.makeDoubleArgument('design_val_reduce_percent', false) design_val_reduce_percent.setDisplayName('Percentage Reduction of Exterior Lighting Design Power (%)') design_val_reduce_percent.setDescription('Enter a value between 0 and 100') args << design_val_reduce_percent # Use daylight control, i.e., AstronomicalClock as control option. # This makes sure that the exterior lights are turned off during the day use_daylight_control = OpenStudio::Measure::OSArgument.makeBoolArgument('use_daylight_control', true) use_daylight_control.setDisplayName('Use daylight control') use_daylight_control.setDescription('If exterior lights will be turned off during the day') use_daylight_control.setDefaultValue(false) args << use_daylight_control # Use occupancy sensing. This will turn off exterior lights when unoccupied, and dim with partial occupancy use_occupancy_sensing = OpenStudio::Measure::OSArgument.makeBoolArgument('use_occupancy_sensing', true) use_occupancy_sensing.setDisplayName('Use occupancy sensing') use_occupancy_sensing.setDescription('If enabled, this will turn off exterior lights when unoccupied, and dim with partial occupancy') use_occupancy_sensing.setDefaultValue(false) args << use_occupancy_sensing # schedule on fraction during user designated period on_frac_in_defined_period = OpenStudio::Measure::OSArgument.makeDoubleArgument('on_frac_in_defined_period', false) on_frac_in_defined_period.setDisplayName('Schedule value representing light on fraction to turn off (0) or dim (<1) during user designated event period') on_frac_in_defined_period.setDescription('Enter a value >=0 and <1') args << on_frac_in_defined_period # user designated period start time user_defined_start_time = OpenStudio::Measure::OSArgument.makeStringArgument('user_defined_start_time', false) user_defined_start_time.setDisplayName('User Designated Event Start Time for the off/dimming') user_defined_start_time.setDescription('In HH:MM:SS format') user_defined_start_time.setDefaultValue('01:00:00') args << user_defined_start_time # user designated period end time user_defined_end_time = OpenStudio::Measure::OSArgument.makeStringArgument('user_defined_end_time', false) user_defined_end_time.setDisplayName('User Designated Event End Time for the off/dimming') user_defined_end_time.setDescription('In HH:MM:SS format') user_defined_end_time.setDefaultValue('04:00:00') args << user_defined_end_time return args end |
#description ⇒ Object
human readable description
18 19 20 21 22 |
# File 'lib/measures/reduce_exterior_lighting_loads/measure.rb', line 18 def description return 'This measure reduces exterior lighting loads by two ways: (1) upgrading the lighting fixtures '\ 'to be more efficient, which reduces the design level value, (2) reducing operational duration'\ 'and/or strength by adjusting control option and schedule based on daylight, occupancy, and/or user designated period.' end |
#modeler_description ⇒ Object
human readable description of modeling approach
25 26 27 28 29 |
# File 'lib/measures/reduce_exterior_lighting_loads/measure.rb', line 25 def modeler_description return 'This measure can (1) reduce design level by percentage if given by the user, (2) update the control option '\ 'to AstronomicalClock, (3) adjust the schedule by replacing with occupancy schedule of '\ 'the majority space/spacetype, and/or turn off or dim during user designated period.' end |
#name ⇒ Object
human readable name
12 13 14 15 |
# File 'lib/measures/reduce_exterior_lighting_loads/measure.rb', line 12 def name # Measure name should be the title case of the class name. return 'Reduce Exterior Lighting Loads' end |
#run(model, runner, user_arguments) ⇒ Object
define what happens when the measure is run
80 81 82 83 84 85 86 87 88 89 90 91 92 93 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 257 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 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 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 376 377 378 379 380 381 |
# File 'lib/measures/reduce_exterior_lighting_loads/measure.rb', line 80 def run(model, runner, user_arguments) super(model, runner, user_arguments) # if no exterior lights in the building, measure not applicable if model.getExteriorLightss.size == 0 runner.registerAsNotApplicable("No exterior lights in the building, measure not applicable.") return true end # use the built-in error checking if !runner.validateUserArguments(arguments(model), user_arguments) return false end # assign the user inputs to variables design_val_reduce_percent = runner.getOptionalDoubleArgumentValue('design_val_reduce_percent', user_arguments) use_daylight_control = runner.getBoolArgumentValue('use_daylight_control', user_arguments) use_occupancy_sensing = runner.getBoolArgumentValue('use_occupancy_sensing', user_arguments) on_frac_in_defined_period = runner.getOptionalDoubleArgumentValue('on_frac_in_defined_period', user_arguments) user_defined_start_time = runner.getOptionalStringArgumentValue('user_defined_start_time', user_arguments) user_defined_end_time = runner.getOptionalStringArgumentValue('user_defined_end_time', user_arguments) # ****** validate parameters ******* # validate design_val_reduce_percent if design_val_reduce_percent.empty? design_val_reduce_percent = 0 elsif design_val_reduce_percent.to_f <= 0 || design_val_reduce_percent.to_f > 100 runner.registerError("Invalid Percentage Reduction of Exterior Lighting Design Power (%) #{design_val_reduce_percent} entered. Value must be >0 and <=100.") return false else design_val_reduce_percent = design_val_reduce_percent.to_f end # validate on_frac_in_defined_period if on_frac_in_defined_period.empty? has_user_defined_event = false elsif on_frac_in_defined_period.to_f < 0 || on_frac_in_defined_period.to_f >= 1 runner.registerError("Invalid schedule fraction value #{on_frac_in_defined_period} entered. Value must be >=0 and <1.") return false else on_frac_in_defined_period = on_frac_in_defined_period.to_f has_user_defined_event = true end # if has user defined event, validate the start and end time, otherwise skip if has_user_defined_event if user_defined_start_time.empty? runner.registerError('User defined event lacks start time, please provide input.') return false end if user_defined_end_time.empty? runner.registerError('User defined event lacks end time, please provide input.') return false end if /(\d\d):(\d\d):(\d\d)/.match(user_defined_start_time.to_s) os_start_time = OpenStudio::Time.new(user_defined_start_time.to_s) else runner.registerError('Start time must be in HH-MM-SS format.') return false end if /(\d\d):(\d\d):(\d\d)/.match(user_defined_end_time.to_s) os_end_time = OpenStudio::Time.new(user_defined_end_time.to_s) else runner.registerError('End time must be in HH-MM-SS format.') return false end if os_start_time == os_end_time runner.registerError('Start and end time can not be the same.') return false end end # report initial condition of model runner.registerInitialCondition("There are #{model.getExteriorLightss.size} exterior lights objects in the building.") # reduce design level by percentage if design_val_reduce_percent > 0 model.getExteriorLightsDefinitions.each do |ext_light_def| origin_design_level = ext_light_def.designLevel ext_light_def.setDesignLevel(origin_design_level * (100-design_val_reduce_percent)/100.0) end runner.registerInfo("Exterior light load is reduced by #{design_val_reduce_percent}%.") end # update control option to AstronomicalClock if true if use_daylight_control model.getExteriorLightss.each do |ext_light| ext_light.setControlOption('AstronomicalClock') end runner.registerInfo("Exterior light is using daylight control.") end # occupancy sensing major_occ_sch = nil #initial if use_occupancy_sensing # get the occupancy schedule of the majority space/spacetype # first try building level schedule set if (not model.building.empty?) && (not model.building.get.defaultScheduleSet.empty?) occ_sch = model.building.get.defaultScheduleSet.get.numberofPeopleSchedule unless occ_sch.empty? major_occ_sch = occ_sch.get end else # then try spacetype spc_type_max_area = 0 # initial major_spc_stype = nil # initial model.getSpaceTypes.each do |spc_type| if spc_type_max_area == 0 spc_type_max_area = spc_type.floorArea major_spc_stype = spc_type elsif spc_type_max_area < spc_type.floorArea spc_type_max_area = spc_type.floorArea major_spc_stype = spc_type end end major_spc_type_default_sch_set = major_spc_stype.defaultScheduleSet if not major_spc_type_default_sch_set.empty? occ_sch = major_spc_type_default_sch_set.get.numberofPeopleSchedule unless occ_sch.empty? major_occ_sch = occ_sch.get end end # if no major occupancy schedule found from space type, then try space if major_occ_sch.nil? spc_max_area = 0 #initial major_spc = nil #initial model.getSpaces.each do |spc| if spc_max_area == 0 spc_max_area = spc.floorArea major_spc = spc elsif spc_max_area < spc.floorArea spc_max_area = spc.floorArea major_spc = spc end end major_spc_default_sch_set = major_spc.defaultScheduleSet if not major_spc_default_sch_set.empty? occ_sch = major_spc_default_sch_set.get.numberofPeopleSchedule unless occ_sch.empty? major_occ_sch = occ_sch.get end else if major_spc.people.size > 0 occ_sch = major_spc.people[0].numberofPeopleSchedule unless occ_sch.empty? major_occ_sch = occ_sch.get else runner.registerWarning("No schedule defined for the people object of the major space #{major_spc.name.to_s}.") end else runner.registerWarning("No people object found for the major space #{major_spc.name.to_s}.") end end end end # check if a major_occ_sch is found if major_occ_sch.nil? runner.registerError("Occupancy sensing control is enabled, but no major occupancy schedule can be found.") return false else model.getExteriorLightss.each do |ext_light| ext_light.setSchedule(major_occ_sch) end runner.registerInfo("Exterior light is using occupancy sensing control.") end end def add_event_to_sch(model, runner, sch, on_frac_in_defined_period, start_time, end_time) new_sch = sch.get.clone(model) new_sch = new_sch.to_Schedule.get new_sch.setName("#{sch.get.name.to_s} add user defined event") # make cooling schedule adjustments and rename. Put in check to skip and warn if schedule not ruleset if !new_sch.to_ScheduleRuleset.empty? schedule = new_sch.to_ScheduleRuleset.get default_rule = schedule.defaultDaySchedule rules = schedule.scheduleRules # update default day schedule default_day_time_vector = default_rule.times default_day_value_vector = default_rule.values default_rule.clearValues updateDaySchedule(default_rule, default_day_time_vector, default_day_value_vector, start_time, end_time, on_frac_in_defined_period) # update all schedule rules if rules.length > 0 rules.each do |rule| day_sch = rule.daySchedule day_time_vector = day_sch.times day_value_vector = day_sch.values day_sch.clearValues updateDaySchedule(day_sch, day_time_vector, day_value_vector, start_time, end_time, on_frac_in_defined_period) end else runner.registerWarning("Exterior light schedule '#{sch.get.name.to_s}' is a ScheduleRuleSet, but has no ScheduleRules associated. It won't be altered by this measure.") end else runner.registerWarning("Schedule '#{sch.get.name.to_s}' isn't a ScheduleRuleset object and won't be altered by this measure.") new_sch.remove # remove un-used clone end return new_sch end def updateDaySchedule(sch_day, vec_time, vec_value, time_begin, time_end, new_value) count = 0 if time_end > time_begin vec_time.each_with_index do |, i| if > time_begin && < time_end && count == 0 sch_day.addValue(time_begin, vec_value[i]) sch_day.addValue(, new_value) count = 1 elsif == time_end && count == 0 sch_day.addValue(time_begin, vec_value[i]) sch_day.addValue(, new_value) count = 2 elsif == time_begin && count == 0 sch_day.addValue(, vec_value[i]) count = 1 elsif > time_end && count == 0 sch_day.addValue(time_begin, vec_value[i]) sch_day.addValue(time_end, new_value) sch_day.addValue(, vec_value[i]) count = 2 elsif > time_begin && < time_end && count==1 sch_day.addValue(, new_value) elsif == time_end && count==1 sch_day.addValue(, new_value) count = 2 elsif > time_end && count == 1 sch_day.addValue(time_end, new_value) sch_day.addValue(, vec_value[i]) count = 2 else sch_day.addValue(, vec_value[i]) end end else # time_end < time_begin, event goes overnight vec_time.each_with_index do |, i| if < time_end sch_day.addValue(, new_value) elsif == time_end && count == 0 sch_day.addValue(, new_value) count = 1 # 1 represents time_end has been filled elsif > time_end && < time_begin && count == 0 sch_day.addValue(time_end, new_value) sch_day.addValue(, vec_value[i]) count = 1 elsif > time_end && < time_begin && count == 1 sch_day.addValue(, vec_value[i]) elsif == time_begin && count == 0 sch_day.addValue(time_end, new_value) sch_day.addValue(, vec_value[i]) count = 2 elsif == time_begin && count == 1 sch_day.addValue(, vec_value[i]) count = 2 # 2 represents time_begin has been filled elsif > time_begin && count == 0 sch_day.addValue(time_end, new_value) sch_day.addValue(time_begin, vec_value[i]) sch_day.addValue(, new_value) count = 2 elsif > time_begin && count == 1 sch_day.addValue(time_begin, vec_value[i]) sch_day.addValue(, new_value) count = 2 elsif > time_begin && count == 2 sch_day.addValue(, new_value) end end end return sch_day end # user defined schedule update # refer to add ceiling fan change thermostat setpoint if has_user_defined_event model.getExteriorLightss.each do |ext_light| if ext_light.schedule.empty? runner.registerError("Has user defined event, but lack existing schedule for exterior light #{ext_light.name.to_s}.") return false else new_sch = add_event_to_sch(model, runner, ext_light.schedule, on_frac_in_defined_period, os_start_time, os_end_time) ext_light.setSchedule(new_sch) end end runner.registerInfo("Exterior light schedule is modified by adding user defined event.") end # report final condition of model runner.registerFinalCondition("The exterior lighting load is reduced.") return true end |
#updateDaySchedule(sch_day, vec_time, vec_value, time_begin, time_end, new_value) ⇒ Object
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 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 |
# File 'lib/measures/reduce_exterior_lighting_loads/measure.rb', line 290 def updateDaySchedule(sch_day, vec_time, vec_value, time_begin, time_end, new_value) count = 0 if time_end > time_begin vec_time.each_with_index do |, i| if > time_begin && < time_end && count == 0 sch_day.addValue(time_begin, vec_value[i]) sch_day.addValue(, new_value) count = 1 elsif == time_end && count == 0 sch_day.addValue(time_begin, vec_value[i]) sch_day.addValue(, new_value) count = 2 elsif == time_begin && count == 0 sch_day.addValue(, vec_value[i]) count = 1 elsif > time_end && count == 0 sch_day.addValue(time_begin, vec_value[i]) sch_day.addValue(time_end, new_value) sch_day.addValue(, vec_value[i]) count = 2 elsif > time_begin && < time_end && count==1 sch_day.addValue(, new_value) elsif == time_end && count==1 sch_day.addValue(, new_value) count = 2 elsif > time_end && count == 1 sch_day.addValue(time_end, new_value) sch_day.addValue(, vec_value[i]) count = 2 else sch_day.addValue(, vec_value[i]) end end else # time_end < time_begin, event goes overnight vec_time.each_with_index do |, i| if < time_end sch_day.addValue(, new_value) elsif == time_end && count == 0 sch_day.addValue(, new_value) count = 1 # 1 represents time_end has been filled elsif > time_end && < time_begin && count == 0 sch_day.addValue(time_end, new_value) sch_day.addValue(, vec_value[i]) count = 1 elsif > time_end && < time_begin && count == 1 sch_day.addValue(, vec_value[i]) elsif == time_begin && count == 0 sch_day.addValue(time_end, new_value) sch_day.addValue(, vec_value[i]) count = 2 elsif == time_begin && count == 1 sch_day.addValue(, vec_value[i]) count = 2 # 2 represents time_begin has been filled elsif > time_begin && count == 0 sch_day.addValue(time_end, new_value) sch_day.addValue(time_begin, vec_value[i]) sch_day.addValue(, new_value) count = 2 elsif > time_begin && count == 1 sch_day.addValue(time_begin, vec_value[i]) sch_day.addValue(, new_value) count = 2 elsif > time_begin && count == 2 sch_day.addValue(, new_value) end end end return sch_day end |