docs: def find_atoms_near_atom(self, source_atom, search_radius, atom_hit_cache = set(), atom_names_to_include = set(), atom_names_to_exclude = set(), restrict_to_CA = False):
          '''It is advisable to set up and use an atom hit cache object. This reduces the number of distance calculations and gives better performance.
             See find_sidechain_atoms_within_radius_of_residue_objects for an example of how to set this up e.g.
                 atom_hit_cache = set()
                 for x in some_loop:
                     this_object.find_atoms_near_atom(source_atom, search_radius, atom_hit_cache = atom_hit_cache)
          '''
          if len(atom_names_to_include) > 0 and len(atom_names_to_exclude) > 0:
              raise Exception('Error: either one of the set of atoms types to include or the set of atom types to exclude can be set but not both.')
  
          atom_names_to_exclude = set(atom_names_to_exclude)
          if atom_names_to_include:
              atom_names_to_exclude = set(self.atom_name_to_group.keys()).difference(atom_names_to_include)
  
          radius = float(search_radius) + self.buffer # add buffer to account for edge cases in searching
          bin_size = self.bin_size
          atom_bins = self.atom_bins
          if source_atom:
              bin_radius = int(math.ceil(radius / bin_size)) # search this many bins in all directions
              xrange = range(max(0, source_atom.bin.x - bin_radius), min(self.atom_bin_dimensions[0], source_atom.bin.x + bin_radius) + 1)
              yrange = range(max(0, source_atom.bin.y - bin_radius), min(self.atom_bin_dimensions[1], source_atom.bin.y + bin_radius) + 1)
              zrange = range(max(0, source_atom.bin.z - bin_radius), min(self.atom_bin_dimensions[2], source_atom.bin.z + bin_radius) + 1)
              for x in xrange:
                  for y in yrange:
                      for z in zrange:
                          for atom in atom_bins[x][y][z]:
                              if atom not in atom_hit_cache:
                                  if restrict_to_CA:
                                      if atom.name == 'CA' and (source_atom - atom <= search_radius):
                                          atom_hit_cache.add(atom)
                                  else:
                                      if (source_atom - atom <= search_radius) and (atom.name not in atom_names_to_exclude):
                                          atom_hit_cache.add(atom)
  
              return atom_hit_cache