Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
436 changes: 129 additions & 307 deletions src/aiida_epw/parsers/epw.py

Large diffs are not rendered by default.

105 changes: 105 additions & 0 deletions src/aiida_epw/parsers/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"""Regular expression schemas and parsers for EPW stdout files."""

import re


def parse_fortran_float(value: str) -> float:
"""Parse a Fortran-style double float (e.g. 1.23D-04) into a Python float."""
value = value.replace("D", "E").replace("d", "E")
value = re.sub(r"([0-9\.]+)([\+\-]\d+)$", r"\1E\2", value)
return float(value)


def parse_space_separated_ints(value: str) -> list[int]:
"""Parse a space-separated string of integers into a list."""
return [int(x) for x in value.split()]


_PATTERNS_LEGACY = [
("Allen_Dynes_Tc", float, r"\s+Estimated Allen-Dynes Tc =\s+([\d\.]+) K"),
("fermi_energy_coarse", float, r"\s+Fermi energy coarse grid =\s+([\d\.-]+)\seV"),
]

_PATTERNS_MODERN = [
("nbndsub", int, r"nbndsub\s*=\s*(\d+)"),
(
"ws_vectors_electrons",
int,
r"^\s*Number of WS vectors for electrons\s+(\d+)",
),
("ws_vectors_phonons", int, r"^\s*Number of WS vectors for phonons\s+(\d+)"),
(
"ws_vectors_electron_phonon",
int,
r"^\s*Number of WS vectors for electron-phonon\s+(\d+)",
),
(
"max_cores_parallelization",
int,
r"^\s*Maximum number of cores for efficient parallelization\s+(\d+)",
),
("ibndmin", int, r"ibndmin\s*=\s*(\d+)"),
("ebndmin", float, r"ebndmin\s*=\s*([+-]?[\d\.]+)"),
("ibndmax", int, r"ibndmax\s*=\s*(\d+)"),
("ebndmax", float, r"ebndmax\s*=\s*([+-]?[\d\.]+)"),
("nbnd_skip", int, r"^\s*Skipping\s+(\d+)\s+occupied bands:"),
(
"fermi_energy_coarse",
float,
r"^\s*Fermi energy coarse grid =\s*([+-]?[\d\.]+)\s+eV",
),
(
"fermi_energy_fine",
float,
r"^\s*Fermi energy is calculated from the fine k-mesh: Ef =\s*([+-]?[\d\.]+)\s+eV",
),
(
"fine_q_mesh",
parse_space_separated_ints,
r"^\s*Using uniform q-mesh:\s+((?:\d+\s*)+)",
),
(
"fine_k_mesh",
parse_space_separated_ints,
r"^\s*Using uniform k-mesh:\s+((?:\d+\s*)+)",
),
("fermi_level", parse_fortran_float, r"Fermi level \(eV\)\s*=\s*([\d\.D+-]+)"),
("DOS", parse_fortran_float, r"DOS\(states/spin/eV/Unit Cell\)\s*=\s*([\d\.D+-]+)"),
(
"electron_smearing",
parse_fortran_float,
r"Electron smearing \(eV\)\s*=\s*([\d\.D+-]+)",
),
("fermi_window", parse_fortran_float, r"Fermi window \(eV\)\s*=\s*([\d\.D+-]+)"),
("lambda", float, r"Electron-phonon coupling strength\s*=\s*([\d\.]+)"),
(
"McMillan_Tc",
float,
r"Estimated Tc using McMillan expression\s*=\s*([\d\.]+) K for muc",
),
(
"Allen_Dynes_Tc",
float,
r"Estimated Tc using Allen-Dynes modified McMillan expression\s*=\s*([\d\.]+) K",
),
(
"SISSO_Tc",
float,
r"Estimated Tc using SISSO machine learning model\s*=\s*([\d\.]+) K",
),
("muc", float, r"for muc\s*=\s*([\d\.]+)"),
("w_log", float, r"Estimated w_log\s*=\s*([\d\.]+) meV"),
(
"BCS_gap",
float,
r"Estimated BCS superconducting gap using McMillan Tc\s*=\s*([\d\.]+) meV",
),
]

# Precompile all regular expressions for maximum performance
REGEX_PATTERNS_LEGACY = [
(key, type_func, re.compile(pat)) for key, type_func, pat in _PATTERNS_LEGACY
]
REGEX_PATTERNS_MODERN = [
(key, type_func, re.compile(pat)) for key, type_func, pat in _PATTERNS_MODERN
]
92 changes: 92 additions & 0 deletions src/aiida_epw/tools/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,95 @@ def _is_numeric_table_row(line):
return False

return True


def parse_transport_matrices(block):
"""Parse transport tensor matrices from a text block."""
parsed = {}

def extract_matrix_pair(header_pattern, text):
start_match = re.search(header_pattern, text)
if not start_match:
return None, None

lines_start = start_match.end()
lines = text[lines_start:].strip().split("\n")
# Take up to 3 lines
lines = lines[:3]

m1 = []
m2 = []
try:
for line in lines:
# Format " val1 val2 val3 | val4 val5 val6 " (approx)
parts = line.split("|")
if len(parts) < 2:
continue

# Handle Fortran D notation
row1 = [
float(x.replace("D", "E").replace("d", "e"))
for x in parts[0].split()
]
row2 = [
float(x.replace("D", "E").replace("d", "e"))
for x in parts[1].split()
]

if len(row1) == 3 and len(row2) == 3:
m1.append(row1)
m2.append(row2)
except ValueError:
pass

if len(m1) == 3 and len(m2) == 3:
return m1, m2
return None, None

def extract_single_matrix(header_pattern, text):
start_match = re.search(header_pattern, text)
if not start_match:
return None

lines_start = start_match.end()
lines = text[lines_start:].strip().split("\n")[:3]
m = []
try:
for line in lines:
# Just one set of 3 values
row = [
float(x.replace("D", "E").replace("d", "e")) for x in line.split()
]
if len(row) == 3:
m.append(row)
except ValueError:
pass

if len(m) == 3:
return m
return None

# 1. Conductivity
cond, cond_B = extract_matrix_pair(
r"Conductivity tensor without magnetic field\s*\|\s*with magnetic field \[Siemens/m\]",
block,
)
if cond:
parsed["conductivity"] = cond
parsed["conductivity_with_B"] = cond_B

# 2. Mobility
mob, hall_mob = extract_matrix_pair(
r"Mobility tensor without magnetic field\s*\|\s*(?:Hall mobility|with magnetic field) \[cm\^2/Vs\]",
block,
)
if mob:
parsed["mobility"] = mob
parsed["hall_mobility"] = hall_mob

# 3. Hall Factor
hall_fac = extract_single_matrix(r"Hall factor", block)
if hall_fac:
parsed["hall_factor"] = hall_fac

return parsed
Loading
Loading