openstudio-geb 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/Gemfile +10 -9
- data/lib/measures/AddElectricVehicleChargingLoad/measure.rb +247 -21
- data/lib/measures/AddElectricVehicleChargingLoad/tests/CZ06RV2.epw +8768 -0
- data/lib/measures/AddElectricVehicleChargingLoad/tests/add_electric_vehicle_charging_load_test.rb +40 -141
- data/lib/measures/AddElectricVehicleChargingLoad/tests/test.osm +55 -55
- data/lib/measures/add_chilled_water_storage_tank/measure.rb +2 -2
- data/lib/measures/add_exterior_blinds_and_control/measure.rb +6 -5
- data/lib/measures/add_interior_blinds_and_control/measure.rb +5 -5
- data/lib/measures/add_rooftop_pv_simple/measure.rb +13 -10
- data/lib/measures/average_ventilation_for_peak_hours/measure.rb +5 -5
- data/lib/measures/enable_occupancy_driven_lighting/measure.rb +2 -2
- data/lib/openstudio/geb/run.rb +5 -1
- data/lib/openstudio/geb/utilities.rb +3 -2
- data/lib/openstudio/geb/version.rb +1 -1
- data/openstudio-geb.gemspec +8 -5
- metadata +34 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd69bb205fad6b56575647180a351d3d05b44047a41ec0024bddafe66b472326
|
4
|
+
data.tar.gz: 8fbaf6cb1142eb2cf96a9ae6e4044a64549cbc7bf7a129d7765bbe6a34c24d11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d92844bc66b7e82fe1225ed29c6d8f2b22a6f3e2708de8081a1ec972e9a21983498b7363c185d4e8ba9f5e3a3365390777ce7cb29f4bbb29307f4b4856d4f927
|
7
|
+
data.tar.gz: 35b575cee5706cd4bc54f33273c2268a7a093ddb487a0b947fdb976b909d5fa0ab92c74a3f092d05e917b949aaef9a411c4d9c1de8e98a0436de6699f49061c5
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -8,18 +8,19 @@ gemspec
|
|
8
8
|
# Windows: set FAVOR_LOCAL_GEMS=1
|
9
9
|
# Note that if allow_local is true, but the gem is not found locally, then it will
|
10
10
|
# checkout the latest version (develop) from github.
|
11
|
-
allow_local = ENV['FAVOR_LOCAL_GEMS']
|
11
|
+
# allow_local = ENV['FAVOR_LOCAL_GEMS']
|
12
|
+
#
|
13
|
+
# if allow_local && File.exists?('../OpenStudio-extension-gem')
|
14
|
+
# gem 'openstudio-extension', path: '../OpenStudio-extension-gem'
|
15
|
+
# else
|
16
|
+
# gem 'openstudio-extension', github: 'NREL/OpenStudio-extension-gem', tag: 'v0.8.1'
|
17
|
+
# end
|
12
18
|
|
13
|
-
|
14
|
-
|
15
|
-
else
|
16
|
-
gem 'openstudio-extension', github: 'NREL/OpenStudio-extension-gem', branch: 'develop'
|
17
|
-
end
|
18
|
-
|
19
|
-
gem 'openstudio_measure_tester', '= 0.3.1' # This includes the dependencies for running unit tests, coverage, and rubocop
|
19
|
+
# you shouldn't need this dependency directly...it is included in extension gem
|
20
|
+
# gem 'openstudio_measure_tester', '= 0.3.1' # This includes the dependencies for running unit tests, coverage, and rubocop
|
20
21
|
|
21
22
|
# simplecov has an unnecessary dependency on native json gem, use fork that does not require this
|
22
|
-
gem 'simplecov', '~> 0.
|
23
|
+
gem 'simplecov', '~> 0.22.0'
|
23
24
|
|
24
25
|
# pin this dependency to avoid unicode_normalize error
|
25
26
|
gem 'addressable', '2.8.1'
|
@@ -30,6 +30,7 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
30
30
|
bldg_use_type_chs = OpenStudio::StringVector.new
|
31
31
|
bldg_use_type_chs << 'home'
|
32
32
|
bldg_use_type_chs << 'workplace'
|
33
|
+
bldg_use_type_chs << 'commercial station'
|
33
34
|
|
34
35
|
bldg_use_type = OpenStudio::Measure::OSArgument.makeChoiceArgument('bldg_use_type', bldg_use_type_chs, true)
|
35
36
|
bldg_use_type.setDisplayName('Building Use Type')
|
@@ -53,6 +54,7 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
53
54
|
charger_level_chs << 'Level 1'
|
54
55
|
charger_level_chs << 'Level 2'
|
55
56
|
charger_level_chs << 'DC charger'
|
57
|
+
charger_level_chs << 'Supercharger'
|
56
58
|
|
57
59
|
charger_level = OpenStudio::Measure::OSArgument.makeChoiceArgument('charger_level', charger_level_chs, true)
|
58
60
|
charger_level.setDisplayName('EV Charger Level')
|
@@ -83,6 +85,24 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
83
85
|
avg_charge_hours.setDefaultValue(4)
|
84
86
|
args << avg_charge_hours
|
85
87
|
|
88
|
+
# variation of arrival time in minutes
|
89
|
+
arrival_time_variation_in_mins = OpenStudio::Measure::OSArgument.makeDoubleArgument('arrival_time_variation_in_mins', false)
|
90
|
+
arrival_time_variation_in_mins.setDescription('Actual arrival time can vary a certain period before and after the average arrival time. '\
|
91
|
+
'This parameter describes this absolute time delta. '\
|
92
|
+
'In other words, average arrival time plus/minus this parameter constitutes the arrival time range. ')
|
93
|
+
arrival_time_variation_in_mins.setDisplayName('Variation of arrival time in minutes')
|
94
|
+
arrival_time_variation_in_mins.setDefaultValue(30)
|
95
|
+
args << arrival_time_variation_in_mins
|
96
|
+
|
97
|
+
# variation of charge time in minutes
|
98
|
+
charge_time_variation_in_mins = OpenStudio::Measure::OSArgument.makeDoubleArgument('charge_time_variation_in_mins', false)
|
99
|
+
charge_time_variation_in_mins.setDescription('Actual charge time can vary a certain period around the average charge hours. '\
|
100
|
+
'This parameter describes this absolute time delta. '\
|
101
|
+
'In other words, average charge hours plus/minus this parameter constitutes the charge time range. ')
|
102
|
+
charge_time_variation_in_mins.setDisplayName('Variation of charge time in minutes')
|
103
|
+
charge_time_variation_in_mins.setDefaultValue(60)
|
104
|
+
args << charge_time_variation_in_mins
|
105
|
+
|
86
106
|
# if EVs are charged on Saturday
|
87
107
|
charge_on_sat = OpenStudio::Measure::OSArgument.makeBoolArgument('charge_on_sat', false)
|
88
108
|
charge_on_sat.setDisplayName('EVs are charged on Saturday')
|
@@ -106,7 +126,10 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
106
126
|
@charging_power = nil
|
107
127
|
@connected_ev = nil
|
108
128
|
@occupied_until_time = nil
|
129
|
+
#TODO for workplace need to use the list instead of single time too, same as commercial station
|
130
|
+
@occupied_until_time_list = Array.new # for commercial station use this
|
109
131
|
@occupied_start_time = nil
|
132
|
+
@occupied_start_time_list = Array.new # for commercial station use this
|
110
133
|
@charged_ev_list = Array.new
|
111
134
|
end
|
112
135
|
|
@@ -116,7 +139,9 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
116
139
|
attr_accessor :charging_power # Type: float, unit: kW
|
117
140
|
attr_accessor :connected_ev # Type: ElectricVehicle
|
118
141
|
attr_accessor :occupied_until_time # Type: Time. Daily end charging time
|
142
|
+
attr_accessor :occupied_until_time_list # Type: Array of Time. List of daily end charging time
|
119
143
|
attr_accessor :occupied_start_time # Type: Time. Daily start charging time
|
144
|
+
attr_accessor :occupied_start_time_list # Type: Array of Time. List of daily start charging time
|
120
145
|
attr_accessor :charged_ev_list # Type: Array
|
121
146
|
end
|
122
147
|
|
@@ -161,6 +186,8 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
161
186
|
avg_leave_time = runner.getStringArgumentValue('avg_leave_time', user_arguments)
|
162
187
|
start_charge_time = runner.getStringArgumentValue('start_charge_time', user_arguments)
|
163
188
|
avg_charge_hours = runner.getDoubleArgumentValue('avg_charge_hours', user_arguments)
|
189
|
+
arrival_time_variation_in_mins = runner.getDoubleArgumentValue('arrival_time_variation_in_mins', user_arguments)
|
190
|
+
charge_time_variation_in_mins = runner.getDoubleArgumentValue('charge_time_variation_in_mins', user_arguments)
|
164
191
|
charge_on_sat = runner.getBoolArgumentValue('charge_on_sat', user_arguments)
|
165
192
|
charge_on_sun = runner.getBoolArgumentValue('charge_on_sun', user_arguments)
|
166
193
|
|
@@ -192,6 +219,14 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
192
219
|
runner.registerError('For homes, start charging time is required, and should be in format of %H:%M, e.g., 16:00.')
|
193
220
|
return false
|
194
221
|
end
|
222
|
+
elsif bldg_use_type == 'commercial station'
|
223
|
+
# check avg_arrival_time should be in correct Time format
|
224
|
+
begin
|
225
|
+
avg_arrival_time = Time.strptime(avg_arrival_time, '%H:%M')
|
226
|
+
rescue ArgumentError
|
227
|
+
runner.registerError('For commercial station, average arrival time is required, and should be in format of %H:%M, e.g., 10:00.')
|
228
|
+
return false
|
229
|
+
end
|
195
230
|
else
|
196
231
|
runner.registerError("Wrong building use type, available options: 'workplace' and 'home'.")
|
197
232
|
return false
|
@@ -214,11 +249,15 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
214
249
|
when 'Level 1'
|
215
250
|
charger.charging_power = 1.5
|
216
251
|
when 'Level 2'
|
217
|
-
charger.charging_power = 7.0
|
252
|
+
# charger.charging_power = 7.0
|
253
|
+
charger.charging_power = 9.6 # C2C expert match input
|
218
254
|
when 'DC charger'
|
219
|
-
charger.charging_power = 50.0
|
255
|
+
# charger.charging_power = 50.0
|
256
|
+
charger.charging_power = 54.0 # C2C expert match input
|
257
|
+
when 'Supercharger'
|
258
|
+
charger.charging_power = 185
|
220
259
|
else
|
221
|
-
runner.registerError("Wrong EV charging level, available options: 'Level 1', 'Level 2', 'DC charger'.")
|
260
|
+
runner.registerError("Wrong EV charging level, available options: 'Level 1', 'Level 2', 'DC charger', 'Supercharger'.")
|
222
261
|
return false
|
223
262
|
end
|
224
263
|
max_charging_power += charger.charging_power
|
@@ -258,13 +297,13 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
258
297
|
if ev_load_new == ev_load
|
259
298
|
ev_load_new = ev_load + ev_charger.charging_power
|
260
299
|
else # if more than one chargers change status at this time point
|
261
|
-
|
300
|
+
ev_load_new += ev_charger.charging_power
|
262
301
|
end
|
263
302
|
elsif ((ev_charger.occupied_until_time - day_start_time)/60).to_i == min
|
264
303
|
if ev_load_new == ev_load
|
265
304
|
ev_load_new = ev_load - ev_charger.charging_power
|
266
305
|
else # if more than one chargers change status at this time point
|
267
|
-
|
306
|
+
ev_load_new -= ev_charger.charging_power
|
268
307
|
end
|
269
308
|
end
|
270
309
|
else # charging overnight
|
@@ -289,7 +328,7 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
289
328
|
puts "ev_load_new: #{ev_load_new}"
|
290
329
|
puts "ev_load: #{ev_load}"
|
291
330
|
time = OpenStudio::Time.new(0, 0, min) # OpenStudio::Time.new(day,hr of day, minute of hr, seconds of hr?)
|
292
|
-
ev_sch.defaultDaySchedule.addValue(time, ev_load/max_charging_power)
|
331
|
+
ev_sch.defaultDaySchedule.addValue(time, (ev_load/max_charging_power).round(2))
|
293
332
|
ev_load = ev_load_new
|
294
333
|
end
|
295
334
|
end
|
@@ -323,18 +362,94 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
323
362
|
return ev_sch
|
324
363
|
end
|
325
364
|
|
365
|
+
def create_ev_sch_single(model, ev_charger, charge_on_sat, charge_on_sun)
|
366
|
+
# create the schedule
|
367
|
+
# Creating a schedule:ruleset
|
368
|
+
ev_sch = OpenStudio::Model::ScheduleRuleset.new(model)
|
369
|
+
ev_sch.setName("EV Charging Power Draw for charger #{ev_charger.name.to_s}")
|
370
|
+
ev_sch.defaultDaySchedule.setName("EV Charging Default for charger #{ev_charger.name.to_s}")
|
371
|
+
day_start_time = Time.strptime("00:00", '%H:%M')
|
372
|
+
|
373
|
+
puts "ev_charger.occupied_start_time_list: #{ev_charger.occupied_start_time_list}"
|
374
|
+
puts "ev_charger.occupied_until_time_list: #{ev_charger.occupied_until_time_list}"
|
375
|
+
occupied_start_time_list = ev_charger.occupied_start_time_list
|
376
|
+
occupied_until_time_list = ev_charger.occupied_until_time_list
|
377
|
+
|
378
|
+
occupied_start_time_list.each_with_index do |occupied_start_time, idx|
|
379
|
+
occupied_until_time = occupied_until_time_list[idx]
|
380
|
+
if occupied_start_time.day == occupied_until_time.day
|
381
|
+
# charging on the same day
|
382
|
+
if idx > 0 && occupied_start_time == occupied_until_time_list[idx-1]
|
383
|
+
# car charging are continuous without vacancy period
|
384
|
+
end_time = OpenStudio::Time.new(0, 0, ((occupied_until_time - day_start_time)/60).to_i) # OpenStudio::Time.new(day,hr of day, minute of hr, seconds of hr?)
|
385
|
+
ev_sch.defaultDaySchedule.addValue(end_time, 1)
|
386
|
+
else
|
387
|
+
# there are vacancy period between cars
|
388
|
+
start_time = OpenStudio::Time.new(0, 0, ((occupied_start_time - day_start_time)/60).to_i) # OpenStudio::Time.new(day,hr of day, minute of hr, seconds of hr?)
|
389
|
+
ev_sch.defaultDaySchedule.addValue(start_time, 0)
|
390
|
+
end_time = OpenStudio::Time.new(0, 0, ((occupied_until_time - day_start_time)/60).to_i) # OpenStudio::Time.new(day,hr of day, minute of hr, seconds of hr?)
|
391
|
+
ev_sch.defaultDaySchedule.addValue(end_time, 1)
|
392
|
+
end
|
393
|
+
else # charging overnight
|
394
|
+
if idx > 0 && occupied_start_time == occupied_until_time_list[idx-1]
|
395
|
+
# car charging are continuous without vacancy period
|
396
|
+
end_time_1 = OpenStudio::Time.new(0, 24, 0, 0) # first till the end of the day
|
397
|
+
end_time_2 = OpenStudio::Time.new(0, 0, ((occupied_until_time - day_start_time)/60).to_i) # OpenStudio::Time.new(day,hr of day, minute of hr, seconds of hr?)
|
398
|
+
ev_sch.defaultDaySchedule.addValue(end_time_1, 1)
|
399
|
+
ev_sch.defaultDaySchedule.addValue(end_time_2, 1)
|
400
|
+
else
|
401
|
+
# there are vacancy period between cars
|
402
|
+
start_time = OpenStudio::Time.new(0, 0, ((occupied_start_time - day_start_time)/60).to_i) # OpenStudio::Time.new(day,hr of day, minute of hr, seconds of hr?)
|
403
|
+
ev_sch.defaultDaySchedule.addValue(start_time, 0)
|
404
|
+
end_time_1 = OpenStudio::Time.new(0, 24, 0, 0) # first till the end of the day
|
405
|
+
end_time_2 = OpenStudio::Time.new(0, 0, ((occupied_until_time - day_start_time)/60).to_i) # OpenStudio::Time.new(day,hr of day, minute of hr, seconds of hr?)
|
406
|
+
ev_sch.defaultDaySchedule.addValue(end_time_1, 1)
|
407
|
+
ev_sch.defaultDaySchedule.addValue(end_time_2, 1)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
if charge_on_sat
|
413
|
+
ev_sch_sat = OpenStudio::Model::ScheduleRule.new(ev_sch, ev_sch.defaultDaySchedule)
|
414
|
+
ev_sch_sat.setName('EV Charging Power Saturday')
|
415
|
+
ev_sch_sat.setApplySaturday(true)
|
416
|
+
else
|
417
|
+
ev_sch_sat_rule = OpenStudio::Model::ScheduleRule.new(ev_sch)
|
418
|
+
ev_sch_sat_rule.setName('EV Charging Power Saturday')
|
419
|
+
ev_sch_sat_rule.setApplySaturday(true)
|
420
|
+
ev_sch_sat = ev_sch_sat_rule.daySchedule
|
421
|
+
ev_sch_sat.setName('EV Charging Saturday')
|
422
|
+
ev_sch_sat.addValue(OpenStudio::Time.new(0,24,0), 0)
|
423
|
+
end
|
424
|
+
|
425
|
+
if charge_on_sun
|
426
|
+
ev_sch_sun = OpenStudio::Model::ScheduleRule.new(ev_sch, ev_sch.defaultDaySchedule)
|
427
|
+
ev_sch_sun.setName('EV Charging Power Sunday')
|
428
|
+
ev_sch_sun.setApplySunday(true)
|
429
|
+
else
|
430
|
+
ev_sch_sun_rule = OpenStudio::Model::ScheduleRule.new(ev_sch)
|
431
|
+
ev_sch_sun_rule.setName('EV Charging Power Sunday')
|
432
|
+
ev_sch_sun_rule.setApplySunday(true)
|
433
|
+
ev_sch_sun = ev_sch_sun_rule.daySchedule
|
434
|
+
ev_sch_sun.setName('EV Charging Sunday')
|
435
|
+
ev_sch_sun.addValue(OpenStudio::Time.new(0,24,0), 0)
|
436
|
+
end
|
437
|
+
|
438
|
+
return ev_sch
|
439
|
+
end
|
440
|
+
|
326
441
|
# *********************************************
|
327
442
|
# for workplace
|
328
443
|
# waitlist is only applicable to workplace. For homes, charging is scheduled with start_charge_time
|
329
444
|
# create all EV chargers
|
330
|
-
def create_ev_sch_for_workplace(model, ev_chargers, max_charging_power, num_evs, avg_arrival_time, avg_leave_time, avg_charge_hours, charge_on_sat, charge_on_sun)
|
445
|
+
def create_ev_sch_for_workplace(model, ev_chargers, max_charging_power, num_evs, avg_arrival_time, arrival_time_variation_in_mins, avg_leave_time, avg_charge_hours, charge_time_variation_in_mins, charge_on_sat, charge_on_sun)
|
331
446
|
ev_list = []
|
332
447
|
for j in 1..num_evs
|
333
448
|
ev = ElectricVehicle.new("ev_#{j.to_s}")
|
334
|
-
ev.arrival_time = avg_arrival_time + rand(-
|
449
|
+
ev.arrival_time = avg_arrival_time + rand(-arrival_time_variation_in_mins...arrival_time_variation_in_mins) * 60 # TODO make sure time format is working correctly, Ruby Times "+" adopts seconds
|
335
450
|
ev.leave_time = avg_leave_time + rand(-30...30) * 60 # TODO make sure time format is working correctly, Ruby Times "+" adopts seconds
|
336
451
|
ev.leave_time = Time.strptime("23:00", '%H:%M') + 3600 if ev.leave_time > Time.strptime("23:00", '%H:%M') + 3600 # fix leave time at 24:00 if later than 24:00
|
337
|
-
ev.needed_charge_hours = avg_charge_hours + rand(-
|
452
|
+
ev.needed_charge_hours = avg_charge_hours + rand(-charge_time_variation_in_mins...charge_time_variation_in_mins) / 60.0 # +- variation charge time
|
338
453
|
ev_list << ev
|
339
454
|
end
|
340
455
|
|
@@ -410,6 +525,96 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
410
525
|
return ev_sch
|
411
526
|
end
|
412
527
|
|
528
|
+
def create_ev_sch_for_commercial_charge_station(model, ev_chargers, max_charging_power, num_evs, avg_arrival_time, arrival_time_variation_in_mins, avg_charge_hours, charge_time_variation_in_mins, charge_on_sat, charge_on_sun)
|
529
|
+
ev_list = []
|
530
|
+
for j in 1..num_evs
|
531
|
+
ev = ElectricVehicle.new("ev_#{j.to_s}")
|
532
|
+
ev.arrival_time = avg_arrival_time + rand(-arrival_time_variation_in_mins...arrival_time_variation_in_mins) * 60 # TODO make sure time format is working correctly, Ruby Times "+" adopts seconds
|
533
|
+
ev.needed_charge_hours = avg_charge_hours + rand(-charge_time_variation_in_mins...charge_time_variation_in_mins) / 60.0 # +- variation minutes
|
534
|
+
ev_list << ev
|
535
|
+
end
|
536
|
+
|
537
|
+
# find the earliest arrival time
|
538
|
+
arrival_time_earliest = Time.strptime("23:00", '%H:%M') + 3600 # initial: 24:00
|
539
|
+
ev_list.each do |this_ev|
|
540
|
+
if this_ev.arrival_time < arrival_time_earliest
|
541
|
+
arrival_time_earliest = this_ev.arrival_time
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
# For workplace: iterate through time, check status of each charger, if vacant, find the EV that has the earliest arrival time within uncharged EVs.
|
546
|
+
# if this EV's leaving time is later than the current time, start charging until fully charged or leaving time, whichever comes first
|
547
|
+
# when no EV is found any more, charging on this day ends, conclude the charging profile
|
548
|
+
# 23 represent 23:00-24:00, corresponding to E+ schedule Until: 24:00
|
549
|
+
ev_sch_list = []
|
550
|
+
for hour in 0..23
|
551
|
+
current_time = Time.strptime("#{hour}:00", '%H:%M') + 3600 # %H: 00..23, 23 should represent the period 23:00-24:00, so add 1 hour to be the check point
|
552
|
+
next if arrival_time_earliest > current_time
|
553
|
+
ev_chargers.each do |ev_charger|
|
554
|
+
if ev_charger.occupied
|
555
|
+
if ev_charger.connected_ev.class.to_s != 'AddElectricVehicleChargingLoad::ElectricVehicle'
|
556
|
+
runner.registerError("EV charger #{ev_charger.name.to_s} shows occupied, but no EV is connected.")
|
557
|
+
return false
|
558
|
+
end
|
559
|
+
# disconnect EV if charged to full. Only check if expected end time is earlier than current time, otherwise check in next iteration.
|
560
|
+
# Time addition uses seconds, so needs to multiple 3600
|
561
|
+
if ev_charger.connected_ev.start_charge_time + ev_charger.connected_ev.needed_charge_hours * 3600 <= current_time
|
562
|
+
ev_charger.occupied_until_time_list << ev_charger.connected_ev.start_charge_time + ev_charger.connected_ev.needed_charge_hours * 3600
|
563
|
+
ev_charger.connected_ev.end_charge_time = ev_charger.connected_ev.start_charge_time + ev_charger.connected_ev.needed_charge_hours * 3600
|
564
|
+
ev_charger.occupied = false
|
565
|
+
ev_charger.connected_ev.has_been_charged = true
|
566
|
+
ev_charger.connected_ev.connected_to_charger = false
|
567
|
+
ev_charger.connected_ev = nil
|
568
|
+
end
|
569
|
+
end
|
570
|
+
# continue to check if charger not occupied, then connect to an EV
|
571
|
+
unless ev_charger.occupied
|
572
|
+
next_ev_to_charge = nil
|
573
|
+
wait_list_time_earliest = Time.strptime("23:00", '%H:%M') + 3600 # initial: 24:00
|
574
|
+
ev_list.each do |this_ev|
|
575
|
+
# skip this EV if it is being charged or is being charged or already left
|
576
|
+
next if this_ev.has_been_charged
|
577
|
+
next if this_ev.connected_to_charger
|
578
|
+
# get the uncharged, earliest arrival EV (so front in wait list)
|
579
|
+
if this_ev.arrival_time < wait_list_time_earliest
|
580
|
+
wait_list_time_earliest = this_ev.arrival_time
|
581
|
+
next_ev_to_charge = this_ev
|
582
|
+
end
|
583
|
+
end
|
584
|
+
# skip if no EV is on the wait list
|
585
|
+
next if next_ev_to_charge.nil?
|
586
|
+
if ev_charger.charged_ev_list.empty?
|
587
|
+
ev_charger.occupied_start_time_list << wait_list_time_earliest
|
588
|
+
next_ev_to_charge.start_charge_time = wait_list_time_earliest
|
589
|
+
else
|
590
|
+
if next_ev_to_charge.arrival_time < ev_charger.occupied_until_time_list[-1]
|
591
|
+
next_ev_to_charge.start_charge_time = ev_charger.occupied_until_time_list[-1]
|
592
|
+
ev_charger.occupied_start_time_list << ev_charger.occupied_until_time_list[-1]
|
593
|
+
else
|
594
|
+
next_ev_to_charge.start_charge_time = next_ev_to_charge.arrival_time
|
595
|
+
ev_charger.occupied_start_time_list << next_ev_to_charge.arrival_time
|
596
|
+
end
|
597
|
+
end
|
598
|
+
ev_charger.occupied = true
|
599
|
+
next_ev_to_charge.connected_to_charger = true
|
600
|
+
ev_charger.connected_ev = next_ev_to_charge
|
601
|
+
ev_charger.charged_ev_list << next_ev_to_charge
|
602
|
+
end
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
606
|
+
ev_chargers.each do |ev_charger|
|
607
|
+
# create schedule for each ev_charger
|
608
|
+
# charger.charging_power
|
609
|
+
ev_sch = create_ev_sch_single(model, ev_charger, charge_on_sat, charge_on_sun)
|
610
|
+
ev_sch_list << ev_sch
|
611
|
+
end
|
612
|
+
|
613
|
+
# ev_sch = create_ev_sch(model, ev_chargers, max_charging_power, charge_on_sat, charge_on_sun)
|
614
|
+
return ev_sch_list
|
615
|
+
end
|
616
|
+
|
617
|
+
|
413
618
|
def create_ev_sch_for_home(model, ev_chargers, max_charging_power, num_evs, start_charge_time, avg_charge_hours, charge_on_sat, charge_on_sun)
|
414
619
|
ev_list = []
|
415
620
|
for j in 1..num_evs
|
@@ -476,22 +681,43 @@ class AddElectricVehicleChargingLoad < OpenStudio::Measure::ModelMeasure
|
|
476
681
|
# create EV load schedule (normalized)
|
477
682
|
case bldg_use_type
|
478
683
|
when 'workplace'
|
479
|
-
ev_sch = create_ev_sch_for_workplace(model, ev_chargers, max_charging_power, num_evs, avg_arrival_time, avg_leave_time, avg_charge_hours, charge_on_sat, charge_on_sun)
|
684
|
+
ev_sch = create_ev_sch_for_workplace(model, ev_chargers, max_charging_power, num_evs, avg_arrival_time, arrival_time_variation_in_mins, avg_leave_time, avg_charge_hours, charge_time_variation_in_mins, charge_on_sat, charge_on_sun)
|
480
685
|
when 'home'
|
481
686
|
ev_sch = create_ev_sch_for_home(model, ev_chargers, max_charging_power, num_evs, start_charge_time, avg_charge_hours, charge_on_sat, charge_on_sun)
|
687
|
+
when 'commercial station'
|
688
|
+
ev_sch_list = create_ev_sch_for_commercial_charge_station(model, ev_chargers, max_charging_power, num_evs, avg_arrival_time, arrival_time_variation_in_mins, avg_charge_hours, charge_time_variation_in_mins, charge_on_sat, charge_on_sun)
|
689
|
+
end
|
690
|
+
|
691
|
+
case bldg_use_type
|
692
|
+
when 'workplace', 'home'
|
693
|
+
# Adding an EV charger definition and instance for the regular EV charging.
|
694
|
+
ev_charger_def = OpenStudio::Model::ExteriorFuelEquipmentDefinition.new(model)
|
695
|
+
ev_charger_level = (max_charging_power * 1000).round(0) # Converting from kW to watts
|
696
|
+
ev_charger_def.setName("#{ev_charger_level}w EV Charging Definition")
|
697
|
+
ev_charger_def.setDesignLevel(ev_charger_level)
|
698
|
+
|
699
|
+
# creating EV charger object for the regular EV charging.
|
700
|
+
ev_charger = OpenStudio::Model::ExteriorFuelEquipment.new(ev_charger_def, ev_sch)
|
701
|
+
ev_charger.setName("#{ev_charger_level}w EV Charger")
|
702
|
+
ev_charger.setFuelType('Electricity')
|
703
|
+
ev_charger.setEndUseSubcategory('Electric Vehicles')
|
704
|
+
when 'commercial station'
|
705
|
+
ev_chargers.each_with_index do |ev_charger, idx|
|
706
|
+
# Adding an EV charger definition and instance for the regular EV charging.
|
707
|
+
ev_charger_def = OpenStudio::Model::ExteriorFuelEquipmentDefinition.new(model)
|
708
|
+
ev_charger_level = (ev_charger.charging_power * 1000).round(0) # Converting from kW to watts
|
709
|
+
ev_charger_def.setName("#{ev_charger_level}w EV Charging Definition")
|
710
|
+
ev_charger_def.setDesignLevel(ev_charger_level)
|
711
|
+
|
712
|
+
# creating EV charger object for the regular EV charging.
|
713
|
+
ev_charger = OpenStudio::Model::ExteriorFuelEquipment.new(ev_charger_def, ev_sch_list[idx])
|
714
|
+
ev_charger.setName("#{ev_charger_level}w EV Charger")
|
715
|
+
ev_charger.setFuelType('Electricity')
|
716
|
+
ev_charger.setEndUseSubcategory('Electric Vehicles')
|
717
|
+
end
|
718
|
+
|
482
719
|
end
|
483
720
|
|
484
|
-
# Adding an EV charger definition and instance for the regular EV charging.
|
485
|
-
ev_charger_def = OpenStudio::Model::ExteriorFuelEquipmentDefinition.new(model)
|
486
|
-
ev_charger_level = max_charging_power * 1000 # Converting from kW to watts
|
487
|
-
ev_charger_def.setName("#{ev_charger_level} w EV Charging Definition")
|
488
|
-
ev_charger_def.setDesignLevel(ev_charger_level)
|
489
|
-
|
490
|
-
# creating EV charger object for the regular EV charging.
|
491
|
-
ev_charger = OpenStudio::Model::ExteriorFuelEquipment.new(ev_charger_def, ev_sch)
|
492
|
-
ev_charger.setName("#{ev_charger_level} w EV Charger")
|
493
|
-
ev_charger.setFuelType('Electricity')
|
494
|
-
ev_charger.setEndUseSubcategory('Electric Vehicles')
|
495
721
|
|
496
722
|
runner.registerInfo("multiplier (kW) = #{max_charging_power}}")
|
497
723
|
|