cctbx / cctbx_project

Computational Crystallography Toolbox
https://cci.lbl.gov/docs/cctbx
Other
207 stars 111 forks source link

boost.python did not match C++ #996

Open Thomas-yunhui opened 1 week ago

Thomas-yunhui commented 1 week ago

I generated the electron density with the structure factor, and I want to modify the electron density and recreate the structure factor. Here are the code and python error messages。

code: nx, ny, nz = electron_density_map.focus() origin = electron_density_map.origin() electron_density_values = np.array(electron_density_map.as_numpy_array()) for ix in range(nx): for iy in range(ny): for iz in range(nz): electron_density_values[ix, iy, iz] *= 2
modified_electron_density_values = flex.double(electron_density_values.ravel()) modified_electron_density_map = flex.double(flex.grid(nx, ny, nz), modified_electron_density_values) fft_map = fft_map.structure_factors_from_real_map(electron_density_map) structure_factors = fft_map.structure_factors(d_min=1.0)

error messages: Traceback (most recent call last): File "C:\Users\DELL\PycharmProjects\test\main.py", line 205, in modified_electron_density_map = flex.double(flex.grid(nx, ny, nz), modified_electron_density_values) Boost.Python.ArgumentError: Python argument types in double.init(double, grid, double) did not match C++ signature: init(class boost::python::api::object, class boost::python::numpy::ndarray) init(class boost::python::api::object, class boost::python::tuple) init(class boost::python::api::object, class boost::python::list) init(class boost::python::api::object, class std::vector<double,class std::allocator >) init(class boost::python::api::object, class scitbx::af::const_ref<class std::basic_string<char,struct std::char_traits,class std::allocator >,class scitbx::af::trivial_accessor>) init(struct _object __ptr64, class scitbx::af::shared_plain) init(struct _object ptr64, unsigned int64) init(struct _object ptr64, unsigned int64, double) init(struct _object ptr64, class scitbx::af::flex_grid<class scitbx::af::small<long,10> >) init(struct _object * ptr64, class scitbx::af::flex_grid<class scitbx::af::small<long,10> >, double) init(struct _object * __ptr64)

I think: (1)Whether it is because the version of python and C++ does not match, resulting in the problem? (2)Code error in the ”Boost. Python. ArgumentError: Python argument types”, I doubt is the Boost. The Python this package has a problem, may be a need to be updated, or to update the right version. (3)The essence of the error is that the python data structure and the C++ data structure do not match, how to make it match, which is a very important problem.

I would appreciate it if you could help me!

phyy-nx commented 6 days ago

Hi, I think there are a couple ways you could modify your code to make it work. First, you skip the conversion to numpy since sliced assignment in flex works fine:

nx, ny, nz = electron_density_map.focus()
origin = electron_density_map.origin()
for ix in range(nx):
  for iy in range(ny):
    for iz in range(nz):
      electron_density_map[ix, iy, iz] *= 2
fft_map = fft_map.structure_factors_from_real_map(electron_density_map)
structure_factors = fft_map.structure_factors(d_min=1.0)

Alternatively if you wanted to keep the numpy conversion, then reshape I think is what you are looking for:

nx, ny, nz = electron_density_map.focus()
origin = electron_density_map.origin()
electron_density_values = np.array(electron_density_map.as_numpy_array())
for ix in range(nx):
  for iy in range(ny):
    for iz in range(nz):
      electron_density_values[ix, iy, iz] *= 2
modified_electron_density_values = flex.double(electron_density_values.ravel())
modified_electron_density_values.reshape(flex.grid(nx, ny, nz))
fft_map = fft_map.structure_factors_from_real_map(modified_electron_density_values)
structure_factors = fft_map.structure_factors(d_min=1.0)

But here you can also skip the ravel and reshape and use the flex.double constructor directly:

nx, ny, nz = electron_density_map.focus()
origin = electron_density_map.origin()
electron_density_values = np.array(electron_density_map.as_numpy_array())
for ix in range(nx):
  for iy in range(ny):
    for iz in range(nz):
      electron_density_values[ix, iy, iz] *= 2
modified_electron_density_values = flex.double(electron_density_values)
fft_map = fft_map.structure_factors_from_real_map(modified_electron_density_values)
structure_factors = fft_map.structure_factors(d_min=1.0)

Hopefully this helps and I didn't add any typos :)

phyy-nx commented 6 days ago

Also I should add that it doesn't look like there's anything wrong with your boost/c++ here. That traceback is just the boost/c++ traceback style when a function signature isn't matched.