Skip to content

BUG: atomate2 failed to compute the 3rd-order elastic tensor. #1212

Open
@hongyi-zhao

Description

@hongyi-zhao

I try to call atomate2 via jobflow-remote to compute the 3rd-order elastic tensor with the following code:

import numpy as np
from jobflow import run_locally
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
from atomate2.vasp.flows.elastic import ElasticMaker
from atomate2.vasp.powerups import (
    update_user_incar_settings,
    update_user_potcar_functional,
    update_user_kpoints_settings,
)
from pymatgen.io.vasp.inputs import Kpoints
from pymatgen.core import Structure
from mp_api.client import MPRester
from atomate2.vasp.powerups import add_metadata_to_flow
#https://github.com/materialsproject/atomate2/issues/1014#issuecomment-2454955891
from atomate2.vasp.flows.mp import MPGGADoubleRelaxMaker, MPGGAStaticMaker

from jobflow import Flow
from jobflow_remote import submit_flow

# Based on the following checking:
#werner@x13dai-t:~/Public/hpc/vasp/pot$ ug -r 'TITEL  = PAW_PBE Pt ' -g POTCAR
#potpaw_PBE.54/Pt/POTCAR:   TITEL  = PAW_PBE Pt 04Feb2005
#potpaw_PBE.64/Pt/POTCAR:   TITEL  = PAW_PBE Pt 04Feb2005
#potpaw_PBE/Pt/POTCAR:   TITEL  = PAW_PBE Pt 05Jan2001
#potpaw_PBE/Pt_new/POTCAR:   TITEL  = PAW_PBE Pt 04Feb2005
#potpaw_PBE/Pt_ZORA/POTCAR:   TITEL  = PAW_PBE Pt 05Jan2001
#potpaw_PBE.52/Pt/POTCAR:   TITEL  = PAW_PBE Pt 04Feb2005
#potpaw_LDA_PBE_52_54_orig/potpaw_PBE.54/Pt/POTCAR:   TITEL  = PAW_PBE Pt 04Feb2005
#potpaw_LDA_PBE_52_54_orig/potpaw_PBE.52/Pt/POTCAR:   TITEL  = PAW_PBE Pt 04Feb2005

#So, all the following versions are the same one in this case:
#user_potcar_functional = "PBE_64"
#user_potcar_functional = "PBE_52"
#user_potcar_functional = "PBE_54"
#user_potcar_functional = "PBE_52_W_HASH"
#user_potcar_functional = "PBE_54_W_HASH"

#要复现MP,根据下面的检查,应该设置potcar版本与MP官方使用的一致。

#In [4]: from mp_api.client import MPRester
#   ...: 
#   ...: material_id = "mp-126"
#   ...: with MPRester() as mpr:
#   ...:     # 获取elastic数据来获取task id
#   ...:     elasticity_doc = mpr.materials.elasticity.search(material_ids=[material_id])
#   ...:     opt_id = elasticity_doc[0].fitting_data.optimization_task.string
#   ...: 
#   ...:     # 使用task id获取详细信息
#   ...:     opt_doc = mpr.materials.tasks.search([opt_id],
#   ...:         fields=["input", "calcs_reversed"])
#   ...: 
#   ...:     # 提取 potcar_spec
#   ...:     potcar_spec = opt_doc[0].calcs_reversed[0].input.potcar_spec
#   ...:     print(f"POTCAR specifications: {potcar_spec}")
#   ...: 
#Retrieving ElasticityDoc documents: 100%|█████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 7543.71it/s]
#Retrieving TaskDoc documents: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 9892.23it/s]
#POTCAR specifications: [PotcarSpec(titel='PAW_PBE Pt 05Jan2001', hash='a604ea3c6a9cc23c739b762f625cf449', summary_stats=None)]

#In [4]: opt_doc[0].calcs_reversed[0].input.potcar_spec
#Out[4]: [PotcarSpec(titel='PAW_PBE Pt 05Jan2001', hash='a604ea3c6a9cc23c739b762f625cf449', summary_stats=None)]

#https://github.com/materialsproject/api/issues/944#issuecomment-2503063154
user_potcar_functional = "PBE"

# 实际测试表明,不同的vasp版本的计算结果是一致的(差别很小,可以忽略):
#In [5]: # MP所使用的vasp版本:
#   ...: for calc in opt_doc[0].calcs_reversed:
#   ...:     print(calc.vasp_version)
#   ...: 
#5.4.4
#5.4.4

material_id = "mp-126"
with MPRester() as mpr:
    # Obtain elastic data and the related task IDs.
    elasticity_doc = mpr.materials.elasticity.search(material_ids=[material_id])
    opt_id = elasticity_doc[0].fitting_data.optimization_task.string
    first_deform_id = str(elasticity_doc[0].fitting_data.deformation_tasks[0])
    opt_doc = mpr.materials.tasks.search([opt_id],
        fields=["input", "orig_inputs", "calcs_reversed"])

    deform_dep_doc = mpr.materials.tasks.search([first_deform_id],
        fields=["input", "orig_inputs", "calcs_reversed"])

structure = mpr.materials.get_structure_by_material_id(material_id)
#ElasticMaker的flow中有 structure_to_conventional的job,所以下面的步骤应该不是必需的:
structure = SpacegroupAnalyzer(structure).get_conventional_standard_structure()

# Process kpoints settings
#opt_kpoints_settings = opt_doc[0].orig_inputs.kpoints
#deform_kpoints_settings = deform_dep_doc[0].orig_inputs.kpoints

# Use calcs-reversed to do the trick:
#https://materialsproject.github.io/atomate2/user/docs_schemas_emmet.html#calcs-reversed
opt_kpoints_settings = opt_doc[0].calcs_reversed[0].input.kpoints
deform_kpoints_settings = deform_dep_doc[0].calcs_reversed[0].input.kpoints

# Process INCAR settings
# Adopt the following strategy: based on the keys in `orig_inputs.incar`, use the corresponding values from `input.parameters`.
# This can be simplified into a one-liner dictionary comprehension:

#opt_incar_settings = {key: opt_doc[0].input.parameters[key] for key in opt_doc[0].orig_inputs.incar.keys() if key in opt_doc[0].input.parameters}
#deform_incar_settings = {key: deform_dep_doc[0].input.parameters[key] for key in deform_dep_doc[0].orig_inputs.incar.keys() if key in deform_dep_doc[0].input.parameters}

# Or, for better readability, you can first define variables and then achieve it as following:
#orig_incar = opt_doc[0].orig_inputs.incar
#input_params = opt_doc[0].input.parameters
#opt_incar_settings = {key: input_params[key] for key in orig_incar.keys() if key in input_params}

#orig_incar = deform_dep_doc[0].orig_inputs.incar
#input_params = deform_dep_doc[0].input.parameters
#deform_incar_settings = {key: input_params[key] for key in orig_incar.keys() if key in input_params}

# Use calcs-reversed to do the trick:
#https://materialsproject.github.io/atomate2/user/docs_schemas_emmet.html#calcs-reversed
opt_incar_settings = opt_doc[0].calcs_reversed[0].input.incar
deform_incar_settings = deform_dep_doc[0].calcs_reversed[0].input.incar

# Handle MAGMOM settings correctly.
if isinstance(opt_incar_settings.get("MAGMOM", []), list):
    magmoms = {}
    for idx, site in enumerate(structure):
        if idx < len(opt_incar_settings.get("MAGMOM", [])):
            magmoms[site.species_string] = opt_incar_settings["MAGMOM"][idx]
    opt_incar_settings["MAGMOM"] = magmoms


if isinstance(deform_incar_settings.get("MAGMOM", []), list):
    magmoms = {}
    for idx, site in enumerate(structure):
        if idx < len(deform_incar_settings.get("MAGMOM", [])):
            magmoms[site.species_string] = deform_incar_settings["MAGMOM"][idx]
    deform_incar_settings["MAGMOM"] = magmoms


#Re: The meaning of "GGA = --".
#https://www.vasp.at/forum/viewtopic.php?p=29678#p29678
#If the GGA tag is not explicitly specified in INCAR, then the functional from the POTCAR (usually PBE) is used. With older VASP versions, this was indicated with "GGA = --" in OUTCAR. Since VASP.6.4.3 this is properly indicated with "GGA = PE".

#In [3]: opt_doc[0].input.parameters['GGA']
#Out[3]: '--'

#In [34]: opt_doc[0].calcs_reversed[0].input.potcar
#Out[34]: ['Pt']

#In [35]: opt_doc[0].calcs_reversed[0].input.potcar_spec
#Out[35]: [PotcarSpec(titel='PAW_PBE Pt 05Jan2001', hash='a604ea3c6a9cc23c739b762f625cf449', summary_stats=None)]

#In [36]: opt_doc[0].calcs_reversed[0].input.potcar_type
#Out[36]: ['PAW_PBE']

flow = ElasticMaker(
    # 展示3阶弹性张量的计算:
    order=3, # Order of the tensor expansion to be determined. Can be either 2 or 3. default value is 2
    bulk_relax_maker=MPGGADoubleRelaxMaker(),  # 使用MP的双重优化设置
    elastic_relax_maker=MPGGAStaticMaker(),    # 使用MP的静态计算设置
    ).make(structure, conventional=True)
flow = update_user_potcar_functional(flow, user_potcar_functional)

flow = update_user_kpoints_settings(flow, opt_kpoints_settings, name_filter="MP GGA relax")
flow = update_user_kpoints_settings(flow, deform_kpoints_settings, name_filter="MP GGA static")

flow = update_user_incar_settings(flow, opt_incar_settings, name_filter="MP GGA relax" )
flow = update_user_incar_settings(flow, deform_incar_settings, name_filter="MP GGA static")

# Add metadata.
#flow = add_metadata_to_flow(
#    flow=flow,
#    additional_fields={
#        "mp_id": "mp-126", 
#        "submission_label": "mp-126_elastic_tensor-GGA-PE"
#    },
#)

# Run the flow
#responses = run_locally(flow, create_folders=True, ensure_success=True)
#elastic_output = responses[flow.jobs[-1].uuid][1].output
#matrix = np.array(elastic_output.elastic_tensor.ieee_format)
#np.set_printoptions(precision=4, suppress=True)
#print(matrix)

# 基于jobflow-remote:
jf_flow = Flow(flow, name='reproduce-mp-elastic')

# 提交计算
#https://github.com/Matgenix/jobflow-remote/issues/277#issuecomment-2759941413
#$ cd "/home/werner/Public/repo/github.com/Matgenix/qtoolkit.git" && ug -i 'SBATCH --mem'
#src/qtoolkit/io/slurm.py
#   157: #SBATCH --mem=$${mem}
#   158: #SBATCH --mem-per-cpu=$${mem_per_cpu}
resources = {
    "nodes": 1,
    "ntasks": 16,
    "mem": "80G",
    "partition": "batch",
    "time": "2400:00:00"
}

#https://github.com/Matgenix/jobflow-remote/issues/277#issuecomment-2759918475
print(submit_flow(jf_flow, project='std', worker="vasp_slurm", resources=resources, exec_config="vasp_slurm"))

But the job fit_elastic_tensor in the flow failed as shown below:

In [11]: ! jf -p std job info 211f2834-2c16-4ed4-be09-6c59085abdfd
The selected project is std from config file /home/werner/.jfremote/std.yaml
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│      db_id = '390'                                                                                                                                           │
│       uuid = '211f2834-2c16-4ed4-be09-6c59085abdfd'                                                                                                          │
│      index = 1                                                                                                                                               │
│       name = 'fit_elastic_tensor'                                                                                                                            │
│      state = 'FAILED'                                                                                                                                        │
│      error = Traceback (most recent call last):                                                                                                              │
│                File "/home/werner/Public/repo/github.com/Matgenix/jobflow-remote.git/src/jobflow_remote/jobs/run.py", line 69, in run_remote_job             │
│                  response = job.run(store=store)                                                                                                             │
│                             ^^^^^^^^^^^^^^^^^^^^                                                                                                             │
│                File "/home/werner/.pyenv/versions/3.11.1/envs/datasci/lib/python3.11/site-packages/jobflow/core/job.py", line 604, in run                    │
│                  response = function(*self.function_args, **self.function_kwargs)                                                                            │
│                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                            │
│                File "/home/werner/Public/repo/github.com/materialsproject/atomate2.git/src/atomate2/common/jobs/elastic.py", line 245, in fit_elastic_tensor │
│                  return ElasticDocument.from_stresses(                                                                                                       │
│                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                       │
│                File "/home/werner/Public/repo/github.com/materialsproject/atomate2.git/src/atomate2/common/schemas/elastic.py", line 267, in from_stresses   │
│                  raw=result.voigt.tolist(), ieee_format=ieee.voigt.tolist()                                                                                  │
│                      ^^^^^^^^^^^^^^^^^^^                                                                                                                     │
│              AttributeError: 'list' object has no attribute 'tolist'                                                                                         │
│     remote = {'step_attempts': 0, 'process_id': '998', 'prerun_cleanup': False}                                                                              │
│ created_on = '2025-06-06 13:21'                                                                                                                              │
│ updated_on = '2025-06-06 14:08'                                                                                                                              │
│ start_time = '2025-06-06 14:08'                                                                                                                              │
│   end_time = '2025-06-06 14:08'                                                                                                                              │
│   metadata = {}                                                                                                                                              │
│    run_dir = '/home/werner/Desktop/std_vasp_slurm/21/1f/28/211f2834-2c16-4ed4-be09-6c59085abdfd_1'                                                           │
│    parents = ['485e627d-8e43-412a-994d-3fe6572b8d8d', '2615a673-a0c5-4805-9cc9-3acb49570594', '804865f9-d32e-4268-a623-e12d34425c59']                        │
│   priority = 0                                                                                                                                               │
│     worker = 'vasp_slurm'                                                                                                                                    │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

See below for the related discussions:

https://www.vasp.at/forum/viewtopic.php?p=31597#p31597
Neraaz/HTESP#1 (comment)

Regards,
Zhao

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions