File size: 8,616 Bytes
ba2dcff
 
64cc758
ba2dcff
 
 
64cc758
 
 
 
 
 
 
 
 
ba2dcff
fa58ff0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ba2dcff
1c33177
ba2dcff
 
 
fa58ff0
 
ba2dcff
 
 
3c60617
ba2dcff
 
 
 
 
 
 
fa58ff0
 
 
ba2dcff
64cc758
 
ba2dcff
64cc758
 
ba2dcff
64cc758
 
fa58ff0
 
 
ba2dcff
64cc758
 
 
ba2dcff
64cc758
 
 
ba2dcff
64cc758
 
 
ba2dcff
64cc758
 
 
fa58ff0
 
 
ba2dcff
64cc758
 
 
fa58ff0
ba2dcff
3c60617
64cc758
 
fa58ff0
 
1c33177
ba2dcff
fa58ff0
 
 
 
 
 
ba2dcff
fa58ff0
 
 
 
ba2dcff
 
 
 
 
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#%% uses the latest version of aggregated inputs to create the dictionary of costs
import json
import sys

import pandas as pd

from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
from utils.data_utils import strip_unit_suffix

def pop_by_name(d: dict, name: str):
    """Pop a key from dict by resource name, ignoring the unit suffix."""
    key = next((k for k in d if strip_unit_suffix(k) == name), None)
    if key:
        d.pop(key)

# Which base methods are replaced by derived variants.
# Methods listed here must have derived entries added in create_sliders_inputs().
REPLACED_BY_DERIVED = {"Bio-char", "Enhanced weathering"}

# Which derived methods follow each base method (in order).
DERIVED_FROM = {
    "Bio-char": [
        "Bio-char - Forest biomass",
        "Bio-char - Non-forest biomass",
        "Bio-char - Unspecified biomass",
    ],
    "Enhanced weathering": [
        "Enhanced weathering - Basalt mineral",
        "Enhanced weathering - Olivine mineral",
        "Enhanced weathering - Wollastonite mineral",
        "Enhanced weathering - Unspecified mineral",
    ],
    "BioCCS with combustion": ["BioCCS with combustion & growing biomass"],
    "BioCCS with anaerobic digestion/fermentation": [
        "BioCCS with anaerobic digestion/fermentation & growing biomass"
    ],
}


def build_method_groups(df, cost_sliders):
    """Build the method_groups dict from the CSV Method group column + derivation rules above.

    Group and method order follows first appearance in inputs_aggregated.csv."""
    base_methods_per_group = {}
    for _, row in df.drop_duplicates(subset=["Implementation"]).iterrows():
        m, g = row["Implementation"], row["Method group"]
        base_methods_per_group.setdefault(g, [])
        if m not in base_methods_per_group[g]:
            base_methods_per_group[g].append(m)

    method_groups = {}
    for g, base_list in base_methods_per_group.items():
        methods = []
        for base in base_list:
            if base not in REPLACED_BY_DERIVED:
                methods.append(base)
            for derived in DERIVED_FROM.get(base, []):
                if derived in cost_sliders:
                    methods.append(derived)
        if methods:
            method_groups[g] = methods
    return method_groups


def build_secondary_resources(df, cost_sliders):
    """Build the full set of (method, resource) secondary pairs from the CSV

    'Is secondary' column, then propagate to derived methods via DERIVED_FROM."""
    # Base pairs from CSV
    base_secondary = set()
    for _, row in df[df["Is secondary"] == True].iterrows():
        base_secondary.add((row["Implementation"], row["Resource"]))

    # Expand to derived methods: derived methods inherit secondary resources from their base
    full_secondary = set(base_secondary)
    for base, deriveds in DERIVED_FROM.items():
        base_resources_secondary = {r for (m, r) in base_secondary if m == base}
        for derived in deriveds:
            if derived in cost_sliders:
                for r in base_resources_secondary:
                    full_secondary.add((derived, r))

    return full_secondary


def create_sliders_inputs():
    df = pd.read_csv("data/inputs_aggregated.csv")

    cost_sliders = {}

    # Build cost_sliders from CSV: one entry per (method, resource) row.
    # Bio-char, Enhanced weathering and BioCCS variants are derived below.
    for _, row in df.iterrows():
        method = row["Implementation"]
        resource = row["Resource"] + " (" + row["Unit"] + ")"
        if row["min"] == row["max"] and row["Resource"] != "Geologic storage":
            row["min"] = row["min"] * .5
        entry = {
            "min": float(row["min"]),
            "median": float(row["median"]),
            "max": float(row["max"])
        }
        cost_sliders.setdefault(method, {})[resource] = entry

    # ── Derived methods ───────────────────────────────────────────────────────
    # Bio-char: split into 3 biomass-specific variants, remove generic base
    cost_sliders["Bio-char - Forest biomass"] = cost_sliders["Bio-char"].copy()
    pop_by_name(cost_sliders["Bio-char - Forest biomass"], "Non-forest biomass")
    pop_by_name(cost_sliders["Bio-char - Forest biomass"], "Unspecified biomass")
    cost_sliders["Bio-char - Non-forest biomass"] = cost_sliders["Bio-char"].copy()
    pop_by_name(cost_sliders["Bio-char - Non-forest biomass"], "Forest biomass")
    pop_by_name(cost_sliders["Bio-char - Non-forest biomass"], "Unspecified biomass")
    cost_sliders["Bio-char - Unspecified biomass"] = cost_sliders["Bio-char"].copy()
    pop_by_name(cost_sliders["Bio-char - Unspecified biomass"], "Forest biomass")
    pop_by_name(cost_sliders["Bio-char - Unspecified biomass"], "Non-forest biomass")
    del cost_sliders["Bio-char"]

    # Enhanced weathering: split into 4 mineral-specific variants, remove generic base
    cost_sliders["Enhanced weathering - Basalt mineral"] = cost_sliders["Enhanced weathering"].copy()
    pop_by_name(cost_sliders["Enhanced weathering - Basalt mineral"], "Olivine mineral")
    pop_by_name(cost_sliders["Enhanced weathering - Basalt mineral"], "Wollastonite mineral")
    pop_by_name(cost_sliders["Enhanced weathering - Basalt mineral"], "Unspecified mineral")
    cost_sliders["Enhanced weathering - Olivine mineral"] = cost_sliders["Enhanced weathering"].copy()
    pop_by_name(cost_sliders["Enhanced weathering - Olivine mineral"], "Basalt mineral")
    pop_by_name(cost_sliders["Enhanced weathering - Olivine mineral"], "Wollastonite mineral")
    pop_by_name(cost_sliders["Enhanced weathering - Olivine mineral"], "Unspecified mineral")
    cost_sliders["Enhanced weathering - Wollastonite mineral"] = cost_sliders["Enhanced weathering"].copy()
    pop_by_name(cost_sliders["Enhanced weathering - Wollastonite mineral"], "Basalt mineral")
    pop_by_name(cost_sliders["Enhanced weathering - Wollastonite mineral"], "Olivine mineral")
    pop_by_name(cost_sliders["Enhanced weathering - Wollastonite mineral"], "Unspecified mineral")
    cost_sliders["Enhanced weathering - Unspecified mineral"] = cost_sliders["Enhanced weathering"].copy()
    pop_by_name(cost_sliders["Enhanced weathering - Unspecified mineral"], "Basalt mineral")
    pop_by_name(cost_sliders["Enhanced weathering - Unspecified mineral"], "Olivine mineral")
    pop_by_name(cost_sliders["Enhanced weathering - Unspecified mineral"], "Wollastonite mineral")
    del cost_sliders["Enhanced weathering"]

    # BioCCS: add growing-biomass variants alongside their base methods
    cost_sliders["BioCCS with combustion & growing biomass"] = cost_sliders["BioCCS with combustion"].copy()
    pop_by_name(cost_sliders["BioCCS with combustion"], "Arable land")
    pop_by_name(cost_sliders["BioCCS with combustion & growing biomass"], "Forest biomass")
    pop_by_name(cost_sliders["BioCCS with combustion & growing biomass"], "Unspecified biomass")

    cost_sliders["BioCCS with anaerobic digestion/fermentation & growing biomass"] = cost_sliders["BioCCS with anaerobic digestion/fermentation"].copy()
    pop_by_name(cost_sliders["BioCCS with anaerobic digestion/fermentation"], "Arable land")
    pop_by_name(cost_sliders["BioCCS with anaerobic digestion/fermentation & growing biomass"], "Non-forest biomass")
    pop_by_name(cost_sliders["BioCCS with anaerobic digestion/fermentation & growing biomass"], "Unspecified biomass")

    # ── Save outputs ──────────────────────────────────────────────────────────
    with open("data/cost_sliders.json", "w") as f:
        json.dump(cost_sliders, f, indent=2)
    print("Saved cost_sliders.json")

    method_groups = build_method_groups(df, cost_sliders)
    with open("data/method_groups.json", "w") as f:
        json.dump(method_groups, f, indent=2)
    print("Saved method_groups.json")

    secondary_resources = build_secondary_resources(df, cost_sliders)
    with open("data/secondary_resources.json", "w") as f:
        json.dump(sorted(secondary_resources), f, indent=2)
    print(f"Saved secondary_resources.json ({len(secondary_resources)} pairs)")

if __name__ == "__main__":
    create_sliders_inputs()
    print("Script executed successfully.")
# %%