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.