urbanopt-scenario 0.3.0 → 0.4.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 +4 -4
- data/.github/pull_request_template.md +2 -2
- data/.gitignore +2 -0
- data/CHANGELOG.md +32 -0
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +33 -17
- data/Jenkinsfile +1 -1
- data/LICENSE.md +1 -1
- data/RDOC_MAIN.md +1 -1
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/docs/README.md +1 -1
- data/docs/package-lock.json +2499 -2322
- data/docs/package.json +13 -9
- data/lib/urbanopt-scenario.rb +1 -1
- data/lib/urbanopt/scenario.rb +2 -1
- data/lib/urbanopt/scenario/default_reports.rb +3 -8
- data/lib/urbanopt/scenario/extension.rb +1 -1
- data/lib/urbanopt/scenario/logger.rb +1 -1
- data/lib/urbanopt/scenario/scenario_base.rb +1 -1
- data/lib/urbanopt/scenario/scenario_csv.rb +22 -9
- data/lib/urbanopt/scenario/scenario_datapoint_base.rb +8 -1
- data/lib/urbanopt/scenario/scenario_post_processor_base.rb +1 -1
- data/lib/urbanopt/scenario/scenario_post_processor_default.rb +81 -8
- data/lib/urbanopt/scenario/scenario_post_processor_opendss.rb +6 -7
- data/lib/urbanopt/scenario/scenario_runner_base.rb +2 -2
- data/lib/urbanopt/scenario/scenario_runner_osw.rb +23 -9
- data/lib/urbanopt/scenario/scenario_visualization.rb +236 -0
- data/lib/urbanopt/scenario/simulation_dir_base.rb +1 -1
- data/lib/urbanopt/scenario/simulation_dir_osw.rb +2 -5
- data/lib/urbanopt/scenario/simulation_mapper_base.rb +1 -1
- data/lib/urbanopt/scenario/version.rb +2 -2
- data/package-lock.json +3 -0
- data/urbanopt-scenario-gem.gemspec +10 -6
- metadata +73 -46
- data/doc_templates/LICENSE.md +0 -27
- data/doc_templates/README.md.erb +0 -42
- data/doc_templates/copyright_erb.txt +0 -31
- data/doc_templates/copyright_js.txt +0 -4
- data/doc_templates/copyright_ruby.txt +0 -29
- data/lib/measures/.rubocop.yml +0 -5
- data/lib/measures/default_feature_reports/LICENSE.md +0 -27
- data/lib/measures/default_feature_reports/README.md +0 -26
- data/lib/measures/default_feature_reports/README.md.erb +0 -42
- data/lib/measures/default_feature_reports/measure.rb +0 -1013
- data/lib/measures/default_feature_reports/measure.xml +0 -160
- data/lib/urbanopt/scenario/default_reports/construction_cost.rb +0 -169
- data/lib/urbanopt/scenario/default_reports/date.rb +0 -97
- data/lib/urbanopt/scenario/default_reports/distributed_generation.rb +0 -379
- data/lib/urbanopt/scenario/default_reports/end_use.rb +0 -159
- data/lib/urbanopt/scenario/default_reports/end_uses.rb +0 -140
- data/lib/urbanopt/scenario/default_reports/feature_report.rb +0 -267
- data/lib/urbanopt/scenario/default_reports/generator.rb +0 -92
- data/lib/urbanopt/scenario/default_reports/location.rb +0 -99
- data/lib/urbanopt/scenario/default_reports/logger.rb +0 -44
- data/lib/urbanopt/scenario/default_reports/power_distribution.rb +0 -102
- data/lib/urbanopt/scenario/default_reports/program.rb +0 -265
- data/lib/urbanopt/scenario/default_reports/reporting_period.rb +0 -304
- data/lib/urbanopt/scenario/default_reports/scenario_report.rb +0 -317
- data/lib/urbanopt/scenario/default_reports/schema/README.md +0 -33
- data/lib/urbanopt/scenario/default_reports/schema/scenario_csv_columns.txt +0 -34
- data/lib/urbanopt/scenario/default_reports/schema/scenario_schema.json +0 -857
- data/lib/urbanopt/scenario/default_reports/solar_pv.rb +0 -93
- data/lib/urbanopt/scenario/default_reports/storage.rb +0 -105
- data/lib/urbanopt/scenario/default_reports/timeseries_csv.rb +0 -299
- data/lib/urbanopt/scenario/default_reports/validator.rb +0 -97
- data/lib/urbanopt/scenario/default_reports/wind.rb +0 -92
data/docs/package.json
CHANGED
@@ -10,17 +10,21 @@
|
|
10
10
|
},
|
11
11
|
"author": "NREL",
|
12
12
|
"dependencies": {
|
13
|
-
"highlight.js": "^
|
14
|
-
"json-schema-ref-parser": "^
|
13
|
+
"highlight.js": "^10.2.0",
|
14
|
+
"json-schema-ref-parser": "^9.0.6",
|
15
15
|
"json-schema-view-js": "git+https://git@github.com/bgschiller/json-schema-view-js.git",
|
16
|
-
"vuepress": "^1.
|
17
|
-
"webpack-dev-middleware": "^3.
|
16
|
+
"vuepress": "^1.5.4",
|
17
|
+
"webpack-dev-middleware": "^3.7.2"
|
18
18
|
},
|
19
19
|
"devDependencies": {
|
20
|
-
"braces": "
|
21
|
-
"
|
22
|
-
"
|
23
|
-
"
|
24
|
-
"
|
20
|
+
"braces": "^3.0.2",
|
21
|
+
"dot-prop": "^5.3.0",
|
22
|
+
"gh-pages": "^3.1.0",
|
23
|
+
"js-yaml": "^3.14.0",
|
24
|
+
"minimist": ">=1.2.3",
|
25
|
+
"node-forge": ">=0.10.0",
|
26
|
+
"serialize-javascript": "^5.0.1",
|
27
|
+
"set-value": "^3.0.2",
|
28
|
+
"yargs-parser": ">=18.1.1"
|
25
29
|
}
|
26
30
|
}
|
data/lib/urbanopt-scenario.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
data/lib/urbanopt/scenario.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -42,5 +42,6 @@ require 'urbanopt/scenario/scenario_runner_osw'
|
|
42
42
|
require 'urbanopt/scenario/simulation_dir_base'
|
43
43
|
require 'urbanopt/scenario/simulation_dir_osw'
|
44
44
|
require 'urbanopt/scenario/simulation_mapper_base'
|
45
|
+
require 'urbanopt/scenario/scenario_visualization'
|
45
46
|
|
46
47
|
require 'urbanopt/scenario/default_reports'
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -31,10 +31,5 @@
|
|
31
31
|
##
|
32
32
|
# Retrieve all default_reports classes.
|
33
33
|
##
|
34
|
-
|
35
|
-
require 'urbanopt/
|
36
|
-
require 'urbanopt/scenario/default_reports/logger'
|
37
|
-
require 'urbanopt/scenario/default_reports/program'
|
38
|
-
require 'urbanopt/scenario/default_reports/reporting_period'
|
39
|
-
require 'urbanopt/scenario/default_reports/scenario_report'
|
40
|
-
require 'urbanopt/scenario/default_reports/timeseries_csv'
|
34
|
+
|
35
|
+
require 'urbanopt/reporting/default_reports'
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -52,7 +52,6 @@ module URBANopt
|
|
52
52
|
|
53
53
|
def initialize(name, root_dir, run_dir, feature_file, mapper_files_dir, csv_file, num_header_rows)
|
54
54
|
super(name, root_dir, run_dir, feature_file)
|
55
|
-
|
56
55
|
@mapper_files_dir = mapper_files_dir
|
57
56
|
@csv_file = csv_file
|
58
57
|
@num_header_rows = num_header_rows
|
@@ -73,13 +72,27 @@ module URBANopt
|
|
73
72
|
|
74
73
|
# Require all simulation mappers in mapper_files_dir
|
75
74
|
def load_mapper_files
|
76
|
-
Dir.glob(File.join(@mapper_files_dir, '/*.rb'))
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
75
|
+
dirs = Dir.glob(File.join(@mapper_files_dir, '/*.rb'))
|
76
|
+
# order is not guaranteed...attempt to add Baseline first, then High Efficiency
|
77
|
+
ordered_dirs = []
|
78
|
+
bindex = dirs.find_index { |i| i.include? 'Baseline.rb' }
|
79
|
+
if bindex
|
80
|
+
ordered_dirs << dirs[bindex]
|
81
|
+
dirs.delete_at(bindex)
|
82
|
+
end
|
83
|
+
hindex = dirs.find_index { |i| i.include? 'HighEfficiency.rb' }
|
84
|
+
if hindex
|
85
|
+
ordered_dirs << dirs[hindex] if hindex
|
86
|
+
dirs.delete_at(hindex)
|
87
|
+
end
|
88
|
+
# then the rest
|
89
|
+
ordered_dirs += dirs
|
90
|
+
|
91
|
+
ordered_dirs.each do |f|
|
92
|
+
require(f)
|
93
|
+
rescue LoadError => e
|
94
|
+
@@logger.error(e.message)
|
95
|
+
raise
|
83
96
|
end
|
84
97
|
end
|
85
98
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -59,6 +59,13 @@ module URBANopt
|
|
59
59
|
@feature.feature_type
|
60
60
|
end
|
61
61
|
|
62
|
+
##
|
63
|
+
# Gets the type of a feature
|
64
|
+
##
|
65
|
+
def feature_location
|
66
|
+
@feature.feature_location
|
67
|
+
end
|
68
|
+
|
62
69
|
##
|
63
70
|
# Return the directory that this datapoint will run in.
|
64
71
|
##
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -29,12 +29,12 @@
|
|
29
29
|
# *********************************************************************************
|
30
30
|
|
31
31
|
require 'urbanopt/scenario/scenario_post_processor_base'
|
32
|
-
require 'urbanopt/
|
33
|
-
require 'urbanopt/scenario/default_reports/logger'
|
32
|
+
require 'urbanopt/reporting/default_reports'
|
34
33
|
|
35
34
|
require 'csv'
|
36
35
|
require 'json'
|
37
36
|
require 'fileutils'
|
37
|
+
require 'sqlite3'
|
38
38
|
|
39
39
|
module URBANopt
|
40
40
|
module Scenario
|
@@ -47,10 +47,11 @@ module URBANopt
|
|
47
47
|
def initialize(scenario_base)
|
48
48
|
super(scenario_base)
|
49
49
|
|
50
|
-
initialization_hash = { directory_name: scenario_base.run_dir, name: scenario_base.name, id: scenario_base.name }
|
51
|
-
@scenario_result = URBANopt::
|
50
|
+
@initialization_hash = { directory_name: scenario_base.run_dir, name: scenario_base.name, id: scenario_base.name }
|
51
|
+
@scenario_result = URBANopt::Reporting::DefaultReports::ScenarioReport.new(@initialization_hash)
|
52
|
+
@default_save_name = 'default_scenario_report'
|
52
53
|
|
53
|
-
@@logger ||= URBANopt::
|
54
|
+
@@logger ||= URBANopt::Reporting::DefaultReports.logger
|
54
55
|
end
|
55
56
|
|
56
57
|
##
|
@@ -70,7 +71,7 @@ module URBANopt
|
|
70
71
|
# [parameters:]
|
71
72
|
# +simulation_dir+ - _SimulationDirOSW_ - An object on SimulationDirOSW class.
|
72
73
|
def add_simulation_dir(simulation_dir)
|
73
|
-
feature_reports = URBANopt::
|
74
|
+
feature_reports = URBANopt::Reporting::DefaultReports::FeatureReport.from_simulation_dir(simulation_dir)
|
74
75
|
|
75
76
|
feature_reports.each do |feature_report|
|
76
77
|
if feature_report.to_hash[:simulation_status] == 'Complete'
|
@@ -83,12 +84,84 @@ module URBANopt
|
|
83
84
|
return feature_reports
|
84
85
|
end
|
85
86
|
|
87
|
+
# Create database file with scenario-level results
|
88
|
+
# Sum values for each timestep across all features. Save to new table in a new database
|
89
|
+
def create_scenario_db_file(file_name = @default_save_name)
|
90
|
+
new_db_file = File.join(@initialization_hash[:directory_name], "#{file_name}.db")
|
91
|
+
scenario_db = SQLite3::Database.open new_db_file
|
92
|
+
scenario_db.execute "CREATE TABLE IF NOT EXISTS ReportData(
|
93
|
+
TimeIndex INTEGER,
|
94
|
+
ReportDataDictionaryIndex INTEGER,
|
95
|
+
Value INTEGER
|
96
|
+
)"
|
97
|
+
|
98
|
+
values_arr = []
|
99
|
+
feature_list = Pathname.new(@initialization_hash[:directory_name]).children.select(&:directory?) # Folders in the run/scenario directory
|
100
|
+
feature_1_name = File.basename(feature_list[0]) # Get name of first feature, so we can read eplusout.sql from there
|
101
|
+
uo_output_sql_file = File.join(@initialization_hash[:directory_name], feature_1_name, 'eplusout.sql')
|
102
|
+
feature_list.each do |feature| # Loop through each feature in the scenario
|
103
|
+
feature_db = SQLite3::Database.open uo_output_sql_file
|
104
|
+
# Doing "db.results_as_hash = true" is prettier, but in this case significantly slower.
|
105
|
+
|
106
|
+
# RDDI == 10 is the timestep value for facility electricity
|
107
|
+
elec_query = feature_db.query "SELECT TimeIndex, Value
|
108
|
+
FROM ReportData
|
109
|
+
WHERE (TimeIndex % 2) != 0
|
110
|
+
AND ReportDataDictionaryIndex=10 order by TimeIndex"
|
111
|
+
|
112
|
+
elec_query.each do |row| # Add up all the values for electricity usage across all Features at this timestep
|
113
|
+
# row[0] == TimeIndex, row[1] == Value
|
114
|
+
arr_match = values_arr.find { |v| v[:time_index] == row[0] }
|
115
|
+
if arr_match.nil?
|
116
|
+
# add new row to value_arr
|
117
|
+
values_arr << { time_index: row[0], elec_val: Float(row[1]), gas_val: 0 }
|
118
|
+
else
|
119
|
+
# running sum
|
120
|
+
arr_match[:elec_val] += Float(row[1])
|
121
|
+
end
|
122
|
+
end # End elec_query
|
123
|
+
elec_query.close
|
124
|
+
|
125
|
+
# RDDI == 255 is the timestep value for facility gas
|
126
|
+
gas_query = feature_db.query "SELECT TimeIndex, Value
|
127
|
+
FROM ReportData
|
128
|
+
WHERE (TimeIndex % 2) != 0
|
129
|
+
AND ReportDataDictionaryIndex=255 order by TimeIndex"
|
130
|
+
|
131
|
+
gas_query.each do |row|
|
132
|
+
# row[0] == TimeIndex, row[1] == Value
|
133
|
+
arr_match = values_arr.find { |v| v[:time_index] == row[0] }
|
134
|
+
if arr_match.nil?
|
135
|
+
# add new row to value_arr
|
136
|
+
values_arr << { time_index: row[0], gas_val: Float(row[1]), elec_val: 0 }
|
137
|
+
else
|
138
|
+
# running sum
|
139
|
+
arr_match[:gas_val] += Float(row[1])
|
140
|
+
end
|
141
|
+
end # End gas_query
|
142
|
+
gas_query.close
|
143
|
+
feature_db.close
|
144
|
+
end # End feature_list loop
|
145
|
+
|
146
|
+
elec_sql = []
|
147
|
+
gas_sql = []
|
148
|
+
values_arr.each do |i|
|
149
|
+
elec_sql << "(#{i[:time_index]}, 10, #{i[:elec_val]})"
|
150
|
+
gas_sql << "(#{i[:time_index]}, 255, #{i[:gas_val]})"
|
151
|
+
end
|
152
|
+
|
153
|
+
# Put summed Values into the database
|
154
|
+
scenario_db.execute("INSERT INTO ReportData (TimeIndex, ReportDataDictionaryIndex, Value) VALUES #{elec_sql.join(', ')}")
|
155
|
+
scenario_db.execute("INSERT INTO ReportData (TimeIndex, ReportDataDictionaryIndex, Value) VALUES #{gas_sql.join(', ')}")
|
156
|
+
scenario_db.close
|
157
|
+
end
|
158
|
+
|
86
159
|
##
|
87
160
|
# Save scenario result
|
88
161
|
##
|
89
162
|
# [parameters:]
|
90
163
|
# +file_name+ - _String_ - Assign a name to the saved scenario results file
|
91
|
-
def save(file_name =
|
164
|
+
def save(file_name = @default_save_name)
|
92
165
|
@scenario_result.save
|
93
166
|
|
94
167
|
return @scenario_result
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -29,8 +29,7 @@
|
|
29
29
|
# *********************************************************************************
|
30
30
|
|
31
31
|
# require 'urbanopt/scenario/scenario_post_processor_base'
|
32
|
-
require 'urbanopt/
|
33
|
-
require 'urbanopt/scenario/default_reports/logger'
|
32
|
+
require 'urbanopt/reporting/default_reports'
|
34
33
|
|
35
34
|
require 'csv'
|
36
35
|
require 'json'
|
@@ -64,7 +63,7 @@ module URBANopt
|
|
64
63
|
@feature_reports_data = {}
|
65
64
|
|
66
65
|
# initialize logger
|
67
|
-
@@logger ||= URBANopt::
|
66
|
+
@@logger ||= URBANopt::Reporting::DefaultReports.logger
|
68
67
|
end
|
69
68
|
|
70
69
|
# load opendss data
|
@@ -166,9 +165,9 @@ module URBANopt
|
|
166
165
|
File.write(File.join(transformer_dir, 'feature_reports', 'default_feature_report_opendss' + '.csv'), transformer_csv)
|
167
166
|
|
168
167
|
# create transformer report
|
169
|
-
transformer_report = URBANopt::
|
170
|
-
|
171
|
-
|
168
|
+
transformer_report = URBANopt::Reporting::DefaultReports::FeatureReport.new(id: k, name: k, directory_name: transformer_dir, feature_type: 'Transformer',
|
169
|
+
timesteps_per_hour: @scenario_report.timesteps_per_hour,
|
170
|
+
simulation_status: 'complete')
|
172
171
|
|
173
172
|
# assign results to transfomrer report
|
174
173
|
transformer_report.power_distribution.over_voltage_hours = over_voltage_hrs
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -55,7 +55,7 @@ module URBANopt
|
|
55
55
|
# +force_clear+ - _Bool_ - Clear Scenario before creating Simulation input files.
|
56
56
|
#
|
57
57
|
# [return:] _Array_ Returns an array of all SimulationDirs, even those created previously, for Scenario.
|
58
|
-
def run(scenario, force_clear = false)
|
58
|
+
def run(scenario, force_clear = false, options = {})
|
59
59
|
raise 'run is not implemented for ScenarioRunnerBase, override in your class'
|
60
60
|
end
|
61
61
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *********************************************************************************
|
2
|
-
# URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
2
|
+
# URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
|
3
3
|
# contributors. All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -55,6 +55,7 @@ module URBANopt
|
|
55
55
|
end
|
56
56
|
|
57
57
|
FileUtils.mkdir_p(scenario.run_dir) if !File.exist?(scenario.run_dir)
|
58
|
+
FileUtils.rm_rf(File.join(scenario.run_dir, 'run_status.json')) if File.exist?(File.join(scenario.run_dir, 'run_status.json'))
|
58
59
|
|
59
60
|
simulation_dirs = scenario.simulation_dirs
|
60
61
|
|
@@ -81,10 +82,11 @@ module URBANopt
|
|
81
82
|
# +scenario+ - _ScenarioBase_ - Scenario to create and run SimulationFiles for.
|
82
83
|
# +force_clear+ - _Bool_ - Clear Scenario before creating SimulationFiles.
|
83
84
|
# [return:] _Array_ Returns array of all SimulationFiles, even those created previously, for Scenario.
|
84
|
-
def run(scenario, force_clear = false)
|
85
|
+
def run(scenario, force_clear = false, options = {})
|
85
86
|
# instantiate openstudio runner - use the defaults for now. If need to change then create
|
86
87
|
# the runner.conf file (i.e. run `rake openstudio:runner:init`)
|
87
|
-
|
88
|
+
# allow passing gemfile_path and bundle_install_path in options
|
89
|
+
runner = OpenStudio::Extension::Runner.new(scenario.root_dir, [], options)
|
88
90
|
|
89
91
|
# create simulation files
|
90
92
|
simulation_dirs = create_simulation_files(scenario, force_clear)
|
@@ -156,18 +158,30 @@ module URBANopt
|
|
156
158
|
# puts "DATAPOINT FAILURES: #{failures}"
|
157
159
|
# end
|
158
160
|
|
159
|
-
#
|
161
|
+
# write results to file and to command line
|
162
|
+
get_results(scenario, simulation_dirs)
|
163
|
+
|
164
|
+
return simulation_dirs
|
165
|
+
end
|
166
|
+
|
167
|
+
def get_results(scenario, simulation_dirs)
|
168
|
+
# look for other failed datapoints (command line display)
|
169
|
+
# also compile datapoint status for latest_run.json file
|
170
|
+
status_arr = []
|
160
171
|
failed_sims = []
|
161
|
-
simulation_dirs.each do |
|
162
|
-
if File.exist?(
|
163
|
-
failed_sims <<
|
172
|
+
simulation_dirs.each do |sim_dir|
|
173
|
+
if File.exist?(sim_dir.failed_job_path)
|
174
|
+
failed_sims << sim_dir.run_dir.split('/')[-1]
|
164
175
|
end
|
176
|
+
status_arr << { "id": sim_dir.feature_id, "status": sim_dir.simulation_status, "mapper_class": sim_dir.mapper_class }
|
165
177
|
end
|
178
|
+
|
179
|
+
# write to file
|
180
|
+
File.open(File.join(scenario.run_dir, 'run_status.json'), 'w') { |f| f.write JSON.pretty_generate("timestamp": Time.now.strftime('%Y-%m-%dT%k:%M:%S.%L'), "results": status_arr) }
|
181
|
+
|
166
182
|
if !failed_sims.empty?
|
167
183
|
puts "FAILED SIMULATION IDs: #{failed_sims.join(',')}"
|
168
184
|
end
|
169
|
-
|
170
|
-
return simulation_dirs
|
171
185
|
end
|
172
186
|
end
|
173
187
|
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt (tm), 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 'csv'
|
32
|
+
require 'date'
|
33
|
+
require 'json'
|
34
|
+
require 'fileutils'
|
35
|
+
|
36
|
+
module URBANopt
|
37
|
+
module Scenario
|
38
|
+
class ResultVisualization
|
39
|
+
def self.create_visualization(run_dir, feature = true)
|
40
|
+
@all_results = []
|
41
|
+
run_dir.each do |folder|
|
42
|
+
name = folder.split('/')[-1]
|
43
|
+
|
44
|
+
# create visualization for scenarios
|
45
|
+
if feature == false
|
46
|
+
csv_dir = File.join(folder, 'default_scenario_report.csv')
|
47
|
+
# create visualization for features
|
48
|
+
elsif feature == true
|
49
|
+
csv_dir = File.join(folder, 'feature_reports/default_feature_report.csv')
|
50
|
+
end
|
51
|
+
|
52
|
+
if File.exist?(csv_dir)
|
53
|
+
size = CSV.open(csv_dir).readlines.size
|
54
|
+
|
55
|
+
monthly_values = {}
|
56
|
+
monthly_totals = {}
|
57
|
+
annual_values = {}
|
58
|
+
|
59
|
+
headers_unitless = []
|
60
|
+
i = 0
|
61
|
+
CSV.foreach(csv_dir).map do |row|
|
62
|
+
if i == 0
|
63
|
+
# store header values from csv
|
64
|
+
headers = row
|
65
|
+
headers.each do |header|
|
66
|
+
header_unitless = header.to_s.split('(')[0]
|
67
|
+
headers_unitless << header_unitless
|
68
|
+
monthly_values[header_unitless] = []
|
69
|
+
end
|
70
|
+
# store values from csv for each row
|
71
|
+
elsif i <= size
|
72
|
+
headers_unitless.each_index do |j|
|
73
|
+
monthly_values[headers_unitless[j]] << row[j]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
i += 1
|
77
|
+
end
|
78
|
+
|
79
|
+
if monthly_values['Datetime'][0].split(/\W+/)[0].to_f > 31
|
80
|
+
format = '%Y/%m/%d %H:%M'
|
81
|
+
year = monthly_values['Datetime'][0].split(/\W+/)[0]
|
82
|
+
else
|
83
|
+
format = '%m/%d/%Y %H:%M'
|
84
|
+
year = monthly_values['Datetime'][0].split(/\W+/)[2]
|
85
|
+
end
|
86
|
+
|
87
|
+
# create dates for each month
|
88
|
+
jan_date = DateTime.new(year.to_i, 1, 1, 1, 0)
|
89
|
+
feb_date = DateTime.new(year.to_i, 2, 1, 0, 0)
|
90
|
+
mar_date = DateTime.new(year.to_i, 3, 1, 0, 0)
|
91
|
+
apr_date = DateTime.new(year.to_i, 4, 1, 0, 0)
|
92
|
+
may_date = DateTime.new(year.to_i, 5, 1, 0, 0)
|
93
|
+
jun_date = DateTime.new(year.to_i, 6, 1, 0, 0)
|
94
|
+
jul_date = DateTime.new(year.to_i, 7, 1, 0, 0)
|
95
|
+
aug_date = DateTime.new(year.to_i, 8, 1, 0, 0)
|
96
|
+
sep_date = DateTime.new(year.to_i, 9, 1, 0, 0)
|
97
|
+
oct_date = DateTime.new(year.to_i, 10, 1, 0, 0)
|
98
|
+
nov_date = DateTime.new(year.to_i, 11, 1, 0, 0)
|
99
|
+
dec_date = DateTime.new(year.to_i, 12, 1, 0, 0)
|
100
|
+
jan_next_year = DateTime.new(year.to_i + 1, 1, 1, 0, 0)
|
101
|
+
|
102
|
+
monthly_values['Datetime'].each do |i|
|
103
|
+
date_obj = DateTime.strptime(i.to_s, format)
|
104
|
+
index = monthly_values['Datetime'].index(i)
|
105
|
+
|
106
|
+
# store index of each date from the csv
|
107
|
+
if feb_date == date_obj
|
108
|
+
@feb_index = index
|
109
|
+
elsif mar_date == date_obj
|
110
|
+
@mar_index = index
|
111
|
+
elsif apr_date == date_obj
|
112
|
+
@apr_index = index
|
113
|
+
elsif may_date == date_obj
|
114
|
+
@may_index = index
|
115
|
+
elsif jun_date == date_obj
|
116
|
+
@jun_index = index
|
117
|
+
elsif jul_date == date_obj
|
118
|
+
@jul_index = index
|
119
|
+
elsif aug_date == date_obj
|
120
|
+
@aug_index = index
|
121
|
+
elsif sep_date == date_obj
|
122
|
+
@sep_index = index
|
123
|
+
elsif oct_date == date_obj
|
124
|
+
@oct_index = index
|
125
|
+
elsif nov_date == date_obj
|
126
|
+
@nov_index = index
|
127
|
+
elsif dec_date == date_obj
|
128
|
+
@dec_index = index
|
129
|
+
elsif jan_next_year == date_obj
|
130
|
+
@jan_next_year_index = index
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
headers_unitless.each_index do |j|
|
135
|
+
i = 0
|
136
|
+
k = 0
|
137
|
+
|
138
|
+
monthly_sum_jan = monthly_sum_feb = monthly_sum_mar = monthly_sum_apr = monthly_sum_may = monthly_sum_jun = monthly_sum_jul = monthly_sum_aug = monthly_sum_sep = monthly_sum_oct = monthly_sum_nov = monthly_sum_dec = annual_sum = 0
|
139
|
+
|
140
|
+
# loop through values for each header
|
141
|
+
all_values = monthly_values[headers_unitless[j]]
|
142
|
+
|
143
|
+
unless @jan_next_year_index.nil? || @feb_index.nil? || @mar_index.nil? || @apr_index.nil? || @may_index.nil? || @jun_index.nil? || @jul_index.nil? || @aug_index.nil? || @sep_index.nil? || @oct_index.nil? || @nov_index.nil? || @dec_index.nil?
|
144
|
+
|
145
|
+
# for each header store monthly sums of values
|
146
|
+
all_values.each do |v|
|
147
|
+
if i < @feb_index
|
148
|
+
monthly_sum_jan += v.to_f
|
149
|
+
i += 1
|
150
|
+
elsif @feb_index <= i && i < @mar_index
|
151
|
+
monthly_sum_feb += v.to_f
|
152
|
+
i += 1
|
153
|
+
elsif @mar_index <= i && i < @apr_index
|
154
|
+
monthly_sum_mar += v.to_f
|
155
|
+
i += 1
|
156
|
+
elsif @apr_index <= i && i < @may_index
|
157
|
+
monthly_sum_apr += v.to_f
|
158
|
+
i += 1
|
159
|
+
elsif @may_index <= i && i < @jun_index
|
160
|
+
monthly_sum_may += v.to_f
|
161
|
+
i += 1
|
162
|
+
elsif @jun_index <= i && i < @jul_index
|
163
|
+
monthly_sum_jun += v.to_f
|
164
|
+
i += 1
|
165
|
+
elsif @jul_index <= i && i < @aug_index
|
166
|
+
monthly_sum_jul += v.to_f
|
167
|
+
i += 1
|
168
|
+
elsif @aug_index <= i && i < @sep_index
|
169
|
+
monthly_sum_aug += v.to_f
|
170
|
+
i += 1
|
171
|
+
elsif @sep_index <= i && i < @oct_index
|
172
|
+
monthly_sum_sep += v.to_f
|
173
|
+
i += 1
|
174
|
+
elsif @oct_index <= i && i < @nov_index
|
175
|
+
monthly_sum_oct += v.to_f
|
176
|
+
i += 1
|
177
|
+
elsif @nov_index <= i && i < @dec_index
|
178
|
+
monthly_sum_nov += v.to_f
|
179
|
+
i += 1
|
180
|
+
elsif @dec_index <= i && i < @jan_next_year_index
|
181
|
+
monthly_sum_dec += v.to_f
|
182
|
+
i += 1
|
183
|
+
end
|
184
|
+
# sum up all values for annual aggregate
|
185
|
+
if k <= size
|
186
|
+
annual_sum += v.to_f
|
187
|
+
k += 1
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# store headers as key and monthly sums as values for each header
|
193
|
+
monthly_totals[headers_unitless[j]] = [monthly_sum_jan, monthly_sum_feb, monthly_sum_mar, monthly_sum_apr, monthly_sum_may, monthly_sum_jun, monthly_sum_jul, monthly_sum_aug, monthly_sum_sep, monthly_sum_oct, monthly_sum_nov, monthly_sum_dec]
|
194
|
+
|
195
|
+
annual_values[headers_unitless[j]] = annual_sum
|
196
|
+
end
|
197
|
+
|
198
|
+
@results = {}
|
199
|
+
@results['name'] = name
|
200
|
+
@results['monthly_values'] = {}
|
201
|
+
@results['annual_values'] = {}
|
202
|
+
|
203
|
+
if @jan_next_year_index.nil? || @feb_index.nil? || @mar_index.nil? || @apr_index.nil? || @may_index.nil? || @jun_index.nil? || @jul_index.nil? || @aug_index.nil? || @sep_index.nil? || @oct_index.nil? || @nov_index.nil? || @dec_index.nil?
|
204
|
+
@results['complete_simulation'] = false
|
205
|
+
puts "#{name} did not contain an annual simulation…visualizations will not render for it."
|
206
|
+
else
|
207
|
+
@results['complete_simulation'] = true
|
208
|
+
end
|
209
|
+
|
210
|
+
monthly_totals&.each do |key, value|
|
211
|
+
unless key == 'Datetime'
|
212
|
+
@results['monthly_values'][key] = value
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
annual_values&.each do |key, value|
|
217
|
+
unless key == 'Datetime'
|
218
|
+
@results['annual_values'][key] = value
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
|
224
|
+
unless @results.nil?
|
225
|
+
@all_results << @results
|
226
|
+
end
|
227
|
+
end
|
228
|
+
# create json with required data stored in a variable
|
229
|
+
results_path = File.join(run_dir[0], '../scenarioData.js')
|
230
|
+
File.open(results_path, 'w') do |file|
|
231
|
+
file << "var scenarioData = #{JSON.pretty_generate(@all_results)};"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end # ResultVisualization
|
235
|
+
end # Scenario
|
236
|
+
end # URBANopt
|