openstudio-geb 0.4.0 → 0.6.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/.gitignore +7 -3
- data/CHANGELOG.md +7 -0
- data/Gemfile +7 -17
- data/files/seasonal_shedding_peak_hours.json +1 -0
- data/files/seasonal_shifting_peak_hours.json +1 -0
- data/files/seasonal_shifting_take_hours.json +1 -0
- 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/AdjustThermostatSetpointsByDegreesForPeakHours/measure.rb +963 -442
- data/lib/measures/add_ceiling_fan/measure.rb +2 -2
- 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/apply_dynamic_coating_to_roof_wall/measure.rb +2 -2
- 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/measures/precooling/measure.rb +964 -354
- data/lib/measures/preheating/measure.rb +940 -356
- data/lib/measures/reduce_epd_by_percentage_for_peak_hours/measure.rb +509 -300
- data/lib/measures/reduce_lpd_by_percentage_for_peak_hours/measure.rb +534 -309
- 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 +7 -6
- metadata +24 -48
@@ -9,6 +9,7 @@
|
|
9
9
|
# http://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/
|
10
10
|
|
11
11
|
# start the measure
|
12
|
+
require 'json'
|
12
13
|
class ReduceEPDByPercentageForPeakHours < OpenStudio::Measure::ModelMeasure
|
13
14
|
# human readable name
|
14
15
|
def name
|
@@ -16,11 +17,11 @@ class ReduceEPDByPercentageForPeakHours < OpenStudio::Measure::ModelMeasure
|
|
16
17
|
end
|
17
18
|
# human readable description
|
18
19
|
def description
|
19
|
-
return "This measure reduces electric equipment loads by a user-specified percentage for a user-specified time period (usually the peak hours). The reduction can be applied to at most
|
20
|
+
return "This measure reduces electric equipment loads for office space types by a user-specified percentage for a user-specified time period (usually the peak hours). The reduction can be applied to at most five periods throughout out the year specified by the user."
|
20
21
|
end
|
21
22
|
# human readable description of modeling approach
|
22
23
|
def modeler_description
|
23
|
-
return "The original schedules for equipment in the building will be found and copied. The copies will be modified to have the percentage reduction during the specified hours, and be applied to the specified date periods through out the year. The rest of the year will keep using the original schedules."
|
24
|
+
return "The original schedules for equipment in the building will be found and copied. The copies will be modified to have the percentage reduction during the specified hours, and be applied to the specified date periods through out the year. The rest of the year will keep using the original schedules. Only schedules defined in scheduleRuleSet format and for office standardsSpaceType will be modified."
|
24
25
|
end
|
25
26
|
# define the arguments that the user will input
|
26
27
|
def arguments(model)
|
@@ -28,73 +29,134 @@ class ReduceEPDByPercentageForPeakHours < OpenStudio::Measure::ModelMeasure
|
|
28
29
|
epd_reduce_percent = OpenStudio::Measure::OSArgument.makeDoubleArgument('epd_reduce_percent', true)
|
29
30
|
epd_reduce_percent.setDisplayName('Percentage Reduction of Electric Equipment Power (%)')
|
30
31
|
epd_reduce_percent.setDescription('Enter a value between 0 and 100')
|
31
|
-
epd_reduce_percent.setDefaultValue(
|
32
|
+
epd_reduce_percent.setDefaultValue(20.0)
|
32
33
|
args << epd_reduce_percent
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
start_time.setDisplayName('Start Time for the Reduction')
|
37
|
-
start_time.setDescription('In HH:MM:SS format')
|
38
|
-
start_time.setDefaultValue('17:00:00')
|
39
|
-
args << start_time
|
40
|
-
|
41
|
-
# make an argument for the end time of the reduction
|
42
|
-
end_time = OpenStudio::Measure::OSArgument.makeStringArgument('end_time', false)
|
43
|
-
end_time.setDisplayName('End Time for the Reduction')
|
44
|
-
end_time.setDescription('In HH:MM:SS format')
|
45
|
-
end_time.setDefaultValue('21:00:00')
|
46
|
-
args << end_time
|
47
|
-
|
48
|
-
# Use alternative default start and end time for different climate zone
|
49
|
-
alt_periods = OpenStudio::Measure::OSArgument.makeBoolArgument('alt_periods', false)
|
50
|
-
alt_periods.setDisplayName('Use alternative default start and end time based on the climate zone of the model?')
|
51
|
-
alt_periods.setDescription('This will overwrite the star and end time you input')
|
52
|
-
alt_periods.setDefaultValue(false)
|
53
|
-
args << alt_periods
|
54
|
-
|
55
|
-
# make an argument for the start date of the reduction
|
56
|
-
start_date1 = OpenStudio::Ruleset::OSArgument.makeStringArgument('start_date1', false)
|
57
|
-
start_date1.setDisplayName('First start date for the Reduction')
|
35
|
+
start_date1 = OpenStudio::Ruleset::OSArgument.makeStringArgument('start_date1', true)
|
36
|
+
start_date1.setDisplayName('First start date for the reduction')
|
58
37
|
start_date1.setDescription('In MM-DD format')
|
59
|
-
start_date1.setDefaultValue('
|
38
|
+
start_date1.setDefaultValue('06-01')
|
60
39
|
args << start_date1
|
61
|
-
|
62
|
-
|
63
|
-
end_date1 = OpenStudio::Ruleset::OSArgument.makeStringArgument('end_date1', false)
|
64
|
-
end_date1.setDisplayName('First end date for the Reduction')
|
40
|
+
end_date1 = OpenStudio::Ruleset::OSArgument.makeStringArgument('end_date1', true)
|
41
|
+
end_date1.setDisplayName('First end date for the reduction')
|
65
42
|
end_date1.setDescription('In MM-DD format')
|
66
|
-
end_date1.setDefaultValue('
|
43
|
+
end_date1.setDefaultValue('09-30')
|
67
44
|
args << end_date1
|
68
45
|
|
69
|
-
|
70
|
-
# make an argument for the second start date of the reduction
|
71
46
|
start_date2 = OpenStudio::Ruleset::OSArgument.makeStringArgument('start_date2', false)
|
72
|
-
start_date2.setDisplayName('Second start date for the
|
73
|
-
start_date2.setDescription('Specify a date in MM-DD format if you want a second
|
47
|
+
start_date2.setDisplayName('Second start date for the reduction (optional)')
|
48
|
+
start_date2.setDescription('Specify a date in MM-DD format if you want a second season of reduction; leave blank if not needed.')
|
74
49
|
start_date2.setDefaultValue('')
|
75
50
|
args << start_date2
|
76
|
-
|
77
|
-
# make an argument for the second end date of the reduction
|
78
51
|
end_date2 = OpenStudio::Ruleset::OSArgument.makeStringArgument('end_date2', false)
|
79
|
-
end_date2.setDisplayName('Second end date for the
|
80
|
-
end_date2.setDescription('Specify a date in MM-DD format if you want a second
|
52
|
+
end_date2.setDisplayName('Second end date for the reduction')
|
53
|
+
end_date2.setDescription('Specify a date in MM-DD format if you want a second season of reduction; leave blank if not needed. If either the start or end date is blank, the period is considered not used.')
|
81
54
|
end_date2.setDefaultValue('')
|
82
55
|
args << end_date2
|
83
56
|
|
84
|
-
|
57
|
+
|
85
58
|
start_date3 = OpenStudio::Ruleset::OSArgument.makeStringArgument('start_date3', false)
|
86
|
-
start_date3.setDisplayName('Third start date for the
|
87
|
-
start_date3.setDescription('Specify a date in MM-DD format if you want a third
|
59
|
+
start_date3.setDisplayName('Third start date for the reduction (optional)')
|
60
|
+
start_date3.setDescription('Specify a date in MM-DD format if you want a third season of reduction; leave blank if not needed.')
|
88
61
|
start_date3.setDefaultValue('')
|
89
62
|
args << start_date3
|
90
|
-
|
91
|
-
# make an argument for the third end date of the reduction
|
92
63
|
end_date3 = OpenStudio::Ruleset::OSArgument.makeStringArgument('end_date3', false)
|
93
|
-
end_date3.setDisplayName('Third end date for the
|
94
|
-
end_date3.
|
64
|
+
end_date3.setDisplayName('Third end date for the reduction')
|
65
|
+
end_date3.setDisplayName('Third end date for the reduction')
|
66
|
+
end_date3.setDescription('Specify a date in MM-DD format if you want a third season of reduction; leave blank if not needed. If either the start or end date is blank, the period is considered not used.')
|
95
67
|
end_date3.setDefaultValue('')
|
96
68
|
args << end_date3
|
97
69
|
|
70
|
+
start_date4 = OpenStudio::Ruleset::OSArgument.makeStringArgument('start_date4', false)
|
71
|
+
start_date4.setDisplayName('Fourth start date for the reduction (optional)')
|
72
|
+
start_date4.setDescription('Specify a date in MM-DD format if you want a fourth season of reduction; leave blank if not needed.')
|
73
|
+
start_date4.setDefaultValue('')
|
74
|
+
args << start_date4
|
75
|
+
end_date4 = OpenStudio::Ruleset::OSArgument.makeStringArgument('end_date4', false)
|
76
|
+
end_date4.setDisplayName('Fourth end date for the reduction')
|
77
|
+
end_date4.setDescription('Specify a date in MM-DD format if you want a fourth season of reduction; leave blank if not needed. If either the start or end date is blank, the period is considered not used.')
|
78
|
+
end_date4.setDefaultValue('')
|
79
|
+
args << end_date4
|
80
|
+
|
81
|
+
|
82
|
+
start_date5 = OpenStudio::Ruleset::OSArgument.makeStringArgument('start_date5', false)
|
83
|
+
start_date5.setDisplayName('Fifth start date for the reduction (optional)')
|
84
|
+
start_date5.setDescription('Specify a date in MM-DD format if you want a fifth season of reduction; leave blank if not needed.')
|
85
|
+
start_date5.setDefaultValue('')
|
86
|
+
args << start_date5
|
87
|
+
end_date5 = OpenStudio::Ruleset::OSArgument.makeStringArgument('end_date5', false)
|
88
|
+
end_date5.setDisplayName('Fifth end date for the reduction')
|
89
|
+
end_date5.setDescription('Specify a date in MM-DD format if you want a fifth season of reduction; leave blank if not needed. If either the start or end date is blank, the period is considered not used.')
|
90
|
+
end_date5.setDefaultValue('')
|
91
|
+
args << end_date5
|
92
|
+
|
93
|
+
# make an argument for the start time of the reduction
|
94
|
+
start_time1 = OpenStudio::Measure::OSArgument.makeStringArgument('start_time1', true)
|
95
|
+
start_time1.setDisplayName('Start time of the reduction for the first season')
|
96
|
+
start_time1.setDescription('In HH:MM:SS format')
|
97
|
+
start_time1.setDefaultValue('17:00:00')
|
98
|
+
args << start_time1
|
99
|
+
end_time1 = OpenStudio::Measure::OSArgument.makeStringArgument('end_time1', true)
|
100
|
+
end_time1.setDisplayName('End time of the reduction for the first season')
|
101
|
+
end_time1.setDescription('In HH:MM:SS format')
|
102
|
+
end_time1.setDefaultValue('21:00:00')
|
103
|
+
args << end_time1
|
104
|
+
|
105
|
+
|
106
|
+
start_time2 = OpenStudio::Measure::OSArgument.makeStringArgument('start_time2', false)
|
107
|
+
start_time2.setDisplayName('Start time of the reduction for the second season (optional)')
|
108
|
+
start_time2.setDescription('In HH:MM:SS format')
|
109
|
+
start_time2.setDefaultValue('')
|
110
|
+
args << start_time2
|
111
|
+
end_time2 = OpenStudio::Measure::OSArgument.makeStringArgument('end_time2', false)
|
112
|
+
end_time2.setDisplayName('End time of the reduction for the second season (optional)')
|
113
|
+
end_time2.setDescription('In HH:MM:SS format')
|
114
|
+
end_time2.setDefaultValue('')
|
115
|
+
args << end_time2
|
116
|
+
|
117
|
+
|
118
|
+
start_time3 = OpenStudio::Measure::OSArgument.makeStringArgument('start_time3', false)
|
119
|
+
start_time3.setDisplayName('Start time of the reduction for the third season (optional)')
|
120
|
+
start_time3.setDescription('In HH:MM:SS format')
|
121
|
+
start_time3.setDefaultValue('')
|
122
|
+
args << start_time3
|
123
|
+
end_time3 = OpenStudio::Measure::OSArgument.makeStringArgument('end_time3', false)
|
124
|
+
end_time3.setDisplayName('End time of the reduction for the third season (optional)')
|
125
|
+
end_time3.setDescription('In HH:MM:SS format')
|
126
|
+
end_time3.setDefaultValue('')
|
127
|
+
args << end_time3
|
128
|
+
|
129
|
+
|
130
|
+
start_time4 = OpenStudio::Measure::OSArgument.makeStringArgument('start_time4', false)
|
131
|
+
start_time4.setDisplayName('Start time of the reduction for the fourth season (optional)')
|
132
|
+
start_time4.setDescription('In HH:MM:SS format')
|
133
|
+
start_time4.setDefaultValue('')
|
134
|
+
args << start_time4
|
135
|
+
end_time4 = OpenStudio::Measure::OSArgument.makeStringArgument('end_time4', false)
|
136
|
+
end_time4.setDisplayName('End time of the reduction for the fourth season (optional)')
|
137
|
+
end_time4.setDescription('In HH:MM:SS format')
|
138
|
+
end_time4.setDefaultValue('')
|
139
|
+
args << end_time4
|
140
|
+
|
141
|
+
|
142
|
+
start_time5 = OpenStudio::Measure::OSArgument.makeStringArgument('start_time5', false)
|
143
|
+
start_time5.setDisplayName('Start time of the reduction for the fifth season (optional)')
|
144
|
+
start_time5.setDescription('In HH:MM:SS format')
|
145
|
+
start_time5.setDefaultValue('')
|
146
|
+
args << start_time5
|
147
|
+
end_time5 = OpenStudio::Measure::OSArgument.makeStringArgument('end_time5', false)
|
148
|
+
end_time5.setDisplayName('End time of the reduction for the fifth season (optional)')
|
149
|
+
end_time5.setDescription('In HH:MM:SS format')
|
150
|
+
end_time5.setDefaultValue('')
|
151
|
+
args << end_time5
|
152
|
+
|
153
|
+
# Use alternative default start and end time for different climate zone
|
154
|
+
alt_periods = OpenStudio::Measure::OSArgument.makeBoolArgument('alt_periods', true)
|
155
|
+
alt_periods.setDisplayName('Use alternative default start and end time based on the state of the model from the Cambium load profile peak period?')
|
156
|
+
alt_periods.setDescription('This will overwrite the start and end time and date provided by the user')
|
157
|
+
alt_periods.setDefaultValue(false)
|
158
|
+
args << alt_periods
|
159
|
+
|
98
160
|
|
99
161
|
return args
|
100
162
|
end
|
@@ -108,14 +170,26 @@ class ReduceEPDByPercentageForPeakHours < OpenStudio::Measure::ModelMeasure
|
|
108
170
|
return false
|
109
171
|
end
|
110
172
|
epd_reduce_percent = runner.getDoubleArgumentValue('epd_reduce_percent', user_arguments)
|
111
|
-
|
112
|
-
|
173
|
+
start_time1 = runner.getStringArgumentValue('start_time1', user_arguments)
|
174
|
+
end_time1 = runner.getStringArgumentValue('end_time1', user_arguments)
|
175
|
+
start_time2 = runner.getStringArgumentValue('start_time2', user_arguments)
|
176
|
+
end_time2 = runner.getStringArgumentValue('end_time2', user_arguments)
|
177
|
+
start_time3 = runner.getStringArgumentValue('start_time3', user_arguments)
|
178
|
+
end_time3 = runner.getStringArgumentValue('end_time3', user_arguments)
|
179
|
+
start_time4 = runner.getStringArgumentValue('start_time4', user_arguments)
|
180
|
+
end_time4 = runner.getStringArgumentValue('end_time4', user_arguments)
|
181
|
+
start_time5 = runner.getStringArgumentValue('start_time5', user_arguments)
|
182
|
+
end_time5 = runner.getStringArgumentValue('end_time5', user_arguments)
|
113
183
|
start_date1 = runner.getStringArgumentValue('start_date1', user_arguments)
|
114
184
|
end_date1 = runner.getStringArgumentValue('end_date1', user_arguments)
|
115
185
|
start_date2 = runner.getStringArgumentValue('start_date2', user_arguments)
|
116
186
|
end_date2 = runner.getStringArgumentValue('end_date2', user_arguments)
|
117
187
|
start_date3 = runner.getStringArgumentValue('start_date3', user_arguments)
|
118
188
|
end_date3 = runner.getStringArgumentValue('end_date3', user_arguments)
|
189
|
+
start_date4 = runner.getStringArgumentValue('start_date4', user_arguments)
|
190
|
+
end_date4 = runner.getStringArgumentValue('end_date4', user_arguments)
|
191
|
+
start_date5 = runner.getStringArgumentValue('start_date5', user_arguments)
|
192
|
+
end_date5 = runner.getStringArgumentValue('end_date5', user_arguments)
|
119
193
|
alt_periods = runner.getBoolArgumentValue('alt_periods', user_arguments)
|
120
194
|
|
121
195
|
# validate the percentage
|
@@ -126,192 +200,161 @@ class ReduceEPDByPercentageForPeakHours < OpenStudio::Measure::ModelMeasure
|
|
126
200
|
runner.registerWarning('The percentage reduction of electric equipment power is negative. This will increase the electric equipment power.')
|
127
201
|
end
|
128
202
|
|
129
|
-
# set the default start and end time based on
|
203
|
+
# set the default start and end time based on state
|
130
204
|
if alt_periods
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
if climateZone.institution == 'ASHRAE'
|
136
|
-
ashraeClimateZone = climateZone.value
|
137
|
-
runner.registerInfo("Using ASHRAE Climate zone #{ashraeClimateZone}.")
|
138
|
-
end
|
205
|
+
state = model.getWeatherFile.stateProvinceRegion
|
206
|
+
if state == ''
|
207
|
+
runner.registerError('Unable to find state in model WeatherFile. The measure cannot be applied.')
|
208
|
+
return false
|
139
209
|
end
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
210
|
+
runner.registerInfo("Using weather file for #{state} state.")
|
211
|
+
file = File.open(File.join(File.dirname(__FILE__), "../../../files/seasonal_shedding_peak_hours.json"))
|
212
|
+
default_peak_periods = JSON.load(file)
|
213
|
+
file.close
|
214
|
+
unless default_peak_periods.key?state
|
215
|
+
runner.registerAsNotApplicable("No default inputs for the state of the WeatherFile #{state}")
|
216
|
+
return false
|
144
217
|
end
|
218
|
+
peak_periods = default_peak_periods[state]
|
219
|
+
start_time1 = peak_periods["winter_peak_start"].split[1]
|
220
|
+
end_time1 = peak_periods["winter_peak_end"].split[1]
|
221
|
+
start_time2 = peak_periods["intermediate_peak_start"].split[1]
|
222
|
+
end_time2 = peak_periods["intermediate_peak_end"].split[1]
|
223
|
+
start_time3 = peak_periods["summer_peak_start"].split[1]
|
224
|
+
end_time3 = peak_periods["summer_peak_end"].split[1]
|
225
|
+
start_time4 = peak_periods["intermediate_peak_start"].split[1]
|
226
|
+
end_time4 = peak_periods["intermediate_peak_end"].split[1]
|
227
|
+
start_time5 = peak_periods["winter_peak_start"].split[1]
|
228
|
+
end_time5 = peak_periods["winter_peak_end"].split[1]
|
229
|
+
start_date1 = '01-01'
|
230
|
+
end_date1 = '03-31'
|
231
|
+
start_date2 = '04-01'
|
232
|
+
end_date2 = '05-31'
|
233
|
+
start_date3 = '06-01'
|
234
|
+
end_date3 = '09-30'
|
235
|
+
start_date4 = '10-01'
|
236
|
+
end_date4 = '11-30'
|
237
|
+
start_date5 = '12-01'
|
238
|
+
end_date5 = '12-31'
|
239
|
+
end
|
145
240
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
end_time = '16:59:00'
|
159
|
-
when '2A'
|
160
|
-
start_time = '17:01:00'
|
161
|
-
end_time = '20:59:00'
|
162
|
-
when '2B'
|
163
|
-
start_time = '17:01:00'
|
164
|
-
end_time = '20:59:00'
|
165
|
-
when '3A'
|
166
|
-
start_time = '19:01:00'
|
167
|
-
end_time = '22:59:00'
|
168
|
-
when '3B'
|
169
|
-
start_time = '18:01:00'
|
170
|
-
end_time = '21:59:00'
|
171
|
-
when '3C'
|
172
|
-
start_time = '19:01:00'
|
173
|
-
end_time = '22:59:00'
|
174
|
-
when '4A'
|
175
|
-
start_time = '12:01:00'
|
176
|
-
end_time = '15:59:00'
|
177
|
-
when '4B'
|
178
|
-
start_time = '17:01:00'
|
179
|
-
end_time = '20:59:00'
|
180
|
-
when '4C'
|
181
|
-
start_time = '17:01:00'
|
182
|
-
end_time = '20:59:00'
|
183
|
-
when '5A'
|
184
|
-
start_time = '20:01:00'
|
185
|
-
end_time = '23:59:00'
|
186
|
-
when '5B'
|
187
|
-
start_time = '17:01:00'
|
188
|
-
end_time = '20:59:00'
|
189
|
-
when '5C'
|
190
|
-
start_time = '17:01:00'
|
191
|
-
end_time = '20:59:00'
|
192
|
-
when '6A'
|
193
|
-
start_time = '16:01:00'
|
194
|
-
end_time = '19:59:00'
|
195
|
-
when '6B'
|
196
|
-
start_time = '17:01:00'
|
197
|
-
end_time = '20:59:00'
|
198
|
-
when '7A'
|
199
|
-
start_time = '16:01:00'
|
200
|
-
end_time = '19:59:00'
|
241
|
+
def validate_time_format(star_time, end_time, runner)
|
242
|
+
time1 = /(\d\d):(\d\d):(\d\d)/.match(star_time)
|
243
|
+
time2 = /(\d\d):(\d\d):(\d\d)/.match(end_time)
|
244
|
+
if time1 and time2
|
245
|
+
os_starttime = OpenStudio::Time.new(star_time)
|
246
|
+
os_endtime = OpenStudio::Time.new(end_time)
|
247
|
+
if star_time >= end_time
|
248
|
+
runner.registerError("The start time needs to be earlier than the end time (currently #{star_time}-#{end_time}).")
|
249
|
+
return false
|
250
|
+
else
|
251
|
+
return os_starttime, os_endtime
|
252
|
+
end
|
201
253
|
else
|
202
|
-
runner.registerError('
|
254
|
+
runner.registerError('The provided time is not in HH-MM-SS format.')
|
203
255
|
return false
|
204
256
|
end
|
205
257
|
end
|
206
258
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
259
|
+
def validate_date_format(start_date1, end_date1, runner, model)
|
260
|
+
smd = /(\d\d)-(\d\d)/.match(start_date1)
|
261
|
+
emd = /(\d\d)-(\d\d)/.match(end_date1)
|
262
|
+
if smd.nil? or emd.nil?
|
263
|
+
runner.registerError('The provided date is not in MM-DD format.')
|
264
|
+
return false
|
265
|
+
else
|
266
|
+
start_month = smd[1].to_i
|
267
|
+
start_day = smd[2].to_i
|
268
|
+
end_month = emd[1].to_i
|
269
|
+
end_day = emd[2].to_i
|
270
|
+
if start_date1 > end_date1
|
271
|
+
runner.registerError('The start date cannot be later date the end time.')
|
272
|
+
return false
|
273
|
+
else
|
274
|
+
# os_start_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new(start_month), start_day)
|
275
|
+
# os_end_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new(end_month), end_day)
|
276
|
+
os_start_date = model.getYearDescription.makeDate(start_month, start_day)
|
277
|
+
os_end_date = model.getYearDescription.makeDate(end_month, end_day)
|
278
|
+
return os_start_date, os_end_date
|
279
|
+
end
|
280
|
+
end
|
212
281
|
end
|
213
282
|
|
214
|
-
|
215
|
-
|
283
|
+
# First time period
|
284
|
+
time_result1 = validate_time_format(start_time1, end_time1, runner)
|
285
|
+
if time_result1
|
286
|
+
shift_time_start1, shift_time_end1 = time_result1
|
216
287
|
else
|
217
|
-
runner.registerError('
|
288
|
+
runner.registerError('The required time period for the reduction is not in correct format!')
|
218
289
|
return false
|
219
290
|
end
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
291
|
+
# The other optional time periods
|
292
|
+
shift_time_start2,shift_time_end2,shift_time_start3,shift_time_end3,shift_time_start4,shift_time_end4,shift_time_start5,shift_time_end5 = [nil]*8
|
293
|
+
if (not start_time2.empty?) and (not end_time2.empty?)
|
294
|
+
time_result2 = validate_time_format(start_time2, end_time2, runner)
|
295
|
+
if time_result2
|
296
|
+
shift_time_start2, shift_time_end2 = time_result2
|
297
|
+
end
|
298
|
+
end
|
299
|
+
if (not start_time3.empty?) and (not end_time3.empty?)
|
300
|
+
time_result3 = validate_time_format(start_time3, end_time3, runner)
|
301
|
+
if time_result3
|
302
|
+
shift_time_start3, shift_time_end3 = time_result3
|
303
|
+
end
|
304
|
+
end
|
305
|
+
if (not start_time4.empty?) and (not end_time4.empty?)
|
306
|
+
time_result4 = validate_time_format(start_time4, end_time4, runner)
|
307
|
+
if time_result4
|
308
|
+
shift_time_start4, shift_time_end4 = time_result4
|
309
|
+
end
|
224
310
|
end
|
311
|
+
if (not start_time5.empty?) and (not end_time5.empty?)
|
312
|
+
time_result5 = validate_time_format(start_time5, end_time5, runner)
|
313
|
+
if time_result5
|
314
|
+
shift_time_start5, shift_time_end5 = time_result5
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
225
318
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
start_month1 = md[1].to_i
|
231
|
-
start_day1 = md[2].to_i
|
319
|
+
# First date period
|
320
|
+
date_result1 = validate_date_format(start_date1, end_date1, runner, model)
|
321
|
+
if date_result1
|
322
|
+
os_start_date1, os_end_date1 = date_result1
|
232
323
|
else
|
233
|
-
runner.registerError('
|
324
|
+
runner.registerError('The required date period for the reduction is not in correct format!')
|
234
325
|
return false
|
235
326
|
end
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
runner.registerError('End date must be in MM-DD format.')
|
244
|
-
return false
|
327
|
+
# Other optional date period
|
328
|
+
os_start_date2, os_end_date2, os_start_date3, os_end_date3, os_start_date4, os_end_date4, os_start_date5, os_end_date5 = [nil]*8
|
329
|
+
if (not start_date2.empty?) and (not end_date2.empty?)
|
330
|
+
date_result2 = validate_date_format(start_date2, end_date2, runner, model)
|
331
|
+
if date_result2
|
332
|
+
os_start_date2, os_end_date2 = date_result2
|
333
|
+
end
|
245
334
|
end
|
246
335
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
if (start_date2.empty? and not end_date2.empty?) or (end_date2.empty? and not start_date2.empty?)
|
252
|
-
runner.registerWarning("Either start date or end date for the second period of reduction is not specified, so the second period of reduction will not be used.")
|
253
|
-
elsif not start_date2.empty? and (not end_date2.empty?)
|
254
|
-
smd = /(\d\d)-(\d\d)/.match(start_date2)
|
255
|
-
if smd
|
256
|
-
start_month2 = smd[1].to_i
|
257
|
-
start_day2 = smd[2].to_i
|
258
|
-
else
|
259
|
-
runner.registerError('Start date must be in MM-DD format. If you do not want a second period, leave both the start and end date blank.')
|
260
|
-
return false
|
336
|
+
if (not start_date3.empty?) and (not end_date3.empty?)
|
337
|
+
date_result3 = validate_date_format(start_date3, end_date3, runner, model)
|
338
|
+
if date_result3
|
339
|
+
os_start_date3, os_end_date3 = date_result3
|
261
340
|
end
|
262
|
-
emd = /(\d\d)-(\d\d)/.match(end_date2)
|
263
|
-
if emd
|
264
|
-
end_month2 = emd[1].to_i
|
265
|
-
end_day2 = emd[2].to_i
|
266
|
-
else
|
267
|
-
runner.registerError('End date must be in MM-DD format. If you do not want a second period, leave both the start and end date blank.')
|
268
|
-
return false
|
269
|
-
end
|
270
|
-
else
|
271
|
-
|
272
341
|
end
|
273
342
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
end_day3 = nil
|
279
|
-
if (start_date3.empty? and not end_date3.empty?) or (end_date3.empty? and not start_date3.empty?)
|
280
|
-
runner.registerWarning("Either start date or end date for the third period of reduction is not specified, so the second period of reduction will not be used.")
|
281
|
-
elsif not start_date3.empty? and (not end_date3.empty?)
|
282
|
-
smd = /(\d\d)-(\d\d)/.match(start_date3)
|
283
|
-
if smd
|
284
|
-
start_month3 = smd[1].to_i
|
285
|
-
start_day3 = smd[2].to_i
|
286
|
-
else
|
287
|
-
runner.registerError('Start date must be in MM-DD format. If you do not want a third period, leave both the start and end date blank.')
|
288
|
-
return false
|
289
|
-
end
|
290
|
-
emd = /(\d\d)-(\d\d)/.match(end_date3)
|
291
|
-
if emd
|
292
|
-
end_month3 = emd[1].to_i
|
293
|
-
end_day3 = emd[2].to_i
|
294
|
-
else
|
295
|
-
runner.registerError('End date must be in MM-DD format. If you do not want a third period, leave both the start and end date blank.')
|
296
|
-
return false
|
343
|
+
if (not start_date4.empty?) and (not end_date4.empty?)
|
344
|
+
date_result4 = validate_date_format(start_date4, end_date4, runner, model)
|
345
|
+
if date_result4
|
346
|
+
os_start_date4, os_end_date4 = date_result4
|
297
347
|
end
|
298
348
|
end
|
299
349
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
os_start_date2 = OpenStudio::Date.new(OpenStudio::MonthOfYear.new(start_month2), start_day2)
|
306
|
-
os_end_date2 = OpenStudio::Date.new(OpenStudio::MonthOfYear.new(end_month2), end_day2)
|
307
|
-
end
|
308
|
-
os_start_date3 = nil
|
309
|
-
os_end_date3 = nil
|
310
|
-
if [start_month3, start_day3, end_month3, end_day3].all?
|
311
|
-
os_start_date3 = OpenStudio::Date.new(OpenStudio::MonthOfYear.new(start_month3), start_day3)
|
312
|
-
os_end_date3 = OpenStudio::Date.new(OpenStudio::MonthOfYear.new(end_month3), end_day3)
|
350
|
+
if (not start_date5.empty?) and (not end_date5.empty?)
|
351
|
+
date_result5 = validate_date_format(start_date5, end_date5, runner, model)
|
352
|
+
if date_result5
|
353
|
+
os_start_date5, os_end_date5 = date_result5
|
354
|
+
end
|
313
355
|
end
|
314
356
|
|
357
|
+
|
315
358
|
# daylightsaving adjustment added in visualization, so deprecated here
|
316
359
|
# # Check model's daylight saving period, if cooling period is within daylight saving period, shift the cooling start time and end time by one hour later
|
317
360
|
# # only check the first period now, assuming majority will only modify for a single period
|
@@ -325,6 +368,46 @@ class ReduceEPDByPercentageForPeakHours < OpenStudio::Measure::ModelMeasure
|
|
325
368
|
# end
|
326
369
|
# end
|
327
370
|
|
371
|
+
applicable_space_types = ["SecondarySchool - Office",
|
372
|
+
"PrimarySchool - Office",
|
373
|
+
"SmallOffice - ClosedOffice",
|
374
|
+
"SmallOffice - Conference",
|
375
|
+
"SmallOffice - OpenOffice",
|
376
|
+
"MediumOffice - Classroom",
|
377
|
+
"MediumOffice - ClosedOffice",
|
378
|
+
"MediumOffice - Conference",
|
379
|
+
"MediumOffice - OpenOffice",
|
380
|
+
"LargeOffice - BreakRoom",
|
381
|
+
"LargeOffice - Classroom",
|
382
|
+
"LargeOffice - ClosedOffice",
|
383
|
+
"LargeOffice - Conference",
|
384
|
+
"LargeOffice - OpenOffice",
|
385
|
+
"SmallHotel - Meeting",
|
386
|
+
"SmallHotel - Office",
|
387
|
+
"Storage - Office",
|
388
|
+
"Hospital - Office",
|
389
|
+
"Outpatient - Conference",
|
390
|
+
"Outpatient - Office",
|
391
|
+
"Warehouse - Office",
|
392
|
+
"WholeBuilding - Sm Office",
|
393
|
+
"WholeBuilding - Md Office",
|
394
|
+
"WholeBuilding - Lg Office",
|
395
|
+
"OfficeGeneral",
|
396
|
+
"OfficeOpen",
|
397
|
+
"Conference",
|
398
|
+
"OfficeSmall"]
|
399
|
+
|
400
|
+
adjust_period_inputs = { "period1" => {"date_start"=>os_start_date1, "date_end"=>os_end_date1,
|
401
|
+
"time_start"=>shift_time_start1, "time_end"=>shift_time_end1},
|
402
|
+
"period2" => {"date_start"=>os_start_date2, "date_end"=>os_end_date2,
|
403
|
+
"time_start"=>shift_time_start2, "time_end"=>shift_time_end2},
|
404
|
+
"period3" => {"date_start"=>os_start_date3, "date_end"=>os_end_date3,
|
405
|
+
"time_start"=>shift_time_start3, "time_end"=>shift_time_end3},
|
406
|
+
"period4" => {"date_start"=>os_start_date4, "date_end"=>os_end_date4,
|
407
|
+
"time_start"=>shift_time_start4, "time_end"=>shift_time_end4},
|
408
|
+
"period5" => {"date_start"=>os_start_date5, "date_end"=>os_end_date5,
|
409
|
+
"time_start"=>shift_time_start5, "time_end"=>shift_time_end5} }
|
410
|
+
|
328
411
|
epd_factor = 1 - (epd_reduce_percent/100)
|
329
412
|
applicable = false
|
330
413
|
equipments = model.getElectricEquipments
|
@@ -333,7 +416,8 @@ class ReduceEPDByPercentageForPeakHours < OpenStudio::Measure::ModelMeasure
|
|
333
416
|
equipments.each do |equip|
|
334
417
|
equip_sch = equip.schedule
|
335
418
|
if equip_sch.empty?
|
336
|
-
runner.registerWarning("#{equip.name} doesn't have a schedule.")
|
419
|
+
runner.registerWarning("#{equip.name} doesn't have a schedule, so it won't be altered.")
|
420
|
+
next
|
337
421
|
else
|
338
422
|
if equip_schedules.key?(equip_sch.get.name.to_s)
|
339
423
|
new_equip_sch = equip_schedules[equip_sch.get.name.to_s]
|
@@ -354,109 +438,142 @@ class ReduceEPDByPercentageForPeakHours < OpenStudio::Measure::ModelMeasure
|
|
354
438
|
end
|
355
439
|
end
|
356
440
|
|
357
|
-
equip_schedules.each do |old_name,
|
358
|
-
schedule_set =
|
359
|
-
default_rule = schedule_set.defaultDaySchedule
|
441
|
+
equip_schedules.each do |old_name, cloned_equip_sch|
|
442
|
+
schedule_set = cloned_equip_sch.to_ScheduleRuleset.get
|
360
443
|
rules = schedule_set.scheduleRules
|
361
444
|
days_covered = Array.new(7, false)
|
362
445
|
original_rule_number = rules.length
|
446
|
+
current_index = 0
|
363
447
|
if original_rule_number > 0
|
364
|
-
runner.registerInfo("
|
365
|
-
current_index = 0
|
448
|
+
runner.registerInfo("schedule rule set #{old_name} has #{original_rule_number} rules.")
|
366
449
|
# rules are in order of priority
|
367
450
|
rules.each do |rule|
|
368
|
-
runner.registerInfo("
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
451
|
+
runner.registerInfo("---- Rule No.#{rule.ruleIndex}: #{rule.name.to_s}")
|
452
|
+
if rule.dateSpecificationType == "SpecificDates"
|
453
|
+
## if the rule applies to SpecificDates, collect the dates that fall into each adjustment date period,
|
454
|
+
## and create a new rule for each date period with covered specific dates
|
455
|
+
runner.registerInfo("======= The rule #{rule.name.to_s} only covers specific dates.")
|
456
|
+
## the specificDates cannot be modified in place because it's a frozen array
|
457
|
+
all_specific_dates = []
|
458
|
+
rule.specificDates.each { |date| all_specific_dates << date }
|
459
|
+
adjust_period_inputs.each do |period, period_inputs|
|
460
|
+
period_inputs["specific_dates"] = []
|
461
|
+
os_start_date = period_inputs["date_start"]
|
462
|
+
os_end_date = period_inputs["date_end"]
|
463
|
+
shift_time_start = period_inputs["time_start"]
|
464
|
+
shift_time_end = period_inputs["time_end"]
|
465
|
+
if [os_start_date, os_end_date, shift_time_start, shift_time_end].all?
|
466
|
+
rule.specificDates.each do |covered_date|
|
467
|
+
if covered_date >= os_start_date and covered_date <= os_end_date
|
468
|
+
period_inputs["specific_dates"] << covered_date
|
469
|
+
all_specific_dates.delete(covered_date)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
runner.registerInfo("========= Specific dates within date range #{os_start_date.to_s} to #{os_end_date.to_s}: #{period_inputs["specific_dates"].map(&:to_s)}")
|
473
|
+
runner.registerInfo("!!! Specific dates haven't been covered: #{all_specific_dates.map(&:to_s)}")
|
474
|
+
next if period_inputs["specific_dates"].empty?
|
475
|
+
rule_period = modify_rule_for_specific_dates(rule, os_start_date, os_end_date, shift_time_start, shift_time_end,
|
476
|
+
epd_factor, period_inputs["specific_dates"])
|
477
|
+
if rule_period
|
478
|
+
applicable = true
|
479
|
+
if schedule_set.setScheduleRuleIndex(rule_period, current_index)
|
480
|
+
current_index += 1
|
481
|
+
runner.registerInfo("-------- The rule #{rule_period.name.to_s} for #{rule_period.dateSpecificationType} is added as priority #{current_index}")
|
482
|
+
else
|
483
|
+
runner.registerError("Fail to set rule index for #{rule_period.name.to_s}.")
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|
400
487
|
end
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
488
|
+
if all_specific_dates.empty?
|
489
|
+
## if all specific dates have been covered by new rules for each adjustment date period, remove the original rule
|
490
|
+
runner.registerInfo("The original rule is removed since no specific date left")
|
491
|
+
else
|
492
|
+
## if there's still dates left to be covered, modify the original rule to only cover these dates
|
493
|
+
## (this is just in case that the rule order was not set correctly, and the original rule is still applied to all specific dates;
|
494
|
+
## also to make the logic in OSM more clearer)
|
495
|
+
## the specificDates cannot be modified in place, so create a new rule with the left dates to replace the original rule
|
496
|
+
original_rule_update = clone_rule_with_new_dayschedule(rule, rule.name.to_s + " - dates left")
|
497
|
+
schedule_set.setScheduleRuleIndex(original_rule_update, current_index)
|
498
|
+
current_index += 1
|
499
|
+
all_specific_dates.each do |date|
|
500
|
+
original_rule_update.addSpecificDate(date)
|
501
|
+
end
|
502
|
+
runner.registerInfo("-------- The original rule #{rule.name.to_s} is modified to only cover the rest of the dates: #{all_specific_dates.map(&:to_s)}")
|
503
|
+
runner.registerInfo("-------- and is shifted to priority #{current_index}")
|
409
504
|
end
|
410
|
-
|
411
|
-
runner.registerInfo("--------------- schedule updated for #{rule_period3.startDate.get} to #{rule_period3.endDate.get}")
|
412
|
-
end
|
505
|
+
rule.remove
|
413
506
|
|
414
|
-
|
415
|
-
|
416
|
-
|
507
|
+
else
|
508
|
+
## If the rule applies to a DateRange, check if the DateRange overlaps with each adjustment date period
|
509
|
+
## if so, create a new rule for that adjustment date period
|
510
|
+
runner.registerInfo("******* The rule #{rule.name.to_s} covers date range #{rule.startDate.get} - #{rule.endDate.get}.")
|
511
|
+
# runner.registerInfo("Before adjustment, the rule #{rule.name.to_s} is #{rule.daySchedule.values}")
|
512
|
+
|
513
|
+
adjust_period_inputs.each do |period, period_inputs|
|
514
|
+
os_start_date = period_inputs["date_start"]
|
515
|
+
os_end_date = period_inputs["date_end"]
|
516
|
+
shift_time_start = period_inputs["time_start"]
|
517
|
+
shift_time_end = period_inputs["time_end"]
|
518
|
+
if [os_start_date, os_end_date, shift_time_start, shift_time_end].all?
|
519
|
+
overlapped, new_start_dates, new_end_dates = check_date_ranges_overlap(rule, os_start_date, os_end_date)
|
520
|
+
if overlapped
|
521
|
+
new_start_dates.each_with_index do |start_date, i|
|
522
|
+
rule_period = modify_rule_for_date_period(rule, start_date, new_end_dates[i], shift_time_start, shift_time_end, epd_factor)
|
523
|
+
if rule_period
|
524
|
+
applicable = true
|
525
|
+
if period == "period1"
|
526
|
+
# check the days covered only once
|
527
|
+
checkDaysCovered(rule_period, days_covered)
|
528
|
+
end
|
529
|
+
if schedule_set.setScheduleRuleIndex(rule_period, current_index)
|
530
|
+
runner.registerInfo("-------- The rule #{rule_period.name.to_s} is added as priority #{current_index}")
|
531
|
+
current_index += 1
|
532
|
+
else
|
533
|
+
runner.registerError("-------- Fail to set rule index for #{rule_period.name.to_s}.")
|
534
|
+
end
|
535
|
+
end
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
539
|
+
end
|
540
|
+
# The original rule will be shifted to the currently lowest priority
|
541
|
+
# Setting the rule to an existing index will automatically push all other rules after it down
|
542
|
+
if schedule_set.setScheduleRuleIndex(rule, current_index)
|
543
|
+
runner.registerInfo("-------- The original rule #{rule.name.to_s} is shifted to priority #{current_index}")
|
544
|
+
current_index += 1
|
545
|
+
else
|
546
|
+
runner.registerError("-------- Fail to set rule index for #{rule.name.to_s}")
|
547
|
+
end
|
417
548
|
end
|
418
549
|
|
419
550
|
end
|
420
551
|
else
|
421
552
|
runner.registerWarning("Electric equipment schedule #{old_name} is a ScheduleRuleSet, but has no ScheduleRules associated. It won't be altered by this measure.")
|
422
553
|
end
|
554
|
+
|
555
|
+
# if all rules not covered all days in a week, then the rest of days use defaultDaySchedule
|
556
|
+
# defaultDaySchedule cannot specify date range, so clone it to a new rule to set date range and cover the rest of days
|
557
|
+
default_day = schedule_set.defaultDaySchedule
|
423
558
|
if days_covered.include?(false)
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
new_default_day.clearValues
|
437
|
-
new_default_day = updateDaySchedule(new_default_day, day_time_vector, day_value_vector, shift_time1, shift_time2, epd_factor)
|
438
|
-
if os_start_date2 and os_end_date2
|
439
|
-
copy_sch_rule_for_period(model, new_default_rule, new_default_day, os_start_date2, os_end_date2)
|
440
|
-
end
|
441
|
-
if os_start_date3 and os_end_date3
|
442
|
-
copy_sch_rule_for_period(model, new_default_rule, new_default_day, os_start_date3, os_end_date3)
|
559
|
+
runner.registerInfo("Some days use default day. Adding new scheduleRule from defaultDaySchedule for applicable date period.")
|
560
|
+
adjust_period_inputs.each do |period, period_inputs|
|
561
|
+
runner.registerInfo("******** current covered days: #{days_covered}")
|
562
|
+
os_start_date = period_inputs["date_start"]
|
563
|
+
os_end_date = period_inputs["date_end"]
|
564
|
+
shift_time_start = period_inputs["time_start"]
|
565
|
+
shift_time_end = period_inputs["time_end"]
|
566
|
+
if [os_start_date, os_end_date, shift_time_start, shift_time_end].all?
|
567
|
+
new_default_rule_period = modify_default_day_for_date_period(schedule_set, default_day, days_covered, os_start_date, os_end_date,
|
568
|
+
shift_time_start, shift_time_end, epd_factor)
|
569
|
+
schedule_set.setScheduleRuleIndex(new_default_rule_period, current_index)
|
570
|
+
end
|
443
571
|
end
|
444
572
|
end
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
# doesn't work for models without scheduleRules
|
449
|
-
# runner.registerInfo("------------------------FINAL--------------------")
|
450
|
-
# space_type.electricEquipment.each do |equip|
|
451
|
-
# lgt_schedule_set = equip.schedule
|
452
|
-
# unless lgt_schedule_set.empty?
|
453
|
-
# runner.registerInfo("Schedule #{lgt_schedule_set.get.name.to_s}:")
|
454
|
-
# sch_set = lgt_schedule_set.get.to_Schedule.get
|
455
|
-
# sch_set.to_ScheduleRuleset.get.scheduleRules.each do |rule|
|
456
|
-
# runner.registerInfo(" rule #{rule.ruleIndex}: #{rule.daySchedule.name.to_s} from #{rule.startDate.get} to #{rule.endDate.get}")
|
457
|
-
# end
|
458
|
-
# end
|
573
|
+
# schedule_set.scheduleRules.each do |final_rule|
|
574
|
+
# runner.registerInfo("Finally rules: #{final_rule.name.to_s} is in priority #{final_rule.ruleIndex}")
|
459
575
|
# end
|
576
|
+
end
|
460
577
|
|
461
578
|
unless applicable
|
462
579
|
runner.registerAsNotApplicable('No electric equipment schedule in the model could be altered.')
|
@@ -465,17 +582,110 @@ class ReduceEPDByPercentageForPeakHours < OpenStudio::Measure::ModelMeasure
|
|
465
582
|
return true
|
466
583
|
end
|
467
584
|
|
468
|
-
def
|
469
|
-
|
470
|
-
|
471
|
-
|
585
|
+
def check_date_ranges_overlap(rule, adjust_start_date, adjust_end_date)
|
586
|
+
## check if the original rule applied DateRange overlaps with the adjustment date period
|
587
|
+
overlapped = false
|
588
|
+
new_start_dates = []
|
589
|
+
new_end_dates = []
|
590
|
+
if rule.endDate.get >= rule.startDate.get and rule.startDate.get <= adjust_end_date and rule.endDate.get >= adjust_start_date
|
591
|
+
overlapped = true
|
592
|
+
new_start_dates << [adjust_start_date, rule.startDate.get].max
|
593
|
+
new_end_dates << [adjust_end_date, rule.endDate.get].min
|
594
|
+
elsif rule.endDate.get < rule.startDate.get
|
595
|
+
## If the DateRange has a endDate < startDate, the range wraps around the year.
|
596
|
+
if rule.endDate.get >= adjust_start_date
|
597
|
+
overlapped = true
|
598
|
+
new_start_dates << adjust_start_date
|
599
|
+
new_end_dates << rule.endDate.get
|
600
|
+
end
|
601
|
+
if rule.startDate.get <= adjust_end_date
|
602
|
+
overlapped = true
|
603
|
+
new_start_dates << rule.startDate.get
|
604
|
+
new_end_dates << adjust_end_date
|
605
|
+
end
|
606
|
+
end
|
607
|
+
return overlapped, new_start_dates, new_end_dates
|
608
|
+
end
|
472
609
|
|
473
|
-
|
474
|
-
|
610
|
+
def clone_rule_with_new_dayschedule(original_rule, new_rule_name)
|
611
|
+
## Cloning a scheduleRule will automatically clone the daySchedule associated with it, but it's a shallow copy,
|
612
|
+
## because the daySchedule is a resource that can be used by many scheduleRule
|
613
|
+
## Therefore, once the daySchedule is modified for the cloned scheduleRule, the original daySchedule is also changed
|
614
|
+
## Also, there's no function to assign a new daySchedule to the existing scheduleRule,
|
615
|
+
## so the only way to clone the scheduleRule but change the daySchedule is to construct a new scheduleRule with a daySchedule passed in
|
616
|
+
## and copy all other settings from the original scheduleRule
|
617
|
+
rule_period = OpenStudio::Model::ScheduleRule.new(original_rule.scheduleRuleset, original_rule.daySchedule)
|
618
|
+
rule_period.setName(new_rule_name)
|
619
|
+
rule_period.setApplySunday(original_rule.applySunday)
|
620
|
+
rule_period.setApplyMonday(original_rule.applyMonday)
|
621
|
+
rule_period.setApplyTuesday(original_rule.applyTuesday)
|
622
|
+
rule_period.setApplyWednesday(original_rule.applyWednesday)
|
623
|
+
rule_period.setApplyThursday(original_rule.applyThursday)
|
624
|
+
rule_period.setApplyFriday(original_rule.applyFriday)
|
625
|
+
rule_period.setApplySaturday(original_rule.applySaturday)
|
626
|
+
return rule_period
|
627
|
+
end
|
475
628
|
|
476
|
-
|
629
|
+
def modify_rule_for_date_period(original_rule, os_start_date, os_end_date, shift_time_start, shift_time_end, adjustment)
|
630
|
+
# The cloned scheduleRule will automatically belongs to the originally scheduleRuleSet
|
631
|
+
# rule_period = original_rule.clone(model).to_ScheduleRule.get
|
632
|
+
# rule_period.daySchedule = original_rule.daySchedule.clone(model)
|
633
|
+
new_rule_name = "#{original_rule.name.to_s} with DF for #{os_start_date.to_s} to #{os_end_date.to_s}"
|
634
|
+
rule_period = clone_rule_with_new_dayschedule(original_rule, new_rule_name)
|
635
|
+
day_rule_period = rule_period.daySchedule
|
636
|
+
day_time_vector = day_rule_period.times
|
637
|
+
day_value_vector = day_rule_period.values
|
638
|
+
if day_time_vector.empty?
|
639
|
+
return false
|
640
|
+
end
|
641
|
+
day_rule_period.clearValues
|
642
|
+
updateDaySchedule(day_rule_period, day_time_vector, day_value_vector, shift_time_start, shift_time_end, adjustment)
|
643
|
+
if rule_period
|
644
|
+
rule_period.setStartDate(os_start_date)
|
645
|
+
rule_period.setEndDate(os_end_date)
|
646
|
+
end
|
647
|
+
return rule_period
|
477
648
|
end
|
478
649
|
|
650
|
+
def modify_rule_for_specific_dates(original_rule, os_start_date, os_end_date, shift_time_start, shift_time_end,
|
651
|
+
adjustment, applied_dates)
|
652
|
+
new_rule_name = "#{original_rule.name.to_s} with DF for #{os_start_date.to_s} to #{os_end_date.to_s}"
|
653
|
+
rule_period = clone_rule_with_new_dayschedule(original_rule, new_rule_name)
|
654
|
+
day_rule_period = rule_period.daySchedule
|
655
|
+
day_time_vector = day_rule_period.times
|
656
|
+
day_value_vector = day_rule_period.values
|
657
|
+
if day_time_vector.empty?
|
658
|
+
return false
|
659
|
+
end
|
660
|
+
day_rule_period.clearValues
|
661
|
+
updateDaySchedule(day_rule_period, day_time_vector, day_value_vector, shift_time_start, shift_time_end, adjustment)
|
662
|
+
if rule_period
|
663
|
+
applied_dates.each do |date|
|
664
|
+
rule_period.addSpecificDate(date)
|
665
|
+
end
|
666
|
+
end
|
667
|
+
return rule_period
|
668
|
+
end
|
669
|
+
|
670
|
+
def modify_default_day_for_date_period(schedule_set, default_day, days_covered, os_start_date, os_end_date,
|
671
|
+
shift_time_start, shift_time_end, epd_factor)
|
672
|
+
# the new rule created for the ScheduleRuleSet by default has the highest priority (ruleIndex=0)
|
673
|
+
new_default_rule = OpenStudio::Model::ScheduleRule.new(schedule_set, default_day)
|
674
|
+
new_default_rule.setName("#{schedule_set.name.to_s} default day with DF for #{os_start_date.to_s} to #{os_end_date.to_s}")
|
675
|
+
new_default_rule.setStartDate(os_start_date)
|
676
|
+
new_default_rule.setEndDate(os_end_date)
|
677
|
+
coverMissingDays(new_default_rule, days_covered)
|
678
|
+
new_default_day = new_default_rule.daySchedule
|
679
|
+
day_time_vector = new_default_day.times
|
680
|
+
day_value_vector = new_default_day.values
|
681
|
+
new_default_day.clearValues
|
682
|
+
new_default_day = updateDaySchedule(new_default_day, day_time_vector, day_value_vector, shift_time_start, shift_time_end, epd_factor)
|
683
|
+
# schedule_set.setScheduleRuleIndex(new_default_rule, 0)
|
684
|
+
return new_default_rule
|
685
|
+
# TODO: if the scheduleRuleSet has holidaySchedule (which is a ScheduleDay), it cannot be altered
|
686
|
+
end
|
687
|
+
|
688
|
+
|
479
689
|
def checkDaysCovered(sch_rule, sch_day_covered)
|
480
690
|
if sch_rule.applySunday
|
481
691
|
sch_day_covered[0] = true
|
@@ -558,7 +768,6 @@ class ReduceEPDByPercentageForPeakHours < OpenStudio::Measure::ModelMeasure
|
|
558
768
|
sch_day.addValue(exist_timestamp, vec_value[i])
|
559
769
|
end
|
560
770
|
end
|
561
|
-
|
562
771
|
return sch_day
|
563
772
|
end
|
564
773
|
|