electron-flow arrows and shortcut groups

User 870ab5b546

08-12-2010 04:08:37

Suppose I draw CH3-OEt using a shortcut group for the OEt group, and I draw an electron-flow arrow from the C-OEt bond to the OEt group.  In this case, getMolObject(MEFlow.E_SINK) returns the O atom that is the attachment point of the shortcut group, and getMolObject(MEFlow.E_SOURCE) returns the C and the O atoms, not the C and the shortcut group.


<?xml version="1.0" ?>
<cml>
<MDocument>
<MChemicalStruct>
<molecule molID="m1">
<atomArray
atomID="a1 a2"
elementType="C R"
sgroupRef="0 sg1"
x2="-7.363124847412109 -5.875599074926944"
y2="2.40625 2.007668670542118"
/>
<bondArray>
<bond atomRefs2="a1 a2" order="1" />
</bondArray>
<molecule id="sg1" role="SuperatomSgroup" title="OEt" leftName="EtO" molID="m2">
<atomArray
atomID="a3 a4 a5"
elementType="O C C"
attachmentPoint="1 0 0"
sgroupAttachmentPoint="1 0 0"
x2="-3.1214629396916767 -4.4551420615197115 -5.788821183347747"
y2="0.7334751182874921 -0.03652488171250834 0.7334751182874912"
/>
<bondArray>
<bond atomRefs2="a4 a3" order="1" />
<bond atomRefs2="a5 a4" order="1" />
</bondArray>
</molecule>
</molecule>
</MChemicalStruct>
<MEFlow id="o2" arcAngle="248.39738999999997" headSkip="0.25"
headLength="0.5" headWidth="0.4" tailSkip="0.15">
<MAtomSetPoint atomRefs="m1.a1 m1.a2" />
<MAtomSetPoint atomRefs="m1.a2" />
</MEFlow>
</MDocument>
</cml>

MechFlow.getAtoms: arrow terminus is bond.
Parent molecule is CCOC
Source Bond: C1 to O2, order 1
MechFlow.getAtoms: arrow terminus is atom.
MechFlow.getAtom: getting MolAtom atom.
Sink Atom: O2

Now, suppose I draw CH3-OEt and H+, and I draw an electron-flow arrow from the OEt group to the proton.  In this case, getMolObject(MEFlow.E_SOURCE) returns the shortcut group.

<?xml version="1.0" ?>
<cml>
<MDocument>
<MChemicalStruct>
<molecule molID="m1">
<atomArray
atomID="a1 a2 a3"
elementType="C R H"
formalCharge="0 0 1"
sgroupRef="0 sg1 0"
x2="-7.363124847412109 -5.875599074926944 -5.053124904632568"
y2="2.40625 2.007668670542118 4.427499771118164"
/>
<bondArray>
<bond atomRefs2="a1 a2" order="1" />
</bondArray>
<molecule id="sg1" role="SuperatomSgroup" title="OEt" leftName="EtO" molID="m2">
<atomArray
atomID="a4 a5 a6"
elementType="O C C"
attachmentPoint="1 0 0"
sgroupAttachmentPoint="1 0 0"
x2="-3.1214629396916767 -4.4551420615197115 -5.788821183347747"
y2="0.7334751182874921 -0.03652488171250834 0.7334751182874912"
/>
<bondArray>
<bond atomRefs2="a6 a5" order="1" />
<bond atomRefs2="a5 a4" order="1" />
</bondArray>
</molecule>
</molecule>
</MChemicalStruct>
<MEFlow id="o2" arcAngle="150.0" headSkip="0.15" headLength="0.5"
headWidth="0.4" tailSkip="0.25">
<MEFlowBasePoint atomRef="m1.a2" />
<MAtomSetPoint atomRefs="m1.a2 m1.a3" weights="0.25 0.75" />
</MEFlow>
</MDocument>
</cml>

MechFlow.getAtoms: arrow terminus is atom.
MechFlow.getAtom: getting MolAtom atom.
Parent molecule is [H+].CCOC
Source Atom: OEt0
MechFlow.getAtoms: arrow terminus is incipient bond.
Sink Incip Bond: O2 to H[+1]3

Either getMolObject(MEFlow.E_SOURCE) needs to return the attachment point, or Marvin should not allow electron-flow arrows to start at shortcut groups.

User 870ab5b546

08-12-2010 18:30:01

In trying to develop a workaround for this problem, I have come to realize that there is no way to set the source and sink of an electron-flow arrow from the public API.  Please remedy this deficiency.  


(If an arrow source or sink is an SgroupAtom, and I ungroup the SgroupAtom's SuperatomSgroup, JChem does not alter the arrow terminus to the SuperatomSgroup's attachment point, and the arrow becomes inconsistent.  So I want to be able to change the arrow source or sink manually.)

ChemAxon d26931946c

13-12-2010 08:43:07

Hi Bob, 


We are investigating the issue and we will respond soon.


Best regards, 


Peter

ChemAxon e500b51457

17-12-2010 09:18:26

Hi Bob,

We could reproduce the inconsistent behavior of MEFlow.getMolObject()
and we registered the problem in our issue tracking system.  

You might be able to manipulate the atoms in the MEFlow with the following methods:
MEFlow.getPointRef(MEFlow.E_SOURCE, null) and MAtomSetPoint.replaceAtom(MolAtom orig, MolAtom a) or MEFlowBasePoint.replaceAtom(MolAtom orig, MolAtom a).

Regards,
Erika

User 870ab5b546

17-12-2010 20:11:57

Revised code according to your suggestion:


    /** Replaces shortcut groups in an arrow's termini with their attachment
* points.
* @throws MechError if this arrow represents two electrons and points
* from an atom to one of its ligands
*/
private void removeSgroupTermini() throws MechError {
final String SELF = "MechFlow.removeSgroupTermini: ";
final int[] flowEndPts = new int[] {E_SOURCE, E_SINK};
for (int flowEndPt : flowEndPts) {
final MolAtom[] flowAtoms = getAtoms(flowEndPt);
for (MolAtom flowAtom : flowAtoms) {
if (flowAtom instanceof SgroupAtom) {
debugPrint(SELF + "flow arrow endpoint ", flowAtoms,
" includes a shortcut group.");
final SgroupAtom superAtom = (SgroupAtom) flowAtom;
final SuperatomSgroup sGroup = superAtom.getSgroup();
final MolAtom attachPt = sGroup.findAttachAtom();
final MPoint mPt = meFlow.getPointRef(flowEndPt, null);
if (mPt instanceof MAtomSetPoint) {
((MAtomSetPoint) mPt).replaceAtom(flowAtom, attachPt);
} else {
((MEFlowBasePoint) mPt).replaceAtom(flowAtom, attachPt);
} // if endPt
debugPrint(SELF + "flow arrow endpoint ", flowAtom,
" changed to ", attachPt);
} // if flow atom is a shortcut group
} // for each atom in terminus
} // for each type of source
setSourceAndSink();
} // removeSgroupTermini()

/** Initiates the source and sink values, modifying them if
* necessary.
* @throws MechError if this arrow represents two electrons and points
* from an atom to one of its ligands
*/
private void setSourceAndSink() throws MechError {
source = meFlow.getMolObject(E_SOURCE);
sink = meFlow.getMolObject(E_SINK);
if (is2ElectronAtom2Atom()) {
final MolAtom srcAtom = getSrcAtom();
final MolAtom sinkAtom = getSinkAtom();
if (srcAtom.getBondTo(sinkAtom) != null) {
throw new MechError("A two-electron electron-flow arrow "
+ "must not point from one atom to another atom "
+ "to which it is already bonded.");
} // if source and sink are already connected
sink = new MolAtom[] {srcAtom, sinkAtom};
} // if is two-electron atom pointing from one atom to another
} // setSourceAndSink()

Debugging output:


MechFlow.getAtoms: arrow terminus is atom.
MechFlow.getAtom: getting MolAtom atom.
MechFlow.removeSgroupTermini: flow arrow endpoint OMe includes a shortcut group.
MechFlow.removeSgroupTermini: flow arrow endpoint OMe changed to O
MechFlow.getAtoms: arrow terminus is incipient bond.
MechFlow.removeSgroupTermini: flow arrow endpoint OMe.H[+1] includes a shortcut group.
MechFlow.removeSgroupTermini: flow arrow endpoint OMe changed to O
java.lang.RuntimeException: MultiFaceAtom does not have any visible face
at chemaxon.struc.graphics.MAtomSetPoint$MultiFaceAtom.getVisible(Unknown Source)
at chemaxon.struc.graphics.MAtomSetPoint.getAtoms(Unknown Source)
at chemaxon.struc.graphics.MEFlow.getMolObject(Unknown Source)
at com.epoch.mechanisms.MechFlow.setSourceAndSink(MechFlow.java:95)
at com.epoch.mechanisms.MechFlow.removeSgroupTermini(MechFlow.java:145)
at com.epoch.mechanisms.MechFlow.<init>(MechFlow.java:71)

So replacing the atom in the MAtomSetPoint or MEFlowBasePoint causes an inconsistency later.

User 870ab5b546

19-12-2010 23:00:36

I get the same error when I try to create my own MEFlow:


    private void extractFlows() {
...
if (flow.hasSGroupInSource()) {
debugPrint("Replacing flow arrow ", objIndex + 1,
" with new arrow that lacks shortcut "
+ "groups.");
final MEFlow newFlow =
MechFlow.makeFlowNoSGroups(flow);
mechDoc.setObject(newFlow, objIndex);
flow = new MechFlow(newFlow, objIndex); // line 362
} // if the flow's source contains a shortcut group
...
}

boolean hasSGroupInSource() {
for (MolAtom flowAtom : getSrcAtoms()) {
if (flowAtom instanceof SgroupAtom) {
return true;
} // if source has a shortcut group
} // for each atom touched by this arrow
return false;
} // hasSGroupInSource()

static MEFlow makeFlowNoSGroups(MechFlow oldFlow) {
final MolAtom[] srcAtoms = oldFlow.getSrcAtoms();
final MolAtom[] snkAtoms = oldFlow.getSinkAtoms();
for (int atNum = 0; atNum < srcAtoms.length; atNum++) {
final MolAtom flowAtom = srcAtoms[atNum];
if (flowAtom instanceof SgroupAtom) {
final SgroupAtom superAtom = (SgroupAtom) flowAtom;
final SuperatomSgroup sGroup = superAtom.getSgroup();
srcAtoms[atNum] = sGroup.findAttachAtom();
} // if atom is a shortcut group
} // for each atom in source
final MAtomSetPoint src = new MAtomSetPoint(srcAtoms);
final MAtomSetPoint snk = new MAtomSetPoint(snkAtoms);
return new MEFlow(src, snk, oldFlow.getNumElectrons());
} // makeFlowNoSGroups(MechFlow)

MechFlow(MEFlow newFlow, int objIndex) throws MechError {
initFlow(newFlow); // line 64
objectIndex = objIndex;
} // MechFlow(MEFlow, int)

private void initFlow(MEFlow newFlow) throws MechError {
meFlow = newFlow;
source = meFlow.getMolObject(MEFlow.E_SOURCE); // line 99
sink = meFlow.getMolObject(MEFlow.E_SINK);
if (is2ElectronAtom2Atom()) {
final MolAtom srcAtom = getSrcAtom();
final MolAtom sinkAtom = getSinkAtom();
if (srcAtom.getBondTo(sinkAtom) != null) {
throw new MechError("A two-electron electron-flow arrow "
+ "must not point from one atom to another atom "
+ "to which it is already bonded.");
} // if source and sink are already connected
sink = new MolAtom[] {srcAtom, sinkAtom};
} // if is two-electron atom pointing from one atom to another
} // initFlow(MEFlow)

Runtime error:


Dec 19, 2010 5:48:40 PM org.apache.catalina.core.StandardWrapperValve invoke
INFO: java.lang.RuntimeException: MultiFaceAtom does not have any visible face
at chemaxon.struc.graphics.MAtomSetPoint$MultiFaceAtom.getVisible(Unknown Source)
at chemaxon.struc.graphics.MAtomSetPoint.getAtoms(Unknown Source)
at chemaxon.struc.graphics.MEFlow.getMolObject(Unknown Source)
at com.epoch.mechanisms.MechFlow.initFlow(MechFlow.java:99)
at com.epoch.mechanisms.MechFlow.<init>(MechFlow.java:64)
at com.epoch.mechanisms.MechData.extractFlows(MechData.java:362)

So I was mistaken earlier when I said there was no way to create an MEFlow through the API.  There is a way, but it's buggy.

ChemAxon e500b51457

22-12-2010 10:56:50

Hi Bob,

I think we should fix the original problem first: the inconsistent behavior of MEFlow.getMolObject() so we don't need the workaround.
We will notify you as soon as the fix is ready.

Regards,
Erika

User 870ab5b546

23-12-2010 04:27:44

I agree that what you suggest is the best solution.  Just have MEFlow.getMolObject(E_SOURCE) return the MolAtom representing the attachment point of the SuperatomSgroup instead of the SgroupAtom, like MEFlow.getMolObject(E_SINK) does.

User 870ab5b546

05-05-2011 12:44:04

Will this problem be fixed in JChem 5.5?

ChemAxon 0a9e2a55e1

06-05-2011 08:53:26

Hi Bob,


Yes, we have rewritten part of the electron flow handling, and this incosistency works fine now. Please check it in the 5.5. - it will be released soon.


Best regards,


Peter