urbanopt-scenario 0.1.1 → 0.3.0
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 +5 -5
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -8
- data/.github/ISSUE_TEMPLATE/feature_request.md +2 -10
- data/.github/pull_request_template.md +5 -15
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +45 -1
- data/{.github/CONTRIBUTING.md → CONTRIBUTING.md} +0 -0
- data/Gemfile +8 -12
- data/Jenkinsfile +2 -2
- data/Rakefile +2 -2
- data/docs/package-lock.json +4607 -6451
- data/docs/package.json +1 -1
- data/lib/measures/.rubocop.yml +1 -1
- data/lib/measures/default_feature_reports/LICENSE.md +1 -1
- data/lib/measures/default_feature_reports/README.md +5 -35
- data/lib/measures/default_feature_reports/measure.rb +315 -44
- data/lib/measures/default_feature_reports/measure.xml +38 -17
- data/lib/urbanopt/scenario.rb +1 -0
- data/lib/urbanopt/scenario/default_reports/distributed_generation.rb +209 -17
- data/lib/urbanopt/scenario/default_reports/feature_report.rb +57 -3
- data/lib/urbanopt/scenario/default_reports/power_distribution.rb +102 -0
- data/lib/urbanopt/scenario/default_reports/program.rb +6 -2
- data/lib/urbanopt/scenario/default_reports/reporting_period.rb +15 -9
- data/lib/urbanopt/scenario/default_reports/scenario_report.rb +24 -7
- data/lib/urbanopt/scenario/default_reports/schema/README.md +11 -12
- data/lib/urbanopt/scenario/default_reports/schema/scenario_csv_columns.txt +33 -12
- data/lib/urbanopt/scenario/default_reports/schema/scenario_schema.json +52 -25
- data/lib/urbanopt/scenario/default_reports/solar_pv.rb +1 -0
- data/lib/urbanopt/scenario/default_reports/timeseries_csv.rb +62 -21
- data/lib/urbanopt/scenario/scenario_post_processor_opendss.rb +276 -0
- data/lib/urbanopt/scenario/scenario_runner_osw.rb +21 -5
- data/lib/urbanopt/scenario/simulation_dir_osw.rb +0 -4
- data/lib/urbanopt/scenario/version.rb +1 -1
- data/urbanopt-scenario-gem.gemspec +10 -12
- metadata +31 -48
- data/.travis.yml +0 -23
- data/lib/change_log.rb +0 -147
- data/lib/measures/default_feature_reports/tests/USA_CO_Golden-NREL.724666_TMY3.epw +0 -8768
- data/lib/measures/default_feature_reports/tests/default_feature_reports_test.rb +0 -238
- data/lib/measures/default_feature_reports/tests/example_model.osm +0 -4378
data/docs/package.json
CHANGED
@@ -13,7 +13,7 @@
|
|
13
13
|
"highlight.js": "^9.15.6",
|
14
14
|
"json-schema-ref-parser": "^6.1.0",
|
15
15
|
"json-schema-view-js": "git+https://git@github.com/bgschiller/json-schema-view-js.git",
|
16
|
-
"vuepress": "^
|
16
|
+
"vuepress": "^1.2.0",
|
17
17
|
"webpack-dev-middleware": "^3.6.0"
|
18
18
|
},
|
19
19
|
"devDependencies": {
|
data/lib/measures/.rubocop.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
URBANopt, Copyright (c) 2019, Alliance for Sustainable Energy, LLC, and other
|
1
|
+
URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
2
|
contributors. All rights reserved.
|
3
3
|
|
4
4
|
Redistribution and use in source and binary forms, with or without modification,
|
@@ -2,16 +2,16 @@
|
|
2
2
|
|
3
3
|
###### (Automatically generated documentation)
|
4
4
|
|
5
|
-
#
|
5
|
+
#
|
6
6
|
|
7
7
|
## Description
|
8
|
-
|
8
|
+
|
9
9
|
|
10
10
|
## Modeler Description
|
11
|
-
|
11
|
+
|
12
12
|
|
13
13
|
## Measure Type
|
14
|
-
|
14
|
+
ModelMeasure
|
15
15
|
|
16
16
|
## Taxonomy
|
17
17
|
|
@@ -19,38 +19,8 @@ ReportingMeasure
|
|
19
19
|
## Arguments
|
20
20
|
|
21
21
|
|
22
|
-
### Feature unique identifier
|
23
|
-
|
24
|
-
**Name:** feature_id,
|
25
|
-
**Type:** String,
|
26
|
-
**Units:** ,
|
27
|
-
**Required:** false,
|
28
|
-
**Model Dependent:** false
|
29
|
-
|
30
|
-
### Feature scenario specific name
|
31
|
-
|
32
|
-
**Name:** feature_name,
|
33
|
-
**Type:** String,
|
34
|
-
**Units:** ,
|
35
|
-
**Required:** false,
|
36
|
-
**Model Dependent:** false
|
37
|
-
|
38
|
-
### URBANopt Feature Type
|
39
|
-
|
40
|
-
**Name:** feature_type,
|
41
|
-
**Type:** String,
|
42
|
-
**Units:** ,
|
43
|
-
**Required:** false,
|
44
|
-
**Model Dependent:** false
|
45
|
-
|
46
|
-
### Reporting Frequency
|
47
|
-
The frequency at which to report timeseries output data.
|
48
|
-
**Name:** reporting_frequency,
|
49
|
-
**Type:** Choice,
|
50
|
-
**Units:** ,
|
51
|
-
**Required:** true,
|
52
|
-
**Model Dependent:** false
|
53
22
|
|
54
23
|
|
24
|
+
This measure does not have any user arguments
|
55
25
|
|
56
26
|
|
@@ -44,7 +44,7 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
44
44
|
|
45
45
|
# human readable description
|
46
46
|
def description
|
47
|
-
return 'Writes default_feature_reports.json
|
47
|
+
return 'Writes default_feature_reports.json and default_feature_reports.csv files used by URBANopt Scenario Default Post Processor'
|
48
48
|
end
|
49
49
|
|
50
50
|
# human readable description of modeling approach
|
@@ -77,7 +77,8 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
77
77
|
reporting_frequency_chs << 'Timestep'
|
78
78
|
reporting_frequency_chs << 'Hourly'
|
79
79
|
reporting_frequency_chs << 'Daily'
|
80
|
-
# reporting_frequency_chs <<
|
80
|
+
# reporting_frequency_chs << 'Zone Timestep'
|
81
|
+
reporting_frequency_chs << 'BillingPeriod' # match it to utility bill object
|
81
82
|
## Utility report here to report the start and end for each fueltype
|
82
83
|
reporting_frequency_chs << 'Monthly'
|
83
84
|
reporting_frequency_chs << 'Runperiod'
|
@@ -85,17 +86,13 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
85
86
|
reporting_frequency = OpenStudio::Measure::OSArgument.makeChoiceArgument('reporting_frequency', reporting_frequency_chs, true)
|
86
87
|
reporting_frequency.setDisplayName('Reporting Frequency')
|
87
88
|
reporting_frequency.setDescription('The frequency at which to report timeseries output data.')
|
88
|
-
reporting_frequency.setDefaultValue('
|
89
|
+
reporting_frequency.setDefaultValue('Timestep')
|
89
90
|
args << reporting_frequency
|
90
91
|
|
91
|
-
# move this in the run method
|
92
|
-
if reporting_frequency.defaultValueDisplayName == 'BillingPeriod'
|
93
|
-
@@logger.error('BillingPeriod frequency is not implemented yet')
|
94
|
-
end
|
95
|
-
|
96
92
|
return args
|
97
93
|
end
|
98
94
|
|
95
|
+
# define fuel types
|
99
96
|
def fuel_types
|
100
97
|
fuel_types = [
|
101
98
|
'Electricity',
|
@@ -109,6 +106,7 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
109
106
|
return fuel_types
|
110
107
|
end
|
111
108
|
|
109
|
+
# define enduses
|
112
110
|
def end_uses
|
113
111
|
end_uses = [
|
114
112
|
'Heating',
|
@@ -131,6 +129,24 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
131
129
|
return end_uses
|
132
130
|
end
|
133
131
|
|
132
|
+
# format datetime
|
133
|
+
def format_datetime(date_time)
|
134
|
+
date_time.tr!('-', '/')
|
135
|
+
date_time.gsub!('Jan', '01')
|
136
|
+
date_time.gsub!('Feb', '02')
|
137
|
+
date_time.gsub!('Mar', '03')
|
138
|
+
date_time.gsub!('Apr', '04')
|
139
|
+
date_time.gsub!('May', '05')
|
140
|
+
date_time.gsub!('Jun', '06')
|
141
|
+
date_time.gsub!('Jul', '07')
|
142
|
+
date_time.gsub!('Aug', '08')
|
143
|
+
date_time.gsub!('Sep', '09')
|
144
|
+
date_time.gsub!('Oct', '10')
|
145
|
+
date_time.gsub!('Nov', '11')
|
146
|
+
date_time.gsub!('Dec', '12')
|
147
|
+
return date_time
|
148
|
+
end
|
149
|
+
|
134
150
|
# return a vector of IdfObject's to request EnergyPlus objects needed by the run method
|
135
151
|
# rubocop:disable Naming/MethodName
|
136
152
|
def energyPlusOutputRequests(runner, user_arguments)
|
@@ -152,17 +168,30 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
152
168
|
end
|
153
169
|
end
|
154
170
|
|
155
|
-
|
171
|
+
# Request the output for each end use/fuel type combination
|
156
172
|
result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,Electricity:Facility,#{reporting_frequency};").get
|
157
173
|
result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,ElectricityProduced:Facility,#{reporting_frequency};").get
|
158
174
|
result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,Gas:Facility,#{reporting_frequency};").get
|
159
175
|
result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,DistrictCooling:Facility,#{reporting_frequency};").get
|
160
176
|
result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,DistrictHeating:Facility,#{reporting_frequency};").get
|
177
|
+
# result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,Cooling:Electricity,#{reporting_frequency};").get
|
178
|
+
# result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,Heating:Electricity,#{reporting_frequency};").get
|
179
|
+
# result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,InteriorLights:Electricity,#{reporting_frequency};").get
|
180
|
+
# result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,ExteriorLights:Electricity,#{reporting_frequency};").get
|
181
|
+
# result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,InteriorEquipment:Electricity,#{reporting_frequency};").get
|
182
|
+
# result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,Fans:Electricity,#{reporting_frequency};").get
|
183
|
+
# result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,Pumps:Electricity,#{reporting_frequency};").get
|
184
|
+
# result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,WaterSystems:Electricity,#{reporting_frequency};").get
|
185
|
+
# result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,Heating:Gas,#{reporting_frequency};").get
|
186
|
+
# result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,WaterSystems:Gas,#{reporting_frequency};").get
|
187
|
+
# result << OpenStudio::IdfObject.load("Output:Meter:MeterFileOnly,InteriorEquipment:Gas,#{reporting_frequency};").get
|
188
|
+
result << OpenStudio::IdfObject.load('Output:Variable,*,Heating Coil Heating Rate,hourly; !- HVAC Average [W];').get
|
161
189
|
|
162
190
|
timeseries_data = ['District Cooling Chilled Water Rate', 'District Cooling Mass Flow Rate',
|
163
191
|
'District Cooling Inlet Temperature', 'District Cooling Outlet Temperature',
|
164
192
|
'District Heating Hot Water Rate', 'District Heating Mass Flow Rate',
|
165
|
-
'District Heating Inlet Temperature', 'District Heating Outlet Temperature'
|
193
|
+
'District Heating Inlet Temperature', 'District Heating Outlet Temperature', 'Cooling Coil Total Cooling Rate',
|
194
|
+
'Heating Coil Heating Rate']
|
166
195
|
|
167
196
|
timeseries_data.each do |ts|
|
168
197
|
result << OpenStudio::IdfObject.load("Output:Variable,*,#{ts},#{reporting_frequency};").get
|
@@ -229,6 +258,11 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
229
258
|
# Assign the user inputs to variables
|
230
259
|
reporting_frequency = runner.getStringArgumentValue('reporting_frequency', user_arguments)
|
231
260
|
|
261
|
+
# BilingPeriod reporting frequency not implemented yet
|
262
|
+
if reporting_frequency == 'BillingPeriod'
|
263
|
+
@@logger.error('BillingPeriod frequency is not implemented yet')
|
264
|
+
end
|
265
|
+
|
232
266
|
# cache runner for this instance of the measure
|
233
267
|
@runner = runner
|
234
268
|
|
@@ -271,7 +305,10 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
271
305
|
feature_report.name = feature_name
|
272
306
|
feature_report.feature_type = feature_type
|
273
307
|
feature_report.directory_name = workflow.absoluteRunDir
|
274
|
-
|
308
|
+
|
309
|
+
timesteps_per_hour = model.getTimestep.numberOfTimestepsPerHour
|
310
|
+
feature_report.timesteps_per_hour = timesteps_per_hour
|
311
|
+
|
275
312
|
feature_report.simulation_status = 'Complete'
|
276
313
|
|
277
314
|
feature_report.reporting_periods << URBANopt::Scenario::DefaultReports::ReportingPeriod.new
|
@@ -434,6 +471,10 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
434
471
|
aspect_ratio ||= nil
|
435
472
|
feature_report.program.aspect_ratio = aspect_ratio
|
436
473
|
|
474
|
+
# total_construction_cost
|
475
|
+
total_construction_cost = sql_query(runner, sql_file, 'Life-Cycle Cost Report', "TableName='Present Value for Recurring, Nonrecurring and Energy Costs (Before Tax)' AND RowName='LCC_MAT - BUILDING - LIFE CYCLE COSTS' AND ColumnName='Cost'")
|
476
|
+
feature_report.program.total_construction_cost = total_construction_cost
|
477
|
+
|
437
478
|
############################################################################
|
438
479
|
##
|
439
480
|
# Get Reporting Periods information and store in the feature_report
|
@@ -544,6 +585,19 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
544
585
|
photovoltaic_power = sql_query(runner, sql_file, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Electric Loads Satisfied' AND RowName='Photovoltaic Power' AND ColumnName='Electricity'")
|
545
586
|
feature_report.reporting_periods[0].energy_production[:electricity_produced][:photovoltaic] = convert_units(photovoltaic_power, 'GJ', 'kBtu')
|
546
587
|
|
588
|
+
## Total utility cost
|
589
|
+
total_utility_cost = sql_query(runner, sql_file, 'Economics Results Summary Report', "TableName='Annual Cost' AND RowName='Cost' AND ColumnName='Total'")
|
590
|
+
feature_report.reporting_periods[0].total_utility_cost = total_utility_cost
|
591
|
+
|
592
|
+
## Utility Costs
|
593
|
+
# electricity utility cost
|
594
|
+
elec_utility_cost = sql_query(runner, sql_file, 'Economics Results Summary Report', "TableName='Annual Cost' AND RowName='Cost' AND ColumnName='Electric'")
|
595
|
+
feature_report.reporting_periods[0].utility_costs[0][:fuel_type] = 'Electricity'
|
596
|
+
feature_report.reporting_periods[0].utility_costs[0][:total_cost] = elec_utility_cost
|
597
|
+
# gas utility cost
|
598
|
+
gas_utility_cost = sql_query(runner, sql_file, 'Economics Results Summary Report', "TableName='Annual Cost' AND RowName='Cost' AND ColumnName='Gas'")
|
599
|
+
feature_report.reporting_periods[0].utility_costs << { fuel_type: 'Natural Gas', total_cost: gas_utility_cost }
|
600
|
+
|
547
601
|
## comfort_result
|
548
602
|
# time_setpoint_not_met_during_occupied_cooling
|
549
603
|
time_setpoint_not_met_during_occupied_cooling = sql_query(runner, sql_file, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Comfort and Setpoint Not Met Summary' AND RowName='Time Setpoint Not Met During Occupied Cooling' AND ColumnName='Facility'")
|
@@ -580,6 +634,19 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
580
634
|
'Electricity:Facility',
|
581
635
|
'ElectricityProduced:Facility',
|
582
636
|
'Gas:Facility',
|
637
|
+
'Cooling:Electricity',
|
638
|
+
'Heating:Electricity',
|
639
|
+
'InteriorLights:Electricity',
|
640
|
+
'ExteriorLights:Electricity',
|
641
|
+
'InteriorEquipment:Electricity',
|
642
|
+
'Fans:Electricity',
|
643
|
+
'Pumps:Electricity',
|
644
|
+
'WaterSystems:Electricity',
|
645
|
+
'HeatRejection:Electricity',
|
646
|
+
'HeatRejection:Gas',
|
647
|
+
'Heating:Gas',
|
648
|
+
'WaterSystems:Gas',
|
649
|
+
'InteriorEquipment:Gas',
|
583
650
|
'DistrictCooling:Facility',
|
584
651
|
'DistrictHeating:Facility',
|
585
652
|
'District Cooling Chilled Water Rate',
|
@@ -589,26 +656,58 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
589
656
|
'District Heating Hot Water Rate',
|
590
657
|
'District Heating Mass Flow Rate',
|
591
658
|
'District Heating Inlet Temperature',
|
592
|
-
'District Heating Outlet Temperature'
|
659
|
+
'District Heating Outlet Temperature',
|
660
|
+
'Cooling Coil Total Cooling Rate',
|
661
|
+
'Heating Coil Heating Rate'
|
593
662
|
]
|
594
663
|
|
664
|
+
# add thermal comfort timeseries
|
665
|
+
comfortTimeseries = ['Zone Thermal Comfort Fanger Model PMV', 'Zone Thermal Comfort Fanger Model PPD']
|
666
|
+
requested_timeseries_names += comfortTimeseries
|
667
|
+
|
668
|
+
# add additional power timeseries (for calculating transformer apparent power to compare to rating ) in VA
|
669
|
+
powerTimeseries = ['Net Electric Energy', 'Electricity:Facility Power', 'ElectricityProduced:Facility Power', 'Electricity:Facility Apparent Power', 'ElectricityProduced:Facility Apparent Power', 'Net Power', 'Net Apparent Power']
|
670
|
+
requested_timeseries_names += powerTimeseries
|
671
|
+
|
672
|
+
# register info all timeseries
|
673
|
+
runner.registerInfo("All timeseries: #{requested_timeseries_names}")
|
674
|
+
|
675
|
+
# timeseries variables to keep to calculate power
|
676
|
+
tsToKeep = ['Electricity:Facility', 'ElectricityProduced:Facility']
|
677
|
+
tsToKeepIndexes = {}
|
678
|
+
|
679
|
+
### powerFactor ###
|
680
|
+
# use power_factor default: 0.9
|
681
|
+
# TODO: Set powerFactor default based on building type
|
682
|
+
powerFactor = 0.9
|
683
|
+
|
684
|
+
### power_conversion ###
|
685
|
+
# divide values by total_seconds to convert J to W (W = J/sec)
|
686
|
+
# divide values by total_hours to convert kWh to kW (kW = kWh/hrs)
|
687
|
+
total_seconds = (60 / timesteps_per_hour.to_f) * 60 # make sure timesteps_per_hour is a float in the division
|
688
|
+
total_hours = 1 / timesteps_per_hour.to_f # make sure timesteps_per_hour is a float in the division
|
689
|
+
# set power_conversion
|
690
|
+
power_conversion = total_hours # we set the power conversio to total_hours since we want to convert lWh to kW
|
691
|
+
puts "Power Converion: to convert kWh to kW values will be divided by #{power_conversion}"
|
692
|
+
|
595
693
|
# number of values in each timeseries
|
596
694
|
n = nil
|
597
|
-
|
598
|
-
# all numeric timeseries values, transpose of CSV file (e.g. values[j] is column, values[j][i] is column and row)
|
695
|
+
# all numeric timeseries values, transpose of CSV file (e.g. values[key_cnt] is column, values[key_cnt][i] is column and row)
|
599
696
|
values = []
|
600
|
-
|
601
|
-
#
|
697
|
+
tmpArray = []
|
698
|
+
# since schedule value will have a bunch of key_values, we need to keep track of these as additional timeseries
|
699
|
+
key_cnt = 0
|
602
700
|
# this is recording the name of these final timeseries to write in the header of the CSV
|
603
701
|
final_timeseries_names = []
|
604
702
|
|
605
703
|
# loop over requested timeseries
|
606
|
-
|
607
|
-
|
704
|
+
requested_timeseries_names.each_index do |i|
|
705
|
+
timeseries_name = requested_timeseries_names[i]
|
706
|
+
puts " *********timeseries_name = #{timeseries_name}******************"
|
608
707
|
runner.registerInfo("TIMESERIES: #{timeseries_name}")
|
609
708
|
|
610
|
-
# get all the key values that this timeseries can be reported for (e.g. if
|
611
|
-
key_values = sql_file.availableKeyValues(
|
709
|
+
# get all the key values that this timeseries can be reported for (e.g. if PMV is requested for each zone)
|
710
|
+
key_values = sql_file.availableKeyValues('RUN PERIOD 1', 'Zone Timestep', timeseries_name)
|
612
711
|
runner.registerInfo("KEY VALUES: #{key_values}")
|
613
712
|
if key_values.empty?
|
614
713
|
key_values = ['']
|
@@ -616,7 +715,7 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
616
715
|
|
617
716
|
# sort keys
|
618
717
|
sorted_keys = key_values.sort
|
619
|
-
requested_keys =
|
718
|
+
requested_keys = requested_timeseries_names
|
620
719
|
final_keys = []
|
621
720
|
# make sure aggregated timeseries are listed in sorted order before all individual feature timeseries
|
622
721
|
sorted_keys.each do |k|
|
@@ -649,7 +748,7 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
649
748
|
new_timeseries_name = key_value
|
650
749
|
end
|
651
750
|
end
|
652
|
-
final_timeseries_names << new_timeseries_name
|
751
|
+
# final_timeseries_names << new_timeseries_name
|
653
752
|
|
654
753
|
# get the actual timeseries
|
655
754
|
ts = sql_file.timeSeries(ann_env_pd.to_s, reporting_frequency.to_s, timeseries_name, key_value)
|
@@ -657,38 +756,210 @@ class DefaultFeatureReports < OpenStudio::Measure::ReportingMeasure
|
|
657
756
|
if n.nil?
|
658
757
|
# first timeseries should always be set
|
659
758
|
runner.registerInfo('First timeseries')
|
660
|
-
values[
|
661
|
-
n = values[
|
759
|
+
values[key_cnt] = ts.get.values
|
760
|
+
n = values[key_cnt].size
|
662
761
|
elsif ts.is_initialized
|
663
762
|
runner.registerInfo('Is Initialized')
|
664
|
-
values[
|
763
|
+
values[key_cnt] = ts.get.values
|
665
764
|
else
|
666
765
|
runner.registerInfo('Is NOT Initialized')
|
667
|
-
values[
|
766
|
+
values[key_cnt] = Array.new(n, 0)
|
767
|
+
end
|
768
|
+
|
769
|
+
# unit conversion
|
770
|
+
old_unit = ts.get.units if ts.is_initialized
|
771
|
+
|
772
|
+
if timeseries_name.include? 'Gas'
|
773
|
+
new_unit = 'kBtu'
|
774
|
+
else
|
775
|
+
new_unit = case old_unit.to_s
|
776
|
+
when 'J'
|
777
|
+
'kWh'
|
778
|
+
when 'kBtu'
|
779
|
+
'kWh'
|
780
|
+
when 'gal'
|
781
|
+
'm3'
|
782
|
+
when 'W'
|
783
|
+
'W'
|
784
|
+
end
|
668
785
|
end
|
669
786
|
|
670
|
-
#
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
787
|
+
# loop through each value and apply unit conversion
|
788
|
+
os_vec = values[key_cnt]
|
789
|
+
if !timeseries_name.include? 'Zone Thermal Comfort'
|
790
|
+
for i in 0..os_vec.length - 1
|
791
|
+
|
792
|
+
unless new_unit == old_unit || old_unit.nil? || new_unit.nil? || !ts.is_initialized
|
793
|
+
os_vec[i] = OpenStudio.convert(os_vec[i], old_unit, new_unit).get
|
794
|
+
end
|
795
|
+
|
796
|
+
end
|
797
|
+
end
|
798
|
+
|
799
|
+
# keep certain timeseries to calculate power
|
800
|
+
if tsToKeep.include? timeseries_name
|
801
|
+
tsToKeepIndexes[timeseries_name] = key_cnt
|
802
|
+
end
|
803
|
+
|
804
|
+
# special processing: power
|
805
|
+
if powerTimeseries.include? timeseries_name
|
806
|
+
# special case: net series (subtract generation from load)
|
807
|
+
if timeseries_name.include? 'Net'
|
808
|
+
|
809
|
+
newVals = Array.new(n, 0)
|
810
|
+
# Apparent power calculation
|
811
|
+
|
812
|
+
if timeseries_name.include?('Apparent')
|
813
|
+
(0..n - 1).each do |j|
|
814
|
+
newVals[j] = (values[tsToKeepIndexes['Electricity:Facility']][j].to_f - values[tsToKeepIndexes['ElectricityProduced:Facility']][j].to_f) / power_conversion / powerFactor
|
815
|
+
j += 1
|
816
|
+
end
|
817
|
+
new_unit = 'kVA'
|
818
|
+
elsif timeseries_name.include? 'Net Electric Energy'
|
819
|
+
(0..n - 1).each do |j|
|
820
|
+
newVals[j] = (values[tsToKeepIndexes['Electricity:Facility']][j].to_f - values[tsToKeepIndexes['ElectricityProduced:Facility']][j].to_f)
|
821
|
+
j += 1
|
822
|
+
end
|
823
|
+
new_unit = 'kWh'
|
824
|
+
else
|
825
|
+
runner.registerInfo('Power calc')
|
826
|
+
# Power calculation
|
827
|
+
(0..n - 1).each do |j|
|
828
|
+
newVals[j] = (values[tsToKeepIndexes['Electricity:Facility']][j].to_f - values[tsToKeepIndexes['ElectricityProduced:Facility']][j].to_f) / power_conversion
|
829
|
+
j += 1
|
830
|
+
end
|
831
|
+
new_unit = 'kW'
|
832
|
+
end
|
833
|
+
|
834
|
+
values[key_cnt] = newVals
|
835
|
+
else
|
836
|
+
tsToKeepIndexes.each do |key, indexValue|
|
837
|
+
if timeseries_name.include? key
|
838
|
+
runner.registerInfo("timeseries_name: #{timeseries_name}, key: #{key}")
|
839
|
+
# use this timeseries
|
840
|
+
newVals = Array.new(n, 0)
|
841
|
+
# Apparent power calculation
|
842
|
+
if timeseries_name.include?('Apparent')
|
843
|
+
(0..n - 1).each do |j|
|
844
|
+
newVals[j] = values[indexValue][j].to_f / power_conversion / powerFactor
|
845
|
+
j += 1
|
846
|
+
end
|
847
|
+
new_unit = 'kVA'
|
848
|
+
else
|
849
|
+
# Power calculation
|
850
|
+
(0..n - 1).each do |j|
|
851
|
+
newVals[j] = values[indexValue][j].to_f / power_conversion
|
852
|
+
j += 1
|
853
|
+
end
|
854
|
+
new_unit = 'kW'
|
855
|
+
end
|
856
|
+
values[key_cnt] = newVals
|
857
|
+
end
|
858
|
+
end
|
688
859
|
end
|
689
860
|
end
|
861
|
+
|
862
|
+
# append units to headers
|
863
|
+
new_timeseries_name += "(#{new_unit})"
|
864
|
+
final_timeseries_names << new_timeseries_name
|
865
|
+
|
866
|
+
# TODO: DELETE PUTS
|
867
|
+
# puts " *********timeseries_name = #{timeseries_name}******************"
|
868
|
+
# if timeseries_name.include? 'Power'
|
869
|
+
# puts "values = #{values[key_cnt]}"
|
870
|
+
# puts "units = #{new_unit}"
|
871
|
+
# end
|
872
|
+
|
873
|
+
# comfort results usually have multiple timeseries (per zone), aggregate into a single series with consistent name and use worst value at each timestep
|
874
|
+
if comfortTimeseries.include? timeseries_name
|
875
|
+
|
876
|
+
# set up array if 1st key_value
|
877
|
+
if key_i == 0
|
878
|
+
runner.registerInfo("SETTING UP NEW ARRAY FOR: #{timeseries_name}")
|
879
|
+
tmpArray = Array.new(n, 0)
|
880
|
+
end
|
881
|
+
|
882
|
+
# add to array (keep max value at each timestep)
|
883
|
+
(0..(n - 1)).each do |ind|
|
884
|
+
# process negative and positive values differently
|
885
|
+
tVal = values[key_cnt][ind].to_f
|
886
|
+
if tVal < 0
|
887
|
+
tmpArray[ind] = [tVal, tmpArray[ind]].min
|
888
|
+
else
|
889
|
+
tmpArray[ind] = [tVal, tmpArray[ind]].max
|
890
|
+
end
|
891
|
+
end
|
892
|
+
|
893
|
+
# aggregate and save when all keyvalues have been processed
|
894
|
+
if key_i == final_keys.size - 1
|
895
|
+
|
896
|
+
hrsOutOfBounds = 0
|
897
|
+
if timeseries_name === 'Zone Thermal Comfort Fanger Model PMV'
|
898
|
+
(0..(n - 1)).each do |ind|
|
899
|
+
# -0.5 < x < 0.5 is within bounds
|
900
|
+
if values[key_cnt][ind].to_f > 0.5 || values[key_cnt][ind].to_f < -0.5
|
901
|
+
hrsOutOfBounds += 1
|
902
|
+
end
|
903
|
+
end
|
904
|
+
hrsOutOfBounds = hrsOutOfBounds.to_f / timesteps_per_hour
|
905
|
+
elsif timeseries_name === 'Zone Thermal Comfort Fanger Model PPD'
|
906
|
+
(0..(n - 1)).each do |ind|
|
907
|
+
# > 20 is outside bounds
|
908
|
+
if values[key_cnt][ind].to_f > 20
|
909
|
+
hrsOutOfBounds += 1
|
910
|
+
end
|
911
|
+
end
|
912
|
+
hrsOutOfBounds = hrsOutOfBounds.to_f / timesteps_per_hour
|
913
|
+
else
|
914
|
+
# this one is already scaled by timestep, no need to divide total
|
915
|
+
(0..(n - 1)).each do |ind|
|
916
|
+
hrsOutOfBounds += values[key_cnt][ind].to_f if values[key_cnt][ind].to_f > 0
|
917
|
+
end
|
918
|
+
end
|
919
|
+
|
920
|
+
# save variable to feature_reports hash
|
921
|
+
runner.registerInfo("timeseries #{timeseries_name}: hours out of bounds: #{hrsOutOfBounds}")
|
922
|
+
if timeseries_name === 'Zone Thermal Comfort Fanger Model PMV'
|
923
|
+
feature_report.reporting_periods[0].comfort_result[:hours_out_of_comfort_bounds_PMV] = hrsOutOfBounds
|
924
|
+
elsif timeseries_name == 'Zone Thermal Comfort Fanger Model PPD'
|
925
|
+
feature_report.reporting_periods[0].comfort_result[:hours_out_of_comfort_bounds_PPD] = hrsOutOfBounds
|
926
|
+
end
|
927
|
+
|
928
|
+
end
|
929
|
+
|
930
|
+
end
|
931
|
+
|
932
|
+
# increment key_cnt in new_keys loop
|
933
|
+
key_cnt += 1
|
690
934
|
end
|
691
935
|
end
|
936
|
+
|
937
|
+
# Add datime column
|
938
|
+
datetimes = []
|
939
|
+
# check what timeseries is available
|
940
|
+
available_ts = sql_file.availableTimeSeries
|
941
|
+
puts "####### available_ts = #{available_ts}"
|
942
|
+
# get the timeseries for any of available timeseries
|
943
|
+
# RK: code enhancement needed
|
944
|
+
ts_d_e = sql_file.timeSeries(ann_env_pd.to_s, reporting_frequency.to_s, 'Electricity:Facility', '')
|
945
|
+
ts_d_g = sql_file.timeSeries(ann_env_pd.to_s, reporting_frequency.to_s, 'Gas:Facility', '')
|
946
|
+
|
947
|
+
if ts_d_e.is_initialized
|
948
|
+
timeseries_d = ts_d_e.get
|
949
|
+
elsif ts_d_g.is_initialized
|
950
|
+
timeseries_d = ts_d_g.get
|
951
|
+
else
|
952
|
+
raise 'ELECTRICITY and GAS results are not initiaized'
|
953
|
+
end
|
954
|
+
# get formated datetimes
|
955
|
+
timeseries_d.dateTimes.each do |datetime|
|
956
|
+
datetimes << format_datetime(datetime.to_s)
|
957
|
+
end
|
958
|
+
# insert datetimes to values
|
959
|
+
values.insert(0, datetimes)
|
960
|
+
# insert datetime header to names
|
961
|
+
final_timeseries_names.insert(0, 'Datetime')
|
962
|
+
|
692
963
|
# rubocop: enable Metrics/BlockLength
|
693
964
|
runner.registerInfo("new final_timeseries_names size: #{final_timeseries_names.size}")
|
694
965
|
|