fr_data module¶
simpest.models.fr_data
¶
Input, output, and parameter data structures for the FraNchEstYN model.
This module defines the typed containers that carry information through the simulation: hourly and daily weather inputs, external crop-model series, the crop, disease, and fungicide state written on each simulated day, the parameter groups that configure each sub-model, and the per-site simulation unit that binds sowing schedule and reference observations together.
All quantities follow the model's canonical units, which are noted inline beside each field (temperatures in °C, biomass and yield in kg ha⁻¹, radiation in MJ m⁻², light interception as a 0–1 fraction, and so on).
CropModelData
dataclass
¶
Output from an external crop model, used as input to damage mechanisms.
Keys are datetime.date objects (year, month, day).
Source code in simpest/models/fr_data.py
@dataclass
class CropModelData:
"""Output from an external crop model, used as input to damage mechanisms.
Keys are datetime.date objects (year, month, day).
"""
f_int: Dict[date, float] = field(default_factory=dict) # fraction 0-1: light interception
yield_: Dict[date, float] = field(default_factory=dict) # kg ha⁻¹: dynamic crop yield
agb: Dict[date, float] = field(default_factory=dict) # kg ha⁻¹: above-ground biomass
cycle_percentage: Dict[date, float] = field(default_factory=dict) # %: crop cycle completion
# Growing degree days (thermal time) carried alongside the crop series. It is
# populated from the external crop model's thermal-time column and used to
# derive cycle progress when GDD-based phenology is enabled.
gdd: Dict[date, float] = field(default_factory=dict) # °C·day: growing degree days
CropOutputs
dataclass
¶
Crop growth state variables output each day.
Source code in simpest/models/fr_data.py
@dataclass
class CropOutputs:
"""Crop growth state variables output each day."""
growing_season: int = 0 # season identifier
day_after_sowing: int = 0 # days since sowing
pheno_code: float = 0.0 # phenological code (1 = vegetative, 2 = reproductive)
growing_degree_days: float = 0.0 # °C·day accumulated GDD
agb_attainable: float = 0.0 # kg ha⁻¹ attainable AGB
agb_actual: float = 0.0 # kg ha⁻¹ actual AGB
yield_attainable: float = 0.0 # kg ha⁻¹ attainable yield
yield_actual: float = 0.0 # kg ha⁻¹ actual yield
light_interception_attainable: float = 0.0 # fraction
light_interception_actual: float = 0.0 # fraction
cycle_completion_percentage: float = 0.0 # %
senescence_started: bool = False
f_int_peak: float = 0.0
DamageMechanisms
dataclass
¶
Damage outputs (one per day) that feed into crop loss calculations.
Source code in simpest/models/fr_data.py
@dataclass
class DamageMechanisms:
"""Damage outputs (one per day) that feed into crop loss calculations."""
light_stealers: float = 0.0 # fraction: reduction in light interception
senescence_accelerators: float = 0.0 # fraction: acceleration of tissue aging
rue_reducers: float = 0.0 # fraction: reduction in radiation use efficiency
assimilate_sappers: float = 0.0 # kg ha⁻¹: assimilate loss from disease
DiseaseOutputs
dataclass
¶
All disease state variables output each day.
Source code in simpest/models/fr_data.py
@dataclass
class DiseaseOutputs:
"""All disease state variables output each day."""
counter_dry: float = 0.0 # hours since last wet period
temp_function: float = 0.0 # temperature suitability (0-1)
rh_function: float = 0.0 # RH suitability (0-1)
hydro_thermal_time_state: float = 0.0 # accumulated hydro-thermal time (hydro-degree days)
hydro_thermal_time_rate: float = 0.0 # daily hydro-thermal time rate
hydro_thermal_time_infection: float = 0.0 # infection accumulation
sporulation_efficiency: float = 0.0 # %
tmax_daily: float = 0.0 # °C
tmin_daily: float = 0.0 # °C
rain_daily: float = 0.0 # mm
rhmax_daily: float = 0.0 # %
rhmin_daily: float = 0.0 # %
lw_daily: float = 0.0 # % (leaf wetness fraction of day)
# Tissue tracking is handled as a list of TissueState in disease_model.py
# Summary aggregates written here each day:
tissue_state: TissueState = field(default_factory=TissueState)
latent_sum: float = 0.0 # % cumulative latent
sporulating_sum: float = 0.0 # % cumulative sporulating
dead_sum: float = 0.0 # % cumulative dead
affected_sum: float = 0.0 # % cumulative affected
disease_severity: float = 0.0 # % disease severity (sporulating + dead)
susceptible_fraction: float = 1.0 # fraction of healthy susceptible tissue
damage_mechanisms: DamageMechanisms = field(default_factory=DamageMechanisms)
first_seasonal_infection: datetime = field(default_factory=lambda: datetime(1900, 1, 1))
cycle_percentage_first_infection: float = 0.0
is_primary_inoculum_started: bool = False
outer_inoculum: float = 0.0
FungicideOutputs
dataclass
¶
Fungicide state variables output each day.
Source code in simpest/models/fr_data.py
@dataclass
class FungicideOutputs:
"""Fungicide state variables output each day."""
concentration_factor: float = 0.0 # fraction - fungicide concentration
tenacity_function: float = 0.0 # unitless - fungicide tenacity function
tenacity: float = 0.0 # fraction - fungicide tenacity (potential efficacy after wash-off)
actual_degradation: float = 0.0 # fraction (1 = not degraded)
potential_degradation: float = 0.0 # fraction
efficacy: float = 0.0 # fraction
FungicideTreatmentSchedule
dataclass
¶
Holds all scheduled fungicide treatment dates for a simulation unit.
Source code in simpest/models/fr_data.py
@dataclass
class FungicideTreatmentSchedule:
"""Holds all scheduled fungicide treatment dates for a simulation unit."""
treatments: List[datetime] = field(default_factory=list)
def add_treatment(self, treatment_date: datetime) -> None:
self.treatments.append(treatment_date)
InputsDaily
dataclass
¶
Daily input record (assembled from 24 hourly records each day).
Source code in simpest/models/fr_data.py
@dataclass
class InputsDaily:
"""Daily input record (assembled from 24 hourly records each day)."""
date: datetime = datetime.min
tmax: float = 0.0 # °C
tmin: float = 0.0 # °C
rad: float = 0.0 # MJ m⁻² d⁻¹
rhx: float = 0.0 # % (max RH)
rhn: float = 0.0 # % (min RH)
precipitation: float = 0.0 # mm
leaf_wetness: float = 0.0 # hours
dew_point: float = 0.0 # °C
latitude: float = 0.0 # degrees
date_treatment_last: datetime = datetime.min
crop_model_data: "CropModelData" = None # populated from external crop model CSV
InputsHourly
dataclass
¶
Hourly input record for the disease model.
Source code in simpest/models/fr_data.py
@dataclass
class InputsHourly:
"""Hourly input record for the disease model."""
date: datetime = datetime.min
air_temperature: float = 0.0 # °C
precipitation: float = 0.0 # mm
relative_humidity: float = 0.0 # %
leaf_wetness: float = 0.0 # 0 or 1
rad: float = 0.0 # MJ m⁻² h⁻¹
dis_ideotype_potential_rate: float = 0.0 # unitless
latitude: float = 0.0 # degrees
date_treatment_last: datetime = datetime.min
Outputs
dataclass
¶
Top-level daily output bundle.
Source code in simpest/models/fr_data.py
@dataclass
class Outputs:
"""Top-level daily output bundle."""
disease: DiseaseOutputs = field(default_factory=DiseaseOutputs)
crop: CropOutputs = field(default_factory=CropOutputs)
inputs_daily: InputsDaily = field(default_factory=InputsDaily)
fungicide: FungicideOutputs = field(default_factory=FungicideOutputs)
ParCrop
dataclass
¶
Crop model parameters.
Source code in simpest/models/fr_data.py
@dataclass
class ParCrop:
"""Crop model parameters."""
tbase_crop: float = 0.0 # °C – base temperature for crop growth
topt_crop: float = 0.0 # °C – optimum temperature
tmax_crop: float = 0.0 # °C – maximum temperature
cycle_length: float = 0.0 # degree-days – total crop cycle length
flowering_start: float = 0.0 # % – crop cycle % when flowering starts
half_int_growth: float = 0.0 # % – cycle % when light interception = 0.5 (growth phase)
half_int_senescence: float = 0.0 # % – cycle % when light interception = 0.5 (senescence phase)
slope_growth: float = 0.0 # unitless – slope of growth light interception curve
slope_senescence: float = 0.0 # unitless – slope of senescence curve
radiation_use_efficiency: float = 0.0 # g MJ⁻¹
partitioning_maximum: float = 0.0 # unitless – max yield partitioning fraction
varietal_resistance: float = 0.0 # 0–1 – varietal resistance to pathogen
ParDisease
dataclass
¶
Disease model parameters.
Source code in simpest/models/fr_data.py
@dataclass
class ParDisease:
"""Disease model parameters."""
outer_inoculum_max: float = 0.0 # unitless – initial inoculum level
outer_inoculum_shape_release: float = 0.0 # 0/1/2 – release shape
outer_inoculum_shape_parameter: float = 0.0 # empirical parameter for shape 1 or 2
pathogen_spread: float = 0.0 # dispersal potential
wetness_duration_optimum: float = 0.0 # hours – optimal leaf wetness
wetness_duration_minimum: float = 0.0 # hours – minimum required wetness
dry_critical_interruption: float = 0.0 # hours – dry spell that disrupts infection
rain50_detachment: float = 0.0 # mm – rain needed for spore detachment
cycle_percentage_onset: float = 0.0 # % – crop cycle % when disease can start
tmin: float = 0.0 # °C – minimum temperature for pathogen
topt: float = 0.0 # °C – optimum temperature
tmax: float = 0.0 # °C – maximum temperature
relative_humidity_critical: float = 0.0 # % – minimum RH for infection
relative_humidity_not_limiting: float = 0.0 # % – RH above which it is not limiting
hydro_thermal_time_onset: float = 0.0 # hydro-degree days – onset threshold
latency_duration: float = 0.0 # days – latency period duration
sporulation_duration: float = 0.0 # days – sporulation duration
light_stealer_damage: float = 0.0 # unitless – lesion size representation
rue_reducer_damage: float = 0.0 # fraction – RUE reduction
senescence_accelerator_damage: float = 0.0 # fraction – senescence acceleration rate
assimilate_sappers_damage: float = 0.0 # kg ha⁻¹ – max assimilate loss
is_splash_borne: bool = False # True if spore release requires rain
ParFungicide
dataclass
¶
Fungicide model parameters.
Source code in simpest/models/fr_data.py
@dataclass
class ParFungicide:
"""Fungicide model parameters."""
a_shape_parameter: float = 0.0 # empirical degradation shape A
b_shape_parameter: float = 0.0 # empirical degradation shape B
degradation_rate: float = 0.0 # first-order degradation rate
initial_dose: float = 0.0 # fraction – initial dose (1 = max dose)
initial_efficacy: float = 0.0 # fraction – initial efficacy (1 = max)
tenacity_factor: float = 0.0 # rain-driven degradation empirical factor
Parameter
dataclass
¶
A single parameter definition with calibration bounds.
Holds the numeric value, the lower and upper bounds used as the calibration search space, and metadata describing the parameter's class and whether it is boolean. Instances are produced by the parameter readers and consumed by both the model runner and the calibration optimizer.
Source code in simpest/models/fr_data.py
@dataclass
class Parameter:
"""A single parameter definition with calibration bounds.
Holds the numeric value, the lower and upper bounds used as the calibration
search space, and metadata describing the parameter's class and whether it is
boolean. Instances are produced by the parameter readers and consumed by both
the model runner and the calibration optimizer.
"""
minimum: float = 0.0 # Lower bound (e.g., calibration search space)
maximum: float = 0.0 # Upper bound (e.g., calibration search space)
value: float = 0.0 # Current numeric value (e.g., for simulation or optimization)
calibration: str = "" # calibration subset tag (e.g., "included", "excluded")
param_class: str = "" # class/category of the parameter (e.g., "disease", "crop")
value_bool: bool = False # For boolean parameters, the value is stored here instead of 'value'
is_boolean: bool = False # True if this parameter is boolean (e.g., "IsSplashBorne"), in which case 'value_bool' is used instead of 'value'
Parameters
dataclass
¶
Container for all three parameter groups.
Source code in simpest/models/fr_data.py
@dataclass
class Parameters:
"""Container for all three parameter groups."""
par_disease: ParDisease = field(default_factory=ParDisease)
par_crop: ParCrop = field(default_factory=ParCrop)
par_fungicide: ParFungicide = field(default_factory=ParFungicide)
ReferenceData
dataclass
¶
Observed / reference data for validation (field measurements).
Source code in simpest/models/fr_data.py
@dataclass
class ReferenceData:
"""Observed / reference data for validation (field measurements)."""
date_fint: Dict[date, float] = field(default_factory=dict)
date_agb: Dict[date, float] = field(default_factory=dict)
date_yield_actual: Dict[date, float] = field(default_factory=dict)
date_yield_attainable: Dict[date, float] = field(default_factory=dict)
# disease_date_disease_sev[pathogen][date] = severity
disease_date_disease_sev: Dict[str, Dict[date, float]] = field(default_factory=dict)
SimulationUnit
dataclass
¶
Everything needed to run one site × variety combination.
Source code in simpest/models/fr_data.py
@dataclass
class SimulationUnit:
"""Everything needed to run one site × variety combination."""
site: str = "" # site identifier (e.g., location name)
crop: str = "" # crop identifier (e.g., crop name)
latitude: float = 0.0 # degrees - site latitude
longitude: float = 0.0 # degrees - site longitude
variety: str = "" # variety identifier (e.g., variety name)
pathogen: str = "" # pathogen identifier
variety_resistance: float = 0.0 # 0–1 – varietal resistance to pathogen
year_sowing_doy: Dict[int, int] = field(default_factory=dict) # Maps simulation year → sowing day-of-year
reference_data: ReferenceData = field(default_factory=ReferenceData) # observed or reference data for validation
fungicide_treatment_schedule: FungicideTreatmentSchedule = field( # fungicide treatment scheduling
default_factory=FungicideTreatmentSchedule
)
TissueState
dataclass
¶
State of a single tissue cohort (SEIR disease model).
Source code in simpest/models/fr_data.py
@dataclass
class TissueState:
"""State of a single tissue cohort (SEIR disease model)."""
latent_state: float = 0.0 # fraction currently in latent phase
sporulating_state: float = 0.0 # fraction currently sporulating
dead_state: float = 0.0 # fraction dead
latent_counter: float = 0.0 # progress counter in latent phase (→ 1 = transitions to sporulating)
sporulating_counter: float = 0.0 # progress counter in sporulating phase (→ 1 = transitions to dead)