1212GNU General Public License for more details.
1313"""
1414
15+ from __future__ import annotations
16+
1517from typing import Dict , Tuple , TYPE_CHECKING
16- import dataclasses
1718from datetime import datetime , timedelta
19+ from pathlib import Path
1820
1921import numpy as np
22+ from pydantic import BaseModel , ConfigDict
2023
2124from itzi .const import DefaultValues , TemporalType , InfiltrationModelType
2225
2326if TYPE_CHECKING :
2427 from itzi .drainage import DrainageNode
2528
2629
27- @dataclasses .dataclass (frozen = True )
28- class DrainageNodeCouplingData :
30+ class DrainageNodeCouplingData (BaseModel ):
2931 """Store the translation between coordinates and array location for a given drainage node."""
3032
33+ model_config = ConfigDict (frozen = True , arbitrary_types_allowed = True )
34+
3135 node_id : str # Name of the drainage node
3236 node_object : "DrainageNode"
3337 # Location in the coordinate system
@@ -38,24 +42,24 @@ class DrainageNodeCouplingData:
3842 col : int | None
3943
4044
41- @dataclasses .dataclass (frozen = True )
42- class DrainageAttributes :
45+ class DrainageAttributes (BaseModel ):
4346 """A base class for drainage data attributes."""
4447
48+ model_config = ConfigDict (frozen = True )
49+
4550 @classmethod
4651 def get_columns_definition (cls , cat_primary_key = True ) -> list [tuple [str , str ]]:
4752 """Return a list of tuples to create DB columns"""
4853 type_mapping = {str : "TEXT" , int : "INT" , float : "REAL" }
4954 db_columns_def = [("cat" , "INTEGER PRIMARY KEY" )]
5055 if not cat_primary_key :
5156 db_columns_def = []
52- for f in dataclasses . fields ( cls ):
53- db_field = (f . name , type_mapping [f . type ])
57+ for field_name , field_info in cls . model_fields . items ( ):
58+ db_field = (field_name , type_mapping [field_info . annotation ])
5459 db_columns_def .append (db_field )
5560 return db_columns_def
5661
5762
58- @dataclasses .dataclass (frozen = True )
5963class DrainageLinkAttributes (DrainageAttributes ):
6064 link_id : str
6165 link_type : str
@@ -67,16 +71,16 @@ class DrainageLinkAttributes(DrainageAttributes):
6771 froude : float
6872
6973
70- @dataclasses .dataclass (frozen = True )
71- class DrainageLinkData :
74+ class DrainageLinkData (BaseModel ):
7275 """Store the instantaneous state of a node during a drainage simulation.
7376 Vertices include the coordinates of the start and end nodes."""
7477
75- vertices : None | Tuple [Tuple [float , float ], ...]
78+ model_config = ConfigDict (frozen = True )
79+
80+ vertices : None | Tuple [Tuple [float , float ] | None , ...]
7681 attributes : DrainageLinkAttributes
7782
7883
79- @dataclasses .dataclass (frozen = True )
8084class DrainageNodeAttributes (DrainageAttributes ):
8185 node_id : str
8286 node_type : str
@@ -101,55 +105,60 @@ class DrainageNodeAttributes(DrainageAttributes):
101105 full_volume : float
102106
103107
104- @dataclasses .dataclass (frozen = True )
105- class DrainageNodeData :
108+ class DrainageNodeData (BaseModel ):
106109 """Store the instantaneous state of a node during a drainage simulation"""
107110
111+ model_config = ConfigDict (frozen = True )
112+
108113 coordinates : None | Tuple [float , float ]
109114 attributes : DrainageNodeAttributes
110115
111116
112- @dataclasses .dataclass (frozen = True )
113- class DrainageNetworkData :
117+ class DrainageNetworkData (BaseModel ):
118+ model_config = ConfigDict (frozen = True )
119+
114120 nodes : Tuple [DrainageNodeData , ...]
115121 links : Tuple [DrainageLinkData , ...]
116122
117123
118- @dataclasses .dataclass (frozen = True )
119- class ContinuityData :
124+ class ContinuityData (BaseModel ):
120125 """Store information about simulation continuity"""
121126
127+ model_config = ConfigDict (frozen = True )
128+
122129 new_domain_vol : float
123130 volume_change : float
124131 volume_error : float
125132 continuity_error : float
126133
127134
128- @dataclasses .dataclass (frozen = True )
129- class SimulationData :
135+ class SimulationData (BaseModel ):
130136 """Immutable data container for passing raw simulation state to Report.
131137
132138 This is a pure data structure containing only the "raw ingredients"
133139 needed for a report. All report-specific calculations (e.g., WSE,
134140 average rates) are performed by the Report class itself.
135141 """
136142
143+ model_config = ConfigDict (frozen = True , arbitrary_types_allowed = True )
144+
137145 sim_time : datetime
138146 time_step : float # time step duration
139147 time_steps_counter : int # number of time steps since last update
140- continuity_data : ContinuityData
148+ continuity_data : ContinuityData | None # Made optional for use in tests
141149 raw_arrays : Dict [str , np .ndarray ]
142150 accumulation_arrays : Dict [str , np .ndarray ]
143151 cell_dx : float # cell size in east-west direction
144152 cell_dy : float # cell size in north-south direction
145153 drainage_network_data : DrainageNetworkData | None
146154
147155
148- @dataclasses .dataclass (frozen = True )
149- class MassBalanceData :
156+ class MassBalanceData (BaseModel ):
150157 """Contains the fields written to the mass balance file"""
151158
152- simulation_time : datetime
159+ model_config = ConfigDict (frozen = True )
160+
161+ simulation_time : datetime | timedelta
153162 average_timestep : float
154163 timesteps : int
155164 boundary_volume : float
@@ -164,10 +173,11 @@ class MassBalanceData:
164173 percent_error : float
165174
166175
167- @dataclasses .dataclass (frozen = True )
168- class SurfaceFlowParameters :
176+ class SurfaceFlowParameters (BaseModel ):
169177 """Parameters for the surface flow model."""
170178
179+ model_config = ConfigDict (frozen = True )
180+
171181 hmin : float = DefaultValues .HFMIN
172182 cfl : float = DefaultValues .CFL
173183 theta : float = DefaultValues .THETA
@@ -179,22 +189,23 @@ class SurfaceFlowParameters:
179189 max_error : float = DefaultValues .MAX_ERROR
180190
181191
182- @dataclasses .dataclass (frozen = True )
183- class SimulationConfig :
192+ class SimulationConfig (BaseModel ):
184193 """Configuration data for a simulation run."""
185194
195+ model_config = ConfigDict (frozen = True )
196+
186197 # Simulation times
187198 start_time : datetime
188199 end_time : datetime
189200 record_step : timedelta
190201 temporal_type : TemporalType
191202 # Input and output raster maps
192- input_map_names : Dict [str , str ]
193- output_map_names : Dict [str , str ]
203+ input_map_names : Dict [str , str | None ]
204+ output_map_names : Dict [str , str | None ]
194205 # Surface flow parameters
195206 surface_flow_parameters : SurfaceFlowParameters
196207 # Mass balance file
197- stats_file : str
208+ stats_file : str | Path | None = None
198209 # Hydrology parameters
199210 dtinf : float = DefaultValues .DTINF
200211 infiltration_model : InfiltrationModelType = InfiltrationModelType .NULL
0 commit comments