docs: def apply(self, topology, references_file=None, use_residue_map=True,
                assert_bond_params=True, assert_angle_params=True,
                assert_dihedral_params=True, assert_improper_params=False,
                *args, **kwargs):
          """Apply the force field to a molecular structure
  
          Parameters
          ----------
          topology : openmm.app.Topology or parmed.Structure or mbuild.Compound
              Molecular structure to apply the force field to
          references_file : str, optional, default=None
              Name of file where force field references will be written (in Bibtex
              format)
          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.
          assert_bond_params : bool, optional, default=True
              If True, Foyer will exit if parameters are not found for all system
              bonds.
          assert_angle_params : bool, optional, default=True
              If True, Foyer will exit if parameters are not found for all system
              angles.
          assert_dihedral_params : bool, optional, default=True
              If True, Foyer will exit if parameters are not found for all system
              proper dihedrals.
          assert_improper_params : bool, optional, default=False
              If True, Foyer will exit if parameters are not found for all system
              improper dihedrals.
          """
          if self.atomTypeDefinitions == {}:
              raise FoyerError('Attempting to atom-type using a force field '
                      'with no atom type defitions.')
  
          if not isinstance(topology, app.Topology):
              residues = kwargs.get('residues')
              topology, positions = generate_topology(topology,
                      self.non_element_types, residues=residues)
          else:
              positions = np.empty(shape=(topology.getNumAtoms(), 3))
              positions[:] = np.nan
          box_vectors = topology.getPeriodicBoxVectors()
          topology = self.run_atomtyping(topology, use_residue_map=use_residue_map)
          system = self.createSystem(topology, *args, **kwargs)
  
          structure = pmd.openmm.load_topology(topology=topology, system=system)
  
          '''
          Check that all topology objects (angles, dihedrals, and impropers)
          have parameters assigned. OpenMM will generate an error if bond parameters
          are not assigned.
          '''
          data = self._SystemData
  
          if data.bonds:
              missing = [b for b in structure.bonds
                         if b.type is None]
              if missing:
                  nmissing = len(structure.bonds) - len(missing)
                  msg = ("Parameters have not been assigned to all bonds. "
                         "Total system bonds: {}, Parametrized bonds: {}"
                         "".format(len(structure.bonds), nmissing))
                  _error_or_warn(assert_bond_params, msg)
  
          if data.angles and (len(data.angles) != len(structure.angles)):
              msg = ("Parameters have not been assigned to all angles. Total "
                     "system angles: {}, Parameterized angles: {}"
                     "".format(len(data.angles), len(structure.angles)))
              _error_or_warn(assert_angle_params, msg)
  
          proper_dihedrals = [dihedral for dihedral in structure.dihedrals
                              if not dihedral.improper]
          if data.propers and len(data.propers) != \
                  len(proper_dihedrals) + len(structure.rb_torsions):
              msg = ("Parameters have not been assigned to all proper dihedrals. "
                     "Total system dihedrals: {}, Parameterized dihedrals: {}. "
                     "Note that if your system contains torsions of Ryckaert-"
                     "Bellemans functional form, all of these torsions are "
                     "processed as propers.".format(len(data.propers),
                     len(proper_dihedrals) + len(structure.rb_torsions)))
              _error_or_warn(assert_dihedral_params, msg)
  
          improper_dihedrals = [dihedral for dihedral in structure.dihedrals
                                if dihedral.improper]
          if data.impropers and len(data.impropers) != \
                  len(improper_dihedrals) + len(structure.impropers):
              msg = ("Parameters have not been assigned to all impropers. Total "
                     "system impropers: {}, Parameterized impropers: {}. "
                     "Note that if your system contains torsions of Ryckaert-"
                     "Bellemans functional form, all of these torsions are "
                     "processed as propers".format(len(data.impropers),
                     len(improper_dihedrals) + len(structure.impropers)))
              _error_or_warn(assert_improper_params, msg)
  
          structure.bonds.sort(key=lambda x: x.atom1.idx)
          structure.positions = positions
          if box_vectors is not None:
              structure.box_vectors = box_vectors
          if references_file:
              atom_types = set(atom.type for atom in structure.atoms)
              self._write_references_to_file(atom_types, references_file)
  
          return structure