code: def describe_features(self, traj):
          
          feature_descs = []
          # fill in the atom indices using just the first frame
          distances, residue_indices = md.compute_contacts(traj[0],
                                          self.contacts, self.scheme,
                                          ignore_nonprotein=False,
                                          periodic=self.periodic)
          top = traj.topology
  
          aind = []
          resseqs = []
          resnames = []
          for resid_ids in residue_indices:
              aind += ["N/A"]
              resseqs += [[top.residue(ri).resSeq for ri in resid_ids]]
              resnames += [[top.residue(ri).name for ri in resid_ids]]
  
          zippy = itertools.product(["Ligand Contact"], [self.scheme],
                                    ["N/A"],
                                    zip(aind, resseqs, residue_indices, resnames))
  
          feature_descs.extend(dict_maker(zippy))
  
          return feature_descs
docs: Return a list of dictionaries describing the contacts features.
  
          Parameters
          ----------
          traj : mdtraj.Trajectory
              The trajectory to describe
  
          Returns
          -------
          feature_descs : list of dict
              Dictionary describing each feature with the following information
              about the atoms participating in each dihedral
                  - resnames: unique names of residues
                  - atominds: the four atom indicies
                  - resseqs: unique residue sequence ids (not necessarily
                    0-indexed)
                  - resids: unique residue ids (0-indexed)
                  - featurizer: Contact
                  - featuregroup: ca, heavy etc.