match fail

User 870ab5b546

30-06-2014 05:48:23

The target:


<?xml version="1.0" encoding="UTF-8"?>
<cml xmlns="http://www.chemaxon.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.chemaxon.com/marvin/help/formats/schema/mrvSchema_6_2_0.xsd" version="ChemAxon file format v6.2, generated by v6.3.1">
<MDocument>
<MChemicalStruct>
<molecule molID="m1">
<atomArray>
<atom id="a1" elementType="C" x2="61.765003204345700" y2="41.119410101821210">
<scalar id="a1.prop1" title="original index" convention="atomprop" dataType="xsd:integer">0</scalar>
</atom>
<atom id="a2" elementType="C" x2="60.431333863297446" y2="40.349393161262164">
<scalar id="a2.prop1" title="original index" convention="atomprop" dataType="xsd:integer">1</scalar>
</atom>
<atom id="a3" elementType="C" x2="60.431333863297446" y2="38.809359280144086">
<scalar id="a3.prop1" title="original index" convention="atomprop" dataType="xsd:integer">2</scalar>
</atom>
<atom id="a4" elementType="C" x2="61.765003204345700" y2="38.039342339585040">
<scalar id="a4.prop1" title="original index" convention="atomprop" dataType="xsd:integer">3</scalar>
</atom>
<atom id="a5" elementType="C" formalCharge="1" x2="63.098672545393960" y2="38.809359280144086">
<scalar id="a5.prop1" title="original index" convention="atomprop" dataType="xsd:integer">4</scalar>
</atom>
<atom id="a6" elementType="C" x2="63.098672545393960" y2="40.349393161262164">
<scalar id="a6.prop1" title="original index" convention="atomprop" dataType="xsd:integer">5</scalar>
</atom>
<atom id="a7" elementType="O" x2="61.765003204345700" y2="42.659410101821210">
<scalar id="a7.prop1" title="original index" convention="atomprop" dataType="xsd:integer">6</scalar>
</atom>
<atom id="a8" elementType="C" x2="60.676058761318420" y2="36.950397896557760">
<scalar id="a8.prop1" title="original index" convention="atomprop" dataType="xsd:integer">7</scalar>
</atom>
<atom id="a9" elementType="C" x2="62.853947647372980" y2="36.950397896557760">
<scalar id="a9.prop1" title="original index" convention="atomprop" dataType="xsd:integer">8</scalar>
</atom>
</atomArray>
<bondArray>
<bond id="b1" atomRefs2="a1 a2" order="1">
<scalar id="a1a2.prop1" title="original index" convention="bondprop" dataType="xsd:integer">0</scalar>
</bond>
<bond id="b2" atomRefs2="a1 a6" order="2">
<scalar id="a1a6.prop1" title="original index" convention="bondprop" dataType="xsd:integer">5</scalar>
</bond>
<bond id="b3" atomRefs2="a1 a7" order="1">
<scalar id="a1a7.prop1" title="original index" convention="bondprop" dataType="xsd:integer">6</scalar>
</bond>
<bond id="b4" atomRefs2="a2 a3" order="2">
<scalar id="a2a3.prop1" title="original index" convention="bondprop" dataType="xsd:integer">1</scalar>
</bond>
<bond id="b5" atomRefs2="a3 a4" order="1">
<scalar id="a3a4.prop1" title="original index" convention="bondprop" dataType="xsd:integer">2</scalar>
</bond>
<bond id="b6" atomRefs2="a4 a5" order="1">
<scalar id="a4a5.prop1" title="original index" convention="bondprop" dataType="xsd:integer">3</scalar>
</bond>
<bond id="b7" atomRefs2="a4 a8" order="1">
<scalar id="a4a8.prop1" title="original index" convention="bondprop" dataType="xsd:integer">7</scalar>
</bond>
<bond id="b8" atomRefs2="a4 a9" order="1">
<scalar id="a4a9.prop1" title="original index" convention="bondprop" dataType="xsd:integer">8</scalar>
</bond>
<bond id="b9" atomRefs2="a5 a6" order="1">
<scalar id="a5a6.prop1" title="original index" convention="bondprop" dataType="xsd:integer">4</scalar>
</bond>
</bondArray>
</molecule>
</MChemicalStruct>
</MDocument>
</cml>

The query:


<?xml version="1.0" encoding="UTF-8"?>
<cml xmlns="http://www.chemaxon.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.chemaxon.com/marvin/help/formats/schema/mrvSchema_6_2_0.xsd" version="ChemAxon file format v6.2, generated by v6.3.1">
<MDocument>
<MChemicalStruct>
<molecule molID="m1">
<atomArray>
<atom id="a1" elementType="C" x2="50.886776725187076" y2="41.089637743295910">
<scalar id="a1.prop1" title="original index" convention="atomprop" dataType="xsd:integer">29</scalar>
</atom>
<atom id="a2" elementType="C" x2="49.553107384138826" y2="40.319620802736864">
<scalar id="a2.prop1" title="original index" convention="atomprop" dataType="xsd:integer">30</scalar>
</atom>
<atom id="a3" elementType="C" x2="49.553107384138826" y2="38.779586921618790">
<scalar id="a3.prop1" title="original index" convention="atomprop" dataType="xsd:integer">31</scalar>
</atom>
<atom id="a4" elementType="C" x2="50.886776725187076" y2="38.009569981059740">
<scalar id="a4.prop1" title="original index" convention="atomprop" dataType="xsd:integer">32</scalar>
</atom>
<atom id="a5" elementType="C" formalCharge="1" x2="52.220446066235326" y2="38.779586921618790">
<scalar id="a5.prop1" title="original index" convention="atomprop" dataType="xsd:integer">33</scalar>
</atom>
<atom id="a6" elementType="C" x2="52.220446066235326" y2="40.319620802736864">
<scalar id="a6.prop1" title="original index" convention="atomprop" dataType="xsd:integer">34</scalar>
</atom>
<atom id="a7" elementType="O" x2="50.886776725187076" y2="42.629637743295900">
<scalar id="a7.prop1" title="original index" convention="atomprop" dataType="xsd:integer">35</scalar>
<scalar id="a7.prop2" title="paired electrons" convention="atomprop" dataType="xsd:integer">4</scalar>
</atom>
<atom id="a8" elementType="C" x2="49.797832282159790" y2="36.920625538032470">
<scalar id="a8.prop1" title="original index" convention="atomprop" dataType="xsd:integer">36</scalar>
</atom>
<atom id="a9" elementType="C" x2="51.975721168214360" y2="36.920625538032470">
<scalar id="a9.prop1" title="original index" convention="atomprop" dataType="xsd:integer">37</scalar>
</atom>
</atomArray>
<bondArray>
<bond id="b1" atomRefs2="a1 a2" order="1">
<scalar id="a1a2.prop1" title="original index" convention="bondprop" dataType="xsd:integer">28</scalar>
</bond>
<bond id="b2" atomRefs2="a1 a6" order="2">
<bondStereo convention="MDL" conventionValue="3"/>
<scalar id="a1a6.prop1" title="original index" convention="bondprop" dataType="xsd:integer">33</scalar>
</bond>
<bond id="b3" atomRefs2="a1 a7" order="1">
<scalar id="a1a7.prop1" title="original index" convention="bondprop" dataType="xsd:integer">34</scalar>
</bond>
<bond id="b4" atomRefs2="a2 a3" order="2">
<scalar id="a2a3.prop1" title="original index" convention="bondprop" dataType="xsd:integer">29</scalar>
</bond>
<bond id="b5" atomRefs2="a3 a4" order="1">
<scalar id="a3a4.prop1" title="original index" convention="bondprop" dataType="xsd:integer">30</scalar>
</bond>
<bond id="b6" atomRefs2="a4 a5" order="1">
<scalar id="a4a5.prop1" title="original index" convention="bondprop" dataType="xsd:integer">31</scalar>
</bond>
<bond id="b7" atomRefs2="a4 a8" order="1">
<scalar id="a4a8.prop1" title="original index" convention="bondprop" dataType="xsd:integer">35</scalar>
</bond>
<bond id="b8" atomRefs2="a4 a9" order="1">
<scalar id="a4a9.prop1" title="original index" convention="bondprop" dataType="xsd:integer">36</scalar>
</bond>
<bond id="b9" atomRefs2="a5 a6" order="1">
<scalar id="a5a6.prop1" title="original index" convention="bondprop" dataType="xsd:integer">32</scalar>
</bond>
</bondArray>
</molecule>
</MChemicalStruct>
</MDocument>
</cml>

We add a UserComparator called WavyBondMatcher to the search options:


    public boolean compareAtoms(int queryAtomNum, int targetAtomNum) {
boolean match = true;
final int qAtomNum = getOrigQueryAtom(queryAtomNum);
final int tAtomNum = getOrigTargetAtom(targetAtomNum);
if (!Utils.among(-1, qAtomNum, tAtomNum)) {
final int qParity = query.getParity(qAtomNum);
final int tParity = target.getParity(tAtomNum);
final int qLocalParity = query.getLocalParity(qAtomNum);
final int tLocalParity = target.getLocalParity(tAtomNum);
match = !(qParity == PARITY_EITHER
// straight or wavy bond on query stereo
&& qLocalParity == PARITY_EITHER
// wavy bond on query stereo or nonstereo
&& (tParity != PARITY_EITHER
// straight or wavy bond on target stereo
|| tLocalParity != PARITY_EITHER));
// no wavy bond on target stereo or nonstereo
// overall, wavy bond on query stereocenter
// and nonwavy bond on target stereocenter
debugPrint("WavyBondMatcher.compareAtoms: "
+ "query = ", query, ", target = ", target,
"; \nqAtom ", query.getAtom(qAtomNum), qAtomNum + 1,
" has parity ", getEnglish(qParity),
" and local parity ", getEnglish(qLocalParity),
"; tAtom ", target.getAtom(tAtomNum), tAtomNum + 1,
" has parity ", getEnglish(tParity),
" and local parity ", getEnglish(tLocalParity),
"; atoms", match ? "" : " do not", " match");
} // if neither query nor target atom is implicit H
return match;
} // compareAtoms(int, int)

When we include the WavyBondMatcher, the target does not match the query. If we omit the WavyBondMatcher, it does. I see this behavior with both JChem 6.2.1 and 6.3.1. I did not see it in previous versions. I don't understand how our UserComparator could possibly change the search result when all atoms have a parity of 0. 


Here is the relevant code:


    public static boolean matchExact(Molecule respMol, Molecule authMol,
int matchFlags) throws MolCompareException {
final String SELF = "MolCompare.matchExact: ";
final Molecule respMolNorm = // respMol;
Normalize.normalizeCoordinateBonds(respMol);
final Molecule authMolNorm = // authMol;
Normalize.normalizeCoordinateBonds(authMol);
debugPrint(SELF + "matchFlags = ", matchFlags);
debugPrintMRV(SELF + "response:\n", respMolNorm,
"\nauthor structure:\n", authMolNorm);
boolean match = false;
final MolSearchOptions searchOpts = new MolSearchOptions(FULL);
searchOpts.setStereoModel(STEREO_MODEL_GLOBAL);
searchOpts.setVagueBondLevel(VAGUE_BOND_OFF);
// required for comparing nonaromatized aromatic rings
searchOpts.setChargeMatching(CHARGE_MATCHING_EXACT);
searchOpts.setRadicalMatching(RADICAL_MATCHING_EXACT);
searchOpts.setValenceMatching(true);
setMatchOptions(searchOpts, matchFlags);
final MolSearch search = new MolSearch();
search.setSearchOptions(searchOpts);
search.setTarget(respMolNorm);
search.setQuery(authMolNorm);
try {
match = search.isMatching();
debugPrint(SELF + "for target ", respMolNorm, " and query ",
authMolNorm, ", search result is ", match);
// workaround for JChem 5.9 bug of not recognizing allene
// enantiomers as such
if (!match && needAlleneEnant(respMolNorm, matchFlags)) {
debugPrint(SELF + "no match, but structure contains an "
+ "allene, so checking its enantiomer.");
match = matchExact(ChemUtils.getMirror(respMolNorm),
authMolNorm, matchFlags & ~CONSIDER_ENANT);
} // if need to redo search with enantiomer
} catch (MolFormatException e1) { // extremely unlikely
Utils.alwaysPrint("Error in " + SELF);
e1.printStackTrace();
throw new MolCompareException(ERROR + SELF + e1.getMessage());
} catch (SearchException e2) {
Utils.alwaysPrint("Error in " + SELF);
e2.printStackTrace();
throw new MolCompareException(ERROR + SELF + e2.getMessage());
} // try
return match;
} // matchExact(Molecule, Molecule, int)


private static void setMatchOptions(MolSearchOptions searchOpts,
int matchFlags) {
final String SELF = "MolCompare.setMatchOptions: ";
final int searchType = searchOpts.getSearchType();
debugPrint(SELF + "searchType = ",
(searchType == DUPLICATE ? "DUPLICATE"
: searchType == FULL ? "FULL" : searchType));
final boolean ignore2D =
(matchFlags & IGNORE_DBL_BOND_STEREO) != 0;
final boolean ignore3D =
(matchFlags & IGNORE_TETRAHEDRAL_STEREO) != 0;
final boolean wavyAnd = (matchFlags & WAVY_AND) != 0;
final boolean considerEnant = (matchFlags & CONSIDER_ENANT) != 0;
final boolean exactExplicitHMatching =
(matchFlags & EXACT_EXPLICIT_H) != 0;
final boolean electronMatching = (matchFlags & ELECTRONS) != 0;
final boolean isotopeLenient = (matchFlags & ISOTOPE_PERMISSIVE) != 0;
if (exactExplicitHMatching) {
debugPrint(SELF + "adding ExplicitHMatcher.");
searchOpts.addUserComparator(new ExplicitHMatcher());
} else debugPrint(SELF + "not adding ExplicitHMatcher.");
if (electronMatching) {
debugPrint(SELF + "adding ElectronMatcher.");
searchOpts.addUserComparator(new ElectronMatcher());
} else debugPrint(SELF + "not adding ElectronMatcher.");
if (ignore2D) {
debugPrint(SELF + "ignoring 2D stereochemistry.");
searchOpts.setDoubleBondStereoMatchingMode(DBS_NONE);
} else {
debugPrint(SELF + "pay attention to 2D stereochemistry.");
searchOpts.setDoubleBondStereoMatchingMode(DBS_ALL);
} // if ignore2D
if (ignore3D) {
debugPrint(SELF + "ignoring 3D stereochemistry.");
searchOpts.setStereoSearchType(STEREO_IGNORE);
} else {
debugPrint(SELF + "pay attention to 3D stereochemistry.");
if (searchType != DUPLICATE) {
searchOpts.setStereoSearchType(STEREO_SPECIFIC);
} // if search initially set to FULL, not DUPLICATE
if (considerEnant) {
debugPrint(SELF + "enantiomer will match as well.");
searchOpts.setStereoSearchType(STEREO_ENANTIOMER);
} // if should consider enantiomers as well
if (wavyAnd) {
searchOpts.setKeepQueryOrder(true); // ChemAxon says it's needed
debugPrint(SELF + "adding WavyBondMatcher.");
searchOpts.addUserComparator(new WavyBondMatcher());
} else debugPrint(SELF + "not adding WavyBondMatcher.");
// Note: JChem 5.6.0.0 doesn't match allene enantiomers
// when the search type is STEREO_ENANTIOMER
searchOpts.setIgnoreAlleneStereo(false); // odd-numbered cumulenes
searchOpts.setIgnoreAxialStereo(false); // allenes & biaryls
searchOpts.setIgnoreSynAntiStereo(true); // otherwise random orientations matter
} // if ignore3D
if (isotopeLenient) {
debugPrint(SELF + "author's unspecified isotopes can match any "
+ "isotopes in response.");
searchOpts.setIsotopeMatching(ISOTOPE_MATCHING_DEFAULT);
} else {
debugPrint(SELF + "author's unspecified isotopes must be unspecified "
+ "in response.");
searchOpts.setIsotopeMatching(ISOTOPE_MATCHING_EXACT);
} // isotopeLenient
} // setMatchOptions(MolSearchOptions, int)

and here is the debugging output:


MolCompare.setMatchOptions: searchType = FULL
MolCompare.setMatchOptions: not adding ExplicitHMatcher.
MolCompare.setMatchOptions: not adding ElectronMatcher.
MolCompare.setMatchOptions: pay attention to 2D stereochemistry.
MolCompare.setMatchOptions: pay attention to 3D stereochemistry.
MolCompare.setMatchOptions: adding WavyBondMatcher.
MolCompare.setMatchOptions: author's unspecified isotopes must be unspecified in response.
MolCompare.matchExact: for target CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4| and query CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, search result is false

This mismatch is an urgent problem, so I hope you can respond soon with your insight.

User 870ab5b546

30-06-2014 13:38:54

I turned on the debug printing for the WavyBondComparator, and I have confirmed that it is returning true. So even though the presence/absence of the WavyBondComparator determines whether the match fails/succeeds, the output of the WavyBondComparator isn't what appears to make the difference.


MolCompare.matchExact: matchFlags = 1
MolCompare.matchExact: response:
<?xml version="1.0" encoding="UTF-8"?>
<cml xmlns="http://www.chemaxon.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.chemaxon.com/marvin/help/formats/schema/mrvSchema_6_2_0.xsd" version="ChemAxon file format v6.2, generated by v6.3.1">
<MDocument>
<MChemicalStruct>
<molecule molID="m1">
<atomArray atomID="a1 a2 a3 a4 a5 a6 a7 a8 a9" elementType="C C C C C C C C O" formalCharge="0 0 0 0 1 0 0 0 0" x2="-0.6256250143051147 -1.959294355353373 -1.959294355353373 -0.6256250143051147 0.7080443267431435 0.7080443267431435 -1.714569457332398 0.1443749856948855 -0.6256250143051146" y2="1.2031588894627314 0.4331419489036908 -1.1068919322143904 -1.8769088727734309 -1.1068919322143904 0.4331419489036908 -2.965853315800714 -3.2105879946014664 2.7431588894627312"/>
<bondArray>
<bond id="b1" atomRefs2="a1 a2" order="1"/>
<bond id="b2" atomRefs2="a1 a6" order="2"/>
<bond id="b3" atomRefs2="a1 a9" order="1"/>
<bond id="b4" atomRefs2="a2 a3" order="2"/>
<bond id="b5" atomRefs2="a3 a4" order="1"/>
<bond id="b6" atomRefs2="a4 a5" order="1"/>
<bond id="b7" atomRefs2="a4 a7" order="1"/>
<bond id="b8" atomRefs2="a4 a8" order="1"/>
<bond id="b9" atomRefs2="a5 a6" order="1"/>
</bondArray>
</molecule>
</MChemicalStruct>
</MDocument>
</cml>
author structure:
<?xml version="1.0" encoding="UTF-8"?>
<cml xmlns="http://www.chemaxon.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.chemaxon.com/marvin/help/formats/schema/mrvSchema_6_2_0.xsd" version="ChemAxon file format v6.2, generated by v6.3.1">
<MDocument>
<MChemicalStruct>
<molecule molID="m1">
<atomArray atomID="a1 a2 a3 a4 a5 a6 a7 a8 a9" elementType="C C C C C C C C O" formalCharge="0 0 0 0 1 0 0 0 0" x2="-0.6256250143051147 -1.959294355353373 -1.959294355353373 -0.6256250143051147 0.7080443267431435 0.7080443267431435 -1.714569457332398 0.1443749856948855 -0.6256250143051146" y2="1.2031588894627314 0.4331419489036908 -1.1068919322143904 -1.8769088727734309 -1.1068919322143904 0.4331419489036908 -2.965853315800714 -3.2105879946014664 2.7431588894627312"/>
<bondArray>
<bond id="b1" atomRefs2="a1 a2" order="1"/>
<bond id="b2" atomRefs2="a2 a3" order="2"/>
<bond id="b3" atomRefs2="a3 a4" order="1"/>
<bond id="b4" atomRefs2="a4 a5" order="1"/>
<bond id="b5" atomRefs2="a5 a6" order="1"/>
<bond id="b6" atomRefs2="a4 a7" order="1"/>
<bond id="b7" atomRefs2="a4 a8" order="1"/>
<bond id="b8" atomRefs2="a1 a9" order="1"/>
<bond id="b9" atomRefs2="a1 a6" order="2">
<bondStereo convention="MDL" conventionValue="3"/>
</bond>
</bondArray>
</molecule>
</MChemicalStruct>
</MDocument>
</cml>
MolCompare.setMatchOptions: searchType = FULL
MolCompare.setMatchOptions: not adding ExplicitHMatcher.
MolCompare.setMatchOptions: not adding ElectronMatcher.
MolCompare.setMatchOptions: pay attention to 2D stereochemistry.
MolCompare.setMatchOptions: pay attention to 3D stereochemistry.
MolCompare.setMatchOptions: adding WavyBondMatcher.
MolCompare.setMatchOptions: author's unspecified isotopes must be unspecified in response.
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C1 has parity NONE and local parity NONE; tAtom C1 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C2 has parity NONE and local parity NONE; tAtom C1 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C2 has parity NONE and local parity NONE; tAtom C2 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C2 has parity NONE and local parity NONE; tAtom C3 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C2 has parity NONE and local parity NONE; tAtom C6 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C3 has parity NONE and local parity NONE; tAtom C1 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C3 has parity NONE and local parity NONE; tAtom C2 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C3 has parity NONE and local parity NONE; tAtom C3 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C3 has parity NONE and local parity NONE; tAtom C6 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C4 has parity NONE and local parity NONE; tAtom C4 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C[+1]5 has parity NONE and local parity NONE; tAtom C[+1]5 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C6 has parity NONE and local parity NONE; tAtom C1 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C6 has parity NONE and local parity NONE; tAtom C2 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C6 has parity NONE and local parity NONE; tAtom C3 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C6 has parity NONE and local parity NONE; tAtom C6 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C7 has parity NONE and local parity NONE; tAtom C1 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C7 has parity NONE and local parity NONE; tAtom C2 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C7 has parity NONE and local parity NONE; tAtom C3 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C7 has parity NONE and local parity NONE; tAtom C4 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C7 has parity NONE and local parity NONE; tAtom C6 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C7 has parity NONE and local parity NONE; tAtom C7 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C7 has parity NONE and local parity NONE; tAtom C8 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C8 has parity NONE and local parity NONE; tAtom C1 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C8 has parity NONE and local parity NONE; tAtom C2 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C8 has parity NONE and local parity NONE; tAtom C3 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C8 has parity NONE and local parity NONE; tAtom C4 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C8 has parity NONE and local parity NONE; tAtom C6 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C8 has parity NONE and local parity NONE; tAtom C7 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom C8 has parity NONE and local parity NONE; tAtom C8 has parity NONE and local parity NONE; atoms match
WavyBondMatcher.compareAtoms: query = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, target = CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|;
qAtom O9 has parity NONE and local parity NONE; tAtom O9 has parity NONE and local parity NONE; atoms match
MolCompare.matchExact: for target CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4| and query CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, search result is false

User 870ab5b546

30-06-2014 13:49:36

Just to show I'm not crazy, here's the output with the WavyBondComparator not added to the search options:


MolCompare.matchExact: matchFlags = 1
MolCompare.matchExact: response:
<?xml version="1.0" encoding="UTF-8"?>
<cml xmlns="http://www.chemaxon.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.chemaxon.com/marvin/help/formats/schema/mrvSchema_6_2_0.xsd" version="ChemAxon file format v6.2, generated by v6.3.1">
<MDocument>
<MChemicalStruct>
<molecule molID="m1">
<atomArray atomID="a1 a2 a3 a4 a5 a6 a7 a8 a9" elementType="C C C C C C C C O" formalCharge="0 0 0 0 1 0 0 0 0" x2="-0.6256250143051147 -1.959294355353373 -1.959294355353373 -0.6256250143051147 0.7080443267431435 0.7080443267431435 -1.714569457332398 0.1443749856948855 -0.6256250143051146" y2="1.2031588894627314 0.4331419489036908 -1.1068919322143904 -1.8769088727734309 -1.1068919322143904 0.4331419489036908 -2.965853315800714 -3.2105879946014664 2.7431588894627312"/>
<bondArray>
<bond id="b1" atomRefs2="a1 a2" order="1"/>
<bond id="b2" atomRefs2="a1 a6" order="2"/>
<bond id="b3" atomRefs2="a1 a9" order="1"/>
<bond id="b4" atomRefs2="a2 a3" order="2"/>
<bond id="b5" atomRefs2="a3 a4" order="1"/>
<bond id="b6" atomRefs2="a4 a5" order="1"/>
<bond id="b7" atomRefs2="a4 a7" order="1"/>
<bond id="b8" atomRefs2="a4 a8" order="1"/>
<bond id="b9" atomRefs2="a5 a6" order="1"/>
</bondArray>
</molecule>
</MChemicalStruct>
</MDocument>
</cml>
author structure:
<?xml version="1.0" encoding="UTF-8"?>
<cml xmlns="http://www.chemaxon.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.chemaxon.com/marvin/help/formats/schema/mrvSchema_6_2_0.xsd" version="ChemAxon file format v6.2, generated by v6.3.1">
<MDocument>
<MChemicalStruct>
<molecule molID="m1">
<atomArray atomID="a1 a2 a3 a4 a5 a6 a7 a8 a9" elementType="C C C C C C C C O" formalCharge="0 0 0 0 1 0 0 0 0" x2="-0.6256250143051147 -1.959294355353373 -1.959294355353373 -0.6256250143051147 0.7080443267431435 0.7080443267431435 -1.714569457332398 0.1443749856948855 -0.6256250143051146" y2="1.2031588894627314 0.4331419489036908 -1.1068919322143904 -1.8769088727734309 -1.1068919322143904 0.4331419489036908 -2.965853315800714 -3.2105879946014664 2.7431588894627312"/>
<bondArray>
<bond id="b1" atomRefs2="a1 a2" order="1"/>
<bond id="b2" atomRefs2="a2 a3" order="2"/>
<bond id="b3" atomRefs2="a3 a4" order="1"/>
<bond id="b4" atomRefs2="a4 a5" order="1"/>
<bond id="b5" atomRefs2="a5 a6" order="1"/>
<bond id="b6" atomRefs2="a4 a7" order="1"/>
<bond id="b7" atomRefs2="a4 a8" order="1"/>
<bond id="b8" atomRefs2="a1 a9" order="1"/>
<bond id="b9" atomRefs2="a1 a6" order="2">
<bondStereo convention="MDL" conventionValue="3"/>
</bond>
</bondArray>
</molecule>
</MChemicalStruct>
</MDocument>
</cml>
MolCompare.setMatchOptions: searchType = FULL
MolCompare.setMatchOptions: not adding ExplicitHMatcher.
MolCompare.setMatchOptions: not adding ElectronMatcher.
MolCompare.setMatchOptions: pay attention to 2D stereochemistry.
MolCompare.setMatchOptions: pay attention to 3D stereochemistry.
MolCompare.setMatchOptions: not adding WavyBondMatcher.
MolCompare.setMatchOptions: author's unspecified isotopes must be unspecified in response.
MolCompare.matchExact: for target CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4| and query CC1(C)[CH+]C=C(O)C=C1 |c:7,t:4|, search result is true

ChemAxon d4fff15f08

30-06-2014 14:52:35

Hi Bob,


 


Thanks for the detailed info, we are (not will) investigating it... and will be back to you as we have news.


 


Thanks for your patience,


Norbert

ChemAxon d9cc14700b

30-06-2014 15:43:10

Hi Bob,


You are not crazy, I managed to reproduce it here in Budapest, Hungary too.


In short, the problem is that Molecule.getParity call in your WavyBondMatcher has a side effect and changes the molecule somehow which makes the matching fail. This seems to be a bug in the chemaxon.struc.Molecule itself and I will forward this issue to our core team.


However, there is a workaround which you can apply until this bug is fixed: you can clone the molecule before retrieving the parity hence preventing changing the state of the original molecule on which other parts of the matching works. This of course may have some performance impact but hopefully it is acceptable temporarily.


The easiest way of this workaround is to clone the molecule as soon as the WavyBondMatcher gets its hands on it :


    @Override
public void setQuery(Molecule q) {
super.setQuery(q.cloneMolecule());
}

@Override
public void setTarget(Molecule t) {
super.setTarget(t.cloneMolecule());
}


Best Regards,
Gabor 

User 870ab5b546

30-06-2014 17:41:00

Thanks, that solves the problem for now. But it must add an incredibly large amount of processing time to clone both molecules every time we call the UserComparator. So I'd appreciate a better fix ASAP! Thanks.

User 870ab5b546

01-07-2014 00:49:33

Correct me if I'm wrong, but wouldn't it be a little more efficient to clone the molecules just before we get their parity, so that we don't have to clone them if one of the atoms is an implicit H atom? 


    public boolean compareAtoms(int queryAtomNum, int targetAtomNum) {
boolean match = true;
final int qAtomNum = getOrigQueryAtom(queryAtomNum);
final int tAtomNum = getOrigTargetAtom(targetAtomNum);
if (!Utils.among(-1, qAtomNum, tAtomNum)) {
final Molecule queryCopy = query.cloneMolecule();
final Molecule targetCopy = target.cloneMolecule();
final int qParity = queryCopy.getParity(qAtomNum);
final int tParity = targetCopy.getParity(tAtomNum);
final int qLocalParity = queryCopy.getLocalParity(qAtomNum);
final int tLocalParity = targetCopy.getLocalParity(tAtomNum);
match = !(qParity == PARITY_EITHER
// straight or wavy bond on query stereo
&& qLocalParity == PARITY_EITHER
// wavy bond on query stereo or nonstereo
&& (tParity != PARITY_EITHER
// straight or wavy bond on target stereo
|| tLocalParity != PARITY_EITHER));
// no wavy bond on target stereo or nonstereo
// overall, wavy bond on query stereocenter
// and nonwavy bond on target stereocenter
debugPrint("WavyBondMatcher.compareAtoms: "
+ "query = ", query, ", target = ", target,
"; \nqAtom ", query.getAtom(qAtomNum), qAtomNum + 1,
" has parity ", getEnglish(qParity),
" and local parity ", getEnglish(qLocalParity),
"; tAtom ", target.getAtom(tAtomNum), tAtomNum + 1,
" has parity ", getEnglish(tParity),
" and local parity ", getEnglish(tLocalParity),
"; atoms", match ? "" : " do not", " match");
} // if neither query nor target atom is implicit H
return match;
} // compareAtoms(int, int)

ChemAxon d9cc14700b

02-07-2014 07:59:00

Hi Bob,


The problem with your approach is that it clones the query and target every time a comparison of non implicit atom pairs happen, while my approach cloned them once when the matcher got them. But you can improve your solution by storing the cloned version in a field of the matcher and clone only if it had not been already cloned.


However, I am not sure how big performance benefit you gain with this, so I suggest you to measure first.


Best Regards,
Gabor 

User 870ab5b546

02-07-2014 13:02:22

Oh, I see, the clone only happens once because it is in the parent comparator. I'll switch back to your solution. One clone per search oughtn't affect performance much.

User 870ab5b546

29-07-2014 13:26:22

Hi, any progress on this bug's fix?

ChemAxon d9cc14700b

30-07-2014 06:44:21

Hi Bob,


Sorry for not updating you about the progress. This bug has been fixed in 14.07.21 release.


Best Regards,
Gabor