def get_complete_results(self, params=None, result_id=None):
        """
        Return available results, analogously to what get_results does, but
        also read the corresponding output files for each result, and
        incorporate them in the result dictionary under the output key, as a
        dictionary of filename: file_contents.

        Args:
          params (dict): parameter specification of the desired parameter
            values, as described in the get_results documentation.

        In other words, results returned by this function will be in the form::

            {
                'params': {
                            'param1': value1,
                            'param2': value2,
                            ...
                            'RngRun': value3
                           },
                'meta': {
                          'elapsed_time': value4,
                          'id': value5
                        }
                'output': {
                            'stdout': stdout_as_string,
                            'stderr': stderr_as_string,
                            'file1': file1_as_string,
                            ...
                          }
            }

        Note that the stdout and stderr entries are always included, even if
        they are empty.
        """

        if result_id is not None:
            results = deepcopy(self.get_results(result_id=result_id))
        else:
            results = deepcopy(self.get_results(params))

        for r in results:
            r['output'] = {}
            available_files = self.get_result_files(r['meta']['id'])
            for name, filepath in available_files.items():
                with open(filepath, 'r') as file_contents:
                    r['output'][name] = file_contents.read()

        return results