Add Molecular Interaction Fields (#7993)

* Add RealValueVect.

* Add UniformRealValueGrid3D

* Add Molecular Interaction Fields (MIFs)

* line endings

* cherry-pick f1bc94a4c8

* format

* Adapt tests for python3.

* Adapt RealValueVector pickling for python3.

* Speed-up of MIF calculations.

* Bugfix in MIFDescriptors.cpp.

* all tests pass

* clean up some memory leaks

* update copyrights

* rename

* rename the library

* complete the rename

* lost file

* another forgotten file

* cleanup

* clang-tidy

* clang-tidy

* windows DLL builds work

* python wrapper and tests cleanup

* convert to catch2 testing

* switch RealValueVect to use std::vector

* remove obsolete friend

* - Replace explicit loops with stdlib implicit equivalents
- Replace explicit types with auto where possible
- Avoid unnecessary copy operations where possible
- Replace raw pointers with exception-safe unique_ptr
- Replace C-style #define with constexpr
- Replace C-style casts with C++ casts
- Replace C-style arrays with std::vector
- Avoid code duplication with templated operators
- Replace VdWaals class taking multiple atom type definitions and force-field name as string parameter with force-field-specific classes deriving from an abstract VdWaals class
- Replace x,y,z doubles with Point3D class where possible
- Removed unused (and untested) DistanceToClosestAtom class
- Renamed some variables and functions for better clarity
- Converted tabs to spaces
- Made the mol parameter in cube read/write functions optional for convenience
- Made the Python wrappers more pythonic (e.g., avoid C++-style passing objects as parameters which are modified in place)
- Implemented alternative Python class constructors using boost::python::make_constructor rather than with external non-class functions
- The Python wrappers taking a sequence of Point3D now take a sequence of sequences, such that the output of Conformer.GetPositions() can be passed
- Made the Python wrapper sequence parsing more robust
- Removed duplicated code from Python wrappers

* - avoid an unnecessary copy

* progress

* works

* more cleanup

* all tests pass

* changes in response to review

---------

Co-authored-by: dfhahn <dfhahn@users.noreply.github.com>
Co-authored-by: ptosco <paolo.tosco@novartis.com>
This commit is contained in:
Greg Landrum
2024-12-14 17:08:43 +01:00
committed by GitHub
parent 6db3f982cb
commit c90cee9b77
70 changed files with 6963 additions and 33 deletions

View File

@@ -1,7 +1,8 @@
rdkit_library(RDGeometryLib
point.cpp Transform2D.cpp Transform3D.cpp
UniformGrid3D.cpp GridUtils.cpp
UniformGrid3D.cpp UniformRealValueGrid3D.cpp
GridUtils.cpp
LINK_LIBRARIES DataStructs RDGeneral)
target_compile_definitions(RDGeometryLib PRIVATE RDKIT_RDGEOMETRYLIB_BUILD)
@@ -12,13 +13,16 @@ rdkit_headers(Grid3D.h
Transform3D.h
Transform.h
UniformGrid3D.h
UniformRealValueGrid3D.h
Utils.h DEST Geometry)
rdkit_test(testTransforms testTransforms.cpp LINK_LIBRARIES RDGeometryLib )
rdkit_test(testGrid testGrid.cpp LINK_LIBRARIES RDGeometryLib)
rdkit_test(testRealValueGrid testRealValueGrid.cpp LINK_LIBRARIES RDGeometryLib DataStructs RDGeneral)
rdkit_catch_test(geometryTestsCatch catch_tests.cpp
LINK_LIBRARIES RDGeometryLib)
if(RDK_BUILD_PYTHON_WRAPPERS)
add_subdirectory(Wrap)
endif()

View File

@@ -35,20 +35,19 @@ class RDKIT_RDGEOMETRYLIB_EXPORT GridException : public std::exception {
};
//! Virtual base class for a grid object
template <typename VectorType, typename ValueType1, typename ValueType2>
class RDKIT_RDGEOMETRYLIB_EXPORT Grid3D {
public:
virtual ~Grid3D() {}
virtual ~Grid3D(){};
virtual int getGridPointIndex(const Point3D &point) const = 0;
virtual int getVal(const Point3D &point) const = 0;
virtual void setVal(const Point3D &point, unsigned int val) = 0;
virtual ValueType1 getVal(const Point3D &point) const = 0;
virtual void setVal(const Point3D &point, ValueType2 val) = 0;
virtual Point3D getGridPointLoc(unsigned int pointId) const = 0;
virtual unsigned int getVal(unsigned int pointId) const = 0;
virtual void setVal(unsigned int pointId, unsigned int val) = 0;
virtual ValueType2 getVal(unsigned int pointId) const = 0;
virtual void setVal(unsigned int pointId, ValueType2 val) = 0;
virtual unsigned int getSize() const = 0;
virtual const RDKit::DiscreteValueVect *getOccupancyVect() const = 0;
virtual const VectorType *getOccupancyVect() const = 0;
};
} // namespace RDGeom

View File

@@ -73,11 +73,11 @@ void UniformGrid3D::initGrid(
UniformGrid3D::UniformGrid3D(const std::string &pkl) {
dp_storage = nullptr;
this->initFromText(pkl.c_str(), pkl.size());
initFromText(pkl.c_str(), pkl.size());
}
UniformGrid3D::UniformGrid3D(const char *pkl, const unsigned int len) {
dp_storage = nullptr;
this->initFromText(pkl, len);
initFromText(pkl, len);
}
UniformGrid3D::~UniformGrid3D() {
@@ -181,7 +181,7 @@ bool UniformGrid3D::compareParams(const UniformGrid3D &other) const {
void UniformGrid3D::setSphereOccupancy(const Point3D &center, double radius,
double stepSize, int maxNumLayers,
bool ignoreOutOfBound) {
int ptIndex = this->getGridPointIndex(center);
int ptIndex = getGridPointIndex(center);
if (ptIndex == -1) {
if (ignoreOutOfBound) {
return;

View File

@@ -8,8 +8,8 @@
// of the RDKit source tree.
//
#include <RDGeneral/export.h>
#ifndef _UNIFORMGRID3D_H_20050124_1703
#define _UNIFORMGRID3D_H_20050124_1703
#ifndef UNIFORMGRID3D_H_20050124_1703
#define UNIFORMGRID3D_H_20050124_1703
#include "point.h"
#include <DataStructs/DiscreteValueVect.h>
@@ -17,7 +17,8 @@
#include <iostream>
namespace RDGeom {
class RDKIT_RDGEOMETRYLIB_EXPORT UniformGrid3D : public Grid3D {
class RDKIT_RDGEOMETRYLIB_EXPORT UniformGrid3D
: public Grid3D<RDKit::DiscreteValueVect, int, unsigned int> {
public:
//! \brief ctor
/*
@@ -28,13 +29,13 @@ class RDKIT_RDGEOMETRYLIB_EXPORT UniformGrid3D : public Grid3D {
\param valType: the data type of the grid (determines the number of bits
per point)
\param offset: OPTIONAL: the offset of the grid from (0,0,0), in
Angstroms.
Angstroms.
\b Note: the values of arguments such as \c dimX and \c spacing
don't actually need to be in Angstroms, but they should be internally
consistent.
\b Note: the values of arguments such as \c dimX and \c spacing
don't actually need to be in Angstroms, but they should be internally
consistent.
*/
*/
UniformGrid3D(double dimX, double dimY, double dimZ, double spacing = 0.5,
RDKit::DiscreteValueVect::DiscreteValueType valType =
RDKit::DiscreteValueVect::TWOBITVALUE,

View File

@@ -0,0 +1,319 @@
//
// Copyright (c) 2014-2024, Novartis Institutes for BioMedical Research and
// other RDKit contributors
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
// The contents are covered by the terms of the BSD license
// which is included in the file license.txt, found at the root
// of the RDKit source tree.
//
#include "UniformRealValueGrid3D.h"
#include <DataStructs/RealValueVect.h>
#include <RDGeneral/StreamOps.h>
#include <RDGeneral/Exceptions.h>
#include <Geometry/point.h>
#include <fstream>
#include <iomanip>
using namespace RDKit;
namespace {
constexpr double OFFSET_TOL = 1.e-4;
constexpr double SPACING_TOL = 1.e-4;
constexpr const char *INCOMPATIBLE_GRIDS = "incompatible grids";
} // end anonymous namespace
namespace RDGeom {
std::int32_t ci_RealValueGrid3DPICKLE_VERSION = 0x1;
UniformRealValueGrid3D::UniformRealValueGrid3D(
const UniformRealValueGrid3D &other) {
UniformRealValueGrid3D::initGrid(
other.d_numX * other.d_spacing, other.d_numY * other.d_spacing,
other.d_numZ * other.d_spacing, other.d_spacing, other.d_offSet,
&other.d_storage);
}
void UniformRealValueGrid3D::initGrid(double dimX, double dimY, double dimZ,
double spacing,
const RDGeom::Point3D &offSet,
const RDKit::RealValueVect *data) {
PRECONDITION(dimX > 0.0, "Invalid x-dimension for grid");
PRECONDITION(dimY > 0.0, "Invalid y-dimension for grid");
PRECONDITION(dimZ > 0.0, "Invalid z-dimension for grid");
PRECONDITION(spacing > 0.0, "Invalid spacing for grid");
d_numX = static_cast<unsigned int>(floor(dimX / spacing + 0.5));
d_numY = static_cast<unsigned int>(floor(dimY / spacing + 0.5));
d_numZ = static_cast<unsigned int>(floor(dimZ / spacing + 0.5));
// PRECONDITION((!data)||data->getValueType()==double,"grid data type
// mismatch");
PRECONDITION(!data || data->size() == d_numX * d_numY * d_numZ,
"grid data size mismatch");
d_spacing = spacing;
d_offSet = offSet;
if (!data) {
d_storage.setLength(d_numX * d_numY * d_numZ);
d_storage.setToVal(0.0);
} else {
d_storage = *data;
}
}
UniformRealValueGrid3D::UniformRealValueGrid3D(const std::string &pkl) {
initFromText(pkl.c_str(), pkl.size());
}
UniformRealValueGrid3D::UniformRealValueGrid3D(const char *pkl,
unsigned int len) {
initFromText(pkl, len);
}
int UniformRealValueGrid3D::getGridIndex(unsigned int xi, unsigned int yi,
unsigned int zi) const {
if (xi >= d_numX) {
return -1;
}
if (yi >= d_numY) {
return -1;
}
if (zi >= d_numZ) {
return -1;
}
return (zi * d_numX * d_numY + yi * d_numX + xi);
}
void UniformRealValueGrid3D::getGridIndices(unsigned int idx, unsigned int &xi,
unsigned int &yi,
unsigned int &zi) const {
if (idx >= d_numX * d_numY * d_numZ) {
throw IndexErrorException(idx);
}
xi = idx % d_numX;
yi = (idx % (d_numX * d_numY)) / d_numX;
zi = idx / (d_numX * d_numY);
}
int UniformRealValueGrid3D::getGridPointIndex(
const RDGeom::Point3D &point) const {
auto tPt = point;
tPt -= d_offSet; // d_origin;
tPt /= d_spacing;
constexpr double move = 0.5;
auto xi = static_cast<int>(floor(tPt.x + move));
auto yi = static_cast<int>(floor(tPt.y + move));
auto zi = static_cast<int>(floor(tPt.z + move));
if ((xi < 0) || (xi >= static_cast<int>(d_numX))) {
return -1;
}
if ((yi < 0) || (yi >= static_cast<int>(d_numY))) {
return -1;
}
if ((zi < 0) || (zi >= static_cast<int>(d_numZ))) {
return -1;
}
return (zi * d_numX * d_numY + yi * d_numX + xi);
}
double UniformRealValueGrid3D::getVal(const RDGeom::Point3D &point) const {
auto id = getGridPointIndex(point);
if (id < 0) {
return -1;
}
return d_storage.getVal(static_cast<unsigned int>(id));
}
double UniformRealValueGrid3D::getVal(unsigned int pointId) const {
return d_storage.getVal(pointId);
}
void UniformRealValueGrid3D::setVal(const RDGeom::Point3D &point, double val) {
auto id = getGridPointIndex(point);
if (id < 0) {
return;
}
d_storage.setVal(static_cast<unsigned int>(id), val);
}
RDGeom::Point3D UniformRealValueGrid3D::getGridPointLoc(
unsigned int pointId) const {
if (pointId >= d_numX * d_numY * d_numZ) {
throw IndexErrorException(pointId);
}
RDGeom::Point3D res((pointId % d_numX) * d_spacing,
((pointId % (d_numX * d_numY)) / d_numX) * d_spacing,
(pointId / (d_numX * d_numY)) * d_spacing);
res += d_offSet; // d_origin;
return res;
}
void UniformRealValueGrid3D::setVal(unsigned int pointId, double val) {
d_storage.setVal(pointId, val);
}
bool UniformRealValueGrid3D::compareParams(
const UniformRealValueGrid3D &other) const {
if (d_numX != other.getNumX()) {
return false;
}
if (d_numY != other.getNumY()) {
return false;
}
if (d_numZ != other.getNumZ()) {
return false;
}
if (fabs(d_spacing - other.getSpacing()) > SPACING_TOL) {
return false;
}
auto dOffset = d_offSet;
dOffset -= other.getOffset();
return dOffset.lengthSq() <= OFFSET_TOL;
}
bool UniformRealValueGrid3D::compareVectors(
const UniformRealValueGrid3D &other) const {
return d_storage.compareVectors(other.d_storage);
}
bool UniformRealValueGrid3D::compareGrids(
const UniformRealValueGrid3D &other) const {
if (!compareParams(other)) {
return false;
}
return d_storage.compareVectors(other.d_storage);
}
UniformRealValueGrid3D &UniformRealValueGrid3D::operator=(
const UniformRealValueGrid3D &other) {
if (this == &other) {
return *this;
}
d_numX = other.d_numX;
d_numY = other.d_numY;
d_numZ = other.d_numZ;
d_spacing = other.d_spacing;
d_offSet = other.d_offSet;
d_storage = other.d_storage;
return *this;
}
UniformRealValueGrid3D &UniformRealValueGrid3D::operator|=(
const UniformRealValueGrid3D &other) {
PRECONDITION(compareParams(other), INCOMPATIBLE_GRIDS);
d_storage |= other.d_storage;
return *this;
}
UniformRealValueGrid3D &UniformRealValueGrid3D::operator&=(
const UniformRealValueGrid3D &other) {
PRECONDITION(compareParams(other), INCOMPATIBLE_GRIDS);
d_storage &= other.d_storage;
return *this;
}
UniformRealValueGrid3D &UniformRealValueGrid3D::operator+=(
const UniformRealValueGrid3D &other) {
PRECONDITION(compareParams(other), INCOMPATIBLE_GRIDS);
d_storage += other.d_storage;
return *this;
}
UniformRealValueGrid3D &UniformRealValueGrid3D::operator-=(
const UniformRealValueGrid3D &other) {
PRECONDITION(compareParams(other), INCOMPATIBLE_GRIDS);
d_storage -= other.d_storage;
return *this;
}
std::string UniformRealValueGrid3D::toString() const {
std::stringstream ss(std::ios_base::binary | std::ios_base::out |
std::ios_base::in);
std::int32_t tVers = ci_RealValueGrid3DPICKLE_VERSION * -1;
streamWrite(ss, tVers);
std::uint32_t tInt;
tInt = d_numX;
streamWrite(ss, tInt);
tInt = d_numY;
streamWrite(ss, tInt);
tInt = d_numZ;
streamWrite(ss, tInt);
streamWrite(ss, d_spacing);
streamWrite(ss, d_offSet.x);
streamWrite(ss, d_offSet.y);
streamWrite(ss, d_offSet.z);
std::string storePkl = d_storage.toString();
std::uint32_t pklSz = storePkl.size();
streamWrite(ss, pklSz);
ss.write(storePkl.c_str(), pklSz * sizeof(char));
return ss.str();
}
void UniformRealValueGrid3D::initFromText(const char *pkl,
const unsigned int length) {
std::stringstream ss(std::ios_base::binary | std::ios_base::in |
std::ios_base::out);
ss.write(pkl, length);
std::int32_t tVers;
streamRead(ss, tVers);
tVers = -tVers;
if (tVers != 0x1) {
throw ValueErrorException("bad version in UniformRealValueGrid3D pickle");
}
std::uint32_t tInt;
streamRead(ss, tInt);
d_numX = tInt;
streamRead(ss, tInt);
d_numY = tInt;
streamRead(ss, tInt);
d_numZ = tInt;
streamRead(ss, d_spacing);
double oX, oY, oZ;
streamRead(ss, oX);
streamRead(ss, oY);
streamRead(ss, oZ);
d_offSet = RDGeom::Point3D(oX, oY, oZ);
std::uint32_t pklSz;
streamRead(ss, pklSz);
std::vector<char> buff(pklSz);
ss.read(buff.data(), pklSz * sizeof(char));
d_storage = RDKit::RealValueVect(buff.data(), pklSz);
}
UniformRealValueGrid3D operator&(const UniformRealValueGrid3D &grd1,
const UniformRealValueGrid3D &grd2) {
UniformRealValueGrid3D ans(grd1);
ans &= grd2;
return ans;
};
UniformRealValueGrid3D operator|(const UniformRealValueGrid3D &grd1,
const UniformRealValueGrid3D &grd2) {
UniformRealValueGrid3D ans(grd1);
ans |= grd2;
return ans;
};
UniformRealValueGrid3D operator+(const UniformRealValueGrid3D &grd1,
const UniformRealValueGrid3D &grd2) {
UniformRealValueGrid3D ans(grd1);
ans += grd2;
return ans;
};
UniformRealValueGrid3D operator-(const UniformRealValueGrid3D &grd1,
const UniformRealValueGrid3D &grd2) {
UniformRealValueGrid3D ans(grd1);
ans -= grd2;
return ans;
};
} // namespace RDGeom

View File

@@ -0,0 +1,201 @@
//
// Copyright (c) 2014-2024, Novartis Institutes for BioMedical Research and
// other RDKit contributors
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
// The contents are covered by the terms of the BSD license
// which is included in the file license.txt, found at the root
// of the RDKit source tree.
//
#include <RDGeneral/export.h>
#ifndef UNIFORMREALVALUEGRID3D_H_20140403
#define UNIFORMREALVALUEGRID3D_H_20140403
#include <DataStructs/RealValueVect.h>
#include <Geometry/point.h>
#include "Grid3D.h"
namespace RDGeom {
class RDKIT_RDGEOMETRYLIB_EXPORT UniformRealValueGrid3D
: public Grid3D<RDKit::RealValueVect, double, double> {
public:
UniformRealValueGrid3D() { initGrid(1.0, 1.0, 1.0, 1.0, RDGeom::Point3D()); };
//! \brief ctor
/*
\param dimX: the x dimension of the grid, in Angstroms
\param dimY: the y dimension of the grid, in Angstroms
\param dimZ: the z dimension of the grid, in Angstroms
\param spacing: the grid spacing, in Angstroms
\param offset: OPTIONAL: the offset of the grid from (0,0,0), in
Angstroms.
\b Note: the values of arguments such as \c dimX and \c spacing
don't actually need to be in Angstroms, but they should be internally
consistent.
*/
UniformRealValueGrid3D(double dimX, double dimY, double dimZ,
double spacing = 0.5,
const RDGeom::Point3D *offset = nullptr,
const RDKit::RealValueVect *data = nullptr) {
if (offset == nullptr) {
initGrid(dimX, dimY, dimZ, spacing,
RDGeom::Point3D(-0.5 * dimX, -0.5 * dimY, -0.5 * dimZ), data);
} else {
initGrid(dimX, dimY, dimZ, spacing, *offset, data);
}
}
UniformRealValueGrid3D(const UniformRealValueGrid3D &other);
UniformRealValueGrid3D &operator=(const UniformRealValueGrid3D &other);
//! construct from a string pickle
UniformRealValueGrid3D(const std::string &pkl);
//! construct from a text pickle
UniformRealValueGrid3D(const char *pkl, unsigned int);
//! \brief Get the index of the grid point closest to point
//!
//! \return the integer index, -1 if the specified point is outside the grid
int getGridPointIndex(const RDGeom::Point3D &point) const override;
//! \brief Get the value at the grid point closest to the specified point
//!
//! \return the double value, -1 if the specified index is outside the grid
double getVal(const RDGeom::Point3D &point) const override;
//! \brief Get the value at a specified grid point
//!
//! \return the double value
double getVal(unsigned int pointId) const override;
//! \brief Set the value at the grid point closest to the specified point
//!
//! doesn't do anything if the point is outside the grid
void setVal(const RDGeom::Point3D &point, double val) override;
//! \brief get the location of the specified grid point
RDGeom::Point3D getGridPointLoc(unsigned int pointId) const override;
//! \brief Set the value at the specified grid point
void setVal(unsigned int pointId, double val) override;
//! \brief get the size of the grid (number of grid points)
unsigned int getSize() const override { return d_numX * d_numY * d_numZ; };
//! \brief get the index of the grid point given the x, y, z indices
//!
//! \return the integer value, -1 if the indices are outside the grid
int getGridIndex(unsigned int xi, unsigned int yi, unsigned int zi) const;
//! \brief get the x, y, and z indices of a grid-point index
//!
void getGridIndices(unsigned int idx, unsigned int &xi, unsigned int &yi,
unsigned int &zi) const;
//! \brief get the number of grid points along x-axis
unsigned int getNumX() const { return d_numX; };
//! \brief get the number of grid points along y-axis
unsigned int getNumY() const { return d_numY; };
//! \brief get the number of grid points along z-axis
unsigned int getNumZ() const { return d_numZ; };
//! \brief get the grid's offset
const RDGeom::Point3D &getOffset() const { return d_offSet; };
//! \brief get the grid's spacing
double getSpacing() const { return d_spacing; };
//! \brief return a \b const pointer to our occupancy vector
const RDKit::RealValueVect *getOccupancyVect() const override {
return &d_storage;
};
//! brief returns raw vector
const std::vector<double> &getData() const { return d_storage.getData(); }
std::vector<double> &getData() { return d_storage.getData(); }
//! \brief returns true if the grid \c other has parameters
//! compatible with ours.
bool compareParams(const UniformRealValueGrid3D &other) const;
//! \brief returns true if the grid \c other has the same values
//! as ours.
bool compareVectors(const UniformRealValueGrid3D &other) const;
//! \brief returns true if the grid \c other has the same parameters and
//! values as ours.
bool compareGrids(const UniformRealValueGrid3D &other) const;
//! \brief calculates the union between the data on this grid and
//! that on \c other.
//! This grid is modified.
//! NOTE that the grids must have the same parameters.
UniformRealValueGrid3D &operator|=(const UniformRealValueGrid3D &other);
//! \brief calculates the intersection between the data on this grid and
//! that on \c other.
//! This grid is modified.
//! NOTE that the grids must have the same parameters.
UniformRealValueGrid3D &operator&=(const UniformRealValueGrid3D &other);
//! \brief calculates the sum of the data on this grid and
//! that on \c other.
//! This grid is modified.
//! NOTE that the grids must have the same parameters.
UniformRealValueGrid3D &operator+=(const UniformRealValueGrid3D &other);
//! \brief calculates the difference between the data on this grid and
//! that on \c other.
//! This grid is modified.
//! NOTE that the grids must have the same parameters.
UniformRealValueGrid3D &operator-=(const UniformRealValueGrid3D &other);
//! \brief create and return a pickle
std::string toString() const;
/*
UniformRealValueGrid3D operator& (const UniformRealValueGrid3D &other) const{
PRECONDITION(dp_storage,"bad storage");
PRECONDITION(compareParams(other),"mismatched params");
UniformRealValueGrid3D
res(d_numX*d_spacing,d_numY*d_spacing,d_numZ*d_spacing, d_spacing,&d_offSet);
return res;
};*/
private:
//! \brief internal initialization code
/*
\param dimX: the x dimension of the grid, in Angstroms
\param dimY: the y dimension of the grid, in Angstroms
\param dimZ: the z dimension of the grid, in Angstroms
\param spacing: the grid spacing, in Angstroms
\param offset: the offset of the grid from (0,0,0), in Angstroms.
\param data: (optional) a pointer to a DoubleVector to use, we take
ownership of the pointer.
*/
void initGrid(double dimX, double dimY, double dimZ, double spacing,
const RDGeom::Point3D &offSet,
const RDKit::RealValueVect *data = nullptr);
unsigned int d_numX, d_numY,
d_numZ; //! number of grid points along x, y, z axes
double d_spacing; //! grid spacing
RDGeom::Point3D d_offSet; //! the grid offset (from the origin)
RDKit::RealValueVect d_storage; //! storage for values at each grid point
//! \brief construct from a pickle
void initFromText(const char *pkl, const unsigned int length);
};
RDKIT_RDGEOMETRYLIB_EXPORT UniformRealValueGrid3D operator|(
const UniformRealValueGrid3D &grd1, const UniformRealValueGrid3D &grd2);
RDKIT_RDGEOMETRYLIB_EXPORT UniformRealValueGrid3D operator&(
const UniformRealValueGrid3D &grd1, const UniformRealValueGrid3D &grd2);
RDKIT_RDGEOMETRYLIB_EXPORT UniformRealValueGrid3D operator+(
const UniformRealValueGrid3D &grd1, const UniformRealValueGrid3D &grd2);
RDKIT_RDGEOMETRYLIB_EXPORT UniformRealValueGrid3D operator-(
const UniformRealValueGrid3D &grd1, const UniformRealValueGrid3D &grd2);
} // namespace RDGeom
#endif

View File

@@ -1,6 +1,6 @@
remove_definitions(-DRDKIT_RDGEOMETRYLIB_BUILD)
rdkit_python_extension(rdGeometry
Point.cpp UniformGrid3D.cpp rdGeometry.cpp
Point.cpp UniformGrid3D.cpp UniformRealValueGrid3D.cpp rdGeometry.cpp
DEST Geometry
LINK_LIBRARIES RDGeometryLib)

View File

@@ -0,0 +1,128 @@
//
// Copyright (c) 2014-2024, Novartis Institutes for BioMedical Research and
// other RDKit contributors
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
// The contents are covered by the terms of the BSD license
// which is included in the file license.txt, found at the root
// of the RDKit source tree.
//
#include <boost/python.hpp>
#include <RDBoost/Wrap.h>
#include <RDGeneral/types.h>
#include <RDGeneral/Invariant.h>
#include <DataStructs/RealValueVect.h>
#include <Geometry/point.h>
#include <Geometry/UniformRealValueGrid3D.h>
#include <Geometry/GridUtils.h>
namespace python = boost::python;
using namespace RDKit;
namespace RDGeom {
struct urvg3d_pickle_suite : rdkit_pickle_suite {
static python::tuple getinitargs(const UniformRealValueGrid3D &self) {
auto res = self.toString();
python::object retval(
python::handle<>(PyBytes_FromStringAndSize(res.c_str(), res.length())));
return python::make_tuple(retval);
}
};
UniformRealValueGrid3D *makeUniformRealValueGrid3D(
double dimX, double dimY, double dimZ, double spacing = 0.5,
const Point3D *offSet = nullptr) {
UniformRealValueGrid3D *grd =
new UniformRealValueGrid3D(dimX, dimY, dimZ, spacing, offSet);
return grd;
}
double getValPoint(const UniformRealValueGrid3D &grid, const Point3D &pt) {
return grid.getVal(pt);
}
double getValIndex(const UniformRealValueGrid3D &grid, unsigned int id) {
return grid.getVal(id);
}
void setValIndex(UniformRealValueGrid3D &grid, unsigned int id, double val) {
grid.setVal(id, val);
}
void setValPoint(UniformRealValueGrid3D &grid, const Point3D &pt, double val) {
grid.setVal(pt, val);
}
python::tuple getGridIndicesWrap(const UniformRealValueGrid3D &grid,
unsigned int idx) {
unsigned int xi, yi, zi;
grid.getGridIndices(idx, xi, yi, zi);
return python::make_tuple(xi, yi, zi);
}
std::string urvGridClassDoc =
"Class to represent a uniform three-dimensional\n\
cubic grid. Each grid point can store a floating point value. \n";
struct urvGrid3D_wrapper {
static void wrap() {
python::class_<UniformRealValueGrid3D>(
"UniformRealValueGrid3D", urvGridClassDoc.c_str(),
python::init<std::string>("Pickle constructor"))
.def(python::init<>("Default constructor"))
.def(python::init<RDGeom::UniformRealValueGrid3D>("Copy constructor"))
.def("__init__",
python::make_constructor(
makeUniformRealValueGrid3D, python::default_call_policies(),
(python::arg("dimX"), python::arg("dimY"), python::arg("dimZ"),
python::arg("spacing") = 0.5,
python::arg("offSet") = python::object())),
"Constructor")
.def("GetGridPointIndex", &UniformRealValueGrid3D::getGridPointIndex,
"Get the index to the grid point closest to the specified point")
.def(
"GetGridIndex", &UniformRealValueGrid3D::getGridIndex,
"Get the index to the grid point with the three integer indices provided")
.def("GetGridIndices", &getGridIndicesWrap,
"Returns the integer indices of the grid index provided.")
.def("GetValPoint", getValPoint,
"Get the value at the closest grid point")
.def("GetVal", getValIndex, "Get the value at the specified grid point")
.def("SetVal", setValIndex, "Set the value at the specified grid point")
.def("SetValPoint", setValPoint,
"Set the value at grid point closest to the specified point")
.def("GetGridPointLoc", &UniformRealValueGrid3D::getGridPointLoc,
"Get the location of the specified grid point")
.def("GetSize", &UniformRealValueGrid3D::getSize,
"Get the size of the grid (number of grid points)")
.def("GetNumX", &UniformRealValueGrid3D::getNumX,
"Get the number of grid points along x-axis")
.def("GetNumY", &UniformRealValueGrid3D::getNumY,
"Get the number of grid points along y-axis")
.def("GetNumZ", &UniformRealValueGrid3D::getNumZ,
"Get the number of grid points along z-axis")
.def("GetOffset", &UniformRealValueGrid3D::getOffset,
python::return_value_policy<python::copy_const_reference>(),
"Get the location of the center of the grid")
.def("GetSpacing", &UniformRealValueGrid3D::getSpacing,
"Get the grid spacing")
.def("GetOccupancyVect", &UniformRealValueGrid3D::getOccupancyVect,
python::return_value_policy<python::reference_existing_object>(),
"Get the occupancy vector for the grid")
.def("CompareVectors", &UniformRealValueGrid3D::compareVectors,
"Compare the vector values between two grid objects.")
.def("CompareParams", &UniformRealValueGrid3D::compareParams,
"Compare the parameters between two grid object.")
.def("CompareGrids", &UniformRealValueGrid3D::compareGrids,
"Compare the parameters and values between two grid objects.")
.def(python::self &= python::self)
.def(python::self |= python::self)
.def(python::self += python::self)
.def(python::self -= python::self)
.def_pickle(RDGeom::urvg3d_pickle_suite());
}
};
} // namespace RDGeom
void wrap_uniformrealvalueGrid() { RDGeom::urvGrid3D_wrapper::wrap(); }

View File

@@ -14,6 +14,7 @@
namespace python = boost::python;
void wrap_point();
void wrap_uniformGrid();
void wrap_uniformrealvalueGrid();
BOOST_PYTHON_MODULE(rdGeometry) {
python::scope().attr("__doc__") =
@@ -21,4 +22,5 @@ BOOST_PYTHON_MODULE(rdGeometry) {
wrap_point();
wrap_uniformGrid();
wrap_uniformrealvalueGrid();
}

View File

@@ -406,6 +406,405 @@ class TestCase(unittest.TestCase):
self.assertEqual(p2.x, p3.x)
self.assertEqual(p2.y, p3.y)
def test1bPoint2D(self):
pt = geom.Point2D()
self.assertTrue(feq(pt.x, 0.0))
self.assertTrue(feq(pt.y, 0.0))
pt = geom.Point2D(3., 4.)
self.assertTrue(feq(pt.x, 3.0))
self.assertTrue(feq(pt.y, 4.0))
self.assertTrue(feq(pt.x, 3.0))
self.assertTrue(feq(pt.y, 4.0))
self.assertTrue(feq(pt[0], 3.0))
self.assertTrue(feq(pt[1], 4.0))
self.assertTrue(feq(pt[-2], 3.0))
self.assertTrue(feq(pt[-1], 4.0))
lst = list(pt)
self.assertTrue(feq(lst[0], 3.0))
self.assertTrue(feq(lst[1], 4.0))
pt2 = geom.Point2D(1., 1.)
pt3 = pt + pt2
self.assertTrue(feq(pt3.x, 4.0))
self.assertTrue(feq(pt3.y, 5.0))
pt += pt2
self.assertTrue(feq(pt.x, 4.0))
self.assertTrue(feq(pt.y, 5.0))
pt3 = pt - pt2
self.assertTrue(feq(pt3.x, 3.0))
self.assertTrue(feq(pt3.y, 4.0))
pt -= pt2
self.assertTrue(feq(pt.x, 3.0))
self.assertTrue(feq(pt.y, 4.0))
pt *= 2.0
self.assertTrue(feq(pt.x, 6.0))
self.assertTrue(feq(pt.y, 8.0))
pt /= 2
self.assertTrue(feq(pt.x, 3.0))
self.assertTrue(feq(pt.y, 4.0))
self.assertTrue(feq(pt.Length(), 5.0))
self.assertTrue(feq(pt.LengthSq(), 25.0))
pt.Normalize()
self.assertTrue(feq(pt.Length(), 1.0))
pt1 = geom.Point2D(1.0, 0.0)
pt2 = geom.Point2D(2.0 * math.cos(math.pi / 6), 2.0 * math.sin(math.pi / 6))
ang = pt1.AngleTo(pt2)
self.assertTrue(feq(ang, math.pi / 6))
prod = pt1.DotProduct(pt2)
self.assertTrue(feq(prod, 2.0 * math.cos(math.pi / 6)))
def test1cPointND(self):
dim = 4
pt = geom.PointND(4)
for i in range(dim):
self.assertTrue(feq(pt[i], 0.0))
pt[0] = 3
pt[3] = 4
self.assertTrue(feq(pt[0], 3.0))
self.assertTrue(feq(pt[3], 4.0))
self.assertTrue(feq(pt[-4], 3.0))
self.assertTrue(feq(pt[-1], 4.0))
lst = list(pt)
self.assertTrue(feq(lst[0], 3.0))
self.assertTrue(feq(lst[3], 4.0))
pt2 = geom.PointND(4)
pt2[0] = 1.
pt2[2] = 1.
pt3 = pt + pt2
self.assertTrue(feq(pt3[0], 4.0))
self.assertTrue(feq(pt3[2], 1.0))
self.assertTrue(feq(pt3[3], 4.0))
pt += pt2
self.assertTrue(feq(pt[0], 4.0))
self.assertTrue(feq(pt[2], 1.0))
self.assertTrue(feq(pt[3], 4.0))
pt3 = pt - pt2
self.assertTrue(feq(pt3[0], 3.0))
self.assertTrue(feq(pt3[2], 0.0))
self.assertTrue(feq(pt3[3], 4.0))
pt -= pt2
self.assertTrue(feq(pt[0], 3.0))
self.assertTrue(feq(pt[2], 0.0))
self.assertTrue(feq(pt[3], 4.0))
pt *= 2.0
self.assertTrue(feq(pt[0], 6.0))
self.assertTrue(feq(pt[1], 0.0))
self.assertTrue(feq(pt[2], 0.0))
self.assertTrue(feq(pt[3], 8.0))
pt /= 2
self.assertTrue(feq(pt[0], 3.0))
self.assertTrue(feq(pt[1], 0.0))
self.assertTrue(feq(pt[2], 0.0))
self.assertTrue(feq(pt[3], 4.0))
self.assertTrue(feq(pt.Length(), 5.0))
self.assertTrue(feq(pt.LengthSq(), 25.0))
pt.Normalize()
self.assertTrue(feq(pt.Length(), 1.0))
pkl = pickle.dumps(pt)
pt2 = pickle.loads(pkl)
self.assertTrue(len(pt) == len(pt2))
for i in range(len(pt)):
self.assertTrue(feq(pt2[i], pt[i]))
def test3UniformGrid(self):
ugrid = geom.UniformGrid3D(20, 18, 15)
self.assertTrue(ugrid.GetNumX() == 40)
self.assertTrue(ugrid.GetNumY() == 36)
self.assertTrue(ugrid.GetNumZ() == 30)
dvect = ugrid.GetOccupancyVect()
ugrid = geom.UniformGrid3D(20, 18, 15, 0.5, DataStructs.DiscreteValueType.TWOBITVALUE)
dvect = ugrid.GetOccupancyVect()
self.assertTrue(dvect.GetValueType() == DataStructs.DiscreteValueType.TWOBITVALUE)
grd = geom.UniformGrid3D(10.0, 10.0, 10.0, 0.5)
grd.SetSphereOccupancy(geom.Point3D(-2.0, -2.0, 0.0), 1.5, 0.25)
grd.SetSphereOccupancy(geom.Point3D(-2.0, 2.0, 0.0), 1.5, 0.25)
grd.SetSphereOccupancy(geom.Point3D(2.0, -2.0, 0.0), 1.5, 0.25)
grd.SetSphereOccupancy(geom.Point3D(2.0, 2.0, 0.0), 1.5, 0.25)
geom.WriteGridToFile(grd, "junk.grd")
grd2 = geom.UniformGrid3D(10.0, 10.0, 10.0, 0.5)
grd2.SetSphereOccupancy(geom.Point3D(-2.0, -2.0, 0.0), 1.5, 0.25)
grd2.SetSphereOccupancy(geom.Point3D(-2.0, 2.0, 0.0), 1.5, 0.25)
grd2.SetSphereOccupancy(geom.Point3D(2.0, -2.0, 0.0), 1.5, 0.25)
dist = geom.TanimotoDistance(grd, grd2)
self.assertTrue(dist == 0.25)
dist = geom.ProtrudeDistance(grd, grd2)
self.assertTrue(dist == 0.25)
dist = geom.ProtrudeDistance(grd2, grd)
self.assertTrue(dist == 0.0)
grd2 = geom.UniformGrid3D(10.0, 10.0, 10.0, 0.5, DataStructs.DiscreteValueType.FOURBITVALUE)
grd2.SetSphereOccupancy(geom.Point3D(-2.0, -2.0, 0.0), 1.5, 0.25, 3)
grd2.SetSphereOccupancy(geom.Point3D(-2.0, 2.0, 0.0), 1.5, 0.25, 3)
grd2.SetSphereOccupancy(geom.Point3D(2.0, -2.0, 0.0), 1.5, 0.25, 3)
self.assertRaises(ValueError, lambda: geom.TanimotoDistance(grd, grd2))
grd2 = geom.UniformGrid3D(10.0, 10.0, 10.0, 1.0)
self.assertRaises(ValueError, lambda: geom.TanimotoDistance(grd, grd2))
grd2 = geom.UniformGrid3D(11.0, 10.0, 10.0, 1.0)
self.assertRaises(ValueError, lambda: geom.TanimotoDistance(grd, grd2))
def testSymmetry(self):
grd = geom.UniformGrid3D(10.0, 10.0, 10.0, 0.5)
grd.SetSphereOccupancy(geom.Point3D(-2.2, -2.0, 0.0), 1.65, 0.25)
grd.SetSphereOccupancy(geom.Point3D(2.2, -2.0, 0.0), 1.65, 0.25)
bPt1 = geom.Point3D(-4.0, -2.0, -2.0)
bPt2 = geom.Point3D(4.0, -2.0, -2.0)
for k in range(8):
bPt1 += geom.Point3D(0.0, 0.0, 0.5)
bPt2 += geom.Point3D(0.0, 0.0, 0.5)
for j in range(8):
bPt1 += geom.Point3D(0.0, 0.5, 0.0)
bPt2 += geom.Point3D(0.0, 0.5, 0.0)
for i in range(8):
bPt1 += geom.Point3D(0.5, 0.0, 0.0)
bPt2 -= geom.Point3D(0.5, 0.0, 0.0)
self.assertTrue(grd.GetValPoint(bPt1) == grd.GetValPoint(bPt2))
bPt1.x = -4.0
bPt2.x = 4.0
bPt1.y = -2.0
bPt2.y = -2.0
def test4UniformRealValueGrid(self):
ugrid = geom.UniformRealValueGrid3D(20, 18, 15)
self.assertTrue(ugrid.GetNumX() == 40)
self.assertTrue(ugrid.GetNumY() == 36)
self.assertTrue(ugrid.GetNumZ() == 30)
dvect = ugrid.GetOccupancyVect()
ugrid = geom.UniformRealValueGrid3D(20, 18, 15, 0.5)
ugrid.SetVal(50, 2.3)
val = ugrid.GetVal(50)
self.assertTrue(feq(val, 2.3))
def test5PointPickles(self):
pt = geom.Point3D(2.0, -3.0, 1.0)
pt2 = pickle.loads(pickle.dumps(pt))
self.assertTrue(feq(pt.x, pt2.x, 1e-6))
self.assertTrue(feq(pt.y, pt2.y, 1e-6))
self.assertTrue(feq(pt.z, pt2.z, 1e-6))
pt = geom.Point2D(2.0, -4.0)
pt2 = pickle.loads(pickle.dumps(pt))
self.assertTrue(feq(pt.x, pt2.x, 1e-6))
self.assertTrue(feq(pt.y, pt2.y, 1e-6))
def test6GridPickles(self):
grd = geom.UniformGrid3D(10.0, 9.0, 8.0, 0.5)
self.assertTrue(grd.GetNumX() == 20)
self.assertTrue(grd.GetNumY() == 18)
self.assertTrue(grd.GetNumZ() == 16)
grd.SetSphereOccupancy(geom.Point3D(-2.0, -2.0, 0.0), 1.5, 0.25)
grd.SetSphereOccupancy(geom.Point3D(-2.0, 2.0, 0.0), 1.5, 0.25)
grd.SetSphereOccupancy(geom.Point3D(2.0, -2.0, 0.0), 1.5, 0.25)
grd.SetSphereOccupancy(geom.Point3D(2.0, 2.0, 0.0), 1.5, 0.25)
self.assertTrue(geom.TanimotoDistance(grd, grd) == 0.0)
grd2 = pickle.loads(pickle.dumps(grd))
self.assertTrue(grd2.GetNumX() == 20)
self.assertTrue(grd2.GetNumY() == 18)
self.assertTrue(grd2.GetNumZ() == 16)
self.assertTrue(geom.TanimotoDistance(grd, grd2) == 0.0)
def test7RealGridPickles(self):
grd = geom.UniformRealValueGrid3D(10.0, 9.0, 8.0, 0.5)
self.assertTrue(grd.GetNumX() == 20)
self.assertTrue(grd.GetNumY() == 18)
self.assertTrue(grd.GetNumZ() == 16)
grd2 = pickle.loads(pickle.dumps(grd))
self.assertTrue(grd2.GetNumX() == 20)
self.assertTrue(grd2.GetNumY() == 18)
self.assertTrue(grd2.GetNumZ() == 16)
def test8GridOps(self):
grd = geom.UniformGrid3D(10, 10, 10)
grd.SetSphereOccupancy(geom.Point3D(-2.0, -2.0, 0.0), 1.0, 0.25)
grd.SetSphereOccupancy(geom.Point3D(-2.0, 2.0, 0.0), 1.0, 0.25)
grd2 = geom.UniformGrid3D(10, 10, 10)
grd2.SetSphereOccupancy(geom.Point3D(2.0, -2.0, 0.0), 1.0, 0.25)
grd2.SetSphereOccupancy(geom.Point3D(2.0, 2.0, 0.0), 1.0, 0.25)
self.assertTrue(geom.TanimotoDistance(grd, grd) == 0.0)
self.assertTrue(geom.TanimotoDistance(grd, grd2) == 1.0)
grd3 = copy.deepcopy(grd)
grd3 |= grd2
self.assertTrue(geom.TanimotoDistance(grd3, grd) == .5)
self.assertTrue(geom.TanimotoDistance(grd3, grd2) == .5)
grd3 = copy.deepcopy(grd)
grd3 += grd2
self.assertTrue(geom.TanimotoDistance(grd3, grd) == .5)
self.assertTrue(geom.TanimotoDistance(grd3, grd2) == .5)
grd3 -= grd
self.assertTrue(geom.TanimotoDistance(grd3, grd) == 1.0)
self.assertTrue(geom.TanimotoDistance(grd3, grd2) == 0)
grd4 = geom.UniformGrid3D(10, 10, 10)
grd4.SetSphereOccupancy(geom.Point3D(-2.0, -2.0, 0.0), 1.0, 0.25)
grd4.SetSphereOccupancy(geom.Point3D(-2.0, 2.0, 0.0), 1.0, 0.25)
grd4.SetSphereOccupancy(geom.Point3D(2.0, -2.0, 0.0), 1.0, 0.25)
self.assertTrue(feq(geom.TanimotoDistance(grd4, grd), .3333))
self.assertTrue(feq(geom.TanimotoDistance(grd4, grd2), .75))
grd4 &= grd2
self.assertTrue(feq(geom.TanimotoDistance(grd4, grd), 1.0))
self.assertTrue(feq(geom.TanimotoDistance(grd4, grd2), .5))
def test9RealGridOps(self):
grd1 = geom.UniformRealValueGrid3D(5.0, 5.0, 5.0, 0.1)
grd2 = geom.UniformRealValueGrid3D(5.0, 5.0, 5.0, 0.1)
grd1.SetVal(50, 37.37)
grd2.SetVal(50, 1.03)
grd3 = copy.deepcopy(grd2)
grd4 = geom.UniformRealValueGrid3D(grd2)
grd1 |= grd2
self.assertTrue(feq(grd1.GetVal(50), 37.37))
self.assertTrue(feq(grd2.GetVal(50), 1.03))
grd2 |= grd1
self.assertTrue(feq(grd1.GetVal(50), 37.37))
self.assertTrue(feq(grd2.GetVal(50), 37.37))
grd2 &= grd3
self.assertTrue(feq(grd2.GetVal(50), 1.03))
self.assertTrue(feq(grd3.GetVal(50), 1.03))
grd3 &= grd1
self.assertTrue(feq(grd1.GetVal(50), 37.37))
self.assertTrue(feq(grd3.GetVal(50), 1.03))
grd2 &= grd4
self.assertTrue(feq(grd2.GetVal(50), 1.03))
self.assertTrue(feq(grd4.GetVal(50), 1.03))
grd4 &= grd1
self.assertTrue(feq(grd1.GetVal(50), 37.37))
self.assertTrue(feq(grd4.GetVal(50), 1.03))
grd1 += grd2
self.assertTrue(feq(grd1.GetVal(50), 38.40))
self.assertTrue(feq(grd2.GetVal(50), 1.03))
grd1 -= grd2
self.assertTrue(feq(grd1.GetVal(50), 37.37))
self.assertTrue(feq(grd2.GetVal(50), 1.03))
grd2 -= grd1
self.assertTrue(feq(grd1.GetVal(50), 37.37))
self.assertTrue(feq(grd2.GetVal(50), -36.34))
def test10Dihedrals(self):
p1 = geom.Point3D(1, 0, 0)
p2 = geom.Point3D(0, 0, 0)
p3 = geom.Point3D(0, 1, 0)
p4 = geom.Point3D(.5, 1, .5)
ang = geom.ComputeDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, math.pi / 4, 4)
ang = geom.ComputeSignedDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, -math.pi / 4, 4)
p4 = geom.Point3D(-.5, 1, .5)
ang = geom.ComputeDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, 3 * math.pi / 4, 4)
ang = geom.ComputeSignedDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, -3 * math.pi / 4, 4)
p4 = geom.Point3D(.5, 1, -.5)
ang = geom.ComputeDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, math.pi / 4, 4)
ang = geom.ComputeSignedDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, math.pi / 4, 4)
p4 = geom.Point3D(-.5, 1, -.5)
ang = geom.ComputeDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, 3 * math.pi / 4, 4)
ang = geom.ComputeSignedDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, 3 * math.pi / 4, 4)
p4 = geom.Point3D(0, 1, 1)
ang = geom.ComputeDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, math.pi / 2, 4)
ang = geom.ComputeSignedDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, -math.pi / 2, 4)
p4 = geom.Point3D(0, 1, -1)
ang = geom.ComputeDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, math.pi / 2, 4)
ang = geom.ComputeSignedDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, math.pi / 2, 4)
p4 = geom.Point3D(1, 1, 0)
ang = geom.ComputeDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, 0, 4)
ang = geom.ComputeSignedDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, 0, 4)
p4 = geom.Point3D(-1, 1, 0)
ang = geom.ComputeDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, math.pi, 4)
ang = geom.ComputeSignedDihedralAngle(p1, p2, p3, p4)
self.assertAlmostEqual(ang, math.pi, 4)
def test11UniformGridIndices(self):
ugrid = geom.UniformGrid3D(20, 18, 15)
idx = ugrid.GetGridIndex(3, 2, 1)
xi, yi, zi = ugrid.GetGridIndices(idx)
self.assertEqual(xi, 3)
self.assertEqual(yi, 2)
self.assertEqual(zi, 1)
def test12UniformRealGridIndices(self):
ugrid = geom.UniformRealValueGrid3D(20, 18, 15)
idx = ugrid.GetGridIndex(3, 2, 1)
xi, yi, zi = ugrid.GetGridIndices(idx)
self.assertEqual(xi, 3)
self.assertEqual(yi, 2)
self.assertEqual(zi, 1)
pt = ugrid.GetOffset()
ugrid.SetValPoint(pt, 2.3)
idx = ugrid.GetGridPointIndex(pt)
self.assertTrue(feq(ugrid.GetValPoint(pt), 2.3))
self.assertTrue(idx == 0)
self.assertTrue(feq(ugrid.GetVal(idx), 2.3))
pt2 = ugrid.GetGridPointLoc(idx)
self.assertTrue(feq(pt.x, pt2.x))
self.assertTrue(feq(pt.y, pt2.y))
self.assertTrue(feq(pt.z, pt2.z))
if __name__ == '__main__':
print("Testing Geometry wrapper")

View File

@@ -0,0 +1,185 @@
//
// Copyright (c) 2014-2024, Novartis Institutes for BioMedical Research and
// other RDKit contributors
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
// The contents are covered by the terms of the BSD license
// which is included in the file license.txt, found at the root
// of the RDKit source tree.
//
#include "UniformRealValueGrid3D.h"
#include <GraphMol/GraphMol.h>
#include <Geometry/point.h>
#include <RDGeneral/Invariant.h>
#include <RDGeneral/utils.h>
#include <RDGeneral/RDLog.h>
#include <RDGeneral/types.h>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <fstream>
#include <ios>
#include <stdlib.h>
using namespace RDGeom;
using namespace RDKit;
void test1UniformRealValueGrid3D() {
RDGeom::UniformRealValueGrid3D grd(6.0, 5.0, 4.0);
CHECK_INVARIANT(grd.getSize() == 960, "");
CHECK_INVARIANT(RDKit::feq(grd.getSpacing(), .5), "");
CHECK_INVARIANT(grd.getNumX() == 12, "");
CHECK_INVARIANT(grd.getNumY() == 10, "");
CHECK_INVARIANT(grd.getNumZ() == 8, "");
RDGeom::UniformRealValueGrid3D grd2(grd);
CHECK_INVARIANT(grd2.getSize() == 960, "");
CHECK_INVARIANT(RDKit::feq(grd2.getSpacing(), .5), "");
CHECK_INVARIANT(grd2.getNumX() == 12, "");
CHECK_INVARIANT(grd2.getNumY() == 10, "");
CHECK_INVARIANT(grd2.getNumZ() == 8, "");
CHECK_INVARIANT(grd2.getOccupancyVect()->getTotalVal() == 0, "");
TEST_ASSERT(grd.compareVectors(grd2));
TEST_ASSERT(grd.compareParams(grd2));
grd.setVal(1, 1.0);
TEST_ASSERT(!grd.compareVectors(grd2));
TEST_ASSERT(grd.compareParams(grd2))
// make sure the data are actually decoupled:
// grd.setSphereOccupancy(Point3D(1.0, 1.0, 0.0), 1.5, 0.25);
// CHECK_INVARIANT(grd.getOccupancyVect()->getTotalVal()>523, "" );
// CHECK_INVARIANT(grd2.getOccupancyVect()->getTotalVal() == 523, "" );
}
void test2UniformRealValueGrid3DPickling() {
RDGeom::UniformRealValueGrid3D grd(5.0, 5.0, 5.0, 0.1);
grd.setVal(50, 2.3);
const std::string pkl = grd.toString();
RDGeom::UniformRealValueGrid3D grd2(pkl);
TEST_ASSERT(grd.compareVectors(grd2));
TEST_ASSERT(grd.compareParams(grd2));
}
void test3UniformRealValueGrid3DIndexing() {
RDGeom::UniformRealValueGrid3D grd(5.0, 5.0, 5.0, 0.1);
{
unsigned int xi = 3, yi = 3, zi = 3;
unsigned int idx = grd.getGridIndex(xi, yi, zi);
unsigned int nxi, nyi, nzi;
grd.getGridIndices(idx, nxi, nyi, nzi);
TEST_ASSERT(nxi == xi);
TEST_ASSERT(nyi == yi);
TEST_ASSERT(nzi == zi);
}
{
unsigned int xi = 3, yi = 3, zi = 5;
unsigned int idx = grd.getGridIndex(xi, yi, zi);
unsigned int nxi, nyi, nzi;
grd.getGridIndices(idx, nxi, nyi, nzi);
TEST_ASSERT(nxi == xi);
TEST_ASSERT(nyi == yi);
TEST_ASSERT(nzi == zi);
}
{
unsigned int xi = 3, yi = 6, zi = 3;
unsigned int idx = grd.getGridIndex(xi, yi, zi);
unsigned int nxi, nyi, nzi;
grd.getGridIndices(idx, nxi, nyi, nzi);
TEST_ASSERT(nxi == xi);
TEST_ASSERT(nyi == yi);
TEST_ASSERT(nzi == zi);
}
{
unsigned int xi = 0, yi = 0, zi = 0;
unsigned int idx = grd.getGridIndex(xi, yi, zi);
unsigned int nxi, nyi, nzi;
grd.getGridIndices(idx, nxi, nyi, nzi);
TEST_ASSERT(nxi == xi);
TEST_ASSERT(nyi == yi);
TEST_ASSERT(nzi == zi);
}
{
unsigned int xi = 8, yi = 2, zi = 1;
unsigned int idx = grd.getGridIndex(xi, yi, zi);
unsigned int nxi, nyi, nzi;
grd.getGridIndices(idx, nxi, nyi, nzi);
TEST_ASSERT(nxi == xi);
TEST_ASSERT(nyi == yi);
TEST_ASSERT(nzi == zi);
}
RDGeom::Point3D pt = grd.getOffset();
grd.setVal(pt, 2.3);
unsigned int id = grd.getGridPointIndex(pt);
TEST_ASSERT(RDKit::feq(grd.getVal(pt), 2.3));
TEST_ASSERT(id == 0);
TEST_ASSERT(RDKit::feq(grd.getVal(id), 2.3));
RDGeom::Point3D pt2 = grd.getGridPointLoc(id);
TEST_ASSERT(RDKit::feq(pt.x, pt2.x));
TEST_ASSERT(RDKit::feq(pt.y, pt2.y));
TEST_ASSERT(RDKit::feq(pt.z, pt2.z));
}
void test4UniformRealValueGrid3DOps() {
RDGeom::UniformRealValueGrid3D grd1(5.0, 5.0, 5.0, 0.1);
RDGeom::UniformRealValueGrid3D grd2(5.0, 5.0, 5.0, 0.1);
grd1.setVal(50, 37.37);
grd2.setVal(50, 1.03);
RDGeom::UniformRealValueGrid3D grd3(grd2);
grd1 |= grd2;
TEST_ASSERT(RDKit::feq(grd1.getVal(50), 37.37));
TEST_ASSERT(RDKit::feq(grd2.getVal(50), 1.03));
grd2 = grd2 | grd1;
TEST_ASSERT(RDKit::feq(grd1.getVal(50), 37.37));
TEST_ASSERT(RDKit::feq(grd2.getVal(50), 37.37));
grd2 = grd2 & grd3;
TEST_ASSERT(RDKit::feq(grd2.getVal(50), 1.03));
TEST_ASSERT(RDKit::feq(grd3.getVal(50), 1.03));
grd3 &= grd1;
TEST_ASSERT(RDKit::feq(grd1.getVal(50), 37.37));
TEST_ASSERT(RDKit::feq(grd3.getVal(50), 1.03));
grd1 += grd2;
TEST_ASSERT(RDKit::feq(grd1.getVal(50), 38.40));
TEST_ASSERT(RDKit::feq(grd2.getVal(50), 1.03));
grd1 -= grd2;
TEST_ASSERT(RDKit::feq(grd1.getVal(50), 37.37));
TEST_ASSERT(RDKit::feq(grd2.getVal(50), 1.03));
grd2 = grd2 - grd1;
TEST_ASSERT(RDKit::feq(grd1.getVal(50), 37.37));
TEST_ASSERT(RDKit::feq(grd2.getVal(50), -36.34));
}
int main() {
std::cout << "***********************************************************\n";
std::cout << "Testing RealValueGrid3D\n";
std::cout << "\t---------------------------------\n";
std::cout << "\t test1UniformRealValueGrid3D \n\n";
test1UniformRealValueGrid3D();
std::cout << "\t---------------------------------\n";
std::cout << "\t test2UniformRealValueGrid3DPickling \n\n";
test2UniformRealValueGrid3DPickling();
std::cout << "\t---------------------------------\n";
std::cout << "\t test3UniformRealValueGrid3DIndexing \n\n";
test3UniformRealValueGrid3DIndexing();
std::cout << "\t---------------------------------\n";
std::cout << "\t test4UniformRealValueGrid3DOps \n\n";
test4UniformRealValueGrid3DOps();
return 0;
}