urbanopt-reporting 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,433 @@
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
+
99
+ # To use the built-in error checking we need the model...
100
+ # get the last model and sql file
101
+ model = runner.lastOpenStudioModel
102
+ if model.empty?
103
+ runner.registerError('Cannot find last model.')
104
+ return false
105
+ end
106
+ model = model.get
107
+
108
+ # use the built-in error checking
109
+ return false unless runner.validateUserArguments(arguments(model), user_arguments)
110
+
111
+ ##Read in argumetns related to variables for output requests
112
+ hhw_loop_name = runner.getStringArgumentValue('hhw_loop_name', user_arguments)
113
+ chw_loop_name = runner.getStringArgumentValue('chw_loop_name', user_arguments)
114
+
115
+
116
+ #Identify key names for output variables.
117
+ plantloops = model.getPlantLoops
118
+
119
+ selected_plant_loops = []
120
+ i = 0
121
+
122
+ variable_name1 = 'System Node Mass Flow Rate'
123
+ variable_name2 = 'System Node Temperature'
124
+ reporting_frequency = 'timestep'
125
+
126
+
127
+ plantloops.each do |plantLoop|
128
+ log "plant loop name #{plantLoop.name.get.to_s}"
129
+ if plantLoop.name.get.to_s.downcase.include? chw_loop_name.to_s
130
+ #Extract plant loop information
131
+ selected_plant_loops[0]=plantLoop
132
+ key_value_chw_outlet = selected_plant_loops[0].demandOutletNode.name.to_s
133
+ key_value_chw_inlet = selected_plant_loops[0].demandInletNode.name.to_s
134
+ result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_chw_outlet},#{variable_name2},timestep;").get
135
+ result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_chw_inlet},#{variable_name2},timestep;").get
136
+ result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_chw_outlet},#{variable_name1},timestep;").get
137
+ end
138
+ 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"
139
+ #Extract plant loop information
140
+ selected_plant_loops[1]=plantLoop
141
+ key_value_hhw_outlet = selected_plant_loops[1].demandOutletNode.name.to_s
142
+ key_value_hhw_inlet = selected_plant_loops[1].demandInletNode.name.to_s
143
+ result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_hhw_outlet},#{variable_name2},timestep;").get
144
+ result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_hhw_inlet},#{variable_name2},timestep;").get
145
+ result << OpenStudio::IdfObject.load("Output:Variable,#{key_value_hhw_outlet},#{variable_name1},timestep;").get
146
+ end
147
+ end
148
+
149
+
150
+ result << OpenStudio::IdfObject.load('Output:Variable,,Site Mains Water Temperature,hourly;').get
151
+ result << OpenStudio::IdfObject.load('Output:Variable,,Site Outdoor Air Drybulb Temperature,hourly;').get
152
+ result << OpenStudio::IdfObject.load('Output:Variable,,Site Outdoor Air Relative Humidity,hourly;').get
153
+ result << OpenStudio::IdfObject.load('Output:Meter,Cooling:Electricity,hourly;').get
154
+ result << OpenStudio::IdfObject.load('Output:Meter,Cooling:Electricity,timestep;').get ##Using this for data at timestep interval
155
+ result << OpenStudio::IdfObject.load('Output:Meter,Heating:Electricity,hourly;').get
156
+ result << OpenStudio::IdfObject.load('Output:Meter,Heating:Gas,hourly;').get
157
+ result << OpenStudio::IdfObject.load('Output:Meter,InteriorLights:Electricity,hourly;').get
158
+ result << OpenStudio::IdfObject.load('Output:Meter,Fans:Electricity,hourly;').get
159
+ result << OpenStudio::IdfObject.load('Output:Meter,InteriorEquipment:Electricity,hourly;').get # Joules
160
+ result << OpenStudio::IdfObject.load('Output:Meter,ExteriorLighting:Electricity,hourly;').get # Joules
161
+ result << OpenStudio::IdfObject.load('Output:Meter,Electricity:Facility,hourly;').get # Joules
162
+ result << OpenStudio::IdfObject.load('Output:Meter,Gas:Facility,hourly;').get # Joules
163
+ result << OpenStudio::IdfObject.load('Output:Meter,Heating:EnergyTransfer,hourly;').get # Joules
164
+ result << OpenStudio::IdfObject.load('Output:Meter,WaterSystems:EnergyTransfer,hourly;').get # Joules
165
+ # these variables are used for the modelica export.
166
+ result << OpenStudio::IdfObject.load('Output:Variable,*,Zone Predicted Sensible Load to Setpoint Heat Transfer Rate,hourly;').get # watts according to e+
167
+ result << OpenStudio::IdfObject.load('Output:Variable,*,Water Heater Total Demand Heat Transfer Rate,hourly;').get # Watts
168
+
169
+ result
170
+ end
171
+
172
+ def extract_timeseries_into_matrix(sqlfile, data, variable_name, str, key_value = nil, default_if_empty = 0,dec_places, timestep)
173
+ log "Executing query for #{variable_name}"
174
+ #column_name = variable_name
175
+ if key_value
176
+ #ts = sqlfile.timeSeries('RUN PERIOD 1', 'Hourly', variable_name, key_value)
177
+ ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name, key_value)
178
+ #column_name += "_#{key_value}"
179
+ column_name=str
180
+ else
181
+ #ts = sqlfile.timeSeries('RUN PERIOD 1', 'Hourly', variable_name)
182
+ ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name)
183
+ end
184
+ log 'Iterating over timeseries'
185
+ column = [column_name.delete(':').delete(' ')] # Set the header of the data to the variable name, removing : and spaces
186
+
187
+ if ts.empty?
188
+ log "No time series for #{variable_name}:#{key_value}... defaulting to #{default_if_empty}"
189
+ # needs to be data.size-1 since the column name is already stored above (+=)
190
+ column += [default_if_empty] * (data.size - 1)
191
+ else
192
+ ts = ts.get if ts.respond_to?(:get)
193
+ ts = ts.first if ts.respond_to?(:first)
194
+
195
+ start = Time.now
196
+ # Iterating in OpenStudio can take up to 60 seconds with 10min data. The quick_proc takes 0.03 seconds.
197
+ # for i in 0..ts.values.size - 1
198
+ # log "... at #{i}" if i % 10000 == 0
199
+ # column << ts.values[i]
200
+ # end
201
+
202
+ quick_proc = ts.values.to_s.split(',')
203
+ quick_proc[0]=quick_proc[0].split('(', 2).last #cleanup necessary to remove opening paren
204
+ quick_proc=quick_proc.map(&:to_f)
205
+ x = 0
206
+ len = quick_proc.length
207
+ log "quick proc #{quick_proc}"
208
+ while(x < len) #Round to the # of decimal places specified
209
+ quick_proc[x]=(quick_proc[x]).round(dec_places)
210
+ x=x+1
211
+ end
212
+ quick_proc=quick_proc.map(&:to_s)
213
+
214
+
215
+ # the first and last have some cleanup items because of the Vector method
216
+ quick_proc[0] = quick_proc[0].gsub(/^.*\(/, '')
217
+ quick_proc[-1] = quick_proc[-1].delete(')')
218
+ column += quick_proc
219
+
220
+
221
+
222
+ log "Took #{Time.now - start} to iterate"
223
+ end
224
+
225
+ log 'Appending column to data'
226
+
227
+ # append the data to the end of the rows
228
+ if column.size == data.size
229
+ data.each_index do |index|
230
+ data[index] << column[index]
231
+ end
232
+ end
233
+
234
+ log "Finished extracting #{variable_name}"
235
+ end
236
+
237
+ def create_new_variable_sum(data, new_var_name, include_str, options=nil)
238
+ var_info = {
239
+ name: new_var_name,
240
+ var_indexes: []
241
+ }
242
+ data.each_with_index do |row, index|
243
+ if index.zero?
244
+ # Get the index of the columns to add
245
+ row.each do |c|
246
+ var_info[:var_indexes] << row.index(c) if c.include? include_str
247
+ end
248
+
249
+ # add the new var to the header row
250
+ data[0] << var_info[:name]
251
+ else
252
+ # sum the values
253
+ sum = 0
254
+ var_info[:var_indexes].each do |var|
255
+ temp_v = row[var].to_f
256
+ if options.nil?
257
+ sum += temp_v
258
+ elsif options[:positive_only] && temp_v > 0
259
+ sum += temp_v
260
+ elsif options[:negative_only] && temp_v < 0
261
+ sum += temp_v
262
+ end
263
+ end
264
+ data[index] << sum
265
+ end
266
+ end
267
+ end
268
+
269
+ def run(runner, user_arguments)
270
+ super(runner, user_arguments)
271
+
272
+ # get the last model and sql file
273
+ model = runner.lastOpenStudioModel
274
+ if model.empty?
275
+ runner.registerError('Cannot find last model.')
276
+ return false
277
+ end
278
+ model = model.get
279
+
280
+ # use the built-in error checking
281
+ return false unless runner.validateUserArguments(arguments(model), user_arguments)
282
+
283
+ args = OsLib_HelperMethods.createRunVariables(runner, model, user_arguments, arguments(model))
284
+ if !args then return false end
285
+
286
+ # lookup and replace argument values from upstream measures
287
+ if args['use_upstream_args'] == true
288
+ args.each do |arg,value|
289
+ next if arg == 'use_upstream_args' # this argument should not be changed
290
+ value_from_osw = OsLib_HelperMethods.check_upstream_measure_for_arg(runner, arg)
291
+ if !value_from_osw.empty?
292
+ runner.registerInfo("Replacing argument named #{arg} from current measure with a value of #{value_from_osw[:value]} from #{value_from_osw[:measure_name]}.")
293
+ new_val = value_from_osw[:value]
294
+ # todo - make code to handle non strings more robust. check_upstream_measure_for_arg could pass bakc the argument type
295
+ if arg == 'hhw_loop_name'
296
+ args[arg] = new_val.to_s
297
+ elsif arg == 'chw_loop_name'
298
+ args[arg] = new_val.to_s
299
+ else
300
+ args[arg] = new_val
301
+ end
302
+ end
303
+ end
304
+ end
305
+ hhw_loop_name = args['hhw_loop_name']
306
+ chw_loop_name = args['chw_loop_name']
307
+ dec_places_temp = args['dec_places_temp']
308
+ dec_places_mass_flow = args['dec_places_mass_flow']
309
+ # get the last model and sql file
310
+ model = runner.lastOpenStudioModel
311
+ if model.empty?
312
+ runner.registerError('Cannot find last model.')
313
+ return false
314
+ end
315
+ model = model.get
316
+
317
+
318
+ timesteps_per_hour=model.getTimestep.numberOfTimestepsPerHour.to_i
319
+ timestep=60/timesteps_per_hour #timestep in minutes
320
+
321
+ sqlFile = runner.lastEnergyPlusSqlFile
322
+ if sqlFile.empty?
323
+ runner.registerError('Cannot find last sql file.')
324
+ return false
325
+ end
326
+ sqlFile = sqlFile.get
327
+ model.setSqlFile(sqlFile)
328
+
329
+ # create a new csv with the values and save to the reports directory.
330
+ # assumptions:
331
+ # - all the variables exist
332
+ # - data are the same length
333
+
334
+ # initialize the rows with the header
335
+ log 'Starting to process Timeseries data'
336
+ # Initial header row
337
+ rows = [
338
+ ['Date Time', 'Month', 'Day', 'Day of Week', 'Hour', 'Minute', 'SecondsFromStart']
339
+ ]
340
+
341
+ # just grab one of the variables to get the date/time stamps
342
+ ts = sqlFile.timeSeries('RUN PERIOD 1', 'Zone Timestep', 'Cooling:Electricity')
343
+ #ts = sqlFile.timeSeries('RUN PERIOD 1', 'Hourly', 'Cooling:Electricity')
344
+ unless ts.empty?
345
+ ts = ts.first
346
+ dt_base = nil
347
+ # Save off the date time values
348
+ ts.dateTimes.each_with_index do |dt, index|
349
+ dt_base = DateTime.parse(dt.to_s) if dt_base.nil?
350
+ dt_current = DateTime.parse(dt.to_s)
351
+ rows << [
352
+ DateTime.parse(dt.to_s).strftime('%m/%d/%Y %H:%M'),
353
+ dt.date.monthOfYear.value,
354
+ dt.date.dayOfMonth,
355
+ dt.date.dayOfWeek.value,
356
+ dt.time.hours,
357
+ dt.time.minutes,
358
+ dt_current.to_time.to_i - dt_base.to_time.to_i + timestep*60
359
+ ]
360
+ end
361
+ end
362
+
363
+ plantloops = model.getPlantLoops
364
+
365
+ selected_plant_loops = []
366
+ i = 0
367
+
368
+ key_var={}
369
+
370
+ plantloops.each do |plantLoop|
371
+ if plantLoop.name.get.to_s.downcase.include? chw_loop_name.to_str
372
+ #Extract plant loop information
373
+ selected_plant_loops[0]=plantLoop
374
+ end
375
+ if plantLoop.name.get.to_s.downcase.include? hhw_loop_name.to_str
376
+ #Get plant loop information
377
+ selected_plant_loops[1]=plantLoop
378
+ end
379
+ end
380
+
381
+ if !selected_plant_loops[1].nil?
382
+ #Set up variables for output
383
+ key_value_hhw_outlet = selected_plant_loops[1].demandOutletNode.name.to_s
384
+ key_value_hhw_inlet = selected_plant_loops[1].demandInletNode.name.to_s
385
+ key_var['hhw_outlet_massflow']='massFlowRateHeating'
386
+ key_var['hhw_outlet_temp']='heatingReturnTemperature[C]'
387
+ key_var['hhw_inlet_temp']='heatingSupplyTemperature[C]'
388
+ #Extract time series
389
+ extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['hhw_outlet_temp'], key_value_hhw_outlet, 0, dec_places_temp, timestep)
390
+ extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['hhw_inlet_temp'], key_value_hhw_inlet, 0, dec_places_temp, timestep)
391
+ 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)
392
+ else
393
+ 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.")
394
+ end
395
+
396
+ if !selected_plant_loops[0].nil?
397
+ #Set up variables for outputs
398
+ key_value_chw_outlet = selected_plant_loops[0].demandOutletNode.name.to_s
399
+ key_value_chw_inlet = selected_plant_loops[0].demandInletNode.name.to_s
400
+ key_var['chw_outlet_massflow']='massFlowRateCooling'
401
+ key_var['chw_outlet_temp']='ChilledWaterReturnTemperature[C]'
402
+ key_var['chw_inlet_temp']='ChilledWaterSupplyTemperature[C]'
403
+ #Extract time series
404
+ extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['chw_outlet_temp'], key_value_chw_outlet, 0, dec_places_temp,timestep)
405
+ extract_timeseries_into_matrix(sqlFile, rows, 'System Node Temperature', key_var['chw_inlet_temp'], key_value_chw_inlet, 0, dec_places_temp,timestep)
406
+ 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)
407
+ else
408
+ 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.")
409
+ end
410
+
411
+
412
+ if selected_plant_loops[0].nil? and selected_plant_loops[1].nil?
413
+ 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.")
414
+ end
415
+
416
+ if !selected_plant_loops.nil?
417
+ # convert this to CSV object
418
+ File.open('./building_loads.csv', 'w') do |f|
419
+ rows.each do |row|
420
+ f << row.join(',') << "\n"
421
+ end
422
+ end
423
+ end
424
+
425
+ true
426
+ ensure
427
+ sqlFile&.close
428
+ end
429
+ end
430
+
431
+
432
+ # register the measure to be used by the application
433
+ ExportTimeSeriesLoadsCSV.new.registerWithApplication