1 /* Copyright (C) 2004-2008 The Chemistry Development Kit (CDK) project 2 * 3 * Contact: cdk-devel@lists.sourceforge.net 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public License 7 * as published by the Free Software Foundation; either version 2.1 8 * of the License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 package org.openscience.cdk.isomorphism.matchers; 20 21 import org.openscience.cdk.AtomRef; 22 import org.openscience.cdk.BondRef; 23 import org.openscience.cdk.interfaces.IAtom; 24 import org.openscience.cdk.interfaces.IAtomContainer; 25 import org.openscience.cdk.interfaces.IBond; 26 import org.openscience.cdk.interfaces.IChemObject; 27 import org.openscience.cdk.interfaces.IStereoElement; 28 29 import java.util.HashMap; 30 import java.util.HashSet; 31 import java.util.Iterator; 32 import java.util.Map; 33 import java.util.Set; 34 35 /** 36 * Utilities for creating queries from 'real' molecules. Note that most of this 37 * functionality has now been replaced by the 38 * {@link QueryAtomContainer#create(IAtomContainer, Expr.Type...)} method and 39 * the documentation simply indicates what settings are used. 40 */ 41 public class QueryAtomContainerCreator { 42 43 /** 44 * Creates a QueryAtomContainer with the following settings: 45 * 46 * <pre> 47 * QueryAtomContainer.create(container, 48 * Expr.Type.ALIPHATIC_ELEMENT, 49 * Expr.Type.AROMATIC_ELEMENT, 50 * Expr.Type.IS_AROMATIC, 51 * Expr.Type.ALIPHATIC_ORDER, 52 * Expr.Type.STEREOCHEMISTRY); 53 * </pre> 54 * 55 * @param container The AtomContainer that stands as model 56 * @return The new QueryAtomContainer created from container. 57 */ createBasicQueryContainer(IAtomContainer container)58 public static QueryAtomContainer createBasicQueryContainer(IAtomContainer container) { 59 return QueryAtomContainer.create(container, 60 Expr.Type.ALIPHATIC_ELEMENT, 61 Expr.Type.AROMATIC_ELEMENT, 62 Expr.Type.IS_AROMATIC, 63 Expr.Type.ALIPHATIC_ORDER, 64 Expr.Type.STEREOCHEMISTRY); 65 } 66 67 /** 68 * Creates a QueryAtomContainer with the following settings: 69 * 70 * <pre> 71 * QueryAtomContainer.create(container, 72 * Expr.Type.ELEMENT, 73 * Expr.Type.ORDER); 74 * </pre> 75 * 76 * @param container The AtomContainer that stands as model 77 * @return The new QueryAtomContainer created from container. 78 */ createSymbolAndBondOrderQueryContainer(IAtomContainer container)79 public static QueryAtomContainer createSymbolAndBondOrderQueryContainer(IAtomContainer container) { 80 return QueryAtomContainer.create(container, 81 Expr.Type.ELEMENT, 82 Expr.Type.ORDER); 83 } 84 85 /** 86 * Creates a QueryAtomContainer with the following settings: 87 * 88 * <pre> 89 * QueryAtomContainer.create(container, 90 * Expr.Type.ELEMENT, 91 * Expr.Type.FORMAL_CHARGE, 92 * Expr.Type.IS_AROMATIC, 93 * Expr.Type.ORDER); 94 * </pre> 95 * 96 * @param container The AtomContainer that stands as model 97 * @return The new QueryAtomContainer created from container. 98 */ createSymbolAndChargeQueryContainer(IAtomContainer container)99 public static QueryAtomContainer createSymbolAndChargeQueryContainer(IAtomContainer container) { 100 return QueryAtomContainer.create(container, 101 Expr.Type.ELEMENT, 102 Expr.Type.FORMAL_CHARGE, 103 Expr.Type.IS_AROMATIC, 104 Expr.Type.ORDER); 105 } 106 createSymbolChargeIDQueryContainer(IAtomContainer container)107 public static QueryAtomContainer createSymbolChargeIDQueryContainer(IAtomContainer container) { 108 QueryAtomContainer queryContainer = new QueryAtomContainer(container.getBuilder()); 109 for (int i = 0; i < container.getAtomCount(); i++) { 110 queryContainer.addAtom(new SymbolChargeIDQueryAtom(container.getAtom(i))); 111 } 112 Iterator<IBond> bonds = container.bonds().iterator(); 113 while (bonds.hasNext()) { 114 IBond bond = bonds.next(); 115 int index1 = container.indexOf(bond.getBegin()); 116 int index2 = container.indexOf(bond.getEnd()); 117 if (bond.isAromatic()) { 118 QueryBond qbond = new QueryBond(queryContainer.getAtom(index1), 119 queryContainer.getAtom(index2), 120 Expr.Type.IS_AROMATIC); 121 queryContainer.addBond(qbond); 122 } else { 123 QueryBond qbond = new QueryBond(queryContainer.getAtom(index1), 124 queryContainer.getAtom(index2), 125 Expr.Type.ORDER, 126 bond.getOrder().numeric()); 127 qbond.setOrder(bond.getOrder()); // backwards compatibility 128 queryContainer.addBond(qbond); 129 } 130 } 131 return queryContainer; 132 } 133 134 /** 135 * Creates a QueryAtomContainer with the following settings: 136 * 137 * <pre> 138 * // aromaticity = true 139 * QueryAtomContainer.create(container, 140 * Expr.Type.IS_AROMATIC, 141 * Expr.Type.ALIPHATIC_ORDER); 142 * // aromaticity = false 143 * QueryAtomContainer.create(container, 144 * Expr.Type.ORDER); 145 * </pre> 146 * 147 * @param container The AtomContainer that stands as model 148 * @param aromaticity option flag 149 * @return The new QueryAtomContainer created from container. 150 */ createAnyAtomContainer(IAtomContainer container, boolean aromaticity)151 public static QueryAtomContainer createAnyAtomContainer(IAtomContainer container, boolean aromaticity) { 152 if (aromaticity) 153 return QueryAtomContainer.create(container, 154 Expr.Type.IS_AROMATIC, 155 Expr.Type.ALIPHATIC_ORDER); 156 else 157 return QueryAtomContainer.create(container, 158 Expr.Type.ORDER); 159 } 160 161 /** 162 * Creates a QueryAtomContainer with the following settings: 163 * 164 * <pre> 165 * // aromaticity = true 166 * QueryAtomContainer.create(container, 167 * Expr.Type.IS_AROMATIC); 168 * // aromaticity = false 169 * QueryAtomContainer.create(container); 170 * </pre> 171 * 172 * @param container The AtomContainer that stands as model 173 * @param aromaticity option flag 174 * @return The new QueryAtomContainer created from container. 175 */ createAnyAtomAnyBondContainer(IAtomContainer container, boolean aromaticity)176 public static QueryAtomContainer createAnyAtomAnyBondContainer(IAtomContainer container, boolean aromaticity) { 177 if (aromaticity) 178 return QueryAtomContainer.create(container, Expr.Type.IS_AROMATIC); 179 else 180 return QueryAtomContainer.create(container); 181 } 182 183 /** 184 * Creates a QueryAtomContainer with the following settings: 185 * 186 * <pre> 187 * QueryAtomContainer.create(container, 188 * Expr.Type.ELEMENT, 189 * Expr.Type.IS_AROMATIC, 190 * Expr.Type.ALIPHATIC_ORDER); 191 * </pre> 192 * 193 * @param container The AtomContainer that stands as model 194 * @return The new QueryAtomContainer created from container. 195 */ createAnyAtomForPseudoAtomQueryContainer(IAtomContainer container)196 public static QueryAtomContainer createAnyAtomForPseudoAtomQueryContainer(IAtomContainer container) { 197 return QueryAtomContainer.create(container, 198 Expr.Type.ELEMENT, 199 Expr.Type.IS_AROMATIC, 200 Expr.Type.ALIPHATIC_ORDER); 201 } 202 isSimpleHydrogen(Expr expr)203 static boolean isSimpleHydrogen(Expr expr) { 204 switch (expr.type()) { 205 case ELEMENT: 206 case ALIPHATIC_ELEMENT: 207 return expr.value() == 1; 208 default: 209 return false; 210 } 211 } 212 suppressQueryHydrogens(IAtomContainer mol)213 public static IAtomContainer suppressQueryHydrogens(IAtomContainer mol) { 214 215 // pre-checks 216 for (IAtom atom : mol.atoms()) { 217 if (!(AtomRef.deref(atom) instanceof QueryAtom)) 218 throw new IllegalArgumentException("Non-query atoms found!"); 219 } 220 for (IBond bond : mol.bonds()) { 221 if (!(BondRef.deref(bond) instanceof QueryBond)) 222 throw new IllegalArgumentException("Non-query bonds found!"); 223 } 224 225 Map<IChemObject,IChemObject> plainHydrogens = new HashMap<>(); 226 for (IAtom atom : mol.atoms()) { 227 int hcnt = 0; 228 for (IAtom nbor : mol.getConnectedAtomsList(atom)) { 229 QueryAtom qnbor = (QueryAtom) AtomRef.deref(nbor); 230 if (mol.getConnectedBondsCount(nbor) == 1 && 231 isSimpleHydrogen(qnbor.getExpression())) { 232 hcnt++; 233 plainHydrogens.put(nbor, atom); 234 } 235 } 236 if (hcnt > 0) { 237 QueryAtom qatom = (QueryAtom) AtomRef.deref(atom); 238 Expr e = qatom.getExpression(); 239 Expr hexpr = new Expr(); 240 for (int i = 0; i < hcnt; i++) 241 hexpr.and(new Expr(Expr.Type.TOTAL_H_COUNT, i).negate()); 242 e.and(hexpr); 243 } 244 } 245 246 // nothing to do 247 if (plainHydrogens.isEmpty()) 248 return mol; 249 250 IAtomContainer res = new QueryAtomContainer(mol.getBuilder()); 251 for (IAtom atom : mol.atoms()) { 252 if (!plainHydrogens.containsKey(atom)) 253 res.addAtom(atom); 254 } 255 for (IBond bond : mol.bonds()) { 256 if (!plainHydrogens.containsKey(bond.getBegin()) && 257 !plainHydrogens.containsKey(bond.getEnd())) 258 res.addBond(bond); 259 } 260 for (IStereoElement se : mol.stereoElements()) { 261 res.addStereoElement(se.map(plainHydrogens)); 262 } 263 264 return res; 265 } 266 } 267