Meteorological data
The meteorological data module handles both station-based and gridded (raster) meteorological forcing for MOBIDIC simulations. It also includes tools for generating synthetic design storm hyetographs from IDF (Intensity-Duration-Frequency) parameters.
Overview
MOBIDICpy supports three modes of meteorological forcing, each suited to different workflows:
Station-based forcing (MeteoData)
Use when you have time-series from weather stations that need spatial interpolation.
- Station time series: Time-series from weather stations
- Spatial interpolation: Performed during simulation (IDW or Nearest Neighbor)
- Format support: MATLAB .mat files and CF-compliant NetCDF
- Optional grid export: Can save interpolated grids as NetCDF for reuse
Raster-based forcing (MeteoRaster)
Use when you have pre-interpolated gridded data or want to reuse previously interpolated results.
- Gridded data: Reads pre-interpolated NetCDF files with dimensions (time, y, x)
- Performance: Faster simulation by skipping real-time interpolation
- Grid validation: Automatically validates that rasters match the model grid
- Best for: Production runs, scenario analysis, or when using external gridded datasets (e.g., reanalysis products)
Design storm hyetographs (HyetographGenerator)
Use for design storm simulations with synthetic precipitation from IDF curves.
- IDF-based generation: Constructs precipitation from spatially distributed IDF parameters (a, n, k)
- Chicago method: Currently implements the Chicago decreasing hyetograph (after-peak curve)
- Areal reduction: Applies areal reduction factor (ARF) coefficient for spatial averaging
- Auto-resampling: IDF parameter rasters are automatically resampled to match the model grid
- Best for: Design flood simulations, flood mapping, infrastructure sizing
IDF formula
The total precipitation depth for a given duration is computed using the Depth-Duration-Frequency (DDF) relationship:
where:
- \(DDF(t)\) is the cumulative precipitation depth (mm) for duration \(t\)
- \(k_a\) is the areal reduction factor (ARF) coefficient
- \(k\) is the return period factor (spatially distributed raster)
- \(a\) is the IDF scale parameter (spatially distributed raster)
- \(n\) is the IDF exponent parameter (spatially distributed raster)
- \(t\) is duration in hours
Workflow recommendation:
- Initial run: Use station-based forcing with
output_forcing_data.meteo_data = True - Subsequent runs: Use the exported raster forcing for faster performance
- Different interpolation: Re-run with station forcing if you need to change interpolation method
API Reference
Input data classes
MeteoData
Container for station-based meteorological data with spatial interpolation capability.
Container for meteorological station data.
This class holds meteorological observations from multiple stations, organized by variable type (precipitation, temperature, wind, etc.).
Attributes:
| Name | Type | Description |
|---|---|---|
stations |
Dictionary mapping variable names to lists of station dictionaries |
|
variables |
List of available meteorological variables |
|
start_date |
First timestamp in the dataset |
|
end_date |
Last timestamp in the dataset |
Source code in mobidic/preprocessing/meteo_preprocessing.py
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | |
__init__(stations)
Initialize MeteoData container.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stations
|
dict[str, list[dict[str, Any]]]
|
Dictionary with variable names as keys (‘precipitation’, ‘temperature_min’, ‘temperature_max’, ‘humidity’, ‘wind_speed’, ‘radiation’) and lists of station dictionaries as values. Each station dict contains: ‘code’, ‘x’, ‘y’, ‘elevation’, ‘time’, ‘data’, ‘name’ (optional). |
required |
Source code in mobidic/preprocessing/meteo_preprocessing.py
from_csv(csv_path, config)
classmethod
Load meteorological data from CSV file(s).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
csv_path
|
str | Path
|
Path to CSV file or directory containing CSV files |
required |
config
|
dict[str, Any]
|
Configuration dictionary specifying CSV structure |
required |
Returns:
| Type | Description |
|---|---|
MeteoData
|
MeteoData object with station data |
Note
This method is planned for future implementation.
Source code in mobidic/preprocessing/meteo_preprocessing.py
from_mat(mat_path)
classmethod
Load meteorological data from MATLAB .mat file (legacy MOBIDIC format).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mat_path
|
str | Path
|
Path to MATLAB .mat file containing meteodata |
required |
Returns:
| Type | Description |
|---|---|
MeteoData
|
MeteoData object with station data |
Examples:
>>> meteo = MeteoData.from_mat("examples/Arno/meteodata/meteodata.mat")
>>> print(meteo)
>>> meteo.to_netcdf("meteodata.nc")
Source code in mobidic/preprocessing/meteo_preprocessing.py
from_netcdf(nc_path)
classmethod
Load meteorological data from NetCDF file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
nc_path
|
str | Path
|
Path to NetCDF file containing meteodata |
required |
Returns:
| Type | Description |
|---|---|
MeteoData
|
MeteoData object with station data |
Examples:
Source code in mobidic/preprocessing/meteo_preprocessing.py
to_netcdf(output_path, compression_level=4, add_metadata=None)
Save meteorological data to CF-compliant NetCDF file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output_path
|
str | Path
|
Path to output NetCDF file |
required |
compression_level
|
int
|
Compression level for NetCDF (0-9, default 4) |
4
|
add_metadata
|
dict[str, Any] | None
|
Additional global attributes to add to NetCDF file |
None
|
Examples:
>>> meteo = MeteoData.from_mat("meteodata.mat")
>>> meteo.to_netcdf("meteodata.nc", add_metadata={"basin": "Arno"})
Source code in mobidic/preprocessing/meteo_preprocessing.py
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | |
MeteoRaster
Container for pre-interpolated raster meteorological forcing.
Container for gridded meteorological data from rasters.
Loads CF-1.12 compliant NetCDF files with dimensions (time, y, x). By default, preloads all data into memory for optimal performance.
Attributes:
| Name | Type | Description |
|---|---|---|
nc_path |
Path to NetCDF file |
|
ds |
xarray Dataset (preloaded by default, or lazy-loaded if preload=False) |
|
variables |
List of available meteorological variables |
|
time_range |
Tuple of (start_time, end_time) |
|
start_date |
First timestamp in the dataset (property) |
|
end_date |
Last timestamp in the dataset (property) |
|
grid_metadata |
Dictionary with shape, resolution, crs, origin |
Performance
Default preload=True: Loads entire dataset into memory at initialization. This provides fast access during simulation (comparable to station interpolation). Use preload=False for very large datasets to use lazy loading (slower but less memory).
Source code in mobidic/preprocessing/meteo_raster.py
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | |
end_date
property
Last timestamp in the dataset.
Returns the end date as pandas Timestamp for consistency with MeteoData API.
start_date
property
First timestamp in the dataset.
Returns the start date as pandas Timestamp for consistency with MeteoData API.
__enter__()
__exit__(exc_type, exc_val, exc_tb)
__init__(nc_path, preload=True)
Initialize from NetCDF file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
nc_path
|
str | Path
|
Path to NetCDF file containing raster meteorological data |
required |
preload
|
bool
|
If True, load all data into memory immediately (default: True). If False, use lazy loading (slower but uses less memory). |
True
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the specified file does not exist |
ValueError
|
If the NetCDF file has invalid structure |
Source code in mobidic/preprocessing/meteo_raster.py
close()
from_netcdf(nc_path, preload=True)
classmethod
Load meteorological raster data from NetCDF file.
This is an alias for init to match the MeteoData API.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
nc_path
|
str | Path
|
Path to NetCDF file containing raster meteorological data |
required |
preload
|
bool
|
If True, load all data into memory immediately (default: True). If False, use lazy loading (slower but uses less memory). |
True
|
Returns:
| Type | Description |
|---|---|
MeteoRaster
|
MeteoRaster object |
Examples:
>>> # Fast loading (preload into memory)
>>> meteo = MeteoRaster.from_netcdf("Arno_meteoraster.nc")
>>> print(meteo)
>>>
>>> # Lazy loading (less memory, slower)
>>> meteo = MeteoRaster.from_netcdf("Arno_meteoraster.nc", preload=False)
Source code in mobidic/preprocessing/meteo_raster.py
get_timestep(time, variable)
Extract 2D grid for a variable at a specific time.
Uses nearest neighbor time sampling. Results are cached to avoid repeated disk reads for the same timestep.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
time
|
datetime
|
Datetime to extract (uses nearest neighbor) |
required |
variable
|
str
|
Variable name (e.g., ‘precipitation’, ‘pet’) |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
2D numpy array (nrows, ncols) in file units (mm/h for precip/pet) |
Raises:
| Type | Description |
|---|---|
KeyError
|
If variable not found in dataset |
Source code in mobidic/preprocessing/meteo_raster.py
validate_grid_alignment(model_metadata)
Validate that raster grid matches model grid.
Checks shape, resolution, and origin alignment. Raises detailed error if grids don’t match.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_metadata
|
dict
|
Dictionary with model grid metadata containing: - shape: (nrows, ncols) - resolution: grid resolution in meters - xllcorner: x coordinate of lower-left corner - yllcorner: y coordinate of lower-left corner - crs: coordinate reference system (optional) |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If grids are not aligned with detailed mismatch info |
Source code in mobidic/preprocessing/meteo_raster.py
HyetographGenerator
Generator for synthetic hyetographs from IDF parameters.
Generator for synthetic hyetographs from IDF parameters.
This class constructs synthetic rainfall time series (hyetographs) from spatially distributed IDF parameters.
Currently implements the Chicago method (decreasing after-peak curve only).
The total precipitation depth for a given duration is computed as
DDF(t) = ka * k * a * t^n
where
- ka is the areal reduction factor (ARF) coefficient
- k is the return period factor (spatially distributed)
- a is the IDF scale parameter (spatially distributed)
- n is the IDF exponent parameter (spatially distributed)
- t is duration in hours
Attributes:
| Name | Type | Description |
|---|---|---|
idf_params |
IDFParameters object with a, n, k grids |
|
ka |
Areal reduction factor coefficient |
Examples:
>>> # Simplest workflow: generate from configuration (recommended)
>>> from mobidic import load_config, load_gisdata, Simulation
>>> config = load_config("basin_hyetograph.yaml")
>>> gisdata = load_gisdata(config.paths.gisdata, config.paths.network)
>>> forcing = HyetographGenerator.from_config(
... config=config,
... base_path="basin_dir",
... start_time=datetime(2000, 1, 1)
... )
>>> sim = Simulation(gisdata, forcing, config)
>>> results = sim.run(forcing.start_date, forcing.end_date)
>>>
>>> # Alternative: generate forcing with manual parameters
>>> generator = HyetographGenerator.from_rasters(
... a_raster="idf/a.tif",
... n_raster="idf/n.tif",
... k_raster="idf/k30.tif",
... ka=0.8,
... ref_raster="dem.tif"
... )
>>> forcing = generator.generate_forcing(
... duration_hours=48,
... start_time=datetime(2023, 11, 1),
... output_path="design_storm.nc",
... add_metadata={"return_period": "30 years"}
... )
>>>
>>> # Advanced workflow: manual control over generation and export
>>> times, precip = generator.generate(
... duration_hours=48,
... start_time=datetime(2023, 11, 1),
... method="chicago_decreasing"
... )
>>> generator.to_netcdf(
... "hyetograph.nc",
... times=times,
... precipitation=precip,
... add_metadata={"event": "design_storm_30yr"}
... )
Source code in mobidic/preprocessing/hyetograph.py
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 | |
__init__(idf_params, ka=1.0)
Initialize HyetographGenerator with IDF parameters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
idf_params
|
IDFParameters
|
IDFParameters object containing a, n, k grids |
required |
ka
|
float
|
Areal reduction factor (ARF) coefficient (default: 1.0) |
1.0
|
Source code in mobidic/preprocessing/hyetograph.py
from_config(config, base_path, start_time, preload=True)
classmethod
Create hyetograph forcing from parameters specified in configuration file.
Convenience method that reads hyetograph parameters from a yaml configuration object, generates the hyetograph, saves to NetCDF, and returns a MeteoRaster ready for simulation.
All parameters (duration, timestep, method, IDF rasters, output path) are read from the configuration file. Only the start time needs to be specified. The start time is a reference datetime for the hyetograph event.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
MOBIDICConfig
|
MOBIDICConfig object with hyetograph configuration section |
required |
base_path
|
str | Path
|
Base path for resolving relative paths in config (typically the directory containing the config file) |
required |
start_time
|
datetime
|
Start datetime for the hyetograph |
required |
preload
|
bool
|
If True, preload all data into memory for fast access (default: True, recommended for normal use) |
True
|
Returns:
| Type | Description |
|---|---|
MeteoRaster
|
MeteoRaster object ready for use in Simulation |
Raises:
| Type | Description |
|---|---|
AttributeError
|
If config does not have a hyetograph section |
ValueError
|
If required configuration parameters are missing |
Examples:
>>> from mobidic import load_config, load_gisdata, Simulation
>>> from mobidic.preprocessing.hyetograph import HyetographGenerator
>>> from datetime import datetime
>>> from pathlib import Path
>>>
>>> # Load configuration
>>> config_file = Path("basin_hyetograph.yaml")
>>> config = load_config(config_file)
>>> gisdata = load_gisdata(config.paths.gisdata, config.paths.network)
>>>
>>> # Generate hyetograph
>>> forcing = HyetographGenerator.from_config(
... config=config,
... base_path=config_file.parent,
... start_time=datetime(2000, 1, 1)
... )
>>>
>>> # Run simulation
>>> sim = Simulation(gisdata, forcing, config)
>>> results = sim.run(forcing.start_date, forcing.end_date)
Notes
- Automatically resamples IDF parameters to DEM grid
- Uses all hyetograph parameters from config (duration, timestep, method, ka)
- Output path read from config.paths.hyetograph
- Creates metadata from config basin and hyetograph sections
- Returns MeteoRaster ready for simulation with proper date range
Source code in mobidic/preprocessing/hyetograph.py
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 | |
from_rasters(a_raster, n_raster, k_raster, ka=1.0, ref_raster=None)
classmethod
Create HyetographGenerator by loading IDF parameters from raster files.
If a reference raster is provided, the IDF parameters will be resampled to match its extent, resolution, and CRS using nearest neighbor interpolation. This is the typical workflow when the IDF rasters have different resolution than the model grid (e.g., DEM).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a_raster
|
str | Path
|
Path to raster file containing IDF ‘a’ parameter |
required |
n_raster
|
str | Path
|
Path to raster file containing IDF ‘n’ parameter |
required |
k_raster
|
str | Path
|
Path to raster file containing IDF ‘k’ parameter |
required |
ka
|
float
|
Areal reduction factor (ARF) coefficient (default: 1.0) |
1.0
|
ref_raster
|
str | Path | None
|
Optional path to reference raster (e.g., DEM) for resampling. If provided, IDF parameters will be resampled to match this grid. |
None
|
Returns:
| Type | Description |
|---|---|
HyetographGenerator
|
HyetographGenerator instance |
Examples:
>>> # Without resampling (IDF rasters already aligned)
>>> generator = HyetographGenerator.from_rasters(
... a_raster="idf/a.tif",
... n_raster="idf/n.tif",
... k_raster="idf/k30.tif",
... ka=0.8
... )
>>>
>>> # With resampling to DEM grid
>>> generator = HyetographGenerator.from_rasters(
... a_raster="idf/a.tif",
... n_raster="idf/n.tif",
... k_raster="idf/k30.tif",
... ka=0.8,
... ref_raster="dem.tif"
... )
Source code in mobidic/preprocessing/hyetograph.py
generate(duration_hours, start_time, method='chicago_decreasing', timestep_hours=1)
Generate hyetograph precipitation time series.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
duration_hours
|
int
|
Total duration of the hyetograph in hours |
required |
start_time
|
datetime
|
Start datetime for the hyetograph |
required |
method
|
Literal['chicago_decreasing']
|
Hyetograph construction method. Currently only “chicago_decreasing” is implemented. |
'chicago_decreasing'
|
timestep_hours
|
int
|
Time step in hours (default: 1) |
1
|
Returns:
| Type | Description |
|---|---|
tuple[list[datetime], ndarray]
|
Tuple of (times, precipitation) where: - times: List of datetime objects for each timestep - precipitation: 3D array (time, y, x) of precipitation (mm/h) |
Raises:
| Type | Description |
|---|---|
ValueError
|
If method is not supported |
Notes
- The Chicago decreasing method generates only the falling part of the Chicago hyetograph (after the peak)
- Precipitation values are in mm/h (intensity)
- NaN values in IDF parameters propagate to output
- If NaN values are > 90% in any parameter, a ValueError is raised during initialization of the HyetographGenerator
Source code in mobidic/preprocessing/hyetograph.py
generate_forcing(duration_hours, start_time, output_path, method='chicago_decreasing', timestep_hours=1, add_metadata=None, preload=True)
Generate hyetograph and return as MeteoRaster ready for simulation.
Convenience method that combines generate(), to_netcdf(), and MeteoRaster.from_netcdf() into a single call. This simplifies the workflow for design storm simulations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
duration_hours
|
int
|
Total duration of the hyetograph in hours |
required |
start_time
|
datetime
|
Start datetime for the hyetograph |
required |
output_path
|
str | Path
|
Path for output NetCDF file |
required |
method
|
Literal['chicago_decreasing']
|
Hyetograph construction method (default: “chicago_decreasing”) |
'chicago_decreasing'
|
timestep_hours
|
int
|
Time step in hours (default: 1) |
1
|
add_metadata
|
dict | None
|
Optional dictionary of additional global attributes |
None
|
preload
|
bool
|
If True, preload all data into memory for fast access (default: True, recommended for normal use) |
True
|
Returns:
| Type | Description |
|---|---|
MeteoRaster
|
MeteoRaster object ready for use in Simulation |
Examples:
>>> # Create generator from IDF rasters
>>> generator = HyetographGenerator.from_rasters(
... a_raster="idf/a.tif",
... n_raster="idf/n.tif",
... k_raster="idf/k30.tif",
... ka=0.8,
... ref_raster="dem.tif"
... )
>>>
>>> # Generate forcing and get MeteoRaster in one call
>>> forcing = generator.generate_forcing(
... duration_hours=48,
... start_time=datetime(2023, 11, 1),
... output_path="design_hyetograph.nc",
... add_metadata={"return_period": "30 years"}
... )
>>>
>>> # Use directly in simulation
>>> sim = Simulation(gisdata, forcing, config)
>>> results = sim.run(forcing.start_date, forcing.end_date)
Notes
- This method is equivalent to calling generate(), to_netcdf(), and MeteoRaster.from_netcdf() sequentially
- The NetCDF file is still created at output_path for later use
Source code in mobidic/preprocessing/hyetograph.py
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 | |
to_netcdf(output_path, times, precipitation, add_metadata=None)
Export hyetograph to CF-compliant NetCDF file.
Creates a NetCDF file compatible with MeteoRaster.from_netcdf() for use as meteorological forcing in MOBIDIC simulations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output_path
|
str | Path
|
Path for output NetCDF file |
required |
times
|
list[datetime]
|
List of datetime objects for each timestep |
required |
precipitation
|
ndarray
|
3D array (time, y, x) of precipitation [mm/h] |
required |
add_metadata
|
dict | None
|
Optional dictionary of additional global attributes |
None
|
Notes
- Output follows CF-1.12 conventions
- Includes CRS information as grid mapping variable
- Precipitation units are mm/h (compatible with MeteoRaster)
Examples:
>>> times, precip = generator.generate(48, datetime(2023, 11, 1))
>>> generator.to_netcdf(
... "design_storm.nc",
... times=times,
... precipitation=precip,
... add_metadata={"return_period": "30 years"}
... )
Source code in mobidic/preprocessing/hyetograph.py
934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 | |
Output classes
MeteoWriter
Writer for saving interpolated meteorological grids from station-based simulations.
Writer for interpolated meteorological data grids.
This class stores interpolated meteorological grids during simulation and writes them to a single CF-compliant NetCDF file at the end.
Unlike StateWriter which uses incremental writing with chunking, this writer buffers all data in memory and writes once. This is more efficient for meteo data which is typically much smaller than state data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output_path
|
str | Path
|
Path to output NetCDF file (will be created/overwritten) |
required |
grid_metadata
|
dict
|
Dictionary with grid metadata (shape, resolution, crs, etc.) |
required |
variables
|
list[str]
|
List of meteorological variable names to save (e.g., [‘precipitation’, ‘temperature’]) |
required |
add_metadata
|
dict | None
|
Additional global attributes (optional) |
None
|
Examples:
>>> # Create writer for precipitation and temperature
>>> writer = MeteoWriter(
... "meteo_forcing.nc",
... metadata,
... variables=['precipitation', 'temperature']
... )
>>> for step in range(num_steps):
... writer.append(current_time, precipitation=precip_grid, temperature=temp_grid)
>>> writer.close() # Writes all data to file
Source code in mobidic/io/meteo.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | |
__enter__()
__exit__(exc_type, exc_val, exc_tb)
Context manager exit - automatically close and write data.
Source code in mobidic/io/meteo.py
__init__(output_path, grid_metadata, variables, add_metadata=None)
Initialize the meteo writer.
Source code in mobidic/io/meteo.py
append(time, **grids)
Append meteorological grids for a timestep.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
time
|
datetime
|
Timestamp for this data |
required |
**grids
|
ndarray
|
Keyword arguments for each variable grid (e.g., precipitation=precip_grid). Each grid should be a 2D numpy array with shape (nrows, ncols). |
{}
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If a required variable is missing or has wrong shape |
Examples:
Source code in mobidic/io/meteo.py
close()
Write all buffered data to NetCDF file and close writer.
This creates a CF-1.12 compliant NetCDF file with all meteorological variables and metadata.
Source code in mobidic/io/meteo.py
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | |
Utility functions
convert_mat_to_netcdf
Direct conversion from MATLAB .mat format to CF-compliant NetCDF.
Convert MATLAB .mat meteorological data to NetCDF format.
This is a convenience function that combines loading from .mat and saving to NetCDF in a single call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mat_path
|
str | Path
|
Path to input MATLAB .mat file |
required |
output_path
|
str | Path
|
Path to output NetCDF file |
required |
compression_level
|
int
|
Compression level (0-9, default 4) |
4
|
add_metadata
|
dict[str, Any] | None
|
Additional global attributes for NetCDF file |
None
|
Examples:
>>> convert_mat_to_netcdf(
... "examples/Arno/meteodata/meteodata.mat",
... "examples/Arno/meteodata/meteodata.nc",
... add_metadata={"basin": "Arno", "basin_id": "1234"}
... )
Source code in mobidic/preprocessing/meteo_preprocessing.py
Supported variables
The meteorological preprocessing module handles six standard variables:
| Variable | Description | Units (NetCDF) | MATLAB field | MATLAB units |
|---|---|---|---|---|
precipitation |
Rainfall and snowfall | mm/h | sp |
mm (cumulated) |
temperature_min |
Minimum air temperature | °C | s_ta_min |
°C |
temperature_max |
Maximum air temperature | °C | s_ta_max |
°C |
humidity |
Relative humidity | % | s_ua |
% |
wind_speed |
Wind speed | m/s | s_vv |
m/s |
radiation |
Solar radiation | W/m² | s_ra |
W/m² |
Automatic precipitation unit conversion
When loading from MATLAB .mat files, precipitation is automatically converted from mm (cumulated over the sampling interval) to mm/h. The conversion infers the timestep from the time array (dt = time[1] - time[0]) and divides precipitation values by the timestep in hours. This ensures consistency with raster forcing, which also uses mm/h.
Usage examples
Example 1: Quick conversion from MATLAB format
The fastest way to convert legacy MATLAB meteorological data:
from mobidic import convert_mat_to_netcdf
convert_mat_to_netcdf(
"input/meteodata.mat",
"output/meteodata.nc",
compression_level=4,
add_metadata={
"basin": "Arno",
"description": "Meteorological forcing for flood event",
}
)
Example 2: Load, inspect, and save station data
When you need to examine data before using it in simulations:
from mobidic import MeteoData
# Load from MATLAB file
meteo = MeteoData.from_mat("input/meteodata.mat")
# Inspect loaded data
print(meteo)
print(f"Date range: {meteo.start_date} to {meteo.end_date}")
print(f"Variables: {meteo.variables}")
# Check station counts
for var_name, stations in meteo.stations.items():
print(f"{var_name}: {len(stations)} stations")
# Save to NetCDF with metadata
meteo.to_netcdf(
"output/meteodata.nc",
compression_level=4,
add_metadata={"basin": "Arno"}
)
Example 3: Work with existing NetCDF station data
Load and access station data from CF-compliant NetCDF files:
from mobidic import MeteoData
# Load from NetCDF
meteo = MeteoData.from_netcdf("output/meteodata.nc")
# Access station data for a specific variable
precip_stations = meteo.stations["precipitation"]
first_station = precip_stations[0]
print(f"Station code: {first_station['code']}")
print(f"Location: ({first_station['x']:.2f}, {first_station['y']:.2f})")
print(f"Elevation: {first_station['elevation']:.1f} m")
print(f"Data shape: {first_station['data'].shape}")
Example 4: Use pre-interpolated raster forcing
Load and run simulations with gridded meteorological data:
from mobidic import MeteoRaster, Simulation, load_gisdata, load_config
# Load raster forcing (default: preload into memory for best performance)
forcing = MeteoRaster.from_netcdf("meteo_raster.nc")
# Inspect raster data
print(f"Variables: {forcing.variables}")
print(f"Time range: {forcing.start_date} to {forcing.end_date}")
print(f"Grid shape: {forcing.grid_metadata['shape']}")
print(f"Resolution: {forcing.grid_metadata['resolution']:.1f} m")
# For very large datasets (>several GB), use lazy loading to save memory
forcing_lazy = MeteoRaster.from_netcdf("meteo_raster.nc", preload=False)
# Use in simulation (automatically detects raster mode)
config = load_config("basin.yaml")
gisdata = load_gisdata("gisdata.nc", "network.parquet")
sim = Simulation(gisdata, forcing, config)
results = sim.run("2023-01-01", "2023-12-31")
Example 5: Export interpolated data for reuse
Create reusable raster forcing from station-based simulations:
from mobidic import MeteoData, Simulation, load_gisdata, load_config
# Load station-based forcing
forcing = MeteoData.from_netcdf("meteo_stations.nc")
# Enable meteo forcing output in configuration
config = load_config("basin.yaml")
config.output_forcing_data.meteo_data = True
# Run simulation (exports forcing grids automatically)
gisdata = load_gisdata("gisdata.nc", "network.parquet")
sim = Simulation(gisdata, forcing, config)
results = sim.run("2023-01-01", "2023-12-31")
# Forcing data saved to: {output_dir}/meteo_forcing.nc
# Use this file as raster forcing in subsequent runs for faster performance
Example 6: Generate design storm hyetograph from configuration
The simplest workflow for design storm simulations reads all parameters from the YAML configuration:
from datetime import datetime
from pathlib import Path
from mobidic import load_config, load_gisdata, Simulation
from mobidic.preprocessing.hyetograph import HyetographGenerator
# Load configuration with hyetograph section
config_file = Path("basin_hyetograph.yaml")
config = load_config(config_file)
gisdata = load_gisdata(config.paths.gisdata, config.paths.network)
# Generate forcing from config - only start_time needed!
# All parameters (IDF rasters, duration, timestep, output path) read from config
forcing = HyetographGenerator.from_config(
config=config,
base_path=config_file.parent,
start_time=datetime(2000, 1, 1)
)
# Run simulation
sim = Simulation(gisdata, forcing, config)
results = sim.run(forcing.start_date, forcing.end_date)
Required configuration (basin_hyetograph.yaml):
paths:
hyetograph: output/design_storm.nc # Output NetCDF path
hyetograph:
a_raster: idf/a.tif # IDF 'a' parameter raster
n_raster: idf/n.tif # IDF 'n' parameter raster
k_raster: idf/k30.tif # Return period factor raster (e.g., 30-year)
duration_hours: 48 # Storm duration
timestep_hours: 1 # Time step
hyetograph_type: chicago_decreasing # Hyetograph method
ka: 0.8 # Areal reduction factor
Example 7: Generate hyetograph with manual parameters
For more control over the hyetograph generation process:
from datetime import datetime
from mobidic import Simulation, load_gisdata, load_config
from mobidic.preprocessing.hyetograph import HyetographGenerator
# Create generator from IDF rasters
generator = HyetographGenerator.from_rasters(
a_raster="idf/a.tif",
n_raster="idf/n.tif",
k_raster="idf/k30.tif",
ka=0.8, # Areal reduction factor
ref_raster="dem.tif" # Reference grid for resampling
)
# Generate forcing and get MeteoRaster in one call
forcing = generator.generate_forcing(
duration_hours=48,
start_time=datetime(2023, 11, 1),
output_path="design_storm.nc",
method="chicago_decreasing",
timestep_hours=1,
add_metadata={"return_period": "30 years"}
)
# Use directly in simulation
config = load_config("basin.yaml")
gisdata = load_gisdata("gisdata.nc", "network.parquet")
sim = Simulation(gisdata, forcing, config)
results = sim.run(forcing.start_date, forcing.end_date)
Example 8: Advanced hyetograph workflow (full control)
For complete control over generation and export:
from datetime import datetime
from mobidic import MeteoRaster
from mobidic.preprocessing.hyetograph import HyetographGenerator
# Create generator
generator = HyetographGenerator.from_rasters(
a_raster="idf/a.tif",
n_raster="idf/n.tif",
k_raster="idf/k30.tif",
ka=0.8,
ref_raster="dem.tif"
)
# Generate time series (returns times and precipitation arrays)
times, precipitation = generator.generate(
duration_hours=48,
start_time=datetime(2023, 11, 1),
method="chicago_decreasing",
timestep_hours=1,
)
# Inspect generated data
print(f"Time steps: {len(times)}")
print(f"Precipitation shape: {precipitation.shape}") # (time, y, x)
print(f"Peak intensity: {precipitation[0].max():.2f} mm/h")
print(f"Total depth: {precipitation.sum(axis=0).max():.1f} mm")
# Save to NetCDF with custom metadata
generator.to_netcdf(
"design_storm.nc",
times=times,
precipitation=precipitation,
add_metadata={
"return_period": "30 years",
"event_type": "design_storm",
"basin": "Arno"
}
)
# Load as MeteoRaster for simulation
forcing = MeteoRaster.from_netcdf("design_storm.nc")
Data formats
Station data (MeteoData)
MATLAB format
Legacy MATLAB .mat files should contain struct arrays with these fields:
% Example structure for precipitation (variable name: sp)
sp(i).code % Station identifier (string or number)
sp(i).est % X coordinate (easting)
sp(i).nord % Y coordinate (northing)
sp(i).quota % Elevation (m)
sp(i).name % Station name (optional)
sp(i).time % Time vector (MATLAB datenum)
sp(i).dati % Data vector (values)
Variable names in MATLAB: sp (precipitation), s_ta_min (temperature min), s_ta_max (temperature max), s_ua (humidity), s_vv (wind speed), s_ra (radiation).
Unit conversions during import
- MATLAB datenum: Automatically converted to pandas datetime, accounting for the epoch difference (MATLAB: January 1, 0000; Unix: January 1, 1970).
- Precipitation: Automatically converted from mm (cumulated over sampling interval) to mm/h by inferring the timestep from the time array.
Internal Python representation
MeteoData stores station data as a nested dictionary:
meteo.stations = {
"precipitation": [
{
"code": "STATION_001",
"x": 671234.5, # Easting
"y": 4821098.3, # Northing
"elevation": 342.0, # meters
"name": "Firenze",
"time": pd.DatetimeIndex([...]),
"data": np.array([...]) # Time series values
},
# ... additional stations
],
"temperature_min": [...],
"temperature_max": [...],
# ... other variables
}
NetCDF format (CF-1.12 compliant)
Station data exported to NetCDF follows Climate and Forecast conventions:
Structure:
Dimensions:
- time: N timesteps
- station_precipitation: M stations for precipitation
- station_temperature_min: K stations for temperature_min
- ... (one dimension per variable)
Coordinates:
- time(time): datetime64[ns]
- x_precipitation(station_precipitation): float64
- y_precipitation(station_precipitation): float64
- elevation_precipitation(station_precipitation): float32
- station_code_precipitation(station_precipitation): str
Data variables:
- precipitation(time, station_precipitation): float32 [mm/h]
- temperature_min(time, station_temperature_min): float32 [°C]
- ... (one variable per meteorological parameter)
Features:
- CF-1.12 compliant metadata (standard_name, long_name, units)
- Zlib compression (default level 4) for efficient storage
- Custom global attributes supported via
add_metadata - Precipitation stored in mm/h (consistent with raster forcing)
Raster data (MeteoRaster)
NetCDF format (CF-1.12 compliant)
Gridded forcing data follows standard CF conventions:
Required structure:
Dimensions:
- time: unlimited (temporal)
- y: grid rows (north-south)
- x: grid columns (east-west)
Coordinates:
- time(time): datetime64[ns] with CF-compliant calendar
- x(x): float64 (easting or longitude)
- y(y): float64 (northing or latitude)
Data variables:
- precipitation(time, y, x): float32 [mm/h]
- pet(time, y, x): float32 [mm/h]
- temperature(time, y, x): float32 [°C]
- ... (additional variables as needed)
Grid mapping:
- crs(): int32 with spatial_ref or crs_wkt attribute
Example inspection:
import xarray as xr
ds = xr.open_dataset("meteo_raster.nc")
print(ds)
# <xarray.Dataset>
# Dimensions: (time: 8761, y: 200, x: 300)
# Coordinates:
# * time (time) datetime64[ns] 2023-01-01 ... 2023-12-31
# * x (x) float64 600000.0 ... 629900.0
# * y (y) float64 4800000.0 ... 4820000.0
# Data variables:
# precipitation (time, y, x) float32 ...
# pet (time, y, x) float32 ...
# temperature (time, y, x) float32 ...
# crs () int32 ...
Requirements:
- Grid must align with model grid (validated automatically)
- Units: mm/h for precipitation, °C for temperature
- Missing values: represented as NaN