CRRA_optimisation_tool / data /generate_model_data.py
CarlyneB's picture
[DOCS/FIX] First draft of Objective No. 5: TO FACILITATE MAINTENANCE AND UPDATES FOR CG STAFF. (No more hard-coded settings, libraries updated, instructions added to the README)
fa58ff0
Raw History Blame
8.62 kB
#%% 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.")
# %%