Skip to content

Commit 79141cb

Browse files
committed
serialize and deserialize SimulationResult to .JSON and .pkl
1 parent e29103e commit 79141cb

2 files changed

Lines changed: 78 additions & 18 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,4 @@ mwe.py
214214
!standard_input.json
215215
*.ipynb
216216
*.code-workspace
217+
*.pkl

src/sparging/model.py

Lines changed: 77 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,7 @@
2020
from sparging.config import ureg, const_g
2121

2222
from sparging.inputs import SimulationInput
23-
24-
from typing import TYPE_CHECKING
25-
26-
if TYPE_CHECKING:
27-
import pint
23+
import pint
2824
from collections.abc import Callable
2925

3026
hours_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
142201
class Simulation:

0 commit comments

Comments
 (0)