CarlyneB commited on
Commit
e4b0fe7
·
1 Parent(s): 43b4d0f

[FIX] Tab4: Deactivate methods with missing resources and fix batch coefficient injection for non-Other methods

Browse files
Files changed (2) hide show
  1. tabs/tab4_optimization.py +45 -0
  2. utils/data_utils.py +1 -1
tabs/tab4_optimization.py CHANGED
@@ -425,6 +425,26 @@ def run_and_store_result():
425
  if m in applied_costs
426
  }
427
  safe_constraints = neutralize_zero_coefficient_methods(applied_costs, standard_constraints)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
428
  neutralized = [
429
  m for m in safe_constraints
430
  if safe_constraints[m].get("active") is False
@@ -480,6 +500,31 @@ def run_and_store_result():
480
  # Display functions keep the full list so group/unit info is available.
481
  custom_resources_for_display = list(custom_resources)
482
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
483
  success, result = run_optimization(
484
  resource_caps=resource_caps_for_lp,
485
  method_constraints=safe_constraints,
 
425
  if m in applied_costs
426
  }
427
  safe_constraints = neutralize_zero_coefficient_methods(applied_costs, standard_constraints)
428
+
429
+ # Deactivate any method that requires a resource not provided in tab1.
430
+ # Hidden resources (e.g. "Other water") are never in resource_caps because
431
+ # they are not shown in tab1. Without this check, methods that consume such
432
+ # resources go unconstrained in the LP and produce misleading results.
433
+ # A resource is "missing" when it is absent from resource_caps (not set by
434
+ # the user) AND has no custom batch covering it.
435
+ custom_batch_names_pre = {b["name"] for b in custom_resources}
436
+ available_resources = set(st.session_state.resource_caps) | custom_batch_names_pre
437
+ for m, costs in applied_costs.items():
438
+ if not safe_constraints.get(m, {}).get("active", True):
439
+ continue
440
+ missing = [
441
+ r for r, c in costs.items()
442
+ if c > 0 and r not in available_resources
443
+ ]
444
+ if missing:
445
+ safe_constraints.setdefault(m, {"active": True, "cap_type": "percent", "cap_value": 100})
446
+ safe_constraints[m] = {**safe_constraints[m], "active": False}
447
+
448
  neutralized = [
449
  m for m in safe_constraints
450
  if safe_constraints[m].get("active") is False
 
500
  # Display functions keep the full list so group/unit info is available.
501
  custom_resources_for_display = list(custom_resources)
502
 
503
+ # Non-"Other" methods that shared an expanded batch (e.g. "Mineral OAE" also
504
+ # used "Limestone") lost their z-variable when the batch was removed from
505
+ # custom_resources_for_lp. Inject the batch as a standard resource coefficient
506
+ # into their applied_costs so the type-A constraint still applies to them.
507
+ #
508
+ # Also zero out the standard group resource coefficient when the standard pool
509
+ # is empty (cap = 0). In the z-variable path the B-constraint allows
510
+ # "y_m - z_{m,n} ≤ 0", letting the batch fully cover the method. In the
511
+ # standard-resource path that substitute mechanism is gone, so a method with
512
+ # cost(group) > 0 and cap(group) = 0 would be incorrectly forced to y = 0
513
+ # by the type-A constraint before it can use the batch at all.
514
+ for batch in custom_resources:
515
+ if batch["name"] not in expanded_batch_names:
516
+ continue
517
+ batch_group = batch.get("group", "")
518
+ group_cap_is_zero = resource_caps_for_lp.get(batch_group, 0.0) == 0.0
519
+ for method_name, coeff_dict in batch.get("methods", {}).items():
520
+ if method_name not in applied_costs:
521
+ continue # "Other" method was already replaced by variants above
522
+ applied_costs[method_name][batch["name"]] = coeff_dict.get("median", 0.0)
523
+ # If the standard pool for this group is empty, zero its coefficient so
524
+ # the type-A constraint doesn't force the method's output to zero.
525
+ if group_cap_is_zero and batch_group in applied_costs[method_name]:
526
+ applied_costs[method_name][batch_group] = 0.0
527
+
528
  success, result = run_optimization(
529
  resource_caps=resource_caps_for_lp,
530
  method_constraints=safe_constraints,
utils/data_utils.py CHANGED
@@ -260,5 +260,5 @@ def get_other_method_variants(method_name: str, custom_resources: list) -> list:
260
 
261
 
262
  def make_variant_name(method_name: str, batch_name: str) -> str:
263
- """Build the display/LP name for a method variant: '<Method> - <Batch>'."""
264
  return f"{method_name}: {batch_name}"
 
260
 
261
 
262
  def make_variant_name(method_name: str, batch_name: str) -> str:
263
+ """Build the display/LP name for a method variant: '<Method>: <Batch>'."""
264
  return f"{method_name}: {batch_name}"