-
Notifications
You must be signed in to change notification settings - Fork 1
/
AggregationTemplate.jl
132 lines (110 loc) · 5.06 KB
/
AggregationTemplate.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
"""
AggregationTemplate(;file, name) <: Modification
This is a mod that outputs aggregated results, given a `file` representing the template of the things to be aggregated. `name` is simply the name of the modification, and will be used as the root for the filename that the aggregated information is saved to.
The `file` should represent a csv table with the following columns:
* `table_name` - the name of the table being aggregated. i.e. `gen`, `bus`, etc.
* `result_name` - the name of the column in the table being aggregated. Note that the column must have a Unit accessible via [`get_table_col_unit`](@ref).
* `filter_` - the filtering conditions for the rows of the table. I.e. `filter1`. See [`parse_comparisons`](@ref) for information on what types of filters could be provided.
* `filter_years` - the filtering conditions for the years to be aggregated. See [`parse_year_idxs`](@ref) for information on the year filters.
* `filter_hours` - the filtering conditions for the hours to be aggregated. See [`parse_hour_idxs`](@ref) for information on the hour filters.
Note that, for the `filter_` or `filter_hours` columns, if a column name of the data table (or hours table) is given, new rows will be created for each unique value of that column. I.e. if a value of `gentype` is given, there will be made a new row for `gentype=>coal`, `gentype=>ng`, etc.
"""
struct AggregationTemplate <: Modification
file::String
name::Symbol
table::DataFrame
function AggregationTemplate(;file, name)
table = read_table(file)
force_table_types!(table, name,
:table_name=>Symbol,
:result_name=>Symbol,
:filter_years=>String,
:filter_hours=>String,
)
for i in 1:1000
col_name = "filter$i"
hasproperty(table, col_name) || continue
force_table_types!(table, name, col_name=>String)
end
return new(file, name, table)
end
end
export AggregationTemplate
mod_rank(::Type{<:AggregationTemplate}) = 5.0
fieldnames_for_yaml(::Type{AggregationTemplate}) = (:file,)
function modify_results!(mod::AggregationTemplate, config, data)
table = copy(mod.table)
filter_cols = setdiff(propertynames(table), [:table_name, :result_name])
# for any rows that are not a pair, separate into multiple rows
not_pair_idx = findfirst(not_a_full_filter, eachrow(table))
while not_pair_idx !== nothing
row = table[not_pair_idx, :]
filter_col_idx = findfirst(filter_col->not_a_full_filter(row[filter_col]), filter_cols)
col_to_expand = filter_cols[filter_col_idx]
if col_to_expand == :filter_hours
area = row.filter_hours
hours_table_col = get_table_col(data, :hours, area)
subareas = Base.sort!(String.(string.(unique(hours_table_col))), by=hours_sortby)
else
area = row[col_to_expand]
data_table_col = get_table_col(data, row.table_name, area)
subareas = sort!(unique(data_table_col))
end
row_dict = Dict(pairs(row))
for subarea in subareas
# Add a row right after the original row
row_dict[col_to_expand] = "$area=>$subarea"
insert!(table, not_pair_idx+1, row_dict)
end
deleteat!(table, not_pair_idx)
# Find the next index that is not a pair, to be expanded
not_pair_idx = findfirst(not_a_full_filter, eachrow(table))
end
table.value = map(eachrow(table)) do row
table_name = row.table_name
result_name = row.result_name
idxs = parse_comparisons(row)
yr_idxs = parse_year_idxs(row.filter_years)
hr_idxs = parse_hour_idxs(row.filter_hours)
return compute_result(data, table_name, result_name, idxs, yr_idxs, hr_idxs)
end
CSV.write(get_out_path(config, string(mod.name, ".csv")), table)
results = get_results(data)
results[mod.name] = table
return
end
function hours_sortby(s::T) where T
if endswith(s, r"h\d+")
m = match(r"h(\d+)", s)
return lpad(m.captures[1], 4, '0') |> T
else
return s |> T
end
end
function extract_results(m::AggregationTemplate, config, data)
results = get_results(data)
haskey(results, m.name) || modify_results!(m, config, data)
return get_result(data, m.name)
end
function combine_results(m::AggregationTemplate, post_config, post_data)
res = join_sim_tables(post_data, :value)
CSV.write(get_out_path(post_config, "$(m.name)_combined.csv"), res)
end
function not_a_full_filter(row::DataFrameRow)
not_a_full_filter(row.filter_years) && return true
not_a_full_filter(row.filter_hours) && return true
for i in 1:1000
col_name = "filter$i"
hasproperty(row, col_name) || break
not_a_full_filter(row[col_name]) && return true
end
return false
end
function not_a_full_filter(s::AbstractString)
isempty(s) && return false
all(isnumeric, s) && return false
contains(s, "=>") && return false
startswith(s, "[") && return false
startswith(s, "y2") && return false
return true
end