CarbonGap commited on
Commit
ba2dcff
·
verified ·
1 Parent(s): 20e291e

Upload 44 files

Browse files

First upload of the V2 model. pending further fixes

Files changed (44) hide show
  1. .streamlit/config.toml +7 -0
  2. README.md +14 -20
  3. app.py +46 -0
  4. config/__init__.py +0 -0
  5. config/__pycache__/__init__.cpython-311.pyc +0 -0
  6. config/__pycache__/config.cpython-311.pyc +0 -0
  7. config/config.py +131 -0
  8. data/__init__.py +0 -0
  9. data/cost_sliders.json +548 -0
  10. data/generate_cost_matrix.py +92 -0
  11. data/inputs_aggregated.csv +76 -0
  12. data/inputs_aggregated_old.csv +74 -0
  13. data/secondary_resources.csv +50 -0
  14. data/update_cost_sliders_with_priority.py +32 -0
  15. optimization/__init__.py +0 -0
  16. optimization/__pycache__/__init__.cpython-311.pyc +0 -0
  17. optimization/__pycache__/optimization.cpython-311.pyc +0 -0
  18. optimization/optimization.py +56 -0
  19. requirements.txt +0 -0
  20. tabs/__init__.py +0 -0
  21. tabs/__pycache__/__init__.cpython-311.pyc +0 -0
  22. tabs/__pycache__/tab0_welcome.cpython-311.pyc +0 -0
  23. tabs/__pycache__/tab1_inputs.cpython-311.pyc +0 -0
  24. tabs/__pycache__/tab2_constraints.cpython-311.pyc +0 -0
  25. tabs/__pycache__/tab3_coefficients.cpython-311.pyc +0 -0
  26. tabs/__pycache__/tab3_test.cpython-311.pyc +0 -0
  27. tabs/__pycache__/tab4_optimization.cpython-311.pyc +0 -0
  28. tabs/__pycache__/tab5_scenarios.cpython-311.pyc +0 -0
  29. tabs/__pycache__/tab5_sensitivity.cpython-311.pyc +0 -0
  30. tabs/__pycache__/tab6_scenarios.cpython-311.pyc +0 -0
  31. tabs/__pycache__/tab6_sensitivity.cpython-311.pyc +0 -0
  32. tabs/tab0_welcome.py +29 -0
  33. tabs/tab1_inputs.py +62 -0
  34. tabs/tab2_constraints.py +104 -0
  35. tabs/tab3_coefficients.py +164 -0
  36. tabs/tab4_optimization.py +206 -0
  37. tabs/tab5_sensitivity.py +107 -0
  38. tabs/tab6_scenarios.py +107 -0
  39. utils/__init__.py +0 -0
  40. utils/__pycache__/__init__.cpython-311.pyc +0 -0
  41. utils/__pycache__/data_utils.cpython-311.pyc +0 -0
  42. utils/__pycache__/ui_helpers.cpython-311.pyc +0 -0
  43. utils/data_utils.py +28 -0
  44. utils/ui_helpers.py +244 -0
.streamlit/config.toml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ [theme]
2
+ base = "light"
3
+ primaryColor = "#3d86e9"
4
+ backgroundColor = "#ffffff"
5
+ secondaryBackgroundColor = "#c6d7f0e1"
6
+ textColor = "#262730"
7
+ font = "monospace"
README.md CHANGED
@@ -1,20 +1,14 @@
1
- ---
2
- title: CRRA Optimization Tool
3
- emoji: 🚀
4
- colorFrom: red
5
- colorTo: red
6
- sdk: docker
7
- app_port: 8501
8
- tags:
9
- - streamlit
10
- pinned: false
11
- short_description: Otpimization tool for the creation of scenarios for CRRA
12
- license: mit
13
- ---
14
-
15
- # Welcome to Streamlit!
16
-
17
- Edit `/src/streamlit_app.py` to customize this app to your heart's desire. :heart:
18
-
19
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
20
- forums](https://discuss.streamlit.io).
 
1
+ ---
2
+ title: Carbon Dioxide Removal Toolkit
3
+ emoji: 🌍
4
+ colorFrom: green
5
+ colorTo: blue
6
+ sdk: streamlit
7
+ sdk_version: "1.32.0"
8
+ app_file: app.py
9
+ pinned: false
10
+ ---
11
+
12
+ # Carbon Dioxide Removal Optimizer
13
+
14
+ A Streamlit app for optimizing carbon removal portfolios across different methods and constraints.
 
 
 
 
 
 
app.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from streamlit_option_menu import option_menu
3
+
4
+ from tabs import (tab0_welcome, tab1_inputs, tab2_constraints,
5
+ tab3_coefficients, tab4_optimization, tab5_sensitivity,
6
+ tab6_scenarios)
7
+ from utils.data_utils import load_slider_data
8
+
9
+ st.set_page_config("Carbon Portfolio Optimizer", layout="wide")
10
+ st.title("Toolkit: CDR Portfolio Optimization")
11
+
12
+ with st.sidebar:
13
+ selected = option_menu(
14
+ "Navigation",
15
+ options=[
16
+ "Welcome",
17
+ "Resource inputs",
18
+ "Method constraints",
19
+ "Resource coefficients",
20
+ "Portfolio generation",
21
+ "Sensitivity analysis",
22
+ "Scenario comparison",
23
+ ],
24
+ icons=["house", "upload", "gear", "sliders", "graph-up-arrow", "card-checklist", "search"],
25
+ default_index=0,
26
+ orientation="vertical"
27
+ )
28
+
29
+ # Dispatch to appropriate tab
30
+ cost_sliders = load_slider_data()
31
+
32
+
33
+ if selected == "Welcome":
34
+ tab0_welcome.render_tab()
35
+ elif selected == "Resource inputs":
36
+ tab1_inputs.render_tab()
37
+ elif selected == "Method constraints":
38
+ tab2_constraints.render_tab()
39
+ elif selected == "Resource coefficients":
40
+ tab3_coefficients.render_tab(cost_sliders)
41
+ elif selected == "Portfolio generation":
42
+ tab4_optimization.render_tab()
43
+ elif selected == "Sensitivity analysis":
44
+ tab5_sensitivity.render_tab()
45
+ elif selected == "Scenario comparison":
46
+ tab6_scenarios.render_tab()
config/__init__.py ADDED
File without changes
config/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (198 Bytes). View file
 
config/__pycache__/config.cpython-311.pyc ADDED
Binary file (5.82 kB). View file
 
config/config.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+
3
+ method_groups = {
4
+ "Forestry": [
5
+ "Afforestation", "Reforestation", "Forest management", "Agroforestry"],
6
+ "Soil carbon sequestration (crop, grasslands)": [
7
+ "Cropland management", "Pasture management"],
8
+ "Blue carbon": [
9
+ "Coastal revegetation (mangrove, seaweeds)"],
10
+ "Durable biobased products": [
11
+ "Durable biobased products"],
12
+ "Bio-char": [
13
+ "Bio-char - Forest biomass", "Bio-char - Non-forest biomass", "Bio-char - Unspecified biomass"
14
+ ],
15
+ "Bio-CCS": [
16
+ "BioCCS with combustion", "BioCCS with combustion & growing biomass", "BioCCS with anaerobic digestion/fermentation", "BioCCS with anaerobic digestion/fermentation & growing biomass"
17
+ ],
18
+ "Enhanced weathering": [
19
+ "Enhanced weathering - Basalt mineral", "Enhanced weathering - Olivine mineral", "Enhanced weathering - Wollastonite mineral", "Enhanced weathering - Unspecified mineral"
20
+ ],
21
+ "Ocean alkalinity enhancement": [
22
+ "Mineral OAE / Ocean liming", "Electrochemical OAE"
23
+ ],
24
+ "Direct air carbon capture and storage (DACCS)": [
25
+ "Electrochemical DACCS", "Low-temp DACCS (solid-sorbent/liquid-solvent)",
26
+ "High-temp DACCS (solid-sorbent/liquid-solvent)", "Mineral looping DACCS",
27
+ "Moisture swing DACCS"
28
+ ],
29
+ "Direct ocean carbon captureand storage (DOCCS)": ["pH swing"],
30
+ "Mineralization": ["Mineralization ex-situ"]
31
+ }
32
+
33
+ resource_groups = {
34
+ "Minerals": ["Basalt mineral (t/tCO2)", "Olivine mineral (t/tCO2)", "Wollastonite mineral (t/tCO2)", "Unspecified mineral (t/tCO2)"],
35
+ "Biomass": ["Forest biomass (t/tCO2)", "Non-forest biomass (t/tCO2)", "Unspecified biomass (t/tCO2)"],
36
+ "Land": ["Arable land (ha/tCO2)", "Non-arable land (ha/tCO2)", "Unspecified land (ha/tCO2)"],
37
+ "Chemicals": ["Unspecified chemical (t/tCO2)"],
38
+ "Energy": ["Electrical energy (MWh/tCO2)", "Thermal energy unspecified grade (MWh/tCO2)", "Thermal energy low grade (MWh/tCO2)", "Thermal energy high grade (MWh/tCO2)"],
39
+ "Water": ["Salt water (Liters/tCO2)", "Unspecified water (Liters/tCO2)"],
40
+ "Shoreline": ["Shoreline (km/tCO2)"],
41
+ }
42
+
43
+ method_order = sum(method_groups.values(), [])
44
+
45
+ resource_order = sum(resource_groups.values(), [])
46
+
47
+ # names used for display
48
+ resource_unit_map = {
49
+ "Land": "ha",
50
+ "Energy": "MWh",
51
+ "Biomass": "t",
52
+ "Minerals": "t",
53
+ "Chemicals": "t",
54
+ "Shoreline": "km",
55
+ "Water": "L"
56
+ }
57
+
58
+ resource_units = {
59
+ "ha/tCO2": ["Arable land (ha/tCO2)", "Non-arable land (ha/tCO2)", "Unspecified land (ha/tCO2)"],
60
+ "MWh/tCO2": ["Electrical energy (MWh/tCO2)", "Thermal energy unspecified grade (MWh/tCO2)", "Thermal energy low grade (MWh/tCO2)", "Thermal energy high grade (MWh/tCO2)"],
61
+ "t/tCO2": ["Forest biomass (t/tCO2)", "Non-forest biomass (t/tCO2)", "Unspecified biomass (t/tCO2)", "Basalt mineral (t/tCO2)", "Olivine mineral (t/tCO2)", "Wollastonite mineral (t/tCO2)", "Unspecified mineral (t/tCO2)", "Unspecified chemical (t/tCO2)"],
62
+ "km/tCO2": ["Shoreline (km/tCO2)"],
63
+ "Liters/tCO2": ["Salt water (Liters/tCO2)", "Unspecified water (Liters/tCO2)"]
64
+ }
65
+
66
+ resource_grouped = {
67
+ "Land": ["Arable land (ha/tCO2)", "Non-arable land (ha/tCO2)", "Unspecified land (ha/tCO2)"],
68
+ "Energy": ["Electrical energy (MWh/tCO2)", "Thermal energy unspecified grade (MWh/tCO2)", "Thermal energy low grade (MWh/tCO2)", "Thermal energy high grade (MWh/tCO2)"],
69
+ "Biomass": ["Forest biomass (t/tCO2)", "Non-forest biomass (t/tCO2)", "Unspecified biomass (t/tCO2)"],
70
+ "Minerals": ["Basalt mineral (t/tCO2)", "Olivine mineral (t/tCO2)", "Wollastonite mineral (t/tCO2)", "Unspecified mineral (t/tCO2)"],
71
+ "Chemicals": ["Unspecified chemical (t/tCO2)"],
72
+ "Shoreline": ["Shoreline (km/tCO2)"],
73
+ "Water": ["Salt water (Liters/tCO2)", "Unspecified water (Liters/tCO2)"]
74
+ }
75
+
76
+ # secondary resources
77
+ secondary_df = pd.read_csv("data/secondary_resources.csv")
78
+ secondary_resources = set(zip(secondary_df["method"], secondary_df["resource"]))
79
+
80
+ # tooltips
81
+ resource_tooltips = {
82
+ # "Arable land (ha/tCO2)": "Land used for growing crops.",
83
+ # "Non-arable land (ha/tCO2)": "Land not suitable for crop production, e.g., pastures.",
84
+ # "Unspecified land (ha/tCO2)": "General land use not specified.",
85
+ # "Electrical energy (MWh/tCO2)": "Electricity consumption per ton of CO2 captured.",
86
+ # "Thermal energy unspecified grade (MWh/tCO2)": "Heat energy consumption per ton of CO2 captured.",
87
+ # "Thermal energy low grade (MWh/tCO2)": "Heat energy consumption per ton of CO2 captured.",
88
+ # "Thermal energy high grade (MWh/tCO2)": "Heat energy consumption per ton of CO2 captured.",
89
+ "Forest biomass (t/tCO2)": "Dry quantities of biomass sourced from forests.",
90
+ "Non-forest biomass (t/tCO2)": "Dry quantities of biomass sourced from non-forest areas.",
91
+ "Unspecified biomass (t/tCO2)": "Dry quantities of general biomass, not specified.",
92
+ # "Basalt mineral (t/tCO2)": "Basalt mineral used in enhanced weathering.",
93
+ # "Olivine mineral (t/tCO2)": "Olivine mineral used in enhanced weathering.",
94
+ # "Wollastonite mineral (t/tCO2)": "Wollastonite mineral used in enhanced weathering.",
95
+ # "Unspecified mineral (t/tCO2)": "General mineral not specified for enhanced weathering.",
96
+ # "Unspecified chemical (t/tCO2)": "General chemical resource not specified.",
97
+ # "Salt water (Liters/tCO2)": "Salt water used in ocean-based methods.",
98
+ # "Unspecified water (Liters/tCO2)": "General water resource not specified.",
99
+ # "Shoreline (km/tCO2)": "Length of shoreline affected by coastal methods."
100
+ }
101
+
102
+ method_tooltips = {
103
+ "Afforestation": "Methods related to afforestation practices.",
104
+ "Reforestation": "Methods related to reforestation practices.",
105
+ "Forest management": "Sustainable management of forest resources.",
106
+ "Agroforestry": "Integration of trees and shrubs into agricultural systems.",
107
+ "Cropland management": "Practices to enhance carbon storage in croplands.",
108
+ "Pasture management": "Sustainable practices for managing pastures.",
109
+ "Coastal revegetation (mangrove, seaweeds)": "Restoration of coastal ecosystems using mangroves and seaweeds.",
110
+ "Durable biobased products": "Production of long-lasting biobased materials.",
111
+ "Bio-char - Forest biomass": "Production of bio-char from forest biomass.",
112
+ "Bio-char - Non-forest biomass": "Production of bio-char from non-forest biomass.",
113
+ "Bio-char - Unspecified biomass": "Production of bio-char from unspecified biomass sources.",
114
+ "BioCCS with combustion": "Bioenergy with carbon capture and storage using combustion.",
115
+ "BioCCS with combustion & growing biomass": "Bioenergy with carbon capture and storage using combustion and growing biomass.",
116
+ "BioCCS with anaerobic digestion/fermentation": "Bioenergy with carbon capture and storage using anaerobic digestion or fermentation.",
117
+ "BioCCS with anaerobic digestion/fermentation & growing biomass": "Bioenergy with carbon capture and storage using anaerobic digestion or fermentation and growing biomass.",
118
+ "Enhanced weathering - Basalt mineral": "Use of basalt mineral for enhanced weathering.",
119
+ "Enhanced weathering - Olivine mineral": "Use of olivine mineral for enhanced weathering.",
120
+ "Enhanced weathering - Wollastonite mineral": "Use of wollastonite mineral for enhanced weathering.",
121
+ "Enhanced weathering - Unspecified mineral": "Use of unspecified mineral for enhanced weathering.",
122
+ "Mineral OAE / Ocean liming": "Ocean alkalinity enhancement using mineral or ocean liming.",
123
+ "Electrochemical OAE": "Ocean alkalinity enhancement using electrochemical methods.",
124
+ "Electrochemical DACCS": "Direct air carbon capture and storage using electrochemical methods.",
125
+ "Low-temp DACCS (solid-sorbent/liquid-solvent)": "Direct air carbon capture and storage using low-temperature solid sorbents or liquid solvents.",
126
+ "High-temp DACCS (solid-sorbent/liquid-solvent)": "Direct air carbon capture and storage using high-temperature solid sorbents or liquid solvents.",
127
+ "Mineral looping DACCS": "Direct air carbon capture and storage using mineral looping.",
128
+ "Moisture swing DACCS": "Direct air carbon capture and storage using moisture swing methods.",
129
+ "pH swing": "Direct ocean carbon capture and storage using pH swing methods.",
130
+ "Mineralization ex-situ": "Ex-situ mineralization methods for carbon capture."
131
+ }
data/__init__.py ADDED
File without changes
data/cost_sliders.json ADDED
@@ -0,0 +1,548 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "Afforestation": {
3
+ "Unspecified land (ha/tCO2)": {
4
+ "min": 0.002,
5
+ "median": 0.094926862556845,
6
+ "max": 0.38461538
7
+ },
8
+ "Unspecified water (Liters/tCO2)": {
9
+ "min": 46000.0,
10
+ "median": 92000.0,
11
+ "max": 92000.0
12
+ }
13
+ },
14
+ "Agroforestry": {
15
+ "Arable land (ha/tCO2)": {
16
+ "min": 0.0025,
17
+ "median": 0.06410128,
18
+ "max": 3.03030303
19
+ }
20
+ },
21
+ "BioCCS with anaerobic digestion/fermentation": {
22
+ "Non-forest biomass (t/tCO2)": {
23
+ "min": 1.315,
24
+ "median": 1.5617433414042998,
25
+ "max": 8.0
26
+ },
27
+ "Unspecified biomass (t/tCO2)": {
28
+ "min": 0.99809364,
29
+ "median": 1.14,
30
+ "max": 2.0
31
+ },
32
+ "Unspecified water (Liters/tCO2)": {
33
+ "min": 368182.0,
34
+ "median": 565909.0,
35
+ "max": 913636.0
36
+ }
37
+ },
38
+ "BioCCS with combustion": {
39
+ "Electrical energy (MWh/tCO2)": {
40
+ "min": 0.0,
41
+ "median": 0.101,
42
+ "max": 0.5
43
+ },
44
+ "Forest biomass (t/tCO2)": {
45
+ "min": 0.55555555,
46
+ "median": 0.59375,
47
+ "max": 0.8547
48
+ },
49
+ "Thermal energy unspecified grade (MWh/tCO2)": {
50
+ "min": 0.0,
51
+ "median": 0.9306111111111112,
52
+ "max": 4.0
53
+ },
54
+ "Unspecified biomass (t/tCO2)": {
55
+ "min": 0.66666667,
56
+ "median": 1.14,
57
+ "max": 2.0
58
+ },
59
+ "Unspecified chemical (t/tCO2)": {
60
+ "min": 0.00013,
61
+ "median": 0.00316,
62
+ "max": 20.2
63
+ },
64
+ "Unspecified water (Liters/tCO2)": {
65
+ "min": 630.0,
66
+ "median": 201625.2165,
67
+ "max": 1296342.17
68
+ }
69
+ },
70
+ "Coastal revegetation (mangrove, seaweeds)": {
71
+ "Non-arable land (ha/tCO2)": {
72
+ "min": 0.0078,
73
+ "median": 0.12056618,
74
+ "max": 0.32828863
75
+ }
76
+ },
77
+ "Cropland management": {
78
+ "Arable land (ha/tCO2)": {
79
+ "min": 0.08264463,
80
+ "median": 0.4206349227777499,
81
+ "max": 9.0
82
+ }
83
+ },
84
+ "Durable biobased products": {
85
+ "Electrical energy (MWh/tCO2)": {
86
+ "min": 2.0,
87
+ "median": 4.0,
88
+ "max": 4.0
89
+ },
90
+ "Non-arable land (ha/tCO2)": {
91
+ "min": 3.0,
92
+ "median": 6.0,
93
+ "max": 6.0
94
+ },
95
+ "Unspecified biomass (t/tCO2)": {
96
+ "min": 0.0,
97
+ "median": 3.57142857,
98
+ "max": 4.0
99
+ },
100
+ "Unspecified water (Liters/tCO2)": {
101
+ "min": 100.0,
102
+ "median": 300.0,
103
+ "max": 500.0
104
+ }
105
+ },
106
+ "Electrochemical DACCS": {
107
+ "Electrical energy (MWh/tCO2)": {
108
+ "min": 0.252556,
109
+ "median": 0.784125,
110
+ "max": 6.2222222222
111
+ },
112
+ "Non-arable land (ha/tCO2)": {
113
+ "min": 0.0002225771032,
114
+ "median": 0.000323748514,
115
+ "max": 0.016
116
+ },
117
+ "Unspecified water (Liters/tCO2)": {
118
+ "min": 1000.0,
119
+ "median": 5000.0,
120
+ "max": 27000.0
121
+ }
122
+ },
123
+ "Electrochemical OAE": {
124
+ "Electrical energy (MWh/tCO2)": {
125
+ "min": 0.83,
126
+ "median": 2.15,
127
+ "max": 5.0
128
+ },
129
+ "Non-arable land (ha/tCO2)": {
130
+ "min": 0.00071,
131
+ "median": 0.00101,
132
+ "max": 0.00131
133
+ },
134
+ "Shoreline (km/tCO2)": {
135
+ "min": 6e-09,
136
+ "median": 1.2e-08,
137
+ "max": 1.2e-08
138
+ },
139
+ "Unspecified mineral (t/tCO2)": {
140
+ "min": 2.4,
141
+ "median": 2.95,
142
+ "max": 3.5
143
+ }
144
+ },
145
+ "Forest management": {
146
+ "Unspecified land (ha/tCO2)": {
147
+ "min": 0.1087,
148
+ "median": 0.76865,
149
+ "max": 1.4286
150
+ }
151
+ },
152
+ "High-temp DACCS (solid-sorbent/liquid-solvent)": {
153
+ "Electrical energy (MWh/tCO2)": {
154
+ "min": 0.077,
155
+ "median": 0.46296111111111,
156
+ "max": 0.77
157
+ },
158
+ "Non-arable land (ha/tCO2)": {
159
+ "min": 1.5e-10,
160
+ "median": 0.0002225771032,
161
+ "max": 0.0009914798235
162
+ },
163
+ "Thermal energy high grade (MWh/tCO2)": {
164
+ "min": 1.125,
165
+ "median": 1.75,
166
+ "max": 3.8
167
+ },
168
+ "Unspecified water (Liters/tCO2)": {
169
+ "min": 0.005,
170
+ "median": 4700.0,
171
+ "max": 50000.0
172
+ }
173
+ },
174
+ "Low-temp DACCS (solid-sorbent/liquid-solvent)": {
175
+ "Electrical energy (MWh/tCO2)": {
176
+ "min": 0.13,
177
+ "median": 0.46296111111111,
178
+ "max": 4.6111111111
179
+ },
180
+ "Non-arable land (ha/tCO2)": {
181
+ "min": 1e-11,
182
+ "median": 0.0002225771032,
183
+ "max": 0.0009914798235
184
+ },
185
+ "Thermal energy low grade (MWh/tCO2)": {
186
+ "min": 0.6388888889,
187
+ "median": 1.5,
188
+ "max": 2.7222222222
189
+ },
190
+ "Unspecified water (Liters/tCO2)": {
191
+ "min": -2000.0,
192
+ "median": 1008.17439,
193
+ "max": 15000.0
194
+ }
195
+ },
196
+ "Mineral OAE / Ocean liming": {
197
+ "Electrical energy (MWh/tCO2)": {
198
+ "min": 0.027,
199
+ "median": 0.6065,
200
+ "max": 4.0
201
+ },
202
+ "Non-arable land (ha/tCO2)": {
203
+ "min": 0.0,
204
+ "median": 0.000355,
205
+ "max": 0.00131
206
+ },
207
+ "Thermal energy unspecified grade (MWh/tCO2)": {
208
+ "min": 0.16,
209
+ "median": 1.4589444444444444,
210
+ "max": 1.55
211
+ },
212
+ "Unspecified mineral (t/tCO2)": {
213
+ "min": 1.4,
214
+ "median": 1.743,
215
+ "max": 5.0
216
+ },
217
+ "Unspecified water (Liters/tCO2)": {
218
+ "min": 339.1655,
219
+ "median": 678.331,
220
+ "max": 678.331
221
+ }
222
+ },
223
+ "Mineral looping DACCS": {
224
+ "Electrical energy (MWh/tCO2)": {
225
+ "min": 0.0,
226
+ "median": 0.0833333333333333,
227
+ "max": 4.0
228
+ },
229
+ "Non-arable land (ha/tCO2)": {
230
+ "min": 0.0002225771032,
231
+ "median": 0.00063889,
232
+ "max": 0.0033
233
+ },
234
+ "Thermal energy unspecified grade (MWh/tCO2)": {
235
+ "min": 1.0,
236
+ "median": 1.81944444445,
237
+ "max": 2.2222222222
238
+ },
239
+ "Unspecified mineral (t/tCO2)": {
240
+ "min": 0.0,
241
+ "median": 0.2,
242
+ "max": 0.5
243
+ },
244
+ "Unspecified water (Liters/tCO2)": {
245
+ "min": 0.0,
246
+ "median": 200.0,
247
+ "max": 26714.00689
248
+ }
249
+ },
250
+ "Mineralization ex-situ": {
251
+ "Electrical energy (MWh/tCO2)": {
252
+ "min": 0.0,
253
+ "median": 0.75,
254
+ "max": 3.0
255
+ },
256
+ "Non-arable land (ha/tCO2)": {
257
+ "min": 0.0002225771032,
258
+ "median": 0.00043604877962,
259
+ "max": 0.0009914798235
260
+ },
261
+ "Olivine mineral (t/tCO2)": {
262
+ "min": 0.4,
263
+ "median": 0.8,
264
+ "max": 0.8
265
+ },
266
+ "Thermal energy unspecified grade (MWh/tCO2)": {
267
+ "min": 0.4,
268
+ "median": 0.45,
269
+ "max": 1.0
270
+ },
271
+ "Unspecified mineral (t/tCO2)": {
272
+ "min": 0.04,
273
+ "median": 3.0,
274
+ "max": 10.0
275
+ },
276
+ "Unspecified water (Liters/tCO2)": {
277
+ "min": 0.0,
278
+ "median": 5450.0,
279
+ "max": 300000.0
280
+ }
281
+ },
282
+ "Moisture swing DACCS": {
283
+ "Electrical energy (MWh/tCO2)": {
284
+ "min": 0.316,
285
+ "median": 0.32466666665,
286
+ "max": 0.3333333333
287
+ },
288
+ "Non-arable land (ha/tCO2)": {
289
+ "min": 8e-06,
290
+ "median": 0.00027248,
291
+ "max": 0.0009914798235
292
+ },
293
+ "Unspecified water (Liters/tCO2)": {
294
+ "min": -146.0,
295
+ "median": 427.0,
296
+ "max": 1000.0
297
+ }
298
+ },
299
+ "Pasture management": {
300
+ "Arable land (ha/tCO2)": {
301
+ "min": 0.07189434,
302
+ "median": 0.25242204,
303
+ "max": 2.28974424
304
+ }
305
+ },
306
+ "Reforestation": {
307
+ "Unspecified land (ha/tCO2)": {
308
+ "min": 0.002,
309
+ "median": 0.094926862556845,
310
+ "max": 38.8
311
+ },
312
+ "Unspecified water (Liters/tCO2)": {
313
+ "min": 46000.0,
314
+ "median": 92000.0,
315
+ "max": 92000.0
316
+ }
317
+ },
318
+ "pH swing": {
319
+ "Electrical energy (MWh/tCO2)": {
320
+ "min": 0.66,
321
+ "median": 1.768,
322
+ "max": 4.67
323
+ },
324
+ "Salt water (Liters/tCO2)": {
325
+ "min": 435000.0,
326
+ "median": 4780000.0,
327
+ "max": 9125000.0
328
+ },
329
+ "Unspecified water (Liters/tCO2)": {
330
+ "min": 217391.304,
331
+ "median": 6608695.652,
332
+ "max": 13000000.0
333
+ }
334
+ },
335
+ "Bio-char - Forest biomass": {
336
+ "Electrical energy (MWh/tCO2)": {
337
+ "min": 0.0,
338
+ "median": 0.00035,
339
+ "max": 0.5
340
+ },
341
+ "Forest biomass (t/tCO2)": {
342
+ "min": 0.33,
343
+ "median": 0.37,
344
+ "max": 0.82
345
+ },
346
+ "Unspecified land (ha/tCO2)": {
347
+ "min": 0.05640158,
348
+ "median": 0.16320079,
349
+ "max": 0.27
350
+ },
351
+ "Unspecified water (Liters/tCO2)": {
352
+ "min": -500.0,
353
+ "median": 100.0,
354
+ "max": 3000.0
355
+ }
356
+ },
357
+ "Bio-char - Non-forest biomass": {
358
+ "Electrical energy (MWh/tCO2)": {
359
+ "min": 0.0,
360
+ "median": 0.00035,
361
+ "max": 0.5
362
+ },
363
+ "Non-forest biomass (t/tCO2)": {
364
+ "min": 0.818,
365
+ "median": 1.3395,
366
+ "max": 1.667
367
+ },
368
+ "Unspecified land (ha/tCO2)": {
369
+ "min": 0.05640158,
370
+ "median": 0.16320079,
371
+ "max": 0.27
372
+ },
373
+ "Unspecified water (Liters/tCO2)": {
374
+ "min": -500.0,
375
+ "median": 100.0,
376
+ "max": 3000.0
377
+ }
378
+ },
379
+ "Bio-char - Unspecified biomass": {
380
+ "Electrical energy (MWh/tCO2)": {
381
+ "min": 0.0,
382
+ "median": 0.00035,
383
+ "max": 0.5
384
+ },
385
+ "Unspecified biomass (t/tCO2)": {
386
+ "min": 0.5,
387
+ "median": 1.20922073,
388
+ "max": 12.86
389
+ },
390
+ "Unspecified land (ha/tCO2)": {
391
+ "min": 0.05640158,
392
+ "median": 0.16320079,
393
+ "max": 0.27
394
+ },
395
+ "Unspecified water (Liters/tCO2)": {
396
+ "min": -500.0,
397
+ "median": 100.0,
398
+ "max": 3000.0
399
+ }
400
+ },
401
+ "Enhanced weathering - Basalt mineral": {
402
+ "Arable land (ha/tCO2)": {
403
+ "min": 1e-06,
404
+ "median": 0.25,
405
+ "max": 2.5
406
+ },
407
+ "Basalt mineral (t/tCO2)": {
408
+ "min": 1.0,
409
+ "median": 4.3,
410
+ "max": 19.0
411
+ },
412
+ "Electrical energy (MWh/tCO2)": {
413
+ "min": 0.00925,
414
+ "median": 0.38875,
415
+ "max": 2.775
416
+ },
417
+ "Non-arable land (ha/tCO2)": {
418
+ "min": 0.0009,
419
+ "median": 0.00906504,
420
+ "max": 40.0
421
+ },
422
+ "Unspecified water (Liters/tCO2)": {
423
+ "min": 100.0,
424
+ "median": 866.0,
425
+ "max": 50000.0
426
+ }
427
+ },
428
+ "Enhanced weathering - Olivine mineral": {
429
+ "Arable land (ha/tCO2)": {
430
+ "min": 1e-06,
431
+ "median": 0.25,
432
+ "max": 2.5
433
+ },
434
+ "Electrical energy (MWh/tCO2)": {
435
+ "min": 0.00925,
436
+ "median": 0.38875,
437
+ "max": 2.775
438
+ },
439
+ "Non-arable land (ha/tCO2)": {
440
+ "min": 0.0009,
441
+ "median": 0.00906504,
442
+ "max": 40.0
443
+ },
444
+ "Olivine mineral (t/tCO2)": {
445
+ "min": 0.27027027,
446
+ "median": 1.25,
447
+ "max": 3.7
448
+ },
449
+ "Unspecified water (Liters/tCO2)": {
450
+ "min": 100.0,
451
+ "median": 866.0,
452
+ "max": 50000.0
453
+ }
454
+ },
455
+ "Enhanced weathering - Wollastonite mineral": {
456
+ "Arable land (ha/tCO2)": {
457
+ "min": 1e-06,
458
+ "median": 0.25,
459
+ "max": 2.5
460
+ },
461
+ "Electrical energy (MWh/tCO2)": {
462
+ "min": 0.00925,
463
+ "median": 0.38875,
464
+ "max": 2.775
465
+ },
466
+ "Non-arable land (ha/tCO2)": {
467
+ "min": 0.0009,
468
+ "median": 0.00906504,
469
+ "max": 40.0
470
+ },
471
+ "Unspecified water (Liters/tCO2)": {
472
+ "min": 100.0,
473
+ "median": 866.0,
474
+ "max": 50000.0
475
+ },
476
+ "Wollastonite mineral (t/tCO2)": {
477
+ "min": 0.56,
478
+ "median": 1.5642857142856998,
479
+ "max": 3.0
480
+ }
481
+ },
482
+ "Enhanced weathering - Unspecified mineral": {
483
+ "Arable land (ha/tCO2)": {
484
+ "min": 1e-06,
485
+ "median": 0.25,
486
+ "max": 2.5
487
+ },
488
+ "Electrical energy (MWh/tCO2)": {
489
+ "min": 0.00925,
490
+ "median": 0.38875,
491
+ "max": 2.775
492
+ },
493
+ "Non-arable land (ha/tCO2)": {
494
+ "min": 0.0009,
495
+ "median": 0.00906504,
496
+ "max": 40.0
497
+ },
498
+ "Unspecified mineral (t/tCO2)": {
499
+ "min": 0.5,
500
+ "median": 2.5,
501
+ "max": 25.0
502
+ },
503
+ "Unspecified water (Liters/tCO2)": {
504
+ "min": 100.0,
505
+ "median": 866.0,
506
+ "max": 50000.0
507
+ }
508
+ },
509
+ "BioCCS with combustion & growing biomass": {
510
+ "Arable land (ha/tCO2)": {
511
+ "min": 0.022803284,
512
+ "median": 0.058399844,
513
+ "max": 1.9451
514
+ },
515
+ "Electrical energy (MWh/tCO2)": {
516
+ "min": 0.0,
517
+ "median": 0.101,
518
+ "max": 0.5
519
+ },
520
+ "Thermal energy unspecified grade (MWh/tCO2)": {
521
+ "min": 0.0,
522
+ "median": 0.9306111111111112,
523
+ "max": 4.0
524
+ },
525
+ "Unspecified chemical (t/tCO2)": {
526
+ "min": 0.00013,
527
+ "median": 0.00316,
528
+ "max": 20.2
529
+ },
530
+ "Unspecified water (Liters/tCO2)": {
531
+ "min": 630.0,
532
+ "median": 201625.2165,
533
+ "max": 1296342.17
534
+ }
535
+ },
536
+ "BioCCS with anaerobic digestion/fermentation & growing biomass": {
537
+ "Arable land (ha/tCO2)": {
538
+ "min": 0.022803284,
539
+ "median": 0.058844191,
540
+ "max": 0.454545455
541
+ },
542
+ "Unspecified water (Liters/tCO2)": {
543
+ "min": 368182.0,
544
+ "median": 565909.0,
545
+ "max": 913636.0
546
+ }
547
+ }
548
+ }
data/generate_cost_matrix.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #%% uses the latest version of aggregated inputs to create the dictionary of costs
2
+ import json
3
+
4
+ import pandas as pd
5
+
6
+
7
+ def create_sliders_inputs():
8
+ df = pd.read_csv("inputs_aggregated.csv")
9
+
10
+ cost_sliders = {}
11
+
12
+ # extract data from inputs and create final dictionary for sliders
13
+ for _, row in df.iterrows():
14
+ method = row["Implementation"]
15
+ # break bio-char into 3 different cases, based on which biomass is used
16
+ """
17
+ For the Implementation "Biochar", we must create three different cases:
18
+ 1. Bio-char - Forest biomass
19
+ 2. Bio-char - Non-forest biomass
20
+ 3. Bio-char - Unspecified biomass
21
+ Where we have to keep the value for the corresponding resource in:
22
+ [Forest biomass OR Non-forest biomass OR Unspecified biomass]
23
+ But set the other two to zero, and keep the values in the other resources intact
24
+ """
25
+ resource = row["Resource"] + " (" + row["Unit"] + ")"
26
+ if row["min"] == row["max"]:
27
+ row["min"] = row["min"] * .5
28
+ entry = {
29
+ "min": float(row["min"]),
30
+ "median": float(row["median"]),
31
+ "max": float(row["max"])
32
+ }
33
+ cost_sliders.setdefault(method, {})[resource] = entry
34
+
35
+ print(cost_sliders)
36
+
37
+ # create the three cases for bio-char
38
+ cost_sliders["Bio-char - Forest biomass"] = cost_sliders["Bio-char"].copy()
39
+ cost_sliders["Bio-char - Forest biomass"].pop("Non-forest biomass (t/tCO2)")
40
+ cost_sliders["Bio-char - Forest biomass"].pop("Unspecified biomass (t/tCO2)")
41
+ cost_sliders["Bio-char - Non-forest biomass"] = cost_sliders["Bio-char"].copy()
42
+ cost_sliders["Bio-char - Non-forest biomass"].pop("Forest biomass (t/tCO2)")
43
+ cost_sliders["Bio-char - Non-forest biomass"].pop("Unspecified biomass (t/tCO2)")
44
+ cost_sliders["Bio-char - Unspecified biomass"] = cost_sliders["Bio-char"].copy()
45
+ cost_sliders["Bio-char - Unspecified biomass"].pop("Forest biomass (t/tCO2)")
46
+ cost_sliders["Bio-char - Unspecified biomass"].pop("Non-forest biomass (t/tCO2)")
47
+ # remove "Bio-char" from the dictionary
48
+ if "Bio-char" in cost_sliders:
49
+ del cost_sliders["Bio-char"]
50
+
51
+ # create all cases for enhanced weathering
52
+ cost_sliders["Enhanced weathering - Basalt mineral"] = cost_sliders["Enhanced weathering"].copy()
53
+ cost_sliders["Enhanced weathering - Basalt mineral"].pop("Olivine mineral (t/tCO2)")
54
+ cost_sliders["Enhanced weathering - Basalt mineral"].pop("Wollastonite mineral (t/tCO2)")
55
+ cost_sliders["Enhanced weathering - Basalt mineral"].pop("Unspecified mineral (t/tCO2)")
56
+ cost_sliders["Enhanced weathering - Olivine mineral"] = cost_sliders["Enhanced weathering"].copy()
57
+ cost_sliders["Enhanced weathering - Olivine mineral"].pop("Basalt mineral (t/tCO2)")
58
+ cost_sliders["Enhanced weathering - Olivine mineral"].pop("Wollastonite mineral (t/tCO2)")
59
+ cost_sliders["Enhanced weathering - Olivine mineral"].pop("Unspecified mineral (t/tCO2)")
60
+ cost_sliders["Enhanced weathering - Wollastonite mineral"] = cost_sliders["Enhanced weathering"].copy()
61
+ cost_sliders["Enhanced weathering - Wollastonite mineral"].pop("Basalt mineral (t/tCO2)")
62
+ cost_sliders["Enhanced weathering - Wollastonite mineral"].pop("Olivine mineral (t/tCO2)")
63
+ cost_sliders["Enhanced weathering - Wollastonite mineral"].pop("Unspecified mineral (t/tCO2)")
64
+ cost_sliders["Enhanced weathering - Unspecified mineral"] = cost_sliders["Enhanced weathering"].copy()
65
+ cost_sliders["Enhanced weathering - Unspecified mineral"].pop("Basalt mineral (t/tCO2)")
66
+ cost_sliders["Enhanced weathering - Unspecified mineral"].pop("Olivine mineral (t/tCO2)")
67
+ cost_sliders["Enhanced weathering - Unspecified mineral"].pop("Wollastonite mineral (t/tCO2)")
68
+ # remove "Enhanced weathering" from the dictionary
69
+ if "Enhanced weathering" in cost_sliders:
70
+ del cost_sliders["Enhanced weathering"]
71
+ # create case for growing biomass in bioccs
72
+ cost_sliders["BioCCS with combustion & growing biomass"] = cost_sliders["BioCCS with combustion"].copy()
73
+ cost_sliders["BioCCS with combustion"].pop("Arable land (ha/tCO2)")
74
+ cost_sliders["BioCCS with combustion & growing biomass"].pop("Forest biomass (t/tCO2)")
75
+ cost_sliders["BioCCS with combustion & growing biomass"].pop("Unspecified biomass (t/tCO2)")
76
+
77
+ cost_sliders["BioCCS with anaerobic digestion/fermentation & growing biomass"] = cost_sliders["BioCCS with anaerobic digestion/fermentation"].copy()
78
+ cost_sliders["BioCCS with anaerobic digestion/fermentation"].pop("Arable land (ha/tCO2)")
79
+ cost_sliders["BioCCS with anaerobic digestion/fermentation & growing biomass"].pop("Non-forest biomass (t/tCO2)")
80
+ cost_sliders["BioCCS with anaerobic digestion/fermentation & growing biomass"].pop("Unspecified biomass (t/tCO2)")
81
+
82
+
83
+
84
+ with open("cost_sliders.json", "w") as f:
85
+ json.dump(cost_sliders, f, indent=2)
86
+
87
+ print("Saved slider configuration to cost_sliders.json")
88
+
89
+ if __name__ == "__main__":
90
+ create_sliders_inputs()
91
+ print("Script executed successfully.")
92
+ # %%
data/inputs_aggregated.csv ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Implementation,Resource,Type,Unit,count,quantile_25,mean,median,quantile_75,std,min,max
2
+ Afforestation,Unspecified land,Physical,ha/tCO2,36,0.024592505,0.11565221097503724,0.094926862556845,0.197075,0.11236779976444418,0.002,0.38461538
3
+ Afforestation,Unspecified water,Physical,Liters/tCO2,2,92000.0,92000.0,92000.0,92000.0,0.0,92000.0,92000.0
4
+ Agroforestry,Arable land,Physical,ha/tCO2,12,0.03995278725,0.4507674440833333,0.06410128000000001,0.2141,0.901140274110988,0.0025,3.03030303
5
+ Bio-char,Electrical energy,Energy,MWh/tCO2,6,8.75e-05,0.1667833333333333,0.00035,0.3750875,0.2581085675964025,0.0,0.5
6
+ Bio-char,Forest biomass,Physical,t/tCO2,6,0.34,0.47283333333333327,0.37,0.55525,0.20162382465042825,0.33,0.82
7
+ Bio-char,Non-forest biomass,Physical,t/tCO2,8,1.142,1.291,1.3395000000000001,1.4885000000000002,0.332019792869556,0.818,1.667
8
+ Bio-char,Unspecified biomass,Physical,t/tCO2,48,0.94339623,1.924254525942129,1.20922073,2.522177213052725,1.9378239910641315,0.5,12.86
9
+ Bio-char,Unspecified land,Physical,ha/tCO2,4,0.05640158,0.16320079,0.16320079,0.27,0.12332110528547877,0.05640158,0.27
10
+ Bio-char,Unspecified water,Physical,Liters/tCO2,9,0.0,633.3333333333334,100.0,500.0,1376.5899897936204,-500.0,3000.0
11
+ BioCCS with anaerobic digestion/fermentation,Arable land,Physical,ha/tCO2,16,0.03793734775,0.100866767,0.058844191000000004,0.10303396649999999,0.11375772648817686,0.022803284,0.454545455
12
+ BioCCS with anaerobic digestion/fermentation,Non-forest biomass,Physical,t/tCO2,6,1.4285714285714,2.689964230684533,1.5617433414042998,2.1282742681047,2.6242499596696813,1.315,8.0
13
+ BioCCS with anaerobic digestion/fermentation,Unspecified biomass,Physical,t/tCO2,6,1.03357023,1.3793645466666666,1.14,1.785,0.4849128814150571,0.99809364,2.0
14
+ BioCCS with anaerobic digestion/fermentation,Unspecified water,Physical,Liters/tCO2,14,395454.5,569805.1428571428,565909.0,654545.5,183277.283077123,368182.0,913636.0
15
+ BioCCS with combustion,Arable land,Physical,ha/tCO2,32,0.038,0.20054008704125,0.058399844,0.09459459,0.4656596577374178,0.022803284,1.9451
16
+ BioCCS with combustion,Electrical energy,Energy,MWh/tCO2,18,0.0277777777777777,0.13097530864197526,0.101,0.1111111111111111,0.16241025701586306,0.0,0.5
17
+ BioCCS with combustion,Forest biomass,Physical,t/tCO2,8,0.5607638875000001,0.67548055375,0.59375,0.8386749975,0.14441914653695664,0.55555555,0.8547
18
+ BioCCS with combustion,Thermal energy unspecified grade,Energy,MWh/tCO2,22,0.3472222222222222,1.0062424242424242,0.9306111111111111,1.025,1.0524401441735463,0.0,4.0
19
+ BioCCS with combustion,Unspecified biomass,Physical,t/tCO2,8,0.9166666675,1.2641666675,1.14,1.625,0.5282247887342408,0.66666667,2.0
20
+ BioCCS with combustion,Unspecified chemical,Physical,t/tCO2,20,0.00027,4.044119,0.00316,0.016,8.287794157908491,0.00013,20.2
21
+ BioCCS with combustion,Unspecified water,Physical,Liters/tCO2,32,6475.0,312937.45634375,201625.2165,542045.5,343154.80918602005,630.0,1296342.17
22
+ "Coastal revegetation (mangrove, seaweeds…)",Non-arable land,Physical,ha/tCO2,11,0.043295020000000004,0.13201796181818182,0.12056618,0.19744896,0.11706388563455744,0.0078,0.32828863
23
+ Cropland management,Arable land,Physical,ha/tCO2,14,0.27061989000000003,1.2779463596825358,0.42063492277774994,1.05233487,2.3297794467976978,0.08264463,9.0
24
+ Durable biobased products,Electrical energy,Energy,MWh/tCO2,2,4.0,4.0,4.0,4.0,0.0,4.0,4.0
25
+ Durable biobased products,Non-arable land,Physical,ha/tCO2,2,6.0,6.0,6.0,6.0,0.0,6.0,6.0
26
+ Durable biobased products,Unspecified biomass,Physical,t/tCO2,6,1.2678571425,2.6071428566666666,3.57142857,3.8928571425,1.8426633339173129,0.0,4.0
27
+ Durable biobased products,Unspecified water,Physical,Liters/tCO2,2,200.0,300.0,300.0,400.0,282.842712474619,100.0,500.0
28
+ Electrochemical DACCS,Electrical energy,Energy,MWh/tCO2,10,0.33333333335000004,2.0320806,0.784125,2.75,2.3788325030763033,0.252556,6.2222222222
29
+ Electrochemical DACCS,Non-arable land,Physical,ha/tCO2,14,0.00027248,0.0026615877837057145,0.000323748514,0.000880697128935,0.005656829998005935,0.0002225771032,0.016
30
+ Electrochemical DACCS,Unspecified water,Physical,Liters/tCO2,6,2000.0,11000.0,5000.0,21500.0,12521.980673998822,1000.0,27000.0
31
+ Electrochemical OAE,Electrical energy,Energy,MWh/tCO2,8,1.6,2.24125,2.15,2.5,1.2835935883292655,0.83,5.0
32
+ Electrochemical OAE,Non-arable land,Physical,ha/tCO2,2,0.00086,0.00101,0.00101,0.00116,0.00042426406871192844,0.00071,0.00131
33
+ Electrochemical OAE,Shoreline,Physical,km/tCO2,2,1.2e-08,1.2e-08,1.2e-08,1.2e-08,0.0,1.2e-08,1.2e-08
34
+ Electrochemical OAE,Unspecified mineral,Physical,t/tCO2,4,2.4,2.95,2.95,3.5,0.6350852961085884,2.4,3.5
35
+ Enhanced weathering,Arable land,Physical,ha/tCO2,28,0.12875,0.548973515,0.25,0.5,0.7099161244217219,1e-06,2.5
36
+ Enhanced weathering,Basalt mineral,Physical,t/tCO2,25,3.33,5.773041804595108,4.3,5.3,4.967901225163679,1.0,19.0
37
+ Enhanced weathering,Electrical energy,Energy,MWh/tCO2,8,0.09285,0.59343125,0.38875000000000004,0.5,0.9045657102947644,0.00925,2.775
38
+ Enhanced weathering,Non-arable land,Physical,ha/tCO2,12,0.004428795,11.432468628333334,0.00906504,28.5714286,17.226399848110834,0.0009,40.0
39
+ Enhanced weathering,Olivine mineral,Physical,t/tCO2,26,0.9090909,1.4295112634615386,1.25,1.58,0.9412466256217807,0.27027027,3.7
40
+ Enhanced weathering,Unspecified mineral,Physical,t/tCO2,19,1.31578947,6.356736418947368,2.5,8.625,7.726415037245945,0.5,25.0
41
+ Enhanced weathering,Unspecified water,Physical,Liters/tCO2,5,500.0,10466.4,866.0,866.0,22102.21859452123,100.0,50000.0
42
+ Enhanced weathering,Wollastonite mineral,Physical,t/tCO2,8,1.3214285714285499,1.62964285714285,1.5642857142856998,1.83,0.7423655162834324,0.56,3.0
43
+ Forest management,Unspecified land,Physical,ha/tCO2,2,0.43867500000000004,0.76865,0.76865,1.0986250000000002,0.9333102404881242,0.1087,1.4286
44
+ High-temp DACCS (solid-sorbent/liquid-solvent),Electrical energy,Energy,MWh/tCO2,32,0.3611111111,0.42378784722013874,0.46296111111111,0.5,0.16317834501458298,0.077,0.77
45
+ High-temp DACCS (solid-sorbent/liquid-solvent),Non-arable land,Physical,ha/tCO2,23,2.2000000000000002e-08,0.00022929641616869565,0.0002225771032,0.000298114257,0.0002987803322061786,1.5e-10,0.0009914798235
46
+ High-temp DACCS (solid-sorbent/liquid-solvent),Thermal energy high grade,Energy,MWh/tCO2,38,1.4722222222,1.954835008771642,1.75,2.3148148055556,0.6439376166933265,1.125,3.8
47
+ High-temp DACCS (solid-sorbent/liquid-solvent),Unspecified water,Physical,Liters/tCO2,16,2502.0435975,10221.02242375,4700.0,8180.0,15886.886921845426,0.005,50000.0
48
+ Low-temp DACCS (solid-sorbent/liquid-solvent),Electrical energy,Energy,MWh/tCO2,44,0.218,0.8953202020237373,0.46296111111111,0.69,1.2556951906425198,0.13,4.6111111111
49
+ Low-temp DACCS (solid-sorbent/liquid-solvent),Non-arable land,Physical,ha/tCO2,23,6.25e-08,0.00023824473964695653,0.0002225771032,0.000298114257,0.00029447829320152126,1e-11,0.0009914798235
50
+ Low-temp DACCS (solid-sorbent/liquid-solvent),Thermal energy low grade,Energy,MWh/tCO2,30,1.4324999999999999,1.6782145666607466,1.5,2.062499999975,0.5167942816781624,0.6388888889,2.7222222222
51
+ Low-temp DACCS (solid-sorbent/liquid-solvent),Unspecified water,Physical,Liters/tCO2,14,0.00075,3186.8824842857143,1008.17439,4925.0,5237.922016339205,-2000.0,15000.0
52
+ Mineral OAE / Ocean liming,Electrical energy,Energy,MWh/tCO2,12,0.323625,1.1535833333333334,0.6065,1.755,1.2860244737055733,0.027,4.0
53
+ Mineral OAE / Ocean liming,Non-arable land,Physical,ha/tCO2,4,0.0,0.000505,0.000355,0.00086,0.0006324818837985268,0.0,0.00131
54
+ Mineral OAE / Ocean liming,Thermal energy unspecified grade,Energy,MWh/tCO2,6,1.3888888888888888,1.2576296296296297,1.4589444444444444,1.529,0.5425887907843043,0.16,1.55
55
+ Mineral OAE / Ocean liming,Unspecified mineral,Physical,t/tCO2,8,1.62,2.489,1.7429999999999999,2.5895,1.5545979728350534,1.4,5.0
56
+ Mineral OAE / Ocean liming,Unspecified water,Physical,Liters/tCO2,2,678.331,678.331,678.331,678.331,0.0,678.331,678.331
57
+ Mineral looping DACCS,Electrical energy,Energy,MWh/tCO2,8,0.0833333333,1.1041666666583332,0.0833333333333333,1.375,1.793811009144325,0.0,4.0
58
+ Mineral looping DACCS,Non-arable land,Physical,ha/tCO2,12,0.0005870872613099999,0.001064587040495,0.00063889,0.0008728674558749999,0.0010640920465922832,0.0002225771032,0.0033
59
+ Mineral looping DACCS,Thermal energy unspecified grade,Energy,MWh/tCO2,4,1.4791666666749999,1.715277777775,1.81944444445,2.05555555555,0.5340152854505239,1.0,2.2222222222
60
+ Mineral looping DACCS,Unspecified mineral,Physical,t/tCO2,4,0.15000000000000002,0.225,0.2,0.275,0.20615528128088303,0.0,0.5
61
+ Mineral looping DACCS,Unspecified water,Physical,Liters/tCO2,6,125.0,6761.8350550000005,200.0,10067.75258,11115.783599449733,0.0,26714.00689
62
+ Mineralization ex-situ,Electrical energy,Energy,MWh/tCO2,8,0.5,1.0625,0.75,1.25,0.9797047660246574,0.0,3.0
63
+ Mineralization ex-situ,Non-arable land,Physical,ha/tCO2,4,0.0002984556613,0.000521538621485,0.00043604877962,0.0006591317398049999,0.00034159549577798685,0.0002225771032,0.0009914798235
64
+ Mineralization ex-situ,Olivine mineral,Physical,t/tCO2,2,0.8,0.8,0.8,0.8,0.0,0.8,0.8
65
+ Mineralization ex-situ,Thermal energy unspecified grade,Energy,MWh/tCO2,4,0.4,0.575,0.45,0.625,0.2872281323269014,0.4,1.0
66
+ Mineralization ex-situ,Unspecified mineral,Physical,t/tCO2,22,0.4375,3.9349999999999996,3.0,7.0,3.6477217286306,0.04,10.0
67
+ Mineralization ex-situ,Unspecified water,Physical,Liters/tCO2,14,200.0,50004.28571428572,5450.0,14500.0,106907.99154947611,0.0,300000.0
68
+ Moisture swing DACCS,Electrical energy,Energy,MWh/tCO2,4,0.316,0.32466666665,0.32466666665,0.3333333333,0.01000740464670849,0.316,0.3333333333
69
+ Moisture swing DACCS,Non-arable land,Physical,ha/tCO2,8,0.00016893282740000002,0.0003308893107425,0.00027248,0.00037989864681,0.0003186555229397746,8e-06,0.0009914798235
70
+ Moisture swing DACCS,Unspecified water,Physical,Liters/tCO2,4,-146.0,427.0,427.0,1000.0,661.6434084913111,-146.0,1000.0
71
+ Pasture management,Arable land,Physical,ha/tCO2,24,0.10225284750000001,0.44236770317026247,0.25242204,0.522974429158825,0.522145451866414,0.07189434,2.28974424
72
+ Reforestation,Unspecified land,Physical,ha/tCO2,34,0.044458695,1.5641017441794511,0.094926862556845,0.1887,6.8258032964187745,0.002,38.8
73
+ Reforestation,Unspecified water,Physical,Liters/tCO2,2,92000.0,92000.0,92000.0,92000.0,0.0,92000.0,92000.0
74
+ pH swing,Electrical energy,Energy,MWh/tCO2,28,0.98,2.2051124785714284,1.768,3.3024999999999998,1.3819088428118145,0.66,4.67
75
+ pH swing,Salt water,Physical,Liters/tCO2,4,435000.0,4780000.0,4780000.0,9125000.0,5017173.8392578475,435000.0,9125000.0
76
+ pH swing,Unspecified water,Physical,Liters/tCO2,4,217391.304,6608695.652,6608695.652,13000000.0,7380042.571581251,217391.304,13000000.0
data/inputs_aggregated_old.csv ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Implementation,Resource,Type,Unit,count,quantile_25,mean,median,quantile_75,std,min,max
2
+ Agroforestry,Arable land,Physical,ha/tCO2,12,0.03995278725,0.4507674440833333,0.06410128000000001,0.2141,0.901140274110988,0.0025,3.03030303
3
+ Bio-char,Electrical energy,Energy,MWh/tCO2,6,8.75e-05,0.1667833333333333,0.00035,0.3750875,0.2581085675964025,0.0,0.5
4
+ Bio-char,Forest biomass,Physical,t/tCO2,6,0.34,0.47283333333333327,0.37,0.55525,0.20162382465042825,0.33,0.82
5
+ Bio-char,Non-forest biomass,Physical,t/tCO2,8,1.142,1.291,1.3395000000000001,1.4885000000000002,0.332019792869556,0.818,1.667
6
+ Bio-char,Unspecified biomass,Physical,t/tCO2,48,0.94339623,1.924254525942129,1.20922073,2.522177213052725,1.9378239910641315,0.5,12.86
7
+ Bio-char,Unspecified land,Physical,ha/tCO2,4,0.05640158,0.16320079,0.16320079,0.27,0.12332110528547877,0.05640158,0.27
8
+ Bio-char,Unspecified water,Physical,Liters/tCO2,9,0.0,633.3333333333334,100.0,500.0,1376.5899897936204,-500.0,3000.0
9
+ BioCCS with anaerobic digestion/fermentation,Arable land,Physical,ha/tCO2,16,0.03793734775,0.100866767,0.058844191000000004,0.10303396649999999,0.11375772648817686,0.022803284,0.454545455
10
+ BioCCS with anaerobic digestion/fermentation,Non-forest biomass,Physical,t/tCO2,6,1.4285714285714,2.689964230684533,1.5617433414042998,2.1282742681047,2.6242499596696813,1.315,8.0
11
+ BioCCS with anaerobic digestion/fermentation,Unspecified biomass,Physical,t/tCO2,6,1.03357023,1.3793645466666666,1.14,1.785,0.4849128814150571,0.99809364,2.0
12
+ BioCCS with anaerobic digestion/fermentation,Unspecified water,Physical,Liters/tCO2,14,395454.5,569805.1428571428,565909.0,654545.5,183277.283077123,368182.0,913636.0
13
+ BioCCS with combustion,Arable land,Physical,ha/tCO2,32,0.038,0.20054008704125,0.058399844,0.09459459,0.4656596577374178,0.022803284,1.9451
14
+ BioCCS with combustion,Electrical energy,Energy,MWh/tCO2,18,0.0277777777777777,0.13097530864197526,0.101,0.1111111111111111,0.16241025701586306,0.0,0.5
15
+ BioCCS with combustion,Forest biomass,Physical,t/tCO2,8,0.5607638875000001,0.67548055375,0.59375,0.8386749975,0.14441914653695664,0.55555555,0.8547
16
+ BioCCS with combustion,Thermal energy,Energy,MWh/tCO2,22,0.3472222222222222,1.0062424242424242,0.9306111111111111,1.025,1.0524401441735463,0.0,4.0
17
+ BioCCS with combustion,Unspecified biomass,Physical,t/tCO2,8,0.9166666675,1.2641666675,1.14,1.625,0.5282247887342408,0.66666667,2.0
18
+ BioCCS with combustion,Unspecified chemical,Physical,t/tCO2,20,0.00027,4.044119,0.00316,0.016,8.287794157908491,0.00013,20.2
19
+ BioCCS with combustion,Unspecified water,Physical,Liters/tCO2,32,6475.0,312937.45634375,201625.2165,542045.5,343154.80918602005,630.0,1296342.17
20
+ "Coastal revegetation (mangrove, seaweeds…)",Non-arable land,Physical,ha/tCO2,11,0.043295020000000004,0.13201796181818182,0.12056618,0.19744896,0.11706388563455744,0.0078,0.32828863
21
+ Cropland management,Arable land,Physical,ha/tCO2,14,0.27061989000000003,1.2779463596825358,0.42063492277774994,1.05233487,2.3297794467976978,0.08264463,9.0
22
+ Durable biobased products,Electrical energy,Energy,MWh/tCO2,2,4.0,4.0,4.0,4.0,0.0,4.0,4.0
23
+ Durable biobased products,Non-arable land,Physical,ha/tCO2,2,6.0,6.0,6.0,6.0,0.0,6.0,6.0
24
+ Durable biobased products,Unspecified biomass,Physical,t/tCO2,6,1.2678571425,2.6071428566666666,3.57142857,3.8928571425,1.8426633339173129,0.0,4.0
25
+ Durable biobased products,Unspecified water,Physical,Liters/tCO2,2,200.0,300.0,300.0,400.0,282.842712474619,100.0,500.0
26
+ Electrochemical DACCS,Electrical energy,Energy,MWh/tCO2,10,0.33333333335000004,2.0320806,0.784125,2.75,2.3788325030763033,0.252556,6.2222222222
27
+ Electrochemical DACCS,Non-arable land,Physical,ha/tCO2,14,0.00027248,0.0026615877837057145,0.000323748514,0.000880697128935,0.005656829998005935,0.0002225771032,0.016
28
+ Electrochemical DACCS,Unspecified water,Physical,Liters/tCO2,6,2000.0,11000.0,5000.0,21500.0,12521.980673998822,1000.0,27000.0
29
+ Electrochemical OAE,Electrical energy,Energy,MWh/tCO2,8,1.6,2.24125,2.15,2.5,1.2835935883292655,0.83,5.0
30
+ Electrochemical OAE,Non-arable land,Physical,ha/tCO2,2,0.00086,0.00101,0.00101,0.00116,0.00042426406871192844,0.00071,0.00131
31
+ Electrochemical OAE,Shoreline,Physical,km/tCO2,2,1.2e-08,1.2e-08,1.2e-08,1.2e-08,0.0,1.2e-08,1.2e-08
32
+ Electrochemical OAE,Unspecified mineral,Physical,t/tCO2,4,2.4,2.95,2.95,3.5,0.6350852961085884,2.4,3.5
33
+ Enhanced weathering,Arable land,Physical,ha/tCO2,28,0.12875,0.548973515,0.25,0.5,0.7099161244217219,1e-06,2.5
34
+ Enhanced weathering,Basalt mineral,Physical,t/tCO2,25,3.33,5.773041804595108,4.3,5.3,4.967901225163679,1.0,19.0
35
+ Enhanced weathering,Electrical energy,Energy,MWh/tCO2,8,0.09285,0.59343125,0.38875000000000004,0.5,0.9045657102947644,0.00925,2.775
36
+ Enhanced weathering,Non-arable land,Physical,ha/tCO2,12,0.004428795,11.432468628333334,0.00906504,28.5714286,17.226399848110834,0.0009,40.0
37
+ Enhanced weathering,Olivine mineral,Physical,t/tCO2,26,0.9090909,1.4295112634615386,1.25,1.58,0.9412466256217807,0.27027027,3.7
38
+ Enhanced weathering,Unspecified mineral,Physical,t/tCO2,19,1.31578947,6.356736418947368,2.5,8.625,7.726415037245945,0.5,25.0
39
+ Enhanced weathering,Unspecified water,Physical,Liters/tCO2,5,500.0,10466.4,866.0,866.0,22102.21859452123,100.0,50000.0
40
+ Enhanced weathering,Wollastonite mineral,Physical,t/tCO2,8,1.3214285714285499,1.62964285714285,1.5642857142856998,1.83,0.7423655162834324,0.56,3.0
41
+ Forest management,Unspecified land,Physical,ha/tCO2,2,0.43867500000000004,0.76865,0.76865,1.0986250000000002,0.9333102404881242,0.1087,1.4286
42
+ Forestry,Unspecified land,Physical,ha/tCO2,70,0.0264,0.8191848413886097,0.094926862556845,0.1887,4.777133871507938,0.002,38.8
43
+ Forestry,Unspecified water,Physical,Liters/tCO2,4,92000.0,92000.0,92000.0,92000.0,0.0,92000.0,92000.0
44
+ High-temp DACCS (solid-sorbent/liquid-solvent),Electrical energy,Energy,MWh/tCO2,32,0.3611111111,0.42378784722013874,0.46296111111111,0.5,0.16317834501458298,0.077,0.77
45
+ High-temp DACCS (solid-sorbent/liquid-solvent),Non-arable land,Physical,ha/tCO2,23,2.2000000000000002e-08,0.00022929641616869565,0.0002225771032,0.000298114257,0.0002987803322061786,1.5e-10,0.0009914798235
46
+ High-temp DACCS (solid-sorbent/liquid-solvent),Thermal energy,Energy,MWh/tCO2,38,1.4722222222,1.954835008771642,1.75,2.3148148055556,0.6439376166933265,1.125,3.8
47
+ High-temp DACCS (solid-sorbent/liquid-solvent),Unspecified water,Physical,Liters/tCO2,16,2502.0435975,10221.02242375,4700.0,8180.0,15886.886921845426,0.005,50000.0
48
+ Low-temp DACCS (solid-sorbent/liquid-solvent),Electrical energy,Energy,MWh/tCO2,44,0.218,0.8953202020237373,0.46296111111111,0.69,1.2556951906425198,0.13,4.6111111111
49
+ Low-temp DACCS (solid-sorbent/liquid-solvent),Non-arable land,Physical,ha/tCO2,23,6.25e-08,0.00023824473964695653,0.0002225771032,0.000298114257,0.00029447829320152126,1e-11,0.0009914798235
50
+ Low-temp DACCS (solid-sorbent/liquid-solvent),Thermal energy,Energy,MWh/tCO2,30,1.4324999999999999,1.6782145666607466,1.5,2.062499999975,0.5167942816781624,0.6388888889,2.7222222222
51
+ Low-temp DACCS (solid-sorbent/liquid-solvent),Unspecified water,Physical,Liters/tCO2,14,0.00075,3186.8824842857143,1008.17439,4925.0,5237.922016339205,-2000.0,15000.0
52
+ Mineral OAE / Ocean liming,Electrical energy,Energy,MWh/tCO2,12,0.323625,1.1535833333333334,0.6065,1.755,1.2860244737055733,0.027,4.0
53
+ Mineral OAE / Ocean liming,Non-arable land,Physical,ha/tCO2,4,0.0,0.000505,0.000355,0.00086,0.0006324818837985268,0.0,0.00131
54
+ Mineral OAE / Ocean liming,Thermal energy,Energy,MWh/tCO2,6,1.3888888888888888,1.2576296296296297,1.4589444444444444,1.529,0.5425887907843043,0.16,1.55
55
+ Mineral OAE / Ocean liming,Unspecified mineral,Physical,t/tCO2,8,1.62,2.489,1.7429999999999999,2.5895,1.5545979728350534,1.4,5.0
56
+ Mineral OAE / Ocean liming,Unspecified water,Physical,Liters/tCO2,2,678.331,678.331,678.331,678.331,0.0,678.331,678.331
57
+ Mineral looping DACCS,Electrical energy,Energy,MWh/tCO2,8,0.0833333333,1.1041666666583332,0.0833333333333333,1.375,1.793811009144325,0.0,4.0
58
+ Mineral looping DACCS,Non-arable land,Physical,ha/tCO2,12,0.0005870872613099999,0.001064587040495,0.00063889,0.0008728674558749999,0.0010640920465922832,0.0002225771032,0.0033
59
+ Mineral looping DACCS,Thermal energy,Energy,MWh/tCO2,4,1.4791666666749999,1.715277777775,1.81944444445,2.05555555555,0.5340152854505239,1.0,2.2222222222
60
+ Mineral looping DACCS,Unspecified mineral,Physical,t/tCO2,4,0.15000000000000002,0.225,0.2,0.275,0.20615528128088303,0.0,0.5
61
+ Mineral looping DACCS,Unspecified water,Physical,Liters/tCO2,6,125.0,6761.8350550000005,200.0,10067.75258,11115.783599449733,0.0,26714.00689
62
+ Mineralization ex-situ,Electrical energy,Energy,MWh/tCO2,8,0.5,1.0625,0.75,1.25,0.9797047660246574,0.0,3.0
63
+ Mineralization ex-situ,Non-arable land,Physical,ha/tCO2,4,0.0002984556613,0.000521538621485,0.00043604877962,0.0006591317398049999,0.00034159549577798685,0.0002225771032,0.0009914798235
64
+ Mineralization ex-situ,Olivine mineral,Physical,t/tCO2,2,0.8,0.8,0.8,0.8,0.0,0.8,0.8
65
+ Mineralization ex-situ,Thermal energy,Energy,MWh/tCO2,4,0.4,0.575,0.45,0.625,0.2872281323269014,0.4,1.0
66
+ Mineralization ex-situ,Unspecified mineral,Physical,t/tCO2,22,0.4375,3.9349999999999996,3.0,7.0,3.6477217286306,0.04,10.0
67
+ Mineralization ex-situ,Unspecified water,Physical,Liters/tCO2,14,200.0,50004.28571428572,5450.0,14500.0,106907.99154947611,0.0,300000.0
68
+ Moisture swing DACCS,Electrical energy,Energy,MWh/tCO2,4,0.316,0.32466666665,0.32466666665,0.3333333333,0.01000740464670849,0.316,0.3333333333
69
+ Moisture swing DACCS,Non-arable land,Physical,ha/tCO2,8,0.00016893282740000002,0.0003308893107425,0.00027248,0.00037989864681,0.0003186555229397746,8e-06,0.0009914798235
70
+ Moisture swing DACCS,Unspecified water,Physical,Liters/tCO2,4,-146.0,427.0,427.0,1000.0,661.6434084913111,-146.0,1000.0
71
+ Pasture management,Arable land,Physical,ha/tCO2,24,0.10225284750000001,0.44236770317026247,0.25242204,0.522974429158825,0.522145451866414,0.07189434,2.28974424
72
+ pH swing,Electrical energy,Energy,MWh/tCO2,28,0.98,2.2051124785714284,1.768,3.3024999999999998,1.3819088428118145,0.66,4.67
73
+ pH swing,Salt water,Physical,Liters/tCO2,4,435000.0,4780000.0,4780000.0,9125000.0,5017173.8392578475,435000.0,9125000.0
74
+ pH swing,Unspecified water,Physical,Liters/tCO2,4,217391.304,6608695.652,6608695.652,13000000.0,7380042.571581251,217391.304,13000000.0
data/secondary_resources.csv ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ method,resource
2
+ Afforestation,Unspecified water (Liters/tCO2)
3
+ Reforestation,Unspecified water (Liters/tCO2)
4
+ Durable biobased products,Non-arable land (ha/tCO2)
5
+ Durable biobased products,Electrical energy (MWh/tCO2)
6
+ Durable biobased products,Unspecified water (Liters/tCO2)
7
+ Bio-char - Forest biomass,Unspecified land (ha/tCO2)
8
+ Bio-char - Forest biomass,Electrical energy (MWh/tCO2)
9
+ Bio-char - Forest biomass,Unspecified water (Liters/tCO2)
10
+ Bio-char - Non-forest biomass,Unspecified land (ha/tCO2)
11
+ Bio-char - Non-forest biomass,Electrical energy (MWh/tCO2)
12
+ Bio-char - Non-forest biomass,Unspecified water (Liters/tCO2)
13
+ Bio-char - Unspecified biomass,Unspecified land (ha/tCO2)
14
+ Bio-char - Unspecified biomass,Electrical energy (MWh/tCO2)
15
+ Bio-char - Unspecified biomass,Unspecified water (Liters/tCO2)
16
+ BioCCS with combustion,Unspecified chemical (t/tCO2)
17
+ BioCCS with combustion,Electrical energy (MWh/tCO2)
18
+ BioCCS with combustion,Thermal energy (MWh/tCO2)
19
+ BioCCS with combustion,Unspecified water (Liters/tCO2)
20
+ BioCCS with combustion & growing biomass,Unspecified chemical (t/tCO2)
21
+ BioCCS with combustion & growing biomass,Electrical energy (MWh/tCO2)
22
+ BioCCS with combustion & growing biomass,Thermal energy (MWh/tCO2)
23
+ BioCCS with combustion & growing biomass,Unspecified water (Liters/tCO2)
24
+ BioCCS with anaerobic digestion/fermentation,Unspecified water (Liters/tCO2)
25
+ BioCCS with anaerobic digestion/fermentation & growing biomass,Unspecified water (Liters/tCO2)
26
+ Enhanced weathering - Basalt mineral,Arable land (ha/tCO2)
27
+ Enhanced weathering - Basalt mineral,Non-arable land (ha/tCO2)
28
+ Enhanced weathering - Basalt mineral,Electrical energy (MWh/tCO2)
29
+ Enhanced weathering - Basalt mineral,Unspecified water (Liters/tCO2)
30
+ Enhanced weathering - Olivine mineral,Arable land (ha/tCO2)
31
+ Enhanced weathering - Olivine mineral,Non-arable land (ha/tCO2)
32
+ Enhanced weathering - Olivine mineral,Electrical energy (MWh/tCO2)
33
+ Enhanced weathering - Olivine mineral,Unspecified water (Liters/tCO2)
34
+ Enhanced weathering - Wollastonite mineral,Arable land (ha/tCO2)
35
+ Enhanced weathering - Wollastonite mineral,Non-arable land (ha/tCO2)
36
+ Enhanced weathering - Wollastonite mineral,Electrical energy (MWh/tCO2)
37
+ Enhanced weathering - Wollastonite mineral,Unspecified water (Liters/tCO2)
38
+ Enhanced weathering - Unspecified mineral,Arable land (ha/tCO2)
39
+ Enhanced weathering - Unspecified mineral,Non-arable land (ha/tCO2)
40
+ Enhanced weathering - Unspecified mineral,Electrical energy (MWh/tCO2)
41
+ Enhanced weathering - Unspecified mineral,Unspecified water (Liters/tCO2)
42
+ Mineral OAE / Ocean liming,Non-arable land (ha/tCO2)
43
+ Mineral OAE / Ocean liming,Electrical energy (MWh/tCO2)
44
+ Mineral OAE / Ocean liming,Thermal energy (MWh/tCO2)
45
+ Mineral OAE / Ocean liming,Unspecified water (Liters/tCO2)
46
+ Electrochemical OAE,Non-arable land (ha/tCO2)
47
+ Electrochemical DACCS,Non-arable land (ha/tCO2)
48
+ Low-temp DACCS (solid-sorbent/liquid-solvent),Unspecified water (Liters/tCO2)
49
+ High-temp DACCS (solid-sorbent/liquid-solvent),Unspecified water (Liters/tCO2)
50
+ Mineral looping DACCS,Unspecified water (Liters/tCO2)
data/update_cost_sliders_with_priority.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ import pandas as pd
4
+
5
+ # === Load JSON data ===
6
+ with open("cost_sliders.json", "r") as f:
7
+ cost_sliders = json.load(f)
8
+
9
+ # === Load resource priority CSV ===
10
+ df_priority = pd.read_csv("resource_priority.csv")
11
+
12
+ # === Validate columns ===
13
+ required_cols = {"method", "resource", "priority"}
14
+ if not required_cols.issubset(df_priority.columns):
15
+ raise ValueError(f"CSV must contain the columns: {required_cols}")
16
+
17
+ # === Update the JSON structure ===
18
+ for _, row in df_priority.iterrows():
19
+ method = row["method"]
20
+ resource = row["resource"]
21
+ priority = row["priority"]
22
+
23
+ if method in cost_sliders and resource in cost_sliders[method]:
24
+ cost_sliders[method][resource]["priority"] = priority
25
+ else:
26
+ print(f"⚠️ Warning: ({method} / {resource}) not found in JSON.")
27
+
28
+ # === Save the updated JSON ===
29
+ with open("cost_sliders_with_priority.json", "w") as f:
30
+ json.dump(cost_sliders, f, indent=2)
31
+
32
+ print("✅ Updated JSON saved to cost_sliders_with_priority.json")
optimization/__init__.py ADDED
File without changes
optimization/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (204 Bytes). View file
 
optimization/__pycache__/optimization.cpython-311.pyc ADDED
Binary file (4.08 kB). View file
 
optimization/optimization.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from scipy.optimize import linprog
3
+
4
+
5
+ def run_optimization(resource_caps, method_constraints, method_costs):
6
+ """
7
+ Run linear optimization to maximize CO₂ removal while respecting resource limits and method constraints.
8
+
9
+ Args:
10
+ resource_caps (dict): {resource: available_quantity}
11
+ method_constraints (dict): {method: {"active": bool, "max_share": float}}
12
+ method_costs (dict): {method: {resource: usage_per_tCO2}}
13
+
14
+ Returns:
15
+ (bool, dict): (success_flag, result_dict)
16
+ result_dict includes "total_removed", "method_usage"
17
+ """
18
+ methods = list(method_costs.keys())
19
+ resources = list(resource_caps.keys())
20
+
21
+ # A matrix: each row is a resource, each column a method
22
+ A_resource = np.array([
23
+ [method_costs[m].get(r, 0.0) for m in methods]
24
+ for r in resources
25
+ ])
26
+ b_resource = np.array([resource_caps[r] for r in resources])
27
+
28
+ # Constraint: sum(x_i) * share_i ≤ x_i
29
+ A_share = []
30
+ b_share = []
31
+ for i, m in enumerate(methods):
32
+ row = np.zeros(len(methods))
33
+ row += -method_constraints[m]["max_share"]
34
+ row[i] += 1
35
+ A_share.append(row)
36
+ b_share.append(0)
37
+
38
+ # Combine constraints
39
+ A_ub = np.vstack([A_resource, A_share])
40
+ b_ub = np.concatenate([b_resource, b_share])
41
+
42
+ # Objective: maximize sum(x_i), hence minimize -1 * sum(x_i)
43
+ c = -1 * np.ones(len(methods))
44
+ bounds = [(0, None)] * len(methods)
45
+
46
+ try:
47
+ result = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, method="highs")
48
+ if result.success:
49
+ x = np.floor(result.x).astype(int)
50
+ total_removed = int(x.sum())
51
+ method_usage = {m: int(x[i]) for i, m in enumerate(methods) if x[i] > 0}
52
+ return True, {"total_removed": total_removed, "method_usage": method_usage}
53
+ else:
54
+ return False, {"message": result.message}
55
+ except Exception as e:
56
+ return False, {"message": str(e)}
requirements.txt CHANGED
Binary files a/requirements.txt and b/requirements.txt differ
 
tabs/__init__.py ADDED
File without changes
tabs/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (196 Bytes). View file
 
tabs/__pycache__/tab0_welcome.cpython-311.pyc ADDED
Binary file (1.48 kB). View file
 
tabs/__pycache__/tab1_inputs.cpython-311.pyc ADDED
Binary file (4.63 kB). View file
 
tabs/__pycache__/tab2_constraints.cpython-311.pyc ADDED
Binary file (5.16 kB). View file
 
tabs/__pycache__/tab3_coefficients.cpython-311.pyc ADDED
Binary file (9.07 kB). View file
 
tabs/__pycache__/tab3_test.cpython-311.pyc ADDED
Binary file (1.52 kB). View file
 
tabs/__pycache__/tab4_optimization.cpython-311.pyc ADDED
Binary file (11 kB). View file
 
tabs/__pycache__/tab5_scenarios.cpython-311.pyc ADDED
Binary file (10.1 kB). View file
 
tabs/__pycache__/tab5_sensitivity.cpython-311.pyc ADDED
Binary file (5.55 kB). View file
 
tabs/__pycache__/tab6_scenarios.cpython-311.pyc ADDED
Binary file (6.79 kB). View file
 
tabs/__pycache__/tab6_sensitivity.cpython-311.pyc ADDED
Binary file (474 Bytes). View file
 
tabs/tab0_welcome.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+
4
+ def render_tab():
5
+ st.header("Welcome!")
6
+ st.markdown("""
7
+ This tool helps you optimize your carbon direct removal portfolio by adjusting resource usage and constraints.
8
+
9
+ **Required:**
10
+ 1. **Resource inputs**: provide the total available quantities of resources for 1 year.
11
+
12
+ **Optionnal:**
13
+
14
+ 2. **Method constraints**: select which carbon removal methods are active and set their maximum portfolio share.
15
+ 3. **Resource efficiency coefficients**: adjust the resource usage for each method.
16
+
17
+ **Outputs:**
18
+
19
+ 4. **Portfolio generation**: run the optimization to find the best portfolio: how much CO2 removed, what methods are used, and in what proportions.
20
+
21
+ **Explore:**
22
+
23
+ 5. **Sensitivity analysis**: analyze how changes in method shares or resource availability affect the portfolio.
24
+ 6. **Scenario comparison**: compare different scenarios based on the optimization results.
25
+
26
+ Let's get started! Use the side tabs to navigate through the sections.
27
+ """)
28
+
29
+
tabs/tab1_inputs.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import streamlit as st
3
+
4
+ from config.config import (resource_groups, resource_order, resource_tooltips,
5
+ resource_unit_map)
6
+ from utils.data_utils import render_resource_input
7
+ from utils.ui_helpers import format_resource_summary
8
+
9
+
10
+ def render_tab():
11
+ # Safe session init
12
+ if "resource_caps" not in st.session_state:
13
+ st.session_state.resource_caps = {}
14
+ for r in resource_order:
15
+ if r not in st.session_state.resource_caps:
16
+ st.session_state.resource_caps[r] = 0.0
17
+
18
+ st.header("Resource inputs")
19
+
20
+ st.info("""
21
+ **Objective:**
22
+
23
+ This section lets you define the **total available quantities of each resource** for the optimization model.
24
+ """)
25
+
26
+ st.warning("⚠️ Resources with zero availability will block portfolio feasibility if required by active methods.")
27
+
28
+ # Reset button
29
+ st.markdown("### Controls")
30
+ col_reset, _ = st.columns([1, 5])
31
+ with col_reset:
32
+ if st.button("🔄 Reset All", type="secondary"):
33
+ for r in st.session_state.resource_caps:
34
+ st.session_state.resource_caps[r] = 0.0
35
+ st.success("All resource values reset to 0.")
36
+ st.rerun()
37
+
38
+ # Inputs by resource group
39
+ st.markdown("### Set available resources for one year")
40
+ for group, rlist in resource_groups.items():
41
+ unit = resource_unit_map.get(group, "")
42
+ with st.expander(f"**{group}** ({unit})", expanded=True):
43
+ cols = st.columns(4)
44
+ for i, r in enumerate(rlist):
45
+ tooltip = resource_tooltips.get(r, None)
46
+ name_clean = r.split(" (")[0]
47
+ with cols[i % 4]:
48
+ render_resource_input(name_clean, r, tooltip=tooltip)
49
+
50
+ # Summary table
51
+ st.markdown("### Summary of available resources")
52
+ df_caps = pd.DataFrame.from_dict({
53
+ r: st.session_state.resource_caps[r]
54
+ for r in resource_order if st.session_state.resource_caps.get(r, 0.0) > 0
55
+ }, orient="index", columns=["Available Amount"]).reindex(resource_order).dropna()
56
+
57
+ if not df_caps.empty:
58
+ df_caps.columns = ["Available Amount"]
59
+ styled = format_resource_summary(df_caps)
60
+ st.table(styled)
61
+ else:
62
+ st.error("No resources defined yet. Set availability above to populate the summary table.")
tabs/tab2_constraints.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # tabs/tab2_constraints.py
2
+
3
+ import pandas as pd
4
+ import streamlit as st
5
+
6
+ from config.config import method_groups, method_order, method_tooltips
7
+ from utils.ui_helpers import format_method_summary
8
+
9
+
10
+ def render_tab():
11
+ st.header("Method constraints")
12
+
13
+ st.info("""
14
+ **Objective:**
15
+
16
+ This section lets you control which CDR methods are included in the optimization
17
+ and assign their **maximum portfolio share**.
18
+
19
+ - Activate or deactivate individual methods
20
+ - Set each method's **max share** (as % of the total portfolio)
21
+ """)
22
+
23
+ # Initialize constraints state
24
+ if "constraints" not in st.session_state:
25
+ st.session_state.constraints = {}
26
+ for m in method_order:
27
+ if m not in st.session_state.constraints:
28
+ st.session_state.constraints[m] = {"active": True, "max_share": 1.0}
29
+
30
+ # UI controls
31
+ with st.expander("⚙️ Manage methods (Open/Close)", expanded=False):
32
+ st.subheader("Activate/deactivate methods and set max allocation")
33
+
34
+ for group, method_list in method_groups.items():
35
+ st.markdown(f"#### {group}")
36
+ cols = st.columns(3)
37
+
38
+ for i, m in enumerate(method_list):
39
+ with cols[i % 3]:
40
+ toggle_key = f"toggle_{m}"
41
+ slider_key = f"slider_{m}_widget"
42
+ tooltip = method_tooltips.get(m, None)
43
+
44
+ # Set default slider value only on first render
45
+ if slider_key not in st.session_state:
46
+ st.session_state[slider_key] = int(st.session_state.constraints[m]["max_share"] * 100)
47
+
48
+ # Toggle
49
+ is_active = st.toggle(
50
+ m,
51
+ value=st.session_state.constraints[m]["active"],
52
+ key=toggle_key,
53
+ help=tooltip
54
+ )
55
+
56
+ if is_active:
57
+ share_val = st.slider(
58
+ "Max share (%)",
59
+ min_value=0,
60
+ max_value=100,
61
+ step=5,
62
+ key=slider_key
63
+ )
64
+ st.session_state.constraints[m] = {
65
+ "active": True,
66
+ "max_share": share_val / 100
67
+ }
68
+
69
+ if share_val == 0:
70
+ st.warning("Max share is 0% but method is active", icon="⚠️")
71
+ else:
72
+ st.session_state.constraints[m] = {
73
+ "active": False,
74
+ "max_share": 0.0
75
+ }
76
+
77
+ # Reset all constraints
78
+ st.divider()
79
+ if st.button("🔄 Reset All Method Constraints"):
80
+ for m in method_order:
81
+ st.session_state.constraints[m] = {"active": True, "max_share": 1.0}
82
+ slider_key = f"slider_{m}_widget"
83
+ if slider_key in st.session_state:
84
+ del st.session_state[slider_key]
85
+ st.success("All method constraints reset to default.")
86
+ st.rerun()
87
+
88
+ # Summary table
89
+ st.subheader("Summary table: Active methods in the model")
90
+
91
+ active_methods_summary = {
92
+ m: int(st.session_state.constraints[m]["max_share"] * 100)
93
+ for m in method_order if st.session_state.constraints[m]["active"]
94
+ }
95
+
96
+ if active_methods_summary:
97
+ df_methods = pd.DataFrame.from_dict(
98
+ active_methods_summary, orient="index", columns=["Max allocation (%)"]
99
+ ).reindex(method_order).dropna()
100
+
101
+ styled = format_method_summary(df_methods)
102
+ st.table(styled)
103
+ else:
104
+ st.warning("No active methods selected.")
tabs/tab3_coefficients.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import streamlit as st
3
+
4
+ from config.config import (method_groups, method_order, resource_groups,
5
+ resource_order, secondary_resources)
6
+ from utils.ui_helpers import format_efficiency_summary
7
+
8
+
9
+ def render_tab(cost_sliders):
10
+ # Initialize costs
11
+ if "costs" not in st.session_state:
12
+ st.session_state.costs = {}
13
+ for m in cost_sliders:
14
+ if m not in st.session_state.costs:
15
+ st.session_state.costs[m] = {}
16
+ for r in cost_sliders[m]:
17
+ if r not in st.session_state.costs[m]:
18
+ st.session_state.costs[m][r] = cost_sliders[m][r]["median"]
19
+
20
+ st.header("Resource efficiency coefficients")
21
+
22
+ st.info("""
23
+ **Objective:**
24
+
25
+ This section lets you adjust the resource usage coefficients for each CDR method to best fit your country conditions.
26
+
27
+ - Select a method using the dropdown
28
+ - Adjust the resource usage coefficients (e.g., land, energy) using sliders
29
+ - Optionally override the slider using a manual input (even outside bounds)
30
+ - Disable secondary resources (e.g., water, chemicals) if needed
31
+ - Reset a single method or all methods with the reset buttons
32
+ - View a summary table of coefficients used in the model
33
+ """)
34
+ st.info("""
35
+ **Information:**
36
+
37
+ Data used in this section is based on
38
+ """)
39
+ st.warning("Blue cells in the table highlight coefficients modified from their **default median values**.")
40
+
41
+ # Combined dropdown for group + method
42
+ method_choices = []
43
+ method_lookup = {}
44
+ for group, methods in method_groups.items():
45
+ for method in methods:
46
+ label = f"{group} | {method}"
47
+ method_choices.append(label)
48
+ method_lookup[label] = method
49
+
50
+ selected_label = st.selectbox("Select a method:", method_choices)
51
+ method_selected = method_lookup[selected_label]
52
+
53
+ with st.expander(f"Manage resources for the {method_selected} method", expanded=True):
54
+ for group_name, rlist in resource_groups.items():
55
+ used = [r for r in rlist if r in cost_sliders[method_selected]]
56
+ if not used:
57
+ continue
58
+
59
+ st.markdown(f"### {group_name}")
60
+ for r in used:
61
+ conf = cost_sliders[method_selected][r]
62
+ default_val = conf["median"]
63
+ min_val = conf["min"]
64
+ max_val = conf["max"]
65
+ if min_val < 0.01:
66
+ step = 0.0001
67
+ fmt = "%.4f"
68
+ elif min_val < 1:
69
+ step = 0.001
70
+ fmt = "%.3f"
71
+ elif min_val < 100:
72
+ step = 0.01
73
+ fmt = "%.2f"
74
+ else:
75
+ step = 1.0
76
+ fmt = "%.0f"
77
+
78
+ slider_key = f"slider_{method_selected}_{r}".replace(" ", "_").lower()
79
+ manual_key = f"manual_{method_selected}_{r}".replace(" ", "_").lower()
80
+ toggle_key = f"toggle_{method_selected}_{r}".replace(" ", "_").lower()
81
+
82
+ is_secondary = (method_selected, r) in secondary_resources
83
+ if is_secondary and toggle_key not in st.session_state:
84
+ st.session_state[toggle_key] = False
85
+
86
+ enabled = True
87
+ if is_secondary:
88
+ enabled = st.checkbox(f"Use {r}", key=toggle_key)
89
+
90
+ if enabled:
91
+ col1, col2 = st.columns([3, 1])
92
+ with col1:
93
+ slider_val = st.slider(
94
+ label=r,
95
+ min_value=min_val,
96
+ max_value=max_val,
97
+ value=st.session_state.costs[method_selected].get(r, default_val),
98
+ step=step,
99
+ format=fmt,
100
+ key=slider_key
101
+ )
102
+ with col2:
103
+ manual_val = st.number_input(
104
+ label="",
105
+ value=slider_val,
106
+ key=manual_key,
107
+ help="Manual override (optional, any value)"
108
+ )
109
+
110
+ # Manual overrides slider if changed
111
+ final_val = manual_val if manual_val != slider_val else slider_val
112
+ st.session_state.costs[method_selected][r] = final_val
113
+ else:
114
+ st.session_state.costs[method_selected][r] = 0.0
115
+ st.markdown("**DISABLED**")
116
+
117
+ # Reset buttons
118
+ col1, col2 = st.columns(2)
119
+ with col1:
120
+ if st.button("🔄 Reset selected method"):
121
+ for r in cost_sliders[method_selected]:
122
+ default_val = cost_sliders[method_selected][r]["median"]
123
+ st.session_state.costs[method_selected][r] = default_val
124
+
125
+ # Clear UI state
126
+ for suffix in ["slider", "manual", "toggle"]:
127
+ key = f"{suffix}_{method_selected}_{r}".replace(" ", "_").lower()
128
+ if key in st.session_state:
129
+ del st.session_state[key]
130
+
131
+ st.success(f"{method_selected} reset to default values.")
132
+ st.rerun()
133
+
134
+ with col2:
135
+ if st.button("🔄 Reset all methods"):
136
+ for m in method_order:
137
+ for r in cost_sliders.get(m, {}):
138
+ default_val = cost_sliders[m][r]["median"]
139
+ st.session_state.costs[m][r] = default_val
140
+
141
+ for suffix in ["slider", "manual", "toggle"]:
142
+ key = f"{suffix}_{m}_{r}".replace(" ", "_").lower()
143
+ if key in st.session_state:
144
+ del st.session_state[key]
145
+
146
+ st.success("All methods reset to default values.")
147
+ st.rerun()
148
+
149
+ # Summary table
150
+ st.subheader("Summary table: resource usage coefficients in the model")
151
+
152
+ df_default = pd.DataFrame(index=method_order, columns=resource_order)
153
+ df_current = pd.DataFrame(index=method_order, columns=resource_order)
154
+
155
+ for m in method_order:
156
+ for r in resource_order:
157
+ df_default.at[m, r] = cost_sliders.get(m, {}).get(r, {}).get("median", 0.0)
158
+ df_current.at[m, r] = st.session_state.costs.get(m, {}).get(r, 0.0)
159
+
160
+ df_default = df_default.astype(float)
161
+ df_current = df_current.astype(float)
162
+
163
+ styled = format_efficiency_summary(df_current, df_default)
164
+ st.table(styled)
tabs/tab4_optimization.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ import pandas as pd
4
+ import plotly.express as px
5
+ import plotly.graph_objects as go
6
+ import streamlit as st
7
+
8
+ from config.config import method_order, resource_order, resource_units
9
+ from optimization.optimization import run_optimization
10
+ from utils.ui_helpers import format_results_summary
11
+
12
+
13
+ def render_tab():
14
+ st.header("Portfolio generation")
15
+ st.info("""
16
+ **Objective:**
17
+ Run the optimization tool, explore results, and save scenarios for comparison or export.
18
+ """)
19
+
20
+ # Input check - ensure all required inputs are available
21
+ if "constraints" not in st.session_state or "costs" not in st.session_state or "resource_caps" not in st.session_state:
22
+ st.error("Missing inputs. Please complete previous steps.")
23
+ return
24
+
25
+ if "scenarios" not in st.session_state:
26
+ st.session_state.scenarios = {}
27
+
28
+ if sum(st.session_state.resource_caps.values()) <= 0:
29
+ st.warning("⚠️ All resources are currently set to 0. Please increase availability.")
30
+ return
31
+
32
+ # Optimization
33
+ if st.button("Run Optimization"):
34
+ success, result = run_optimization(
35
+ resource_caps=st.session_state.resource_caps,
36
+ method_constraints=st.session_state.constraints,
37
+ method_costs=st.session_state.costs,
38
+ )
39
+
40
+ if success:
41
+ allocations = result["method_usage"]
42
+ total_removed = result["total_removed"]
43
+
44
+ if total_removed <= 0:
45
+ st.warning("❌ Optimization removed 0 tCO₂. Relax constraints or increase resources.")
46
+ return
47
+
48
+ total_cost = sum(
49
+ allocations[m] * sum(st.session_state.costs[m].values())
50
+ for m in allocations
51
+ )
52
+
53
+ st.session_state.latest_result = {
54
+ "summary": {
55
+ "total_co2_removed": total_removed,
56
+ "total_cost": total_cost
57
+ },
58
+ "allocations": allocations,
59
+ "resource_caps": st.session_state.resource_caps.copy(),
60
+ "method_constraints": st.session_state.constraints,
61
+ "method_costs": st.session_state.costs,
62
+ }
63
+
64
+ st.success(f"✅ Optimization successful: {total_removed:,.0f} tCO₂ removed")
65
+ else:
66
+ st.error("❌ Optimization failed")
67
+ if "message" in result:
68
+ st.error(result["message"])
69
+
70
+ # --- Display Section ---
71
+ if "latest_result" not in st.session_state:
72
+ return
73
+
74
+ latest = st.session_state.latest_result
75
+ allocations = latest["allocations"]
76
+ resource_caps = latest["resource_caps"]
77
+ method_costs = latest["method_costs"]
78
+
79
+ if not allocations or sum(allocations.values()) == 0:
80
+ return
81
+
82
+ # --- Metrics ---
83
+ col1, col2 = st.columns(2)
84
+ col1.metric("Total CO₂ Removed", f"{latest['summary']['total_co2_removed']:,.0f} t")
85
+ col2.metric("Methods Used", len(allocations))
86
+
87
+ # --- Summary Table ---
88
+ st.subheader("Optimization Summary")
89
+ df_result = pd.DataFrame.from_dict(allocations, orient="index", columns=["tCO₂ removed"])
90
+ df_result["tCO₂ removed"] = pd.to_numeric(df_result["tCO₂ removed"], errors="coerce")
91
+ total = df_result["tCO₂ removed"].sum()
92
+ if total > 0:
93
+ df_result["Share (%)"] = (df_result["tCO₂ removed"] / total * 100).round(2)
94
+ df_result = df_result.sort_values(by="tCO₂ removed", ascending=False)
95
+ st.table(format_results_summary(df_result))
96
+
97
+ # --- Donut Chart ---
98
+ st.markdown("### Method allocation breakdown")
99
+ fig_donut = px.pie(
100
+ df_result.reset_index(),
101
+ names="index",
102
+ values="tCO₂ removed",
103
+ hole=0.4,
104
+ labels={"index": "Method", "tCO₂ removed": "tCO₂ Removed"},
105
+ )
106
+ fig_donut.update_traces(
107
+ textinfo="label+percent",
108
+ textposition="outside",
109
+ pull=[0.02] * len(df_result),
110
+ marker=dict(line=dict(color="#000000", width=1)),
111
+ showlegend=False,
112
+ )
113
+ st.plotly_chart(fig_donut, use_container_width=True)
114
+
115
+ # --- Heatmap of Resource Use ---
116
+ st.markdown("### Resource usage heatmap (% of cap)")
117
+ heatmap_matrix, heatmap_y = [], []
118
+ available_resources = [r for r in resource_order if resource_caps.get(r, 0) > 0]
119
+
120
+ for method in df_result.index:
121
+ row = []
122
+ for r in available_resources:
123
+ usage = method_costs.get(method, {}).get(r, 0.0) * allocations.get(method, 0.0)
124
+ row.append((usage / resource_caps[r]) * 100 if resource_caps[r] > 0 else 0)
125
+ heatmap_matrix.append(row)
126
+ heatmap_y.append(method)
127
+
128
+ fig_heatmap = go.Figure(data=go.Heatmap(
129
+ z=heatmap_matrix,
130
+ x=available_resources,
131
+ y=heatmap_y,
132
+ colorscale="Blues",
133
+ hovertemplate="Method: %{y}<br>Resource: %{x}<br>% Used: %{z:.2f}%<extra></extra>",
134
+ ))
135
+ fig_heatmap.update_layout(
136
+ title="Resource Usage vs. Cap",
137
+ xaxis_title="Resource",
138
+ yaxis_title="Method",
139
+ height=400,
140
+ )
141
+ st.plotly_chart(fig_heatmap, use_container_width=True)
142
+
143
+ # --- Absolute Resource Use ---
144
+ st.markdown("### Absolute resource usage by unit")
145
+ df_abs = []
146
+ for m, co2_removed in allocations.items():
147
+ for unit, resources in resource_units.items():
148
+ for r in resources:
149
+ if r in method_costs.get(m, {}):
150
+ used = method_costs[m][r] * co2_removed
151
+ if used > 0:
152
+ df_abs.append({
153
+ "Method": m,
154
+ "Resource": r,
155
+ "Used": used,
156
+ "Unit": unit
157
+ })
158
+
159
+ if df_abs:
160
+ df_abs = pd.DataFrame(df_abs)
161
+ for unit in df_abs["Unit"].unique():
162
+ df_unit = df_abs[df_abs["Unit"] == unit]
163
+ st.markdown(f"#### Resources in {unit}")
164
+ fig = px.bar(
165
+ df_unit,
166
+ x="Resource",
167
+ y="Used",
168
+ color="Method",
169
+ barmode="group",
170
+ labels={"Used": f"Used ({unit})"},
171
+ )
172
+ fig.update_layout(
173
+ height=300 + 30 * df_unit["Resource"].nunique(),
174
+ margin=dict(t=30, b=30),
175
+ legend_title_text="",
176
+ )
177
+ st.plotly_chart(fig, use_container_width=True)
178
+
179
+ # --- Save Scenario ---
180
+ st.markdown("### Save scenario")
181
+ st.text_input("Scenario name", key="scenario_name")
182
+
183
+ if st.button("Save Scenario"):
184
+ name = st.session_state.get("scenario_name", "").strip()
185
+ if not name:
186
+ st.warning("Please enter a name before saving.")
187
+ elif name in st.session_state.scenarios:
188
+ st.warning("Scenario name already exists.")
189
+ else:
190
+ st.session_state.scenarios[name] = latest
191
+ st.success(f"Scenario '{name}' saved.")
192
+
193
+ # --- Preview Saved Scenario ---
194
+ current_name = st.session_state.get("scenario_name", "").strip()
195
+ if current_name and current_name in st.session_state.scenarios:
196
+ scenario = st.session_state.scenarios[current_name]
197
+ st.markdown(f"#### Scenario: {current_name}")
198
+ df_saved = pd.DataFrame.from_dict(
199
+ scenario["allocations"], orient="index", columns=["tCO₂ removed"]
200
+ )
201
+ df_saved["tCO₂ removed"] = pd.to_numeric(df_saved["tCO₂ removed"], errors="coerce")
202
+ total = df_saved["tCO₂ removed"].sum()
203
+ if total > 0:
204
+ df_saved["Share (%)"] = (df_saved["tCO₂ removed"] / total * 100).round(2)
205
+ df_saved = df_saved.sort_values(by="tCO₂ removed", ascending=False)
206
+ st.table(format_results_summary(df_saved))
tabs/tab5_sensitivity.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import plotly.express as px
3
+ import streamlit as st
4
+
5
+ from config.config import method_order, resource_order
6
+ from optimization.optimization import run_optimization
7
+
8
+
9
+ def render_tab():
10
+ st.header("Sensitivity Analysis")
11
+ st.info("""
12
+ **Objective**:
13
+
14
+ - Explore how varying **one or multiple resources' availability** or **methods' maximum allocation** affects total CO₂ removed.
15
+ """)
16
+
17
+ if "resource_caps" not in st.session_state or "constraints" not in st.session_state or "costs" not in st.session_state:
18
+ st.warning("Please complete the setup in previous tabs before running sensitivity analysis.")
19
+ return
20
+
21
+ # Compute baseline once
22
+ baseline_success, baseline_result = run_optimization(
23
+ resource_caps=st.session_state.resource_caps,
24
+ method_constraints=st.session_state.constraints,
25
+ method_costs=st.session_state.costs,
26
+ )
27
+ baseline_removed = baseline_result["total_removed"] if baseline_success else 0
28
+
29
+ tab1, tab2 = st.tabs(["🔁 Resource Sensitivity", "🔁 Method Sensitivity"])
30
+
31
+ with tab1:
32
+ st.subheader("Impact of resource availability")
33
+ selected_resources = st.multiselect("Select one or more resources:", resource_order)
34
+
35
+ if not selected_resources:
36
+ st.warning("Please select at least one resource to run the sensitivity analysis.")
37
+ else:
38
+ percentages = list(range(0, 210, 10))
39
+ all_data = []
40
+
41
+ for resource in selected_resources:
42
+ for pct in percentages:
43
+ temp_caps = st.session_state.resource_caps.copy()
44
+ base_cap = st.session_state.resource_caps.get(resource, 1)
45
+ temp_caps[resource] = base_cap * pct / 100
46
+
47
+ success, result = run_optimization(
48
+ resource_caps=temp_caps,
49
+ method_constraints=st.session_state.constraints,
50
+ method_costs=st.session_state.costs,
51
+ )
52
+
53
+ co2_removed = result["total_removed"] if success else 0
54
+ all_data.append({
55
+ "Input": resource,
56
+ "% of cap": pct,
57
+ "CO₂ removed (t)": co2_removed
58
+ })
59
+
60
+ df = pd.DataFrame(all_data)
61
+ fig = px.line(df, x="% of cap", y="CO₂ removed (t)", color="Input",
62
+ title="Sensitivity to Resource Availability")
63
+
64
+ fig.add_hline(y=baseline_removed, line_dash="dash", line_color="gray",
65
+ annotation_text=f"Baseline: {baseline_removed:,} tCO₂",
66
+ annotation_position="top left")
67
+
68
+ st.plotly_chart(fig, use_container_width=True)
69
+
70
+ with tab2:
71
+ st.subheader("Impact of max allocation per method")
72
+ selected_methods = st.multiselect("Select one or more methods:", method_order)
73
+
74
+ if not selected_methods:
75
+ st.warning("Please select at least one method to run the sensitivity analysis.")
76
+ else:
77
+ percentages = list(range(0, 110, 10))
78
+ all_data = []
79
+
80
+ for method in selected_methods:
81
+ for pct in percentages:
82
+ temp_constraints = st.session_state.constraints.copy()
83
+ temp_constraints[method] = temp_constraints.get(method, {}).copy()
84
+ temp_constraints[method]["max_share"] = pct / 100
85
+
86
+ success, result = run_optimization(
87
+ resource_caps=st.session_state.resource_caps,
88
+ method_constraints=temp_constraints,
89
+ method_costs=st.session_state.costs,
90
+ )
91
+
92
+ co2_removed = result["total_removed"] if success else 0
93
+ all_data.append({
94
+ "Input": method,
95
+ "% max allocation": pct,
96
+ "CO₂ removed (t)": co2_removed
97
+ })
98
+
99
+ df = pd.DataFrame(all_data)
100
+ fig = px.line(df, x="% max allocation", y="CO₂ removed (t)", color="Input",
101
+ title="Sensitivity to Method Max Allocation")
102
+
103
+ fig.add_hline(y=baseline_removed, line_dash="dash", line_color="gray",
104
+ annotation_text=f"Baseline: {baseline_removed:,} tCO₂",
105
+ annotation_position="top left")
106
+
107
+ st.plotly_chart(fig, use_container_width=True)
tabs/tab6_scenarios.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ import pandas as pd
4
+ import plotly.express as px
5
+ import streamlit as st
6
+
7
+
8
+ def is_valid_scenario(scenario):
9
+ return (
10
+ isinstance(scenario, dict)
11
+ and "allocations" in scenario
12
+ and "resource_caps" in scenario
13
+ and "method_costs" in scenario
14
+ and "method_constraints" in scenario
15
+ and "summary" in scenario
16
+ )
17
+
18
+ def render_tab():
19
+ st.header("Scenario Comparison")
20
+
21
+ if "scenarios" not in st.session_state:
22
+ st.session_state.scenarios = {}
23
+
24
+ if not st.session_state.scenarios:
25
+ st.info("No scenarios have been saved yet.")
26
+ return
27
+
28
+ # Select scenarios from current workspace
29
+ st.markdown("### Select Scenarios to Compare")
30
+ scenario_names = list(st.session_state.scenarios.keys())
31
+ selected = st.multiselect("Select scenarios", scenario_names, default=scenario_names)
32
+
33
+ if not selected:
34
+ st.warning("Please select at least one scenario to display the comparison.")
35
+ return
36
+
37
+ # Remove buttons
38
+ for name in selected:
39
+ col1, col2 = st.columns([10, 1])
40
+ with col1:
41
+ st.markdown(f"**{name}**")
42
+ with col2:
43
+ if st.button("❌", key=f"remove_{name}"):
44
+ st.session_state.scenarios.pop(name, None)
45
+ st.rerun()
46
+
47
+ # Prepare data
48
+ all_methods, all_resources = set(), set()
49
+ for name in selected:
50
+ scenario = st.session_state.scenarios[name]
51
+ all_methods.update(scenario.get("allocations", {}).keys())
52
+ all_resources.update(scenario.get("resource_caps", {}).keys())
53
+ all_methods, all_resources = sorted(all_methods), sorted(all_resources)
54
+
55
+ summary_rows, method_alloc_df, resource_usage_df = [], [], []
56
+ for name in selected:
57
+ data = st.session_state.scenarios[name]
58
+ allocations = data.get("allocations", {})
59
+ resource_caps = data.get("resource_caps", {})
60
+ constraints = data.get("method_constraints", {})
61
+
62
+ row = {
63
+ "Scenario": name,
64
+ "CO₂ Removed (t)": data.get("summary", {}).get("total_co2_removed", 0),
65
+ }
66
+
67
+ for method in all_methods:
68
+ val = allocations.get(method, 0)
69
+ row[f"{method} (tCO₂)"] = val
70
+ method_alloc_df.append({"Scenario": name, "Method": method, "tCO₂": val})
71
+
72
+ for resource in all_resources:
73
+ total_used = 0
74
+ for method, tco2 in allocations.items():
75
+ coeffs = constraints.get(method, {}).get("resources", {})
76
+ if not isinstance(coeffs, dict):
77
+ continue
78
+ unit_use = coeffs.get(resource, 0)
79
+ used = unit_use * tco2
80
+ total_used += used
81
+ if used > 0:
82
+ resource_usage_df.append({"Scenario": name, "Method": method, "Resource": resource, "Used": used})
83
+ row[f"{resource} used"] = total_used
84
+
85
+ summary_rows.append(row)
86
+
87
+ # Comparison table
88
+ df_summary = pd.DataFrame(summary_rows)
89
+ st.subheader("Summary Table")
90
+ st.dataframe(df_summary.style.format(na_rep="-", thousands=","), use_container_width=True)
91
+ st.download_button("Download Comparison CSV", df_summary.to_csv(index=False).encode("utf-8"), "scenario_comparison.csv", "text/csv")
92
+
93
+ # Charts
94
+ if method_alloc_df:
95
+ st.subheader("Method Allocations")
96
+ fig1 = px.bar(pd.DataFrame(method_alloc_df), x="Method", y="tCO₂", color="Scenario", barmode="group")
97
+ st.plotly_chart(fig1, use_container_width=True)
98
+
99
+ if resource_usage_df:
100
+ st.subheader("Resource Use per Method")
101
+ fig2 = px.bar(pd.DataFrame(resource_usage_df), x="Resource", y="Used", color="Scenario", facet_col="Method", facet_col_wrap=3)
102
+ st.plotly_chart(fig2, use_container_width=True)
103
+
104
+ st.subheader("Total Resource Use per Scenario")
105
+ df_total = pd.DataFrame(resource_usage_df).groupby(["Scenario", "Resource"]).sum(numeric_only=True).reset_index()
106
+ fig3 = px.bar(df_total, x="Scenario", y="Used", color="Resource", barmode="stack")
107
+ st.plotly_chart(fig3, use_container_width=True)
utils/__init__.py ADDED
File without changes
utils/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (197 Bytes). View file
 
utils/__pycache__/data_utils.cpython-311.pyc ADDED
Binary file (1.7 kB). View file
 
utils/__pycache__/ui_helpers.cpython-311.pyc ADDED
Binary file (11 kB). View file
 
utils/data_utils.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ import streamlit as st
4
+
5
+
6
+ @st.cache_data
7
+ def load_slider_data():
8
+ """Load slider data from a JSON file and cache it for performance."""
9
+ with open("data/cost_sliders.json") as f:
10
+ return json.load(f)
11
+
12
+ def render_resource_input(name_clean, r, tooltip=None):
13
+ if tooltip:
14
+ st.markdown(
15
+ f"""<span title="{tooltip}" style="font-weight: 500;">{name_clean} <sup style="color:#999;">ℹ️</sup></span>""",
16
+ unsafe_allow_html=True
17
+ )
18
+ else:
19
+ st.markdown(f"**{name_clean}**")
20
+
21
+ cap = st.number_input(
22
+ label="", # Label shown above
23
+ min_value=0.0,
24
+ value=float(st.session_state.resource_caps.get(r, 0.0)),
25
+ format="%.2f",
26
+ key=f"cap_{r}"
27
+ )
28
+ st.session_state.resource_caps[r] = cap
utils/ui_helpers.py ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pandas as pd
3
+ import streamlit as st
4
+
5
+ # params
6
+ background_color = "#3d86e9"
7
+
8
+ def styled_table(df):
9
+ return (
10
+ df.style
11
+ .set_table_styles([{"selector": "th", "props": [("background-color", background_color), ("font-weight", "bold")]}])
12
+ )
13
+
14
+ def highlight_differences(data, df_default):
15
+ styled = pd.DataFrame('', index=data.index, columns=data.columns)
16
+ for m in data.index:
17
+ for r in data.columns:
18
+ if m in df_default.index and r in df_default.columns:
19
+ current = data.at[m, r]
20
+ default = df_default.at[m, r]
21
+ if abs(current - default) > 1e-6:
22
+ styled.at[m, r] = 'background-color: #cce5ff'
23
+ return styled
24
+
25
+ def smart_format(val):
26
+ return f"{val:.2e}" if abs(val) < 0.01 else f"{val:.2f}"
27
+
28
+ def inputs_table_style(df):
29
+ return(
30
+ df.style
31
+ .set_properties(**{'text-align': 'right'})
32
+ .format(smart_format)
33
+ .set_table_styles([{"selector": "th", "props": [("background-color", background_color), ("font-weight", "bold")]}])
34
+ )
35
+
36
+ def format_method_summary(df: pd.DataFrame):
37
+ df = df.copy()
38
+ df.index.name = "CDR Method"
39
+ df.reset_index(inplace=True)
40
+
41
+ return (
42
+ df.style
43
+ .set_table_styles([
44
+ {"selector": "thead th", "props": [("background-color", background_color), ("color", "white"), ("font-weight", "bold")]},
45
+ {"selector": "td.col0", "props": [("text-align", "left"), ("font-weight", "bold")]},
46
+ {"selector": "td.col1", "props": [("text-align", "center")]}
47
+ ])
48
+ )
49
+
50
+ def format_results_summary(df: pd.DataFrame):
51
+ df = df.copy()
52
+ df.index.name = "CDR Method"
53
+ df.reset_index(inplace=True)
54
+
55
+ return (
56
+ df.style
57
+ .format({
58
+ "tCO₂ removed": "{:,.0f}",
59
+ "Share (%)": "{:.2f}"
60
+ })
61
+ .set_table_styles([
62
+ {"selector": "thead th", "props": [("background-color", background_color), ("color", "white"), ("font-weight", "bold")]},
63
+ {"selector": "td.col0", "props": [("text-align", "left"), ("font-weight", "bold")]},
64
+ {"selector": "td.col1", "props": [("text-align", "center")]}
65
+ ])
66
+ )
67
+
68
+ def format_efficiency_summary(df: pd.DataFrame, df_default: pd.DataFrame):
69
+ df_numeric = df.copy()
70
+ df_numeric.index.name = "Method"
71
+
72
+ df_display = df_numeric.applymap(smart_display_format)
73
+
74
+ # Highlight modified values
75
+ def highlight_changes(data):
76
+ styled = pd.DataFrame('', index=data.index, columns=data.columns)
77
+ for m in data.index:
78
+ for r in data.columns:
79
+ try:
80
+ current = df_numeric.at[m, r]
81
+ default = df_default.at[m, r]
82
+ if abs(current - default) > 1e-6:
83
+ styled.at[m, r] = 'background-color: #cce5ff'
84
+ except:
85
+ continue
86
+ return styled
87
+
88
+ # Table style
89
+ num_columns = df.shape[1]
90
+ styles = [
91
+ {"selector": "thead th", "props": [("background-color", background_color), ("color", "white"), ("font-weight", "bold")]},
92
+ {"selector": "th.row_heading", "props": [("text-align", "left"), ("font-weight", "bold"), ("width", "240px")]}
93
+ ]
94
+ for i in range(num_columns):
95
+ styles.append({
96
+ "selector": f"td.col{i}",
97
+ "props": [("text-align", "center"), ("width", "160px")]
98
+ })
99
+
100
+ return df_display.style.apply(highlight_changes, axis=None).set_table_styles(styles)
101
+
102
+ # -----------------------------
103
+ # SLIDER GROUP HELPER
104
+ # -----------------------------
105
+ def render_slider_group(method_name, resource, slider_data, key_prefix="", enable_toggle=False, toggle_default=True, store_path=None):
106
+ """
107
+ Renders a slider for a method/resource pair with optional enable toggle.
108
+ Reads from and writes to st.session_state using store_path: ("costs", method, resource).
109
+ Avoids value reset issues by separating widget key from storage.
110
+ """
111
+ base_key = f"{key_prefix}{method_name}_{resource}".replace(" ", "_").lower()
112
+ toggle_key = f"{base_key}_toggle"
113
+ widget_key = f"{base_key}_slider"
114
+
115
+ # Validate data availability
116
+ if method_name not in slider_data or resource not in slider_data[method_name]:
117
+ return None
118
+
119
+ values = slider_data[method_name][resource]
120
+ min_val = values.get("min", 0.0)
121
+ med_val = values.get("median", 0.5)
122
+ max_val = values.get("max", 1.0)
123
+
124
+ # Handle toggle for secondary resources
125
+ enabled = True
126
+ if enable_toggle:
127
+ if toggle_key not in st.session_state:
128
+ st.session_state[toggle_key] = toggle_default
129
+ enabled = st.checkbox(f"Use {resource}", key=toggle_key)
130
+
131
+ if not enabled:
132
+ return None
133
+
134
+ # Determine slider format and step size
135
+ step = 0.01 if max_val < 100 else 1.0
136
+ fmt = "%.2f" if max_val < 100 else "%.0f"
137
+
138
+ # Ensure session state value exists
139
+ if store_path:
140
+ base, m, r = store_path
141
+ if base not in st.session_state:
142
+ st.session_state[base] = {}
143
+ if m not in st.session_state[base]:
144
+ st.session_state[base][m] = {}
145
+ if r not in st.session_state[base][m]:
146
+ st.session_state[base][m][r] = med_val
147
+
148
+ current_val = st.session_state[base][m][r]
149
+ else:
150
+ if base_key not in st.session_state:
151
+ st.session_state[base_key] = med_val
152
+ current_val = st.session_state[base_key]
153
+
154
+ # Render slider with separate widget key
155
+ val = st.slider(
156
+ label=f"{method_name} – {resource}",
157
+ min_value=float(min_val),
158
+ max_value=float(max_val),
159
+ value=float(current_val),
160
+ step=step,
161
+ format=fmt,
162
+ key=widget_key
163
+ )
164
+
165
+ # Sync slider output to session state
166
+ if store_path:
167
+ st.session_state[base][m][r] = val
168
+ else:
169
+ st.session_state[base_key] = val
170
+
171
+ return val
172
+
173
+ # -----------------------------
174
+ # TABLE FORMATTING HELPER
175
+ # -----------------------------
176
+ def format_results_table(df, highlight_changes=False, precision=2):
177
+ """
178
+ Applies consistent styling to result tables.
179
+ """
180
+ def bold_methods(val):
181
+ return f"font-weight: bold" if isinstance(val, str) else ""
182
+
183
+ styled = df.style.format(
184
+ {col: f"{{:.{precision}f}}" for col in df.select_dtypes(include=[np.number]).columns}
185
+ ).applymap(bold_methods, subset=[df.columns[0]])
186
+
187
+ if highlight_changes:
188
+ styled = styled.highlight_max(axis=0, color='lightgreen')
189
+
190
+ return styled
191
+
192
+ def format_resource_summary(df: pd.DataFrame):
193
+ """
194
+ Format a resource availability summary table with styling and column width control.
195
+ """
196
+ df = df.copy()
197
+ col = df.columns[0]
198
+ df[col] = df[col].map(lambda x: f"{x:,.2f}")
199
+ df.index.name = "Resource" # label the index for clarity
200
+
201
+ return (
202
+ df.style
203
+ .set_table_styles([
204
+ {
205
+ "selector": "thead th:nth-child(1)", # First column header (after index)
206
+ "props": [
207
+ ("background-color", background_color),
208
+ ("color", "white"),
209
+ ("font-weight", "bold")
210
+ ]
211
+ },
212
+ {
213
+ "selector": "thead th:nth-child(2)", # Second column header
214
+ "props": [
215
+ ("background-color", background_color),
216
+ ("color", "white"),
217
+ ("font-weight", "bold")
218
+ ]
219
+ }
220
+ ])
221
+ )
222
+
223
+ def smart_display_format(val):
224
+ if abs(val) < 1e-8:
225
+ return ""
226
+ elif abs(val) < 0.001:
227
+ return f"{val:,.5f}"
228
+ elif abs(val) < 0.01:
229
+ return f"{val:,.4f}"
230
+ elif abs(val) < 1:
231
+ return f"{val:,.3f}"
232
+ elif abs(val) < 100:
233
+ return f"{val:,.2f}"
234
+ else:
235
+ return f"{val:,.0f}"
236
+
237
+ # -----------------------------
238
+ # CHART LABEL CLEANER (Optional)
239
+ # -----------------------------
240
+ def clean_labels(labels):
241
+ """
242
+ Cleans labels to remove zero-allocation items or clutter.
243
+ """
244
+ return [label for label in labels if label and label.strip() != ""]