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.
@@ -278,7 +278,10 @@ module URBANopt
278
278
  'Service',
279
279
  'Uncovered Parking',
280
280
  'Covered Parking',
281
- 'Mixed use'
281
+ 'Mixed use',
282
+ 'Single-Family',
283
+ 'Multifamily (2 to 4 units)',
284
+ 'Multifamily (5 or more units)'
282
285
  ]
283
286
  end
284
287
 
@@ -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] }} (kWh)</span>
185
- <span class="md-subhead">Monthly Net Energy (kWh)</span>
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.monthlyFuelChartOptions = {
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.monthlyNetChartOptions = {
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.annualEndUseChartOptions = {
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', 'Gas: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
- var datasetUnit = 'Electricity:Facility(kWh)';
427
- } else if (dataset == 'ElectricityProduced:Facility') {
428
- var datasetUnit = 'ElectricityProduced:Facility(kWh)'
429
- } else if (dataset == 'Gas:Facility') {
430
- var datasetUnit = 'Gas:Facility(kBtu)'
431
- };
432
- $scope.monthlyFuelChartData[feature.name].push({
433
- key: datasetUnit,
434
- values: _.map(values, function (value, i) {
435
- value;
436
- monthlyFuelYMax = _.max([monthlyFuelYMax, value]);
437
- return {
438
- x: months[i],
439
- y: value
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
- $scope.monthlyFuelChartOptions.chart['yDomain'] = [0, _.round(monthlyFuelYMax)];
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
- var value = feature.monthly_values['Electricity:Facility'][i] - feature.monthly_values['ElectricityProduced:Facility'][i] + (feature.monthly_values['Gas:Facility'][i]*0.293); //kBtu to kWh
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
- $scope.monthlyNetChartOptions.chart['yDomain'] = [_.round(monthlyNetYMin), _.round(monthlyNetYMax)];
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
- $scope.annualEndUseChartData[feature.name] = [];
473
- // Find all applicable end uses
474
- _.forEach(applicableEndUseKeys, function (endUseKey){
475
- var endUseValue = feature.annual_values[endUseKey]
476
-
477
- // console.log("endUseKey: ", endUseKey, " endUseValue: ", endUseValue);
478
-
479
- $scope.annualEndUseChartData[feature.name].push({
480
- key: endUseKey,
481
- values: [{
482
- x: 'End Use',
483
- y: endUseValue
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
- $scope.annualEndUseChartOptions.chart['yDomain'] = [0, _.round(1.1 * annualTotalYMax)];
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'));