Skip to content

Commit 85514a0

Browse files
committed
docs: define PWmat first-principles arguments
Coding-Agent: Codex Codex-Version: codex-cli 0.149.0 Model: gpt-5.6-sol Reasoning-Effort: xhigh
1 parent d5ce577 commit 85514a0

2 files changed

Lines changed: 204 additions & 1 deletion

File tree

dpgen/generator/arginfo.py

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,134 @@ def fp_style_custom_args() -> list[Argument]:
987987
]
988988

989989

990+
def fp_style_pwmat_args() -> list[Argument]:
991+
"""Return first-principles arguments for PWmat labeling."""
992+
required_generated_keys = {
993+
"node1",
994+
"node2",
995+
"in.atom",
996+
"ecut",
997+
"e_error",
998+
"rho_error",
999+
"kspacing",
1000+
"flag_symm",
1001+
}
1002+
1003+
def has_required_generated_keys(params):
1004+
return required_generated_keys.issubset(params)
1005+
1006+
generated_args = [
1007+
Argument("node1", int, optional=False, doc="First PWmat node-grid size."),
1008+
Argument("node2", int, optional=False, doc="Second PWmat node-grid size."),
1009+
Argument(
1010+
"in.atom",
1011+
str,
1012+
optional=False,
1013+
doc="Atom-configuration filename written to the PWmat input.",
1014+
),
1015+
Argument(
1016+
"ecut",
1017+
[int, float],
1018+
optional=False,
1019+
doc="Plane-wave energy cutoff.",
1020+
),
1021+
Argument(
1022+
"e_error",
1023+
[int, float],
1024+
optional=False,
1025+
doc="Electronic-energy convergence threshold.",
1026+
),
1027+
Argument(
1028+
"rho_error",
1029+
[int, float],
1030+
optional=False,
1031+
doc="Charge-density convergence threshold.",
1032+
),
1033+
Argument(
1034+
"kspacing",
1035+
[int, float],
1036+
optional=False,
1037+
doc="Reciprocal-space spacing used to generate MP_N123.",
1038+
),
1039+
Argument(
1040+
"flag_symm",
1041+
[int, str],
1042+
optional=False,
1043+
doc="PWmat symmetry flag: 0, 1, 2, 3, or 'NONE'.",
1044+
),
1045+
Argument(
1046+
"icmix",
1047+
[int, float],
1048+
optional=True,
1049+
doc="SCF mixing parameter used to build scf_iter0_2.",
1050+
),
1051+
Argument(
1052+
"smearing",
1053+
int,
1054+
optional=True,
1055+
doc="PWmat smearing method written to SCF iteration settings.",
1056+
),
1057+
Argument(
1058+
"sigma",
1059+
[int, float],
1060+
optional=True,
1061+
doc="Smearing width written to SCF iteration settings.",
1062+
),
1063+
Argument(
1064+
"user_pwmat_params",
1065+
dict,
1066+
optional=True,
1067+
doc="Arbitrary PWmat keys overriding the generated input dictionary.",
1068+
),
1069+
]
1070+
1071+
return [
1072+
Argument(
1073+
"fp_pp_path",
1074+
str,
1075+
optional=False,
1076+
doc="Directory containing PWmat pseudopotential files.",
1077+
),
1078+
Argument(
1079+
"fp_pp_files",
1080+
list[str],
1081+
optional=False,
1082+
doc="Pseudopotential filenames ordered consistently with type_map.",
1083+
),
1084+
Argument(
1085+
"fp_incar",
1086+
str,
1087+
optional=True,
1088+
doc="Existing etot.input template; this takes highest priority.",
1089+
),
1090+
Argument(
1091+
"user_fp_params",
1092+
dict,
1093+
optional=True,
1094+
extra_check=has_required_generated_keys,
1095+
extra_check_errmsg=(
1096+
"user_fp_params must define node1, node2, in.atom, ecut, "
1097+
"e_error, rho_error, kspacing, and flag_symm"
1098+
),
1099+
doc=(
1100+
"Compatibility input mapping. The current generator consumes "
1101+
"node1, node2, in.atom, ecut, e_error, rho_error, kspacing, and "
1102+
"flag_symm, regenerates etot.input, and ignores other keys."
1103+
),
1104+
),
1105+
Argument(
1106+
"fp_params",
1107+
dict,
1108+
optional=True,
1109+
sub_fields=generated_args,
1110+
doc=(
1111+
"Parameters used by make_pwmat_input_user_dict when neither "
1112+
"fp_incar nor user_fp_params is supplied."
1113+
),
1114+
),
1115+
]
1116+
1117+
9901118
def fp_style_variant_type_args() -> Variant:
9911119
doc_fp_style = "Software for First Principles."
9921120
doc_amber_diff = (
@@ -1001,6 +1129,10 @@ def fp_style_variant_type_args() -> Variant:
10011129
"The command argument in the machine file should be the script to run custom FP codes. "
10021130
"The extra forward and backward files can be defined in the machine file."
10031131
)
1132+
doc_pwmat = (
1133+
"PWmat density-functional labeling. The machine command should invoke "
1134+
"the site-specific PWmat executable."
1135+
)
10041136

10051137
return Variant(
10061138
"fp_style",
@@ -1013,7 +1145,7 @@ def fp_style_variant_type_args() -> Variant:
10131145
Argument(
10141146
"amber/diff", dict, fp_style_amber_diff_args(), doc=doc_amber_diff
10151147
),
1016-
Argument("pwmat", dict, [], doc="TODO: add doc"),
1148+
Argument("pwmat", dict, fp_style_pwmat_args(), doc=doc_pwmat),
10171149
Argument("pwscf", dict, fp_style_pwscf_args()),
10181150
Argument("cpx", dict, fp_style_cpx_args()),
10191151
Argument("custom", dict, fp_style_custom_args(), doc=doc_custom),

tests/test_pwmat_arginfo.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""Validate PWmat first-principles parameter documentation."""
2+
3+
import unittest
4+
5+
from dargs import Argument
6+
7+
from dpgen.generator.arginfo import fp_style_variant_type_args
8+
9+
10+
class TestPWmatArginfo(unittest.TestCase):
11+
def setUp(self):
12+
self.arginfo = Argument("fp", dict, sub_variants=[fp_style_variant_type_args()])
13+
self.pseudopotentials = {
14+
"fp_style": "pwmat",
15+
"fp_pp_path": ".",
16+
"fp_pp_files": ["C.UPF", "H.UPF"],
17+
}
18+
19+
def check(self, data):
20+
normalized = self.arginfo.normalize_value(data)
21+
self.arginfo.check_value(normalized, strict=True)
22+
23+
def test_existing_input_file(self):
24+
self.check({**self.pseudopotentials, "fp_incar": "etot.input"})
25+
26+
def test_generated_fp_params(self):
27+
self.check(
28+
{
29+
**self.pseudopotentials,
30+
"fp_params": {
31+
"node1": 4,
32+
"node2": 1,
33+
"in.atom": "atom.config",
34+
"ecut": 50,
35+
"e_error": 1e-4,
36+
"rho_error": 1e-4,
37+
"kspacing": 0.1,
38+
"flag_symm": "NONE",
39+
"icmix": 1.0,
40+
"smearing": 2,
41+
"sigma": 0.025,
42+
"user_pwmat_params": {"job": "SCF", "out.wg": False},
43+
},
44+
}
45+
)
46+
47+
def test_compatibility_user_fp_params(self):
48+
self.check(
49+
{
50+
**self.pseudopotentials,
51+
"user_fp_params": {
52+
"node1": 4,
53+
"node2": 1,
54+
"job": "SCF",
55+
"in.atom": "atom.config",
56+
"in.psp1": "C.UPF",
57+
"in.psp2": "H.UPF",
58+
"ecut": 50,
59+
"flag_symm": 2,
60+
"e_error": 1e-4,
61+
"rho_error": 1e-4,
62+
"scf_iter0_1": "6 4 3 0.0000 0.025 2",
63+
"xcfunctional": "PBE",
64+
"kspacing": 0.1,
65+
},
66+
}
67+
)
68+
69+
70+
if __name__ == "__main__":
71+
unittest.main()

0 commit comments

Comments
 (0)