"""Динамические нормы по уравнениям GfE (Германия).""" from __future__ import annotations from typing import Any USP_DYNAMIC_KEY = "usp" NEL_DYNAMIC_KEY = "nel" # GfE 2001 Milchkühe — Erhaltung + Milch (Standardmilch / FCM) NEL_MAINTENANCE_COEFF = 0.293 # MJ NEL / (kg LM)^0,75 / Tag NEL_PER_KG_MILK_MJ = 3.3 # MJ NEL / kg Milch (FCM) def gfe_usp_min_g( mass_kg: float | None, milk_yield_kg: float | None = None, ) -> float | None: """ Минимальная суточная потребность в усвояемом протеине (уСП / nXP), г/сут. GfE: 0,09 × (масса^0,75) × 6,25 + удой × 85 г. """ if mass_kg is None or mass_kg <= 0: return None maintenance = 0.09 * (mass_kg**0.75) * 6.25 milk = max(float(milk_yield_kg or 0), 0.0) * 85.0 return maintenance + milk def gfe_nel_min_mj( mass_kg: float | None, milk_yield_kg: float | None = None, ) -> float | None: """ Минимальная суточная потребность в ЧЭЛ (NEL), МДж/сут. GfE 2001: 0,293 × LM^0,75 + удой × 3,3 (MJ NEL на кг молока). """ if mass_kg is None or mass_kg <= 0: return None maintenance = NEL_MAINTENANCE_COEFF * (mass_kg**0.75) milk = max(float(milk_yield_kg or 0), 0.0) * NEL_PER_KG_MILK_MJ return maintenance + milk def preview_dynamic_norms( mass_kg: float | None, milk_yield_kg: float | None = None, ) -> dict[str, Any]: """Расчётные min по GfE для UI (без учёта сохранённых норм).""" _, dynamic = apply_dynamic_norms( {}, mass_kg=mass_kg, milk_yield_kg=milk_yield_kg, ) return dynamic def apply_dynamic_norms( stored: dict[str, dict[str, float | None]], *, mass_kg: float | None, milk_yield_kg: float | None, ration_type: str | None = None, force_dynamic: bool = False, ) -> tuple[dict[str, dict[str, float | None]], dict[str, Any]]: """ Заполняет нормы по GfE, если в БД min не задан. force_dynamic=True — пересчитать min уСП/ЧЭЛ по массе и удою даже при нормах в БД (автоготовка с явными mass_kg / milk_yield_kg). Возвращает (resolved_norms, dynamic_meta). """ del ration_type resolved: dict[str, dict[str, float | None]] = { key: {"min": bounds.get("min"), "max": bounds.get("max")} for key, bounds in stored.items() } dynamic: dict[str, Any] = {} for key, compute, formula in ( (USP_DYNAMIC_KEY, gfe_usp_min_g, "0.09×масса^0.75×6.25 + удой×85"), (NEL_DYNAMIC_KEY, gfe_nel_min_mj, "0.293×масса^0.75 + удой×3.3"), ): bounds = resolved.get(key, {"min": None, "max": None}) if force_dynamic or bounds.get("min") is None: computed = compute(mass_kg, milk_yield_kg) if computed is not None: entry = dict(bounds) entry["min"] = computed resolved[key] = entry dynamic[key] = {"min": computed, "formula": formula} return resolved, dynamic