This package contains a complete, standalone Python implementation of the SOPRA model for Grapholita funebrana (plum fruit moth) population dynamics. The implementation has been translated from the original Pascal version and thoroughly validated against Pascal reference results.
# Clone or download this repository
cd SOPRA_Python_Standalone
# Install in development mode with all dependencies
pip install -e .[all]
# Or install with specific optional dependencies
pip install -e .[jupyter] # For Jupyter notebook support
pip install -e .[dev] # For development tools# Install only core dependencies
pip install -e .- Python 3.8+
- numpy >= 1.21.0
- pandas >= 1.3.0
- matplotlib >= 3.4.0
Optional dependencies:
- jupyter >= 1.0.0 (for notebook examples)
- networkx >= 2.6.0 (for visualization)
graphoPy/
├── src/sopra/ # Main package directory
│ ├── __init__.py # Package initialization and exports
│ ├── core.py # Core SOPRA model functions
│ ├── meteo.py # Meteorological data utilities
│ └── cli.py # Command-line interface
├── tests/ # Test suite
│ ├── __init__.py
│ ├── test_core.py # Core functionality tests
│ └── test_meteo.py # Meteorological data tests
├── examples/ # Example notebooks and demos
│ ├── SOPRA_Demo.ipynb # Main demonstration notebook
│ ├── SOPRA_Demo_backup.ipynb # Backup notebook
│ ├── stations.txt # Station metadata
│ └── README.md # Examples documentation
├── data/ # Test data and outputs
│ ├── input/ # Input meteorological data
│ │ └── sopra_in/ # Standard format meteo files (2004-2024)
│ ├── output/ # Model outputs
│ │ ├── output_run_Pascal/ # Pascal reference results
│ │ └── output_run_Python/ # Python implementation results
│ └── README.md # Data documentation
├── Makefile # Build and test automation
├── pyproject.toml # Package configuration and metadata
└── README.md # This file
# Install all dependencies
make install-all
# Run unit tests (31 tests, 71% coverage)
make test-unit
# Execute demo notebook
make test-notebook
# Clean up
make cleanimport sopra
from sopra import core, meteo
# Initialize SOPRA model
constants = core.assign_const_and_var_gfune()
values = core.init_value_gfune()
# Load meteorological data
import pandas as pd
meteo_df = pd.read_csv('sopra_in/metaig24.std', sep='\t', header=None,
names=['day', 'hour', 'temp_air', 'solar_rad', 'temp_soil'])
# Run simulation for one time step
result = core.update_gfune(
values=values, day=1, hour=0, temp_air=10.0,
solar_rad=100.0, temp_soil=8.0,
curr_param=None, constants=constants
)
print(f"Simulation result: {result}")# Launch Jupyter notebook
jupyter notebook SOPRA_Demo.ipynbThe demo notebook provides:
- Complete walkthrough of the SOPRA model
- Meteorological data processing examples
- Population dynamics visualization
- Validation against Pascal reference results
# Verify package integrity
sopra-verify- Format: Tab-separated values, no headers
- Columns:
day,hour,temp_air,solar_rad,temp_soil - Units: day (1-365), hour (0-23), temperature (°C), solar radiation (W/m²)
- Resolution: Hourly meteorological data
- Population stages: pupae, adults, eggs, larvae, diapause individuals
- Temporal resolution: Hourly time series with daily summaries
- Validation metrics: Comparison with Pascal reference results
- Species: Grapholita funebrana (plum fruit moth)
- Model type: Temperature-dependent population dynamics with delayed response
- Life cycle: Overwintering → spring adults → first generation → summer adults → second generation → diapause
- Temperature-dependent development: Linear rate relationships
- Delayed response models: ODE system for stage transitions
- Multi-generational lifecycle: Two generations per year
- Trunk temperature calculation: Estimates bark temperature for pupae development
| Category | Functions | Description |
|---|---|---|
| Core | update_gfune() |
Main simulation step |
| Environment | rate(), get_trunk_temp() |
Temperature processing |
| Initialization | assign_const_and_var_gfune(), init_value_gfune() |
Model setup |
| Population | del_loop_fun(), block_delay_stage() |
Population dynamics |
| Code | Station Name | Location |
|---|---|---|
| AIG | Aigle | Western Switzerland |
| BAS | Basel / Binningen | Northern Switzerland |
| BER | Bern / Zollikofen | Central Switzerland |
| BUS | Buchs / Aarau | Central Switzerland |
| CGI | Nyon / Changins | Western Switzerland |
| GUT | Güttingen | Eastern Switzerland |
| MAG | Magadino / Cadenazzo | Southern Switzerland |
| PAY | Payerne | Western Switzerland |
| REH | Zürich / Affoltern | Central Switzerland |
| SIO | Sion | Valais |
| STG | St. Gallen | Eastern Switzerland |
| VAD | Vaduz | Liechtenstein |
| WAE | Wädenswil | Central Switzerland |
The Python implementation has been thoroughly validated against the original Pascal version:
- Precision: Maximum differences < 1e-6 (excellent precision)
- Coverage: All 13 stations for 2024 validated successfully
- Life stages: All population stages match Pascal reference
- Seasonal dynamics: Correct timing of emergence, reproduction, and diapause
pip install pandas numpy matplotlib pathlib- Python 3.7 or higher
- Tested with Python 3.8+
- Windows/Linux/macOS
- Minimum 1GB RAM
- 100MB disk space
For portable deployment across different systems, configure these environment variables:
# Set path to meteorological data archive
export SOPRA_METEO_ARCHIVE_PATH="/path/to/your/meteo/archive"
# Set path to Pascal reference data (for validation)
export SOPRA_PASCAL_REFERENCE_PATH="/path/to/pascal/reference.csv"Windows:
set SOPRA_METEO_ARCHIVE_PATH=C:\path\to\your\meteo\archive
set SOPRA_PASCAL_REFERENCE_PATH=C:\path\to\pascal\reference.csvIf environment variables are not set, the system will:
- Try platform-specific default paths (if they exist)
- Fall back to relative paths in the current directory
- Look for
sopra_in/directory for meteorological data - Look for
output_run_Pascal/gfu_all_years.csvfor Pascal reference data
This ensures the package works out-of-the-box for development while remaining portable for deployment.
The SOPRA Demo notebook automatically detects the runtime environment:
🏢 Agroscope Network Environment:
- Accesses meteorological archive for comprehensive data processing
- Converts Excel files to .std format for validation
- Full functionality including historical data analysis
🌐 External Environment:
- Automatically skips archive-dependent operations
- Uses provided sample
.stdfiles insopra_in/directory - Full model validation and simulation capabilities maintained
- External users can add their own
.stdfiles as needed
For External Users:
- ✅ No additional setup required - the notebook handles everything automatically
- ✅ Complete functionality available with included sample data
- ✅ Easy data integration - just add
.stdfiles tosopra_in/directory - ✅ Full validation - Python vs Pascal comparison works with provided data
# Load data and run simulation
meteo_data = read_meteo_file("sopra_in/metaig24.std")
results = run_sopra_model(meteo_data, "aig")
print(f"Simulated {len(results)} days for Aigle")# Analyze population peaks
population_cols = ['pupae_w', 'adults_w', 'eggs1', 'larvae1', 'diap']
for col in population_cols:
peak_value = results[col].max()
peak_day = results.loc[results[col].idxmax(), 'day']
print(f"{col}: {peak_value:.6f} on day {peak_day}")# Compare with Pascal reference
comparison = validate_python_vs_pascal("aig", 2024)
print("Validation completed!")The sopra.core module contains the main SOPRA model functions:
from sopra import core
# Model initialization
constants = core.assign_const_and_var_gfune() # Initialize constants
values = core.init_value_gfune() # Initialize state variables
# Core simulation functions
result = core.update_gfune(values, day, hour, temp_air, solar_rad, temp_soil)
trunk_temps = core.get_trunk_temp(day, temp_air, solar_rad)
dev_rate = core.rate(b1, b2, temp)Key Functions:
assign_const_and_var_gfune(): Initialize biological and physical constantsinit_value_gfune(): Initialize population values for all life stagesupdate_gfune(): Execute one simulation time stepget_trunk_temp(): Compute trunk temperature from meteorological datarate(): Calculate temperature-dependent development rates
The sopra.meteo module provides meteorological data utilities:
from sopra import meteo
# Station information
stations = meteo.STATIONS
station_info = meteo.get_station_info('AIG')
# File discovery and validation
file_path = meteo.discover_meteo_file(2024, 'AIG', 'Aigle', 'Aigle')
is_valid, message = meteo.validate_meteo_file(file_path)Key Functions:
discover_meteo_file(): Find meteorological data filesvalidate_meteo_file(): Validate data file format and completenessget_station_info(): Get station metadata by codeget_cross_platform_paths(): Handle platform-specific paths
# Install with development tools
pip install -e .[dev]
# Run tests (when available)
pytest
# Code formatting
black src/sopra/
flake8 src/sopra/
# Type checking
mypy src/sopra/# Build distribution packages
python -m build
# Install from built package
pip install dist/sopra-1.0.0-py3-none-any.whlTo use your own meteorological data:
- Format data as tab-separated
.stdfiles - Place in
sopra_in/directory - Use naming convention:
met{station}{year}.std
To process multiple years:
- Add historical
.stdfiles tosopra_in/ - Use the validation functions for cross-year analysis
- Compare results across different years
To modify model parameters:
- Edit constants in
assign_const_and_var_gfune() - Adjust initial values in
init_value_gfune() - Re-run simulations with new parameters
- Original Pascal SOPRA implementation
- Swiss meteorological station network (MeteoSwiss)
- Grapholita funebrana biological parameters from experimental studies
Q: Import errors when loading functions
A: Ensure all .py files are in the same directory as your notebook
Q: Missing meteorological data
A: Check that .std files exist in sopra_in/ directory
Q: Validation fails
A: Verify Pascal reference data is available in output_run_Pascal/
Run this code to verify package integrity:
import os
required_files = [
'grapholita_fun_utils.py',
'sopra_meteo_utils.py',
'stations.txt',
'sopra_in/',
'output_run_Pascal/gfu_all_years.csv'
]
for file_path in required_files:
status = "✅" if os.path.exists(file_path) else "❌"
print(f"{status} {file_path}")The project includes a comprehensive test suite with 71% code coverage.
# Run all unit tests with coverage report
make test-unit
# Run specific test file
pytest tests/test_core.py -v
# Run with detailed coverage report
pytest --cov=sopra --cov-report=htmlTest Coverage:
src/sopra/__init__.py: 100%src/sopra/core.py: 86%src/sopra/meteo.py: 42%- Overall: 71%
Test Suite (31 tests):
- ✅ Core utility functions (rate calculations, temperature modeling)
- ✅ Model initialization and configuration
- ✅ Delay and stage progression functions
- ✅ Main update loop and population dynamics
- ✅ Meteorological data handling
- ✅ Station information and file validation
# Install with development tools
make install-dev
# Or using pip directly
pip install -e .[dev]
# Code formatting
black src/sopra/
flake8 src/sopra/
# Type checking
mypy src/sopra/# Build distribution packages
python -m build
# Install from built package
pip install dist/sopra-1.0.0-py3-none-any.whl# Verify package integrity
sopra-verify
# Or from Python
python verify_package.pyThe package includes validation against Pascal reference results in output_run_Pascal/gfu_all_years.csv. Maximum differences have been asssessed (error max <
The package includes 2024 meteorological data for 13 Swiss stations:
| Code | Station | Records | Code | Station | Records |
|---|---|---|---|---|---|
| AIG | Aigle | 8,702 | PAY | Payerne | 8,657 |
| BAS | Basel | 8,702 | REH | Zürich/Affoltern | 8,702 |
| BER | Bern | 8,702 | SIO | Sion | 8,699 |
| BUS | Buchs/Aarau | 8,702 | STG | St. Gallen | 8,703 |
| CGI | Nyon/Changins | 8,616 | VAD | Vaduz | 8,703 |
| GUT | Güttingen | 8,638 | WAE | Wädenswil | 8,648 |
| MAG | Magadino | 8,703 | Total | 112,877 |
The original SOPRA source codes (in Pascal) were written by Benno Graf and Jörg Samietz (Agroscope, Switzerland). This includes but is not limited to the Grapholita funebrana model.
This Python implementation has been written by Matthieu Wilhelm (Agroscope, Switzerland).
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
This package provides everything needed to run the SOPRA Grapholita funebrana model in Python. The implementation is validated, documented, and ready for operational use in pest management and research applications.
Start with SOPRA_Demo.ipynb for a complete walkthrough!
