Files
2026-07-17 12:57:18 +03:00

95 lines
3.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Динамические нормы по уравнениям 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