1818 */
1919package org .openscience .cdk .isomorphism .matchers ;
2020
21+ import org .openscience .cdk .AtomRef ;
22+ import org .openscience .cdk .BondRef ;
23+ import org .openscience .cdk .interfaces .IAtom ;
2124import org .openscience .cdk .interfaces .IAtomContainer ;
2225import org .openscience .cdk .interfaces .IBond ;
26+ import org .openscience .cdk .interfaces .IChemObject ;
27+ import org .openscience .cdk .interfaces .IStereoElement ;
2328
29+ import java .util .HashMap ;
30+ import java .util .HashSet ;
2431import java .util .Iterator ;
32+ import java .util .Map ;
33+ import java .util .Set ;
2534
2635/**
2736 * Utilities for creating queries from 'real' molecules. Note that most of this
@@ -102,9 +111,9 @@ public static QueryAtomContainer createSymbolChargeIDQueryContainer(IAtomContain
102111 }
103112 Iterator <IBond > bonds = container .bonds ().iterator ();
104113 while (bonds .hasNext ()) {
105- IBond bond = bonds .next ();
106- int index1 = container .indexOf (bond .getBegin ());
107- int index2 = container .indexOf (bond .getEnd ());
114+ IBond bond = bonds .next ();
115+ int index1 = container .indexOf (bond .getBegin ());
116+ int index2 = container .indexOf (bond .getEnd ());
108117 if (bond .isAromatic ()) {
109118 QueryBond qbond = new QueryBond (queryContainer .getAtom (index1 ),
110119 queryContainer .getAtom (index2 ),
@@ -135,7 +144,7 @@ public static QueryAtomContainer createSymbolChargeIDQueryContainer(IAtomContain
135144 * Expr.Type.ORDER);
136145 * </pre>
137146 *
138- * @param container The AtomContainer that stands as model
147+ * @param container The AtomContainer that stands as model
139148 * @param aromaticity option flag
140149 * @return The new QueryAtomContainer created from container.
141150 */
@@ -160,7 +169,7 @@ public static QueryAtomContainer createAnyAtomContainer(IAtomContainer container
160169 * QueryAtomContainer.create(container);
161170 * </pre>
162171 *
163- * @param container The AtomContainer that stands as model
172+ * @param container The AtomContainer that stands as model
164173 * @param aromaticity option flag
165174 * @return The new QueryAtomContainer created from container.
166175 */
@@ -190,4 +199,68 @@ public static QueryAtomContainer createAnyAtomForPseudoAtomQueryContainer(IAtomC
190199 Expr .Type .IS_AROMATIC ,
191200 Expr .Type .ALIPHATIC_ORDER );
192201 }
202+
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+
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+ }
193266}
0 commit comments