IDAES / idaes-pse

The IDAES Process Systems Engineering Framework
https://idaes-pse.readthedocs.io/
Other
216 stars 234 forks source link

Model Serializer does not like Numpy Ints #929

Open dallan-keylogic opened 2 years ago

dallan-keylogic commented 2 years ago

When a Pyomo component is assigned a value that's a Numpy Int, the model serializer spits out an error when trying to serialize the issue.

import numpy as np
import pyomo.environ as pyo
import idaes.core.util.model_serializer as ms

m = pyo.ConcreteModel()
m.x = pyo.Var(initialize=0)
m.x.fix(np.array([1])[0])
ms.to_json(m, fname="test.json.gz")

Traceback (most recent call last): File "C:\Users[Redacted]\miniconda3\envs\idaes-new\lib\site-packages\IPython\core\interactiveshell.py", line 3397, in run_code exec(code_obj, self.user_global_ns, self.user_ns) File "", line 1, in <cell line: 1> ms.to_json(m, fname="test.json.gz") File "c:\users[Redacted]\work\idaes-pse\idaes\core\util\model_serializer.py", line 735, in to_json f.write(json.dumps(sd, **dump_kw).encode("utf-8")) File "C:\Users[Redacted]\miniconda3\envs\idaes-new\lib\json__init__.py", line 234, in dumps return cls( File "C:\Users[Redacted]\miniconda3\envs\idaes-new\lib\json\encoder.py", line 199, in encode chunks = self.iterencode(o, _one_shot=True) File "C:\Users[Redacted]\miniconda3\envs\idaes-new\lib\json\encoder.py", line 257, in iterencode return _iterencode(o, 0) File "C:\Users[Redacted]\miniconda3\envs\idaes-new\lib\json\encoder.py", line 179, in default raise TypeError(f'Object of type {o.class.name} ' TypeError: Object of type int32 is not JSON serializable

Note that this exception is not thrown with Numpy float types.

While the code in that minimum example would never be produced naturally, it's easy to run into this issue if you're using Pandas dataframes:

df = pd.read_csv("flowsheet_operating_conditions.csv")

idx = df.last_valid_index()
for var in m.fs.manipulated_variables:
    shortname = var.name.split(".")[-1]
    alias = alias_dict[var]
    var[0].fix(df[alias][idx])

res = solver.solve(m, tee=True)
ms.to_json(m, fname="solution.json.gz")

A workaround is to explicitly cast the dataframe's output to a float or int, as appropriate, before setting/fixing the Pyomo component to a value:

var[0].fix(float(df[alias][idx]))

There may be edge cases where you can get integer overflow, I'm not sure about how Python numeric types compare to Numpy ones.

andrewlee94 commented 2 years ago

I thought Pyomo in general had issues with numpy floats (let alone ints) - I seem to recall having run into issues with this before. Thus, I am wondering if this should be a more general issue of catching numpy representations and casting them to general Python.