Take a list of marked "interesting" atoms (heteroatoms, special carbons)
        and attempt to connect them, returning a list of disjoint groups of
        special atoms (and their connected hydrogens).

        :param atoms: set of marked "interesting" atoms, presumably identified
            using other functions in this class.
        :return: list of sets of ints, representing groups of connected atoms

def link_marked_atoms(self, atoms):
        """
        Take a list of marked "interesting" atoms (heteroatoms, special carbons)
        and attempt to connect them, returning a list of disjoint groups of
        special atoms (and their connected hydrogens).

        :param atoms: set of marked "interesting" atoms, presumably identified
            using other functions in this class.
        :return: list of sets of ints, representing groups of connected atoms
        """

        # We will add hydrogens to functional groups
        hydrogens = {n for n in self.molgraph.graph.nodes if
                     str(self.species[n]) == "H"}

        # Graph representation of only marked atoms
        subgraph = self.molgraph.graph.subgraph(list(atoms)).to_undirected()

        func_grps_no_h = [x for x in nx.connected_components(subgraph)]

        func_grps = []
        for func_grp in func_grps_no_h:
            grp_hs = set()
            for node in func_grp:
                neighbors = self.molgraph.graph[node]
                for neighbor in neighbors.keys():
                    # Add all associated hydrogens into the functional group
                    if neighbor in hydrogens:
                        grp_hs.add(neighbor)
            func_grp = func_grp.union(grp_hs)

            func_grps.append(func_grp)

        return func_grps