Files
rdkit/Code/GraphMol/MolInteractionFields/testMIF.cpp
Greg Landrum 644296fe13 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>
2024-12-19 09:54:52 +01:00

570 lines
20 KiB
C++

//
// 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 <catch2/catch_all.hpp>
#include <Geometry/UniformRealValueGrid3D.h>
#include <Geometry/point.h>
#include <RDGeneral/utils.h>
#include <RDGeneral/RDLog.h>
#include <GraphMol/MolInteractionFields/MIFDescriptors.h>
#include <GraphMol/RDKitBase.h>
#include <GraphMol/SmilesParse/SmilesParse.h>
#include <GraphMol/FileParsers/FileParsers.h>
#include <GraphMol/DistGeomHelpers/Embedder.h>
#include <GraphMol/PartialCharges/GasteigerCharges.h>
#include <GraphMol/PartialCharges/GasteigerParams.h>
#include <vector>
#include <algorithm>
#include <iostream>
#include <fstream>
using namespace RDGeom;
using namespace RDKit;
using namespace RDMIF;
namespace RDMIF {
class testfunctor {
public:
testfunctor() {}
double operator()(const double &, const double &, const double &,
double) const {
return 1.0;
}
};
} // namespace RDMIF
TEST_CASE("constructGrid") {
std::string path = getenv("RDBASE");
path += "/Code/GraphMol/MolInteractionFields/test_data/";
// //Generate Molecule with 3D Coordinates and Partial Charges
// RWMol mol=*SmilesToMol("Cl");
// MolOps::addHs(*mol);
// DGeomHelpers::EmbedMolecule(*mol);
// MolToMolFile(*mol, path + "HCl.mol");
auto fopts = v2::FileParsers::MolFileParserParams();
fopts.removeHs = false;
auto mol = v2::FileParsers::MolFromMolFile(path + "HCl.mol", fopts);
REQUIRE(mol);
auto grd = *constructGrid(*mol, 0, 5.0, 0.5);
Point3D bond =
mol->getConformer().getAtomPos(1) - mol->getConformer().getAtomPos(0);
CHECK(feq(grd.getSpacing(), 0.5));
CHECK(feq(grd.getNumX(), std::floor((fabs(bond.x) + 10.0) / 0.5 + 0.5)));
CHECK(feq(grd.getNumY(), std::floor((fabs(bond.y) + 10.0) / 0.5 + 0.5)));
CHECK(feq(grd.getNumZ(), std::floor((fabs(bond.z) + 10.0) / 0.5 + 0.5)));
}
TEST_CASE("CalculateDescriptors") {
RealValueVect data(125, 0.0);
Point3D o(0.0, 0.0, 0.0);
UniformRealValueGrid3D grd(5.0, 5.0, 5.0, 1.0, &o, &data);
calculateDescriptors(grd, testfunctor());
CHECK(grd.getOccupancyVect()->getTotalVal() == grd.getSize());
}
TEST_CASE("CubeFiles") {
std::string path = getenv("RDBASE");
path += "/Code/GraphMol/MolInteractionFields/test_data/";
auto fopts = v2::FileParsers::MolFileParserParams();
fopts.removeHs = false;
auto mol = v2::FileParsers::MolFromMolFile(path + "HCl.mol", fopts);
REQUIRE(mol);
RealValueVect data(125, 0.0);
Point3D o(0.0, 0.0, 0.0);
UniformRealValueGrid3D grd(5.0, 5.0, 5.0, 1.0, &o, &data);
for (unsigned int i = 0; i < grd.getSize(); i++) {
grd.setVal(i, double(i / 10.0));
}
writeToCubeFile(grd, path + "test3.cube", mol.get());
UniformRealValueGrid3D grd2;
auto mol2 = readFromCubeFile(grd2, path + "test3.cube");
CHECK(grd.getSize() == grd2.getSize());
for (unsigned int i = 0; i < grd2.getSize(); i++) {
CHECK(feq(grd2.getVal(i), double(i / 10.0)));
}
CHECK(grd.getNumX() == grd2.getNumX());
CHECK(grd.getNumY() == grd2.getNumY());
CHECK(grd.getNumZ() == grd2.getNumZ());
CHECK(feq(grd.getOffset().x, grd2.getOffset().x));
CHECK(feq(grd.getSpacing(), grd2.getSpacing()));
CHECK(grd.compareVectors(grd2));
CHECK(grd.compareParams(grd2));
CHECK(grd.compareGrids(grd2));
CHECK(mol->getNumAtoms() == mol2->getNumAtoms());
for (unsigned int i = 0; i < mol->getNumAtoms(); i++) {
CHECK(mol->getAtomWithIdx(i)->getAtomicNum() ==
mol2->getAtomWithIdx(i)->getAtomicNum());
CHECK(feq(mol->getConformer().getAtomPos(i).x,
mol2->getConformer().getAtomPos(i).x));
CHECK(feq(mol->getConformer().getAtomPos(i).y,
mol2->getConformer().getAtomPos(i).y));
CHECK(feq(mol->getConformer().getAtomPos(i).z,
mol2->getConformer().getAtomPos(i).z));
}
}
TEST_CASE("Coulomb") {
std::string path = getenv("RDBASE");
path += "/Code/GraphMol/MolInteractionFields/test_data/";
auto fopts = v2::FileParsers::MolFileParserParams();
fopts.removeHs = false;
auto mol = v2::FileParsers::MolFromMolFile(path + "HCl.mol", fopts);
REQUIRE(mol);
computeGasteigerCharges(*mol);
std::vector<double> charges;
std::vector<Point3D> pos;
Conformer conf = mol->getConformer(0);
for (auto i = 0u; i < mol->getNumAtoms(); ++i) {
charges.push_back(
mol->getAtomWithIdx(i)->getProp<double>("_GasteigerCharge"));
pos.push_back(conf.getAtomPos(i));
}
auto grd = *constructGrid(*mol);
auto grd2 = *constructGrid(*mol);
Coulomb coul(*mol);
calculateDescriptors<Coulomb>(grd, coul);
calculateDescriptors<Coulomb>(grd2, Coulomb(charges, pos));
CHECK(grd.compareGrids(grd2));
CHECK(feq(coul(0.0, 0.0, 0.0, 1000), 0.0));
CHECK(coul(2.0, 0.0, 0.0, 1000) < 0);
CHECK(coul(-2.0, 0.0, 0.0, 1000) > 0);
CHECK(feq(coul(0.0, 0.0, 0.0, 0.1), 0.0));
calculateDescriptors<Coulomb>(grd, Coulomb(*mol, 0, 1.0, true));
for (unsigned int i = 0; i < grd.getSize(); i++) {
CHECK(grd.getVal(i) <= 0.0);
}
Coulomb coul1(*mol, 0, -1.0, false, "_GasteigerCharge", 0.0, 0.01);
CHECK(coul1(-2.0, 0.0, 0.0, 1000) < 0);
CHECK(coul1(2.0, 0.0, 0.0, 1000) > 0);
Coulomb coul2 = Coulomb(*mol, 0, -.5, false, "_GasteigerCharge", 0.0, 0.01);
CHECK(coul1(-2.0, 0.0, 0.0, 1000) < coul2(-2.0, 0.0, 0.0, 1000));
Coulomb coul3(*mol, 0, 1.0, false, "_GasteigerCharge", 0.01, 1.0);
CHECK(coul3(0.0, 0.0, 0.0, 1000) > coul3(0.1, 0.0, 0.0, 1000));
CHECK(coul3(0.66, 0.0, 0.0, 1000) > coul3(0.68, 0.0, 0.0, 1000));
CHECK(coul3(0.70, 0.0, 0.0, 1000) > coul3(0.68, 0.0, 0.0, 1000));
CHECK(feq(coul3(0.0, 0.0, 0.0, 0.1), 0.0));
}
TEST_CASE("CoulombDielectric") {
std::string path = getenv("RDBASE");
path += "/Code/GraphMol/MolInteractionFields/test_data/";
auto fopts = v2::FileParsers::MolFileParserParams();
fopts.removeHs = false;
auto mol = v2::FileParsers::MolFromMolFile(path + "HCl.mol", fopts);
REQUIRE(mol);
computeGasteigerCharges(*mol);
std::vector<double> charges;
std::vector<Point3D> pos;
Conformer conf = mol->getConformer(0);
for (auto i = 0u; i < mol->getNumAtoms(); ++i) {
charges.push_back(
mol->getAtomWithIdx(i)->getProp<double>("_GasteigerCharge"));
pos.push_back(conf.getAtomPos(i));
}
auto grd = *constructGrid(*mol);
auto grd2 = *constructGrid(*mol);
CoulombDielectric couldiele(*mol);
calculateDescriptors<CoulombDielectric>(grd, couldiele);
calculateDescriptors<CoulombDielectric>(grd2,
CoulombDielectric(charges, pos));
CHECK(grd.compareGrids(grd2));
CHECK(feq(couldiele(0.0, 0.0, 0.0, 1000), 0.0));
CHECK(couldiele(2.0, 0.0, 0.0, 1000) < 0);
CHECK(couldiele(-2.0, 0.0, 0.0, 1000) > 0);
calculateDescriptors<CoulombDielectric>(
grd, CoulombDielectric(*mol, 0, 1.0, true));
for (unsigned int i = 0; i < grd.getSize(); i++) {
CHECK(grd.getVal(i) <= 0.0);
}
CHECK(feq(couldiele(0.0, 0.0, 0.0, 1000), 0.0));
CHECK(couldiele(2.0, 0.0, 0.0, 1000) < 0);
CHECK(couldiele(-2.0, 0.0, 0.0, 1000) > 0);
calculateDescriptors<CoulombDielectric>(
grd, CoulombDielectric(*mol, 0, 1.0, true));
for (unsigned int i = 0; i < grd.getSize(); i++) {
CHECK(grd.getVal(i) <= 0.0);
}
CoulombDielectric couldiele1(*mol, 0, -1.0);
CHECK(couldiele1(-2.0, 0.0, 0.0, 1000) < 0);
CHECK(couldiele1(2.0, 0.0, 0.0, 1000) > 0);
CoulombDielectric couldiele2(*mol, 0, -.5);
CHECK(couldiele1(-2.0, 0.0, 0.0, 1000) < couldiele2(-2.0, 0.0, 0.0, 1000));
CoulombDielectric couldiele3(*mol, 0, 1.0, false, "_GasteigerCharge", 0.01,
1.0);
CHECK(couldiele3(0.0, 0.0, 0.0, 1000) > couldiele3(0.1, 0.0, 0.0, 1000));
CHECK(couldiele3(0.66, 0.0, 0.0, 1000) > couldiele3(0.68, 0.0, 0.0, 1000));
CHECK(couldiele3(0.70, 0.0, 0.0, 1000) > couldiele3(0.68, 0.0, 0.0, 1000));
mol = v2::FileParsers::MolFromMolFile(path + "glucose.mol", fopts);
REQUIRE(mol);
computeGasteigerCharges(*mol);
CoulombDielectric couldiele4(*mol, 0, 1.0, false, "_GasteigerCharge", 0.01,
1.0, 80.0, 4.0);
CoulombDielectric couldiele5(*mol, 0, 1.0, false, "_GasteigerCharge", 0.01,
1.0, 200.0, 4.0);
CoulombDielectric couldiele6(*mol, 0, 1.0, false, "_GasteigerCharge", 0.01,
1.0, 80.0, 10.0);
CHECK(couldiele5(-1.0, 0.0, 0.0, 1000) < couldiele4(-1.0, 0.0, 0.0, 1000));
CHECK(couldiele6(-1.0, 0.0, 0.0, 1000) < couldiele4(-1.0, 0.0, 0.0, 1000));
}
TEST_CASE("VdWaals") {
std::string path = getenv("RDBASE");
path += "/Code/GraphMol/MolInteractionFields/test_data/";
auto fopts = v2::FileParsers::MolFileParserParams();
fopts.removeHs = false;
auto mol = v2::FileParsers::MolFromMolFile(path + "HCl.mol", fopts);
REQUIRE(mol);
try {
MMFFVdWaals vdw(*mol, 0, 6, false, 1.0);
} catch (ValueErrorException &dexp) {
BOOST_LOG(rdInfoLog) << "Expected failure: " << dexp.what() << "\n";
}
mol = v2::FileParsers::MolFromMolFile(path + "HCN.mol", fopts);
REQUIRE(mol);
{
MMFFVdWaals vdw(*mol, 0, 6, false, 1.0);
CHECK(vdw(-5.0, 0, 0, 1000) < 0);
CHECK(vdw(-1.68, 0, 0, 1000) > vdw(-5.0, 0, 0, 1000));
CHECK(vdw(-5.0, 0, 0, 1000) < vdw(-10.0, 0, 0, 1000));
}
auto mol2 = v2::FileParsers::MolFromMolFile(path + "h2o.mol", fopts);
REQUIRE(mol2);
MMFFVdWaals vdw(*mol2, 0, 6, false, 1.0);
MMFFVdWaals vdw2(*mol2, 0, 6, true, 1.0);
CHECK(fabs(vdw2(-3.0, 0, 0, 1000) - vdw(-3.0, 0, 0, 1000)) > 0.0001);
UFFVdWaals vdw3(*mol, 0, "O_3", 1.0);
CHECK(vdw3(-5.0, 0, 0, 1000) < 0);
CHECK(vdw3(-1.68, 0, 0, 1000) > vdw3(-5.0, 0, 0, 1000));
CHECK(vdw3(-5.0, 0, 0, 1000) < vdw3(-10.0, 0, 0, 1000));
std::vector<std::string> names{
"acetone", "aceticacid", "phenol", "phenolate",
"serine", "threonine", "ethanol", "diethylether",
"h2o", "ammonia", "ethylamine", "imine",
"acetonitrile", "histidine", "phenylamine", "methylammonium",
"fluoromethane", "chloromethane", "bromomethane", "glycine",
"glyphe", "glysergly", "glythrgly", "glucose"};
for (const auto &name : names) {
mol = v2::FileParsers::MolFromMolFile(path + name + ".mol", fopts);
REQUIRE(mol);
MMFFVdWaals mmffVdw(*mol);
CHECK(mmffVdw(0.0, 0.0, 0.0, 1000));
UFFVdWaals uffVdw(*mol);
CHECK(uffVdw(0.0, 0.0, 0.0, 1000));
}
}
TEST_CASE("HBond") {
std::string path = getenv("RDBASE");
path += "/Code/GraphMol/MolInteractionFields/test_data/";
// Generate Molecule with 3D Coordinates and Partial Charges
auto fopts = v2::FileParsers::MolFileParserParams();
fopts.removeHs = false;
auto mol =
v2::FileParsers::MolFromMolFile(path + "ethane.mol", fopts); // Ethane
REQUIRE(mol);
auto grd = *constructGrid(*mol, 0, 5.0, 1);
for (unsigned int i = 0; i < grd.getSize(); i++) {
grd.setVal(i, 1.0);
}
UniformRealValueGrid3D grd1(grd);
HBond hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 0);
calculateDescriptors<HBond>(grd, hbonddes);
TEST_ASSERT(!grd.compareGrids(grd1));
const RealValueVect *vect = grd.getOccupancyVect();
const RealValueVect *vect1 = grd1.getOccupancyVect();
CHECK((unsigned int)fabs(((*vect1 - *vect).getTotalVal())) == grd.getSize());
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 0);
for (unsigned int i = 0; i < grd.getSize(); i++) {
grd.setVal(i, 1.0);
}
calculateDescriptors<HBond>(grd, hbonddes);
TEST_ASSERT(!grd.compareGrids(grd1));
CHECK((unsigned int)fabs(((*vect1 - *vect).getTotalVal())));
mol = v2::FileParsers::MolFromMolFile(path + "aceticacid.mol",
fopts); // Acetic Acid
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 2);
calculateDescriptors<HBond>(grd, hbonddes);
HBond hbonddes1(*mol, 0, "O", true, 0.001);
CHECK(hbonddes1.getNumInteractions() == 1);
calculateDescriptors<HBond>(grd, hbonddes1);
HBond hbonddes2(*mol, 0, "O", false, 0.001);
CHECK(hbonddes1(4.0, 0.0, 1.0, 1000) > hbonddes2(4.0, 0.0, 1.0, 1000));
HBond hbonddes3(*mol, 0, "NH", true, 0.001);
CHECK(hbonddes3.getNumInteractions() == 2);
CHECK(hbonddes(2.0, 2.0, 2.0, 1000) < hbonddes3(2.0, 2.0, 2.0, 1000));
HBond hbonddes4(*mol, 0, "N", true, 0.001);
CHECK(hbonddes4.getNumInteractions() == 1);
CHECK(hbonddes1(3.0, 0.0, 0.0, 1000) < hbonddes4(3.0, 0.0, 0.0, 1000));
mol =
v2::FileParsers::MolFromMolFile(path + "acetone.mol", fopts); // Acetone
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 1);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 0);
calculateDescriptors<HBond>(grd, hbonddes);
mol = v2::FileParsers::MolFromMolFile(path + "diethylether.mol",
fopts); // Et2O
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 1);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 0);
calculateDescriptors<HBond>(grd, hbonddes);
mol = v2::FileParsers::MolFromMolFile(path + "h2o.mol", fopts); // H2O
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 1);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 2);
calculateDescriptors<HBond>(grd, hbonddes);
mol =
v2::FileParsers::MolFromMolFile(path + "ammonia.mol", fopts); // ammonia
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 1);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 3);
calculateDescriptors<HBond>(grd, hbonddes);
mol = v2::FileParsers::MolFromMolFile(path + "imine.mol", fopts); // imine
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 1);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 0);
calculateDescriptors<HBond>(grd, hbonddes);
mol = v2::FileParsers::MolFromMolFile(path + "methylammonium.mol",
fopts); // methylammonium
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 0);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 3);
calculateDescriptors<HBond>(grd, hbonddes);
mol = v2::FileParsers::MolFromMolFile(path + "chloromethane.mol",
fopts); // Chloromethane
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 1);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 0);
calculateDescriptors<HBond>(grd, hbonddes);
mol = v2::FileParsers::MolFromMolFile(path + "phosphonate.mol",
fopts); // Phosphonate
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 3);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 0);
calculateDescriptors<HBond>(grd, hbonddes);
mol = v2::FileParsers::MolFromMolFile(path + "phosphatediester.mol",
fopts); // Phosphatediester
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 4);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 0);
calculateDescriptors<HBond>(grd, hbonddes);
mol = v2::FileParsers::MolFromMolFile(path + "hydrogenphosphatediester.mol",
fopts); // Hydrogenphosphatediester
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 4);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 1);
calculateDescriptors<HBond>(grd, hbonddes);
mol = v2::FileParsers::MolFromMolFile(path + "mustardgas.mol",
fopts); // mustard gas
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 2);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 0);
calculateDescriptors<HBond>(grd, hbonddes);
mol = v2::FileParsers::MolFromMolFile(path + "alicin.mol", fopts); // Alicin
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 1);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 0);
calculateDescriptors<HBond>(grd, hbonddes);
mol = v2::FileParsers::MolFromMolFile(path + "sulfanilamide.mol",
fopts); // Sulfanilamide
REQUIRE(mol);
grd = *constructGrid(*mol, 0, 5.0, 1);
hbonddes = HBond(*mol, 0, "OH", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 3);
calculateDescriptors<HBond>(grd, hbonddes);
hbonddes = HBond(*mol, 0, "O", true, 0.001);
CHECK(hbonddes.getNumInteractions() == 4);
calculateDescriptors<HBond>(grd, hbonddes);
}
TEST_CASE("Hydrophilic") {
std::string path = getenv("RDBASE");
path += "/Code/GraphMol/MolInteractionFields/test_data/";
auto fopts = v2::FileParsers::MolFileParserParams();
fopts.removeHs = false;
auto mol = v2::FileParsers::MolFromMolFile(path + "h2o.mol", fopts);
REQUIRE(mol);
Hydrophilic hydro(*mol);
HBond hbondOH(*mol, 0, "OH");
HBond hbondO(*mol, 0, "O");
double hyd = hydro(0.0, 0.0, 0.0, 1000), hOH = hbondOH(0.0, 0.0, 0.0, 1000),
hO = hbondO(0.0, 0.0, 0.0, 1000);
CHECK(feq(std::min(hOH, hO), hyd));
hyd = hydro(1.0, 1.5, 2.0, 1000);
hOH = hbondOH(1.0, 1.5, 2.0, 1000);
hO = hbondO(1.0, 1.5, 2.0, 1000);
CHECK(feq(std::min(hOH, hO), hyd));
hyd = hydro(2.0, 1.5, -3.0, 1000);
hOH = hbondOH(2.0, 1.5, -3.0, 1000);
hO = hbondO(2.0, 1.5, -3.0, 1000);
CHECK(feq(std::min(hOH, hO), hyd));
hyd = hydro(-2.5, 0.5, 3.0, 1000);
hOH = hbondOH(-2.5, 0.5, 3.0, 1000);
hO = hbondO(-2.5, 0.5, 3.0, 1000);
CHECK(feq(std::min(hOH, hO), hyd));
hyd = hydro(10.0, 1.5, 1.0, 1000);
hOH = hbondOH(10.0, 1.5, 1.0, 1000);
hO = hbondO(10.0, 1.5, 1.0, 1000);
CHECK(feq(std::min(hOH, hO), hyd));
hyd = hydro(6.0, -5.0, 0.0, 1000);
hOH = hbondOH(6.0, -5.0, 0.0, 1000);
hO = hbondO(6.0, -5.0, 0.0, 1000);
CHECK(feq(std::min(hOH, hO), hyd));
hyd = hydro(-3.0, -3.0, 7.0, 1000);
hOH = hbondOH(-3.0, -3.0, 7.0, 1000);
hO = hbondO(-3.0, -3.0, 7.0, 1000);
CHECK(feq(std::min(hOH, hO), hyd));
hyd = hydro(1.0, 0.0, 0.0, 1000);
hOH = hbondOH(1.0, 0.0, 0.0, 1000);
hO = hbondO(1.0, 0.0, 0.0, 1000);
CHECK(feq(std::min(hOH, hO), hyd));
hyd = hydro(0.0, 2.0, 2.0, 1000);
hOH = hbondOH(0.0, 2.0, 2.0, 1000);
hO = hbondO(0.0, 2.0, 2.0, 1000);
CHECK(feq(std::min(hOH, hO), hyd));
hyd = hydro(2.0, -2.0, 0.0, 1000);
hOH = hbondOH(2.0, -2.0, 0.0, 1000);
hO = hbondO(2.0, -2.0, 0.0, 1000);
CHECK(feq(std::min(hOH, hO), hyd));
hyd = hydro(2.0, -2.0, -3.0, 1000);
hOH = hbondOH(2.0, -2.0, -3.0, 1000);
hO = hbondO(2.0, -2.0, -3.0, 1000);
CHECK(feq(std::min(hOH, hO), hyd));
}