result depends on contraction state of shortcut group

User 870ab5b546

05-10-2014 18:48:13

Using either JChem 14.9.8.0 and 14.9.22.0, when I submit this substrate with its contracted CO2H shortcut group:


<?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/schema/mrvSchema_14_8_4.xsd" version="ChemAxon file format v14.8.4, generated by v14.9.22.0">
<MDocument>
<MChemicalStruct>
<molecule molID="m1">
<atomArray atomID="a1 a2 a3 a4 a5 a6 a7 a8" elementType="C C C C C C Br R" sgroupRef="0 0 0 0 0 0 0 sg1" x2="-2.068000078201294 -3.4016694192495525 -3.4016694192495525 -2.068000078201294 -0.7343307371530357 -0.7343307371530357 -4.735348541077588 0.5993532749841951" y2="2.0240338784954766 1.254016937936436 -0.286016943181645 -1.0560338837406855 -0.286016943181645 1.254016937936436 -1.0560169431816455 2.0240084676103276"/>
<bondArray>
<bond id="b1" atomRefs2="a1 a2" order="1"/>
<bond id="b2" atomRefs2="a1 a6" order="2"/>
<bond id="b3" atomRefs2="a2 a3" order="2"/>
<bond id="b4" atomRefs2="a3 a4" order="1"/>
<bond id="b5" atomRefs2="a4 a5" order="2"/>
<bond id="b6" atomRefs2="a5 a6" order="1"/>
<bond id="b7" atomRefs2="a3 a7" order="1"/>
<bond id="b8" atomRefs2="a6 a8" order="1"/>
</bondArray>
<molecule id="sg1" role="SuperatomSgroup" title="CO2H" leftName="HO2C" molID="m2">
<atomArray atomID="a9 a10 a11" elementType="C O O" attachmentPoint="1 0 0" sgroupAttachmentPoint="1 0 0" x2="8.686674883414504 7.146674883445563 9.456683353709552" y2="0.9796716551391549 0.9796814358113408 2.3133458866042"/>
<bondArray>
<bond id="b9" atomRefs2="a10 a9" order="1"/>
<bond id="b10" atomRefs2="a9 a11" order="2"/>
</bondArray>
<AttachmentPointArray>
<attachmentPoint atom="a9" order="1" bond="b8"/>
</AttachmentPointArray>
</molecule>
</molecule>
</MChemicalStruct>
</MDocument>
</cml>

to Reactor with this reaction definition:

<?xml version="1.0" ?>
<MDocument>
<MChemicalStruct>
<reaction>
<propertyList>
<property dictRef="NAME" title="NAME">
<scalar><![CDATA[arene nitration]]></scalar>
</property>
<property dictRef="REACTIVITY" title="REACTIVITY">
<scalar><![CDATA[energyE(ratom(1)) - min(energyE(reactant(0), filter(reactant(0), "aromaticAtom()"))) <= 0.077]]></scalar>
</property>
<property dictRef="EXPLAIN_REACTIVITY" title="EXPLAIN_REACTIVITY">
<scalar><![CDATA[Aromatic atoms must have localization energy close to the compound's minimum to provide the main product. ]]></scalar>
</property>
<property dictRef="SELECTIVITY" title="SELECTIVITY">
<scalar>-stericHindrance(ratom(1))</scalar>
</property>
<property dictRef="EXPLAIN_SELECTIVITY" title="EXPLAIN_SELECTIVITY">
<scalar><![CDATA[Among atoms determined by the reactivity rule, aromatic atom with the least steric hindrance provides the main product. ]]></scalar>
</property>
<property dictRef="TOLERANCE" title="TOLERANCE">
<scalar>0.04</scalar>
</property>
<property dictRef="EXPLAIN_TOLERANCE" title="EXPLAIN_TOLERANCE">
<scalar><![CDATA[Permits ortho products for O(-) and OH.]]></scalar>
</property>
<property dictRef="Stop after one reaction" title="Stop after one reaction">
<scalar>true</scalar>
</property>
</propertyList>
<reactantList>
<molecule molID="m1">
<atomArray
atomID="a1 a2"
elementType="C H"
mrvMap="1 2"
mrvQueryProps="a1 0"
x2="-8.620575316403775 -8.620575316403775"
y2="11.09088749380601 12.630887493806009"
/>
<bondArray>
<bond atomRefs2="a1 a2" order="1" />
</bondArray>
</molecule>
</reactantList>
<productList>
<molecule molID="m2">
<atomArray
atomID="a1 a2 a3 a4"
elementType="N C O O"
formalCharge="1 0 0 -1"
mrvMap="3 1 0 0"
mrvQueryProps="0 a1 0 0"
x2="9.966641700900924 10.069514351401217 8.632962579072888 11.30032082272896"
y2="11.82239134287164 10.285831152778506 12.592391342871641 12.59239134287164"
/>
<bondArray>
<bond atomRefs2="a1 a4" order="1" />
<bond atomRefs2="a2 a1" order="1" />
<bond atomRefs2="a1 a3" order="2" />
</bondArray>
</molecule>
</productList>
</reaction>
</MChemicalStruct>
</MDocument>

utilizing this snippet of code:


            caller.debugPrint("Permutation ", perm, " of ", numPerms,
": ", starters);
reactor.setReactants(starters);
for (int reactCt = 0; reactCt < MAX_REACT; reactCt++) {
reactorProds = reactor.react();
if (Utils.isEmpty(reactorProds)) {
caller.debugPrint("Product set ", reactCt + 1,
" from Reactor for permutation ", perm,
" is empty; breaking.");
break;
} // if there are no products
gotProducts = true;
caller.debugPrint("Product set ", reactCt + 1,
" obtained from Reactor for permutation ", perm, ".");
...
caller.debugPrint("After implicitizing H atoms, ",
"Reactor products are: ", reactorProds);
...
} // while still getting products from reactor

I get a single product (what I think is the wrong one, but that's not really at issue here), 2-nitro-4-bromobenzoic acid. Here is the relevant part of the log output:


Permutation 1 of 1: [[#8]-[#6](=O)-c1ccc(Br)cc1]
Product set 1 obtained from Reactor for permutation 1.
After implicitizing H atoms, Reactor products are: [[#8]-[#6](=O)-c1ccc(Br)cc1-[#7+](-[#8-])=O]
Product set 2 from Reactor for permutation 1 is empty; breaking.
SingleRxnSolver.calcProducts: For loop 1, thisRxnLoopProducts is: [[#8]-[#6](=O)-c1ccc(Br)cc1-[#7+](-[#8-])=O]

However, if I expand or ungroup the CO2H shortcut group in the substrate, then I get two products, both the 2- and 3- isomers. Here is the relevant part of the log output.


Permutation 1 of 1: [[#8]-[#6](=O)-c1ccc(Br)cc1]
Product set 1 obtained from Reactor for permutation 1.
After implicitizing H atoms, Reactor products are: [[#8]-[#6](=O)-c1ccc(Br)cc1-[#7+](-[#8-])=O]
Product set 2 obtained from Reactor for permutation 1.
After implicitizing H atoms, Reactor products are: [[#8]-[#6](=O)-c1ccc(Br)c(c1)-[#7+](-[#8-])=O]
Product set 3 from Reactor for permutation 1 is empty; breaking.
SingleRxnSolver.calcProducts: For loop 1, thisRxnLoopProducts is: [[#8]-[#6](=O)-c1ccc(Br)cc1-[#7+](-[#8-])=O.[#8]-[#6](=O)-c1ccc(Br)c(c1)-[#7+](-[#8-])=O]

Please note also that before sending any substrate to Reactor, our code subjects it to the command:


mol.ungroupSgroups(SHORTCUT_GROUPS);

where SHORTCUT_GROUPS is defined:


EnumSet<SgroupType> SHORTCUT_GROUPS = EnumSet.of(SgroupType.SUPERATOM);

It seems to me that there should be zero difference between the substrate with the contracted shortcut group and the same substrate with the expanded or ungrouped shortcut group. So why am I observing different results???

ChemAxon e08c317633

06-10-2014 09:38:44

We cannot reproduce the error with Reactor and Standardizer command line applications (14.9.22.0).


$ react -r arene_nitration.mrv input.mrv
OC(=O)C1=C(C=C(Br)C=C1)[N+]([O-])=O

$ standardize -c ungroupsgroups input.mrv -f mrv | react -r arene_nitration.mrv
OC(=O)C1=CC=C(Br)C=C1[N+]([O-])=O

First command runs reactor with the submitted input reactant and reaction, the second command first ungoups all abbreviated groups in the input reactant and then runs reactor. The results are the same.


The error should be somewhere in your code, but from the code snippet you provided it cannot be identified where.  

User 870ab5b546

06-10-2014 13:40:05

Well, very interesting. I also cannot reproduce the problem when I copy the structure I gave you, paste it into the test page, and submit the structure. But when I delete the CO2H group, then redraw it, and then expand it, I can repeat the problem. So this problem may be related to some of the recent problems with shortcut groups that I've noted elsewhere in this forum.


I set up a JSP page here to illustrate the problem. Draw the CO2H shortcut group manually, then expand it. I've attached the page here so you can look at the code. It does use some external methods. Here's the normalizeNoClone() method (value of isMech would be false):


    public static void normalizeNoClone(Molecule mol, boolean isMech) {
final String SELF = "Normalize.normalizeNoClone: ";
mol.aromatize(MoleculeGraph.AROM_GENERAL);
if (!isMech) mol.ungroupSgroups(SHORTCUT_GROUPS);
normalizeRadicals(mol);
normalizeStereoBonds(mol);
if (isMech) removeUnbondedMulticenterAtoms(mol);
else try {
final Standardizer localStandardizer =
new Standardizer(AppConfig.standardizer);
localStandardizer.standardize(mol);
} catch (IllegalArgumentException e) {
Utils.alwaysPrint(SELF + "caught IllegalArgumentException trying "
+ "to create copy of AppConfig.standardizer or trying "
+ "to standardize:\n", mol);
e.printStackTrace();
} catch (LicenseException e) {
Utils.alwaysPrint(SELF + "caught LicenseException.");
e.printStackTrace();
} // try
mol.valenceCheck(); // resets implicit H counts
} // normalizeNoClone(Molecule, boolean)

public static void normalizeRadicals(Molecule mol) {
for (final MolAtom atom : mol.getAtomArray()) {
normalizeRadical(atom);
} // for each atom
} // normalizeRadicals(Molecule)

public static void normalizeRadical(MolAtom atom) {
final int rad = atom.getRadicalValue().getIntValue();
if (Utils.among(rad,
Radical.DIVALENT_SINGLET.getIntValue(),
Radical.DIVALENT_TRIPLET.getIntValue())) {
atom.setRadicalValue(Radical.DIVALENT);
} else if (Utils.among(rad,
Radical.TRIVALENT.getIntValue(),
Radical.TRIVALENT_DOUBLET.getIntValue(),
Radical.TRIVALENT_QUARTET.getIntValue())) {
atom.setRadicalValue(Radical.MONOVALENT);
}
} // normalizeRadical(MolAtom)

public static void normalizeStereoBonds(Molecule mol) {
int bondNum = 0;
for (final MolBond bond : mol.getBondArray()) {
final int stereo = StereoFunctions.getBondStereoFlags(bond);
if (Utils.among(stereo, MolBond.UP, MolBond.DOWN, MolBond.WAVY)) {
final MolAtom atom1 = bond.getAtom1();
final MolAtom atom2 = bond.getAtom2();
final int atom1Num = mol.indexOf(atom1);
final int atom2Num = mol.indexOf(atom2);
// flip switched up, down, wavy bonds
final int parity1 = mol.getParity(atom1Num);
final int parity2 = mol.getParity(atom2Num);
final boolean atom1InStereoDbl = isInStereoDoubleBond(atom1);
final boolean atom2InStereoDbl = isInStereoDoubleBond(atom2);
if (!Utils.among(parity1, MolAtom.PARITY_EVEN,
MolAtom.PARITY_ODD, MolAtom.PARITY_EITHER)
&& (Utils.among(parity2, MolAtom.PARITY_EVEN,
MolAtom.PARITY_ODD, MolAtom.PARITY_EITHER)
|| (atom2InStereoDbl && !atom1InStereoDbl))) {
bond.swap();
} // if bond is pointing from nonstereocenter to stereocenter
} // up or down or wavy
} // for each bond
} // normalizeStereoBonds(Molecule)

private static boolean isInStereoDoubleBond(MolAtom atom) {
for (final MolBond bond : atom.getBondArray()) {
if (bond.getType() == 2) {
final int stereo = bond.calcStereo2();
return stereo != 0;
} // if bond is double bond
} // for each bond
return false;
} // isInStereoDoubleBond(MolAtom)

Let me know if you need to look at any others as well.


P.S. We just updated to Java 8. No change in behavior.