<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def project_parensemble(self,par_file=None,nsing=None, inplace=True,enforce_bounds='reset'):
 """ perform the null-space projection operations for null-space monte carlo Parameters par_file: str an optional file of parameter values to use nsing: int number of singular values to in forming null subspace matrix inplace: bool overwrite the existing parameter ensemble with the projected values enforce_bounds: str how to enforce parameter bounds. can be None, 'reset', or 'drop'. Default is None Returns ------- par_en : pyemu.ParameterEnsemble if inplace is False, otherwise None Note ---- to use this method, the MonteCarlo instance must have been constructed with the ``jco`` argument. Example ------- """

        assert self.jco is not None,"MonteCarlo.project_parensemble()" +\
                                    "requires a jacobian attribute"
        if par_file is not None:
            assert os.path.exists(par_file),"monte_carlo.draw() error: par_file not found:" +\
                par_file
            self.parensemble.pst.parrep(par_file)

        # project the ensemble
        self.log("projecting parameter ensemble")
        en = self.parensemble.project(self.get_null_proj(nsing),inplace=inplace,log=self.log)
        self.log("projecting parameter ensemble")
        return en