openstudio-load-flexibility-measures 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +4 -0
  4. data/LICENSE.md +1 -1
  5. data/doc_templates/LICENSE.md +1 -1
  6. data/doc_templates/copyright_erb.txt +1 -1
  7. data/doc_templates/copyright_js.txt +1 -1
  8. data/doc_templates/copyright_ruby.txt +1 -1
  9. data/lib/measures/ShiftScheduleByType/LICENSE.md +27 -0
  10. data/lib/measures/ShiftScheduleByType/README.md +40 -0
  11. data/lib/measures/ShiftScheduleByType/README.md.erb +42 -0
  12. data/lib/measures/ShiftScheduleByType/measure.rb +385 -0
  13. data/lib/measures/ShiftScheduleByType/measure.xml +115 -0
  14. data/lib/measures/ShiftScheduleByType/tests/3Story2Space.osm +3030 -0
  15. data/lib/measures/ShiftScheduleByType/tests/ShiftScheduleByType_Test.rb +193 -0
  16. data/lib/measures/add_central_ice_storage/LICENSE.md +1 -1
  17. data/lib/measures/add_central_ice_storage/measure.rb +1 -1
  18. data/lib/measures/add_central_ice_storage/measure.xml +6 -6
  19. data/lib/measures/add_central_ice_storage/resources/OsLib_Schedules.rb +1 -1
  20. data/lib/measures/add_central_ice_storage/tests/add_central_ice_storage_test.rb +1 -1
  21. data/lib/measures/add_hpwh/LICENSE.md +1 -1
  22. data/lib/measures/add_hpwh/measure.rb +1 -1
  23. data/lib/measures/add_hpwh/measure.xml +5 -5
  24. data/lib/measures/add_hpwh/tests/add_hpwh_test.rb +1 -1
  25. data/lib/measures/add_packaged_ice_storage/LICENSE.md +1 -1
  26. data/lib/measures/add_packaged_ice_storage/measure.rb +1 -1
  27. data/lib/measures/add_packaged_ice_storage/measure.xml +5 -5
  28. data/lib/measures/add_packaged_ice_storage/tests/add_packaged_ice_storage_test.rb +1 -1
  29. data/lib/openstudio/load_flexibility_measures/version.rb +2 -2
  30. data/lib/openstudio/load_flexibility_measures.rb +1 -1
  31. metadata +9 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58c0563232be8b88f9766cd0ca55fc83f282b141cc13dc55bdde3b24124c4c20
4
- data.tar.gz: aaaea1cd2ec323627f0920bd06793100f4915699f8ab8095674153dbaf19eb80
3
+ metadata.gz: f82406e85fdfe5b319faece1421d911dc44a19d5c027353dcf067f43fcc36ba0
4
+ data.tar.gz: 85c43e9c24d407e2c1f56932ff96eac28b12344396d5ae6e0ac86d6d16c36ae6
5
5
  SHA512:
6
- metadata.gz: 833b28b174e78831ce682c558b0f6c4e99da74183b60e6fd2dd11c9f6f6178729b6ce2a5a30a51de3a962e79eb8bfa4d66e5712df85877f3bcce39f625a2d2e6
7
- data.tar.gz: b53231a2296561ba29e069733f0e41fda1b5003d1d1fca852e2c1728dd33741b2bf20a6cf9a2ee06daa3d203af614a658ceb940ce9cc9a99548892e0f3728bef
6
+ metadata.gz: 19a523c49d23e17579ee80cd5c71d3895a749663fce80302ac93b92ac74834c0932bc4475851e8b6a400585803b9ff08d46eae68bf007c00acc27c147501ddf0
7
+ data.tar.gz: 6e8cbcc894b9d68c55a70274f4044d8e7c19dfc6b853891103d20c10120224759ba00d62b6367446a74a3670d90947891cdc9d540f360ff91f22e4e1ebd69583
data/.gitignore CHANGED
@@ -34,3 +34,4 @@ runner.conf
34
34
 
35
35
  # DS_Store
36
36
  lib/.DS_Store
37
+ *.DS_Store
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # OpenStudio Load Flexibility Measures Gem
2
2
 
3
+ ## Version 0.5.1
4
+ - Added the ShiftScheduleByType measure - [#47](https://github.com/NREL/openstudio-load-flexibility-measures-gem/issues/47)
5
+ - Updating licenses and measure versions / checksums for 2022
6
+
3
7
  ## Version 0.5.0
4
8
  * Updated OS Standards dependency to 0.2.16
5
9
  * Fixed [#41](https://github.com/NREL/openstudio-load-flexibility-measures-gem/issues/41), Error in applying add_hpwh measure with "non-simplified" options to MF prototype building in OS 3.3
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC. All rights reserved.
1
+ OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC. All rights reserved.
2
2
 
3
3
  Redistribution and use in source and binary forms, with or without modification, are permitted
4
4
  provided that the following conditions are met:
@@ -1,4 +1,4 @@
1
- OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC. All rights reserved.
1
+ OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC. All rights reserved.
2
2
 
3
3
  Redistribution and use in source and binary forms, with or without modification, are permitted
4
4
  provided that the following conditions are met:
@@ -1,6 +1,6 @@
1
1
  <%
2
2
  # *******************************************************************************
3
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
3
+ # OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC.
4
4
  # All rights reserved.
5
5
  # Redistribution and use in source and binary forms, with or without
6
6
  # modification, are permitted provided that the following conditions are met:
@@ -1,4 +1,4 @@
1
1
  /* @preserve
2
- * OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC. All rights reserved.
2
+ * OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC. All rights reserved.
3
3
  * Use of this source code is governed by a BSD-style license that can be found at openstudio.net/license.
4
4
  */
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -0,0 +1,27 @@
1
+ OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted
4
+ provided that the following conditions are met:
5
+
6
+ (1) Redistributions of source code must retain the above copyright notice, this list of conditions
7
+ and the following disclaimer.
8
+
9
+ (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions
10
+ and the following disclaimer in the documentation and/or other materials provided with the distribution.
11
+
12
+ (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse
13
+ or promote products derived from this software without specific prior written permission from the
14
+ respective party.
15
+
16
+ (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other
17
+ derivative works may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar
18
+ designation without specific prior written permission from Alliance for Sustainable Energy, LLC.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
21
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES GOVERNMENT,
23
+ OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
25
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,40 @@
1
+
2
+
3
+ ###### (Automatically generated documentation)
4
+
5
+ # ShiftScheduleByType
6
+
7
+ ## Description
8
+ This measure was developed for the URBANopt Class Project and shifts specific building schedules if they include cooling ("CLG"), heating ("HTG"), or air ("Air") strings. The measure will shift these chosen schedules by an amount specified by the user and will also output a .csv file of the schedules before and after the shift.
9
+
10
+ ## Modeler Description
11
+ Depending on the model's thermostat deadband settings, shifting of exclusively cooling or heating schedules can result in EnergyPlus deadband errors. It is recommended to shift both cooling and heating schedules using the 'coolheat' option for schedchoice. If no schedules for the current model include the cooling, heating, or air strings, none will be shifted. Schedules including the string 'setback' are intentionally excluded from shifts in order to prevent EnergyPlus errors.
12
+
13
+ ## Measure Type
14
+ ModelMeasure
15
+
16
+ ## Taxonomy
17
+
18
+
19
+ ## Arguments
20
+
21
+
22
+ ### Shift Schedule Profiles Forward (24hr, use decimal for sub hour and negative values for backward shift).
23
+
24
+ **Name:** shift_value,
25
+ **Type:** Double,
26
+ **Units:** ,
27
+ **Required:** true,
28
+ **Model Dependent:** false
29
+
30
+ ### Choose which schedule class(es) to shift by the specified shift value
31
+
32
+ **Name:** schedchoice,
33
+ **Type:** Choice,
34
+ **Units:** ,
35
+ **Required:** true,
36
+ **Model Dependent:** false
37
+
38
+
39
+
40
+
@@ -0,0 +1,42 @@
1
+ <%#= README.md.erb is used to auto-generate README.md. %>
2
+ <%#= To manually maintain README.md throw away README.md.erb and manually edit README.md %>
3
+ ###### (Automatically generated documentation)
4
+
5
+ # <%= name %>
6
+
7
+ ## Description
8
+ <%= description %>
9
+
10
+ ## Modeler Description
11
+ <%= modelerDescription %>
12
+
13
+ ## Measure Type
14
+ <%= measureType %>
15
+
16
+ ## Taxonomy
17
+ <%= taxonomy %>
18
+
19
+ ## Arguments
20
+
21
+ <% arguments.each do |argument| %>
22
+ ### <%= argument[:display_name] %>
23
+ <%= argument[:description] %>
24
+ **Name:** <%= argument[:name] %>,
25
+ **Type:** <%= argument[:type] %>,
26
+ **Units:** <%= argument[:units] %>,
27
+ **Required:** <%= argument[:required] %>,
28
+ **Model Dependent:** <%= argument[:model_dependent] %>
29
+ <% end %>
30
+
31
+ <% if arguments.size == 0 %>
32
+ <%= "This measure does not have any user arguments" %>
33
+ <% end %>
34
+
35
+ <% if outputs.size > 0 %>
36
+ ## Outputs
37
+ <% output_names = [] %>
38
+ <% outputs.each do |output| %>
39
+ <% output_names << output[:display_name] %>
40
+ <% end %>
41
+ <%= output_names.join(", ") %>
42
+ <% end %>
@@ -0,0 +1,385 @@
1
+ # *******************************************************************************
2
+ # OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC.
3
+ # All rights reserved.
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # (1) Redistributions of source code must retain the above copyright notice,
8
+ # this list of conditions and the following disclaimer.
9
+ #
10
+ # (2) Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # (3) Neither the name of the copyright holder nor the names of any contributors
15
+ # may be used to endorse or promote products derived from this software without
16
+ # specific prior written permission from the respective party.
17
+ #
18
+ # (4) Other than as required in clauses (1) and (2), distributions in any form
19
+ # of modifications or other derivative works may not use the "OpenStudio"
20
+ # trademark, "OS", "os", or any other confusingly similar designation without
21
+ # specific prior written permission from Alliance for Sustainable Energy, LLC.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
24
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
27
+ # UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
28
+ # THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
30
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33
+ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+ # *******************************************************************************
35
+
36
+ # see the URL below for information on how to write OpenStudio measures
37
+ # http://openstudio.nrel.gov/openstudio-measure-writing-guide
38
+
39
+ # see the URL below for access to C++ documentation on model objects (click on "model" in the main window to view model objects)
40
+ # http://openstudio.nrel.gov/sites/openstudio.nrel.gov/files/nv_data/cpp_documentation_it/model/html/namespaces.html
41
+
42
+ # This measure was created as an adaptation of the "ShiftScheduleProfileTime" common
43
+ # measure. This measure adds the ability to choose types (Cooling/Heating) of
44
+ # schedules to shift instead of choosing all schedules or one schedule.
45
+
46
+ # Start the measure
47
+ class ShiftScheduleByType < OpenStudio::Measure::ModelMeasure
48
+ # define the name that a user will see, this method may be deprecated as
49
+ # the display name in PAT comes from the name field in measure.xml
50
+ def name
51
+ return 'ShiftScheduleByType'
52
+ end
53
+
54
+ # human readable description
55
+ def description
56
+ return 'This measure was developed for the URBANopt Class Project and shifts specific building schedules if they include cooling ("CLG"), heating ("HTG"), or air ("Air") strings. The measure will shift these chosen schedules by an amount specified by the user and will also output a .csv file of the schedules before and after the shift.'
57
+ end
58
+
59
+ # human readable description of modeling approach
60
+ def modeler_description
61
+ return "Depending on the model's thermostat deadband settings, shifting of exclusively cooling or heating schedules can result in EnergyPlus deadband errors. It is recommended to shift both cooling and heating schedules using the 'coolheat' option for schedchoice. If no schedules for the current model include the cooling, heating, or air strings, none will be shifted. Schedules including the string 'setback' are intentionally excluded from shifts in order to prevent EnergyPlus errors."
62
+ end
63
+
64
+ # Define the arguments that the user will input
65
+ def arguments(model)
66
+ args = OpenStudio::Measure::OSArgumentVector.new
67
+
68
+ # Argument to specify the amount of time by which the chosen schedule(s) will be shifted
69
+ shift_value = OpenStudio::Measure::OSArgument.makeDoubleArgument('shift_value', true)
70
+ shift_value.setDisplayName('Shift Schedule Profiles Forward (24hr, use decimal for sub hour and negative values for backward shift).')
71
+ shift_value.setDefaultValue(1)
72
+ args << shift_value
73
+
74
+ # Argument to choose which schedules will be shifted
75
+ choices = OpenStudio::StringVector.new
76
+ choices << 'Cooling'
77
+ choices << 'Heating'
78
+ choices << 'CoolHeat'
79
+ schedchoice = OpenStudio::Measure::OSArgument.makeChoiceArgument('schedchoice', choices)
80
+ schedchoice.setDisplayName('Choose which schedule class(es) to shift by the specified shift value')
81
+ schedchoice.setDefaultValue('CoolHeat')
82
+ args << schedchoice
83
+
84
+ return args
85
+ end
86
+
87
+ # define what happens when the measure is run
88
+ def run(model, runner, user_arguments)
89
+ super(model, runner, user_arguments)
90
+
91
+ # use the built-in error checking
92
+ if !runner.validateUserArguments(arguments(model), user_arguments)
93
+ return false
94
+ end
95
+
96
+ # Export CSV file with Schedule setpoints before schedule shifts
97
+ #model1 = runner.lastOpenStudioModel
98
+ #model = model1.get
99
+ interval = 60
100
+ header = []
101
+ header << 'Time'
102
+ schedules = []
103
+ model.getScheduleDays.each do |schedule|
104
+ header << schedule.name.get
105
+ schedules << schedule
106
+ end
107
+
108
+ dt = OpenStudio::Time.new(0, 0, interval, 0)
109
+ time = OpenStudio::Time.new(0, 0, 0, 0)
110
+ stop = OpenStudio::Time.new(1, 0, 0, 0)
111
+ values = []
112
+ while time <= stop
113
+ row = []
114
+ row << time.to_s
115
+ schedules.each do |schedule|
116
+ row << schedule.getValue(time)
117
+ end
118
+ values << row
119
+
120
+ time += dt
121
+ end
122
+
123
+ runner.registerInfo("Writing CSV report 'schedulereportbefore.csv'")
124
+ File.open('schedulereportbefore.csv', 'w') do |file|
125
+ file.puts header.join(',')
126
+ values.each do |row|
127
+ file.puts row.join(',')
128
+ end
129
+ end
130
+
131
+ # populate choice argument for schedules that are applied to surfaces in the model
132
+ schedule_handles = OpenStudio::StringVector.new
133
+ schedule_display_names = OpenStudio::StringVector.new
134
+
135
+ # putting space types and names into hash
136
+ schedule_args = model.getScheduleRulesets
137
+ schedule_args_hash = {}
138
+ schedule_args.each do |schedule_arg|
139
+ schedule_args_hash[schedule_arg.name.to_s] = schedule_arg
140
+ end
141
+
142
+ # looping through sorted hash of schedules
143
+ schedule_args_hash.sort.map do |key, value|
144
+ # only include if schedule use count > 0
145
+ if value.directUseCount > 0
146
+ schedule_handles << value.handle.to_s
147
+ schedule_display_names << key
148
+ end
149
+ end
150
+
151
+ # Assign the user inputs to variables
152
+ shift_value = runner.getDoubleArgumentValue('shift_value', user_arguments)
153
+ schedchoice = runner.getStringArgumentValue('schedchoice', user_arguments)
154
+
155
+ apply_to_all_schedules = true
156
+
157
+ # Check shift value for reasonableness
158
+ if (shift_value / 24) == (shift_value / 24).to_i
159
+ runner.registerAsNotApplicable('No schedule shift was requested, the model was not changed.')
160
+ end
161
+
162
+ # Get schedules for measure
163
+ schedules = []
164
+ if apply_to_all_schedules
165
+ raw_schedules = model.getScheduleRulesets
166
+ raw_schedules_hash = {}
167
+ raw_schedules.each do |raw_schedule|
168
+ raw_schedules_hash[raw_schedule.name.to_s] = raw_schedule
169
+ end
170
+
171
+ # Looping through sorted hash of schedules
172
+ raw_schedules_hash.sort.map do |name, value|
173
+ # Only include if the schedule is used in the model
174
+ if value.directUseCount > 0
175
+ schedule_handles << value.handle.to_s
176
+ schedule_display_names << name
177
+ runner.registerInfo("Searching Schedule: #{name}")
178
+ if !name.downcase.include?("setback")
179
+ if schedchoice == "Cool" # Cooling and Air Only
180
+ if (name.to_s.include?("CLG") || name.to_s.include?("Air"))
181
+ # ADD v to Cooling list
182
+ schedules << value
183
+ runner.registerInfo("Schedule #{name} does contain 'CLG' or 'Air'")
184
+ else
185
+ runner.registerInfo("Schedule #{name} does not contain 'CLG' or 'Air'")
186
+ end
187
+ elsif schedchoice == "Heat" # Heating and Air Only
188
+ if (name.to_s.include?("HTG") || name.to_s.include?("Air"))
189
+ # ADD v to Heating list
190
+ schedules << value
191
+ runner.registerInfo("Schedule #{name} does contain 'HTG' or 'Air'")
192
+ else
193
+ runner.registerInfo("Schedule #{name} does not contain 'HTG' or 'Air'")
194
+ end
195
+ elsif schedchoice == "CoolHeat" # Cooling, Heating, and Air
196
+ if (name.to_s.include?("CLG") || name.to_s.include?("HTG") || name.to_s.include?("Air"))
197
+ # ADD v to Cooling/Heating list
198
+ schedules << value
199
+ runner.registerInfo("Schedule #{name} does contain 'CLG' or 'HTG' or 'Air'")
200
+ else
201
+ runner.registerInfo("Schedule #{name} does not contain 'CLG' or 'HTG' or 'Air'")
202
+ end
203
+ else
204
+ runner.registerError('Unexpected value of schedchoice: ' + schedchoice + '.')
205
+ return false
206
+ end
207
+ end
208
+ end
209
+ end
210
+
211
+ else
212
+ runner.registerAsNotApplicable('No schedules included in shift')
213
+ end
214
+
215
+ # Loop through all chosen schedules
216
+ schedules.each do |schedule|
217
+ # Array of all profiles to change
218
+ profiles = []
219
+
220
+ # Push default profiles to array
221
+ default_rule = schedule.defaultDaySchedule
222
+ profiles << default_rule
223
+
224
+ # Push profiles to array
225
+ rules = schedule.scheduleRules
226
+ rules.each do |rule|
227
+ day_sch = rule.daySchedule
228
+ profiles << day_sch
229
+ end
230
+
231
+ # Add design days to array
232
+ summer_design = schedule.summerDesignDaySchedule
233
+ winter_design = schedule.winterDesignDaySchedule
234
+ profiles << summer_design
235
+ profiles << winter_design
236
+
237
+ # Reporting initial condition of model
238
+ if apply_to_all_schedules
239
+ runner.registerInitialCondition("#{schedules.size} schedules are shifted in this model.")
240
+ else
241
+ runner.registerInitialCondition("Schedule #{schedule.name} has #{profiles.size} profiles including design days.")
242
+ end
243
+
244
+ # Rename schedule
245
+ schedule.setName("#{schedule.name} - (shifted #{shift_value} hours)")
246
+
247
+ shift_hours = shift_value.to_i
248
+ shift_minutes = ((shift_value - shift_value.to_i) * 60).to_i
249
+
250
+ # Give info messages as I change specific profiles
251
+ runner.registerInfo("Adjusting #{schedule.name}")
252
+
253
+ # Edit profiles
254
+ profiles.each do |day_sch|
255
+ times = day_sch.times
256
+ values = day_sch.values
257
+
258
+ runner.registerInfo("Old day_sch: #{day_sch}")
259
+ runner.registerInfo("Old Times: #{times}")
260
+ runner.registerInfo("Old Values: #{values}")
261
+
262
+ # Time objects to use in measure
263
+ time_0 = OpenStudio::Time.new(0, 0, 0, 0)
264
+ time_24 = OpenStudio::Time.new(0, 24, 0, 0)
265
+ shift_time = OpenStudio::Time.new(0, shift_hours, shift_minutes, 0)
266
+
267
+ # Arrays for values to avoid overlap conflict of times
268
+ new_times = []
269
+ new_values = []
270
+
271
+ if values.length < 2 # Avoid adjusting schedules with only one cooling/heating/air setpoint
272
+ new_times = times
273
+ new_values = values
274
+ else # Adjust schedules with more than 3 setpoints
275
+ # Create a pair of times and values for what will be 0 time after adjustment
276
+ new_times << time_24
277
+ if shift_time > time_0
278
+ new_values << day_sch.getValue(time_24 - shift_time)
279
+ else
280
+ new_values << day_sch.getValue(time_0 - shift_time)
281
+ end
282
+
283
+ # Clear values
284
+ day_sch.clearValues
285
+
286
+ # Unfreeze arrays before editing
287
+ times = times.clone(freeze: false) if times.frozen?
288
+ values = values.clone(freeze: false) if values.frozen?
289
+
290
+ if values.length == 2
291
+ timeschg = values.length - 2
292
+ else
293
+ timeschg = values.length - 3
294
+ end
295
+
296
+ # Count number of arrays
297
+ for i in 0..timeschg
298
+ new_time = times[i] + shift_time
299
+ # Adjust wrap around times for times that are t > 24 or t < 0
300
+ if new_time < time_0
301
+ new_time = new_time + time_24
302
+ values.rotate(1) # Move first value to last value in array
303
+ runner.registerWarning("Times adjusted for wrap around due to new time < 0.")
304
+ elsif new_time > time_24
305
+ new_time = new_time - time_24
306
+ values.rotate(-1) # Move last value to first value in array
307
+ runner.registerWarning("Times adjusted for wrap around due to new time > 24.")
308
+ else # If 0 < new_time < 24
309
+ new_time = new_time
310
+ end
311
+ # Make new values
312
+ new_times = times.insert(i, new_time)
313
+ new_times.delete_at(i+1)
314
+ end
315
+
316
+ new_values = values # Set new values equal to original schedule values
317
+ new_times.freeze
318
+
319
+ end
320
+
321
+ if values.length <= 4
322
+ timeschg = values.length - 1
323
+ else
324
+ timeschg = values.length - 2
325
+ end
326
+
327
+ for i in 0..(timeschg)
328
+ day_sch.addValue(new_times[i], new_values[i])
329
+ end
330
+ runner.registerInfo("New day_sch: #{day_sch}")
331
+ runner.registerInfo("New Times: #{new_times}")
332
+ runner.registerInfo("New Values: #{new_values}")
333
+ end
334
+ end
335
+
336
+ # Report final condition of model
337
+ if apply_to_all_schedules
338
+ runner.registerFinalCondition('Shifted time for all profiles for all schedules.')
339
+ else
340
+ runner.registerFinalCondition("Shifted time for all profiles used by this schedule.")
341
+ end
342
+
343
+ # Export CSV file with Schedule setpoints after schedule shifts
344
+ #model = runner.lastOpenStudioModel
345
+ #model = model.get
346
+ interval = 60
347
+
348
+ header = []
349
+ header << 'Time'
350
+ schedules = []
351
+
352
+ model.getScheduleDays.each do |schedule|
353
+ header << schedule.name.get
354
+ schedules << schedule
355
+ end
356
+
357
+ dt = OpenStudio::Time.new(0, 0, interval, 0)
358
+ time = OpenStudio::Time.new(0, 0, 0, 0)
359
+ stop = OpenStudio::Time.new(1, 0, 0, 0)
360
+ values = []
361
+ while time <= stop
362
+ row = []
363
+ row << time.to_s
364
+ schedules.each do |schedule|
365
+ row << schedule.getValue(time)
366
+ end
367
+ values << row
368
+
369
+ time += dt
370
+ end
371
+
372
+ runner.registerInfo("Writing CSV report 'schedulereportafter.csv'")
373
+ File.open('schedulereportafter.csv', 'w') do |file|
374
+ file.puts header.join(',')
375
+ values.each do |row|
376
+ file.puts row.join(',')
377
+ end
378
+ end
379
+
380
+ return true
381
+ end
382
+ end
383
+
384
+ # Allow the measure to be used by the application
385
+ ShiftScheduleByType.new.registerWithApplication