2020from sparging .config import ureg , const_g
2121
2222from sparging .inputs import SimulationInput
23-
24- from typing import TYPE_CHECKING
25-
26- if TYPE_CHECKING :
27- import pint
23+ import pint
2824from collections .abc import Callable
2925
3026hours_to_seconds = 3600
@@ -49,21 +45,23 @@ class SimulationResults:
4945 inventories_T2_salt : np .ndarray [pint .Quantity ]
5046 sources_T2 : np .ndarray [pint .Quantity ]
5147 fluxes_T2 : np .ndarray [pint .Quantity ]
52- sim_input : SimulationInput
53- dt : pint .Quantity
54- dx : pint . Quantity
48+ dt : pint . Quantity = None
49+ dx : pint .Quantity = None
50+ sim_input : SimulationInput = None
5551
5652 keys_to_ignore_results = [ # TODO do it the other way: keys_to_include_results
57- "c_T2_solutions" ,
58- "y_T2_solutions" ,
59- "J_T2_solutions" ,
60- "x_ct" ,
61- "x_y" ,
62- "inventories_T2_salt" ,
63- "times" ,
64- "source_T2 " ,
65- "fluxes_T2" ,
53+ # "c_T2_solutions",
54+ # "y_T2_solutions",
55+ # "J_T2_solutions",
56+ # "x_ct",
57+ # "x_y",
58+ # "inventories_T2_salt",
59+ # "times",
60+ # "sources_T2 ",
61+ # "fluxes_T2",
6662 "sim_input" ,
63+ "dt" ,
64+ "dx" ,
6765 ]
6866
6967 def to_yaml (self , output_path : Path ):
@@ -90,7 +88,7 @@ def to_yaml(self, output_path: Path):
9088 with open (output_path , "w" ) as f :
9189 yaml .dump (output , f , sort_keys = False )
9290
93- def to_json (self , output_path : Path ):
91+ def serialize_output (self ):
9492 sim_dict = self .sim_input .__dict__ .copy ()
9593
9694 # structure the output
@@ -116,10 +114,44 @@ def to_json(self, output_path: Path):
116114 print (
117115 "found list in results, converting to list for JSON serialization"
118116 )
117+ if isinstance (value , pint .Quantity ):
118+ # convert pint.Quantity to string for JSON serialization
119+ output [key ] = value .to_base_units ().magnitude
120+ print (
121+ "found pint.Quantity in results, converting to magnitude for JSON serialization"
122+ )
123+ else :
124+ print (
125+ f"{ key } is of type { type (value )} , no conversion needed for JSON serialization"
126+ )
127+
128+ for k , v in output ["results" ].items ():
129+ if isinstance (v , pint .Quantity ):
130+ units = str (v .units )
131+ output ["results" ][k ] = {"value" : v .magnitude , "units" : units }
132+
133+ if isinstance (v .magnitude , np .ndarray ):
134+ print (
135+ f"found pint.Quantity with numpy array magnitude in results[{ k } ], converting to list for JSON serialization"
136+ )
137+ output ["results" ][k ]["value" ] = v .magnitude .tolist ()
138+
139+ return output
140+
141+ def to_json (self , output_path : Path ):
142+ output = self .serialize_output ()
119143
120144 with open (output_path , "w" ) as f :
121145 json .dump (output , f , indent = 3 )
122146
147+ def to_pickle (self , output_path : Path ):
148+ import pickle
149+
150+ output = self .serialize_output ()
151+
152+ with open (output_path , "wb" ) as f :
153+ pickle .dump (output , f )
154+
123155 def profiles_to_csv (self , output_path : Path ):
124156 """save c_T2 and y_T2 profiles at all time steps to csv files, one for c_T2 and one for y_T2, with columns for each time step"""
125157 import pandas as pd
@@ -137,6 +169,33 @@ def profiles_to_csv(self, output_path: Path):
137169 df_c_T2 .to_csv (output_path .joinpath ("_c_T2.csv" ), index = False )
138170 df_y_T2 .to_csv (output_path .joinpath ("_y_T2.csv" ), index = False )
139171
172+ @classmethod
173+ def deserialize_output (cls , data : dict ) -> SimulationResults :
174+ # only read the "results" key
175+ # for each key in results, if the dict have "value" and "units" keys, convert it back to pint.Quantity
176+ results = data .get ("results" , {})
177+ for k , v in results .items ():
178+ if isinstance (v , dict ) and "value" in v and "units" in v :
179+ results [k ] = ureg .Quantity (v ["value" ], v ["units" ])
180+
181+ return cls (** results )
182+
183+ @classmethod
184+ def from_json (cls , input_path : Path ) -> SimulationResults :
185+ with open (input_path , "r" ) as f :
186+ data = json .load (f )
187+
188+ return cls .deserialize_output (data )
189+
190+ @classmethod
191+ def from_pickle (cls , input_path : Path ) -> SimulationResults :
192+ import pickle
193+
194+ with open (input_path , "rb" ) as f :
195+ data = pickle .load (f )
196+
197+ return cls .deserialize_output (data )
198+
140199
141200@dataclass
142201class Simulation :
0 commit comments