/** * Adds 3D coordinates for singly-bonded ligands of a reference atom (A). Initially designed for * hydrogens. The ligands of refAtom are identified and those with 3D coordinates used to generate * the new points. (This allows structures with partially known 3D coordinates to be used, as when * groups are added.) "Bent" and "non-planar" groups can be formed by taking a subset of the * calculated points. Thus R-NH2 could use 2 of the 3 points calculated from (1,iii) nomenclature: * A is point to which new ones are "attached". A may have ligands B, C... B may have ligands J, * K.. points X1, X2... are returned The cases (see individual routines, which use idealised * geometry by default): (0) zero ligands of refAtom. The resultant points are randomly oriented: * (i) 1 points required; +x,0,0 (ii) 2 points: use +x,0,0 and -x,0,0 (iii) 3 points: equilateral * triangle in xy plane (iv) 4 points x,x,x, x,-x,-x, -x,x,-x, -x,-x,x (1a) 1 ligand(B) of refAtom * which itself has a ligand (J) (i) 1 points required; vector along AB vector (ii) 2 points: 2 * vectors in ABJ plane, staggered and eclipsed wrt J (iii) 3 points: 1 staggered wrt J, the * others +- gauche wrt J (1b) 1 ligand(B) of refAtom which has no other ligands. A random J is * generated and (1a) applied (2) 2 ligands(B, C) of refAtom A (i) 1 points required; vector in * ABC plane bisecting AB, AC. If ABC is linear, no points (ii) 2 points: 2 vectors at angle ang, * whose resultant is 2i (3) 3 ligands(B, C, D) of refAtom A (i) 1 points required; if A, B, C, D * coplanar, no points. else vector is resultant of BA, CA, DA * * <p>fails if atom itself has no coordinates or >4 ligands * * @param atomContainer describing the ligands of refAtom. It could be the whole molecule, or * could be a selected subset of ligands * @param refAtom (A) to which new ligands coordinates could be added * @param length A-X length * @param angle B-A-X angle (used in certain cases) * @return Point3D[] points calculated. If request could not be fulfilled (e.g. too many atoms, or * strange geometry, returns empty array (zero length, not null) * @cdk.keyword coordinate generation */ public static Point3d[] calculate3DCoordinatesForLigands( AtomContainer atomContainer, IAtom refAtom, int nwanted, double length, double angle) { Point3d newPoints[] = new Point3d[0]; Point3d aPoint = refAtom.getPoint3d(); // get ligands List connectedAtoms = atomContainer.getConnectedAtomsList(refAtom); if (connectedAtoms == null) { return newPoints; } int nligands = connectedAtoms.size(); AtomContainer ligandsWithCoords = new AtomContainer(); for (int i = 0; i < nligands; i++) { Atom ligand = (Atom) connectedAtoms.get(i); if (ligand.getPoint3d() != null) { ligandsWithCoords.addAtom(ligand); } } int nwithCoords = ligandsWithCoords.getAtomCount(); // too many ligands at present if (nwithCoords > 3) { return newPoints; } if (nwithCoords == 0) { newPoints = calculate3DCoordinates0(refAtom.getPoint3d(), nwanted, length); } else if (nwithCoords == 1) { // ligand on A IAtom bAtom = ligandsWithCoords.getAtom(0); connectedAtoms = ligandsWithCoords.getConnectedAtomsList(bAtom); // does B have a ligand (other than A) Atom jAtom = null; for (int i = 0; i < connectedAtoms.size(); i++) { Atom connectedAtom = (Atom) connectedAtoms.get(i); if (!connectedAtom.equals(refAtom)) { jAtom = connectedAtom; break; } } newPoints = calculate3DCoordinates1( aPoint, bAtom.getPoint3d(), (jAtom != null) ? jAtom.getPoint3d() : null, nwanted, length, angle); } else if (nwithCoords == 2) { Point3d bPoint = ligandsWithCoords.getAtom(0).getPoint3d(); Point3d cPoint = ligandsWithCoords.getAtom(1).getPoint3d(); newPoints = calculate3DCoordinates2(aPoint, bPoint, cPoint, nwanted, length, angle); } else if (nwithCoords == 3) { Point3d bPoint = ligandsWithCoords.getAtom(0).getPoint3d(); Point3d cPoint = ligandsWithCoords.getAtom(1).getPoint3d(); Point3d dPoint = ligandsWithCoords.getAtom(2).getPoint3d(); newPoints = new Point3d[1]; newPoints[0] = calculate3DCoordinates3(aPoint, bPoint, cPoint, dPoint, length); } return newPoints; }
/* * this is a test contributed by mario baseda / see bug #1610997 * @cdk.bug 1610997 */ @Test public void testModel3D_bug_1610997() throws Exception { Assume.assumeTrue(runSlowTests()); boolean notCalculatedResults = false; List inputList = new ArrayList(); //////////////////////////////////////////////////////////////////////////////////////////// // generate the input molecules. This are molecules without x, y, z coordinats String[] smiles = new String[] { "CC", "OCC", "O(C)CCC", "c1ccccc1", "C(=C)=C", "OCC=CCc1ccccc1(C=C)", "O(CC=C)CCN", "CCCCCCCCCCCCCCC", "OCC=CCO", "NCCCCN" }; SmilesParser sp = new SmilesParser(NoNotificationChemObjectBuilder.getInstance()); IAtomContainer[] atomContainer = new IAtomContainer[smiles.length]; for (int i = 0; i < smiles.length; i++) { atomContainer[i] = sp.parseSmiles(smiles[i]); inputList.add(atomContainer[i]); } System.out.println(inputList.size()); /////////////////////////////////////////////////////////////////////////////////////////// // Generate 2D coordinats for the input molecules with the Structure Diagram Generator StructureDiagramGenerator str; List resultList = new ArrayList(); for (Iterator iter = inputList.iterator(); iter.hasNext(); ) { IAtomContainer molecules = (IAtomContainer) iter.next(); str = new StructureDiagramGenerator(); str.setMolecule((IMolecule) molecules); str.generateCoordinates(); resultList.add(str.getMolecule()); } inputList = resultList; ///////////////////////////////////////////////////////////////////////////////////////////// // Delete x and y coordinats for (Iterator iter = inputList.iterator(); iter.hasNext(); ) { IAtomContainer molecules = (IAtomContainer) iter.next(); for (Iterator atom = molecules.atoms().iterator(); atom.hasNext(); ) { Atom last = (Atom) atom.next(); last.setPoint2d(null); } } //////////////////////////////////////////////////////////////////////////////////////////////////// // Test for the method Model3DBuildersWithMM2ForceField ModelBuilder3D mb3d = ModelBuilder3D.getInstance(); for (Iterator iter = inputList.iterator(); iter.hasNext(); ) { IAtomContainer molecules = (IAtomContainer) iter.next(); IMolecule mol = molecules.getBuilder().newInstance(IMolecule.class, molecules); mol = mb3d.generate3DCoordinates(mol, false); System.out.println("Calculation done"); } for (Iterator iter = inputList.iterator(); iter.hasNext(); ) { IAtomContainer molecule = (IAtomContainer) iter.next(); checkAverageBondLength(molecule); for (Iterator atom = molecule.atoms().iterator(); atom.hasNext(); ) { Atom last = (Atom) atom.next(); if (last.getPoint3d() == null) notCalculatedResults = true; } } Assert.assertFalse(notCalculatedResults); }