Skip to content

Commit

Permalink
Full verification workchain
Browse files Browse the repository at this point in the history
- Rename measure to transferability and separate bands and eos
  • Loading branch information
unkcpz committed Jun 26, 2024
1 parent 754d7cd commit ccd80c3
Show file tree
Hide file tree
Showing 44 changed files with 30,390 additions and 900 deletions.
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ aiida-sssp-workflow = "aiida_sssp_workflow.cli:cmd_root"
"sssp_workflow.birch_murnaghan_fit" = "aiida_sssp_workflow.calculations.birch_murnaghan_fit:birch_murnaghan_fit"

[project.entry-points."aiida.workflows"]
"sssp_workflow.measure.transferability" = "aiida_sssp_workflow.workflows.measure.transferability:EOSTransferabilityWorkChain"
"sssp_workflow.measure.bands" = "aiida_sssp_workflow.workflows.measure.bands:BandStructureWorkChain"
"sssp_workflow.transferability.eos" = "aiida_sssp_workflow.workflows.transferability.eos:TransferabilityEOSWorkChain"
"sssp_workflow.transferability.bands" = "aiida_sssp_workflow.workflows.transferability.bands:TransferabilityBandsWorkChain"
"sssp_workflow.convergence.caching" = "aiida_sssp_workflow.workflows.convergence.caching:_CachingConvergenceWorkChain"
"sssp_workflow.convergence.eos" = "aiida_sssp_workflow.workflows.convergence.eos:ConvergenceEOSWorkChain"
"sssp_workflow.convergence.cohesive_energy" = "aiida_sssp_workflow.workflows.convergence.cohesive_energy:ConvergenceCohesiveEnergyWorkChain"
"sssp_workflow.convergence.phonon_frequencies" = "aiida_sssp_workflow.workflows.convergence.phonon_frequencies:ConvergencePhononFrequenciesWorkChain"
"sssp_workflow.convergence.pressure" = "aiida_sssp_workflow.workflows.convergence.pressure:ConvergencePressureWorkChain"
"sssp_workflow.convergence.bands" = "aiida_sssp_workflow.workflows.convergence.bands:ConvergenceBandsWorkChain"
"sssp_workflow.verification" = "aiida_sssp_workflow.workflows.verifications:VerificationWorkChain"
"sssp_workflow.verification" = "aiida_sssp_workflow.workflows.verification:FullVerificationWorkChain"

[project.urls]
Documentation = "https://aiida-sssp-workflow.readthedocs.io/"
Expand Down
201 changes: 91 additions & 110 deletions src/aiida_sssp_workflow/cli/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,68 @@
Running verification workchain
"""

import os
from typing import List, Tuple
from pathlib import Path

import aiida
import click
from aiida import orm
from aiida.cmdline.params import options, types
from aiida.cmdline.utils import echo
from aiida.engine import run_get_node, submit
from aiida.engine import ProcessBuilder, run_get_node, submit
from aiida.plugins import DataFactory, WorkflowFactory

from aiida_pseudo.data.pseudo.upf import UpfData
from aiida_sssp_workflow.cli import cmd_root
from aiida_sssp_workflow.workflows.verifications import (
DEFAULT_CONVERGENCE_PROPERTIES_LIST,
DEFAULT_MEASURE_PROPERTIES_LIST,
DEFAULT_PROPERTIES_LIST,
)

UpfData = DataFactory("pseudo.upf")
VerificationWorkChain = WorkflowFactory("sssp_workflow.verification")

# Trigger the launch by running:
# aiida-sssp-workflow launch --property measure.precision --pw-code pw-7.0@localhost --ph-code ph-7.0@localhost --protocol test --cutoff-control test --criteria efficiency --withmpi True -- examples/_static/Si_ONCV_PBE-1.2.upf
def guess_properties_list(property: list) -> Tuple[List[str], str]:
# if the property is not specified, use the default list with all properties calculated.
# otherwise, use the specified properties.
if not property:
properties_list = DEFAULT_PROPERTIES_LIST
extra_desc = "All properties"
elif len(property) == 1 and property[0] == "convergence":
properties_list = DEFAULT_CONVERGENCE_PROPERTIES_LIST
extra_desc = "Convergence"
elif len(property) == 1 and property[0] == "measure":
properties_list = DEFAULT_MEASURE_PROPERTIES_LIST
extra_desc = "Measure"
else:
properties_list = list(property)
extra_desc = f"{properties_list}"

return properties_list, extra_desc

def guess_is_convergence(properties_list: list) -> bool:
"""Check if it is a convergence test"""

return any([c for c in properties_list if c.startswith("convergence")])

def guess_is_full_convergence(properties_list: list) -> bool:
"""Check if all properties are run for convergence test"""

return len([c for c in properties_list if c.startswith("convergence")]) == len(DEFAULT_CONVERGENCE_PROPERTIES_LIST)

def guess_is_measure(properties_list: list) -> bool:
"""Check if it is a measure test"""

return any([c for c in properties_list if c.startswith("measure")])

def guess_is_ph(properties_list: list) -> bool:
"""Check if it has a measure test"""

return any([c for c in properties_list if "phonon_frequencies" in c])


# Trigger the launch by running:
# aiida-sssp-workflow launch --property measure.precision --pw-code pw-7.0@localhost --ph-code ph-7.0@localhost --protocol test --cutoff-control test --withmpi True -- examples/_static/Si_ONCV_PBE-1.2.upf
@cmd_root.command("launch")
@click.argument("pseudo", type=click.Path(exists=True))
@options.OverridableOption(
Expand All @@ -51,11 +89,6 @@
type=click.FLOAT,
help="Oxygen ecutrho to use for oxides precision measure workflow.",
)
@options.OverridableOption(
"--pw-code-large-memory",
"pw_code_large_memory",
type=types.CodeParamType(entry_point="quantumespresso.pw"),
)(required=False)
@options.OverridableOption(
"--ph-code", "ph_code", type=types.CodeParamType(entry_point="quantumespresso.ph")
)(required=False)
Expand All @@ -68,10 +101,9 @@
@click.option(
"protocol",
"--protocol",
default="acwf",
help="Protocol to use for the verification, (acwf, test).",
default="standard",
help="Protocol to use for the verification, (standard, quick, test).",
)
@click.option("withmpi", "--withmpi", default=True, help="Run with mpi.")
@click.option("npool", "--npool", default=1, help="Number of pool.")
@click.option("walltime", "--walltime", default=3600, help="Walltime.")
@click.option(
Expand Down Expand Up @@ -100,143 +132,92 @@
@click.option(
"ecutwfc",
"--ecutwfc",
type=float,
help="Cutoff energy for wavefunctions in Rydberg.",
)
@click.option(
"ecutrho",
"--ecutrho",
type=float,
help="Cutoff energy for charge density in Rydberg.",
)
# cutoff_control, criteria, configuration is for convergence workflows only
@click.option(
"cutoff_control",
"--cutoff-control",
help="Cutoff control for convergence workflow, (standard, quick, opsp).",
)
@click.option(
"criteria", "--criteria", help="Criteria for convergence (efficiency, precision)."
)
# configuration is hard coded for convergence workflow, but here is an interface for experiment purpose
# when this is passed with convergence test, only one can be passed.
# When it is passed with measure test, can be multiple configurations.
@click.option(
"configuration",
"--configuration",
multiple=True,
default=(),
default=[],
help="Configuration of structure, can be: SC, FCC, BCC, Diamond, XO, XO2, XO3, X2O, X2O3, X2O5, GS, RE",
)
def launch(
pw_code,
ph_code,
pw_code_large_memory,
property,
protocol,
ecutwfc,
ecutrho,
cutoff_control,
criteria,
configuration,
withmpi,
npool,
walltime,
pw_code: orm.Code,
ph_code: orm.Code,
property: list,
protocol: str,
configuration: list,
npool: int,
walltime: int,
resources,
pseudo,
oxygen_pseudo,
oxygen_ecutwfc,
oxygen_ecutrho,
clean_workdir,
daemon,
comment,
pseudo: Path,
clean_workdir: bool,
daemon: bool,
comment: str,
):
"""Launch the verification workchain."""
# if the property is not specified, use the default list with all properties calculated.
# otherwise, use the specified properties.
if not property:
properties_list = DEFAULT_PROPERTIES_LIST
extra_desc = "All properties"
elif len(property) == 1 and property[0] == "convergence":
properties_list = DEFAULT_CONVERGENCE_PROPERTIES_LIST
extra_desc = "Convergence"
elif len(property) == 1 and property[0] == "measure":
properties_list = DEFAULT_MEASURE_PROPERTIES_LIST
extra_desc = "Measure"
else:
properties_list = list(property)
extra_desc = f"{properties_list}"

# validate the options are all provide for the property
is_convergence = False
is_measure = False
is_ph = False
for prop in properties_list:
if prop.startswith("convergence"):
is_convergence = True
if prop.startswith("measure"):
is_measure = True
if "phonon_frequencies" in prop:
is_ph = True

# raise error if the options are not provided
if is_convergence and not (cutoff_control and criteria):
echo.echo_critical(
"cutoff_control, criteria must be provided for convergence workflow."
)
properties_list, extra_desc = guess_properties_list(property)

if is_measure and not (ecutwfc and ecutrho):
echo.echo_critical("ecutwfc and ecutrho must be provided for measure workflow.")
is_convergence = guess_is_convergence(properties_list)
is_full_convergence = guess_is_full_convergence(properties_list)
is_measure = guess_is_measure(properties_list)
is_ph = guess_is_ph(properties_list)

if is_ph and not ph_code:
echo.echo_critical("ph_code must be provided for phonon frequencies.")

# raise warning if the options are over provided, e.g. cutoff_control is provided for measure workflow
if is_measure and (cutoff_control or criteria):
echo.echo_warning("cutoff_control, criteria are not used for measure workflow.")

# raise warning if pw_code_large_memory is provided for not include cohesive energy convergence workflow
if pw_code_large_memory and (
not is_convergence or "convergence.cohesive_energy" not in properties_list
):
echo.echo_warning("pw_code_large_memory is not used for this workflow.")
echo.echo_critical("ph_code must be provided since we run on it for phonon frequencies.")

if is_convergence and len(configuration) > 1:
echo.echo_critical(
"Only one configuration is allowed for convergence workflow."
)

if is_convergence and (ecutwfc or ecutrho):
echo.echo_warning("ecutwfc and ecutrho are not used for convergence workflow.")
if is_measure and not is_full_convergence:
echo.echo_warning("Full convergence tests are not run, so we use maximum cutoffs for transferability verification.")

# Load the curent AiiDA profile and log to user
_profile = aiida.load_profile()
echo.echo_info(f"Current profile: {_profile.name}")

basename = os.path.basename(pseudo)

computer = pw_code.computer.label
label, _ = os.path.splitext(basename)

# convert configuration to list
configuration = list(configuration)
configuration_list = list(configuration)

if len(configuration) == 0:
if len(configuration_list) == 0:
conf_label = "default"
elif len(configuration) == 1:
conf_label = configuration[0]
elif len(configuration_list) == 1:
conf_label = configuration_list[0]
else:
conf_label = "/".join(configuration)

pre_label = (
f"{protocol}"
if not is_convergence
else f"{protocol}-{criteria}-{cutoff_control}"
)
label = orm.Str(f"({pre_label} at {computer} - {conf_label}) {label}")

with open(pseudo, "rb") as stream:
pseudo = UpfData(stream)
conf_label = "/".join(configuration_list)

resources = dict(resources)
if "num_machines" not in resources:
resources["num_machines"] = 1

builder: ProcessBuilder = FullVerificationWorkChain.get_builder(
pseudo=pseudo,
protocol=protocol,
properties_list=properties_list,
configuration_list=configuration_list,
clean_workdir=clean_workdir,
)

builder.metadata.label = f"({protocol} at {pw_code.computer.label} - {conf_label}) {pseudo.stem}"
builder.metadata.description = f"""Calculation is run on protocol: {protocol}; on {pw_code.computer.label}; on configuration {conf_label}; on pseudo {pseudo.stem}."""

builder.pw_code = pw_code
if is_ph:
builder.ph_code = ph_code

inputs = {
"measure": {
"protocol": orm.Str(protocol),
Expand All @@ -257,7 +238,7 @@ def launch(
"resources": resources,
"max_wallclock_seconds": walltime,
"withmpi": withmpi,
}
},
),
"parallelization": orm.Dict(dict={"npool": npool}),
"clean_workdir": orm.Bool(clean_workdir),
Expand Down
6 changes: 3 additions & 3 deletions src/aiida_sssp_workflow/protocol/control.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ quick:
test:
description: test only

wfc_scan: [30, 35] # at fix dual
nc_dual_scan: [] # at fix wfc
nonnc_dual_scan: [] # at fix rho
wfc_scan: [20, 30] # at fix dual
nc_dual_scan: [3.0, 4.0] # at fix wfc
nonnc_dual_scan: [6.0, 8.0] # at fix rho
nonnc_high_dual_scan: [8.0, 12.0]
35 changes: 0 additions & 35 deletions src/aiida_sssp_workflow/protocol/convergence.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,41 +69,6 @@ fine:
scale_count: 7
scale_increment: 0.02

acwf:
name: acwf
description: The parameters of EOS is exactly the same as it used in nat.phys.rev 2024 paper.

base: # base parameters is inherit by other process
occupations: smearing
degauss: 0.0045 # balanced protocol of qe -> gabriel
smearing: fd
conv_thr_per_atom: 1.0e-10
kpoints_distance: 0.06 # balanced protocol of qe -> gabriel
mixing_beta: 0.4

cohesive_energy:
atom_smearing: gaussian
vacuum_length: 12.0

phonon_frequencies:
qpoints_list:
- [0.5, 0.5, 0.5]
epsilon: false
tr2_ph: 1.0e-14
diagonalization: cg

pressure:
scale_count: 7
scale_increment: 0.02

bands:
init_nbands_factor: 3.0
fermi_shift: 10.0

eos:
scale_count: 7
scale_increment: 0.02

test:
name: test-only
description: Protocol to run test of workflow.
Expand Down
Loading

0 comments on commit ccd80c3

Please sign in to comment.