urbanopt-cli 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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'));