Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ See also our [versioning policy](https://amici.readthedocs.io/en/latest/versioni
This is a wrapper for both `amici.run_simulation` and
`amici.run_simulations`, depending on the type of the `edata` argument.
It also supports passing some `Solver` options as keyword arguments.
* Improved `pickle` support for `amici.{ModelPtr,Solver,ExpData`.
* Improved `pickle` support for `amici.{Model,ModelPtr,Solver,ExpData`.
Note that AMICI's pickling support is only intended for short-term storage
or inter-process communication.
Reading pickled objects after updating AMICI or the model code will almost
certainly fail.
* `amici.ModelPtr` now supports sufficient pickling for use in
multi-processing contexts. This works only if the amici-generated model
* `amici.Model`and `amici.ModelPtr` now support sufficient pickling for use
in multi-processing contexts. This works only if the amici-generated model
package exists in the same file system location and does not change until
unpickling.
* `amici.Solver` is now picklable if amici was built with HDF5 support.
Expand Down
4 changes: 4 additions & 0 deletions python/tests/test_swig_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,10 @@ def test_pickle_model(sbml_example_presimulation_module):
!= model_pickled.get_steady_state_sensitivity_mode()
)

# ensure we can pickle after clone()
model_clone = model.clone()
pickle.loads(pickle.dumps(model_clone))


def test_pickle_edata():
ny = 2
Expand Down
37 changes: 37 additions & 0 deletions swig/model.i
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,38 @@ using namespace amici;
%newobject amici::Model::clone;

%rename(create_solver) amici::Model::get_solver;
%rename(_cpp_model_clone) amici::Model::clone;

%extend amici::Model {
%pythoncode %{
def clone(self):
"""Clone the model instance."""
clone = self._cpp_model_clone()
try:
# copy module reference if present
clone.module = self.module
except Exception:
pass

return clone

def __deepcopy__(self, memo):
return self.clone()

def __reduce__(self):
from amici.swig_wrappers import restore_model, get_model_settings, file_checksum

return (
restore_model,
(
self.get_name(),
Path(self.module.__spec__.origin).parent,
get_model_settings(self),
file_checksum(self.module.extension_path),
),
{}
)

@overload
def simulate(
self: AmiciModel,
Expand Down Expand Up @@ -192,6 +218,17 @@ def simulate(

%extend std::unique_ptr<amici::Model> {
%pythoncode %{
def clone(self):
"""Clone the model instance."""
clone = self._cpp_model_clone()
try:
# copy module reference if present
clone.module = self.module
except Exception:
pass

return clone

def __deepcopy__(self, memo):
return self.clone()

Expand Down
Loading