Skip to content

Add typed engine params per disease model - #2

Open
fedjo wants to merge 1 commit into
agstack:masterfrom
GreenSupplyChain-DIH:feature/generic-model-import
Open

fedjo wants to merge 1 commit into
agstack:masterfrom
GreenSupplyChain-DIH:feature/generic-model-import

Conversation

@fedjo

@fedjo fedjo commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator

This pull request introduces a typed parameter schema system for pest/disease risk model engines, enabling more robust validation and extensibility for model-specific parameters. It adds new engine parameter schemas, updates the catalog to use them, and refactors existing model code to leverage these typed parameters. The changes also provide a mechanism for registering and retrieving engine parameter schemas via the model registry.

Key changes include:

Engine parameter schema system

  • Introduced EngineParamsBase and specific subclasses (e.g., FuzzyMamdaniParams, PowderyMildewGrapeParams) in engine_params.py to define and validate engine-specific parameters using Pydantic, with model validators for domain-specific constraints.
  • Updated PestModelBase to support an optional engine_params_schema class variable, allowing each model to declare its parameter schema.

Model registry enhancements

  • Extended ModelRegistry to index and retrieve engine parameter schemas by engine_type, and added the EngineTypeNotFound exception for missing schemas.

Catalog and threat definition updates

  • Updated pest_catalog.json to include engine_type and engine_params fields for threats, notably for "Powdery mildew" (grape) and added a new entry for "Pear scab" (pear), both specifying their engine and parameters.
  • Modified ThreatDefinition to support lazy validation of engine_params via the registry, and to bridge legacy fuzzy rules if no typed params are present.

Model refactoring for parameterization

  • Refactored the PowderyMildewGrape model to use the new PowderyMildewGrapeParams schema for all engine parameters, replacing hardcoded constants with values from the schema and updating logic accordingly.

Type and import improvements

  • Added type-checking imports and annotations to ensure correct typing and avoid circular dependencies, especially for engine parameter types.

These changes lay the groundwork for a more extensible and robust model engine system, allowing for easier integration of new models and parameter types in the future.

Example: adding a model with its own engine type (Apple Scab, Mills-type)

A new engine type needs only a params schema, a model class and an entry point. No core changes.

1. Params schema

Subclass EngineParamsBase with a unique engine_type literal (the registry lookup key).

class AppleScabParams(EngineParamsBase):
    engine_type: Literal["apple_scab_mills"] = "apple_scab_mills"
    min_wet_hours: float = 9.0
    t_min: float = 6.0

2. Model

Subclass PestModelBase, declare metadata and engine_params_schema, and read per-threat overrides in calculate().

class AppleScabMills(PestModelBase):
    metadata: ClassVar[ModelMetadata] = ModelMetadata(name="apple_scab_mills", ...)
    engine_params_schema: ClassVar = AppleScabParams

    def calculate(self, weather_data, parameters=None, threat=None):
        p = (AppleScabParams.model_validate(threat.engine_params)
             if threat and threat.engine_params else AppleScabParams())
        ...

3. Entry point

In pyproject.toml (third-party packages do the same in their own):

[project.entry-points."agstack_pnd.models"]
apple_scab_mills = "agstack_pnd.models.disease.applescab:AppleScabMills"

Re-run pip install -e . to pick it up.

4. Threat

In src/agstack_pnd/catalog/data/pest_catalog.json, on the apple Venturia inaequalis entry:

"engine_type": "apple_scab_mills",
"engine_params": { "min_wet_hours": 9.0, "t_min": 6.0 }

Threats without engine_params keep the legacy fuzzy_rules behaviour.

5. Verify

reg = ModelRegistry()
reg.get_engine_params_schema("apple_scab_mills")      # AppleScabParams
t = get_threat("apple", "Venturia inaequalis")
t.resolve_engine_params(reg)                          # validated params
reg.get_by_name("apple_scab_mills").calculate(wx, threat=t)
pytest tests/unit/test_catalog.py tests/unit/test_engine_params.py -q

@fedjo
fedjo requested a review from sumerjohal October 5, 2026 08:13
@fedjo fedjo added the enhancement New feature or request label Oct 5, 2026
@fedjo
fedjo requested a review from nik-suri October 5, 2026 08:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants