public static IAtomContainer suppressHydrogens(IAtomContainer org) {

        boolean anyHydrogenPresent = false;
        for (IAtom atom : org.atoms()) {
            if ("H".equals(atom.getSymbol())) {
                anyHydrogenPresent = true;
                break;
            }
        }

        if (!anyHydrogenPresent)
            return org;

        // crossing atoms, positional variation atoms etc
        Set<IAtom>         xatoms  = Collections.emptySet();
        Collection<Sgroup> sgroups = org.getProperty(CDKConstants.CTAB_SGROUPS);
        if (sgroups != null) {
            xatoms = new HashSet<>();
            for (Sgroup sgroup : sgroups) {
                for (IBond bond : sgroup.getBonds()) {
                    xatoms.add(bond.getBegin());
                    xatoms.add(bond.getEnd());
                }
            }
        }

        // we need fast adjacency checks (to check for suppression and
        // update hydrogen counts)
        GraphUtil.EdgeToBondMap bondmap = GraphUtil.EdgeToBondMap.withSpaceFor(org);
        final int[][] graph = GraphUtil.toAdjList(org, bondmap);

        final int nOrgAtoms = org.getAtomCount();
        final int nOrgBonds = org.getBondCount();

        int nCpyAtoms = 0;
        int nCpyBonds = 0;

        final Set<IAtom> hydrogens        = new HashSet<IAtom>(nOrgAtoms);
        final Set<IBond> bondsToHydrogens = new HashSet<IBond>();
        final IAtom[] cpyAtoms = new IAtom[nOrgAtoms];

        // filter the original container atoms for those that can/can't
        // be suppressed
        for (int v = 0; v < nOrgAtoms; v++) {
            final IAtom atom = org.getAtom(v);
            if (suppressibleHydrogen(org, graph, bondmap, v) &&
                !xatoms.contains(atom)) {
                hydrogens.add(atom);
                incrementImplHydrogenCount(org.getAtom(graph[v][0]));
            } else {
                cpyAtoms[nCpyAtoms++] = atom;
            }
        }

        // none of the hydrogens could be suppressed - no changes need to be made
        if (hydrogens.isEmpty()) return org;

        // we now update the bonds - we have auxiliary variable remaining that
        // bypasses the set membership checks if all suppressed bonds are found
        IBond[] cpyBonds = new IBond[nOrgBonds - hydrogens.size()];
        int remaining = hydrogens.size();

        for (final IBond bond : org.bonds()) {
            if (remaining > 0 && (hydrogens.contains(bond.getBegin()) || hydrogens.contains(bond.getEnd()))) {
                bondsToHydrogens.add(bond);
                remaining--;
                continue;
            }
            cpyBonds[nCpyBonds++] = bond;
        }

        // we know how many hydrogens we removed and we should have removed the
        // same number of bonds otherwise the containers is a strange
        if (nCpyBonds != cpyBonds.length)
            throw new IllegalArgumentException("number of removed bonds was less than the number of removed hydrogens");

        List<IStereoElement> elements = new ArrayList<IStereoElement>();

        for (IStereoElement se : org.stereoElements()) {
            if (se instanceof ITetrahedralChirality) {
                ITetrahedralChirality tc = (ITetrahedralChirality) se;
                IAtom focus = tc.getChiralAtom();
                IAtom[] neighbors = tc.getLigands();
                boolean updated = false;
                for (int i = 0; i < neighbors.length; i++) {
                    if (hydrogens.contains(neighbors[i])) {
                        neighbors[i] = focus;
                        updated = true;
                    }
                }

                // no changes
                if (!updated) {
                    elements.add(tc);
                } else {
                    elements.add(new TetrahedralChirality(focus, neighbors, tc.getStereo()));
                }
            } else if (se instanceof ExtendedTetrahedral) {
                ExtendedTetrahedral tc = (ExtendedTetrahedral) se;
                IAtom   focus    = tc.getFocus();
                IAtom[] carriers = tc.getCarriers().toArray(new IAtom[4]);
                IAtom[] ends     = ExtendedTetrahedral.findTerminalAtoms(org, focus);
                boolean updated = false;
                for (int i = 0; i < carriers.length; i++) {
                    if (hydrogens.contains(carriers[i])) {
                        if (org.getBond(carriers[i], ends[0]) != null)
                            carriers[i] = ends[0];
                        else
                            carriers[i] = ends[1];
                        updated = true;
                    }
                }
                // no changes
                if (!updated) {
                    elements.add(tc);
                } else {
                    elements.add(new ExtendedTetrahedral(focus, carriers, tc.getConfigOrder()));
                }
            } else if (se instanceof IDoubleBondStereochemistry) {
                IDoubleBondStereochemistry db = (IDoubleBondStereochemistry) se;
                Conformation conformation = db.getStereo();

                IBond orgStereo = db.getStereoBond();
                IBond orgLeft = db.getBonds()[0];
                IBond orgRight = db.getBonds()[1];

                // we use the following variable names to refer to the
                // double bond atoms and substituents
                // x       y
                //  \     /
                //   u = v

                IAtom u = orgStereo.getBegin();
                IAtom v = orgStereo.getEnd();
                IAtom x = orgLeft.getOther(u);
                IAtom y = orgRight.getOther(v);

                // if xNew == x and yNew == y we don't need to find the
                // connecting bonds
                IAtom xNew = x;
                IAtom yNew = y;

                if (hydrogens.contains(x)) {
                    conformation = conformation.invert();
                    xNew = findSingleBond(org, u, x);
                }

                if (hydrogens.contains(y)) {
                    conformation = conformation.invert();
                    yNew = findSingleBond(org, v, y);
                }

                // no other atoms connected, invalid double-bond configuration
                // is removed. example [2H]/C=C/[H]
                if (x == null || y == null ||
                    xNew == null || yNew == null) continue;

                // no changes
                if (x.equals(xNew) && y.equals(yNew)) {
                    elements.add(db);
                    continue;
                }

                // XXX: may perform slow operations but works for now
                IBond cpyLeft  = !Objects.equals(xNew, x) ? org.getBond(u, xNew) : orgLeft;
                IBond cpyRight = !Objects.equals(yNew, y) ? org.getBond(v, yNew) : orgRight;

                elements.add(new DoubleBondStereochemistry(orgStereo,
                                                           new IBond[]{cpyLeft, cpyRight},
                                                           conformation));
            } else if (se instanceof ExtendedCisTrans) {
                ExtendedCisTrans db = (ExtendedCisTrans) se;
                int config = db.getConfigOrder();

                IBond focus     = db.getFocus();
                IBond orgLeft   = db.getCarriers().get(0);
                IBond orgRight  = db.getCarriers().get(1);

                // we use the following variable names to refer to the
                // extended double bond atoms and substituents
                // x       y
                //  \     /
                //   u===v
                IAtom[] ends = ExtendedCisTrans.findTerminalAtoms(org, focus);
                IAtom u = ends[0];
                IAtom v = ends[1];
                IAtom x = orgLeft.getOther(u);
                IAtom y = orgRight.getOther(v);

                // if xNew == x and yNew == y we don't need to find the
                // connecting bonds
                IAtom xNew = x;
                IAtom yNew = y;

                if (hydrogens.contains(x)) {
                    config ^= 0x3;
                    xNew = findSingleBond(org, u, x);
                }

                if (hydrogens.contains(y)) {
                    config ^= 0x3;
                    yNew = findSingleBond(org, v, y);
                }

                // no other atoms connected, invalid double-bond configuration
                // is removed. example [2H]/C=C/[H]
                if (x == null || y == null ||
                    xNew == null || yNew == null) continue;

                // no changes
                if (x.equals(xNew) && y.equals(yNew)) {
                    elements.add(db);
                    continue;
                }

                // XXX: may perform slow operations but works for now
                IBond cpyLeft  = !Objects.equals(xNew, x) ? org.getBond(u, xNew) : orgLeft;
                IBond cpyRight = !Objects.equals(yNew, y) ? org.getBond(v, yNew) : orgRight;

                elements.add(new ExtendedCisTrans(focus,
                                                  new IBond[]{cpyLeft, cpyRight},
                                                  config));
            } else if (se instanceof Atropisomeric) {
                // can not have any H's
                elements.add(se);
            }
        }

        org.setAtoms(Arrays.copyOf(cpyAtoms, nCpyAtoms));
        org.setBonds(cpyBonds);
        org.setStereoElements(elements);

        // single electron and lone pairs are not really used but we update
        // them just in-case but we just use the inefficient AtomContainer
        // methods

        if (org.getSingleElectronCount() > 0) {
            Set<ISingleElectron> remove = new HashSet<ISingleElectron>();
            for (ISingleElectron se : org.singleElectrons()) {
                if (hydrogens.contains(se.getAtom())) remove.add(se);
            }
            for (ISingleElectron se : remove) {
                org.removeSingleElectron(se);
            }
        }

        if (org.getLonePairCount() > 0) {
            Set<ILonePair> remove = new HashSet<ILonePair>();
            for (ILonePair lp : org.lonePairs()) {
                if (hydrogens.contains(lp.getAtom())) remove.add(lp);
            }
            for (ILonePair lp : remove) {
                org.removeLonePair(lp);
            }
        }

        if (sgroups != null) {
            for (Sgroup sgroup : sgroups) {
                if (sgroup.getValue(SgroupKey.CtabParentAtomList) != null) {
                    Collection<IAtom> pal = sgroup.getValue(SgroupKey.CtabParentAtomList);
                    pal.removeAll(hydrogens);
                }
                for (IAtom hydrogen : hydrogens)
                    sgroup.removeAtom(hydrogen);
                for (IBond bondToHydrogen : bondsToHydrogens)
                    sgroup.removeBond(bondToHydrogen);
            }
        }

        return org;
    }
public static IAtomContainer suppressHydrogens ( IAtomContainer org ) { boolean anyHydrogenPresent = false ; for ( IAtom atom : org . atoms ( ) ) { if ( "H" . equals ( atom . getSymbol ( ) ) ) { anyHydrogenPresent = true ; break ; } } if ( ! anyHydrogenPresent ) return org ; Set < IAtom > xatoms = Collections . emptySet ( ) ; Collection < Sgroup > sgroups = org . getProperty ( CDKConstants . CTAB_SGROUPS ) ; if ( sgroups != null ) { xatoms = new HashSet < > ( ) ; for ( Sgroup sgroup : sgroups ) { for ( IBond bond : sgroup . getBonds ( ) ) { xatoms . add ( bond . getBegin ( ) ) ; xatoms . add ( bond . getEnd ( ) ) ; } } } GraphUtil . EdgeToBondMap bondmap = GraphUtil . EdgeToBondMap . withSpaceFor ( org ) ; final int [ ] [ ] graph = GraphUtil . toAdjList ( org , bondmap ) ; final int nOrgAtoms = org . getAtomCount ( ) ; final int nOrgBonds = org . getBondCount ( ) ; int nCpyAtoms = 0 ; int nCpyBonds = 0 ; final Set < IAtom > hydrogens = new HashSet < IAtom > ( nOrgAtoms ) ; final Set < IBond > bondsToHydrogens = new HashSet < IBond > ( ) ; final IAtom [ ] cpyAtoms = new IAtom [ nOrgAtoms ] ; for ( int v = 0 ; v < nOrgAtoms ; v ++ ) { final IAtom atom = org . getAtom ( v ) ; if ( suppressibleHydrogen ( org , graph , bondmap , v ) && ! xatoms . contains ( atom ) ) { hydrogens . add ( atom ) ; incrementImplHydrogenCount ( org . getAtom ( graph [ v ] [ 0 ] ) ) ; } else { cpyAtoms [ nCpyAtoms ++ ] = atom ; } } if ( hydrogens . isEmpty ( ) ) return org ; IBond [ ] cpyBonds = new IBond [ nOrgBonds - hydrogens . size ( ) ] ; int remaining = hydrogens . size ( ) ; for ( final IBond bond : org . bonds ( ) ) { if ( remaining > 0 && ( hydrogens . contains ( bond . getBegin ( ) ) || hydrogens . contains ( bond . getEnd ( ) ) ) ) { bondsToHydrogens . add ( bond ) ; remaining -- ; continue ; } cpyBonds [ nCpyBonds ++ ] = bond ; } if ( nCpyBonds != cpyBonds . length ) throw new IllegalArgumentException ( "number of removed bonds was less than the number of removed hydrogens" ) ; List < IStereoElement > elements = new ArrayList < IStereoElement > ( ) ; for ( IStereoElement se : org . stereoElements ( ) ) { if ( se instanceof ITetrahedralChirality ) { ITetrahedralChirality tc = ( ITetrahedralChirality ) se ; IAtom focus = tc . getChiralAtom ( ) ; IAtom [ ] neighbors = tc . getLigands ( ) ; boolean updated = false ; for ( int i = 0 ; i < neighbors . length ; i ++ ) { if ( hydrogens . contains ( neighbors [ i ] ) ) { neighbors [ i ] = focus ; updated = true ; } } if ( ! updated ) { elements . add ( tc ) ; } else { elements . add ( new TetrahedralChirality ( focus , neighbors , tc . getStereo ( ) ) ) ; } } else if ( se instanceof ExtendedTetrahedral ) { ExtendedTetrahedral tc = ( ExtendedTetrahedral ) se ; IAtom focus = tc . getFocus ( ) ; IAtom [ ] carriers = tc . getCarriers ( ) . toArray ( new IAtom [ 4 ] ) ; IAtom [ ] ends = ExtendedTetrahedral . findTerminalAtoms ( org , focus ) ; boolean updated = false ; for ( int i = 0 ; i < carriers . length ; i ++ ) { if ( hydrogens . contains ( carriers [ i ] ) ) { if ( org . getBond ( carriers [ i ] , ends [ 0 ] ) != null ) carriers [ i ] = ends [ 0 ] ; else carriers [ i ] = ends [ 1 ] ; updated = true ; } } if ( ! updated ) { elements . add ( tc ) ; } else { elements . add ( new ExtendedTetrahedral ( focus , carriers , tc . getConfigOrder ( ) ) ) ; } } else if ( se instanceof IDoubleBondStereochemistry ) { IDoubleBondStereochemistry db = ( IDoubleBondStereochemistry ) se ; Conformation conformation = db . getStereo ( ) ; IBond orgStereo = db . getStereoBond ( ) ; IBond orgLeft = db . getBonds ( ) [ 0 ] ; IBond orgRight = db . getBonds ( ) [ 1 ] ; IAtom u = orgStereo . getBegin ( ) ; IAtom v = orgStereo . getEnd ( ) ; IAtom x = orgLeft . getOther ( u ) ; IAtom y = orgRight . getOther ( v ) ; IAtom xNew = x ; IAtom yNew = y ; if ( hydrogens . contains ( x ) ) { conformation = conformation . invert ( ) ; xNew = findSingleBond ( org , u , x ) ; } if ( hydrogens . contains ( y ) ) { conformation = conformation . invert ( ) ; yNew = findSingleBond ( org , v , y ) ; } if ( x == null || y == null || xNew == null || yNew == null ) continue ; if ( x . equals ( xNew ) && y . equals ( yNew ) ) { elements . add ( db ) ; continue ; } IBond cpyLeft = ! Objects . equals ( xNew , x ) ? org . getBond ( u , xNew ) : orgLeft ; IBond cpyRight = ! Objects . equals ( yNew , y ) ? org . getBond ( v , yNew ) : orgRight ; elements . add ( new DoubleBondStereochemistry ( orgStereo , new IBond [ ] { cpyLeft , cpyRight } , conformation ) ) ; } else if ( se instanceof ExtendedCisTrans ) { ExtendedCisTrans db = ( ExtendedCisTrans ) se ; int config = db . getConfigOrder ( ) ; IBond focus = db . getFocus ( ) ; IBond orgLeft = db . getCarriers ( ) . get ( 0 ) ; IBond orgRight = db . getCarriers ( ) . get ( 1 ) ; IAtom [ ] ends = ExtendedCisTrans . findTerminalAtoms ( org , focus ) ; IAtom u = ends [ 0 ] ; IAtom v = ends [ 1 ] ; IAtom x = orgLeft . getOther ( u ) ; IAtom y = orgRight . getOther ( v ) ; IAtom xNew = x ; IAtom yNew = y ; if ( hydrogens . contains ( x ) ) { config ^= 0x3 ; xNew = findSingleBond ( org , u , x ) ; } if ( hydrogens . contains ( y ) ) { config ^= 0x3 ; yNew = findSingleBond ( org , v , y ) ; } if ( x == null || y == null || xNew == null || yNew == null ) continue ; if ( x . equals ( xNew ) && y . equals ( yNew ) ) { elements . add ( db ) ; continue ; } IBond cpyLeft = ! Objects . equals ( xNew , x ) ? org . getBond ( u , xNew ) : orgLeft ; IBond cpyRight = ! Objects . equals ( yNew , y ) ? org . getBond ( v , yNew ) : orgRight ; elements . add ( new ExtendedCisTrans ( focus , new IBond [ ] { cpyLeft , cpyRight } , config ) ) ; } else if ( se instanceof Atropisomeric ) { elements . add ( se ) ; } } org . setAtoms ( Arrays . copyOf ( cpyAtoms , nCpyAtoms ) ) ; org . setBonds ( cpyBonds ) ; org . setStereoElements ( elements ) ; if ( org . getSingleElectronCount ( ) > 0 ) { Set < ISingleElectron > remove = new HashSet < ISingleElectron > ( ) ; for ( ISingleElectron se : org . singleElectrons ( ) ) { if ( hydrogens . contains ( se . getAtom ( ) ) ) remove . add ( se ) ; } for ( ISingleElectron se : remove ) { org . removeSingleElectron ( se ) ; } } if ( org . getLonePairCount ( ) > 0 ) { Set < ILonePair > remove = new HashSet < ILonePair > ( ) ; for ( ILonePair lp : org . lonePairs ( ) ) { if ( hydrogens . contains ( lp . getAtom ( ) ) ) remove . add ( lp ) ; } for ( ILonePair lp : remove ) { org . removeLonePair ( lp ) ; } } if ( sgroups != null ) { for ( Sgroup sgroup : sgroups ) { if ( sgroup . getValue ( SgroupKey . CtabParentAtomList ) != null ) { Collection < IAtom > pal = sgroup . getValue ( SgroupKey . CtabParentAtomList ) ; pal . removeAll ( hydrogens ) ; } for ( IAtom hydrogen : hydrogens ) sgroup . removeAtom ( hydrogen ) ; for ( IBond bondToHydrogen : bondsToHydrogens ) sgroup . removeBond ( bondToHydrogen ) ; } } return org ; }
Suppress any explicit hydrogens in the provided container. Only hydrogens
that can be represented as a hydrogen count value on the atom are
suppressed. The container is updated and no elements are copied, please
use either {@link #copyAndSuppressedHydrogens} if you would to preserve
the old instance.

@param org the container from which to remove hydrogens
@return the input for convenience
@see #copyAndSuppressedHydrogens