UPDATE
This commit is contained in:
@@ -402,8 +402,7 @@ def _run_simulation(context: GrowthSimulationContext) -> tuple[dict[str, Any], i
|
||||
)
|
||||
return response["result"], response.get("scenario_id"), None
|
||||
except Exception as exc:
|
||||
fallback = _run_projection_engine(context)
|
||||
return fallback, None, str(exc)
|
||||
raise GrowthSimulationError(f"Simulation engine failed: {exc}") from exc
|
||||
|
||||
|
||||
def summarize_growth_stages(
|
||||
@@ -566,3 +565,132 @@ def run_growth_simulation(payload: dict[str, Any], progress_callback=None) -> di
|
||||
"daily_records_count": len(simulation_result.get("daily_output", [])),
|
||||
"default_page_size": context.page_size,
|
||||
}
|
||||
|
||||
|
||||
def _estimate_leaf_count(lai: float) -> float:
|
||||
return max(lai, 0.0) * 12000.0
|
||||
|
||||
|
||||
def _build_current_farm_chart_payload(
|
||||
context: GrowthSimulationContext,
|
||||
simulation_result: dict[str, Any],
|
||||
scenario_id: int | None,
|
||||
simulation_warning: str | None,
|
||||
) -> dict[str, Any]:
|
||||
daily_output = simulation_result.get("daily_output") or []
|
||||
categories = [str(item.get("DAY")) for item in daily_output]
|
||||
|
||||
leaf_count_series = [round(_estimate_leaf_count(_safe_float(item.get("LAI"))), 2) for item in daily_output]
|
||||
biomass_series = [round(_safe_float(item.get("TAGP")), 2) for item in daily_output]
|
||||
storage_weight_series = [round(_safe_float(item.get("TWSO")), 2) for item in daily_output]
|
||||
lai_series = [round(_safe_float(item.get("LAI")), 4) for item in daily_output]
|
||||
moisture_series = [round(_safe_float(item.get("SM")) * 100.0, 2) for item in daily_output]
|
||||
|
||||
latest = daily_output[-1] if daily_output else {}
|
||||
latest_lai = _safe_float(latest.get("LAI"), 0.0)
|
||||
latest_biomass = _safe_float(latest.get("TAGP"), 0.0)
|
||||
latest_storage = _safe_float(latest.get("TWSO"), 0.0)
|
||||
latest_moisture = _safe_float(latest.get("SM"), 0.0) * 100.0
|
||||
|
||||
summary = [
|
||||
{
|
||||
"title": "تعداد برگ تخمینی",
|
||||
"subtitle": "وضعیت فعلی",
|
||||
"amount": round(_estimate_leaf_count(latest_lai), 2),
|
||||
"unit": "leaf",
|
||||
"avatarColor": "success",
|
||||
"avatarIcon": "tabler-leaf",
|
||||
},
|
||||
{
|
||||
"title": "وزن بیوماس",
|
||||
"subtitle": "برآورد فعلی",
|
||||
"amount": round(latest_biomass, 2),
|
||||
"unit": "kg/ha",
|
||||
"avatarColor": "primary",
|
||||
"avatarIcon": "tabler-chart-bar",
|
||||
},
|
||||
{
|
||||
"title": "وزن محصول",
|
||||
"subtitle": "برآورد فعلی",
|
||||
"amount": round(latest_storage, 2),
|
||||
"unit": "kg/ha",
|
||||
"avatarColor": "warning",
|
||||
"avatarIcon": "tabler-scale",
|
||||
},
|
||||
{
|
||||
"title": "رطوبت خاک",
|
||||
"subtitle": "آخرین روز",
|
||||
"amount": round(latest_moisture, 2),
|
||||
"unit": "%",
|
||||
"avatarColor": "info",
|
||||
"avatarIcon": "tabler-droplet",
|
||||
},
|
||||
]
|
||||
|
||||
return {
|
||||
"farm_uuid": context.farm_uuid,
|
||||
"plant_name": context.plant_name,
|
||||
"engine": simulation_result.get("engine"),
|
||||
"model_name": simulation_result.get("model_name"),
|
||||
"scenario_id": scenario_id,
|
||||
"simulation_warning": simulation_warning,
|
||||
"categories": categories,
|
||||
"series": [
|
||||
{"name": "تعداد برگ تخمینی", "key": "leaf_count_estimate", "data": leaf_count_series},
|
||||
{"name": "وزن بیوماس", "key": "biomass_weight", "data": biomass_series},
|
||||
{"name": "وزن محصول", "key": "storage_organ_weight", "data": storage_weight_series},
|
||||
{"name": "شاخص سطح برگ", "key": "lai", "data": lai_series},
|
||||
{"name": "رطوبت خاک", "key": "soil_moisture_percent", "data": moisture_series},
|
||||
],
|
||||
"summary": summary,
|
||||
"current_state": {
|
||||
"date": latest.get("DAY"),
|
||||
"leaf_count_estimate": round(_estimate_leaf_count(latest_lai), 2),
|
||||
"leaf_area_index": round(latest_lai, 4),
|
||||
"biomass_weight": round(latest_biomass, 2),
|
||||
"storage_organ_weight": round(latest_storage, 2),
|
||||
"soil_moisture_percent": round(latest_moisture, 2),
|
||||
"development_stage": round(_safe_float(latest.get("DVS"), 0.0), 4),
|
||||
"gdd": round(_safe_float(latest.get("GDD"), 0.0), 2),
|
||||
},
|
||||
"metrics": simulation_result.get("metrics") or {},
|
||||
"daily_output": daily_output,
|
||||
}
|
||||
|
||||
|
||||
class CurrentFarmChartSimulator:
|
||||
"""سازنده chart وضعیت فعلی مزرعه برای خروجی مستقل از dashboard."""
|
||||
|
||||
def simulate(self, *, farm_uuid: str, plant_name: str | None = None) -> dict[str, Any]:
|
||||
if not farm_uuid:
|
||||
raise GrowthSimulationError("farm_uuid is required.")
|
||||
|
||||
resolved_plant_name = plant_name
|
||||
if not resolved_plant_name:
|
||||
sensor = (
|
||||
SensorData.objects.prefetch_related("plants")
|
||||
.filter(farm_uuid=farm_uuid)
|
||||
.first()
|
||||
)
|
||||
if sensor is None:
|
||||
raise GrowthSimulationError("Farm not found.")
|
||||
plant = sensor.plants.first()
|
||||
if plant is None:
|
||||
raise GrowthSimulationError("Plant not found for the selected farm.")
|
||||
resolved_plant_name = plant.name
|
||||
|
||||
context = build_growth_context(
|
||||
{
|
||||
"farm_uuid": farm_uuid,
|
||||
"plant_name": resolved_plant_name,
|
||||
"dynamic_parameters": DEFAULT_DYNAMIC_PARAMETERS,
|
||||
"page_size": DEFAULT_PAGE_SIZE,
|
||||
}
|
||||
)
|
||||
simulation_result, scenario_id, simulation_warning = _run_simulation(context)
|
||||
return _build_current_farm_chart_payload(
|
||||
context,
|
||||
simulation_result,
|
||||
scenario_id,
|
||||
simulation_warning,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user