CropAI / backend /bio_twin.py
bapi143's picture
Deploy CropAI Backend
5fd7795
Raw History Blame Contribute Delete
5.96 kB
"""
CropAI Physics-Informed Disease Micro-Climate Twin (Bio-Twin™)
Computes Leaf Wetness Duration (LWD), Dew-Point Differential, and Spore Germination Index (SGI)
to forecast fungal infection windows before spore penetration occurs.
"""
import math
from typing import Dict, Any, List
class PhysicsBioTwinEngine:
"""Physics-Informed Neural & Thermodynamic Fungal Infection Predictor."""
@staticmethod
def calculate_dew_point(temp_c: float, humidity_pct: float) -> float:
"""Calculates dew point using the Magnus-Tetens formula."""
a = 17.27
b = 237.7
alpha = ((a * temp_c) / (b + temp_c)) + math.log(max(humidity_pct, 1.0) / 100.0)
dew_point = (b * alpha) / (a - alpha)
return round(dew_point, 2)
@staticmethod
def simulate_microclimate_infection_risk(
crop: str,
temperature_c: float,
humidity_pct: float,
wind_speed_kmh: float,
leaf_wetness_hours: float,
cloud_cover_pct: float = 60.0
) -> Dict[str, Any]:
"""
Simulates micro-climate conditions inside the crop canopy and computes
the Spore Germination Index (SGI: 0.0 to 1.0) for high-risk pathogens.
"""
dew_point = PhysicsBioTwinEngine.calculate_dew_point(temperature_c, humidity_pct)
temp_dew_diff = max(0.0, temperature_c - dew_point)
# 1. Estimate effective Leaf Wetness Duration (LWD)
# Higher humidity + low wind + low temp-dew difference = high condensation retention
wind_factor = max(0.2, 1.0 - (wind_speed_kmh / 40.0))
humidity_factor = max(0.0, (humidity_pct - 65.0) / 35.0)
effective_lwd = leaf_wetness_hours + (humidity_factor * wind_factor * 3.5)
effective_lwd = min(24.0, max(0.0, effective_lwd))
# 2. Pathogen Specific Fungal Infection Models
crop_lower = crop.lower()
if "rice" in crop_lower or "paddy" in crop_lower:
target_disease = "Paddy Blast (Magnaporthe oryzae)"
# Blast optimal: Temp 24-28C, LWD > 8 hrs, Humidity > 85%
temp_suitability = math.exp(-0.5 * ((temperature_c - 26.0) / 4.0) ** 2)
lwd_suitability = 1.0 / (1.0 + math.exp(-0.8 * (effective_lwd - 7.0)))
hum_suitability = 1.0 / (1.0 + math.exp(-0.2 * (humidity_pct - 82.0)))
sgi = temp_suitability * lwd_suitability * hum_suitability
critical_window_hours = 18
elif "wheat" in crop_lower:
target_disease = "Yellow / Stripe Rust (Puccinia striiformis)"
# Rust optimal: Temp 12-18C, high moisture, low wind
temp_suitability = math.exp(-0.5 * ((temperature_c - 15.0) / 3.5) ** 2)
lwd_suitability = 1.0 / (1.0 + math.exp(-0.7 * (effective_lwd - 6.0)))
hum_suitability = 1.0 / (1.0 + math.exp(-0.15 * (humidity_pct - 80.0)))
sgi = temp_suitability * lwd_suitability * hum_suitability
critical_window_hours = 24
elif "potato" in crop_lower or "tomato" in crop_lower:
target_disease = "Late Blight (Phytophthora infestans)"
# Late Blight optimal: Temp 15-22C, LWD > 10 hrs
temp_suitability = math.exp(-0.5 * ((temperature_c - 18.0) / 3.0) ** 2)
lwd_suitability = 1.0 / (1.0 + math.exp(-0.9 * (effective_lwd - 8.0)))
hum_suitability = 1.0 / (1.0 + math.exp(-0.2 * (humidity_pct - 85.0)))
sgi = temp_suitability * lwd_suitability * hum_suitability
critical_window_hours = 12
else:
target_disease = "General Fungal Leaf Spot / Blight"
sgi = (humidity_pct / 100.0) * min(1.0, effective_lwd / 12.0)
critical_window_hours = 24
sgi = min(1.0, max(0.05, sgi))
sgi_pct = round(sgi * 100.0, 1)
# 3. Categorize Risk & Action Protocol
if sgi >= 0.70:
risk_category = "CRITICAL_SPORE_GERMINATION_ALERT"
forecast_message = (
f"High-risk fungal germination window active for {target_disease}. "
f"Leaf canopy wetness ({round(effective_lwd, 1)} hrs) and thermal conditions "
f"are optimal for spore hyphae penetration within the next {critical_window_hours} hours."
)
preventive_actions = [
"Drain standing water from furrows to reduce canopy relative humidity.",
"Apply prophylactic bio-shield (Pseudomonas fluorescens 0.5% or Trichoderma viride) within 24h.",
"Avoid nitrogenous top-dressing fertilizer which promotes lush, susceptible succulent leaf tissue."
]
elif sgi >= 0.40:
risk_category = "MODERATE_MICROCLIMATE_RISK"
forecast_message = (
f"Moderate micro-climate risk for {target_disease}. "
"Conditions favor spore survival. Monitor field closely."
)
preventive_actions = [
"Inspect lower canopy leaves during early morning dew hours.",
"Ensure weed-free field borders to improve air circulation."
]
else:
risk_category = "LOW_MICROCLIMATE_RISK"
forecast_message = f"Canopy micro-climate is unfavorable for {target_disease} spore germination."
preventive_actions = [
"Maintain normal crop irrigation schedule."
]
return {
"crop": crop,
"target_pathogen": target_disease,
"spore_germination_index_pct": sgi_pct,
"risk_classification": risk_category,
"calculated_dew_point_c": dew_point,
"effective_leaf_wetness_hours": round(effective_lwd, 1),
"critical_infection_window_hours": critical_window_hours,
"physics_forecast_summary": forecast_message,
"preventive_canopy_actions": preventive_actions
}
bio_twin_engine = PhysicsBioTwinEngine()