CarlyneB commited on
Commit
36d3ed3
·
1 Parent(s): 8006bee

[FIX] tab5: exclude zero-cap resources and inactive methods from sensitivity selectors, remove redundant session state guards

Browse files
Files changed (1) hide show
  1. tabs/tab5_sensitivity.py +44 -27
tabs/tab5_sensitivity.py CHANGED
@@ -27,8 +27,18 @@ def compute_baseline():
27
  )
28
  baseline_removed = baseline_result["total_removed"] if baseline_success else 0
29
 
30
- custom_resource_names = [b["name"] for b in st.session_state.get("custom_resources", [])]
31
- all_resources = [r for r in resource_order if r not in hidden_resource_names] + custom_resource_names
 
 
 
 
 
 
 
 
 
 
32
 
33
  resource_to_unit = get_resource_to_unit()
34
  for b in st.session_state.get("custom_resources", []):
@@ -121,7 +131,8 @@ def panel_method_sensitivity(baseline_removed):
121
 
122
  Sweeps each selected method's cap from 0 % to 100 % of its current value
123
  in 10 % steps, re-solves the LP at each point, and plots total CO₂ removed.
124
- Skips methods whose current cap is 0.
 
125
 
126
  Args:
127
  baseline_removed (float): total CO₂ removed at current inputs.
@@ -138,14 +149,38 @@ def panel_method_sensitivity(baseline_removed):
138
  # independent variants (e.g. "Enhanced weathering - Other mineral: Ganite")
139
  # by run_expanded_optimization — offer those variants as selectable
140
  # entries too, alongside the standard method names, so their own cap can
141
- # be swept just like any other method.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  custom_resources = st.session_state.get("custom_resources", [])
143
  method_options = []
144
  for m in method_order:
145
  variants = get_other_method_variants(m, custom_resources)
146
  if variants:
147
- method_options.extend(make_variant_name(m, b["name"]) for b in variants)
148
- else:
 
 
 
149
  method_options.append(m)
150
 
151
  selected_methods = st.multiselect(
@@ -158,18 +193,11 @@ def panel_method_sensitivity(baseline_removed):
158
 
159
  percentages = list(range(0, 110, 10))
160
  all_data = []
161
- skipped = []
162
 
163
  for method in selected_methods:
164
  constraint = st.session_state.constraints.get(method) or default_constraint()
165
  cap_type = constraint.get("cap_type", "percent")
166
- current_cap = constraint.get(
167
- "cap_value", 100 if cap_type == "percent" else 0.0
168
- )
169
-
170
- if current_cap <= 0:
171
- skipped.append(method)
172
- continue
173
 
174
  for pct in percentages:
175
  perturbed_constraints = copy.deepcopy(st.session_state.constraints)
@@ -198,9 +226,6 @@ def panel_method_sensitivity(baseline_removed):
198
  f"CO₂ removed ({CO2_UNIT})": result["total_removed"] if success else 0,
199
  })
200
 
201
- for m in skipped:
202
- st.warning(f"Method **{m}** has a cap of 0 — set a value first to include it.", icon=":material/warning:")
203
-
204
  if not all_data:
205
  return
206
 
@@ -229,8 +254,8 @@ def render_tab():
229
 
230
  Computes a baseline optimisation from session state, then lets the user
231
  sweep one or more resources (or method caps) over a range and plots how
232
- total CO₂ removed changes. Requires resource_caps, constraints, and costs
233
- to be present in session state.
234
 
235
  Returns:
236
  None
@@ -247,14 +272,6 @@ def render_tab():
247
  unsafe_allow_html=True,
248
  )
249
 
250
- if (
251
- "resource_caps" not in st.session_state
252
- or "constraints" not in st.session_state
253
- or "costs" not in st.session_state
254
- ):
255
- st.warning("Please complete the setup in previous tabs before running sensitivity analysis.", icon=":material/warning:")
256
- return
257
-
258
  baseline_removed, all_resources, resource_to_unit = compute_baseline()
259
 
260
  tab1, tab2 = st.tabs(["🔁 Resource sensitivity", "🔁 Method sensitivity"])
 
27
  )
28
  baseline_removed = baseline_result["total_removed"] if baseline_success else 0
29
 
30
+ # Only offer resources that actually have a quantity set — sweeping a
31
+ # resource currently at 0 always gives 0 regardless of the % slider
32
+ # (any percentage of a 0 base cap is still 0), so it's never useful to
33
+ # compare.
34
+ custom_resource_names = [
35
+ b["name"] for b in st.session_state.get("custom_resources", [])
36
+ if float(b.get("amount", 0)) > 0
37
+ ]
38
+ all_resources = [
39
+ r for r in resource_order
40
+ if r not in hidden_resource_names and st.session_state.resource_caps.get(r, 0) > 0
41
+ ] + custom_resource_names
42
 
43
  resource_to_unit = get_resource_to_unit()
44
  for b in st.session_state.get("custom_resources", []):
 
131
 
132
  Sweeps each selected method's cap from 0 % to 100 % of its current value
133
  in 10 % steps, re-solves the LP at each point, and plots total CO₂ removed.
134
+ Methods whose current cap is already 0 are excluded from the selector
135
+ entirely (sweeping "X% of 0" is always 0, never useful to compare).
136
 
137
  Args:
138
  baseline_removed (float): total CO₂ removed at current inputs.
 
149
  # independent variants (e.g. "Enhanced weathering - Other mineral: Ganite")
150
  # by run_expanded_optimization — offer those variants as selectable
151
  # entries too, alongside the standard method names, so their own cap can
152
+ # be swept just like any other method. An "Other"-tagged method with NO
153
+ # batch attached has no variant AND can never produce any result on its
154
+ # own (its only resource is the hidden "Other X" pool, which is never
155
+ # directly settable) — skip it entirely rather than offer a sweep that
156
+ # would always show a flat 0 line.
157
+ #
158
+ # Same reasoning as the resource panel: a method whose current cap is
159
+ # already 0 would sweep to "X% of 0", always 0 regardless of the slider —
160
+ # never useful to compare — so it's excluded from the list up front
161
+ # instead of being selectable and only warned about afterwards. Same for
162
+ # a method that is simply inactive (missing resources, manually toggled
163
+ # off in Tab 2...): sweeping its cap_value doesn't touch "active", so the
164
+ # perturbed run stays forced to 0 regardless — just as pointless to offer.
165
+ def _current_cap(method_name):
166
+ constraint = st.session_state.constraints.get(method_name) or default_constraint()
167
+ cap_type = constraint.get("cap_type", "percent")
168
+ return constraint.get("cap_value", 100 if cap_type == "percent" else 0.0)
169
+
170
+ def _is_sweepable(method_name):
171
+ constraint = st.session_state.constraints.get(method_name) or default_constraint()
172
+ return constraint.get("active", True) and _current_cap(method_name) > 0
173
+
174
  custom_resources = st.session_state.get("custom_resources", [])
175
  method_options = []
176
  for m in method_order:
177
  variants = get_other_method_variants(m, custom_resources)
178
  if variants:
179
+ method_options.extend(
180
+ make_variant_name(m, b["name"]) for b in variants
181
+ if _is_sweepable(make_variant_name(m, b["name"]))
182
+ )
183
+ elif not is_other_method(m) and _is_sweepable(m):
184
  method_options.append(m)
185
 
186
  selected_methods = st.multiselect(
 
193
 
194
  percentages = list(range(0, 110, 10))
195
  all_data = []
 
196
 
197
  for method in selected_methods:
198
  constraint = st.session_state.constraints.get(method) or default_constraint()
199
  cap_type = constraint.get("cap_type", "percent")
200
+ current_cap = _current_cap(method)
 
 
 
 
 
 
201
 
202
  for pct in percentages:
203
  perturbed_constraints = copy.deepcopy(st.session_state.constraints)
 
226
  f"CO₂ removed ({CO2_UNIT})": result["total_removed"] if success else 0,
227
  })
228
 
 
 
 
229
  if not all_data:
230
  return
231
 
 
254
 
255
  Computes a baseline optimisation from session state, then lets the user
256
  sweep one or more resources (or method caps) over a range and plots how
257
+ total CO₂ removed changes. resource_caps, constraints, and costs are
258
+ guaranteed present by app.py's shared init, which runs before any tab.
259
 
260
  Returns:
261
  None
 
272
  unsafe_allow_html=True,
273
  )
274
 
 
 
 
 
 
 
 
 
275
  baseline_removed, all_resources, resource_to_unit = compute_baseline()
276
 
277
  tab1, tab2 = st.tabs(["🔁 Resource sensitivity", "🔁 Method sensitivity"])