Skip to content

Commit 9218be4

Browse files
committed
Measure precision workflow accept ecutwfc/ecutrho as inputs (#214)
* hotfix, report exception in bands * WIP: measure precision workflow accept ecutwfc/ecutrho as inputs * CLI: support error throw and warnings when inputs are not proper
1 parent eb54f2b commit 9218be4

File tree

10 files changed

+200
-156
lines changed

10 files changed

+200
-156
lines changed

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,12 @@ This what we call it residual volume is therefore a stiffness-agnostic value tha
3838
In convergence delta factor calculation, the GS configurations from Cottiner's paper are used.
3939
To have a uniform sence of precision through looking at delta factor, the value is defined as delta factor per atom.
4040
However, since it is hard to define delta per/atom for oxides, ACWF does not use per/atom value to represent results.
41-
To compatible with it, the precision verification also use the structure delta.
41+
It uses the nu factor which was defined in the ACWF paper.
42+
43+
For the oxides, it needs oxygen pseudopotential first, same as nitrides.
44+
The verification needs to run for all know oxygen/nitrigen pseudopotentials filst. However, the cutoffs of them are not known and the cutoffs are input for the precision measure.
45+
So the very first run is the convergence test on all oxygen/nitrigen pseudopotentials.
46+
Once the recommended cutoffs are known, the precision measure can be run for all oxygen/nitrigen elements.
4247

4348
In the convergence verification, there are many options to choose from for what configuration to use. But it is redundant to use all of them, we what the configuration that gives the largest recommended cutoff energy for the pseudopotential.
4449
After tests (show test results, which in `sssp-verify-scripts`), we found that the for non-magnetic elements, the Diamond configuration that gives the largest cutoff energy. For magnetic elements, the GS configuration calculation with magnetization turned on for the bulk (in cohesive energy which usually give the largest recommended cutoff, where the atomic calculation still don't have magnetization turned on and it is not needed because the pseudopotential is generated in the close shell approximiation (??)) that gives the largest cutoff energy.
@@ -190,4 +195,4 @@ MIT
190195

191196
## Contact
192197

193-
📧 email: jusong.yu@epfl.ch
198+
📧 email: jusong.yu@psi.ch

aiida_sssp_workflow/calculations/calculate_bands_distance.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def fun_shift(occ, bands_diff, shift):
171171
def get_bands_distance(
172172
bandsdata_a: dict,
173173
bandsdata_b: dict,
174-
smearing: float,
174+
smearing: float, # from degauss
175175
fermi_shift: float,
176176
do_smearing: bool,
177177
spin: bool,
@@ -189,6 +189,9 @@ def get_bands_distance(
189189
190190
First aligh the number of two bands, e.g tranctrate the overceed nubmer of bands
191191
"""
192+
_RY_TO_EV = 13.6056980659
193+
smearing = smearing * _RY_TO_EV
194+
192195
# post process to deserial list to numpy arrar
193196
for key in ["bands", "kpoints", "weights"]:
194197
bandsdata_a[key] = np.asarray(bandsdata_a[key])

aiida_sssp_workflow/cli/run.py

Lines changed: 74 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import click
1010
from aiida import orm
1111
from aiida.cmdline.params import options, types
12+
from aiida.cmdline.utils import echo
1213
from aiida.engine import run_get_node, submit
1314
from aiida.plugins import DataFactory, WorkflowFactory
1415

@@ -27,12 +28,13 @@
2728

2829

2930
@cmd_root.command("launch")
31+
@click.argument("pseudo", type=click.Path(exists=True))
3032
@options.OverridableOption(
3133
"--pw-code", "pw_code", type=types.CodeParamType(entry_point="quantumespresso.pw")
3234
)(required=True)
3335
@options.OverridableOption(
3436
"--ph-code", "ph_code", type=types.CodeParamType(entry_point="quantumespresso.ph")
35-
)(required=True)
37+
)(required=False)
3638
@click.option(
3739
"--property",
3840
multiple=True,
@@ -42,22 +44,8 @@
4244
@click.option(
4345
"protocol",
4446
"--protocol",
45-
default="standard",
46-
help="Protocol to use for the verification.",
47-
)
48-
@click.option(
49-
"cutoff_control",
50-
"--cutoff-control",
51-
default="standard",
52-
help="Control of convergence.",
53-
)
54-
@click.option(
55-
"criteria", "--criteria", default="efficiency", help="Criteria of convergence."
56-
)
57-
@click.option(
58-
"configuration",
59-
"--configuration",
60-
help="(convergence only) Configuration of structure, can be: SC, FCC, BCC, Diamond, XO, XO2, XO3, X2O, X2O3, X2O5, GS.",
47+
default="acwf",
48+
help="Protocol to use for the verification, (acwf, test).",
6149
)
6250
@click.option("withmpi", "--withmpi", default=True, help="Run with mpi.")
6351
@click.option("npool", "--npool", default=1, help="Number of pool.")
@@ -78,12 +66,39 @@
7866
"--comment",
7967
help="Add a comment word as the prefix the workchain description.",
8068
)
81-
@click.argument("pseudo", type=click.Path(exists=True))
69+
# ecutwfc and ecutrho are for measure workflows only
70+
@click.option(
71+
"ecutwfc",
72+
"--ecutwfc",
73+
help="Cutoff energy for wavefunctions in Rydberg.",
74+
)
75+
@click.option(
76+
"ecutrho",
77+
"--ecutrho",
78+
help="Cutoff energy for charge density in Rydberg.",
79+
)
80+
# cutoff_control, criteria, configuration is for convergence workflows only
81+
@click.option(
82+
"cutoff_control",
83+
"--cutoff-control",
84+
help="Cutoff control for convergence workflow, (standard, quick, opsp).",
85+
)
86+
@click.option(
87+
"criteria", "--criteria", help="Criteria for convergence (efficiency, precision)."
88+
)
89+
# configuration is hard coded for convergence workflow, but here is an interface for experiment purpose
90+
@click.option(
91+
"configuration",
92+
"--configuration",
93+
help="(convergence test only) Configuration of structure, can be: SC, FCC, BCC, Diamond, XO, XO2, XO3, X2O, X2O3, X2O5, GS, RE",
94+
)
8295
def launch(
8396
pw_code,
8497
ph_code,
8598
property,
8699
protocol,
100+
ecutwfc,
101+
ecutrho,
87102
cutoff_control,
88103
criteria,
89104
configuration,
@@ -112,8 +127,41 @@ def launch(
112127
properties_list = list(property)
113128
extra_desc = f"{properties_list}"
114129

130+
# validate the options are all provide for the property
131+
is_convergence = False
132+
is_measure = False
133+
is_ph = False
134+
for prop in properties_list:
135+
if prop.startswith("convergence"):
136+
is_convergence = True
137+
if prop.startswith("measure"):
138+
is_measure = True
139+
if "phonon_frequencies" in prop:
140+
is_ph = True
141+
142+
# raise error if the options are not provided
143+
if is_convergence and not (cutoff_control and criteria):
144+
echo.echo_critical(
145+
"cutoff_control, criteria must be provided for convergence workflow."
146+
)
147+
148+
if is_measure and not (ecutwfc and ecutrho):
149+
echo.echo_critical("ecutwfc and ecutrho must be provided for measure workflow.")
150+
151+
if is_ph and not ph_code:
152+
echo.echo_critical("ph_code must be provided for phonon frequencies.")
153+
154+
# raise warning if the options are over provided, e.g. cutoff_control is provided for measure workflow
155+
if is_measure and (cutoff_control or criteria or configuration):
156+
echo.echo_warning(
157+
"cutoff_control, criteria, configuration are not used for measure workflow."
158+
)
159+
160+
if is_convergence and (ecutwfc or ecutrho):
161+
echo.echo_warning("ecutwfc and ecutrho are not used for convergence workflow.")
162+
115163
_profile = aiida.load_profile()
116-
click.echo(f"Current profile: {_profile.name}")
164+
echo.echo_info(f"Current profile: {_profile.name}")
117165

118166
basename = os.path.basename(pseudo)
119167

@@ -130,15 +178,15 @@ def launch(
130178
inputs = {
131179
"measure": {
132180
"protocol": orm.Str(protocol),
133-
"cutoff_control": orm.Str(cutoff_control),
181+
"wavefunction_cutoff": orm.Float(ecutwfc),
182+
"charge_density_cutoff": orm.Float(ecutrho),
134183
},
135184
"convergence": {
136185
"protocol": orm.Str(protocol),
137186
"cutoff_control": orm.Str(cutoff_control),
138187
"criteria": orm.Str(criteria),
139188
},
140189
"pw_code": pw_code,
141-
"ph_code": ph_code,
142190
"pseudo": pseudo,
143191
"label": label,
144192
"properties_list": orm.List(properties_list),
@@ -156,6 +204,9 @@ def launch(
156204
"clean_workdir": orm.Bool(clean_workdir),
157205
}
158206

207+
if is_ph:
208+
inputs["ph_code"] = ph_code
209+
159210
if configuration is not None:
160211
inputs["convergence"]["configuration"] = orm.Str(configuration)
161212

@@ -167,8 +218,8 @@ def launch(
167218
description = f"{label.value} ({extra_desc})"
168219
node.description = f"({comment}) {description}" if comment else description
169220

170-
click.echo(node)
171-
click.echo(f"calculated on property: {'/'.join(properties_list)}")
221+
echo.echo_info(node)
222+
echo.echo_success(f"calculated on property: {'/'.join(properties_list)}")
172223

173224

174225
if __name__ == "__main__":

aiida_sssp_workflow/protocol/control.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
precheck:
33
description: run on 150 v.s 200 v.s 300 Ry wavefunction cutoff with fix dual to give sense whether 200 Ry enough
44

5-
# max_wfc: 0 # Not used if run precision measurement veri with this protocol, just raise exception.
65
wfc_scan: [150, 200, 300] # at fix dual
76
nc_dual_scan: [] # set empty so rho test not run
87
nonnc_dual_scan: []
@@ -11,7 +10,6 @@ precheck:
1110
standard:
1211
description: high wavefunction cutoff set and cutoffs dense interval therefore time consuming
1312

14-
max_wfc: 200 # The max wfc cut for precision measurement
1513
wfc_scan: [30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 90, 100, 120, 150, 200] # at fix dual
1614
nc_dual_scan: [2.0, 2.5, 3.0, 3.5, 4.0] # at fix wfc
1715
nonnc_dual_scan: [6.0, 6.5, 7.0, 7.5, 8.0]
@@ -20,7 +18,6 @@ standard:
2018
quick:
2119
description: low wavefunction cutoff set and cutoffs sparse interval therefore can run on local
2220

23-
max_wfc: 200 # The max wfc cut for precision measurement
2421
wfc_scan: [30, 40, 50, 60, 75, 100, 150, 200] # at fix dual
2522
nc_dual_scan: [3.0, 3.5, 4.0] # at fix wfc
2623
nonnc_dual_scan: [6.0, 7.0, 8.0]
@@ -29,7 +26,6 @@ quick:
2926
test:
3027
description: test only
3128

32-
max_wfc: 35 # The max wfc cut for precision measurement
3329
wfc_scan: [30, 35] # at fix dual
3430
nc_dual_scan: [] # at fix wfc
3531
nonnc_dual_scan: [] # at fix rho
@@ -38,7 +34,6 @@ test:
3834
opsp:
3935
description: To running opsp verification, make the calculations finished fast.
4036

41-
max_wfc: 40 # The max wfc cut for precision measurement
4237
wfc_scan: [30, 35] # at fix dual
4338
nc_dual_scan: [2.0, 4.0] # at fix wfc
4439
nonnc_dual_scan: [6.0, 8.0]

aiida_sssp_workflow/protocol/converge.yml

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -37,42 +37,42 @@ acwf:
3737
mixing_beta: 0.4
3838

3939

40-
moderate:
41-
name: moderate
42-
description: The protocol where input parameters bring from aiidaqe moderate protocol. Only for QE >= 6.8
43-
44-
base: # base parameters is inherit by other process
45-
occupations: smearing
46-
degauss: 0.01
47-
smearing: cold
48-
conv_thr_per_atom: 1.0e-10
49-
kpoints_distance: 0.15
50-
51-
cohesive_energy:
52-
atom_smearing: gaussian
53-
vacuum_length: 12.0
54-
55-
phonon_frequencies:
56-
qpoints_list:
57-
- [0.5, 0.5, 0.5]
58-
epsilon: false
59-
tr2_ph: 1.0e-16
60-
61-
pressure:
62-
scale_count: 7
63-
scale_increment: 0.02
64-
mixing_beta: 0.4
65-
66-
bands:
67-
init_nbands_factor: 3.0
68-
fermi_shift: 10.0
69-
kpoints_distance_scf: 0.15
70-
kpoints_distance_bands: 0.15
71-
72-
delta:
73-
scale_count: 7
74-
scale_increment: 0.02
75-
mixing_beta: 0.4
40+
#moderate:
41+
# name: moderate
42+
# description: The protocol where input parameters bring from aiidaqe moderate protocol. Only for QE >= 6.8
43+
#
44+
# base: # base parameters is inherit by other process
45+
# occupations: smearing
46+
# degauss: 0.01
47+
# smearing: cold
48+
# conv_thr_per_atom: 1.0e-10
49+
# kpoints_distance: 0.15
50+
#
51+
# cohesive_energy:
52+
# atom_smearing: gaussian
53+
# vacuum_length: 12.0
54+
#
55+
# phonon_frequencies:
56+
# qpoints_list:
57+
# - [0.5, 0.5, 0.5]
58+
# epsilon: false
59+
# tr2_ph: 1.0e-16
60+
#
61+
# pressure:
62+
# scale_count: 7
63+
# scale_increment: 0.02
64+
# mixing_beta: 0.4
65+
#
66+
# bands:
67+
# init_nbands_factor: 3.0
68+
# fermi_shift: 10.0
69+
# kpoints_distance_scf: 0.15
70+
# kpoints_distance_bands: 0.15
71+
#
72+
# delta:
73+
# scale_count: 7
74+
# scale_increment: 0.02
75+
# mixing_beta: 0.4
7676

7777
test:
7878
name: test-only

aiida_sssp_workflow/workflows/convergence/bands.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ class ConvergenceBandsWorkChain(_BaseConvergenceWorkChain):
7474

7575
# pylint: disable=too-many-instance-attributes
7676

77-
_RY_TO_EV = 13.6056980659
78-
7977
_PROPERTY_NAME = "bands"
8078
_EVALUATE_WORKCHAIN = BandsWorkChain
8179
_MEASURE_OUT_PROPERTY = "eta_c"
@@ -186,7 +184,7 @@ def helper_compare_result_extract_fun(self, sample_node, reference_node, **kwarg
186184
sample_band_parameters,
187185
reference_band_structure,
188186
reference_band_parameters,
189-
smearing=orm.Float(self.ctx.degauss * self._RY_TO_EV),
187+
smearing=orm.Float(self.ctx.degauss),
190188
fermi_shift=orm.Float(self.ctx.fermi_shift),
191189
do_smearing=orm.Bool(True),
192190
spin=orm.Bool(spin),

aiida_sssp_workflow/workflows/measure/__init__.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,17 @@
99

1010
UpfData = DataFactory("pseudo.upf")
1111

12-
1312
class _BaseMeasureWorkChain(SelfCleanWorkChain):
13+
"""Base Measure Workchain since bands measure and precision measure share same input ports
14+
"""
15+
# ECUT for oxygen, remember to update this if the oxygen pseudo is changed
16+
_O_ECUTWFC = 75.0
17+
_O_ECUTRHO = 600.0
18+
19+
# ECUT for nitrogen, remember to update this if the nitrogen pseudo is changed
20+
_N_ECUTWFC = 80.0
21+
_N_ECUTRHO = 320.0
22+
1423
@classmethod
1524
def define(cls, spec):
1625
"""Define the process specification."""
@@ -22,9 +31,24 @@ def define(cls, spec):
2231
help='Pseudopotential to be verified')
2332
spec.input('protocol', valid_type=orm.Str, required=True,
2433
help='The protocol which define input calculation parameters.')
25-
spec.input('cutoff_control', valid_type=orm.Str, default=lambda: orm.Str('standard'),
26-
help='The control protocol where define max_wfc.')
34+
spec.input('wavefunction_cutoff', valid_type=orm.Float, required=True, help='The wavefunction cutoff.')
35+
spec.input('charge_density_cutoff', valid_type=orm.Float, required=True, help='The charge density cutoff.')
2736
spec.input('options', valid_type=orm.Dict, required=True,
2837
help='Optional `options` to use for the `PwCalculations`.')
2938
spec.input('parallelization', valid_type=orm.Dict, required=True,
3039
help='Parallelization options for the `PwCalculations`.')
40+
41+
def _get_pw_cutoff(self, structure: orm.StructureData, ecutwfc: float, ecutrho: float):
42+
"""Get cutoff pair, if strcture contains oxygen or nitrogen, need
43+
to use the max between pseudo cutoff and the O/N cutoff.
44+
"""
45+
elements = set(structure.get_symbols_set())
46+
if "O" in elements:
47+
ecutwfc = max(ecutwfc, self._O_ECUTWFC)
48+
ecutrho = max(ecutrho, self._O_ECUTRHO)
49+
50+
if "N" in elements:
51+
ecutwfc = max(ecutwfc, self._N_ECUTWFC)
52+
ecutrho = max(ecutrho, self._N_ECUTRHO)
53+
54+
return ecutwfc, ecutrho

0 commit comments

Comments
 (0)