Skip to content

Commit

Permalink
Use annotations from future for cleaner type hint. Moved qe_time_to_s…
Browse files Browse the repository at this point in the history
…ec to utils. Renamed BaseStdoutParser.parse_stdout_base to parse for compatibility with parent abstract class.
  • Loading branch information
gbrunin committed Nov 22, 2024
1 parent c31f570 commit 90b3608
Show file tree
Hide file tree
Showing 11 changed files with 58 additions and 45 deletions.
2 changes: 2 additions & 0 deletions src/qe_tools/converters/ase.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-

from __future__ import annotations

from importlib.util import find_spec

import numpy as np
Expand Down
2 changes: 2 additions & 0 deletions src/qe_tools/converters/pymatgen.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import annotations

from importlib.util import find_spec

_has_pmg = bool(find_spec('pymatgen'))
Expand Down
32 changes: 1 addition & 31 deletions src/qe_tools/converters/qe.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,4 @@
# -*- coding: utf-8 -*-
"""Tools for converting Quantum ESPRESSO outputs to Python data types."""


def convert_qe_time_to_sec(timestr):
"""Given the walltime string of Quantum Espresso, converts it in a number of seconds (float)."""
rest = timestr.strip()

if 'd' in rest:
days, rest = rest.split('d')
else:
days = '0'

if 'h' in rest:
hours, rest = rest.split('h')
else:
hours = '0'

if 'm' in rest:
minutes, rest = rest.split('m')
else:
minutes = '0'

if 's' in rest:
seconds, rest = rest.split('s')
else:
seconds = '0.'

if rest.strip():
raise ValueError(f"Something remained at the end of the string '{timestr}': '{rest}'")

num_seconds = float(seconds) + float(minutes) * 60.0 + float(hours) * 3600.0 + float(days) * 86400.0

return num_seconds
from __future__ import annotations
2 changes: 2 additions & 0 deletions src/qe_tools/inputs/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
Tools for parsing QE PW input files.
"""

from __future__ import annotations

import re
from typing import Dict, Iterable, List, Optional

Expand Down
2 changes: 2 additions & 0 deletions src/qe_tools/inputs/cp.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-

from __future__ import annotations

from qe_tools.inputs.base import BaseInputFile

__all__ = ('CpInputFile',)
Expand Down
2 changes: 2 additions & 0 deletions src/qe_tools/inputs/pw.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
Tools for parsing QE PW input files
"""

from __future__ import annotations

import re

from qe_tools.exceptions import ParsingError
Expand Down
5 changes: 3 additions & 2 deletions src/qe_tools/outputs/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
"""Base parser for the outputs of Quantum ESPRESSO."""

from typing import Union
from __future__ import annotations

import abc


Expand All @@ -10,7 +11,7 @@ class BaseOutput(abc.ABC):
Abstract class for the outputs of Quantum ESPRESSO.
"""

def __init__(self, outputs: Union[dict, None] = None, executable: Union[str, None] = None):
def __init__(self, outputs: dict | None = None, executable: str | None = None):
self.outputs = outputs
self.executable = executable

Expand Down
13 changes: 7 additions & 6 deletions src/qe_tools/outputs/parsers/base.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# -*- coding: utf-8 -*-
"""Base parser for the outputs of Quantum ESPRESSO."""

from __future__ import annotations

import abc
import re
from qe_tools.converters.qe import convert_qe_time_to_sec
from qe_tools.utils import convert_qe_time_to_sec


class BaseOutputFileParser(abc.ABC):
Expand All @@ -19,7 +21,7 @@ def __init__(self, string: str):
self.dict_out: dict = {}

@abc.abstractmethod
def parse(self, *args, **kwargs):
def parse(self):
"""
Parse the output of Quantum ESPRESSO.
This should be implemented for XML and standard output,
Expand All @@ -43,25 +45,24 @@ def from_file(cls, filename: str):
class BaseStdoutParser(BaseOutputFileParser):
"""Abstract class for the parsing of stdout files of Quantum ESPRESSO."""

def parse_stdout_base(self, stdout: str) -> None:
def parse(self):
"""Parse the ``stdout`` content of a Quantum ESPRESSO calculation.
This function only checks for basic content like the code name and version,
as well as the wall time of the calculation.
:param stdout: the stdout content as a string.
:returns: dictionary of the parsed data.
"""
parsed_data = {}

code_match = re.search(
r'Program\s(?P<code_name>[A-Z|a-z|\_|\d]+)\sv\.(?P<code_version>[\d\.|a-z|A-Z]+)\s', stdout
r'Program\s(?P<code_name>[A-Z|a-z|\_|\d]+)\sv\.(?P<code_version>[\d\.|a-z|A-Z]+)\s', self.string
)
if code_match:
code_name = code_match.groupdict()['code_name']
parsed_data['code_version'] = code_match.groupdict()['code_version']

wall_match = re.search(rf'{code_name}\s+:[\s\S]+CPU\s+(?P<wall_time>[\s.\d|s|m|d|h]+)\sWALL', stdout)
wall_match = re.search(rf'{code_name}\s+:[\s\S]+CPU\s+(?P<wall_time>[\s.\d|s|m|d|h]+)\sWALL', self.string)

if wall_match:
parsed_data['wall_time_seconds'] = convert_qe_time_to_sec(wall_match.groupdict()['wall_time'])
Expand Down
5 changes: 2 additions & 3 deletions src/qe_tools/outputs/parsers/pw.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import annotations

from importlib.resources import files
from xml.etree import ElementTree

Expand Down Expand Up @@ -60,6 +62,3 @@ class PwStdoutParser(BaseStdoutParser):

def __init__(self, string: str):
super().__init__(string=string)

def parse(self):
self.parse_stdout_base(self.string)
6 changes: 3 additions & 3 deletions src/qe_tools/outputs/pw.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""Output of the Quantum ESPRESSO pw.x code."""

from typing import Union
from __future__ import annotations

from pathlib import Path

Expand All @@ -12,11 +12,11 @@
class PwOutput(BaseOutput):
"""Output of the Quantum ESPRESSO pw.x code."""

def __init__(self, outputs: Union[dict, None] = None):
def __init__(self, outputs: dict | None = None):
super().__init__(outputs=outputs, executable='pw.x')

@classmethod
def from_dir(cls, directory: Union[str, Path], filetype: str = 'both'):
def from_dir(cls, directory: str | Path, filetype: str = 'both'):
"""
From a directory, locates the standard output and XML files and
parses them.
Expand Down
32 changes: 32 additions & 0 deletions src/qe_tools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,35 @@ def parse_version(
if qe_version is None:
return _LATEST_VERSION
return Version(qe_version)


def convert_qe_time_to_sec(timestr):
"""Given the walltime string of Quantum Espresso, converts it in a number of seconds (float)."""
rest = timestr.strip()

if 'd' in rest:
days, rest = rest.split('d')
else:
days = '0'

if 'h' in rest:
hours, rest = rest.split('h')
else:
hours = '0'

if 'm' in rest:
minutes, rest = rest.split('m')
else:
minutes = '0'

if 's' in rest:
seconds, rest = rest.split('s')
else:
seconds = '0.'

if rest.strip():
raise ValueError(f"Something remained at the end of the string '{timestr}': '{rest}'")

num_seconds = float(seconds) + float(minutes) * 60.0 + float(hours) * 3600.0 + float(days) * 86400.0

return num_seconds

0 comments on commit 90b3608

Please sign in to comment.