urbanopt-reporting 0.2.1 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -1
  3. data/LICENSE.md +1 -1
  4. data/doc_templates/LICENSE.md +1 -1
  5. data/doc_templates/copyright_erb.txt +1 -1
  6. data/doc_templates/copyright_js.txt +1 -1
  7. data/doc_templates/copyright_ruby.txt +1 -1
  8. data/docs/package-lock.json +3 -3
  9. data/docs/package.json +1 -1
  10. data/lib/measures/default_feature_reports/LICENSE.md +1 -1
  11. data/lib/measures/default_feature_reports/measure.rb +193 -59
  12. data/lib/measures/default_feature_reports/measure.xml +11 -11
  13. data/lib/measures/export_modelica_loads/LICENSE.md +27 -0
  14. data/lib/measures/export_modelica_loads/README.md +26 -0
  15. data/lib/measures/export_modelica_loads/README.md.erb +42 -0
  16. data/lib/measures/export_modelica_loads/docs/.gitkeep +0 -0
  17. data/lib/measures/export_modelica_loads/measure.rb +373 -0
  18. data/lib/measures/export_modelica_loads/measure.xml +92 -0
  19. data/lib/measures/export_modelica_loads/resources/report.html.in +13 -0
  20. data/lib/measures/export_time_series_modelica/LICENSE.md +1 -0
  21. data/lib/measures/export_time_series_modelica/README.md +59 -0
  22. data/lib/measures/export_time_series_modelica/README.md.erb +42 -0
  23. data/lib/measures/export_time_series_modelica/docs/.gitkeep +0 -0
  24. data/lib/measures/export_time_series_modelica/measure.rb +429 -0
  25. data/lib/measures/export_time_series_modelica/measure.xml +147 -0
  26. data/lib/measures/export_time_series_modelica/resources/os_lib_helper_methods.rb +399 -0
  27. data/lib/measures/export_time_series_modelica/resources/report.html.in +13 -0
  28. data/lib/urbanopt/reporting/default_reports/end_uses.rb +23 -9
  29. data/lib/urbanopt/reporting/default_reports/feature_report.rb +62 -5
  30. data/lib/urbanopt/reporting/default_reports/reporting_period.rb +42 -22
  31. data/lib/urbanopt/reporting/default_reports/scenario_report.rb +7 -4
  32. data/lib/urbanopt/reporting/default_reports/schema/scenario_csv_columns.txt +15 -0
  33. data/lib/urbanopt/reporting/default_reports/schema/scenario_schema.json +33 -5
  34. data/lib/urbanopt/reporting/version.rb +1 -1
  35. data/urbanopt-reporting-gem.gemspec +1 -1
  36. metadata +19 -4
@@ -3,8 +3,8 @@
3
3
  <schema_version>3.0</schema_version>
4
4
  <name>default_feature_reports</name>
5
5
  <uid>9ee3135a-8070-4408-bfa1-b75fecf9dd4f</uid>
6
- <version_id>1f4eb28d-d586-4c10-8d23-f3495054ce1e</version_id>
7
- <version_modified>20200921T204602Z</version_modified>
6
+ <version_id>d4f5b2e2-f93d-4ce2-9c68-ed29714fdc0c</version_id>
7
+ <version_modified>20201208T230102Z</version_modified>
8
8
  <xml_checksum>FB304155</xml_checksum>
9
9
  <class_name>DefaultFeatureReports</class_name>
10
10
  <display_name>DefaultFeatureReports</display_name>
@@ -126,17 +126,23 @@
126
126
  <usage_type>test</usage_type>
127
127
  <checksum>CC4BFFAF</checksum>
128
128
  </file>
129
+ <file>
130
+ <filename>README.md</filename>
131
+ <filetype>md</filetype>
132
+ <usage_type>readme</usage_type>
133
+ <checksum>0B68E96D</checksum>
134
+ </file>
129
135
  <file>
130
136
  <filename>LICENSE.md</filename>
131
137
  <filetype>md</filetype>
132
138
  <usage_type>license</usage_type>
133
- <checksum>D8541540</checksum>
139
+ <checksum>BBD19F47</checksum>
134
140
  </file>
135
141
  <file>
136
142
  <filename>default_feature_reports_test.rb</filename>
137
143
  <filetype>rb</filetype>
138
144
  <usage_type>test</usage_type>
139
- <checksum>A5706600</checksum>
145
+ <checksum>19681175</checksum>
140
146
  </file>
141
147
  <file>
142
148
  <version>
@@ -147,13 +153,7 @@
147
153
  <filename>measure.rb</filename>
148
154
  <filetype>rb</filetype>
149
155
  <usage_type>script</usage_type>
150
- <checksum>3C7B646E</checksum>
151
- </file>
152
- <file>
153
- <filename>README.md</filename>
154
- <filetype>md</filetype>
155
- <usage_type>readme</usage_type>
156
- <checksum>0B68E96D</checksum>
156
+ <checksum>48AEB753</checksum>
157
157
  </file>
158
158
  </files>
159
159
  </measure>
@@ -0,0 +1,27 @@
1
+ OpenStudio(R), Copyright (c) 2008-2020, 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,26 @@
1
+
2
+
3
+ ###### (Automatically generated documentation)
4
+
5
+ # Export Modelica Loads
6
+
7
+ ## Description
8
+ Use the results from the EnergyPlus simulation to generate a load file for use in Modelica. This will create a MOS and a CSV file of the heating, cooling, and hot water loads.
9
+
10
+ ## Modeler Description
11
+
12
+
13
+ ## Measure Type
14
+ ReportingMeasure
15
+
16
+ ## Taxonomy
17
+
18
+
19
+ ## Arguments
20
+
21
+
22
+
23
+
24
+ This measure does not have any user arguments
25
+
26
+
@@ -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,373 @@
1
+ # *******************************************************************************
2
+ # OpenStudio(R), Copyright (c) 2008-2020, 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
+ require 'erb'
37
+
38
+ # start the measure
39
+ class ExportModelicaLoads < OpenStudio::Measure::ReportingMeasure
40
+ # human readable name
41
+ def name
42
+ # Measure name should be the title case of the class name.
43
+ return 'Export Modelica Loads'
44
+ end
45
+
46
+ def description
47
+ return 'Use the results from the EnergyPlus simulation to generate a load file for use in Modelica. This will create a MOS and a CSV file of the heating, cooling, and hot water loads.'
48
+ end
49
+
50
+ def modeler_description
51
+ return ''
52
+ end
53
+
54
+ def log(str)
55
+ puts "#{Time.now}: #{str}"
56
+ end
57
+
58
+ def arguments(_model)
59
+ args = OpenStudio::Measure::OSArgumentVector.new
60
+
61
+ # this measure does not require any user arguments, return an empty list
62
+ return args
63
+ end
64
+
65
+ # return a vector of IdfObject's to request EnergyPlus objects needed by the run method
66
+ def energyPlusOutputRequests(runner, user_arguments)
67
+ super(runner, user_arguments)
68
+
69
+ result = OpenStudio::IdfObjectVector.new
70
+
71
+ # To use the built-in error checking we need the model...
72
+ # get the last model and sql file
73
+ model = runner.lastOpenStudioModel
74
+ if model.empty?
75
+ runner.registerError('Cannot find last model.')
76
+ return false
77
+ end
78
+ model = model.get
79
+
80
+ # use the built-in error checking
81
+ if !runner.validateUserArguments(arguments(model), user_arguments)
82
+ return false
83
+ end
84
+
85
+ result << OpenStudio::IdfObject.load('Output:Variable,,Site Mains Water Temperature,timestep;').get
86
+ result << OpenStudio::IdfObject.load('Output:Variable,,Site Outdoor Air Drybulb Temperature,timestep;').get
87
+ result << OpenStudio::IdfObject.load('Output:Variable,,Site Outdoor Air Relative Humidity,timestep;').get
88
+ result << OpenStudio::IdfObject.load('Output:Meter,Cooling:Electricity,timestep;').get
89
+ result << OpenStudio::IdfObject.load('Output:Meter,Heating:Electricity,timestep;').get
90
+ result << OpenStudio::IdfObject.load('Output:Meter,Heating:Gas,timestep;').get
91
+ result << OpenStudio::IdfObject.load('Output:Meter,InteriorLights:Electricity,timestep;').get
92
+ result << OpenStudio::IdfObject.load('Output:Meter,Fans:Electricity,timestep;').get
93
+ result << OpenStudio::IdfObject.load('Output:Meter,InteriorEquipment:Electricity,timestep;').get # Joules
94
+ result << OpenStudio::IdfObject.load('Output:Meter,ExteriorLighting:Electricity,timestep;').get # Joules
95
+ result << OpenStudio::IdfObject.load('Output:Meter,Electricity:Facility,timestep;').get # Joules
96
+ result << OpenStudio::IdfObject.load('Output:Meter,Electricity:Facility,timestep;').get ##Using this for data at timestep interval
97
+ result << OpenStudio::IdfObject.load('Output:Meter,Gas:Facility,timestep;').get # Joules
98
+ result << OpenStudio::IdfObject.load('Output:Meter,Heating:EnergyTransfer,timestep;').get # Joules
99
+ result << OpenStudio::IdfObject.load('Output:Meter,WaterSystems:EnergyTransfer,timestep;').get # Joules
100
+ # these variables are used for the modelica export.
101
+ result << OpenStudio::IdfObject.load('Output:Variable,*,Zone Predicted Sensible Load to Setpoint Heat Transfer Rate,timestep;').get # watts according to e+
102
+ result << OpenStudio::IdfObject.load('Output:Variable,*,Water Heater Total Demand Heat Transfer Rate,timestep;').get # Watts
103
+
104
+ return result
105
+ end
106
+
107
+ def extract_timeseries_into_matrix(sqlfile, data, variable_name, key_value = nil, default_if_empty = 0, timestep)
108
+ log "Executing query for #{variable_name}"
109
+ column_name = variable_name
110
+ if key_value
111
+ # ts = sqlfile.timeSeries('RUN PERIOD 1', 'Hourly', variable_name, key_value)
112
+ ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name, key_value)
113
+ column_name += "_#{key_value}"
114
+ else
115
+ # ts = sqlfile.timeSeries('RUN PERIOD 1', 'Hourly', variable_name)
116
+ ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name)
117
+ end
118
+ log 'Iterating over timeseries'
119
+ column = [column_name.delete(':').delete(' ')] # Set the header of the data to the variable name, removing : and spaces
120
+
121
+ if ts.empty?
122
+ log "No time series for #{variable_name}:#{key_value}... defaulting to #{default_if_empty}"
123
+ # needs to be data.size-1 since the column name is already stored above (+=)
124
+ column += [default_if_empty] * (data.size - 1)
125
+ else
126
+ ts = ts.get if ts.respond_to?(:get)
127
+ ts = ts.first if ts.respond_to?(:first)
128
+
129
+ start = Time.now
130
+ # Iterating in OpenStudio can take up to 60 seconds with 10min data. The quick_proc takes 0.03 seconds.
131
+ # for i in 0..ts.values.size - 1
132
+ # log "... at #{i}" if i % 10000 == 0
133
+ # column << ts.values[i]
134
+ # end
135
+
136
+ quick_proc = ts.values.to_s.split(',')
137
+
138
+ # the first and last have some cleanup items because of the Vector method
139
+ quick_proc[0] = quick_proc[0].gsub(/^.*\(/, '')
140
+ quick_proc[-1] = quick_proc[-1].delete(')')
141
+ column += quick_proc
142
+
143
+ log "Took #{Time.now - start} to iterate"
144
+ end
145
+
146
+ log 'Appending column to data'
147
+
148
+ # append the data to the end of the rows
149
+ if column.size == data.size
150
+ data.each_index do |index|
151
+ data[index] << column[index]
152
+ end
153
+ end
154
+
155
+ log "Finished extracting #{variable_name}"
156
+ end
157
+
158
+ def create_new_variable_sum(data, new_var_name, include_str, options = nil)
159
+ var_info = {
160
+ name: new_var_name,
161
+ var_indexes: []
162
+ }
163
+ data.each_with_index do |row, index|
164
+ if index.zero?
165
+ # Get the index of the columns to add
166
+ row.each do |c|
167
+ if c.include? include_str
168
+ var_info[:var_indexes] << row.index(c)
169
+ end
170
+ end
171
+
172
+ # add the new var to the header row
173
+ data[0] << var_info[:name]
174
+ else
175
+ # sum the values
176
+ sum = 0
177
+ var_info[:var_indexes].each do |var|
178
+ temp_v = row[var].to_f
179
+ if options.nil?
180
+ sum += temp_v
181
+ elsif options[:positive_only] && temp_v > 0
182
+ sum += temp_v
183
+ elsif options[:negative_only] && temp_v < 0
184
+ sum += temp_v
185
+ end
186
+ end
187
+
188
+ # Also round the data here, because we don't need 10 decimals
189
+ data[index] << sum.round(1)
190
+ end
191
+ end
192
+ end
193
+
194
+ def run(runner, user_arguments)
195
+ super(runner, user_arguments)
196
+
197
+ # get the last model and sql file
198
+ model = runner.lastOpenStudioModel
199
+ if model.empty?
200
+ runner.registerError('Cannot find last model.')
201
+ return false
202
+ end
203
+ model = model.get
204
+
205
+ # use the built-in error checking
206
+ return false unless runner.validateUserArguments(arguments(model), user_arguments)
207
+
208
+ # get the last model and sql file
209
+ model = runner.lastOpenStudioModel
210
+ if model.empty?
211
+ runner.registerError('Cannot find last model.')
212
+ return false
213
+ end
214
+ model = model.get
215
+
216
+ timesteps_per_hour=model.getTimestep.numberOfTimestepsPerHour.to_i
217
+ timestep=60/timesteps_per_hour #timestep in minutes
218
+
219
+ sqlFile = runner.lastEnergyPlusSqlFile
220
+ if sqlFile.empty?
221
+ runner.registerError('Cannot find last sql file.')
222
+ return false
223
+ end
224
+ sqlFile = sqlFile.get
225
+ model.setSqlFile(sqlFile)
226
+
227
+ # create a new csv with the values and save to the reports directory.
228
+ # assumptions:
229
+ # - all the variables exist
230
+ # - data are the same length
231
+
232
+ # initialize the rows with the header
233
+ log 'Starting to process Timeseries data'
234
+ # Initial header row
235
+ rows = [
236
+ ['Date Time', 'Month', 'Day', 'Day of Week', 'Hour', 'Minute', 'SecondsFromStart']
237
+ ]
238
+
239
+ # just grab one of the variables to get the date/time stamps
240
+ attribute_name = 'Electricity:Facility'
241
+ ts = sqlFile.timeSeries('RUN PERIOD 1', 'Zone Timestep', attribute_name)
242
+ if ts.empty?
243
+ runner.registerError("This feature does not have the attribute '#{attribute_name}' to enable this measure to work." \
244
+ "To resolve, simulate a building with electricity or remove this measure from your workflow.")
245
+ else
246
+ ts = ts.first
247
+ dt_base = nil
248
+ # Save off the date time values
249
+ ts.dateTimes.each_with_index do |dt, index|
250
+ dt_base = DateTime.parse(dt.to_s) if dt_base.nil?
251
+ dt_current = DateTime.parse(dt.to_s)
252
+ rows << [
253
+ DateTime.parse(dt.to_s).strftime('%m/%d/%Y %H:%M'),
254
+ dt.date.monthOfYear.value,
255
+ dt.date.dayOfMonth,
256
+ dt.date.dayOfWeek.value,
257
+ dt.time.hours,
258
+ dt.time.minutes,
259
+ dt_current.to_time.to_i - dt_base.to_time.to_i + timestep*60
260
+ ]
261
+ end
262
+ end
263
+
264
+ # add in the other variables by columns -- should really pull this from the report variables defined above
265
+ extract_timeseries_into_matrix(sqlFile, rows, 'Site Outdoor Air Drybulb Temperature', 'Environment', 0, timestep)
266
+ extract_timeseries_into_matrix(sqlFile, rows, 'Site Outdoor Air Relative Humidity', 'Environment', 0, timestep)
267
+ extract_timeseries_into_matrix(sqlFile, rows, 'Heating:Electricity', nil, 0, timestep)
268
+ extract_timeseries_into_matrix(sqlFile, rows, 'Heating:Gas', nil, 0, timestep)
269
+ extract_timeseries_into_matrix(sqlFile, rows, 'Cooling:Electricity', nil, 0, timestep)
270
+ extract_timeseries_into_matrix(sqlFile, rows, 'Electricity:Facility', nil, 0, timestep)
271
+ extract_timeseries_into_matrix(sqlFile, rows, 'Gas:Facility', nil, 0, timestep)
272
+ extract_timeseries_into_matrix(sqlFile, rows, 'Heating:EnergyTransfer', nil, 0, timestep)
273
+ extract_timeseries_into_matrix(sqlFile, rows, 'WaterSystems:EnergyTransfer', nil, 0, timestep)
274
+
275
+ # get all zones and save the names for later use in aggregation.
276
+ tz_names = []
277
+ model.getThermalZones.each do |tz|
278
+ tz_names << tz.name.get if tz.name.is_initialized
279
+ extract_timeseries_into_matrix(sqlFile, rows, 'Zone Predicted Sensible Load to Setpoint Heat Transfer Rate', tz_names.last, 0, timestep)
280
+ extract_timeseries_into_matrix(sqlFile, rows, 'Water Heater Heating Rate', tz_names.last, 0, timestep)
281
+ end
282
+
283
+ # sum up a couple of the columns and create a new columns
284
+ create_new_variable_sum(rows, 'TotalSensibleLoad', 'ZonePredictedSensibleLoadtoSetpointHeatTransferRate')
285
+ create_new_variable_sum(rows, 'TotalCoolingSensibleLoad', 'ZonePredictedSensibleLoadtoSetpointHeatTransferRate', negative_only: true)
286
+ create_new_variable_sum(rows, 'TotalHeatingSensibleLoad', 'ZonePredictedSensibleLoadtoSetpointHeatTransferRate', positive_only: true)
287
+ create_new_variable_sum(rows, 'TotalWaterHeating', 'WaterHeaterHeatingRate')
288
+
289
+ # convert this to CSV object
290
+ File.open('./building_loads.csv', 'w') do |f|
291
+ rows.each do |row|
292
+ f << row.join(',') << "\n"
293
+ end
294
+ end
295
+
296
+ # covert the row data into the format needed by modelica
297
+ modelica_data = [['seconds', 'cooling', 'heating', 'waterheating']]
298
+ seconds_index = nil
299
+ total_water_heating_index = nil
300
+ total_cooling_sensible_index = nil
301
+ total_heating_sensible_index = nil
302
+ peak_cooling = 0
303
+ peak_heating = 0
304
+ peak_water_heating = 0
305
+ rows.each_with_index do |row, index|
306
+ if index.zero?
307
+ seconds_index = row.index('SecondsFromStart')
308
+ total_cooling_sensible_index = row.index('TotalCoolingSensibleLoad')
309
+ total_heating_sensible_index = row.index('TotalHeatingSensibleLoad')
310
+ total_water_heating_index = row.index('TotalWaterHeating')
311
+ else
312
+ new_data = [
313
+ row[seconds_index],
314
+ row[total_cooling_sensible_index],
315
+ row[total_heating_sensible_index],
316
+ row[total_water_heating_index]
317
+ ]
318
+
319
+ modelica_data << new_data
320
+
321
+ # store the peaks
322
+ peak_cooling = row[total_cooling_sensible_index] if row[total_cooling_sensible_index] < peak_cooling
323
+ peak_heating = row[total_heating_sensible_index] if row[total_heating_sensible_index] > peak_heating
324
+ peak_water_heating = row[total_water_heating_index] if row[total_water_heating_index] > peak_water_heating
325
+ end
326
+ end
327
+
328
+ File.open('./modelica.mos', 'w') do |f|
329
+ f << "#1\n"
330
+ f << "#Heating and Cooling Model loads from OpenStudio Prototype Buildings\n"
331
+ f << "# Building Type: {{BUILDINGTYPE}}\n"
332
+ f << "# Climate Zone: {{CLIMATEZONE}}\n"
333
+ f << "# Vintage: {{VINTAGE}}\n"
334
+ f << "# Simulation ID (for debugging): {{SIMID}}\n"
335
+ f << "# URL: https://github.com/urbanopt/openstudio-prototype-loads\n"
336
+ f << "\n"
337
+ f << "#First column: Seconds in the year (loads are hourly)\n"
338
+ f << "#Second column: cooling loads in Watts (as negative numbers).\n"
339
+ f << "#Third column: space heating loads in Watts\n"
340
+ f << "#Fourth column: water heating in Watts\n"
341
+ f << "\n"
342
+ f << "#Peak space cooling load = #{peak_cooling} Watts\n"
343
+ f << "#Peak space heating load = #{peak_heating} Watts\n"
344
+ f << "#Peak water heating load = #{peak_water_heating} Watts\n"
345
+ f << "double tab1(8760,4)\n"
346
+ modelica_data.each_with_index do |row, index|
347
+ next if index.zero?
348
+ f << row.join(';') << "\n"
349
+ end
350
+ end
351
+
352
+ # Find the total runtime for energyplus and save it into a registerValue
353
+ total_time = -999
354
+ location_of_file = ['../eplusout.end', './run/eplusout.end']
355
+ first_index = location_of_file.map { |f| File.exist?(f) }.index(true)
356
+ if first_index
357
+ match = File.read(location_of_file[first_index]).to_s.match(/Elapsed.Time=(.*)hr(.*)min(.*)sec/)
358
+ total_time = match[1].to_i * 3600 + match[2].to_i * 60 + match[3].to_f
359
+ end
360
+
361
+ runner.registerValue('energyplus_runtime', total_time, 'sec')
362
+ runner.registerValue('peak_cooling_load', peak_cooling, 'W')
363
+ runner.registerValue('peak_heating_load', peak_heating, 'W')
364
+ runner.registerValue('peak_water_heating', peak_water_heating, 'W')
365
+
366
+ return true
367
+ ensure
368
+ sqlFile.close if sqlFile
369
+ end
370
+ end
371
+
372
+ # register the measure to be used by the application
373
+ ExportModelicaLoads.new.registerWithApplication