urbanopt-reporting 0.3.3 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/measures/default_feature_reports/measure.rb +3 -4
- data/lib/measures/export_modelica_loads/measure.rb +53 -47
- data/lib/measures/export_time_series_modelica/measure.rb +124 -128
- data/lib/measures/export_time_series_modelica/resources/os_lib_helper_methods.rb +1 -1
- data/lib/urbanopt/reporting/default_reports/feature_report.rb +3 -1
- data/lib/urbanopt/reporting/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75187e938a1cbfabd1d74eba912af03fcd2aade54955a490d68ea1b97b229dd2
|
4
|
+
data.tar.gz: 25b56a46e4569a71a7c01964bf64f2a14d8c30fdc9f6f5167fd61b40f272eb52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a5f20c29cc1eec6aafeece4479a52c4c5a6a0ecfb0374a0b8f243551f9a7d49ecfbcf25b233ce7e19441551adcd87c5eb668ad509d4c87b0681ea1a187da6b2
|
7
|
+
data.tar.gz: bccc2ad11e97d3330f2706cb9a7d32c5c0209130af88738854e6d56fb6d34b5ccfcc8b51b42633d3f359bf4c03c34d4888108528bd38c558c96ec06569c92e9d
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# URBANopt Reporting Gem
|
2
2
|
|
3
|
+
## Version 0.3.4
|
4
|
+
|
5
|
+
Date Range: 01/14/21 - 01/15/21
|
6
|
+
|
7
|
+
- Fixed [#53]( https://github.com/urbanopt/urbanopt-reporting-gem/issues/53 ), Make subfolders in feature saving if necessary
|
8
|
+
- Fixed [#55]( https://github.com/urbanopt/urbanopt-reporting-gem/issues/55 ), Fix new measures
|
9
|
+
|
3
10
|
## Version 0.3.3
|
4
11
|
|
5
12
|
Date Range: 12/09/20 - 01/13/21
|
@@ -505,18 +505,17 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
505
505
|
feature_report.program.roof_area_sqft[:total_roof_area_sqft] = total_roof_area_sqft
|
506
506
|
|
507
507
|
# available_roof_area_sqft
|
508
|
-
# RK: a more robust method should be implemented to find the available_roof_area
|
508
|
+
# RK: a more robust method should be implemented to find the available_roof_area
|
509
509
|
# assign available roof area to be a percentage of the total roof area
|
510
510
|
|
511
511
|
if building_types[0][:building_type].include? 'Single-Family Detached'
|
512
512
|
feature_report.program.roof_area_sqft[:available_roof_area_sqft] = 0.45 * total_roof_area_sqft
|
513
|
-
else
|
513
|
+
else
|
514
514
|
feature_report.program.roof_area_sqft[:available_roof_area_sqft] = 0.75 * total_roof_area_sqft
|
515
515
|
end
|
516
516
|
|
517
517
|
# RK: Temporary solution: assign available roof area to be equal to total roof area
|
518
|
-
#feature_report.program.roof_area_sqft[:available_roof_area_sqft] = total_roof_area_sqft
|
519
|
-
|
518
|
+
# feature_report.program.roof_area_sqft[:available_roof_area_sqft] = total_roof_area_sqft
|
520
519
|
|
521
520
|
# orientation
|
522
521
|
# RK: a more robust method should be implemented to find orientation(finding main axis of the building using aspect ratio)
|
@@ -82,37 +82,38 @@ class ExportModelicaLoads < OpenStudio::Measure::ReportingMeasure
|
|
82
82
|
return false
|
83
83
|
end
|
84
84
|
|
85
|
-
result << OpenStudio::IdfObject.load('Output:Variable,,Site Mains Water Temperature,
|
86
|
-
result << OpenStudio::IdfObject.load('Output:Variable,,Site Outdoor Air Drybulb Temperature,
|
87
|
-
result << OpenStudio::IdfObject.load('Output:Variable,,Site Outdoor Air Relative Humidity,
|
88
|
-
result << OpenStudio::IdfObject.load('Output:Meter,Cooling:Electricity,
|
89
|
-
result << OpenStudio::IdfObject.load('Output:Meter,Heating:Electricity,
|
90
|
-
result << OpenStudio::IdfObject.load('Output:Meter,Heating:Gas,
|
91
|
-
result << OpenStudio::IdfObject.load('Output:Meter,InteriorLights:Electricity,
|
92
|
-
result << OpenStudio::IdfObject.load('Output:Meter,Fans:Electricity,
|
93
|
-
result << OpenStudio::IdfObject.load('Output:Meter,InteriorEquipment:Electricity,
|
94
|
-
result << OpenStudio::IdfObject.load('Output:Meter,ExteriorLighting:Electricity,
|
95
|
-
result << OpenStudio::IdfObject.load('Output:Meter,Electricity:Facility,
|
96
|
-
result << OpenStudio::IdfObject.load('Output:Meter,
|
97
|
-
result << OpenStudio::IdfObject.load('Output:Meter,
|
98
|
-
result << OpenStudio::IdfObject.load('Output:Meter,
|
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
|
99
100
|
# these variables are used for the modelica export.
|
100
|
-
result << OpenStudio::IdfObject.load('Output:Variable,*,Zone Predicted Sensible Load to Setpoint Heat Transfer Rate,
|
101
|
-
result << OpenStudio::IdfObject.load('Output:Variable,*,Water Heater Total Demand Heat Transfer Rate,
|
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
|
102
103
|
|
103
104
|
return result
|
104
105
|
end
|
105
106
|
|
106
|
-
def extract_timeseries_into_matrix(sqlfile, data, variable_name, key_value = nil, default_if_empty=0)
|
107
|
+
def extract_timeseries_into_matrix(sqlfile, data, variable_name, key_value = nil, default_if_empty = 0, timestep)
|
107
108
|
log "Executing query for #{variable_name}"
|
108
109
|
column_name = variable_name
|
109
110
|
if key_value
|
110
|
-
ts = sqlfile.timeSeries('RUN PERIOD 1', 'Hourly', variable_name, key_value)
|
111
|
-
|
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)
|
112
113
|
column_name += "_#{key_value}"
|
113
114
|
else
|
114
|
-
ts = sqlfile.timeSeries('RUN PERIOD 1', 'Hourly', variable_name)
|
115
|
-
|
115
|
+
# ts = sqlfile.timeSeries('RUN PERIOD 1', 'Hourly', variable_name)
|
116
|
+
ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name)
|
116
117
|
end
|
117
118
|
log 'Iterating over timeseries'
|
118
119
|
column = [column_name.delete(':').delete(' ')] # Set the header of the data to the variable name, removing : and spaces
|
@@ -120,7 +121,7 @@ class ExportModelicaLoads < OpenStudio::Measure::ReportingMeasure
|
|
120
121
|
if ts.empty?
|
121
122
|
log "No time series for #{variable_name}:#{key_value}... defaulting to #{default_if_empty}"
|
122
123
|
# needs to be data.size-1 since the column name is already stored above (+=)
|
123
|
-
column += [default_if_empty] * (data.size-1)
|
124
|
+
column += [default_if_empty] * (data.size - 1)
|
124
125
|
else
|
125
126
|
ts = ts.get if ts.respond_to?(:get)
|
126
127
|
ts = ts.first if ts.respond_to?(:first)
|
@@ -154,10 +155,10 @@ class ExportModelicaLoads < OpenStudio::Measure::ReportingMeasure
|
|
154
155
|
log "Finished extracting #{variable_name}"
|
155
156
|
end
|
156
157
|
|
157
|
-
def create_new_variable_sum(data, new_var_name, include_str, options=nil)
|
158
|
+
def create_new_variable_sum(data, new_var_name, include_str, options = nil)
|
158
159
|
var_info = {
|
159
|
-
|
160
|
-
|
160
|
+
name: new_var_name,
|
161
|
+
var_indexes: []
|
161
162
|
}
|
162
163
|
data.each_with_index do |row, index|
|
163
164
|
if index.zero?
|
@@ -212,6 +213,9 @@ class ExportModelicaLoads < OpenStudio::Measure::ReportingMeasure
|
|
212
213
|
end
|
213
214
|
model = model.get
|
214
215
|
|
216
|
+
timesteps_per_hour=model.getTimestep.numberOfTimestepsPerHour.to_i
|
217
|
+
timestep=60/timesteps_per_hour #timestep in minutes
|
218
|
+
|
215
219
|
sqlFile = runner.lastEnergyPlusSqlFile
|
216
220
|
if sqlFile.empty?
|
217
221
|
runner.registerError('Cannot find last sql file.')
|
@@ -233,45 +237,47 @@ class ExportModelicaLoads < OpenStudio::Measure::ReportingMeasure
|
|
233
237
|
]
|
234
238
|
|
235
239
|
# just grab one of the variables to get the date/time stamps
|
236
|
-
|
237
|
-
ts = sqlFile.timeSeries('RUN PERIOD 1', '
|
238
|
-
|
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
|
239
246
|
ts = ts.first
|
240
247
|
dt_base = nil
|
241
248
|
# Save off the date time values
|
242
249
|
ts.dateTimes.each_with_index do |dt, index|
|
243
|
-
runner.registerInfo("My index is #{index}")
|
244
250
|
dt_base = DateTime.parse(dt.to_s) if dt_base.nil?
|
245
251
|
dt_current = DateTime.parse(dt.to_s)
|
246
252
|
rows << [
|
247
253
|
DateTime.parse(dt.to_s).strftime('%m/%d/%Y %H:%M'),
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
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
|
254
260
|
]
|
255
261
|
end
|
256
262
|
end
|
257
263
|
|
258
264
|
# add in the other variables by columns -- should really pull this from the report variables defined above
|
259
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'Site Outdoor Air Drybulb Temperature', 'Environment', 0)
|
260
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'Site Outdoor Air Relative Humidity', 'Environment', 0)
|
261
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'Heating:Electricity', nil, 0)
|
262
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'Heating:Gas', nil, 0)
|
263
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'Cooling:Electricity', nil, 0)
|
264
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'Electricity:Facility', nil, 0)
|
265
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'Gas:Facility', nil, 0)
|
266
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'Heating:EnergyTransfer', nil, 0)
|
267
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'WaterSystems:EnergyTransfer', nil, 0)
|
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)
|
268
274
|
|
269
275
|
# get all zones and save the names for later use in aggregation.
|
270
276
|
tz_names = []
|
271
277
|
model.getThermalZones.each do |tz|
|
272
278
|
tz_names << tz.name.get if tz.name.is_initialized
|
273
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'Zone Predicted Sensible Load to Setpoint Heat Transfer Rate', tz_names.last, 0)
|
274
|
-
extract_timeseries_into_matrix(sqlFile, rows, 'Water Heater Heating Rate', tz_names.last, 0)
|
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)
|
275
281
|
end
|
276
282
|
|
277
283
|
# sum up a couple of the columns and create a new columns
|
@@ -346,7 +352,7 @@ class ExportModelicaLoads < OpenStudio::Measure::ReportingMeasure
|
|
346
352
|
# Find the total runtime for energyplus and save it into a registerValue
|
347
353
|
total_time = -999
|
348
354
|
location_of_file = ['../eplusout.end', './run/eplusout.end']
|
349
|
-
first_index = location_of_file.map {|f| File.exist?(f)}.index(true)
|
355
|
+
first_index = location_of_file.map { |f| File.exist?(f) }.index(true)
|
350
356
|
if first_index
|
351
357
|
match = File.read(location_of_file[first_index]).to_s.match(/Elapsed.Time=(.*)hr(.*)min(.*)sec/)
|
352
358
|
total_time = match[1].to_i * 3600 + match[2].to_i * 60 + match[3].to_f
|
@@ -61,25 +61,25 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
61
61
|
puts "#{Time.now}: #{str}"
|
62
62
|
end
|
63
63
|
|
64
|
-
def arguments(_model)
|
64
|
+
def arguments(_model)
|
65
65
|
args = OpenStudio::Measure::OSArgumentVector.new
|
66
|
-
|
66
|
+
|
67
67
|
hhw_loop_name = OpenStudio::Measure::OSArgument.makeStringArgument('hhw_loop_name', true)
|
68
68
|
hhw_loop_name.setDisplayName('Name or Partial Name of Heating Hot Water Loop, non-case-sensitive')
|
69
69
|
hhw_loop_name.setDefaultValue('hot')
|
70
70
|
args << hhw_loop_name
|
71
|
-
|
72
|
-
|
71
|
+
|
72
|
+
chw_loop_name = OpenStudio::Measure::OSArgument.makeStringArgument('chw_loop_name', true)
|
73
73
|
chw_loop_name.setDisplayName('Name or Partial Name of Chilled Water Loop, non-case-sensitive')
|
74
74
|
chw_loop_name.setDefaultValue('chilled')
|
75
75
|
args << chw_loop_name
|
76
|
-
|
77
|
-
|
76
|
+
|
77
|
+
dec_places_mass_flow = OpenStudio::Measure::OSArgument.makeIntegerArgument('dec_places_mass_flow', true)
|
78
78
|
dec_places_mass_flow.setDisplayName('Number of Decimal Places to Round Mass Flow Rate')
|
79
79
|
dec_places_mass_flow.setDescription('Number of decimal places to which mass flow rate will be rounded')
|
80
80
|
dec_places_mass_flow.setDefaultValue(3)
|
81
81
|
args << dec_places_mass_flow
|
82
|
-
|
82
|
+
|
83
83
|
dec_places_temp = OpenStudio::Measure::OSArgument.makeIntegerArgument('dec_places_temp', true)
|
84
84
|
dec_places_temp.setDisplayName('Number of Decimal Places to Round Temperature')
|
85
85
|
dec_places_temp.setDescription('Number of decimal places to which temperature will be rounded')
|
@@ -94,7 +94,6 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
94
94
|
super(runner, user_arguments)
|
95
95
|
|
96
96
|
result = OpenStudio::IdfObjectVector.new
|
97
|
-
|
98
97
|
|
99
98
|
# To use the built-in error checking we need the model...
|
100
99
|
# get the last model and sql file
|
@@ -107,51 +106,48 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
107
106
|
|
108
107
|
# use the built-in error checking
|
109
108
|
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
109
|
|
116
|
-
|
117
|
-
|
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
|
118
116
|
|
119
117
|
selected_plant_loops = []
|
120
118
|
i = 0
|
121
|
-
|
122
|
-
variable_name1 = 'System Node Mass Flow Rate'
|
123
|
-
variable_name2 = 'System Node Temperature'
|
124
|
-
reporting_frequency = 'timestep'
|
125
119
|
|
126
|
-
|
120
|
+
variable_name1 = 'System Node Mass Flow Rate'
|
121
|
+
variable_name2 = 'System Node Temperature'
|
122
|
+
reporting_frequency = 'timestep'
|
123
|
+
|
127
124
|
plantloops.each do |plantLoop|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
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
|
149
145
|
|
150
146
|
result << OpenStudio::IdfObject.load('Output:Variable,,Site Mains Water Temperature,hourly;').get
|
151
147
|
result << OpenStudio::IdfObject.load('Output:Variable,,Site Outdoor Air Drybulb Temperature,hourly;').get
|
152
148
|
result << OpenStudio::IdfObject.load('Output:Variable,,Site Outdoor Air Relative Humidity,hourly;').get
|
153
149
|
result << OpenStudio::IdfObject.load('Output:Meter,Cooling:Electricity,hourly;').get
|
154
|
-
|
150
|
+
result << OpenStudio::IdfObject.load('Output:Meter,Electricity:Facility,timestep;').get ##Using this for data at timestep interval
|
155
151
|
result << OpenStudio::IdfObject.load('Output:Meter,Heating:Electricity,hourly;').get
|
156
152
|
result << OpenStudio::IdfObject.load('Output:Meter,Heating:Gas,hourly;').get
|
157
153
|
result << OpenStudio::IdfObject.load('Output:Meter,InteriorLights:Electricity,hourly;').get
|
@@ -169,17 +165,16 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
169
165
|
result
|
170
166
|
end
|
171
167
|
|
172
|
-
def extract_timeseries_into_matrix(sqlfile, data, variable_name, str, key_value = nil, default_if_empty = 0,dec_places, timestep)
|
168
|
+
def extract_timeseries_into_matrix(sqlfile, data, variable_name, str, key_value = nil, default_if_empty = 0,dec_places, timestep)
|
173
169
|
log "Executing query for #{variable_name}"
|
174
170
|
#column_name = variable_name
|
175
171
|
if key_value
|
176
|
-
|
177
|
-
ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name, key_value)
|
172
|
+
ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name, key_value)
|
178
173
|
#column_name += "_#{key_value}"
|
179
|
-
|
174
|
+
column_name=str
|
180
175
|
else
|
181
176
|
#ts = sqlfile.timeSeries('RUN PERIOD 1', 'Hourly', variable_name)
|
182
|
-
ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name)
|
177
|
+
ts = sqlfile.timeSeries('RUN PERIOD 1', 'Zone Timestep', variable_name)
|
183
178
|
end
|
184
179
|
log 'Iterating over timeseries'
|
185
180
|
column = [column_name.delete(':').delete(' ')] # Set the header of the data to the variable name, removing : and spaces
|
@@ -191,7 +186,7 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
191
186
|
else
|
192
187
|
ts = ts.get if ts.respond_to?(:get)
|
193
188
|
ts = ts.first if ts.respond_to?(:first)
|
194
|
-
|
189
|
+
|
195
190
|
start = Time.now
|
196
191
|
# Iterating in OpenStudio can take up to 60 seconds with 10min data. The quick_proc takes 0.03 seconds.
|
197
192
|
# for i in 0..ts.values.size - 1
|
@@ -200,24 +195,21 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
200
195
|
# end
|
201
196
|
|
202
197
|
quick_proc = ts.values.to_s.split(',')
|
203
|
-
|
204
|
-
|
205
|
-
|
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
|
206
201
|
len = quick_proc.length
|
207
|
-
|
208
|
-
while(x < len) #Round to the # of decimal places specified
|
202
|
+
log "quick proc #{quick_proc}"
|
203
|
+
while(x < len) #Round to the # of decimal places specified
|
209
204
|
quick_proc[x]=(quick_proc[x]).round(dec_places)
|
210
205
|
x=x+1
|
211
|
-
|
212
|
-
|
206
|
+
end
|
207
|
+
quick_proc=quick_proc.map(&:to_s)
|
213
208
|
|
214
|
-
|
215
209
|
# 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(')')
|
210
|
+
quick_proc[0] = quick_proc[0].gsub(/^.*\(/, '')
|
211
|
+
quick_proc[-1] = quick_proc[-1].delete(')')
|
218
212
|
column += quick_proc
|
219
|
-
|
220
|
-
|
221
213
|
|
222
214
|
log "Took #{Time.now - start} to iterate"
|
223
215
|
end
|
@@ -279,9 +271,11 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
279
271
|
|
280
272
|
# use the built-in error checking
|
281
273
|
return false unless runner.validateUserArguments(arguments(model), user_arguments)
|
282
|
-
|
283
|
-
|
284
|
-
|
274
|
+
|
275
|
+
args = OsLib_HelperMethods.createRunVariables(runner, model, user_arguments, arguments(model))
|
276
|
+
if !args
|
277
|
+
return false
|
278
|
+
end
|
285
279
|
|
286
280
|
# lookup and replace argument values from upstream measures
|
287
281
|
if args['use_upstream_args'] == true
|
@@ -291,7 +285,7 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
291
285
|
if !value_from_osw.empty?
|
292
286
|
runner.registerInfo("Replacing argument named #{arg} from current measure with a value of #{value_from_osw[:value]} from #{value_from_osw[:measure_name]}.")
|
293
287
|
new_val = value_from_osw[:value]
|
294
|
-
#
|
288
|
+
# TODO: make code to handle non strings more robust. check_upstream_measure_for_arg could pass back the argument type
|
295
289
|
if arg == 'hhw_loop_name'
|
296
290
|
args[arg] = new_val.to_s
|
297
291
|
elsif arg == 'chw_loop_name'
|
@@ -303,9 +297,9 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
303
297
|
end
|
304
298
|
end
|
305
299
|
hhw_loop_name = args['hhw_loop_name']
|
306
|
-
|
307
|
-
|
308
|
-
|
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']
|
309
303
|
# get the last model and sql file
|
310
304
|
model = runner.lastOpenStudioModel
|
311
305
|
if model.empty?
|
@@ -313,10 +307,9 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
313
307
|
return false
|
314
308
|
end
|
315
309
|
model = model.get
|
316
|
-
|
317
310
|
|
318
|
-
|
319
|
-
|
311
|
+
timesteps_per_hour=model.getTimestep.numberOfTimestepsPerHour.to_i
|
312
|
+
timestep=60/timesteps_per_hour #timestep in minutes
|
320
313
|
|
321
314
|
sqlFile = runner.lastEnergyPlusSqlFile
|
322
315
|
if sqlFile.empty?
|
@@ -339,9 +332,12 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
339
332
|
]
|
340
333
|
|
341
334
|
# just grab one of the variables to get the date/time stamps
|
342
|
-
|
343
|
-
|
344
|
-
|
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
|
345
341
|
ts = ts.first
|
346
342
|
dt_base = nil
|
347
343
|
# Save off the date time values
|
@@ -355,7 +351,7 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
355
351
|
dt.date.dayOfWeek.value,
|
356
352
|
dt.time.hours,
|
357
353
|
dt.time.minutes,
|
358
|
-
dt_current.to_time.to_i - dt_base.to_time.to_i + timestep*60
|
354
|
+
dt_current.to_time.to_i - dt_base.to_time.to_i + timestep*60
|
359
355
|
]
|
360
356
|
end
|
361
357
|
end
|
@@ -364,69 +360,69 @@ class ExportTimeSeriesLoadsCSV < OpenStudio::Measure::ReportingMeasure
|
|
364
360
|
|
365
361
|
selected_plant_loops = []
|
366
362
|
i = 0
|
367
|
-
|
368
|
-
|
363
|
+
|
364
|
+
key_var={}
|
369
365
|
|
370
366
|
plantloops.each do |plantLoop|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
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.")
|
379
390
|
end
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
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"
|
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
|
421
418
|
end
|
422
|
-
|
423
|
-
end
|
419
|
+
end
|
424
420
|
|
425
421
|
true
|
426
422
|
ensure
|
427
423
|
sqlFile&.close
|
428
424
|
end
|
429
|
-
|
425
|
+
end
|
430
426
|
|
431
427
|
|
432
428
|
# register the measure to be used by the application
|
@@ -40,6 +40,7 @@ require_relative 'thermal_storage'
|
|
40
40
|
|
41
41
|
require 'json-schema'
|
42
42
|
require 'json'
|
43
|
+
require 'fileutils'
|
43
44
|
|
44
45
|
module URBANopt
|
45
46
|
module Reporting
|
@@ -244,6 +245,7 @@ module URBANopt
|
|
244
245
|
Dir.mkdir(results_dir_path) unless Dir.exist?(File.join(@directory_name, 'feature_reports'))
|
245
246
|
|
246
247
|
@timeseries_csv.path = File.join(@directory_name, 'feature_reports', file_name + '.csv')
|
248
|
+
FileUtils.mkdir_p File.dirname(@timeseries_csv.path)
|
247
249
|
@timeseries_csv.save_data
|
248
250
|
|
249
251
|
## save json rport
|
@@ -270,7 +272,7 @@ module URBANopt
|
|
270
272
|
|
271
273
|
return true
|
272
274
|
end
|
273
|
-
|
275
|
+
|
274
276
|
##
|
275
277
|
# Calls the individual functions to save 'default_feature_report.json' and 'default_feature_report.csv'
|
276
278
|
# For backward compatibility and ease of use
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: urbanopt-reporting
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rawad El Kontar
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-01-
|
12
|
+
date: 2021-01-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|