All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.actelion.research.chem.reaction.ReactionClassifier Maven / Gradle / Ivy

There is a newer version: 2024.11.2
Show newest version
/*
 * Copyright (c) 1997 - 2016
 * Actelion Pharmaceuticals Ltd.
 * Gewerbestrasse 16
 * CH-4123 Allschwil, Switzerland
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the the copyright holder nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Thomas Sander
 */

package com.actelion.research.chem.reaction;

import com.actelion.research.chem.Molecule;
import com.actelion.research.chem.StereoMolecule;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;

public class ReactionClassifier {
	private static final boolean DEBUG = true;

//	private static final int MAXAROMS = 19;
	private static final int MAXFATMS = 64;		// maximal no of atoms per fragment
	private static final int MAXATMCNO = 190;	// max allowed atomic number
	private static final int MAXCONNS = 6;

//	private static final int MAXMOLS = 16;
	private static final int MAXATOMS = 256;
//	private static final int MAXBONDS = 256;
	private static final int MAXMPPNGNO = 512;

	private static final int MAXINDICES = Classification.MAXINDICES;
//	private static final int INDEXLEN = Classification.INDEXLEN;
	private static final int MAXFLASH = Classification.MAXFLASH;
	private static final int MAXUNITS = Classification.MAXUNITS;
//	private static final int MAXENDUR = Classification.MAXENDUR;

//	private static final int  RCLASSES	= 13;
	private static final int  S_CONST	=  0;
	private static final int HD_D_CONST	=  1;
	private static final int D_D_CONST	=  2;
	private static final int HD_REAR	=  3;
	private static final int D_REAR		=  4;
	private static final int S_FRAG		=  5;
	private static final int C1_REFU	=  6;
	private static final int LONG_REFU	=  7;
	private static final int HETERO_REFU = 8;
	private static final int HD_D_FRAG	=  9;
	private static final int D_D_FRAG	= 10;
	private static final int E_RING_C	= 11;
	private static final int E_RING_O	= 12;

	private static final int BONDBITS	=  5;		// bits in indexfile: C-C bond specific data
	private static final int HRXNBITS	= 25;		//					half rxn specific data
	private static final int DRXNBITS	= 11;		//			two end half rxn specific data
	private static final int CRXNBITS	=  4;		//	bits for electrocyclic reaction class
	private static final int REARBITS	= 13;		//			half rearrangement specific data
	private static final int PROPBITS	= 11;		// nr of bits of carbon describing properties

//	private static final int MAXPRUNOPTIONS = 58;

	public static final int cErrorNoError = 0;
	public static final int cErrorNoChangeNorEFG = 1;
	public static final int cErrorEductMapNoOverused = 2;
	public static final int cErrorProdMapNoOverused1 = 3;
	public static final int cErrorProdMapNoOverused2 = 4;
	public static final int cErrorMapNoNotInProduct = 5;
	public static final int cErrorMapNoNotInEduct = 6;
	public static final int cErrorDupProdMapNoDifEd = 7;
//	public static final int cErrorMaxNoOfMolsReached = 8;
	public static final int cErrorProdRemapFailed = 9;
	public static final int cErrorEduFragPartMapped = 10;
	public static final int cErrorFragmentAtomLimit = 11;
	public static final int cErrorProdFragPartMapped = 12;
	public static final int cErrorUnexpected = 13;
	public static final int cErrorUnMappedCInConOrFr = 14;
	public static final int cErrorCCBondCleavageLimit = 15;
	public static final int cErrorCCBondCreationLimit = 16;
	public static final int cErrorComplexReaction = 17;
	public static final int cErrorNoChangingAtoms = 18;
	public static final int cErrorForkedOrLongStrand = 19;
	public static final int cError2AlphasInSameStrand = 20;
	public static final int cErrorHRClassifyError = 21;
	public static final int cErrorCRClassifyError = 22;
	public static final int cErrorDRClassifyError = 23;
	public static final int cErrorRAClassifyError = 24;
	public static final int cErrorREClassifyError = 25;
	public static final int cErrorIncoOrLeavMissing = 26;
	public static final int cErrorUnitReactionLimit = 27;
	public static final int cErrorNoDatabaseReaction = 28;

	public static final int cIndexNone = 0;
	public static final int cIndexOnePermToFile = 1;
	public static final int cIndexFullPermutation = 2;

	private static final int cAtomPiChange			= 0x0100;	// TODO use real value
	private static final int cAtomZChange			= 0x0200;	// TODO use real value
	private static final int cAtomSigmaChange		= 0x0400;	// TODO use real value
	private static final int cAtomChanges			= 0x1000;	// TODO use real value
	private static final int cAtomNoCounterAtom		= 0x2000;	// TODO use real value
	private static final int cAtomDBondToHetero		= 0x4000;	// TODO use real value
	private static final int cAtomNotClassifiedYet	= 0x8000;	// TODO use real value

	private static final int CARBON = 1;
//	private static final int HYDROGEN	= 3;

	private static int data,mask;
	private static int indexnum,indexpoin,availbits;

	private ClassificationData mClassificationData;
	private BufferedWriter gErrout;
	private Reaction mRxn;
	private Classification mResult;
	private int mIndexToCreate,mUnitRxn;
	private int[][] mAtomType,mSigma,mPi,mH,mZ,mAtomFlags,mCorProd,mCorAtom;
	private int[][][] mConnMpNo,mConnCMNo,mConnType;

	public ReactionClassifier() {
		mClassificationData = ClassificationData.getInstance();
		}


	public int classify(Reaction theReaction) {
		return classify(cIndexNone, theReaction);
		}


	public int classify(int indexToCreate, /*CBatchClassifier theBatchClassifierP,*/ Reaction theReaction) {
//TODO		CEFGClassifier	efgClassifier;
		
		mIndexToCreate = indexToCreate;
		mRxn = theReaction;
//		mBatchClassifierP = theBatchClassifierP;

		if (indexToCreate != cIndexNone && !(theReaction instanceof DatabaseReaction))
			return cErrorNoDatabaseReaction;

		for (int mol=0; mol 2)
						return cErrorEductMapNoOverused;
					}
				}
		
			if (!doubleFound)
				continue;
		
			for (int atm=0; atm 1)
							return cErrorProdMapNoOverused1;
						if (dirtyProduct != -1 && dirtyProduct != p)
							return cErrorProdMapNoOverused2;
						dirtyProduct = p;
						}
		
					proMapNoCount[mapNo]++;
					proMol[mapNo] = p;
					}
				}
			}
		
		if (dirtyProduct == -1)  // all products are free of duplicate mapping numbers
			return cErrorNoError;
		
		int highestMappingNo = 0;
		for (int i=1; i 0 && proMapNoCount[i] > 0) {
				highestMappingNo = i;
				continue;
				}
			if (eduMapNoCount[i] != 0)
				return cErrorMapNoNotInProduct;
			if (proMapNoCount[i] != 0)
				return cErrorMapNoNotInEduct;
			}
		
		int dirtyEduct = -1;
		for (int i=1; i<=highestMappingNo; i++) {
			if (proMapNoCount[i] > 1) {
				if (dirtyEduct != -1 && dirtyEduct != eduMol[i])
					return cErrorDupProdMapNoDifEd;
				dirtyEduct = eduMol[i];
				}
			}

		StereoMolecule duplicateEduct = new StereoMolecule(mRxn.getReactant(dirtyEduct));
		duplicateEduct.ensureHelperArrays(Molecule.cHelperParities);
		mRxn.addReactant(duplicateEduct, dirtyEduct);

		StereoMolecule mol = mRxn.getProduct(dirtyProduct);
		for (int atm=0; atm MAXMPPNGNO)
			return false;
		
		boolean successful = true;  // default
		for (atm=0; atm= 1) && (atomicNo <= MAXATMCNO))
					mAtomType[m][atm] = types[atomicNo];
				else if (gErrout != null) {
					try {
						gErrout.write("Rxn: "+mRxn.getName()+", unknown atomic #: "+atomicNo);
						gErrout.newLine();
						}
					catch (IOException ioe) {}
					}
				}
			}
		
		for (int m=0; m mConnType[m][actlAtm][i]) {
								if (mConnType[m][actlAtm][i] != 0) {
									for (int j=MAXCONNS-1; j>i; j--)
										mConnType[m][actlAtm][j] = mConnType[m][actlAtm][j-1];
									}
								mConnType[m][actlAtm][i] = remotTyp;
								break;
								}
							}
						}
					}
				}

			if (gErrout != null) {
				for (int atm=0; atm mConnMpNo[m][actlAtm][i]) {
								if (mConnMpNo[m][actlAtm][i] != 0) {
									for (int j=MAXCONNS-1; j>i; j--)
										mConnMpNo[m][actlAtm][j] =
											mConnMpNo[m][actlAtm][j-1];
									}
								mConnMpNo[m][actlAtm][i] = mol.getAtomMapNo(connAtm);
								break;
								}
							}
						}
		
									// store sorted mapping no's of connected carbons
									// independent of bond order only one entry
					if (mAtomType[m][connAtm] == CARBON) {
						for (int i=0; i mConnCMNo[m][actlAtm][i]) {
								if (mConnCMNo[m][actlAtm][i] != 0) {
									for (int j=MAXCONNS-1; j>i; j--)
										mConnCMNo[m][actlAtm][j] =
											mConnCMNo[m][actlAtm][j-1];
									}
								mConnCMNo[m][actlAtm][i] = mol.getAtomMapNo(connAtm);
								break;
								}
							}
						}
		
					switch (3 & mAtomType[m][connAtm]) {  // determine z,pi,sigma,h
						case 1:
							mSigma[m][actlAtm] += 1;
							mPi[m][actlAtm] += mol.getBondOrder(bnd) - 1;
							break;
						case 2:
							mZ[m][actlAtm] += mol.getBondOrder(bnd);
							break;
						}
					}
				}
			for (int atm=0; atm= mols) && (mRxn.getAtomMappingNo( mol, atm ) == 0)) continue;
				if (mCorAtom[m][atm] == 255) {
					mAtomFlags[m][atm] |= cAtomChanges + cAtomNoCounterAtom;
					continue;							// no mapping info available
					}

				int proMol = mCorProd[m][atm];
				int proAtm = mCorAtom[m][atm];
		
				if (gErrout != null) {
					try {
						gErrout.write("EduAtom: "+atm+" conntype:");
						for (int i=0; i<4; i++)
							gErrout.write(mConnType[m][atm][i]);
						gErrout.newLine();
						gErrout.write("ProAtom: "+atm+" conntype:");
						for (int i=0; i<4; i++)
							gErrout.write(mConnType[proMol][proAtm][i]);
						gErrout.newLine();
						gErrout.write("EduAtom: "+atm+" connmpno:");
						for (int i=0; i<4; i++)
							gErrout.write(mConnMpNo[m][atm][i]);
						gErrout.newLine();
						gErrout.write("ProAtom: "+atm+" connmpno:");
						for (int i=0; i<4; i++)
							gErrout.write(mConnMpNo[proMol][proAtm][i]);
						gErrout.newLine();
						}
					catch (IOException ioe) {}
					}
		
				boolean found = false;
				for (int i=0; i 5) {				// reset changMsk for nonchanging aromatics
				for (int atm=0; atm atm) {
								if (ccBndClv == 4) return cErrorCCBondCleavageLimit;
								ccBCmol[ccBndClv] = m;	// more than 2 CC-bonds cleaved
								ccBCatm[ccBndClv] = atm;
								ccBndClv++;
								ccBCmol[ccBndClv] = m;
								ccBCatm[ccBndClv] = oppositeAtom;
								ccBndClv++;
								}
							}
						}
					}
		
				for (int i=0; i= mRxn.getReactants())) continue;
								StereoMolecule kMol = mRxn.getMolecule(k);
								for (int l=0; l m)
							|| ((oppositeMol == m) && (oppositeAtom > atm))) {
								if (ccBndFrm == 4) return cErrorCCBondCreationLimit;
								ccBFmol[ccBndFrm] = m;	// more than 2 new C-C bonds
								ccBFatm[ccBndFrm] = atm;
								ccBndFrm++;
								ccBFmol[ccBndFrm] = oppositeMol;
								ccBFatm[ccBndFrm] = oppositeAtom;
								ccBndFrm++;
								}
							}
						}
					}
				}
			}
		
		if (gErrout != null) {
			try {
				gErrout.write("Form:"+ccBndFrm+", Clv:"+ccBndClv+"; ccBFmols:"+ccBFmol[0]+","+ccBFmol[1]+"; ccBFatms:"+ccBFatm[0]+","+ccBFatm[0]);
				gErrout.newLine();
				}
			catch (IOException ioe) {}
			}
		
		if (ccBndFrm == 2 && ccBndClv == 0)
			{
		//	gSC_no++;
			int retval = snglCnst(ccBFmol,ccBFatm);
			if (retval != 0) return retval;
		//	gCSC_no++;
			}
		else if (ccBndFrm == 4 && ccBndClv == 0)
			{
		//	gDC_no++;
			int retval = dblCnst(ccBFmol,ccBFatm);
			if (retval != 0) return retval;
		//	gCDC_no++;
			}
		else if (ccBndFrm == 0 && ccBndClv == 2)
			{
		//	gSF_no++;
			int retval = snglFrgm(ccBCmol,ccBCatm);
			if (retval != 0) return retval;
		//	gCSF_no++;
			}
		else if (ccBndFrm == 0 && ccBndClv == 4)
			{
		//	gDF_no++;
			int retval = dblFrgm(ccBCmol,ccBCatm);
			if (retval != 0) return retval;
		//	gCDF_no++;
			}
		else if (ccBndFrm == 2 && ccBndClv == 2)
			{
		//	gRA_no++;
			int retval = rearrang(ccBFmol,ccBFatm,ccBCmol,ccBCatm);
			if (retval != 0) return retval;
		//	gCRA_no++;
			}
		else if (ccBndFrm != 0 || ccBndClv != 0)
			{
			if (gErrout != null) {
				try {
					gErrout.write("Form:"+ccBndFrm+", Clv:"+ccBndClv);
					gErrout.newLine();
					}
				catch (IOException ioe) {}
				}
			mResult.mClassName = "not classified";
			return cErrorComplexReaction;
			}
		
		//if (ccBndFrm == 0 && ccBndClv == 0) gRE_no++;
		int retval = refuncs();
		if (retval != 0) return retval;

		if (mUnitRxn == 0)	// no skeletal nor refunc unit reactions found
			if (mIndexToCreate != cIndexFullPermutation)
				return cErrorNoChangingAtoms;
		
		//if (ccBndFrm == 0 && ccBndClv == 0) gCRE_no++;
		
		mResult.mUnitRxns = mUnitRxn;
		findClassNam();
		markReactionCenters();
		
		return cErrorNoError;
		}


	private int snglCnst(int[] ccBFmol, int[] ccBFatm) {
		int[] strLngth = new int[2];
		int[][] strand = new int[2][8];		// strand[atm][0]: molecule
		int atm;				// strand[atm][1-8]: alpha - delta
		
		for (atm=0; atm<2; atm++)	// get atom no's of changing strand
			{
			strand[atm][0] = ccBFmol[atm];
			strand[atm][1] = ccBFatm[atm];
			strLngth[atm] = findStrand(strand[atm]);

			if (gErrout != null)
				try { gErrout.newLine(); } catch (IOException ioe) {}

			if (strLngth[atm] < 1) return cErrorForkedOrLongStrand;	// branched strand
			}
		return oneConst(strand[0],strand[1],strLngth[0],strLngth[1]);
		}


	/**
     * manage one Construction Reaction with known strands
	 * @return
	 */
	private int oneConst( int[] strand1, int[] strand2, int strLen1, int strLen2 ) {
		int[] indexdata = new int[3];
														// electrocyclic ring closure
		if (strand1[0] == strand2[0] && strand1[1] == strand2[strLen2])
			return ringClosure(strand1,strand2,strLen1,strLen2);
		
		int retval = bndSpcDat(strand1,strand2,2,indexdata,0);
		if (retval != 0) return retval;

		// z-pi-Lists of entire strand
		int deltaLst = getDelta(strand1,strLen1,7);	// classify first half construction
		retval = clssfyHR(indexdata,1,deltaLst,strand1,strLen1,true,6);
		if (retval != 0) return retval;						// classification error
		
		deltaLst = getDelta(strand2,strLen2,7);   // classify second half construction
		retval = clssfyHR(indexdata,2,deltaLst,strand2,strLen2,true,7);
		if (retval != 0) return retval;						// classification error
		
		mResult.mMainClass[mUnitRxn] = S_CONST;

		if (mIndexToCreate != cIndexNone) {
			DatabaseReaction dbrxn = (DatabaseReaction)mRxn;

			putindexbits('n',32,(dbrxn.getReactionYield() << 24) + dbrxn.getReactionRegNo());
			putindexbits(' ',BONDBITS,indexdata[0]);			// write rxn index entry
			putindexbits(' ',HRXNBITS,indexdata[1]);
			putindexbits('l',HRXNBITS,indexdata[2]);
			
	//		if (mBatchClassifierP)
	//			mBatchClassifierP->incIndexEntries( S_CONST );
			
			if (mIndexToCreate == cIndexFullPermutation) {		// supply index for query
				putindexbits('c',32,dbrxn.getReactionRegNo());
				putindexbits(' ',BONDBITS,indexdata[0]);
				putindexbits(' ',HRXNBITS,indexdata[2]);
				putindexbits('l',HRXNBITS,indexdata[1]);
				}
			}

		mUnitRxn++;
		return cErrorNoError;
		}


	/**
	 * manage an electrocyclic ring closure reaction
	 * @return
	 */
	private int ringClosure( int[] strand1, int[] strand2, int strLen1, int strLen2 ) {
		int[] indexdata = new int[4];
		
		int retval = bndSpcDat(strand1,strand2,2,indexdata,0);
		if (retval != 0) return retval;
		
		int deltaLst = getDelta(strand1,strLen1,7);
		int tempDeltaLst = getDelta(strand2,strLen2,7);
		if (tempDeltaLst > deltaLst)
			deltaLst = tempDeltaLst;

		retval = clssfyCR(indexdata,1,deltaLst,strand1,strLen1,true);
		if (retval != 0) return retval;						// classification error

		indexdata[2] = properties(strand1[0],strand1[1]);
		indexdata[3] = properties(strand2[0],strand2[1]);
		
		mResult.mFlashMol[mUnitRxn][6] = strand1[0];
		mResult.mFlashAtom[mUnitRxn][6] = strand1[1];
		mResult.mFlashMol[mUnitRxn][7] = strand2[0];
		mResult.mFlashAtom[mUnitRxn][7] = strand2[1];
		mResult.mMainClass[mUnitRxn] = E_RING_C;
		
		if (mIndexToCreate != cIndexNone) {
			DatabaseReaction dbrxn = (DatabaseReaction)mRxn;

			putindexbits('n',32,(dbrxn.getReactionYield() << 24) + dbrxn.getReactionRegNo());
			putindexbits(' ',BONDBITS,indexdata[0]);			// write rxn index entry
			putindexbits(' ',CRXNBITS,indexdata[1]);
			putindexbits(' ',PROPBITS,indexdata[2]);
			putindexbits('l',PROPBITS,indexdata[3]);
			
	//		if (mBatchClassifierP)
	//			mBatchClassifierP->incIndexEntries( E_RING_C );
			
			if (mIndexToCreate == cIndexFullPermutation)
				{
				putindexbits('c',32,dbrxn.getReactionRegNo());
				putindexbits(' ',BONDBITS,indexdata[0]);
				putindexbits(' ',CRXNBITS,indexdata[1]);
				putindexbits(' ',PROPBITS,indexdata[3]);
				putindexbits('l',PROPBITS,indexdata[2]);
				}
			}

		mUnitRxn++;
		
		return cErrorNoError;
		}


	/**
	 * calculate z-pi-list from strand no's
	 */
	private int getDelta(int[] strand, int strLngth, int maxLngth) {
		int eduZ,proZ;
		int i,mol;
		int eduLst,proLst;
		
		eduLst = proLst = 0;
		mol = strand[0];

		for (i=1; i<=maxLngth; i++)
			{
			eduLst <<= 4;
			proLst <<= 4;
			if (i>strLngth) continue;
			eduZ = mZ[mol][strand[i]];
			proZ = mZ[mCorProd[mol][strand[i]]][mCorAtom[mol][strand[i]]];
			if ((eduZ == 4) || (proZ == 4))
				{
				eduZ -= 1;
				proZ -= 1;
				}
			eduLst += (eduZ<<2) + mPi[mol][strand[i]];
			proLst += (proZ<<2) + mPi[mCorProd[mol][strand[i]]][mCorAtom[mol][strand[i]]];
			}

		if (gErrout != null) {
			try {
				gErrout.write(String.format("eduLst:%8x, proLst:%8x, deltaLst:%8x\n", eduLst,proLst,eduLst-proLst));
				gErrout.newLine();
				}
			catch (IOException ioe) {}
			}

		return eduLst-proLst;
		}


	/**
	 * double Construction Reaction
	 * @return
	 */
	private int dblCnst(int[] ccBFmol, int[] ccBFatm) {
		int[] indexdata = new int[6];
		int[] strLngth = new int[4];
		int strnd;
		int hlfRxn1,hlfRxn2,depRxn;
		int[] dependnc = new int[2];	// indicates for each educt atom of new formed
										// bond, if this an independent half reaction (0)
										// or if the appropriate strand ends with an atom
										// from that the second bond is formed (atm no)
		int[][] strand = new int[4][8];	// strand[atm][0]: molecule
										// strand[atm][1-7]: alpha - delta
		
		for (int atm=0; atm<4; atm++) {		// get atom no's of changing strands
			strand[atm][0] = ccBFmol[atm];
			strand[atm][1] = ccBFatm[atm];
			strLngth[atm] = findStrand(strand[atm]);

			if (gErrout != null)
				try { gErrout.newLine(); } catch (IOException ioe) {}

			if (strLngth[atm] < 1) return cErrorForkedOrLongStrand;	// branched strand
			}
		
		for (int i=0; i<2; i++)
			dependnc[i] =
		 	+ (strand[i][0] == strand[2][0] && strand[i][1] == strand[2][strLngth[2]] ? 2 : 0)
		 	+ (strand[i][0] == strand[3][0] && strand[i][1] == strand[3][strLngth[3]] ? 3 : 0);

		if ((dependnc[0] == 0) && (dependnc[1] == 0)) {
			int retval = oneConst(strand[0],strand[1],strLngth[0],strLngth[1]);
			if (retval != 0) return retval;
			return oneConst(strand[2],strand[3],strLngth[2],strLngth[3]);
			}
		
		if ((dependnc[0] == 0) || (dependnc[1] == 0)) {
			if (dependnc[0] == 0) {
				hlfRxn1 = 0;
				hlfRxn2 = (dependnc[1] == 2) ? 3 : 2;
				depRxn = 1;
				}
			else
				{
				hlfRxn1 = 1;
				hlfRxn2 = (dependnc[0] == 2) ? 3 : 2;
				depRxn = 0;
				}
		
			if (strand[hlfRxn1][0] == strand[depRxn][0])
				if (strand[hlfRxn1][1] == strand[depRxn][strLngth[depRxn]])
					return cError2AlphasInSameStrand;		// both alpha carbons share one strand
			if (strand[hlfRxn2][0] == strand[5-hlfRxn2][0])
				if (strand[hlfRxn2][1] == strand[5-hlfRxn2][strLngth[5-hlfRxn2]])
					return cError2AlphasInSameStrand;		// both alpha carbons share one strand
		
			int retval = bndSpcDat(strand[hlfRxn1],strand[depRxn],0,indexdata,0);
			if (retval != 0) return retval;
			retval = bndSpcDat(strand[hlfRxn2],strand[5-hlfRxn2],2,indexdata,1);
			if (retval != 0) return retval;
		
			int deltaLst = getDelta(strand[depRxn],strLngth[depRxn],strLngth[depRxn]);
			int tempDeltaLst = getDelta(strand[5-hlfRxn2],strLngth[5-hlfRxn2],strLngth[5-hlfRxn2]);
		
			if (tempDeltaLst > deltaLst)	// use strand with higher delta z-pi-list
				{
				deltaLst = tempDeltaLst;
				depRxn = 5-hlfRxn2;
				}
		
												// two end hlf rxn
			retval = clssfyDR(indexdata,2,deltaLst,true,strand[depRxn],strLngth[depRxn],4);
			if (retval != 0) return retval;
		
			deltaLst = getDelta(strand[hlfRxn1],strLngth[hlfRxn1],7);			// standard hlf rxn
			retval = clssfyHR(indexdata,4,deltaLst,strand[hlfRxn1],strLngth[hlfRxn1],true,6);
			if (retval != 0) return retval;						// classification error
		
			deltaLst = getDelta(strand[hlfRxn2],strLngth[hlfRxn2],7);		// standard hlf rxn
			retval = clssfyHR(indexdata,5,deltaLst,strand[hlfRxn2],strLngth[hlfRxn2],true,7);
			if (retval != 0) return retval;						// classification error
		
			mResult.mMainClass[mUnitRxn] = HD_D_CONST;

			if (mIndexToCreate != cIndexNone) {
				DatabaseReaction dbrxn = (DatabaseReaction)mRxn;

				putindexbits('n',32,(dbrxn.getReactionYield() << 24) + dbrxn.getReactionRegNo());
				putindexbits(' ',BONDBITS,indexdata[0]);		// write rxn index entry
				putindexbits(' ',BONDBITS,indexdata[1]);
				putindexbits(' ',DRXNBITS,indexdata[2]);
				putindexbits(' ',HRXNBITS,indexdata[4]);
				putindexbits('l',HRXNBITS,indexdata[5]);
			
	//			if (mBatchClassifierP)
	//				mBatchClassifierP->incIndexEntries( HD_D_CONST );
			
				if (mIndexToCreate == cIndexFullPermutation) {
					putindexbits('c',32,dbrxn.getReactionRegNo());
					putindexbits(' ',BONDBITS,indexdata[1]);
					putindexbits(' ',BONDBITS,indexdata[0]);
					putindexbits(' ',DRXNBITS,indexdata[3]);
					putindexbits(' ',HRXNBITS,indexdata[5]);
					putindexbits('l',HRXNBITS,indexdata[4]);
					}
				}
		
			mUnitRxn++;
			for (int i=1; i<=strLngth[depRxn]; i++)
				mAtomFlags[strand[depRxn][0]][strand[depRxn][i]] &= ~cAtomNotClassifiedYet;
			}
		else
			{
			if (strand[0][0] == strand[1][0])
				if (strand[0][1] == strand[1][strLngth[1]])
					return cError2AlphasInSameStrand;		// both alpha carbons share one strand
			if (strand[2][0] == strand[3][0])
				if (strand[2][1] == strand[3][strLngth[3]])
					return cError2AlphasInSameStrand;		// both alpha carbons share one strand
		
			int retval = bndSpcDat(strand[0],strand[1],0,indexdata,0);
			if (retval != 0) return retval;
			retval = bndSpcDat(strand[2],strand[3],2,indexdata,1);
			if (retval != 0) return retval;
		
			for (strnd=0; strnd<2; strnd++)
				{
				int deltaLst = getDelta(strand[strnd],strLngth[strnd],strLngth[strnd]);
				int tempDeltaLst = getDelta(strand[dependnc[strnd]],strLngth[dependnc[strnd]],
						strLngth[dependnc[strnd]]);
		
				if (tempDeltaLst > deltaLst)
					{
					deltaLst = tempDeltaLst;
					depRxn = dependnc[strnd];
					}
				else depRxn = strnd;
		
				retval = clssfyDR(indexdata,2+2*strnd,deltaLst,true,strand[depRxn],strLngth[depRxn],strnd*2+4);
				if (retval != 0) return retval;
		
				for (int i=1; i<=strLngth[strnd]; i++)
					mAtomFlags[strand[strnd][0]][strand[strnd][i]] &= ~cAtomNotClassifiedYet;
				}
		
			mResult.mMainClass[mUnitRxn] = D_D_CONST;

			if (mIndexToCreate != cIndexNone) {
				DatabaseReaction dbrxn = (DatabaseReaction)mRxn;

				putindexbits('n',32,(dbrxn.getReactionYield() << 24) + dbrxn.getReactionRegNo());
				putindexbits(' ',BONDBITS,indexdata[0]);		// write rxn index entry
				putindexbits(' ',BONDBITS,indexdata[1]);
				putindexbits(' ',DRXNBITS,indexdata[2]);
				putindexbits('l',DRXNBITS,indexdata[4]);
			
	//			if (mBatchClassifierP)
	//				mBatchClassifierP->incIndexEntries( D_D_CONST );
			
				if (mIndexToCreate == cIndexFullPermutation) {
					putindexbits('c',32,dbrxn.getReactionRegNo());
					putindexbits(' ',BONDBITS,indexdata[0]);
					putindexbits(' ',BONDBITS,indexdata[1]);
					putindexbits(' ',DRXNBITS,indexdata[4]);
					putindexbits('l',DRXNBITS,indexdata[2]);
					putindexbits('c',32,dbrxn.getReactionRegNo());
					putindexbits(' ',BONDBITS,indexdata[1]);
					putindexbits(' ',BONDBITS,indexdata[0]);
					putindexbits(' ',DRXNBITS,indexdata[3]);
					putindexbits('l',DRXNBITS,indexdata[5]);
					putindexbits('c',32,dbrxn.getReactionRegNo());
					putindexbits(' ',BONDBITS,indexdata[1]);
					putindexbits(' ',BONDBITS,indexdata[0]);
					putindexbits(' ',DRXNBITS,indexdata[5]);
					putindexbits('l',DRXNBITS,indexdata[3]);
					}
				}

			mUnitRxn++;
			}
		return cErrorNoError;
		}


	/**
	 * single fragmentation Reaction
	 * @return
	 */
	private int snglFrgm(int[] ccBCmol, int[] ccBCatm) {
		int[][] strand = new int[2][8];
		int[] strLngth = new int[2];
		
		for (int atm=0; atm<2; atm++) {			// get atom no's of changing strand
			strand[atm][0] = ccBCmol[atm];
			strand[atm][1] = ccBCatm[atm];
			strLngth[atm] = findStrand(strand[atm]);

			if (gErrout != null)
				try { gErrout.newLine(); } catch (IOException ioe) {}

			if (strLngth[atm] < 1) return cErrorForkedOrLongStrand;	// branched strand
			}
		return oneFrgm(strand[0],strand[1],strLngth[0],strLngth[1]);
		}


	/**
	 * handle one fragmentation Reaction
	 * @return
	 */
	private int oneFrgm(int[] strand1, int[] strand2, int strLen1, int strLen2) {
		int[] indexdata = new int[3];
		
														// electrocyclic ring opening
		if (strand1[0] == strand2[0] && strand1[1] == strand2[strLen2])
			return ringOpening(strand1,strand2,strLen1,strLen2);
		
		int retval = bndSpcDat(strand1,strand2,2,indexdata,0);
		if (retval != 0) return retval;
		
		int deltaLst = getDelta(strand1,strLen1,7);   // classify first half fragmentation
		retval = clssfyHR(indexdata,1,-deltaLst,strand1,strLen1,false,6);
		if (retval != 0) return retval;						// classification error
		
		deltaLst = getDelta(strand2,strLen2,7);  // classify second half fragmentation
		retval = clssfyHR(indexdata,2,-deltaLst,strand2,strLen2,false,7);
		if (retval != 0) return retval;						// classification error
		
		mResult.mMainClass[mUnitRxn] = S_FRAG;

		if (mIndexToCreate != cIndexNone) {
			DatabaseReaction dbrxn = (DatabaseReaction)mRxn;

			putindexbits('n',32,(dbrxn.getReactionYield() << 24) + dbrxn.getReactionRegNo());
			putindexbits(' ',BONDBITS,indexdata[0]);			// write rxn index entry
			putindexbits(' ',HRXNBITS,indexdata[1]);
			putindexbits('l',HRXNBITS,indexdata[2]);
			
	//		if (mBatchClassifierP)
	//			mBatchClassifierP->incIndexEntries( S_FRAG );
			
			if (mIndexToCreate == cIndexFullPermutation) {
				putindexbits('c',32,dbrxn.getReactionRegNo());
				putindexbits(' ',BONDBITS,indexdata[0]);
				putindexbits(' ',HRXNBITS,indexdata[2]);
				putindexbits('l',HRXNBITS,indexdata[1]);
				}
			}

		mUnitRxn++;
		return cErrorNoError;
		}


	/**
	 * manage an electrocyclic ring opening reaction
	 * @return
	 */
	private int ringOpening(int[] strand1, int[] strand2, int strLen1, int strLen2) {
		int[] indexdata = new int[4];
		
		int retval = bndSpcDat(strand1,strand2,2,indexdata,0);
		if (retval != 0) return retval;
		
		int deltaLst = getDelta(strand1,strLen1,7);
		int tempDeltaLst = getDelta(strand2,strLen2,7);
		if (tempDeltaLst < deltaLst)
			deltaLst = tempDeltaLst;
		
		retval = clssfyCR(indexdata,1,-deltaLst,strand1,strLen1,false);
		if (retval != 0) return retval;						// classification error
		
		indexdata[2] = properties(strand1[0],strand1[1]);
		indexdata[3] = properties(strand2[0],strand2[1]);
		
		mResult.mFlashMol[mUnitRxn][6] = strand1[0];
		mResult.mFlashAtom[mUnitRxn][6] = strand1[1];
		mResult.mFlashMol[mUnitRxn][7] = strand2[0];
		mResult.mFlashAtom[mUnitRxn][7] = strand2[1];
		
		mResult.mMainClass[mUnitRxn] = E_RING_O;

		if (mIndexToCreate != cIndexNone) {
			DatabaseReaction dbrxn = (DatabaseReaction)mRxn;

			putindexbits('n',32,(dbrxn.getReactionYield() << 24) + dbrxn.getReactionRegNo());
			putindexbits(' ',BONDBITS,indexdata[0]);			// write rxn index entry
			putindexbits(' ',CRXNBITS,indexdata[1]);
			putindexbits(' ',PROPBITS,indexdata[2]);
			putindexbits('l',PROPBITS,indexdata[3]);
	
	//		if (mBatchClassifierP)
	//			mBatchClassifierP->incIndexEntries( E_RING_O );
			
			if (mIndexToCreate == cIndexFullPermutation)
				{
				putindexbits('c',32,dbrxn.getReactionRegNo());
				putindexbits(' ',BONDBITS,indexdata[0]);
				putindexbits(' ',CRXNBITS,indexdata[1]);
				putindexbits(' ',PROPBITS,indexdata[3]);
				putindexbits('l',PROPBITS,indexdata[2]);
				}
			}

		mUnitRxn++;
		
		return cErrorNoError;
		}


	/**
	 * double Fragmentation Reaction
	 * @return
	 */
	private int dblFrgm(int[] ccBCmol, int[] ccBCatm) {
		int[] indexdata = new int[6];
		int[] strLngth = new int[4];
		int hlfRxn1,hlfRxn2,depRxn;
		int[] dependnc = new int[2];	// indicates for each educt atom of new formed
										// bond, if this an independent half reaction (0)
										// or if the appropriate strand ends with an atom
										// from that the second bond is formed (atm no)

		int[][] strand = new int[4][8];	// strand[atm][0]: molecule
										// strand[atm][1-8]: alpha - delta

		for (int atm=0; atm<4; atm++) {		// get atom no's of changing strands
			strand[atm][0] = ccBCmol[atm];
			strand[atm][1] = ccBCatm[atm];
			strLngth[atm] = findStrand(strand[atm]);

			if (gErrout != null)
				try { gErrout.newLine(); } catch (IOException ioe) {}

			if (strLngth[atm] < 1) return cErrorForkedOrLongStrand;	// branched strand
			}
		
		for (int i=0; i<2; i++)
			dependnc[i] =
			+ (strand[i][0] == strand[2][0] && strand[i][1] == strand[2][strLngth[2]] ? 2 : 0)
			+ (strand[i][0] == strand[3][0] && strand[i][1] == strand[3][strLngth[3]] ? 3 : 0);
		
		if ((dependnc[0] == 0) && (dependnc[1] == 0)) {
			int retval = oneFrgm(strand[0],strand[1],strLngth[0],strLngth[1]);
			if (retval != 0) return retval;
			return oneFrgm(strand[2],strand[3],strLngth[2],strLngth[3]);
			}
		
		if ((dependnc[0] == 0) || (dependnc[1] == 0))
			{
			if (dependnc[0] == 0)
				{
				hlfRxn1 = 0;
				hlfRxn2 = (dependnc[1] == 2) ? 3 : 2;
				depRxn = 1;
				}
			else
				{
				hlfRxn1 = 1;
				hlfRxn2 = (dependnc[0] == 2) ? 3 : 2;
				depRxn = 0;
				}
		
			if (strand[hlfRxn1][0] == strand[depRxn][0])
				if (strand[hlfRxn1][1] == strand[depRxn][strLngth[depRxn]])
					return cError2AlphasInSameStrand;		// both alpha carbons share one strand
			if (strand[hlfRxn2][0] == strand[5-hlfRxn2][0])
				if (strand[hlfRxn2][1] == strand[5-hlfRxn2][strLngth[5-hlfRxn2]])
					return cError2AlphasInSameStrand;		// both alpha carbons share one strand
		
			int retval = bndSpcDat(strand[hlfRxn1],strand[depRxn],0,indexdata,0);
			if (retval != 0) return retval;
			retval = bndSpcDat(strand[hlfRxn2],strand[5-hlfRxn2],2,indexdata,1);
			if (retval != 0) return retval;
		
			int deltaLst = getDelta(strand[depRxn],strLngth[depRxn],strLngth[depRxn]);
			int tempDeltaLst = getDelta(strand[5-hlfRxn2],strLngth[5-hlfRxn2],strLngth[5-hlfRxn2]);
		
			if (tempDeltaLst < deltaLst) {  // lower delta z-pi-list here gives higher after inversion
				deltaLst = tempDeltaLst;
				depRxn = 5-hlfRxn2;
				}
		
															// two end hlf rxn
			retval = clssfyDR(indexdata,2,-deltaLst,false,strand[depRxn],strLngth[depRxn],4);
			if (retval != 0) return retval;
		
			deltaLst = getDelta(strand[hlfRxn1],strLngth[hlfRxn1],7);		// standard hlf rxn
			retval = clssfyHR(indexdata,4,-deltaLst,strand[hlfRxn1],strLngth[hlfRxn1],false,6);
			if (retval != 0) return retval;						// classification error
		
			deltaLst = getDelta(strand[hlfRxn2],strLngth[hlfRxn2],7);		// standard hlf rxn
			retval = clssfyHR(indexdata,5,-deltaLst,strand[hlfRxn2],strLngth[hlfRxn2],false,7);
			if (retval != 0) return retval;						// classification error
		
			mResult.mMainClass[mUnitRxn] = HD_D_FRAG;

			if (mIndexToCreate != cIndexNone) {
				DatabaseReaction dbrxn = (DatabaseReaction)mRxn;

				putindexbits('n',32,(dbrxn.getReactionYield() << 24) + dbrxn.getReactionRegNo());
				putindexbits(' ',BONDBITS,indexdata[0]);		// write rxn index entry
				putindexbits(' ',BONDBITS,indexdata[1]);
				putindexbits(' ',DRXNBITS,indexdata[2]);
				putindexbits(' ',HRXNBITS,indexdata[4]);
				putindexbits('l',HRXNBITS,indexdata[5]);
			
	//			if (mBatchClassifierP)
	//				mBatchClassifierP->incIndexEntries( HD_D_FRAG );
			
				if (mIndexToCreate == cIndexFullPermutation)
					{
					putindexbits('c',32,dbrxn.getReactionRegNo());
					putindexbits(' ',BONDBITS,indexdata[1]);
					putindexbits(' ',BONDBITS,indexdata[0]);
					putindexbits(' ',DRXNBITS,indexdata[3]);
					putindexbits(' ',HRXNBITS,indexdata[5]);
					putindexbits('l',HRXNBITS,indexdata[4]);
					}
				}
		
			mUnitRxn++;
			for (int i=1; i<=strLngth[depRxn]; i++)
				mAtomFlags[strand[depRxn][0]][strand[depRxn][i]] &= ~cAtomNotClassifiedYet;
			}
		else
			{
			if (strand[0][0] == strand[1][0])
				if (strand[0][1] == strand[1][strLngth[1]])
					return cError2AlphasInSameStrand;		// both alpha carbons share one strand
			if (strand[2][0] == strand[3][0])
				if (strand[2][1] == strand[3][strLngth[3]])
					return cError2AlphasInSameStrand;		// both alpha carbons share one strand
		
			int retval = bndSpcDat(strand[0],strand[1],0,indexdata,0);
			if (retval != 0) return retval;
			retval = bndSpcDat(strand[2],strand[3],2,indexdata,1);
			if (retval != 0) return retval;
		
			for (int strnd=0; strnd<2; strnd++) {
				int deltaLst = getDelta(strand[strnd],strLngth[strnd],strLngth[strnd]);
				int tempDeltaLst = getDelta(strand[dependnc[strnd]],strLngth[dependnc[strnd]],strLngth[dependnc[strnd]]);
		
				if (tempDeltaLst < deltaLst) {
					deltaLst = tempDeltaLst;
					depRxn = dependnc[strnd];
					}
				else depRxn = strnd;
		
				retval = clssfyDR(indexdata,2+2*strnd,-deltaLst,false,strand[depRxn],strLngth[depRxn],strnd*2+4);
				if (retval != 0) return retval;
		
				for (int i=1; i<=strLngth[strnd]; i++)
					mAtomFlags[strand[strnd][0]][strand[strnd][i]] &= ~cAtomNotClassifiedYet;
				}
		
			mResult.mMainClass[mUnitRxn] = D_D_FRAG;

			if (mIndexToCreate != cIndexNone) {
				DatabaseReaction dbrxn = (DatabaseReaction)mRxn;

				putindexbits('n',32,(dbrxn.getReactionYield() << 24) + dbrxn.getReactionRegNo());
				putindexbits(' ',BONDBITS,indexdata[0]);		// write rxn index entry
				putindexbits(' ',BONDBITS,indexdata[1]);
				putindexbits(' ',DRXNBITS,indexdata[2]);
				putindexbits('l',DRXNBITS,indexdata[4]);
			
	//			if (mBatchClassifierP)
	//				mBatchClassifierP->incIndexEntries( D_D_FRAG );
			
				if (mIndexToCreate == cIndexFullPermutation)
					{
					putindexbits('c',32,dbrxn.getReactionRegNo());
					putindexbits(' ',BONDBITS,indexdata[0]);
					putindexbits(' ',BONDBITS,indexdata[1]);
					putindexbits(' ',DRXNBITS,indexdata[4]);
					putindexbits('l',DRXNBITS,indexdata[2]);
					putindexbits('c',32,dbrxn.getReactionRegNo());
					putindexbits(' ',BONDBITS,indexdata[1]);
					putindexbits(' ',BONDBITS,indexdata[0]);
					putindexbits(' ',DRXNBITS,indexdata[3]);
					putindexbits('l',DRXNBITS,indexdata[5]);
					putindexbits('c',32,dbrxn.getReactionRegNo());
					putindexbits(' ',BONDBITS,indexdata[1]);
					putindexbits(' ',BONDBITS,indexdata[0]);
					putindexbits(' ',DRXNBITS,indexdata[5]);
					putindexbits('l',DRXNBITS,indexdata[3]);
					}
				}

			mUnitRxn++;
			}
		return cErrorNoError;
		}


	/**
	 * rearrangement
	 * @return
	 */
	private int rearrang(int[] ccBFmol, int[] ccBFatm, int[] ccBCmol, int[] ccBCatm) {
		int[] strLngth = new int[4];
		int[] indexdata = new int[5];
		int[] dependnc = new int[2];// indicates for each educt atom of new formed
									// bond, if this an independent half reaction (0)
									// or if the appropriate strand ends with an atom
									// from that the second bond is formed (atm no)

		int[][] strand = new int[4][8];				// strand[atm][0]: molecule
													// strand[atm][1-8]: alpha - delta
		for (int i=0; i<2; i++) {
			strand[i][0] = ccBFmol[i];
			strand[i][1] = ccBFatm[i];
			strLngth[i] = findStrand(strand[i]);
			if (strLngth[i] < 1) return cErrorForkedOrLongStrand;		// branched strand
		
			int strEnd = strand[i][strLngth[i]];
			for (int j=0; j<2; j++)
				if (strEnd == ccBCatm[j] && ccBFmol[i] == ccBCmol[j])
					dependnc[i] = j+2;
			}
		
		for (int i=0; i<2; i++) {
			strand[i+2][0] = ccBCmol[i];
			strand[i+2][1] = ccBCatm[i];
			strLngth[i+2] = findStrand(strand[i+2]);
			if (strLngth[i+2] < 1) return cErrorForkedOrLongStrand;	// branched strand
			}
		
		if ((dependnc[0] == 0) && (dependnc[1] == 0)) {
			int retval = oneConst(strand[0],strand[1],strLngth[0],strLngth[1]);
			if (retval != 0) return retval;
			return oneFrgm(strand[2],strand[3],strLngth[2],strLngth[3]);
			}
		
		if ((dependnc[0] == 0) || (dependnc[1] == 0)) {
			int hlfCon,hlfFrg,depRxn;
			if (dependnc[0] == 0) {
				hlfCon = 0;
				hlfFrg = (dependnc[1] == 2) ? 3 : 2;
				depRxn = 1;
				}
			else
				{
				hlfCon = 1;
				hlfFrg = (dependnc[0] == 2) ? 3 : 2;
				depRxn = 0;
				}
		
			mResult.mRearStrandLen[0] = strLngth[depRxn];

			int retval = bndSpcDat(strand[hlfCon],strand[depRxn],0,indexdata,0);
			if (retval != 0) return retval;
			retval = bndSpcDat(strand[hlfFrg],strand[5-hlfFrg],2,indexdata,1);
			if (retval != 0) return retval;
		
			int deltaLst = getDelta(strand[depRxn],strLngth[depRxn],7);		// two end hlf rearr
			retval = clssfyRA(indexdata,2,deltaLst,
								strand[depRxn],strLngth[depRxn],4);
			if (retval != 0) return retval;
		
			deltaLst = getDelta(strand[hlfCon],strLngth[hlfCon],7);			// contruction
			retval = clssfyHR(indexdata,3,deltaLst,strand[hlfCon],strLngth[hlfCon],true,6);
			if (retval != 0) return retval;						// classification error
		
			deltaLst = getDelta(strand[hlfFrg],strLngth[hlfFrg],7);			// fragmentation
			retval = clssfyHR(indexdata,4,-deltaLst,strand[hlfFrg],strLngth[hlfFrg],false,7);
			if (retval != 0) return retval;						// classification error
		
			mResult.mMainClass[mUnitRxn] = HD_REAR;

			if (mIndexToCreate != cIndexNone) {
				DatabaseReaction dbrxn = (DatabaseReaction)mRxn;

				putindexbits('n',32,(dbrxn.getReactionYield() << 24) + dbrxn.getReactionRegNo());
				putindexbits(' ',BONDBITS,indexdata[0]);		// write rxn index entry
				putindexbits(' ',BONDBITS,indexdata[1]);
				putindexbits(' ',REARBITS,indexdata[2]);
				putindexbits(' ',HRXNBITS,indexdata[3]);
				putindexbits('l',HRXNBITS,indexdata[4]);
			
	//			if (mBatchClassifierP)
	//				mBatchClassifierP->incIndexEntries( HD_REAR );
				}
		
			mUnitRxn++;
			for (int i=1; i<=strLngth[depRxn]; i++)
				mAtomFlags[strand[depRxn][0]][strand[depRxn][i]] &= ~cAtomNotClassifiedYet;
			}
		else {
			for (int strnd=0; strnd<2; strnd++) {
				mResult.mRearStrandLen[strnd] = strLngth[strnd];
		
				int retval = bndSpcDat( strand[strnd*2],strand[strnd*2+1],
									strnd*2,indexdata,strnd);
				if (retval != 0) return retval;
		
				int deltaLst = getDelta(strand[strnd],strLngth[strnd],7);
				retval = clssfyRA(indexdata,2+strnd,deltaLst,
									strand[strnd],strLngth[strnd],strnd*2+4);
				if (retval != 0) return retval;
		
				for (int i=1; i<=strLngth[strnd]; i++)
					mAtomFlags[strand[strnd][0]][strand[strnd][i]] &= ~cAtomNotClassifiedYet;
				}

			mResult.mMainClass[mUnitRxn] = D_REAR;

			if (mIndexToCreate != cIndexNone) {
				DatabaseReaction dbrxn = (DatabaseReaction)mRxn;

				putindexbits('n',32,(dbrxn.getReactionYield() << 24) + dbrxn.getReactionRegNo());
				putindexbits(' ',BONDBITS,indexdata[0]);		// write rxn index entry
				putindexbits(' ',BONDBITS,indexdata[1]);
				putindexbits(' ',REARBITS,indexdata[2]);
				putindexbits('l',REARBITS,indexdata[3]);
			
	//			if (mBatchClassifierP)
	//				mBatchClassifierP->incIndexEntries( D_REAR );
			
				if (mIndexToCreate == cIndexFullPermutation) {
					putindexbits('c',32,dbrxn.getReactionRegNo());
					putindexbits(' ',BONDBITS,indexdata[0]);
					putindexbits(' ',BONDBITS,indexdata[1]);
					putindexbits(' ',REARBITS,indexdata[3]);
					putindexbits('l',REARBITS,indexdata[2]);
					}
				}

			mUnitRxn++;
			}
		
		return cErrorNoError;
		}


	/**
	 * classify simple half reaction
	 * @return
	 */
	private int clssfyHR(int[] HRindex, int hr, int deltazp,
						 int[] strand, int strLngth, boolean construction, int flshBase) {
		int[] fgroup = new int[4];
		int[] fAtm = new int[4];
		
		mResult.mFlashMol[mUnitRxn][flshBase] = strand[0];
		mResult.mFlashAtom[mUnitRxn][flshBase] = strand[1];
		
		for (int i=0; i maxgroup)
						{
						maxgroup = fgroup[j];
						maxatm = fAtm[j];
						}
					}
				}
			HRindex[hr] |= maxgroup;
			mResult.mChngGrps[mUnitRxn][flshBase-6] = maxgroup;
			mResult.mFlashMol[mUnitRxn][flshBase+2] = flashMol;
			mResult.mFlashAtom[mUnitRxn][flshBase+2] = maxatm;
			return cErrorNoError;
			}

//		#if WRITE_DELTA
		if (gErrout != null) {
			try {
				gErrout.write(String.format("HR-deltaZP: %x",deltazp));
				gErrout.newLine();
				}
			catch (IOException ioe) {}
			}
		
		return cErrorHRClassifyError;
		}


	/**
	 * classify ring closure reaction
	 * @return
	 */
	private int clssfyCR(int[] CRindex, int cr, int deltazp, int[] strand, int strLen, boolean ringClosure) {
		for (int i=0; i 1) wdrawing = 1;
							}
						}
					}
				DRindex[dr] <<= 2;
				DRindex[dr] |= donating + wdrawing;
		
				DRindex[dr+1] = (0xFFFFFFC3 & DRindex[dr]) | (16*sigma2 + 4*sigma1);
		
				return cErrorNoError;
				}
			}
		
//		#if WRITE_DELTA
		if (gErrout != null) {
			try {
				gErrout.write(String.format("DR-deltaZP: %x",deltazp));
				gErrout.newLine();
				}
			catch (IOException ioe) {}
			}
		
		return cErrorDRClassifyError;
		}


	/**
	 * classify two end half rearrangement
	 * @return
	 */
	private int clssfyRA(int[] RAindex, int ra, int deltazp, int[] strand, int strLngth, int flshBase) {
		int i,mol,formAtm,clvgAtm;

		mResult.mFlashMol[mUnitRxn][flshBase] = strand[0];
		mResult.mFlashAtom[mUnitRxn][flshBase] = strand[1];
		mResult.mFlashMol[mUnitRxn][flshBase+1] = strand[0];
		mResult.mFlashAtom[mUnitRxn][flshBase+1] = strand[strLngth];
		
		for (i=0; i= entries) || (deltazp > mClassificationData.getRRxnDelta(poin))) {
				poin -= step;
				step >>= 1;
				}
			else if (deltazp < mClassificationData.getRRxnDelta(poin)) {
				poin += step;
				step >>= 1;
				}
			else {
				mResult.mUnitName[mUnitRxn] = mClassificationData.getRRefuncName( poin );
				mResult.mClassResult[mUnitRxn] = poin;
				return cErrorNoError;
				}
			}
		
//		#if WRITE_DELTA
		if (gErrout != null) {
			try {
				gErrout.write(String.format("RE-deltaZP: %x",deltazp));
				gErrout.newLine();
				}
			catch (IOException ioe) {}
			}
		
		return cErrorREClassifyError;
		}


	/**
	 * store C-C bond specific data
	 * @return
	 */
	private int bndSpcDat(int[] strand1, int[] strand2, int flshBase, int[] bndIndex, int bi) {
		bndIndex[bi] = 0;
		
		int m1 = strand1[0];
		int m2 = strand2[0];
		int atm1 = strand1[1];
		int atm2 = strand2[1];
		
		mResult.mFlashAtom[mUnitRxn][flshBase] = m1;
		mResult.mFlashAtom[mUnitRxn][flshBase] = atm1;
		mResult.mFlashAtom[mUnitRxn][flshBase+1] = m2;
		mResult.mFlashAtom[mUnitRxn][flshBase+1] = atm2;
		
		if (m1 != m2) return cErrorNoError;
								// intermolecular because of different educt molecules
		
		if (conLngth(m1,atm1,atm2,false) != 0) bndIndex[bi] = 16;		// bit 4: intramolecular

		StereoMolecule mol1 = mRxn.getMolecule(m1);
		for (int i=0; i 0) if (connLength > 15) connLength = 15;
		bndIndex[bi] |= connLength;							// bit 0-3: new ring's size
		return cErrorNoError;
		}


	/**
	 * classify refunctionalisation reactions
	 * @return
	 */
	private int refuncs() {
		int[][] leavType = new int[8][MAXCONNS];	// all leaving groups within one refunc
		int[][] incoType = new int[8][MAXCONNS];	// all incoming groups within one refunc
		int[] nrofLeav = new int[8];
		int[] nrofInco = new int[8];				// appropriate numbers of inc/leav grps
		int[][] leavAtm = new int[8][MAXCONNS];		// corresponding atom numbers			
		int[][] incoAtm = new int[8][MAXCONNS];
		int[][] stereo = new int[8][1];
		int[][] strand = new int[2][8];
		int[][][] fGrpCombs = new int[MAXUNITS][MAXINDICES][4];
		int[][] REindex = new int[MAXUNITS][2];
				// contains index information for all single refunc rxns within one
				// REACCS entry (in case mIndexToCreate == cIndexOnePermToFile) or
				// all possible indices of one refunc rxn due to different combinations
				// of functional groups (mIndexToCreate == cIndexFullPermutation)
		int[] delLst = new int[2];
		int[] dummy = new int[1];

		for (int mol=0; mol delLst[0]) ? 1 : 0;

				int retval = clssfyRE(delLst[higher]);
				if (retval != 0) return retval;
		
				for (int i=1; i<=strLngth; i++)
					mAtomFlags[mol][strand[0][i]] &= ~cAtomNotClassifiedYet;
		
				cChange++;
		
				if (strLngth == 1) mResult.mMainClass[mUnitRxn] = C1_REFU;
				else			   mResult.mMainClass[mUnitRxn] = LONG_REFU;
		
		        for (int i=1; i<=strLngth; i++)  // initialize arrays for changing groups
					for (int j=0; j<4; j++) {
			            incoType[i][j] = 0;
		    	        leavType[i][j] = 0;
			            }
		
				for (int i=1; i<=strLngth; i++) {   // get class numbers of changing groups
					int actlAtm = strand[higher][i];
					int proMol = mCorProd[mol][actlAtm];
					int proAtm = mCorAtom[mol][actlAtm];
																	// incoming atoms
					nrofInco[i] = leaving(proMol,proAtm,mol,actlAtm,incoType[i],incoAtm[i],stereo[i]);
		
					for (int j=0; j> 4;
						if ((mClassificationData.getRRxnDef( mResult.mClassResult[mUnitRxn], i, j ) & 64) != 0)
							fGrpCombs[mUnitRxn][i][j] = incoType[strndPos][num];
						else
							fGrpCombs[mUnitRxn][i][j] = leavType[strndPos][num];
						}
					}
		
				boolean schonda = false;
				for (int j=firstRefuUnit; j>1); k++) {
								if (fGrpCombs[mUnitRxn][k][0] == fGrpCombs[j][0][0]
								 && fGrpCombs[mUnitRxn][k][1] == fGrpCombs[j][0][1]
								 && fGrpCombs[mUnitRxn][k][2] == fGrpCombs[j][0][2]
								 && fGrpCombs[mUnitRxn][k][3] == fGrpCombs[j][0][3]) {
									schonda = true;
									break;
									}
								}
							}
						if (REindex[mUnitRxn][0] == REindex[j][1]) {
							for (int k=(mClassificationData.getRRxnMasks( mResult.mClassResult[mUnitRxn] ) >>1);
									k> 4;
					if ((mClassificationData.getRRxnDef( mResult.mClassResult[mUnitRxn], 0, j ) & 64) != 0) {
						mResult.mFlashMol[mUnitRxn][j+2] = mCorProd[mol][strand[higher][1]];
						mResult.mFlashAtom[mUnitRxn][j+2] = incoAtm[strndPos][num];
						}
					else {
						mResult.mFlashMol[mUnitRxn][j+2] = mol;
						mResult.mFlashAtom[mUnitRxn][j+2] = leavAtm[strndPos][num];
						}
					}
		
				mUnitRxn++;
				if (mUnitRxn == MAXUNITS) return cErrorUnitReactionLimit;
				}
			if (mUnitRxn == MAXUNITS) return cErrorUnitReactionLimit;
			}
		
		if (cChange != 0) {
			if (mIndexToCreate != cIndexNone) {
				DatabaseReaction dbrxn = (DatabaseReaction)mRxn;

				if (mIndexToCreate == cIndexOnePermToFile) {	// write one entry per separated unit rxn to file
					int unitRxns = mUnitRxn;
					for (mUnitRxn=firstRefuUnit; mUnitRxnincIndexEntries( mResult.mMainClass[mUnitRxn] );
						}
					}
				else if (mIndexToCreate == cIndexFullPermutation) {		// store all combinations of all unit rxns into array
					int unitRxns = mUnitRxn;
					for (mUnitRxn=firstRefuUnit; mUnitRxn= (mClassificationData.getRRxnMasks( mResult.mClassResult[mUnitRxn] )/2))) {
								putindexbits('c',32,dbrxn.getReactionRegNo());
								putindexbits(' ',midBits,REindex[mUnitRxn][1]);
								putindexbits(' ',8,fGrpCombs[mUnitRxn][j][0]);
								putindexbits(' ',8,fGrpCombs[mUnitRxn][j][1]);
								putindexbits(' ',8,fGrpCombs[mUnitRxn][j][2]);
								putindexbits('l',8,fGrpCombs[mUnitRxn][j][3]);
								}
							else {
								putindexbits('c',32,dbrxn.getReactionRegNo());
								putindexbits(' ',midBits,REindex[mUnitRxn][0]);
								putindexbits(' ',8,fGrpCombs[mUnitRxn][j][0]);
								putindexbits(' ',8,fGrpCombs[mUnitRxn][j][1]);
								putindexbits(' ',8,fGrpCombs[mUnitRxn][j][2]);
								putindexbits('l',8,fGrpCombs[mUnitRxn][j][3]);
								}
							}
						}
					}
				}
			}
		
		int hChange = 0;						// refunctionalisation at non-carbon atom
		firstRefuUnit = mUnitRxn;
		for (int m=0; m 0)
					mResult.mUnitName[mUnitRxn] = "R"+deltaZ+Molecule.cAtomLabel[mol.getAtomicNo(atm)];
				else
					mResult.mUnitName[mUnitRxn] = "S,"+Molecule.cAtomLabel[mol.getAtomicNo(atm)];
		
				mAtomFlags[m][atm] &= ~cAtomNotClassifiedYet;
		
				mResult.mMainClass[mUnitRxn] = HETERO_REFU;
		
				hChange++;
		
				if (mIndexToCreate == cIndexNone) { mUnitRxn++; continue; }
		
				incoType[0][0] = incoType[0][1] = 0;
				nrofInco[0] = leaving(mCorProd[m][atm],mCorAtom[m][atm],m,atm,incoType[0],incoAtm[0],dummy);
		
				while (nrofInco[0] > 2) {
					boolean found = false;
					for (int j=0; !found && j 2) {
					boolean found = false;
					for (int j=0; !found && jincIndexEntries( HETERO_REFU );
						}
					}
				else if (mIndexToCreate == cIndexFullPermutation) {		// store all combinations of one(!) refunc rxn in array
					int unitRxns = mUnitRxn;
					for (mUnitRxn=firstRefuUnit; mUnitRxn 0)) return;
		
		if (bits != 0) mask = 1 << (bits-1);
		for (int i=0; ilongToIndexFile( &data,
//									 mClassResultP->getMainClass( mUnitRxn ) );
				data = 0;
				availbits = 32;
				}
			data <<= 1;
			if ((mask & datum) != 0) data |= 1;
			mask >>= 1;
			availbits--;
			}
		
		if (mode == 'l') {	// write last bits of entry
			data <<= availbits;
			if (mIndexToCreate == cIndexFullPermutation)
				mResult.mIndex[mUnitRxn][indexnum][indexpoin] = data;
//			if (mIndexToCreate == cIndexOnePermToFile)
//				mBatchClassifierP->longToIndexFile( &data,
//								 mClassResultP->getMainClass( mUnitRxn ) );
			}
		}


	/**
	 * if (checkProduct == 0) then return length of shortest chain between two
	 * 							atoms except direct bond (any mol allowed )
	 * if (checkProduct == 1) then return length of shortest chain between two
	 *							educt atoms, that exists in the product as well
	 *							(only educt atoms allowed)
	 * @param mol
	 * @param atm1
	 * @param atm2
	 * @param checkProduct
	 * @return
	 */
	private int conLngth( int mol, int atm1, int atm2, boolean checkProduct ) {
		int[][] mask = new int[2][MAXATOMS];
		int[] lastAtm = new int[MAXATOMS];
		int[] proAtm = new int[MAXATOMS];

		StereoMolecule mol1 = mRxn.getMolecule(mol);

		for (int atm=0; atm");
				}
			catch (IOException ioe) {}
			}

		while (true) {
			boolean overflow = false;
			int atm = -1;
			do {
				overflow = (histConn[histpoin] == mol.getConnAtoms(histAtms[histpoin]));
				if (overflow) break;
				atm = mol.getConnAtom(histAtms[histpoin], histConn[histpoin]++);
				} while ((atm == histAtms[histpoin-1])
						|| (foundMsk[atm] != 0)
						|| (mAtomType[m][atm] != CARBON));
		
			if (!overflow) {
				if (frgAtmNo > MAXFATMS)
					return cErrorFragmentAtomLimit;	// fragment carbons exceed limit
				fragAtms[frgAtmNo] = atm;
				foundMsk[atm] = frgAtmNo++;
				histAtms[++histpoin] = atm;
				histConn[histpoin] = 0;
		
				if (gErrout != null)
					try { gErrout.write(" "+atm); } catch (IOException ioe) {}
				}
			else {
				if (--histpoin == 0) break;
				}
			}
		fragAtms[0] = frgAtmNo-1;
		
		if (gErrout != null)
			try { gErrout.newLine(); } catch (IOException ioe) {}
		
		return cErrorNoError;
		}


/*/////////////////////////////////////////////////////////////////// private //
void flagAromaticBonds( int mol, int aromAtms[] )
////////////////////////////////////////////////////////////////////////////////
{
int atm,aroms,i,j,k;

if (!aromAtms[0])
	return;

aroms = 31 & (int)aromAtms[0];
for (i=2; i<=aroms; i++)
	{
	atm = aromAtms[i];
	for (j=1; j 0)
			if (eCharge > pCharge)
				for (int i=0; i 4) return 0;
		
		if (!mol2.isAtomStereoCenter(atm2)) return 0;
		if (!mol1.isAtomStereoCenter(atm1)) return 1;

		// for (i=0; i 8) continue;  // not likely to happen
			grpAtm[nrofTypes] = connAtm;
			grpMapNo[nrofTypes] = mol.getAtomMapNo(connAtm);
			type[nrofTypes] = gettyp( m, connAtm, atm, fGrpBndOrdr, secCrit[nrofTypes] );
			nrofTypes++;
			for (int j=1; j  C-C-O-CH2-Me
     * comparing the mapping numbers of CO and CH2 answers if a real substitution of
     * acetate by ethanolate or a reduction takes place !
     * @param atm atom Y
     * @param xAtm atom A
     * @param bndOrdr bond order A-Y
	 * @return type of leaving group connected to atom A in A-Y[-Z]
	 */
	private int gettyp(int m, int atm, int xAtm, int bndOrdr, int[] secCrit ) {
		int connAtm,i;
		final int[] fGrpClass = { 0,
		  2,																  0,
		 40, 48,										 56,  0,  0,  0,216,  0,
		 36, 42,										 50, 58,  0,  0,220,  0,
		 37, 44, 64, 68, 70, 80, 84, 85, 86, 87, 72, 76, 52, 59,232,  0,222,  0,
		 38, 45, 65, 69, 71, 82,  0, 89, 90, 91, 73, 77, 54, 60, 62,  0,223,  0,
		 39, 46, 66,	 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
					 69, 71, 83, 92, 93, 94, 95, 74, 78, 55, 61, 63,  0,  0,  0,
		  0, 47, 67,	114,115,116,117,118,119,120,121,122,123,124,125,126,127,
		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  6,222,  0,  0,  0,  0,
		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 };
		
		secCrit[0] = 0;	// default for uncomplicated leaving groups
		secCrit[1] = 0;

		StereoMolecule mol = mRxn.getMolecule(m);
		if (mol.getAtomicNo(atm) == 7) {	// nitrogen functionalities
			if (mol.getAtomMapNo(atm) != 0) {
				secCrit[0] = mol.getAtomMapNo(atm);
				secCrit[1] = bndOrdr;
				}
		
			if (bndOrdr == 3) return 184;					// nitrile
		
			if (bndOrdr == 2) {
				if (mol.getAtomCharge(atm) == 1) {	// positive charge at N
					switch (mZ[m][atm]) {
						case 0: return 176;						// immonium
						case 1: return 178;						// nitrones etc.
						default: return 179;					// iso nitro etc.
						}
					}
				else
					{
					switch (mZ[m][atm]) {
						case 0: return 180;						// imine
						default: return 182;					// oximes etc.
						}
					}		
				}
			else
				{
				if (mol.getAtomCharge(atm) == 1) {	// positive charge at N
					if (mZ[m][atm] == 1) return 172;		// amine oxide
					if (mZ[m][atm] > 1) return 174;		// nitro etc.
					switch (mPi[m][atm]) {
						case 0: return 168;						// ammonium
						case 1: return 170;						// immonium
						default: return 171;					// isonitrile
						}
					}
		
				if (mZ[m][atm] == 0) {					// no hetero atoms at N
					if (mPi[m][atm] == 0) {				// no double bonds to C
						switch (mSigma[m][atm]) {
							case 1: return 160;					// prim amine
							case 2: return 161;					//  sec amine
							default: return 162;				// tert amine
							}
						}
					else return 163;						// imine -N=C
					}
				else if (mZ[m][atm] == 1) {				// z=1 at N
					return 164;
					}
				else {										// z=2 at N
					return 166;
					}
				}
			}
		else if (mol.getAtomicNo(atm) == 8) {	// oxygen functionalities
			if (bndOrdr == 2) return 156;			// carbonyl

			connAtm = -1;
			for (i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy