@@ -290,6 +290,7 @@ public static Collection<MCSSolution> matcher(Holder mh) throws Exception {
290290 }
291291
292292 int skippedIdentity = 0 , skippedRatio = 0 , skippedTanimoto = 0 ;
293+ List <MCSSolution > directMCSSolutions = new ArrayList <>();
293294
294295 for (Combination c : jobMap .keySet ()) {
295296 int substrateIndex = c .getRowIndex ();
@@ -298,14 +299,30 @@ public static Collection<MCSSolution> matcher(Holder mh) throws Exception {
298299 IAtomContainer product = reactionStructureInformation .getProduct (productIndex );
299300
300301 /*
301- * PRE-FILTER 1: Identity — if canonical SMILES match, the MCS
302- * will be the full molecule. Still run MCS (needed for correct
303- * atom correspondence), but mark as likely identity for logging.
302+ * PRE-FILTER 1: Identity — if canonical SMILES match, build the
303+ * atom mapping directly (atom i → atom i). Do NOT run SMSD: identical
304+ * molecules can have multiple valid MCS solutions due to symmetry,
305+ * and SMSD may return a non-identity mapping that causes spurious
306+ * bond changes in the calculator.
304307 */
305308 String eSmi = eductSmiles .getOrDefault (substrateIndex , "" );
306309 String pSmi = productSmiles .getOrDefault (productIndex , "" );
307- if (!eSmi .isEmpty () && eSmi .equals (pSmi )) {
308- skippedIdentity ++; // just count, still run MCS for correct mapping
310+ if (!eSmi .isEmpty () && eSmi .equals (pSmi ) && educt .getAtomCount () == product .getAtomCount ()) {
311+ try {
312+ IAtomContainer eductClone = cloneWithIDs (educt );
313+ IAtomContainer productClone = cloneWithIDs (product );
314+ AtomAtomMapping identityAAM = new AtomAtomMapping (eductClone , productClone );
315+ for (int ai = 0 ; ai < eductClone .getAtomCount (); ai ++) {
316+ identityAAM .put (eductClone .getAtom (ai ), productClone .getAtom (ai ));
317+ }
318+ MCSSolution identityMCS = new MCSSolution (substrateIndex , productIndex ,
319+ eductClone , productClone , identityAAM );
320+ directMCSSolutions .add (identityMCS );
321+ skippedIdentity ++;
322+ continue ; // skip MCSThread for this pair
323+ } catch (Exception ex ) {
324+ LOGGER .debug ("Identity shortcut failed, falling back to MCS: " + ex .getMessage ());
325+ }
309326 }
310327
311328 /*
@@ -381,6 +398,8 @@ public static Collection<MCSSolution> matcher(Holder mh) throws Exception {
381398 LOGGER .error (SEVERE , "MCS worker failed" , cause );
382399 }
383400 }
401+ // Add directly-constructed identity mappings (bypassed MCSThread)
402+ threadedUniqueMCSSolutions .addAll (directMCSSolutions );
384403 // This will make the executor accept no new threads
385404 // and finish all existing threads in the queue
386405 executor .shutdown ();
0 commit comments