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
@@ -0,0 +1,92 @@
1
+ <?xml version="1.0"?>
2
+ <measure>
3
+ <schema_version>3.0</schema_version>
4
+ <name>export_modelica_loads</name>
5
+ <uid>7051db01-2e55-4223-b5b5-fee615b68dd0</uid>
6
+ <version_id>7782f28c-19e6-449d-8cf3-e3f915550ebd</version_id>
7
+ <version_modified>20201203T151454Z</version_modified>
8
+ <xml_checksum>2C8A3EEF</xml_checksum>
9
+ <class_name>ExportModelicaLoads</class_name>
10
+ <display_name>Export Modelica Loads</display_name>
11
+ <description>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.</description>
12
+ <modeler_description></modeler_description>
13
+ <arguments />
14
+ <outputs />
15
+ <provenances />
16
+ <tags>
17
+ <tag>Reporting.QAQC</tag>
18
+ </tags>
19
+ <attributes>
20
+ <attribute>
21
+ <name>Measure Type</name>
22
+ <value>ReportingMeasure</value>
23
+ <datatype>string</datatype>
24
+ </attribute>
25
+ <attribute>
26
+ <name>Uses SketchUp API</name>
27
+ <value>false</value>
28
+ <datatype>boolean</datatype>
29
+ </attribute>
30
+ </attributes>
31
+ <files>
32
+ <file>
33
+ <filename>README.md.erb</filename>
34
+ <filetype>erb</filetype>
35
+ <usage_type>readmeerb</usage_type>
36
+ <checksum>703C9964</checksum>
37
+ </file>
38
+ <file>
39
+ <filename>.gitkeep</filename>
40
+ <filetype>gitkeep</filetype>
41
+ <usage_type>doc</usage_type>
42
+ <checksum>00000000</checksum>
43
+ </file>
44
+ <file>
45
+ <filename>export_modelica_loads_test.rb</filename>
46
+ <filetype>rb</filetype>
47
+ <usage_type>test</usage_type>
48
+ <checksum>83EC81AC</checksum>
49
+ </file>
50
+ <file>
51
+ <filename>example_model.osm</filename>
52
+ <filetype>osm</filetype>
53
+ <usage_type>test</usage_type>
54
+ <checksum>39B6E26C</checksum>
55
+ </file>
56
+ <file>
57
+ <filename>USA_CO_Golden-NREL.724666_TMY3.epw</filename>
58
+ <filetype>epw</filetype>
59
+ <usage_type>test</usage_type>
60
+ <checksum>BDF687C1</checksum>
61
+ </file>
62
+ <file>
63
+ <filename>report.html.in</filename>
64
+ <filetype>in</filetype>
65
+ <usage_type>resource</usage_type>
66
+ <checksum>3F69E3FB</checksum>
67
+ </file>
68
+ <file>
69
+ <filename>LICENSE.md</filename>
70
+ <filetype>md</filetype>
71
+ <usage_type>license</usage_type>
72
+ <checksum>E0468DD6</checksum>
73
+ </file>
74
+ <file>
75
+ <filename>README.md</filename>
76
+ <filetype>md</filetype>
77
+ <usage_type>readme</usage_type>
78
+ <checksum>544E6A47</checksum>
79
+ </file>
80
+ <file>
81
+ <version>
82
+ <software_program>OpenStudio</software_program>
83
+ <identifier>3.0.1</identifier>
84
+ <min_compatible>3.0.1</min_compatible>
85
+ </version>
86
+ <filename>measure.rb</filename>
87
+ <filetype>rb</filetype>
88
+ <usage_type>script</usage_type>
89
+ <checksum>AE19F661</checksum>
90
+ </file>
91
+ </files>
92
+ </measure>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>ReportingMeasure</title>
6
+ <link href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet">
7
+ <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
8
+ <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.3.9/d3.min.js"></script>
9
+ </head>
10
+ <body>
11
+ <%= output %>
12
+ </body>
13
+ </html>
@@ -0,0 +1 @@
1
+ Insert your license here
@@ -0,0 +1,59 @@
1
+
2
+
3
+ ###### (Automatically generated documentation)
4
+
5
+ # ExportTimeSeriesLoadsCSV
6
+
7
+ ## Description
8
+ This measure will add the required output variables and create a CSV file with plant loop level mass flow rates and temperatures for use in a Modelica simulation. Note that this measure has certain
9
+ requirements for naming of hydronic loops (discussed in the modeler description section).
10
+
11
+ ## Modeler Description
12
+ This measure is currently configured to report the temperatures and mass flow rates at the demand outlet and inlet nodes of hot water and chilled water loops, after adding the required output variables to the model. These values can be used to calculate the sum of the demand-side loads, and could thus represent the load on a connection to a district thermal energy system, or on
13
+ building-level primary equipment. This measure assumes that the model includes hydronic HVAC loops, and that the hot water and chilled water loop names can each be uniquely identified by a user-provided string. This measure also assumes that there is a single heating hot water loop
14
+ and a single chilled-water loop per building.
15
+
16
+ ## Measure Type
17
+ ReportingMeasure
18
+
19
+ ## Taxonomy
20
+
21
+
22
+ ## Arguments
23
+
24
+
25
+ ### Name or Partial Name of Heating Hot Water Loop, non-case-sensitive
26
+
27
+ **Name:** hhw_loop_name,
28
+ **Type:** String,
29
+ **Units:** ,
30
+ **Required:** true,
31
+ **Model Dependent:** false
32
+
33
+ ### Name or Partial Name of Chilled Water Loop, non-case-sensitive
34
+
35
+ **Name:** chw_loop_name,
36
+ **Type:** String,
37
+ **Units:** ,
38
+ **Required:** true,
39
+ **Model Dependent:** false
40
+
41
+ ### Number of Decimal Places to Round Mass Flow Rate
42
+ Number of decimal places to which mass flow rate will be rounded
43
+ **Name:** dec_places_mass_flow,
44
+ **Type:** Integer,
45
+ **Units:** ,
46
+ **Required:** true,
47
+ **Model Dependent:** false
48
+
49
+ ### Number of Decimal Places to Round Temperature
50
+ Number of decimal places to which temperature will be rounded
51
+ **Name:** dec_places_temp,
52
+ **Type:** Integer,
53
+ **Units:** ,
54
+ **Required:** true,
55
+ **Model Dependent:** false
56
+
57
+
58
+
59
+
@@ -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,429 @@
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
+
39
+ # start the measure
40
+ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
41
+ Dir[File.dirname(__FILE__) + '/resources/*.rb'].each { |file| require file }
42
+ include OsLib_HelperMethods
43
+ # human readable name
44
+ def name
45
+ # Measure name should be the title case of the class name.
46
+ 'ExportTimeSeriesLoadsCSV'
47
+ end
48
+
49
+ def description
50
+ 'This measure will add the required output variables and create a CSV file with plant loop level mass flow rates and temperatures for use in a Modelica simulation. Note that this measure has certain
51
+ requirements for naming of hydronic loops (discussed in the modeler description section).'
52
+ end
53
+
54
+ def modeler_description
55
+ 'This measure is currently configured to report the temperatures and mass flow rates at the demand outlet and inlet nodes of hot water and chilled water loops, after adding the required output variables to the model. These values can be used to calculate the sum of the demand-side loads, and could thus represent the load on a connection to a district thermal energy system, or on
56
+ building-level primary equipment. This measure assumes that the model includes hydronic HVAC loops, and that the hot water and chilled water loop names can each be uniquely identified by a user-provided string. This measure also assumes that there is a single heating hot water loop
57
+ and a single chilled-water loop per building.'
58
+ end
59
+
60
+ def log(str)
61
+ puts "#{Time.now}: #{str}"
62
+ end
63
+
64
+ def arguments(_model)
65
+ args = OpenStudio::Measure::OSArgumentVector.new
66
+
67
+ hhw_loop_name = OpenStudio::Measure::OSArgument.makeStringArgument('hhw_loop_name', true)
68
+ hhw_loop_name.setDisplayName('Name or Partial Name of Heating Hot Water Loop, non-case-sensitive')
69
+ hhw_loop_name.setDefaultValue('hot')
70
+ args << hhw_loop_name
71
+
72
+ chw_loop_name = OpenStudio::Measure::OSArgument.makeStringArgument('chw_loop_name', true)
73
+ chw_loop_name.setDisplayName('Name or Partial Name of Chilled Water Loop, non-case-sensitive')
74
+ chw_loop_name.setDefaultValue('chilled')
75
+ args << chw_loop_name
76
+
77
+ dec_places_mass_flow = OpenStudio::Measure::OSArgument.makeIntegerArgument('dec_places_mass_flow', true)
78
+ dec_places_mass_flow.setDisplayName('Number of Decimal Places to Round Mass Flow Rate')
79
+ dec_places_mass_flow.setDescription('Number of decimal places to which mass flow rate will be rounded')
80
+ dec_places_mass_flow.setDefaultValue(3)
81
+ args << dec_places_mass_flow
82
+
83
+ dec_places_temp = OpenStudio::Measure::OSArgument.makeIntegerArgument('dec_places_temp', true)
84
+ dec_places_temp.setDisplayName('Number of Decimal Places to Round Temperature')
85
+ dec_places_temp.setDescription('Number of decimal places to which temperature will be rounded')
86
+ dec_places_temp.setDefaultValue(1)
87
+ args << dec_places_temp
88
+
89
+ return args
90
+ end
91
+
92
+ # return a vector of IdfObject's to request EnergyPlus objects needed by the run method
93
+ def energyPlusOutputRequests(runner, user_arguments)
94
+ super(runner, user_arguments)
95
+
96
+ result = OpenStudio::IdfObjectVector.new
97
+
98
+ # To use the built-in error checking we need the model...
99
+ # get the last model and sql file
100
+ model = runner.lastOpenStudioModel
101
+ if model.empty?
102
+ runner.registerError('Cannot find last model.')
103
+ return false
104
+ end
105
+ model = model.get
106
+
107
+ # use the built-in error checking
108
+ return false unless runner.validateUserArguments(arguments(model), user_arguments)
109
+
110
+ ##Read in argumetns related to variables for output requests
111
+ hhw_loop_name = runner.getStringArgumentValue('hhw_loop_name', user_arguments)
112
+ chw_loop_name = runner.getStringArgumentValue('chw_loop_name', user_arguments)
113
+
114
+ #Identify key names for output variables.
115
+ plantloops = model.getPlantLoops
116
+
117
+ selected_plant_loops = []
118
+ i = 0
119
+
120
+ variable_name1 = 'System Node Mass Flow Rate'
121
+ variable_name2 = 'System Node Temperature'
122
+ reporting_frequency = 'timestep'
123
+
124
+ plantloops.each do |plantLoop|
125
+ log "plant loop name #{plantLoop.name.get.to_s}"
126
+ if plantLoop.name.get.to_s.downcase.include? chw_loop_name.to_s
127
+ #Extract plant loop information
128
+ selected_plant_loops[0]=plantLoop
129
+ key_value_chw_outlet = selected_plant_loops[0].demandOutletNode.name.to_s
130
+ key_value_chw_inlet = selected_plant_loops[0].demandInletNode.name.to_s
131
+ result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_chw_outlet},#{variable_name2},timestep;").get
132
+ result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_chw_inlet},#{variable_name2},timestep;").get
133
+ result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_chw_outlet},#{variable_name1},timestep;").get
134
+ end
135
+ if plantLoop.name.get.to_s.downcase.include? hhw_loop_name.to_s and !plantLoop.name.get.to_s.downcase.include? "service" and !plantLoop.name.get.to_s.downcase.include? "domestic"
136
+ #Extract plant loop information
137
+ selected_plant_loops[1]=plantLoop
138
+ key_value_hhw_outlet = selected_plant_loops[1].demandOutletNode.name.to_s
139
+ key_value_hhw_inlet = selected_plant_loops[1].demandInletNode.name.to_s
140
+ result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_hhw_outlet},#{variable_name2},timestep;").get
141
+ result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_hhw_inlet},#{variable_name2},timestep;").get
142
+ result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_hhw_outlet},#{variable_name1},timestep;").get
143
+ end
144
+ end
145
+
146
+ result << OpenStudio::IdfObject.load('Output:Variable,,Site Mains Water Temperature,hourly;').get
147
+ result << OpenStudio::IdfObject.load('Output:Variable,,Site Outdoor Air Drybulb Temperature,hourly;').get
148
+ result << OpenStudio::IdfObject.load('Output:Variable,,Site Outdoor Air Relative Humidity,hourly;').get
149
+ result << OpenStudio::IdfObject.load('Output:Meter,Cooling:Electricity,hourly;').get
150
+ result << OpenStudio::IdfObject.load('Output:Meter,Electricity:Facility,timestep;').get ##Using this for data at timestep interval
151
+ result << OpenStudio::IdfObject.load('Output:Meter,Heating:Electricity,hourly;').get
152
+ result << OpenStudio::IdfObject.load('Output:Meter,Heating:Gas,hourly;').get
153
+ result << OpenStudio::IdfObject.load('Output:Meter,InteriorLights:Electricity,hourly;').get
154
+ result << OpenStudio::IdfObject.load('Output:Meter,Fans:Electricity,hourly;').get
155
+ result << OpenStudio::IdfObject.load('Output:Meter,InteriorEquipment:Electricity,hourly;').get # Joules
156
+ result << OpenStudio::IdfObject.load('Output:Meter,ExteriorLighting:Electricity,hourly;').get # Joules
157
+ result << OpenStudio::IdfObject.load('Output:Meter,Electricity:Facility,hourly;').get # Joules
158
+ result << OpenStudio::IdfObject.load('Output:Meter,Gas:Facility,hourly;').get # Joules
159
+ result << OpenStudio::IdfObject.load('Output:Meter,Heating:EnergyTransfer,hourly;').get # Joules
160
+ result << OpenStudio::IdfObject.load('Output:Meter,WaterSystems:EnergyTransfer,hourly;').get # Joules
161
+ # these variables are used for the modelica export.
162
+ result << OpenStudio::IdfObject.load('Output:Variable,*,Zone Predicted Sensible Load to Setpoint Heat Transfer Rate,hourly;').get # watts according to e+
163
+ result << OpenStudio::IdfObject.load('Output:Variable,*,Water Heater Total Demand Heat Transfer Rate,hourly;').get # Watts
164
+
165
+ result
166
+ end
167
+
168
+ def extract_timeseries_into_matrix(sqlfile, data, variable_name, str, key_value = nil, default_if_empty = 0,dec_places, timestep)
169
+ log "Executing query for #{variable_name}"
170
+ #column_name = variable_name
171
+ if key_value
172
+ ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name, key_value)
173
+ #column_name += "_#{key_value}"
174
+ column_name=str
175
+ else
176
+ #ts = sqlfile.timeSeries('RUN PERIOD 1', 'Hourly', variable_name)
177
+ ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name)
178
+ end
179
+ log 'Iterating over timeseries'
180
+ column = [column_name.delete(':').delete(' ')] # Set the header of the data to the variable name, removing : and spaces
181
+
182
+ if ts.empty?
183
+ log "No time series for #{variable_name}:#{key_value}... defaulting to #{default_if_empty}"
184
+ # needs to be data.size-1 since the column name is already stored above (+=)
185
+ column += [default_if_empty] * (data.size - 1)
186
+ else
187
+ ts = ts.get if ts.respond_to?(:get)
188
+ ts = ts.first if ts.respond_to?(:first)
189
+
190
+ start = Time.now
191
+ # Iterating in OpenStudio can take up to 60 seconds with 10min data. The quick_proc takes 0.03 seconds.
192
+ # for i in 0..ts.values.size - 1
193
+ # log "... at #{i}" if i % 10000 == 0
194
+ # column << ts.values[i]
195
+ # end
196
+
197
+ quick_proc = ts.values.to_s.split(',')
198
+ quick_proc[0]=quick_proc[0].split('(', 2).last #cleanup necessary to remove opening paren
199
+ quick_proc=quick_proc.map(&:to_f)
200
+ x = 0
201
+ len = quick_proc.length
202
+ log "quick proc #{quick_proc}"
203
+ while(x < len) #Round to the # of decimal places specified
204
+ quick_proc[x]=(quick_proc[x]).round(dec_places)
205
+ x=x+1
206
+ end
207
+ quick_proc=quick_proc.map(&:to_s)
208
+
209
+ # the first and last have some cleanup items because of the Vector method
210
+ quick_proc[0] = quick_proc[0].gsub(/^.*\(/, '')
211
+ quick_proc[-1] = quick_proc[-1].delete(')')
212
+ column += quick_proc
213
+
214
+ log "Took #{Time.now - start} to iterate"
215
+ end
216
+
217
+ log 'Appending column to data'
218
+
219
+ # append the data to the end of the rows
220
+ if column.size == data.size
221
+ data.each_index do |index|
222
+ data[index] << column[index]
223
+ end
224
+ end
225
+
226
+ log "Finished extracting #{variable_name}"
227
+ end
228
+
229
+ def create_new_variable_sum(data, new_var_name, include_str, options=nil)
230
+ var_info = {
231
+ name: new_var_name,
232
+ var_indexes: []
233
+ }
234
+ data.each_with_index do |row, index|
235
+ if index.zero?
236
+ # Get the index of the columns to add
237
+ row.each do |c|
238
+ var_info[:var_indexes] << row.index(c) if c.include? include_str
239
+ end
240
+
241
+ # add the new var to the header row
242
+ data[0] << var_info[:name]
243
+ else
244
+ # sum the values
245
+ sum = 0
246
+ var_info[:var_indexes].each do |var|
247
+ temp_v = row[var].to_f
248
+ if options.nil?
249
+ sum += temp_v
250
+ elsif options[:positive_only] && temp_v > 0
251
+ sum += temp_v
252
+ elsif options[:negative_only] && temp_v < 0
253
+ sum += temp_v
254
+ end
255
+ end
256
+ data[index] << sum
257
+ end
258
+ end
259
+ end
260
+
261
+ def run(runner, user_arguments)
262
+ super(runner, user_arguments)
263
+
264
+ # get the last model and sql file
265
+ model = runner.lastOpenStudioModel
266
+ if model.empty?
267
+ runner.registerError('Cannot find last model.')
268
+ return false
269
+ end
270
+ model = model.get
271
+
272
+ # use the built-in error checking
273
+ return false unless runner.validateUserArguments(arguments(model), user_arguments)
274
+
275
+ args = OsLib_HelperMethods.createRunVariables(runner, model, user_arguments, arguments(model))
276
+ if !args
277
+ return false
278
+ end
279
+
280
+ # lookup and replace argument values from upstream measures
281
+ if args['use_upstream_args'] == true
282
+ args.each do |arg,value|
283
+ next if arg == 'use_upstream_args' # this argument should not be changed
284
+ value_from_osw = OsLib_HelperMethods.check_upstream_measure_for_arg(runner, arg)
285
+ if !value_from_osw.empty?
286
+ runner.registerInfo("Replacing argument named #{arg} from current measure with a value of #{value_from_osw[:value]} from #{value_from_osw[:measure_name]}.")
287
+ new_val = value_from_osw[:value]
288
+ # TODO: make code to handle non strings more robust. check_upstream_measure_for_arg could pass back the argument type
289
+ if arg == 'hhw_loop_name'
290
+ args[arg] = new_val.to_s
291
+ elsif arg == 'chw_loop_name'
292
+ args[arg] = new_val.to_s
293
+ else
294
+ args[arg] = new_val
295
+ end
296
+ end
297
+ end
298
+ end
299
+ hhw_loop_name = args['hhw_loop_name']
300
+ chw_loop_name = args['chw_loop_name']
301
+ dec_places_temp = args['dec_places_temp']
302
+ dec_places_mass_flow = args['dec_places_mass_flow']
303
+ # get the last model and sql file
304
+ model = runner.lastOpenStudioModel
305
+ if model.empty?
306
+ runner.registerError('Cannot find last model.')
307
+ return false
308
+ end
309
+ model = model.get
310
+
311
+ timesteps_per_hour=model.getTimestep.numberOfTimestepsPerHour.to_i
312
+ timestep=60/timesteps_per_hour #timestep in minutes
313
+
314
+ sqlFile = runner.lastEnergyPlusSqlFile
315
+ if sqlFile.empty?
316
+ runner.registerError('Cannot find last sql file.')
317
+ return false
318
+ end
319
+ sqlFile = sqlFile.get
320
+ model.setSqlFile(sqlFile)
321
+
322
+ # create a new csv with the values and save to the reports directory.
323
+ # assumptions:
324
+ # - all the variables exist
325
+ # - data are the same length
326
+
327
+ # initialize the rows with the header
328
+ log 'Starting to process Timeseries data'
329
+ # Initial header row
330
+ rows = [
331
+ ['Date Time', 'Month', 'Day', 'Day of Week', 'Hour', 'Minute', 'SecondsFromStart']
332
+ ]
333
+
334
+ # just grab one of the variables to get the date/time stamps
335
+ attribute_name = 'Electricity:Facility'
336
+ ts = sqlFile.timeSeries('RUN PERIOD 1', 'Zone Timestep', attribute_name)
337
+ if ts.empty?
338
+ runner.registerError("This feature does not have the attribute '#{attribute_name}' to enable this measure to work." \
339
+ "To resolve, simulate a building with electricity or remove this measure from your workflow.")
340
+ else
341
+ ts = ts.first
342
+ dt_base = nil
343
+ # Save off the date time values
344
+ ts.dateTimes.each_with_index do |dt, index|
345
+ dt_base = DateTime.parse(dt.to_s) if dt_base.nil?
346
+ dt_current = DateTime.parse(dt.to_s)
347
+ rows << [
348
+ DateTime.parse(dt.to_s).strftime('%m/%d/%Y %H:%M'),
349
+ dt.date.monthOfYear.value,
350
+ dt.date.dayOfMonth,
351
+ dt.date.dayOfWeek.value,
352
+ dt.time.hours,
353
+ dt.time.minutes,
354
+ dt_current.to_time.to_i - dt_base.to_time.to_i + timestep*60
355
+ ]
356
+ end
357
+ end
358
+
359
+ plantloops = model.getPlantLoops
360
+
361
+ selected_plant_loops = []
362
+ i = 0
363
+
364
+ key_var={}
365
+
366
+ plantloops.each do |plantLoop|
367
+ if plantLoop.name.get.to_s.downcase.include? chw_loop_name.to_str
368
+ #Extract plant loop information
369
+ selected_plant_loops[0]=plantLoop
370
+ end
371
+ if plantLoop.name.get.to_s.downcase.include? hhw_loop_name.to_str
372
+ #Get plant loop information
373
+ selected_plant_loops[1]=plantLoop
374
+ end
375
+ end
376
+
377
+ if !selected_plant_loops[1].nil?
378
+ #Set up variables for output
379
+ key_value_hhw_outlet = selected_plant_loops[1].demandOutletNode.name.to_s
380
+ key_value_hhw_inlet = selected_plant_loops[1].demandInletNode.name.to_s
381
+ key_var['hhw_outlet_massflow']='massFlowRateHeating'
382
+ key_var['hhw_outlet_temp']='heatingReturnTemperature[C]'
383
+ key_var['hhw_inlet_temp']='heatingSupplyTemperature[C]'
384
+ #Extract time series
385
+ extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['hhw_outlet_temp'], key_value_hhw_outlet, 0, dec_places_temp, timestep)
386
+ extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['hhw_inlet_temp'], key_value_hhw_inlet, 0, dec_places_temp, timestep)
387
+ extract_timeseries_into_matrix(sqlFile, rows, 'System Node Mass Flow Rate', key_var['hhw_outlet_massflow'], key_value_hhw_outlet, 0, dec_places_mass_flow, timestep)
388
+ else
389
+ runner.registerWarning("No hot water loop found. If one is expected, make sure the hot water loop name argument provides a string present in its name.")
390
+ end
391
+
392
+ if !selected_plant_loops[0].nil?
393
+ #Set up variables for outputs
394
+ key_value_chw_outlet = selected_plant_loops[0].demandOutletNode.name.to_s
395
+ key_value_chw_inlet = selected_plant_loops[0].demandInletNode.name.to_s
396
+ key_var['chw_outlet_massflow']='massFlowRateCooling'
397
+ key_var['chw_outlet_temp']='ChilledWaterReturnTemperature[C]'
398
+ key_var['chw_inlet_temp']='ChilledWaterSupplyTemperature[C]'
399
+ #Extract time series
400
+ extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['chw_outlet_temp'], key_value_chw_outlet, 0, dec_places_temp,timestep)
401
+ extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['chw_inlet_temp'], key_value_chw_inlet, 0, dec_places_temp,timestep)
402
+ extract_timeseries_into_matrix(sqlFile, rows, 'System Node Mass Flow Rate', key_var['chw_outlet_massflow'], key_value_chw_outlet, 0, dec_places_mass_flow,timestep)
403
+ else
404
+ runner.registerWarning("No chilled water loop found. If one is expected, make sure the chilled water loop name argument provides a string present in its name.")
405
+ end
406
+
407
+
408
+ if selected_plant_loops[0].nil? and selected_plant_loops[1].nil?
409
+ runner.registerWarning("No HVAC plant loops found. If one or more plant loops are expected, make sure they follow the naming conventions mentioned in the previous warnings.")
410
+ end
411
+
412
+ if !selected_plant_loops.nil?
413
+ # convert this to CSV object
414
+ File.open('./building_loads.csv', 'w') do |f|
415
+ rows.each do |row|
416
+ f << row.join(',') << "\n"
417
+ end
418
+ end
419
+ end
420
+
421
+ true
422
+ ensure
423
+ sqlFile&.close
424
+ end
425
+ end
426
+
427
+
428
+ # register the measure to be used by the application
429
+ ExportTimeSeriesLoadsCSV.new.registerWithApplication