xtb-python icon indicating copy to clipboard operation
xtb-python copied to clipboard

Cannot deepcopy the Atoms object post calculation

Open Andrew-S-Rosen opened this issue 4 years ago • 2 comments

Currently, it is not possible to deepcopy() the Atoms object after an xTB calculation with the ASE interface.

from copy import deepcopy
from xtb.ase.calculator import XTB
from ase.build import molecule
atoms = molecule("H2")
atoms.calc = XTB(method="GFN2-xTB")
atoms.get_potential_energy()
deepcopy(atoms)

Returns:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/tmp/ipykernel_3220/591948702.py in <module>
      5 atoms.calc = XTB(method="GFN2-xTB")
      6 atoms.get_potential_energy()
----> 7 deepcopy(atoms)

~/anaconda3/envs/xtb/lib/python3.8/copy.py in deepcopy(x, memo, _nil)
    170                     y = x
    171                 else:
--> 172                     y = _reconstruct(x, memo, *rv)
    173 
    174     # If is its own copy, don't memoize.

~/anaconda3/envs/xtb/lib/python3.8/copy.py in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    268     if state is not None:
    269         if deep:
--> 270             state = deepcopy(state, memo)
    271         if hasattr(y, '__setstate__'):
    272             y.__setstate__(state)

~/anaconda3/envs/xtb/lib/python3.8/copy.py in deepcopy(x, memo, _nil)
    144     copier = _deepcopy_dispatch.get(cls)
    145     if copier is not None:
--> 146         y = copier(x, memo)
    147     else:
    148         if issubclass(cls, type):

~/anaconda3/envs/xtb/lib/python3.8/copy.py in _deepcopy_dict(x, memo, deepcopy)
    228     memo[id(x)] = y
    229     for key, value in x.items():
--> 230         y[deepcopy(key, memo)] = deepcopy(value, memo)
    231     return y
    232 d[dict] = _deepcopy_dict

~/anaconda3/envs/xtb/lib/python3.8/copy.py in deepcopy(x, memo, _nil)
    170                     y = x
    171                 else:
--> 172                     y = _reconstruct(x, memo, *rv)
    173 
    174     # If is its own copy, don't memoize.

~/anaconda3/envs/xtb/lib/python3.8/copy.py in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    268     if state is not None:
    269         if deep:
--> 270             state = deepcopy(state, memo)
    271         if hasattr(y, '__setstate__'):
    272             y.__setstate__(state)

~/anaconda3/envs/xtb/lib/python3.8/copy.py in deepcopy(x, memo, _nil)
    144     copier = _deepcopy_dispatch.get(cls)
    145     if copier is not None:
--> 146         y = copier(x, memo)
    147     else:
    148         if issubclass(cls, type):

~/anaconda3/envs/xtb/lib/python3.8/copy.py in _deepcopy_dict(x, memo, deepcopy)
    228     memo[id(x)] = y
    229     for key, value in x.items():
--> 230         y[deepcopy(key, memo)] = deepcopy(value, memo)
    231     return y
    232 d[dict] = _deepcopy_dict

~/anaconda3/envs/xtb/lib/python3.8/copy.py in deepcopy(x, memo, _nil)
    170                     y = x
    171                 else:
--> 172                     y = _reconstruct(x, memo, *rv)
    173 
    174     # If is its own copy, don't memoize.

~/anaconda3/envs/xtb/lib/python3.8/copy.py in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    268     if state is not None:
    269         if deep:
--> 270             state = deepcopy(state, memo)
    271         if hasattr(y, '__setstate__'):
    272             y.__setstate__(state)

~/anaconda3/envs/xtb/lib/python3.8/copy.py in deepcopy(x, memo, _nil)
    144     copier = _deepcopy_dispatch.get(cls)
    145     if copier is not None:
--> 146         y = copier(x, memo)
    147     else:
    148         if issubclass(cls, type):

~/anaconda3/envs/xtb/lib/python3.8/copy.py in _deepcopy_dict(x, memo, deepcopy)
    228     memo[id(x)] = y
    229     for key, value in x.items():
--> 230         y[deepcopy(key, memo)] = deepcopy(value, memo)
    231     return y
    232 d[dict] = _deepcopy_dict

~/anaconda3/envs/xtb/lib/python3.8/copy.py in deepcopy(x, memo, _nil)
    159                     reductor = getattr(x, "__reduce_ex__", None)
    160                     if reductor is not None:
--> 161                         rv = reductor(4)
    162                     else:
    163                         reductor = getattr(x, "__reduce__", None)

TypeError: cannot pickle '_cffi_backend.__CDataGCP' object

Andrew-S-Rosen avatar Jan 25 '22 23:01 Andrew-S-Rosen

Indeed, the API in xtb does not implement a copy function which could be used to create a deepcopy of any API object at the moment. For the ASE Calculator case this wouldn't be an issue since the API objects are (re)created on demand.

Further, I'm not sure what the actual requirements are for implementing a deepcopy mechanism in Python, especially since the objects we want to copy are automatically generated by CFFI from the xtb.hinformation and only represent opaque handles (void*).

awvwgk avatar Jan 26 '22 07:01 awvwgk

Got it, thanks for the info and prompt reply!

Andrew-S-Rosen avatar Jan 26 '22 07:01 Andrew-S-Rosen