docs: def run_atomtyping(self, topology, use_residue_map=True):
          """Atomtype the topology
  
          Parameters
          ----------
          topology : openmm.app.Topology
              Molecular structure to find atom types of
          use_residue_map : boolean, optional, default=True
              Store atomtyped topologies of residues to a dictionary that maps
              them to residue names.  Each topology, including atomtypes, will be
              copied to other residues with the same name. This avoids repeatedly
              calling the subgraph isomorphism on idential residues and should
              result in better performance for systems with many identical
              residues, i.e. a box of water. Note that for this to be applied to
              independent molecules, they must each be saved as different
              residues in the topology.
          """
          if use_residue_map:
              independent_residues = _check_independent_residues(topology)
  
              if independent_residues:
                  residue_map = dict()
  
                  for res in topology.residues():
                      if res.name not in residue_map.keys():
                          residue = _topology_from_residue(res)
                          find_atomtypes(residue, forcefield=self)
                          residue_map[res.name] = residue
  
                  for key, val in residue_map.items():
                      _update_atomtypes(topology, key, val)
  
              else:
                  find_atomtypes(topology, forcefield=self)
  
          else:
              find_atomtypes(topology, forcefield=self)
  
          if not all([a.id for a in topology.atoms()][0]):
              raise ValueError('Not all atoms in topology have atom types')
  
          return topology