Source code for aiida_lammps.parsers.parse_raw.lammps_output

"""Set of functions to parse the unformatted output file from LAMMPS"""

# pylint: disable=fixme
import ast
import re
from typing import Optional, Union

import numpy as np


[docs] def parse_outputfile( filename: Optional[str] = None, file_contents: Optional[str] = None ) -> Union[dict, dict]: """ Parse the lammps output file file, this is the redirected screen output. This will gather the time dependent data stored in the output file and stores it as a dictionary. It will also gather single quantities and stores them into a different dictionary. :param filename: name of the lammps output file, defaults to None :type filename: str, optional :param file_contents: contents of the lammps output file, defaults to None :type file_contents: str, optional :return: dictionary with the time dependent data, dictionary with the global data :rtype: dict """ # pylint: disable=too-many-branches, too-many-locals if filename is None and file_contents is None: return None if filename is not None: try: with open(filename) as handler: data = handler.read() data = data.split("\n") except OSError: return None if file_contents is not None: data = file_contents.split("\n") header_line_position = -1 header_line = "" _data = [] end_found = False parsed_data = {} global_parsed_data = {"warnings": [], "errors": []} perf_regex = re.compile(r".*Performance\:.*\,\s+([0-9\.]*)\stimesteps\/s.*") performance_match = perf_regex.search(file_contents or "") if performance_match: global_parsed_data["steps_per_second"] = float(performance_match.group(1)) for index, line in enumerate(data): line = line.strip() if "ERROR" in line: _line = {"message": line} if "Last command" in data[index + 1].strip(): _line["command"] = data[index + 1].strip() global_parsed_data["errors"].append(_line) if "WARNING" in line: global_parsed_data["warnings"].append(line) if "binsize" in line: global_parsed_data["binsize"] = ast.literal_eval( line.split()[2].replace(",", "") ) global_parsed_data["bins"] = [ ast.literal_eval(entry) for entry in line.split()[5:] ] if "ghost atom cutoff" in line: global_parsed_data["ghost_atom_cutoff"] = ast.literal_eval(line.split()[-1]) if "master list distance cutoff" in line: global_parsed_data["master_list_distance_cutoff"] = ast.literal_eval( line.split()[-1] ) if "max neighbors/atom" in line: global_parsed_data["max_neighbors_atom"] = ast.literal_eval( line.split()[2].replace(",", "") ) if "Unit style" in line: global_parsed_data["units_style"] = line.split(":")[-1].strip() if line.startswith("units"): global_parsed_data["units_style"] = line.split("units")[-1].strip() if "Total wall time:" in line: global_parsed_data["total_wall_time"] = line.split()[-1] if "bin:" in line: global_parsed_data["bin"] = line.split()[-1] if "Minimization stats" in line: global_parsed_data["minimization"] = {} if "Stopping criterion" in line: global_parsed_data["minimization"]["stop_criterion"] = ( line.strip().split("=")[-1].strip() ) if "Energy initial, next-to-last, final" in line: global_parsed_data["minimization"]["energy_relative_difference"] = ( _calculate_energy_tolerance(data[index + 1]) ) if "Force two-norm initial, final" in line: global_parsed_data["minimization"]["force_two_norm"] = float( line.strip().split("=")[-1].split()[-1].strip() ) if line.startswith("Step"): _data = [] end_found = False header_line_position = index header_line = [ re.sub("[^a-zA-Z0-9_]", "__", entry) for entry in line.split() ] if ( header_line_position > 0 and index != header_line_position and not end_found and not line.split()[0].replace(".", "", 1).isdigit() ): end_found = True if header_line_position > 0 and index != header_line_position and not end_found: _data.append([ast.literal_eval(entry) for entry in line.split()]) _data = np.asarray(_data) for index, entry in enumerate(header_line): parsed_data[entry] = _data[:, index].tolist() return {"time_dependent": parsed_data, "global": global_parsed_data}
def _calculate_energy_tolerance(line: str) -> float: """Determine the energy tolerance found in the minimization step""" energy = [float(entry) for entry in line.split()] return (energy[-1] - energy[-2]) / energy[-1]