urbanopt-reporting 0.2.1 → 0.3.4

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.
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