/* $Revision$ $Author$ $Date$ * * Copyright (C) 1997-2009 Christoph Steinbeck, Stefan Kuhn <shk3@users.sf.net> * * Contact: cdk-devel@lists.sourceforge.net * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * All we ask is that proper credit is given for our work, which includes * - but is not limited to - adding the above copyright notice to the beginning * of your source code files, and to any copyright notice that you may distribute * with programs based on this work. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.openscience.cdk.structgen.stochastic; import org.openscience.cdk.exception.CDKException; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IAtomContainerSet; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; import org.openscience.cdk.tools.SaturationChecker; import org.openscience.cdk.tools.manipulator.AtomContainerSetManipulator; import org.openscience.cdk.tools.manipulator.BondManipulator; /** * Randomly generates a single, connected, correctly bonded structure from * a number of fragments. * <p>Assign hydrogen counts to each heavy atom. The hydrogens should not be * in the atom pool but should be assigned implicitly to the heavy atoms in * order to reduce computational cost. * * @author steinbeck * @cdk.created 2001-09-04 * @cdk.module structgen * @cdk.githash */ public class PartialFilledStructureMerger { private ILoggingTool logger = LoggingToolFactory.createLoggingTool(PartialFilledStructureMerger.class); SaturationChecker satCheck; /** * Constructor for the PartialFilledStructureMerger object. */ public PartialFilledStructureMerger() { satCheck = new SaturationChecker(); } /** * Randomly generates a single, connected, correctly bonded structure from * a number of fragments. IMPORTANT: The AtomContainers in the set must be * connected. If an AtomContainer is disconnected, no valid result will * be formed * @param atomContainers The fragments to generate for. * @return The newly formed structure. * @throws CDKException No valid result could be formed. */ public IAtomContainer generate(IAtomContainerSet atomContainers) throws CDKException { int iteration = 0; boolean structureFound = false; do { iteration++; boolean bondFormed; do{ bondFormed=false; for(IAtomContainer ac : atomContainers.atomContainers()){ for(IAtom atom : ac.atoms()){ if (!satCheck.isSaturated(atom, ac)) { IAtom partner = getAnotherUnsaturatedNode(atom, atomContainers); if (partner != null) { IAtomContainer toadd = AtomContainerSetManipulator.getRelevantAtomContainer(atomContainers, partner); double cmax1 = satCheck.getCurrentMaxBondOrder(atom, ac); double cmax2 = satCheck.getCurrentMaxBondOrder(partner, toadd); double max = Math.min(cmax1, cmax2); double order = Math.min(Math.max(1.0, max), 3.0);//(double)Math.round(Math.random() * max) logger.debug("cmax1, cmax2, max, order: " + cmax1 + ", " + cmax2 + ", " + max + ", " + order); if(toadd!=ac){ atomContainers.removeAtomContainer(toadd); ac.add(toadd); } ac.addBond( ac.getBuilder().newBond( atom, partner, BondManipulator.createBondOrder(order) ) ); bondFormed = true; } } } } }while(bondFormed); if (atomContainers.getAtomContainerCount()==1 && satCheck.allSaturated(atomContainers.getAtomContainer(0))) { structureFound = true; } } while (!structureFound && iteration < 5); if (atomContainers.getAtomContainerCount()==1 && satCheck.allSaturated(atomContainers.getAtomContainer(0))) { structureFound = true; } if(!structureFound) throw new CDKException("Could not combine the fragments to combine a valid, satured structure"); return atomContainers.getAtomContainer(0); } /** * Gets a randomly selected unsaturated atom from the set. If there are any, it will be from another * container than exclusionAtom. * * @return The unsaturated atom. */ private IAtom getAnotherUnsaturatedNode(IAtom exclusionAtom, IAtomContainerSet atomContainers) throws CDKException { IAtom atom; for(IAtomContainer ac : atomContainers.atomContainers()){ if(!ac.contains(exclusionAtom)){ int next = 0;//(int) (Math.random() * ac.getAtomCount()); for (int f = next; f < ac.getAtomCount(); f++) { atom = ac.getAtom(f); if (!satCheck.isSaturated(atom, ac) && exclusionAtom != atom && !ac.getConnectedAtomsList(exclusionAtom).contains(atom)) { return atom; } } } } for(IAtomContainer ac : atomContainers.atomContainers()){ int next = ac.getAtomCount();//(int) (Math.random() * ac.getAtomCount()); for (int f = 0; f < next; f++) { atom = ac.getAtom(f); if (!satCheck.isSaturated(atom, ac) && exclusionAtom != atom && !ac.getConnectedAtomsList(exclusionAtom).contains(atom)) { return atom; } } } return null; } }