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

@@ -19,6 +19,7 @@
#include "base64.h"
#include <cmath>
#include "DiscreteValueVect.h"
#include "RealValueVect.h"
#include <RDGeneral/Invariant.h>
#include <RDGeneral/RDLog.h>
#include <RDGeneral/Exceptions.h>
@@ -1450,6 +1451,117 @@ void test17Github3994() {
TEST_ASSERT(siv1 == siv2);
}
void test14RealVect() {
RealValueVect vect1(30);
unsigned int i;
for (i = 0; i < 15; ++i) {
vect1.setVal(2 * i, 1.0);
}
TEST_ASSERT(vect1.getLength() == 30);
TEST_ASSERT(feq(vect1.getTotalVal(), 15.0));
for (i = 0; i < vect1.getLength(); ++i) {
TEST_ASSERT(feq(vect1.getVal(i), (i + 1) % 2));
}
RealValueVect vect2(30);
for (i = 0; i < vect2.getLength(); ++i) {
vect2.setVal(i, double(1.0 / (i + 1.0)));
}
TEST_ASSERT(vect2.getLength() == 30);
for (i = 0; i < vect2.getLength(); ++i) {
TEST_ASSERT(feq(vect2.getVal(i), double(1.0 / (i + 1.0))));
}
// test copy constructor and operator[]
RealValueVect vect3(vect2);
TEST_ASSERT(vect3.getLength() == 30);
for (i = 0; i < vect3.getLength(); ++i) {
TEST_ASSERT(feq(vect3[i], double(1.0 / (i + 1.0))));
}
double Pi = 3.141592;
RealValueVect vect4(60, Pi);
TEST_ASSERT(feq(vect4.getTotalVal(), 60 * Pi));
}
void test15RealVectDists() {
RealValueVect v1(30);
RealValueVect v2(30);
unsigned int i;
for (i = 0; i < 15; ++i) {
v1.setVal(2 * i, 1.0);
v2.setVal(2 * i, 1.0);
}
TEST_ASSERT(feq(computeL1Norm(v1, v2), 0));
for (i = 0; i < 30; ++i) {
v2.setVal(i, i % 2);
}
TEST_ASSERT(feq(computeL1Norm(v1, v2), 30.0));
for (i = 0; i < 30; ++i) {
if (i % 3 == 0) {
v2.setVal(i, 1.0);
} else {
v2.setVal(i, 0.0);
}
}
TEST_ASSERT(feq(computeL1Norm(v1, v2), 15.0));
for (i = 0; i < 30; ++i) {
v1.setVal(i, 0.0);
v2.setVal(i, i / 10.0);
}
TEST_ASSERT(feq(computeL1Norm(v1, v2), 43.5))
}
void test16RealVectPickles() {
RealValueVect v1(30);
unsigned int i;
for (i = 0; i < 15; ++i) {
v1.setVal(2 * i, 1.1);
}
RealValueVect v2(v1.toString());
TEST_ASSERT(feq(computeL1Norm(v1, v2), 0.0));
}
void test17RealVectOps() {
RealValueVect vect1(8);
for (unsigned int i = 0; i < 4; ++i) {
vect1.setVal(2 * i, 2.1);
}
TEST_ASSERT(vect1.getLength() == 8);
TEST_ASSERT(feq(vect1.getTotalVal(), 8.4));
RealValueVect vect2(8);
for (unsigned int i = 0; i < 4; ++i) {
vect2.setVal(2 * i + 1, 2.2);
vect2.setVal(2 * i, 1.1);
}
TEST_ASSERT(feq(vect2.getTotalVal(), 13.2));
RealValueVect vect3 = vect1 & vect2;
TEST_ASSERT(vect3.getLength() == 8);
TEST_ASSERT(feq(vect3.getTotalVal(), 4.4));
RealValueVect vect4 = vect1 | vect2;
TEST_ASSERT(vect4.getLength() == 8);
TEST_ASSERT(feq(vect4.getTotalVal(), 17.2));
RealValueVect vect5 = vect1 + vect2;
TEST_ASSERT(vect5.getLength() == 8);
TEST_ASSERT(feq(vect5.getTotalVal(), 21.6));
vect5 = vect1 - vect2;
TEST_ASSERT(feq(vect5.getTotalVal(), -4.8));
vect5 = vect2 - vect1;
TEST_ASSERT(feq(vect5.getTotalVal(), 4.8));
}
int main() {
RDLog::InitLogs();
boost::logging::enable_logs("rdApp.info");
@@ -1561,5 +1673,21 @@ int main() {
<< std::endl;
test17Github3994();
BOOST_LOG(rdInfoLog)
<< " Test RealValue Vectors 1: Constructors and Accessing Values -------------------------------"
<< std::endl;
test14RealVect();
BOOST_LOG(rdInfoLog)
<< " Test RealValue Vectors 2: L1Norm -------------------------------"
<< std::endl;
test15RealVectDists();
BOOST_LOG(rdInfoLog)
<< " Test RealValue Vectors 3: Pickles -------------------------------"
<< std::endl;
test16RealVectPickles();
BOOST_LOG(rdInfoLog)
<< " Test RealValue Vectors 4: Vector Operations -------------------------------"
<< std::endl;
test17RealVectOps();
return 0;
}