urbanopt-cli 0.5.0 → 0.5.1
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/.gitignore +3 -1
- data/CHANGELOG.md +20 -0
- data/CMakeLists.txt +10 -10
- data/FindOpenStudioSDK.cmake +6 -6
- data/Gemfile +9 -9
- data/example_files/Gemfile +3 -3
- data/example_files/example_project.json +35 -20
- data/example_files/example_project_with_electric_network.json +2116 -0
- data/example_files/mappers/Baseline.rb +4 -1
- data/example_files/mappers/EvCharging.rb +131 -0
- data/example_files/mappers/base_workflow.osw +26 -1
- data/example_files/validation_schema.yaml +149 -0
- data/example_files/visualization/input_visualization_feature.html +213 -56
- data/example_files/visualization/input_visualization_scenario.html +92 -30
- data/lib/uo_cli.rb +204 -90
- data/lib/uo_cli/version.rb +1 -1
- data/uo_cli.gemspec +4 -6
- metadata +15 -27
- data/developer_nrel_key.rb +0 -31
@@ -0,0 +1,131 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt™, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
|
+
# contributors. All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice, this list
|
9
|
+
# of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer in the documentation and/or other
|
13
|
+
# materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of the copyright holder nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without specific
|
17
|
+
# prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
22
|
+
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
23
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
24
|
+
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
26
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
27
|
+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
28
|
+
# OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
# *********************************************************************************
|
30
|
+
|
31
|
+
require 'urbanopt/reporting'
|
32
|
+
require 'openstudio/common_measures'
|
33
|
+
require 'openstudio/model_articulation'
|
34
|
+
|
35
|
+
require_relative 'HighEfficiency'
|
36
|
+
|
37
|
+
require 'json'
|
38
|
+
|
39
|
+
module URBANopt
|
40
|
+
module Scenario
|
41
|
+
class EvChargingMapper < HighEfficiencyMapper
|
42
|
+
def create_osw(scenario, features, feature_names)
|
43
|
+
osw = super(scenario, features, feature_names)
|
44
|
+
|
45
|
+
feature = features[0]
|
46
|
+
|
47
|
+
def ev_charging_type(building_type)
|
48
|
+
typical_home = ['Single-Family', 'Multifamily (2 to 4 units)', 'Multifamily (5 or more units)', 'Lodging']
|
49
|
+
typical_public = ['Public assembly', 'Strip shopping mall', 'Enclosed mall', 'Retail other than mall', 'Food service', 'Nonrefrigerated warehouse', 'Food sales', 'Refrigerated warehouse', 'Religious worship', 'Service', 'Public order and safety', 'Uncovered Parking', 'Covered Parking']
|
50
|
+
typical_work = ['Office', 'Laboratory', 'Education', 'Inpatient health care', 'Outpatient health care', 'Nursing']
|
51
|
+
|
52
|
+
if typical_home.include? building_type
|
53
|
+
return 'Typical Home'
|
54
|
+
elsif typical_public.include? building_type
|
55
|
+
return 'Typical Public'
|
56
|
+
elsif typical_work.include? building_type
|
57
|
+
return 'Typical Work'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# add EV loads
|
62
|
+
ev_charging = nil
|
63
|
+
|
64
|
+
begin
|
65
|
+
ev_charging = feature.ev_charging
|
66
|
+
rescue
|
67
|
+
end
|
68
|
+
|
69
|
+
if ev_charging != true
|
70
|
+
puts "Please set ev_charging to true to add EV loads."
|
71
|
+
elsif ev_charging == true
|
72
|
+
OpenStudio::Extension.set_measure_argument(osw, 'add_ev_load', '__SKIP__', false)
|
73
|
+
begin
|
74
|
+
ev_charging_station_type = feature.ev_charging_station_type
|
75
|
+
rescue
|
76
|
+
end
|
77
|
+
if !ev_charging_station_type.nil? && !ev_charging_station_type.empty?
|
78
|
+
OpenStudio::Extension.set_measure_argument(osw, 'add_ev_load', 'chg_station_type', ev_charging_station_type)
|
79
|
+
else
|
80
|
+
building_type = feature.building_type
|
81
|
+
# For mixed use building ev_charging_station_type must be specified
|
82
|
+
if building_type == 'Mixed use'
|
83
|
+
puts "Specify the ev_charging_station_type for the Feature, add_ev_load measure not applied."
|
84
|
+
else
|
85
|
+
ev_charging_station_type = ev_charging_type(building_type)
|
86
|
+
OpenStudio::Extension.set_measure_argument(osw, 'add_ev_load', 'chg_station_type', ev_charging_station_type)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
begin
|
91
|
+
if ev_charging_station_type == 'Typical Work'
|
92
|
+
delay_type = feature.delay_type
|
93
|
+
OpenStudio::Extension.set_measure_argument(osw, 'add_ev_load', 'delay_type', delay_type)
|
94
|
+
end
|
95
|
+
rescue
|
96
|
+
end
|
97
|
+
|
98
|
+
begin
|
99
|
+
ev_charging_behavior = feature.ev_charging_behavior
|
100
|
+
if !ev_charging_behavior.nil? && !ev_charging_behavior.empty?
|
101
|
+
OpenStudio::Extension.set_measure_argument(osw, 'add_ev_load', 'charge_behavior', ev_charging_behavior)
|
102
|
+
end
|
103
|
+
rescue
|
104
|
+
end
|
105
|
+
|
106
|
+
begin
|
107
|
+
ev_percent = feature.ev_percent
|
108
|
+
if !ev_percent.nil? && !ev_percent.empty?
|
109
|
+
OpenStudio::Extension.set_measure_argument(osw, 'add_ev_load', 'ev_percent', ev_percent)
|
110
|
+
end
|
111
|
+
rescue
|
112
|
+
end
|
113
|
+
|
114
|
+
#Add EMS Control to EV charging only if ev_charging is true
|
115
|
+
begin
|
116
|
+
ev_curtailment_frac = feature.ev_curtailment_frac
|
117
|
+
rescue
|
118
|
+
end
|
119
|
+
|
120
|
+
if !ev_curtailment_frac.nil?
|
121
|
+
OpenStudio::Extension.set_measure_argument(osw, 'add_ems_to_control_ev_charging', '__SKIP__', false)
|
122
|
+
OpenStudio::Extension.set_measure_argument(osw, 'add_ems_to_control_ev_charging', 'curtailment_frac', ev_curtailment_frac)
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
return osw
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -60,6 +60,21 @@
|
|
60
60
|
"__SKIP__":true,
|
61
61
|
"blend_method":"Building Story"
|
62
62
|
}
|
63
|
+
},{
|
64
|
+
"measure_dir_name": "add_ev_load",
|
65
|
+
"arguments": {
|
66
|
+
"__SKIP__": true,
|
67
|
+
"chg_station_type": "Typical Public",
|
68
|
+
"delay_type": "Min Delay",
|
69
|
+
"charge_behavior": "Business as Usual",
|
70
|
+
"ev_percent": 100
|
71
|
+
}
|
72
|
+
},{
|
73
|
+
"measure_dir_name": "add_ems_to_control_ev_charging",
|
74
|
+
"arguments": {
|
75
|
+
"__SKIP__": true,
|
76
|
+
"curtailment_frac": 0.5
|
77
|
+
}
|
63
78
|
},{
|
64
79
|
"measure_dir_name":"urban_geometry_creation_zoning",
|
65
80
|
"arguments":{
|
@@ -130,6 +145,16 @@
|
|
130
145
|
"size_mult":"0.75",
|
131
146
|
"charge_start":"23:00"
|
132
147
|
}
|
148
|
+
},{
|
149
|
+
"measure_dir_name":"export_time_series_modelica",
|
150
|
+
"arguments":{
|
151
|
+
"__SKIP__":false
|
152
|
+
}
|
153
|
+
},{
|
154
|
+
"measure_dir_name":"export_modelica_loads",
|
155
|
+
"arguments":{
|
156
|
+
"__SKIP__":false
|
157
|
+
}
|
133
158
|
},{
|
134
159
|
"measure_dir_name":"default_feature_reports",
|
135
160
|
"arguments":{
|
@@ -142,4 +167,4 @@
|
|
142
167
|
],
|
143
168
|
"name":null,
|
144
169
|
"description":null
|
145
|
-
}
|
170
|
+
}
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# General bounds for expected EUI values
|
2
|
+
# Commercial building reference: https://portfoliomanager.energystar.gov/pdf/reference/US%20National%20Median%20Table.pdf
|
3
|
+
# Residential building reference: https://www.eia.gov/consumption/residential/data/2015/c&e/pdf/ce1.1.pdf
|
4
|
+
# Converting between SI & Imperial EUI units: https://eddysantosa.com/eui/
|
5
|
+
# You may adjust these values for the <building_type>s in your FeatureFile. The references above may be useful guidelines
|
6
|
+
EUI:
|
7
|
+
IP:
|
8
|
+
Units: "kBtu/ft2/yr"
|
9
|
+
Single-Family Detached:
|
10
|
+
min: 10
|
11
|
+
max: 60
|
12
|
+
Single-Family Attached:
|
13
|
+
min: 10
|
14
|
+
max: 60
|
15
|
+
Multifamily (2 to 4 units):
|
16
|
+
min: 20
|
17
|
+
max: 75
|
18
|
+
Multifamily (5 or more units):
|
19
|
+
min: 10
|
20
|
+
max: 60
|
21
|
+
Office:
|
22
|
+
min: 40
|
23
|
+
max: 75
|
24
|
+
Laboratory:
|
25
|
+
min: 100
|
26
|
+
max: 150
|
27
|
+
Nonrefrigerated warehouse:
|
28
|
+
min: 10
|
29
|
+
max: 40
|
30
|
+
Food sales:
|
31
|
+
min: 50
|
32
|
+
max: 250
|
33
|
+
Public order and safety:
|
34
|
+
min: 40
|
35
|
+
max: 75
|
36
|
+
Outpatient health care:
|
37
|
+
min: 50
|
38
|
+
max: 100
|
39
|
+
Refrigerated warehouse:
|
40
|
+
min: 75
|
41
|
+
max: 100
|
42
|
+
Religious worship:
|
43
|
+
min: 20
|
44
|
+
max: 40
|
45
|
+
Public assembly:
|
46
|
+
min: 40
|
47
|
+
max: 60
|
48
|
+
Education:
|
49
|
+
min: 40
|
50
|
+
max: 100
|
51
|
+
Food service:
|
52
|
+
min: 200
|
53
|
+
max: 500
|
54
|
+
Inpatient health care:
|
55
|
+
min: 200
|
56
|
+
max: 300
|
57
|
+
Nursing:
|
58
|
+
min: 50
|
59
|
+
max: 100
|
60
|
+
Lodging:
|
61
|
+
min: 50
|
62
|
+
max: 100
|
63
|
+
Strip shopping mall:
|
64
|
+
min: 80
|
65
|
+
max: 120
|
66
|
+
Enclosed mall:
|
67
|
+
min: 50
|
68
|
+
max: 75
|
69
|
+
Retail other than mall:
|
70
|
+
min: 40
|
71
|
+
max: 75
|
72
|
+
Service:
|
73
|
+
min: 30
|
74
|
+
max: 75
|
75
|
+
Mixed use:
|
76
|
+
min: 10
|
77
|
+
max: 75
|
78
|
+
|
79
|
+
SI:
|
80
|
+
Units: "kWh/m2/yr"
|
81
|
+
Single-Family Detached:
|
82
|
+
min: 30
|
83
|
+
max: 200
|
84
|
+
Single-Family Attached:
|
85
|
+
min: 30
|
86
|
+
max: 200
|
87
|
+
Multifamily (2 to 4 units):
|
88
|
+
min: 63
|
89
|
+
max: 237
|
90
|
+
Multifamily (5 or more units):
|
91
|
+
min: 30
|
92
|
+
max: 200
|
93
|
+
Office:
|
94
|
+
min: 126
|
95
|
+
max: 237
|
96
|
+
Laboratory:
|
97
|
+
min: 315
|
98
|
+
max: 475
|
99
|
+
Nonrefrigerated warehouse:
|
100
|
+
min: 31
|
101
|
+
max: 126
|
102
|
+
Food sales:
|
103
|
+
min: 157
|
104
|
+
max: 789
|
105
|
+
Public order and safety:
|
106
|
+
min: 126
|
107
|
+
max: 237
|
108
|
+
Outpatient health care:
|
109
|
+
min: 157
|
110
|
+
max: 315
|
111
|
+
Refrigerated warehouse:
|
112
|
+
min: 236
|
113
|
+
max: 315
|
114
|
+
Religious worship:
|
115
|
+
min: 63
|
116
|
+
max: 126
|
117
|
+
Public assembly:
|
118
|
+
min: 126
|
119
|
+
max: 190
|
120
|
+
Education:
|
121
|
+
min: 126
|
122
|
+
max: 315
|
123
|
+
Food service:
|
124
|
+
min: 630
|
125
|
+
max: 1577
|
126
|
+
Inpatient health care:
|
127
|
+
min: 630
|
128
|
+
max: 946
|
129
|
+
Nursing:
|
130
|
+
min: 157
|
131
|
+
max: 315
|
132
|
+
Lodging:
|
133
|
+
min: 157
|
134
|
+
max: 315
|
135
|
+
Strip shopping mall:
|
136
|
+
min: 252
|
137
|
+
max: 379
|
138
|
+
Enclosed mall:
|
139
|
+
min: 157
|
140
|
+
max: 237
|
141
|
+
Retail other than mall:
|
142
|
+
min: 126
|
143
|
+
max: 237
|
144
|
+
Service:
|
145
|
+
min: 94
|
146
|
+
max: 237
|
147
|
+
Mixed use:
|
148
|
+
min: 31
|
149
|
+
max: 789
|
@@ -32,6 +32,10 @@
|
|
32
32
|
color: red;
|
33
33
|
}
|
34
34
|
|
35
|
+
.button-pad {
|
36
|
+
padding:5px 15px;
|
37
|
+
}
|
38
|
+
|
35
39
|
nvd3 {
|
36
40
|
display: block;
|
37
41
|
width: 100%;
|
@@ -154,6 +158,7 @@
|
|
154
158
|
<div ng-controller="MyAppCtrl" class="container">
|
155
159
|
|
156
160
|
<h1>Features</h1>
|
161
|
+
<md-button class="button-pad md-raised md-primary" ng-click="toggleAxes()">Toggle Y-Axis Ranges</md-button>
|
157
162
|
|
158
163
|
<h2>Monthly Fuel Use</h2>
|
159
164
|
<md-content class="md-padding" layout-sm="column" layout="row" layout-wrap>
|
@@ -167,7 +172,7 @@
|
|
167
172
|
</md-card-title-text>
|
168
173
|
</md-card-title>
|
169
174
|
<md-card-content>
|
170
|
-
<nvd3 class="h-320 remove-x-lines" options="monthlyFuelChartOptions" data="monthlyFuelChartData[feature.name]"></nvd3>
|
175
|
+
<nvd3 class="h-320 remove-x-lines" options="monthlyFuelChartOptions[feature.name]" data="monthlyFuelChartData[feature.name]"></nvd3>
|
171
176
|
</md-card-content>
|
172
177
|
</md-card>
|
173
178
|
</div>
|
@@ -181,13 +186,14 @@
|
|
181
186
|
<md-card-title-text>
|
182
187
|
<span class="md-headline">{{ feature.name }}</span>
|
183
188
|
<span class="md-subhead">Annual Net Energy - {{
|
184
|
-
annualNetChartData[feature.name] }}
|
185
|
-
|
189
|
+
annualNetChartData[feature.name] }}
|
190
|
+
</span>
|
191
|
+
<span class="md-subhead">Monthly Net Energy </span>
|
186
192
|
<span ng-if="feature.complete_simulation!=true" class="md-subhead error">{{errorText}}</span>
|
187
193
|
</md-card-title-text>
|
188
194
|
</md-card-title>
|
189
195
|
<md-card-content>
|
190
|
-
<nvd3 class="h-320 remove-x-lines" options="monthlyNetChartOptions" data="monthlyNetChartData[feature.name]"></nvd3>
|
196
|
+
<nvd3 class="h-320 remove-x-lines" options="monthlyNetChartOptions[feature.name]" data="monthlyNetChartData[feature.name]"></nvd3>
|
191
197
|
</md-card-content>
|
192
198
|
</md-card>
|
193
199
|
</div>
|
@@ -205,7 +211,7 @@
|
|
205
211
|
</md-card-title-text>
|
206
212
|
</md-card-title>
|
207
213
|
<md-card-content>
|
208
|
-
<nvd3 class="h-420 remove-x-lines" options="annualEndUseChartOptions" data="annualEndUseChartData[feature.name]"></nvd3>
|
214
|
+
<nvd3 class="h-420 remove-x-lines" options="annualEndUseChartOptions[feature.name]" data="annualEndUseChartData[feature.name]"></nvd3>
|
209
215
|
</md-card-content>
|
210
216
|
</md-card>
|
211
217
|
</div>
|
@@ -225,10 +231,10 @@
|
|
225
231
|
myApp.controller('MyAppCtrl', function ($scope) {
|
226
232
|
$scope.features = scenarioData;
|
227
233
|
|
228
|
-
$scope.
|
234
|
+
$scope.defaultMonthlyFuelChartOptions = {
|
229
235
|
chart: {
|
230
236
|
type: 'multiBarChart',
|
231
|
-
color: ['#187C7C', '#8CC025', '#CE2828'],
|
237
|
+
color: ['#187C7C', '#8CC025', '#CE2828', '#AFECE7', '#F19953'],
|
232
238
|
height: 320,
|
233
239
|
margin: {
|
234
240
|
top: 45,
|
@@ -272,7 +278,7 @@
|
|
272
278
|
}
|
273
279
|
};
|
274
280
|
|
275
|
-
$scope.
|
281
|
+
$scope.defaultMonthlyNetChartOptions = {
|
276
282
|
chart: {
|
277
283
|
type: 'multiBarChart',
|
278
284
|
color: ['#014D4D'],
|
@@ -319,7 +325,7 @@
|
|
319
325
|
}
|
320
326
|
};
|
321
327
|
|
322
|
-
$scope.
|
328
|
+
$scope.defaultAnnualEndUseChartOptions = {
|
323
329
|
chart: {
|
324
330
|
type: 'multiBarChart',
|
325
331
|
// color: ['#014D4D'],
|
@@ -370,11 +376,17 @@
|
|
370
376
|
}
|
371
377
|
};
|
372
378
|
|
379
|
+
// use different options for each feature
|
380
|
+
$scope.monthlyFuelChartOptions = {};
|
381
|
+
$scope.monthlyNetChartOptions = {};
|
382
|
+
$scope.annualEndUseChartOptions = {};
|
383
|
+
|
373
384
|
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
374
385
|
|
375
|
-
var datasets = ['Electricity:Facility', 'ElectricityProduced:Facility', '
|
386
|
+
var datasets = ['Electricity:Facility', 'ElectricityProduced:Facility', 'NaturalGas:Facility', 'Propane:Facility', 'FuelOilNo2:Facility', 'OtherFuels:Facility'];
|
387
|
+
|
388
|
+
var endUseKeys = ['Heating:Electricity', 'Cooling:Electricity', 'InteriorLights:Electricity', 'ExteriorLights:Electricity', 'ExteriorEquipment:Electricity', 'InteriorEquipment:Electricity', 'Fans:Electricity', 'Pumps:Electricity', 'HeatRejection:Electricity', 'WaterSystems:Electricity'];
|
376
389
|
|
377
|
-
var endUseKeys = ['Heating:Electricity', 'Cooling:Electricity', 'InteriorLights:Electricity', 'ExteriorLights:Electricity', 'InteriorEquipment:Electricity', 'Fans:Electricity', 'Pumps:Electricity', 'HeatRejection:Electricity', 'WaterSystems:Electricity'];
|
378
390
|
|
379
391
|
var applicableEndUseKeys = [];
|
380
392
|
|
@@ -383,12 +395,18 @@
|
|
383
395
|
$scope.annualNetChartData = {};
|
384
396
|
|
385
397
|
$scope.annualEndUseChartData = {};
|
386
|
-
|
398
|
+
|
399
|
+
// calculate global maximums across features
|
387
400
|
var monthlyFuelYMax = 0;
|
388
401
|
var monthlyNetYMin = 0;
|
389
402
|
var monthlyNetYMax = 0;
|
390
|
-
|
391
403
|
var annualTotalYMax = 0;
|
404
|
+
|
405
|
+
// also record totals per feature
|
406
|
+
$scope.annualEndUseTotals = {};
|
407
|
+
$scope.monthlyFuelTotals = {};
|
408
|
+
$scope.monthlyNetTotals = {};
|
409
|
+
|
392
410
|
$scope.errorText = "No data. This feature either did not complete successfully or did not include an annual simulation ranging from January 1 to December 31.";
|
393
411
|
|
394
412
|
// figure out max total energy use and applicable end uses
|
@@ -398,65 +416,150 @@
|
|
398
416
|
|
399
417
|
_.forEach(endUseKeys, function (endUseKey) {
|
400
418
|
var endUseValue = feature.annual_values[endUseKey];
|
401
|
-
//console.log("endUseKey: ", endUseKey, "endUseValue: ", endUseValue);
|
419
|
+
// console.log("endUseKey: ", endUseKey, "endUseValue: ", endUseValue);
|
402
420
|
|
403
421
|
if (endUseValue == 0 || !endUseValue) {
|
404
422
|
console.log("no data found for: ", endUseKey);
|
405
423
|
}
|
406
424
|
else {
|
407
425
|
applicableEndUseKeys.push(endUseKey);
|
408
|
-
total_value += endUseValue
|
426
|
+
total_value += endUseValue;
|
409
427
|
}
|
410
428
|
});
|
429
|
+
// global maximum
|
411
430
|
annualTotalYMax = _.max([annualTotalYMax, total_value]);
|
431
|
+
|
412
432
|
});
|
413
433
|
|
414
434
|
applicableEndUseKeys = _.uniq(applicableEndUseKeys).sort();
|
415
435
|
|
416
|
-
|
436
|
+
// store global default
|
437
|
+
$scope.defaultAnnualEndUseChartOptions.chart['yDomain'] = [0, _.round(annualTotalYMax)];
|
438
|
+
|
417
439
|
// gather data for each feature
|
418
440
|
_.forEach($scope.features, function (feature) {
|
419
441
|
|
442
|
+
// calculate local maximums per feature
|
443
|
+
var localFuelYMax = 0;
|
444
|
+
var localNetYMax = 0;
|
445
|
+
var localNetYMin = 100000000;
|
446
|
+
var localEndUseMax = 0;
|
447
|
+
|
420
448
|
if(feature['complete_simulation'] == true){
|
449
|
+
|
421
450
|
// monthly fuel use
|
422
451
|
$scope.monthlyFuelChartData[feature.name] = [];
|
452
|
+
var changeToKbtu = false;
|
453
|
+
var kbtu_datasets = ['NaturalGas:Facility', 'Propane:Facility', 'FuelOilNo2:Facility', 'OtherFuels:Facility'];
|
454
|
+
// first iterate through all kbtu datasets to see if you'll need to change to kBtu units
|
455
|
+
_.forEach(kbtu_datasets, function (kbtu_dataset) {
|
456
|
+
var values = feature.monthly_values[kbtu_dataset];
|
457
|
+
if (!(values.every(item => item === 0))) {
|
458
|
+
changeToKbtu = true;
|
459
|
+
}
|
460
|
+
});
|
461
|
+
|
423
462
|
_.forEach(datasets, function (dataset) {
|
463
|
+
|
424
464
|
var values = feature.monthly_values[dataset];
|
465
|
+
var datasetUnit = "";
|
466
|
+
|
425
467
|
if (dataset == 'Electricity:Facility') {
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
}
|
441
|
-
}
|
442
|
-
})
|
468
|
+
// first check if there is data to include
|
469
|
+
if (!(values.every(item => item === 0))) {
|
470
|
+
console.log(changeToKbtu);
|
471
|
+
if (changeToKbtu) {
|
472
|
+
var kBtuValues = [];
|
473
|
+
var kwhValues = feature.monthly_values[dataset]
|
474
|
+
_.forEach(kwhValues, function (kwhValue) {
|
475
|
+
new_value = kwhValue*3.4121416; //convert kwh to kbtu
|
476
|
+
kBtuValues.push(new_value);
|
477
|
+
})
|
478
|
+
values = kBtuValues;
|
479
|
+
datasetUnit = 'Electricity:Facility(kBtu)';
|
480
|
+
} else {
|
481
|
+
datasetUnit = 'Electricity:Facility(kWh)';
|
482
|
+
}
|
483
|
+
}
|
484
|
+
} else if (dataset == 'ElectricityProduced:Facility') {
|
485
|
+
// first check if there is data to include
|
486
|
+
if (!(values.every(item => item === 0))) {
|
487
|
+
if (changeToKbtu) {
|
488
|
+
var kBtuValues = [];
|
489
|
+
var kwhValues = feature.monthly_values[dataset];
|
490
|
+
_.forEach(kwhValues, function (kwhValue) {
|
491
|
+
new_value = kwhValue*3.4121416; //convert kwh to kbtu
|
492
|
+
kBtuValues.push(new_value);
|
493
|
+
})
|
494
|
+
values = kBtuValues;
|
495
|
+
datasetUnit = 'ElectricityProduced:Facility(kBtu)';
|
496
|
+
|
497
|
+
} else {
|
498
|
+
datasetUnit = 'ElectricityProduced:Facility(kWh)'
|
499
|
+
}
|
500
|
+
}
|
501
|
+
} else {
|
502
|
+
// everything else gets kBtu for now
|
503
|
+
if (!(values.every(item => item === 0))) {
|
504
|
+
datasetUnit = dataset + '(kBtu)';
|
505
|
+
}
|
506
|
+
};
|
507
|
+
// if datasetUnit is empty string, there is no data so don't push it in the array
|
508
|
+
if (datasetUnit != ""){
|
509
|
+
$scope.monthlyFuelChartData[feature.name].push({
|
510
|
+
key: datasetUnit,
|
511
|
+
values: _.map(values, function (value, i) {
|
512
|
+
value;
|
513
|
+
// global
|
514
|
+
monthlyFuelYMax = _.max([monthlyFuelYMax, value]);
|
515
|
+
// local
|
516
|
+
localFuelYMax = _.max([localFuelYMax, value]);
|
517
|
+
return {
|
518
|
+
x: months[i],
|
519
|
+
y: value
|
520
|
+
};
|
521
|
+
})
|
522
|
+
});
|
523
|
+
}
|
443
524
|
});
|
444
|
-
|
525
|
+
// calculate both the global (default) max and the per-feature max
|
526
|
+
$scope.monthlyFuelTotals[feature.name] = _.round(localFuelYMax);
|
527
|
+
$scope.defaultMonthlyFuelChartOptions.chart['yDomain'] = [0, _.round(monthlyFuelYMax)];
|
445
528
|
}
|
446
529
|
|
447
530
|
// monthly net use
|
448
|
-
|
449
531
|
if(feature['complete_simulation'] == true){
|
450
532
|
$scope.monthlyNetChartData[feature.name] = [];
|
533
|
+
var values = feature.monthly_values['NaturalGas:Facility'];
|
534
|
+
var changeToKbtu = false;
|
535
|
+
if (!(values.every(item => item === 0))) {
|
536
|
+
changeToKbtu = true
|
537
|
+
}
|
538
|
+
if (changeToKbtu){
|
539
|
+
var unit = ' (kBtu)'
|
540
|
+
}
|
541
|
+
else {
|
542
|
+
var unit = ' (kWh)'
|
543
|
+
}
|
544
|
+
|
451
545
|
$scope.annualNetChartData[feature.name] = 0;
|
452
546
|
$scope.monthlyNetChartData[feature.name].push({
|
453
|
-
key: 'Net Energy Use',
|
547
|
+
key: 'Net Energy Use' + unit,
|
454
548
|
values: _.map(months, function (month, i) {
|
455
|
-
|
549
|
+
if (changeToKbtu){
|
550
|
+
var value = feature.monthly_values['Electricity:Facility'][i]*3.41 - feature.monthly_values['ElectricityProduced:Facility'][i]*3.41 + feature.monthly_values['NaturalGas:Facility'][i]; //Values are in kBtu
|
551
|
+
}
|
552
|
+
else {
|
553
|
+
var value = feature.monthly_values['Electricity:Facility'][i] - feature.monthly_values['ElectricityProduced:Facility'][i]; //Values are in kWh
|
554
|
+
}
|
456
555
|
value;
|
457
556
|
$scope.annualNetChartData[feature.name] += value;
|
557
|
+
// global
|
458
558
|
monthlyNetYMin = _.min([monthlyNetYMin, value]);
|
459
559
|
monthlyNetYMax = _.max([monthlyNetYMax, value]);
|
560
|
+
// local
|
561
|
+
localNetYMax = _.max([localNetYMax, value]);
|
562
|
+
localNetYMin = _.min([localNetYMin, value]);
|
460
563
|
return {
|
461
564
|
x: month,
|
462
565
|
y: value
|
@@ -464,32 +567,86 @@
|
|
464
567
|
})
|
465
568
|
});
|
466
569
|
$scope.annualNetChartData[feature.name] = _.round($scope.annualNetChartData[feature.name]);
|
467
|
-
|
570
|
+
// calculate global range and local range
|
571
|
+
$scope.monthlyNetTotals[feature.name] = [_.round(localNetYMin), _.round(localNetYMax)];
|
572
|
+
$scope.defaultMonthlyNetChartOptions.chart['yDomain'] = [_.round(monthlyNetYMin), _.round(monthlyNetYMax)];
|
468
573
|
}
|
469
574
|
|
470
575
|
// annual end use
|
471
|
-
if(feature['complete_simulation'] == true){
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
576
|
+
if(feature['complete_simulation'] == true) {
|
577
|
+
$scope.annualEndUseChartData[feature.name] = [];
|
578
|
+
// Find all applicable end uses
|
579
|
+
_.forEach(applicableEndUseKeys, function (endUseKey){
|
580
|
+
var endUseValue = feature.annual_values[endUseKey]
|
581
|
+
|
582
|
+
localEndUseMax += endUseValue
|
583
|
+
// console.log("endUseKey: ", endUseKey, " endUseValue: ", endUseValue);
|
584
|
+
|
585
|
+
$scope.annualEndUseChartData[feature.name].push({
|
586
|
+
key: endUseKey,
|
587
|
+
values: [{
|
588
|
+
x: 'End Use',
|
589
|
+
y: endUseValue
|
590
|
+
}]
|
591
|
+
});
|
592
|
+
|
485
593
|
});
|
486
|
-
|
487
|
-
|
488
|
-
|
594
|
+
|
595
|
+
// also store local maximum for each feature
|
596
|
+
$scope.annualEndUseTotals[feature.name] = _.round(localEndUseMax);
|
597
|
+
|
489
598
|
}
|
490
599
|
});
|
600
|
+
|
601
|
+
// assign chart options for each feature. assign global maximum to start
|
602
|
+
_.forEach($scope.features, function (feature) {
|
603
|
+
$scope.monthlyFuelChartOptions[feature.name] = _.cloneDeep($scope.defaultMonthlyFuelChartOptions);
|
604
|
+
$scope.monthlyNetChartOptions[feature.name] = _.cloneDeep($scope.defaultMonthlyNetChartOptions);
|
605
|
+
$scope.annualEndUseChartOptions[feature.name] = _.cloneDeep($scope.defaultAnnualEndUseChartOptions);
|
606
|
+
|
491
607
|
});
|
492
|
-
|
608
|
+
|
609
|
+
// console.log("LOCAL MAXES:");
|
610
|
+
// console.log($scope.annualEndUseTotals);
|
611
|
+
// console.log($scope.monthlyFuelTotals);
|
612
|
+
// console.log($scope.monthlyNetTotals);
|
613
|
+
// console.log("GLOBAL MAXES:");
|
614
|
+
// console.log(annualTotalYMax);
|
615
|
+
// console.log(monthlyNetYMin, monthlyNetYMax);
|
616
|
+
// console.log(monthlyFuelYMax);
|
617
|
+
// console.log("OPTIONS:")
|
618
|
+
// console.log($scope.annualEndUseChartOptions);
|
619
|
+
// console.log($scope.monthlyFuelChartOptions);
|
620
|
+
// console.log($scope.monthlyNetChartOptions);
|
621
|
+
|
622
|
+
// change Y axes from global maximum to local maximum
|
623
|
+
$scope.axes = 0;
|
624
|
+
|
625
|
+
$scope.toggleAxes = function () {
|
626
|
+
|
627
|
+
if ($scope.axes == 0) {
|
628
|
+
|
629
|
+
// change axis
|
630
|
+
_.forEach($scope.features, function (feature) {
|
631
|
+
$scope.monthlyFuelChartOptions[feature.name].chart['yDomain'] = [0, $scope.monthlyFuelTotals[feature.name]];
|
632
|
+
$scope.monthlyNetChartOptions[feature.name].chart['yDomain'] = $scope.monthlyNetTotals[feature.name];
|
633
|
+
$scope.annualEndUseChartOptions[feature.name].chart['yDomain'] = [0, $scope.annualEndUseTotals[feature.name]];
|
634
|
+
});
|
635
|
+
|
636
|
+
$scope.axes = 1;
|
637
|
+
|
638
|
+
} else {
|
639
|
+
|
640
|
+
_.forEach($scope.features, function (feature) {
|
641
|
+
$scope.monthlyFuelChartOptions[feature.name].chart['yDomain'] = _.cloneDeep($scope.defaultMonthlyFuelChartOptions.chart['yDomain']);
|
642
|
+
$scope.monthlyNetChartOptions[feature.name].chart['yDomain'] = _.cloneDeep($scope.defaultMonthlyNetChartOptions.chart['yDomain']);
|
643
|
+
$scope.annualEndUseChartOptions[feature.name].chart['yDomain'] = _.cloneDeep($scope.defaultAnnualEndUseChartOptions.chart['yDomain']);
|
644
|
+
});
|
645
|
+
$scope.axes = 0;
|
646
|
+
}
|
647
|
+
};
|
648
|
+
|
649
|
+
});
|
493
650
|
|
494
651
|
_.delay(function () {
|
495
652
|
window.dispatchEvent(new Event('resize'));
|