Drop complex magnitude matching and use absolute values for k-point moment tests (#5364)

This commit is contained in:
SY Wang 2026-06-07 05:40:05 +08:00 committed by GitHub
parent f229b202dd
commit dccd4e42be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 12 additions and 63 deletions

View file

@ -6,12 +6,12 @@
#
# compute ground state for graphene with PBE and SZV
# compute the dipole moments for kpoints in the &DFT section
"C2_pbe_scf_kp.inp" = [{matcher="Dipole_abs_dx_at_kp_1", tol=1.0E-06, ref=0.5705436}]
"C2_pbe_scf_kp.inp" = [{matcher="Dipole_at_kp_1", tol=1.0E-06, ref=0.544}]
# compute the dipole moments for kpoints provided via &KPOINTS in the &MOMENTS section
"C2_pbe_moment_kp.inp" = [{matcher="Dipole_abs_dx_at_kp_1", tol=1.0E-06, ref=0.3695416}]
"C2_pbe_moment_kp.inp" = [{matcher="Dipole_at_kp_1", tol=1.0E-06, ref=0.344}]
# compute the dipole moments for kpoints provided via &KPOINT_SET in the &MOMENTS section
# and ensure matching of Berry Curvature
"C2_pbe_moment_kpset.inp" = [{matcher="BC_near_K_point", tol=1.0E-01, ref=-7100}]
# compute dipole for open shell system of monolayer CrSBr
"CrSBr_open_shell.inp" = [{matcher="Dipole_abs_dx_for_CrSBr", tol=1.0E-06, ref=0.4214356E-01}]
"CrSBr_open_shell.inp" = [{matcher="Dipole_for_CrSBr", tol=1.0E-06, ref=0.298E-01}]
#EOF

View file

@ -35,12 +35,15 @@ class Matcher(Protocol):
# ======================================================================================
class GenericMatcher(Matcher):
def __init__(self, pattern: str, col: int, regex: bool = False):
def __init__(
self, pattern: str, col: int, regex: bool = False, abs_value: bool = False
):
self.pattern = pattern
self.regex_mode = regex
self.abs_value = abs_value
if not regex:
for c in r"[]()|+*?":
pattern = pattern.replace(c, f"\\{c}") # escape special chars
pattern = pattern.replace(c, f"\\{c}")
self.regex = re.compile(pattern)
self.col = col
@ -64,6 +67,8 @@ class GenericMatcher(Matcher):
# parse result
try:
value = float(value_str.replace("D", "E"))
if self.abs_value:
value = abs(value)
except:
error = f"Could not parse result as float: '{value_str}'.\n"
return MatchResult("WRONG RESULT", error, value=None)
@ -78,54 +83,6 @@ class GenericMatcher(Matcher):
return MatchResult("OK", error=None, value=value) # passed
# ======================================================================================
class ComplexAbsMatcher(Matcher):
def __init__(self, pattern: str, re_col: int, im_col: int, regex: bool = False):
self.pattern = pattern
self.regex_mode = regex
if not regex:
for c in r"[]()|+*?":
pattern = pattern.replace(c, f"\\{c}") # escape special chars
self.regex = re.compile(pattern)
self.re_col = re_col
self.im_col = im_col
def run(self, output: str, **kwargs: Any) -> MatchResult:
tol, ref = kwargs["tol"], kwargs["ref"]
assert isinstance(tol, (float, int))
assert isinstance(ref, (float, int))
for line in reversed(output.split("\n")):
match = self.regex.search(line)
if match:
if self.regex_mode and len(match.groups()) >= 2:
re_str, im_str = match.group(1), match.group(2)
else:
fields = line.split()
re_str = fields[self.re_col - 1]
im_str = fields[self.im_col - 1]
break
else:
error = f"Result not found: '{self.pattern}'.\n"
return MatchResult("WRONG RESULT", error, value=None)
try:
re_val = float(re_str.replace("D", "E"))
im_val = float(im_str.replace("D", "E"))
value = (re_val * re_val + im_val * im_val) ** 0.5
except:
error = f"Could not parse result as complex float: '{re_str} {im_str}'.\n"
return MatchResult("WRONG RESULT", error, value=None)
diff = value - ref
rel_error = abs(diff / ref if ref != 0.0 else diff)
if rel_error > tol:
error = f"Difference too large: {rel_error:.2e} > {tol}, value: {value}.\n"
return MatchResult("WRONG RESULT", error, value)
return MatchResult("OK", error=None, value=value)
# ======================================================================================
class TextPresenceMatcher(Matcher):
def __init__(self, text: str):
@ -410,18 +367,10 @@ registry["M126"] = GenericMatcher(r" # Total charge ", col=5)
registry["M127"] = GenericMatcher(r"Checksum (Acoustic Sum Rule):", col=5)
# Dipole moment calculated at a specific k-point (-0.375,-0.375, 0.00)
registry["Dipole_at_kp_1"] = GenericMatcher(r" 1 1 2", col=4)
# Phase-independent |dx_nm| for the same matrix element.
registry["Dipole_abs_dx_at_kp_1"] = ComplexAbsMatcher(
r" 1 1 2", re_col=4, im_col=5
)
registry["Dipole_at_kp_1"] = GenericMatcher(r" 1 1 2", col=4, abs_value=True)
# Dipole moment calculated at a specific k-point (-0.375,-0.375, 0.00)
# registry["Dipole_for_CrSBr"] = GenericMatcher(r" 1 31 32", col=4)
registry["Dipole_abs_dx_for_CrSBr"] = ComplexAbsMatcher(
r" 1 31 32", re_col=4, im_col=5
)
registry["Dipole_for_CrSBr"] = GenericMatcher(r" 1 31 32", col=4, abs_value=True)
# Berry curvature calculated from dipoles near K point in graphene BZ
registry["BC_near_K_point"] = GenericMatcher(r" 1 4", col=5)