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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/lib/measures/default_feature_reports/measure.rb +41 -4
- data/lib/measures/export_modelica_loads/LICENSE.md +27 -0
- data/lib/measures/export_modelica_loads/README.md +26 -0
- data/lib/measures/export_modelica_loads/README.md.erb +42 -0
- data/lib/measures/export_modelica_loads/docs/.gitkeep +0 -0
- data/lib/measures/export_modelica_loads/measure.rb +367 -0
- data/lib/measures/export_modelica_loads/measure.xml +92 -0
- data/lib/measures/export_modelica_loads/resources/report.html.in +13 -0
- data/lib/measures/export_time_series_modelica/LICENSE.md +1 -0
- data/lib/measures/export_time_series_modelica/README.md +59 -0
- data/lib/measures/export_time_series_modelica/README.md.erb +42 -0
- data/lib/measures/export_time_series_modelica/docs/.gitkeep +0 -0
- data/lib/measures/export_time_series_modelica/measure.rb +433 -0
- data/lib/measures/export_time_series_modelica/measure.xml +147 -0
- data/lib/measures/export_time_series_modelica/resources/os_lib_helper_methods.rb +399 -0
- data/lib/measures/export_time_series_modelica/resources/report.html.in +13 -0
- data/lib/urbanopt/reporting/default_reports/feature_report.rb +48 -0
- data/lib/urbanopt/reporting/default_reports/reporting_period.rb +14 -2
- data/lib/urbanopt/reporting/default_reports/scenario_report.rb +7 -4
- data/lib/urbanopt/reporting/default_reports/schema/scenario_schema.json +25 -13
- data/lib/urbanopt/reporting/version.rb +1 -1
- metadata +17 -2
@@ -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 %>
|
File without changes
|
@@ -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
|