88import logging
99import json
1010import networkx as nx
11+ import pandas as pd
1112
1213import wntr .epanet
1314from wntr .epanet .util import FlowUnits
2324logger = logging .getLogger (__name__ )
2425
2526
27+ def _nan_to_none (value ):
28+ """Convert NaN values to None for pandas 3.0 compatibility."""
29+ if pd .isna (value ):
30+ return None
31+ return value
32+
33+
2634def to_dict (wn ) -> dict :
2735 """
2836 Convert a WaterNetworkModel into a dictionary
@@ -120,12 +128,12 @@ def from_dict(d: dict, append=None):
120128 dl = node .setdefault ("demand_timeseries_list" )
121129 if dl is not None and len (dl ) > 0 :
122130 base_demand = dl [0 ].setdefault ("base_val" , 0.0 )
123- pattern_name = dl [0 ].setdefault ("pattern_name" )
124- demand_category = dl [0 ].setdefault ("category" )
131+ pattern_name = _nan_to_none ( dl [0 ].setdefault ("pattern_name" ) )
132+ demand_category = _nan_to_none ( dl [0 ].setdefault ("category" ) )
125133 else :
126134 base_demand = node .setdefault ('base_demand' ,0.0 )
127- pattern_name = node .setdefault ('pattern_name' )
128- demand_category = node .setdefault ('demand_category' )
135+ pattern_name = _nan_to_none ( node .setdefault ('pattern_name' ) )
136+ demand_category = _nan_to_none ( node .setdefault ('demand_category' ) )
129137 wn .add_junction (
130138 name = name ,
131139 base_demand = base_demand ,
@@ -140,7 +148,7 @@ def from_dict(d: dict, append=None):
140148 j .minimum_pressure = node .setdefault ("minimum_pressure" )
141149 j .pressure_exponent = node .setdefault ("pressure_exponent" )
142150 j .required_pressure = node .setdefault ("required_pressure" )
143- j .tag = node .setdefault ("tag" )
151+ j .tag = _nan_to_none ( node .setdefault ("tag" ) )
144152
145153 j ._leak = node .setdefault ("leak" , False )
146154 j ._leak_area = node .setdefault ("leak_area" , 0.0 )
@@ -152,8 +160,8 @@ def from_dict(d: dict, append=None):
152160 if dl is not None and len (dl ) > 1 :
153161 for i in range (1 , len (dl )):
154162 base_val = dl [i ].setdefault ("base_val" , 0.0 )
155- pattern_name = dl [i ].setdefault ("pattern_name" )
156- category = dl [i ].setdefault ("category" )
163+ pattern_name = _nan_to_none ( dl [i ].setdefault ("pattern_name" ) )
164+ category = _nan_to_none ( dl [i ].setdefault ("category" ) )
157165 j .add_demand (base_val , pattern_name , category )
158166 elif node ["node_type" ] == "Tank" :
159167 coordinates = node .setdefault ("coordinates" )
@@ -166,7 +174,7 @@ def from_dict(d: dict, append=None):
166174 max_level = node .setdefault ("max_level" , node .setdefault ("min_level" , 0 ) + 10 ),
167175 diameter = node .setdefault ("diameter" , 0 ),
168176 min_vol = node .setdefault ("min_vol" , 0 ),
169- vol_curve = node .setdefault ("vol_curve_name" ),
177+ vol_curve = _nan_to_none ( node .setdefault ("vol_curve_name" ) ),
170178 overflow = node .setdefault ("overflow" , False ),
171179 coordinates = coordinates ,
172180 )
@@ -177,20 +185,20 @@ def from_dict(d: dict, append=None):
177185 if node .setdefault ("mixing_model" ):
178186 t .mixing_model = node .setdefault ("mixing_model" )
179187 t .bulk_coeff = node .setdefault ("bulk_coeff" )
180- t .tag = node .setdefault ("tag" )
188+ t .tag = _nan_to_none ( node .setdefault ("tag" ) )
181189 # custom additional attributes
182190 for attr in list (set (node .keys ()) - set (dir (t ))):
183191 setattr ( t , attr , node [attr ] )
184192 elif node ["node_type" ] == "Reservoir" :
185193 wn .add_reservoir (
186194 name ,
187195 base_head = node .setdefault ("base_head" ),
188- head_pattern = node .setdefault ("head_pattern_name" ),
196+ head_pattern = _nan_to_none ( node .setdefault ("head_pattern_name" ) ),
189197 coordinates = node .setdefault ("coordinates" ),
190198 )
191199 r = wn .get_node (name )
192200 r .initial_quality = node .setdefault ("initial_quality" , 0.0 )
193- r .tag = node .setdefault ("tag" )
201+ r .tag = _nan_to_none ( node .setdefault ("tag" ) )
194202 # custom additional attributes
195203 for attr in list (set (node .keys ()) - set (dir (r ))):
196204 setattr ( r , attr , node [attr ] )
@@ -213,7 +221,7 @@ def from_dict(d: dict, append=None):
213221 )
214222 p = wn .get_link (name )
215223 p .bulk_coeff = link .setdefault ("bulk_coeff" )
216- p .tag = link .setdefault ("tag" )
224+ p .tag = _nan_to_none ( link .setdefault ("tag" ) )
217225 p .vertices = link .setdefault ("vertices" , list ())
218226 p .wall_coeff = link .setdefault ("wall_coeff" )
219227 # custom additional attributes
@@ -230,15 +238,15 @@ def from_dict(d: dict, append=None):
230238 if pump_type .lower () == "power"
231239 else link .setdefault ("pump_curve_name" ),
232240 speed = link .setdefault ("base_speed" , 1.0 ),
233- pattern = link .setdefault ("speed_pattern_name" ),
241+ pattern = _nan_to_none ( link .setdefault ("speed_pattern_name" ) ),
234242 initial_status = link .setdefault ("initial_status" , "OPEN" ),
235243 )
236244 p = wn .get_link (name )
237- p .efficiency_curve_name = link .setdefault ("efficiency_curve_name" )
238- p .energy_pattern = link .setdefault ("energy_pattern" )
245+ p .efficiency_curve_name = _nan_to_none ( link .setdefault ("efficiency_curve_name" ) )
246+ p .energy_pattern = _nan_to_none ( link .setdefault ("energy_pattern" ) )
239247 p .energy_price = link .setdefault ("energy_price" )
240248 p .initial_setting = link .setdefault ("initial_setting" )
241- p .tag = link .setdefault ("tag" )
249+ p .tag = _nan_to_none ( link .setdefault ("tag" ) )
242250 p .vertices = link .setdefault ("vertices" , list ())
243251 # custom additional attributes
244252 for attr in list (set (link .keys ()) - set (dir (p ))):
@@ -257,7 +265,7 @@ def from_dict(d: dict, append=None):
257265 )
258266 v = wn .get_link (name )
259267 if valve_type .lower () == "gpv" :
260- v .headloss_curve_name = link .setdefault ("headloss_curve_name" )
268+ v .headloss_curve_name = _nan_to_none ( link .setdefault ("headloss_curve_name" ) )
261269 v .vertices = link .setdefault ("vertices" , list ())
262270 # custom additional attributes
263271 for attr in list (set (link .keys ()) - set (dir (v ))):
0 commit comments