obrms improvements

Add timeout option (necessary for mols with many symmetries) and fix bug
with default behavior (was not doing one to one mappings).  Also, added
test.
This commit is contained in:
David Koes 2023-07-01 15:02:06 -04:00
parent 2b211d6acf
commit 253271442a
2 changed files with 33 additions and 5 deletions

View File

@ -17,6 +17,7 @@ and so you can quickly develop the tests and try them out.
import os
import re
import sys
import math
import unittest
from subprocess import CalledProcessError, Popen, PIPE, check_output, STDOUT
@ -521,5 +522,22 @@ charge 1
# mol2 displays element twice
self.assertEqual(output.count('H'), 12)
def testOBRMS(self):
'''Sanity checks for obrms'''
sdffile = self.getTestFile('testsym_2Dtests.sdf')
output, err = run_exec( f"obrms -t 10 {sdffile} {sdffile}")
# all rmsds should be zero
rmsds = [float(line.split()[-1]) for line in output.split('\n') if line]
for rmsd in rmsds:
self.assertEqual(rmsd, 0, "RMSD not zero between identical structures")
output, err = run_exec( f"obrms -t 10 -f {sdffile} {sdffile}")
#first zero, second nonzero, last inf
rmsds = [float(line.split()[-1]) for line in output.split('\n') if line]
self.assertEqual(rmsds[0],0)
self.assertEqual(rmsds[1],2.73807)
self.assertEqual(rmsds[-1],math.inf)
if __name__ == "__main__":
unittest.main()

View File

@ -165,10 +165,13 @@ class Matcher
};
public:
Matcher(OBMol& mol) : ref(&mol)
Matcher(OBMol& mol, int timeout) : ref(&mol)
{
query = std::shared_ptr<OBQuery>(CompileMoleculeQuery(&mol));
mapper = std::shared_ptr<OBIsomorphismMapper>(OBIsomorphismMapper::GetInstance(query.get()));
if(timeout > 0) {
mapper->SetTimeout(timeout);
}
}
@ -221,6 +224,7 @@ int main(int argc, char **argv)
string fileRef;
string fileTest;
string fileOut;
int timeout = 0;
const char *helpmsg =
"obrms: Computes the heavy-atom RMSD of identical compound structures.\n"
@ -231,19 +235,21 @@ int main(int argc, char **argv)
"\t -m, --minimize compute minimum RMSD\n"
"\t -x, --cross compute all n^2 RMSDs between molecules of reference file\n"
"\t -s, --separate separate reference file into constituent molecules and report best RMSD\n"
"\t -t, --timeout give up on matching after specified number of seconds\n"
"\t -h, --help help message\n";
struct option long_options[] = {
{"firstonly", no_argument, nullptr, 'f'},
{"minimize", no_argument, nullptr, 'm'},
{"cross", no_argument, nullptr, 'x'},
{"separate", no_argument, nullptr, 's'},
{"timeout", required_argument, nullptr, 't'},
{"out", required_argument, nullptr, 'o'},
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0}
};
int option_index = 0;
int c = 0;
while ((c = getopt_long(argc, argv, "hfmxso:", long_options, &option_index) ) != -1) {
while ((c = getopt_long(argc, argv, "hfmxst:o:", long_options, &option_index) ) != -1) {
switch(c) {
case 'o':
fileOut = optarg;
@ -260,6 +266,9 @@ int main(int argc, char **argv)
case 's':
separate = true;
break;
case 't':
timeout = atoi(optarg);
break;
case 'h':
cout << helpmsg;
exit(0);
@ -325,7 +334,7 @@ int main(int argc, char **argv)
for(unsigned i = 0, n = refmols.size() ; i < n; i++) {
OBMol& ref = refmols[i];
Matcher matcher(ref);
Matcher matcher(ref, timeout);
cout << ref.GetTitle();
for(unsigned j = 0; j < n; j++) {
OBMol& moltest = refmols[j];
@ -337,6 +346,8 @@ int main(int argc, char **argv)
} else {
OBConversion testconv(fileTest);
//check comparison file
while (refconv.Read(&molref))
{
@ -350,11 +361,10 @@ int main(int argc, char **argv)
vector<Matcher> matchers;
for(unsigned i = 0, n = refmols.size(); i < n; i++) {
processMol(refmols[i]);
Matcher matcher(refmols[i]); // create the matcher
Matcher matcher(refmols[i], timeout); // create the matcher
matchers.push_back(matcher);
}
OBConversion testconv(fileTest);
OBMol moltest;
while (testconv.Read(&moltest))
{