from __future__ import annotations from .models import CatOptConstraint, CatOptProblem, CatOptVariable, LocalProblem, PlanDelta, RegionalConstraint class AgriMeshCanonicalMapper: def to_catopt(self, local_problem: LocalProblem, regional_constraint: RegionalConstraint) -> CatOptProblem: need = max(local_problem.target_soil_moisture_pct - local_problem.current_soil_moisture_pct, 0.0) return CatOptProblem( problem_id=f"{local_problem.farm_id}:{regional_constraint.regional_water_quota_id}", variables=[ CatOptVariable( name="irrigation_liters", lower=0.0, upper=local_problem.irrigation_budget_liters, target=min(local_problem.irrigation_budget_liters, need * local_problem.plot_area_hectares * 10.0), ) ], constraints=[ CatOptConstraint( name="water_quota", expression=f"irrigation_liters <= {regional_constraint.water_quota_liters}", ), CatOptConstraint( name="energy_cap", expression=f"energy_kwh <= {regional_constraint.energy_cap_kwh}", ), ], objective="minimize squared deviation from target soil moisture", metadata={ "farm_id": local_problem.farm_id, "drought_target_moisture_pct": regional_constraint.drought_target_moisture_pct, "plot_area_hectares": local_problem.plot_area_hectares, }, ) def from_plan_delta(self, delta: PlanDelta) -> dict[str, float | str]: return { "farm_id": delta.farm_id, "irrigation_liters": delta.irrigation_liters, "fertilizer_kg": delta.fertilizer_kg, "energy_kwh": delta.energy_kwh, "tag": delta.tag, }