diff --git a/README.md b/README.md
index 5b12bcd..b3ac4a3 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,7 @@
[APEX](https://github.com/deepmodeling/APEX): Alloy Property EXplorer using simulations, is a component of the [AI Square](https://aissquare.com/) project that involves the restructuring of the [DP-Gen](https://github.com/deepmodeling/dpgen) `auto_test` module to develop a versatile and extensible Python package for general alloy property testing. This package enables users to conveniently establish a wide range of property-test workflows by utilizing various computational approaches, including support for LAMMPS, VASP, and ABACUS.
## New Features Update (v1.0)
+* Add calculation function of `phonon` spectrum (v1.1.0)
* Decouple property calculations into individual sub-workflow to facilitate the customization of complex property functions
* Support one-click parallel submission of multiple workflows
* Support `run` step in the single step test mode (Interaction method similar to `auto_test`)
@@ -28,6 +29,7 @@
- [3.1.2.4. Vacancy](#3124-vacancy)
- [3.1.2.5. Interstitial](#3125-interstitial)
- [3.1.2.6. Gamma Line](#3126-gamma-line)
+ - [3.1.2.7. Phonon Spectrum](#3127-phonon-spectrum)
- [3.2. Command](#32-command)
- [3.2.1. Workflow Submission](#321-workflow-submission)
- [3.2.2. Single-Step Test](#322-single-step-test)
@@ -43,7 +45,7 @@ APEX adopts the functionality of the second-generation alloy properties calculat
The comprehensive architecture of APEX is demonstrated below:
-
+
Figure 1. APEX schematic diagram
@@ -344,7 +346,31 @@ The parameters related to Gamma line calculation are listed below:
"n_steps": 10
}
```
- **It should be noted that for various crystal structures, users can further define slip parameters within the respective nested dictionaries, which will be prioritized for adoption. In above example, the slip system configuration within the "hcp" dictionary will be utilized.**
+ It should be noted that for various crystal structures, **users can further define slip parameters within the respective nested dictionaries, which will be prioritized for adoption**. In above example, the slip system configuration within the "hcp" dictionary will be utilized.
+
+##### 3.1.2.7. Phonon Spectrum
+This function incorporates part of [dflow-phonon](https://github.com/Chengqian-Zhang/dflow-phonon) codes into APEX to make it more complete. This workflow is realized via [Phonopy](https://github.com/phonopy/phonopy), and plus [phonoLAMMPS](https://github.com/abelcarreras/phonolammps) for LAMMPS calculation.
+
+*IMPORTANT!!*: it should be noticed that one will need the **phonoLAMMPS** package pre-installed within one's `run_image` for proper `LAMMPS` calculation of phonon spectrum.
+
+The parameters related to `Phonon` calculation are listed below:
+ | Key words | Data structure | Default | Description |
+ | :------------ | ----- | ----- | ------------------- |
+ | primitive | Bool | False | Whether to find primitive lattice structure for phonon calculation |
+ | approach | String | "linear" | Specify phonon calculation method when using `VASP`; Two options: 1. "linear" for the *Linear Response Method*, and 2. "displacement" for the *Finite Displacement Method* |
+ | supercell_size | Sequence[Int] | [2, 2, 2] | Size of supercell created for calculation |
+ | MESH | Sequence[Int] | None | Specify the dimensions of the grid in reciprocal space for which the phonon frequencies and eigenvectors are to be calculated. For example: [8, 8, 8]; Refer to [Phonopy MESH](http://phonopy.github.io/phonopy/setting-tags.html#mesh-sampling-tags) |
+ | PRIMITIVE_AXES | String | None | To define the basis vectors of a primitive cell in terms of the basis vectors of a conventional cell for input cell transformation. For example: "0.0 0.5 0.5 0.5 0.0 0.5 0.5 0.5 0.0"; Refer to [Phonopy PRIMITIVE_AXES](http://phonopy.github.io/phonopy/setting-tags.html#primitive-axes-or-primitive-axis) |
+ | BAND | String | None | Indicate band path in reciprocal space as format of [Phonopy BAND](http://phonopy.github.io/phonopy/setting-tags.html#band-and-band-points); For example: "0 0 0 1/2 0 1/2, 1/2 1/2 1 0 0 0 1/2 1/2 1/2" |
+ | BAND_POINTS | Int | 51 | Number of sampling points including the path ends |
+ | BAND_CONNECTION | Bool | True | With this option, band connections are estimated from eigenvectors and band structure is drawn considering band crossings. In sensitive cases, to obtain better band connections, it requires to increase number of points calculated in band segments by the `BAND_POINTS` tag. |
+
+When utilize the `VASP`, you have **two** primary calculation methods at your disposal: the **Linear Response Method** and the **Finite Displacement Method**.
+
+The **Linear Response Method** has an edge over the Finite Displacement Method in that it eliminates the need for creating super-cells, thereby offering computational efficiency in certain cases. Additionally, this method is particularly well-suited for systems with anomalous phonon dispersion (like systems with Kohn anomalies), as it can precisely calculate the phonons at the specified points.
+
+On the other hand, the **Finite Displacement Method**'s advantage lies in its versatility; it functions as an add-on compatible with any code, including those beyond the scope of density functional theory. The only requirement is that the external code can compute forces. For instance, ABACUS may lack an implementation of the Linear Response Method, but can effectively utilize the Finite Displacement Method implemented in phonon calculation.
+
### 3.2. Command
APEX currently supports two seperate run modes: **workflow submission** (running via dflow) and **single-step test** (running without dflow).
diff --git a/apex/__init__.py b/apex/__init__.py
index 2b3a52a..629101b 100644
--- a/apex/__init__.py
+++ b/apex/__init__.py
@@ -1,5 +1,5 @@
import os
-__version__ = '1.0.2'
+__version__ = '1.1.1'
LOCAL_PATH = os.getcwd()
diff --git a/apex/__main__.py b/apex/__main__.py
index 0e592cc..bc89e4d 100644
--- a/apex/__main__.py
+++ b/apex/__main__.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-from .main import main
+from apex.main import main
if __name__ == '__main__':
main()
diff --git a/apex/core/calculator/ABACUS.py b/apex/core/calculator/ABACUS.py
index 5e475fc..b1f0d6e 100644
--- a/apex/core/calculator/ABACUS.py
+++ b/apex/core/calculator/ABACUS.py
@@ -4,8 +4,7 @@
from dpdata import LabeledSystem
from monty.serialization import dumpfn
-import apex.core.calculator.lib.abacus as abacus
-import apex.core.calculator.lib.abacus_scf as abacus_scf
+from apex.core.calculator.lib import abacus_utils, abacus_scf
#from dpgen import dlog
from apex.core.calculator.Task import Task
from apex.utils import sepline
@@ -98,7 +97,7 @@ def make_input_file(self, output_dir, task_type, task_param):
incar_relax = abacus_scf.get_abacus_input_parameters(relax_incar_path)
# deal with relaxation
-
+ prop_type = task_param.get("type", "relaxation")
cal_type = task_param["cal_type"]
cal_setting = task_param["cal_setting"]
@@ -158,7 +157,7 @@ def make_input_file(self, output_dir, task_type, task_param):
raise RuntimeError("not supported calculation type for ABACUS")
# modify STRU file base on the value of fix_atom
- abacus.stru_fix_atom(os.path.join(output_dir, "STRU"), fix_atom)
+ abacus_utils.stru_fix_atom(os.path.join(output_dir, "STRU"), fix_atom)
if "basis_type" not in incar:
logging.info("'basis_type' is not defined, set to be 'pw'!")
@@ -169,7 +168,7 @@ def make_input_file(self, output_dir, task_type, task_param):
% incar["basis_type"]
)
raise RuntimeError(mess)
- abacus.write_input(os.path.join(output_dir, "../INPUT"), incar)
+ abacus_utils.write_input(os.path.join(output_dir, "../INPUT"), incar)
cwd = os.getcwd()
os.chdir(output_dir)
if not os.path.islink("INPUT"):
@@ -182,7 +181,7 @@ def make_input_file(self, output_dir, task_type, task_param):
if "kspacing" in incar:
kspacing = float(incar["kspacing"])
if os.path.isfile(os.path.join(output_dir, "STRU")):
- kpt = abacus.make_kspacing_kpt(
+ kpt = abacus_utils.make_kspacing_kpt(
os.path.join(output_dir, "STRU"), kspacing
)
kpt += [0, 0, 0]
@@ -195,7 +194,7 @@ def make_input_file(self, output_dir, task_type, task_param):
mess += "You can set key word 'kspacing' (unit in 1/bohr) as a float value in INPUT\n"
mess += "or set key word 'K_POINTS' as a list in 'cal_setting', e.g. [1,2,3,0,0,0]\n"
raise RuntimeError(mess)
- abacus.write_kpt(os.path.join(output_dir, "KPT"), kpt)
+ abacus_utils.write_kpt(os.path.join(output_dir, "KPT"), kpt)
def compute(self, output_dir):
if not os.path.isfile(os.path.join(output_dir, "INPUT")):
diff --git a/apex/core/calculator/Lammps.py b/apex/core/calculator/Lammps.py
index c9aa52f..7707675 100644
--- a/apex/core/calculator/Lammps.py
+++ b/apex/core/calculator/Lammps.py
@@ -4,15 +4,15 @@
from monty.serialization import dumpfn, loadfn
-import apex.core.calculator.lib.lammps as lammps
+from apex.core.calculator.lib import lammps_utils
#from dpgen import dlog
-from apex.core.calculator.lib.lammps import (
+from apex.core.calculator.lib.lammps_utils import (
inter_deepmd,
inter_eam_alloy,
inter_eam_fs,
inter_meam,
)
-from apex.core.calculator.Task import Task
+from .Task import Task
from dflow.python import upload_packages
upload_packages.append(__file__)
@@ -129,10 +129,10 @@ def make_potential_files(self, output_dir):
dumpfn(self.inter, os.path.join(output_dir, "inter.json"), indent=4)
def make_input_file(self, output_dir, task_type, task_param):
- lammps.cvt_lammps_conf(
+ lammps_utils.cvt_lammps_conf(
os.path.join(output_dir, "POSCAR"),
os.path.join(output_dir, "conf.lmp"),
- lammps.element_list(self.type_map),
+ lammps_utils.element_list(self.type_map),
)
# dumpfn(task_param, os.path.join(output_dir, 'task.json'), indent=4)
@@ -195,7 +195,7 @@ def make_input_file(self, output_dir, task_type, task_param):
relax_vol = cal_setting["relax_vol"]
if [relax_pos, relax_shape, relax_vol] == [True, False, False]:
- fc = lammps.make_lammps_equi(
+ fc = lammps_utils.make_lammps_equi(
"conf.lmp",
self.type_map,
self.inter_func,
@@ -207,7 +207,7 @@ def make_input_file(self, output_dir, task_type, task_param):
False,
)
elif [relax_pos, relax_shape, relax_vol] == [True, True, True]:
- fc = lammps.make_lammps_equi(
+ fc = lammps_utils.make_lammps_equi(
"conf.lmp",
self.type_map,
self.inter_func,
@@ -225,7 +225,7 @@ def make_input_file(self, output_dir, task_type, task_param):
] and not task_type == "eos":
if "scale2equi" in task_param:
scale2equi = task_param["scale2equi"]
- fc = lammps.make_lammps_press_relax(
+ fc = lammps_utils.make_lammps_press_relax(
"conf.lmp",
self.type_map,
scale2equi[int(output_dir[-6:])],
@@ -239,7 +239,7 @@ def make_input_file(self, output_dir, task_type, task_param):
maxeval,
)
else:
- fc = lammps.make_lammps_equi(
+ fc = lammps_utils.make_lammps_equi(
"conf.lmp",
self.type_map,
self.inter_func,
@@ -256,7 +256,7 @@ def make_input_file(self, output_dir, task_type, task_param):
False,
] and task_type == "eos":
task_param["cal_setting"]["relax_shape"] = False
- fc = lammps.make_lammps_equi(
+ fc = lammps_utils.make_lammps_equi(
"conf.lmp",
self.type_map,
self.inter_func,
@@ -268,7 +268,7 @@ def make_input_file(self, output_dir, task_type, task_param):
False,
)
elif [relax_pos, relax_shape, relax_vol] == [False, False, False]:
- fc = lammps.make_lammps_eval(
+ fc = lammps_utils.make_lammps_eval(
"conf.lmp", self.type_map, self.inter_func, self.model_param
)
@@ -276,7 +276,7 @@ def make_input_file(self, output_dir, task_type, task_param):
raise RuntimeError("not supported calculation setting for LAMMPS")
elif cal_type == "static":
- fc = lammps.make_lammps_eval(
+ fc = lammps_utils.make_lammps_eval(
"conf.lmp", self.type_map, self.inter_func, self.model_param
)
@@ -442,7 +442,7 @@ def compute(self, output_dir):
_tmp = self.type_map
#dlog.debug(_tmp)
- type_map_list = lammps.element_list(self.type_map)
+ type_map_list = lammps_utils.element_list(self.type_map)
type_map_idx = list(range(len(type_map_list)))
atom_numbs = []
diff --git a/apex/core/calculator/VASP.py b/apex/core/calculator/VASP.py
index 1842c19..89c3604 100644
--- a/apex/core/calculator/VASP.py
+++ b/apex/core/calculator/VASP.py
@@ -6,10 +6,10 @@
from pymatgen.core.structure import Structure
from pymatgen.io.vasp import Incar, Kpoints
-import apex.core.calculator.lib.vasp as vasp
#from dpgen import dlog
from apex.core.calculator.Task import Task
-from apex.core.calculator.lib.vasp import incar_upper
+from apex.core.calculator.lib import vasp_utils
+from apex.core.calculator.lib.vasp_utils import incar_upper
from apex.utils import sepline
from dflow.python import upload_packages
upload_packages.append(__file__)
@@ -81,7 +81,7 @@ def make_input_file(self, output_dir, task_type, task_param):
incar_relax = incar_upper(Incar.from_file(relax_incar_path))
# deal with relaxation
-
+ prop_type = task_param.get("type", "relaxation")
cal_type = task_param["cal_type"]
cal_setting = task_param["cal_setting"]
@@ -89,10 +89,28 @@ def make_input_file(self, output_dir, task_type, task_param):
if "input_prop" in cal_setting and os.path.isfile(cal_setting["input_prop"]):
incar_prop = os.path.abspath(cal_setting["input_prop"])
incar = incar_upper(Incar.from_file(incar_prop))
+ logging.info(f"Will use user specified INCAR (path: {incar_prop}) for {prop_type} calculation")
# revise INCAR based on the INCAR provided in the "interaction"
else:
- incar = incar_relax
+ if prop_type == "phonon":
+ approach = task_param.get("approach", "linear")
+ logging.info(f"No specification of INCAR for {prop_type} calculation, will auto generate")
+ if approach == "linear":
+ incar = incar_upper(Incar.from_str(
+ vasp_utils.make_vasp_phonon_dfpt_incar(
+ ecut=650, ediff=0.0000001, npar=None, kpar=None
+ )))
+ elif approach == "displacement":
+ incar = incar_upper(Incar.from_str(
+ vasp_utils.make_vasp_static_incar(
+ ecut=650, ediff=0.0000001, npar=8, kpar=1
+ )))
+ else:
+ if not prop_type == "relaxation":
+ logging.info(f"No specification of INCAR for {prop_type} calculation, will use INCAR for relaxation")
+ incar = incar_relax
+
if cal_type == "relaxation":
relax_pos = cal_setting["relax_pos"]
relax_shape = cal_setting["relax_shape"]
@@ -192,7 +210,7 @@ def make_input_file(self, output_dir, task_type, task_param):
os.remove("INCAR")
os.symlink("../INCAR", "INCAR")
os.chdir(cwd)
- ret = vasp.make_kspacing_kpoints(self.path_to_poscar, kspacing, kgamma)
+ ret = vasp_utils.make_kspacing_kpoints(self.path_to_poscar, kspacing, kgamma)
kp = Kpoints.from_str(ret)
kp.write_file(os.path.join(output_dir, "KPOINTS"))
diff --git a/apex/core/calculator/calculator.py b/apex/core/calculator/calculator.py
index 54de864..316f008 100644
--- a/apex/core/calculator/calculator.py
+++ b/apex/core/calculator/calculator.py
@@ -4,6 +4,7 @@
from dflow.python import upload_packages
upload_packages.append(__file__)
+LAMMPS_TYPE = ["deepmd", "meam", "eam_fs", "eam_alloy"]
def make_calculator(inter_parameter, path_to_poscar):
"""
@@ -14,7 +15,7 @@ def make_calculator(inter_parameter, path_to_poscar):
return VASP(inter_parameter, path_to_poscar)
elif inter_type == "abacus":
return ABACUS(inter_parameter, path_to_poscar)
- elif inter_type in ["deepmd", "meam", "eam_fs", "eam_alloy"]:
+ elif inter_type in LAMMPS_TYPE:
return Lammps(inter_parameter, path_to_poscar)
# if inter_type == 'siesta':
# return Siesta(inter_parameter, path_to_poscar)
diff --git a/apex/core/calculator/lib/abacus_scf.py b/apex/core/calculator/lib/abacus_scf.py
index 93a77c6..788fd69 100644
--- a/apex/core/calculator/lib/abacus_scf.py
+++ b/apex/core/calculator/lib/abacus_scf.py
@@ -3,7 +3,7 @@
import numpy as np
from dpdata.abacus.scf import get_cell, get_coords, get_nele_from_stru
-from apex.core.calculator.lib import vasp
+from . import vasp_utils
from dflow.python import upload_packages
from dargs.dargs import Argument
upload_packages.append(__file__)
@@ -423,7 +423,7 @@ def make_kspacing_kpoints_stru(stru, kspacing):
if type(kspacing) is not list:
kspacing = [kspacing, kspacing, kspacing]
box = stru["cells"]
- rbox = vasp.reciprocal_box(box)
+ rbox = vasp_utils.reciprocal_box(box)
kpoints = [
max(1, (np.ceil(2 * np.pi * np.linalg.norm(ii) / ks).astype(int)))
for ii, ks in zip(rbox, kspacing)
diff --git a/apex/core/calculator/lib/abacus.py b/apex/core/calculator/lib/abacus_utils.py
similarity index 94%
rename from apex/core/calculator/lib/abacus.py
rename to apex/core/calculator/lib/abacus_utils.py
index 3551cde..d3262b1 100644
--- a/apex/core/calculator/lib/abacus.py
+++ b/apex/core/calculator/lib/abacus_utils.py
@@ -1,11 +1,12 @@
#!/usr/bin/python3
-import os
+import logging
+import os, re
import dpdata
import numpy as np
from pymatgen.core.structure import Structure
-import apex.core.calculator.lib.abacus_scf as abacus_scf
+from . import abacus_scf
from dflow.python import upload_packages
upload_packages.append(__file__)
@@ -499,3 +500,22 @@ def modify_stru_path(strucf, tpath):
with open(strucf, "w") as f1:
f1.writelines(lines)
+
+def append_orb_file_to_stru(stru, orb: dict = None, prefix: str = ""):
+ with open(stru, 'r') as fin:
+ all_string = fin.read()
+
+ if not re.search("NUMERICAL_ORBITAL", all_string) and orb:
+ logging.info(msg="Append user specific orbital files to STRU")
+ orbital_string = "NUMERICAL_ORBITAL\n"
+ for key, item in orb.items():
+ orbital_string += str(os.path.join(prefix, item))
+ orbital_string += '\n'
+ all_string_new = orbital_string + "\n" + all_string
+
+ if os.path.isfile(stru) or os.path.islink(stru):
+ os.remove(stru)
+
+ with open(stru, 'w') as fout:
+ fout.write(all_string_new)
+
diff --git a/apex/core/calculator/lib/lammps.py b/apex/core/calculator/lib/lammps_utils.py
similarity index 99%
rename from apex/core/calculator/lib/lammps.py
rename to apex/core/calculator/lib/lammps_utils.py
index fcc8fa8..19f0bd3 100644
--- a/apex/core/calculator/lib/lammps.py
+++ b/apex/core/calculator/lib/lammps_utils.py
@@ -9,7 +9,7 @@
from dpdata.periodic_table import Element
from packaging.version import Version
-import apex.core.lib.util as util
+from apex.core.lib import util
from dflow.python import upload_packages
upload_packages.append(__file__)
diff --git a/apex/core/calculator/lib/vasp.py b/apex/core/calculator/lib/vasp_utils.py
similarity index 98%
rename from apex/core/calculator/lib/vasp.py
rename to apex/core/calculator/lib/vasp_utils.py
index ab337dd..a3a6b8f 100644
--- a/apex/core/calculator/lib/vasp.py
+++ b/apex/core/calculator/lib/vasp_utils.py
@@ -5,7 +5,7 @@
import numpy as np
from pymatgen.io.vasp import Incar, Kpoints, Potcar
-import apex.core.lib.util as util
+from apex.core.lib import util
#from apex.calculator.lib.vasp import incar_upper
from dflow.python import upload_packages
upload_packages.append(__file__)
@@ -364,11 +364,12 @@ def make_vasp_relax_incar(
return ret
-def make_vasp_phonon_incar(
- ecut, ediff, npar, kpar, kspacing=0.5, kgamma=True, ismear=1, sigma=0.2
+def make_vasp_phonon_dfpt_incar(
+ ecut, ediff, npar, kpar, kspacing=0.3, kgamma=True, ismear=1, sigma=0.22
):
isif = 2
ret = ""
+ ret += "ADDGRID=True\n"
ret += "PREC=A\n"
ret += "ENCUT=%d\n" % ecut
ret += "# ISYM=0\n"
@@ -377,7 +378,7 @@ def make_vasp_phonon_incar(
ret += "EDIFFG=-0.01\n"
ret += "LREAL=A\n"
# ret += 'NPAR=%d\n' % npar
- ret += "KPAR=%d\n" % kpar
+ # ret += "KPAR=%d\n" % kpar
ret += "\n"
ret += "ISMEAR=%d\n" % ismear
ret += "SIGMA=%f\n" % sigma
diff --git a/apex/core/common_equi.py b/apex/core/common_equi.py
index 11e49d9..2c6be70 100644
--- a/apex/core/common_equi.py
+++ b/apex/core/common_equi.py
@@ -3,9 +3,8 @@
import shutil
import logging
from monty.serialization import dumpfn
-import apex.core.calculator.lib.abacus as abacus
-import apex.core.lib.crys as crys
-import apex.core.lib.util as util
+from apex.core.calculator.lib import abacus_utils
+from apex.core.lib import crys
from apex.core.calculator.calculator import make_calculator
from apex.core.lib.utils import create_path
from apex.core.lib.dispatcher import make_submission
@@ -67,7 +66,7 @@ def make_equi(confs, inter_param, relax_param):
crys.sc(ele_list[element_label]).to("POSCAR", "POSCAR")
if inter_param["type"] == "abacus" and not os.path.exists("STRU"):
- abacus.poscar2stru("POSCAR", inter_param, "STRU")
+ abacus_utils.poscar2stru("POSCAR", inter_param, "STRU")
os.remove("POSCAR")
os.chdir(cwd)
@@ -82,7 +81,7 @@ def make_equi(confs, inter_param, relax_param):
if "mp-" in crys_type and not os.path.exists(os.path.join(ii, "POSCAR")):
get_structure(crys_type).to("POSCAR", os.path.join(ii, "POSCAR"))
if inter_param["type"] == "abacus" and not os.path.exists("STRU"):
- abacus.poscar2stru(
+ abacus_utils.poscar2stru(
os.path.join(ii, "POSCAR"), inter_param, os.path.join(ii, "STRU")
)
os.remove(os.path.join(ii, "POSCAR"))
@@ -91,7 +90,7 @@ def make_equi(confs, inter_param, relax_param):
POSCAR = "POSCAR"
if inter_param["type"] == "abacus":
shutil.copyfile(os.path.join(ii, "STRU"), os.path.join(ii, "STRU.bk"))
- abacus.modify_stru_path(os.path.join(ii, "STRU"), "pp_orb/")
+ abacus_utils.modify_stru_path(os.path.join(ii, "STRU"), "pp_orb/")
poscar = os.path.abspath(os.path.join(ii, "STRU"))
POSCAR = "STRU"
if not os.path.exists(poscar):
diff --git a/apex/core/common_prop.py b/apex/core/common_prop.py
index 7ab8ffb..5c116f3 100644
--- a/apex/core/common_prop.py
+++ b/apex/core/common_prop.py
@@ -12,6 +12,7 @@
from apex.core.lib.dispatcher import make_submission
from apex.core.property.Surface import Surface
from apex.core.property.Vacancy import Vacancy
+from apex.core.property.Phonon import Phonon
from apex.utils import sepline, get_task_type
from dflow.python import upload_packages
upload_packages.append(__file__)
@@ -36,6 +37,8 @@ def make_property_instance(parameters, inter_param):
return Surface(parameters, inter_param)
elif prop_type == "gamma":
return Gamma(parameters, inter_param)
+ elif prop_type == "phonon":
+ return Phonon(parameters, inter_param)
else:
raise RuntimeError(f"unknown dflowautotest type {prop_type}")
diff --git a/apex/core/gen_confs.py b/apex/core/gen_confs.py
index 6e8e9c1..9029757 100644
--- a/apex/core/gen_confs.py
+++ b/apex/core/gen_confs.py
@@ -7,7 +7,7 @@
from pymatgen.analysis.structure_matcher import StructureMatcher
from pymatgen.ext.matproj import Composition, MPRester
-import apex.core.lib.crys as crys
+from apex.core.lib import crys
from dflow.python import upload_packages
upload_packages.append(__file__)
diff --git a/apex/core/lib/util.py b/apex/core/lib/util.py
index d18bf2f..32831dc 100644
--- a/apex/core/lib/util.py
+++ b/apex/core/lib/util.py
@@ -5,13 +5,14 @@
import requests
#from dpgen import dlog
-from apex.core.calculator.lib import abacus, lammps, vasp
+from apex.core.calculator.lib import abacus_utils, lammps_utils, vasp_utils
from apex.core.lib.utils import cmd_append_log
from dflow.python import upload_packages
upload_packages.append(__file__)
lammps_task_type = ["deepmd", "meam", "eam_fs", "eam_alloy"] # 06/13 revised
+
def voigt_to_stress(inpt):
ret = np.zeros((3, 3))
ret[0][0] = inpt[0]
@@ -98,13 +99,13 @@ def collect_task(all_task, task_type):
if task_type == "vasp":
output_file = "OUTCAR"
- check_finished = vasp.check_finished
+ check_finished = vasp_utils.check_finished
elif task_type in lammps_task_type:
output_file = "log.lammps"
- check_finished = lammps.check_finished
+ check_finished = lammps_task_type.check_finished
elif task_type == "abacus":
output_file = "OUT.ABACUS/running_relax.log"
- check_finished = abacus.check_finished
+ check_finished = abacus_utils.check_finished
run_tasks_ = []
for ii in all_task:
diff --git a/apex/core/mpdb.py b/apex/core/mpdb.py
index e986fbc..a38cab6 100644
--- a/apex/core/mpdb.py
+++ b/apex/core/mpdb.py
@@ -1,6 +1,5 @@
import os
-from pymatgen.core import Structure
from pymatgen.ext.matproj import MPRester, MPRestError
from dflow.python import upload_packages
upload_packages.append(__file__)
diff --git a/apex/core/property/EOS.py b/apex/core/property/EOS.py
index b17a5d0..896437a 100644
--- a/apex/core/property/EOS.py
+++ b/apex/core/property/EOS.py
@@ -7,9 +7,9 @@
import numpy as np
from monty.serialization import dumpfn, loadfn
-import apex.core.calculator.lib.abacus as abacus
-import apex.core.calculator.lib.vasp as vasp
-import apex.core.calculator.lib.abacus_scf as abacus_scf
+from apex.core.calculator.lib import abacus_utils
+from apex.core.calculator.lib import vasp_utils
+from apex.core.calculator.lib import abacus_scf
from apex.core.property.Property import Property
from apex.core.refine import make_refine
from apex.core.reproduce import make_repro, post_repro
@@ -176,7 +176,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
if self.inter_param["type"] == "abacus":
equi_contcar = os.path.join(
- path_to_equi, abacus.final_stru(path_to_equi)
+ path_to_equi, abacus_utils.final_stru(path_to_equi)
)
else:
equi_contcar = os.path.join(path_to_equi, "CONTCAR")
@@ -193,7 +193,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
/ np.array(stru_data["atom_numbs"]).sum()
)
else:
- vol_to_poscar = vasp.poscar_vol(equi_contcar) / vasp.poscar_natoms(
+ vol_to_poscar = vasp_utils.poscar_vol(equi_contcar) / vasp_utils.poscar_natoms(
equi_contcar
)
self.parameter["scale2equi"] = []
@@ -210,11 +210,11 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
if self.inter_param["type"] == "abacus":
POSCAR = "STRU"
POSCAR_orig = "STRU.orig"
- scale_func = abacus.stru_scale
+ scale_func = abacus_utils.stru_scale
else:
POSCAR = "POSCAR"
POSCAR_orig = "POSCAR.orig"
- scale_func = vasp.poscar_scale
+ scale_func = vasp_utils.poscar_scale
for ii in [
"INCAR",
diff --git a/apex/core/property/Elastic.py b/apex/core/property/Elastic.py
index 5f391d1..e4d94d0 100644
--- a/apex/core/property/Elastic.py
+++ b/apex/core/property/Elastic.py
@@ -11,12 +11,12 @@
from pymatgen.core.structure import Structure
from pymatgen.io.vasp import Incar, Kpoints
-import apex.core.calculator.lib.abacus as abacus
-import apex.core.calculator.lib.vasp as vasp
-import apex.core.calculator.lib.abacus_scf as abacus_scf
+from apex.core.calculator.lib import abacus_utils
+from apex.core.calculator.lib import vasp_utils
+from apex.core.calculator.lib import abacus_scf
from apex.core.property.Property import Property
from apex.core.refine import make_refine
-from apex.core.calculator.lib.vasp import incar_upper
+from apex.core.calculator.lib.vasp_utils import incar_upper
from dflow.python import upload_packages
upload_packages.append(__file__)
@@ -87,7 +87,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
cwd = os.getcwd()
if self.inter_param["type"] == "abacus":
- CONTCAR = abacus.final_stru(path_to_equi)
+ CONTCAR = abacus_utils.final_stru(path_to_equi)
POSCAR = "STRU"
else:
CONTCAR = "CONTCAR"
@@ -153,7 +153,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
raise RuntimeError("please do relaxation first")
if self.inter_param["type"] == "abacus":
- ss = abacus.stru2Structure(equi_contcar)
+ ss = abacus_utils.stru2Structure(equi_contcar)
else:
ss = Structure.from_file(equi_contcar)
dfm_ss = DeformedStructureSet(
@@ -183,7 +183,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
task_list.append(output_task)
dfm_ss.deformed_structures[ii].to("POSCAR", "POSCAR")
if self.inter_param["type"] == "abacus":
- abacus.poscar2stru("POSCAR", self.inter_param, "STRU")
+ abacus_utils.poscar2stru("POSCAR", self.inter_param, "STRU")
os.remove("POSCAR")
# record strain
df = Strain.from_deformation(dfm_ss.deformations[ii])
@@ -209,12 +209,12 @@ def post_process(self, task_list):
input_aba = abacus_scf.get_abacus_input_parameters("INPUT")
if "kspacing" in input_aba:
kspacing = float(input_aba["kspacing"])
- kpt = abacus.make_kspacing_kpt(poscar_start, kspacing)
+ kpt = abacus_utils.make_kspacing_kpt(poscar_start, kspacing)
kpt += [0, 0, 0]
- abacus.write_kpt("KPT", kpt)
+ abacus_utils.write_kpt("KPT", kpt)
del input_aba["kspacing"]
os.remove("INPUT")
- abacus.write_input("INPUT", input_aba)
+ abacus_utils.write_input("INPUT", input_aba)
else:
os.rename(os.path.join(task_list[0], "KPT"), "./KPT")
else:
@@ -223,7 +223,7 @@ def post_process(self, task_list):
)
kspacing = incar.get("KSPACING")
kgamma = incar.get("KGAMMA", False)
- ret = vasp.make_kspacing_kpoints(poscar_start, kspacing, kgamma)
+ ret = vasp_utils.make_kspacing_kpoints(poscar_start, kspacing, kgamma)
kp = Kpoints.from_string(ret)
if os.path.isfile("KPOINTS"):
os.remove("KPOINTS")
diff --git a/apex/core/property/Gamma.py b/apex/core/property/Gamma.py
index 5533b01..d12361f 100644
--- a/apex/core/property/Gamma.py
+++ b/apex/core/property/Gamma.py
@@ -11,8 +11,8 @@
from pymatgen.core.surface import SlabGenerator
from pymatgen.analysis.diffraction.tem import TEMCalculator
-import apex.core.calculator.lib.abacus as abacus
-import apex.core.calculator.lib.vasp as vasp
+from apex.core.calculator.lib import abacus_utils
+from apex.core.calculator.lib import vasp_utils
from apex.core.property.Property import Property
from apex.core.refine import make_refine
from apex.core.reproduce import make_repro, post_repro
@@ -180,7 +180,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
else:
if self.inter_param["type"] == "abacus":
- CONTCAR = abacus.final_stru(path_to_equi)
+ CONTCAR = abacus_utils.final_stru(path_to_equi)
POSCAR = "STRU"
else:
CONTCAR = "CONTCAR"
@@ -197,11 +197,11 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
if self.inter_param["type"] == "abacus":
stru = dpdata.System(equi_contcar, fmt="stru")
stru.to("contcar", "CONTCAR.tmp")
- ptypes = vasp.get_poscar_types("CONTCAR.tmp")
+ ptypes = vasp_utils.get_poscar_types("CONTCAR.tmp")
ss = Structure.from_file("CONTCAR.tmp")
os.remove("CONTCAR.tmp")
else:
- ptypes = vasp.get_poscar_types(equi_contcar)
+ ptypes = vasp_utils.get_poscar_types(equi_contcar)
# read structure from relaxed CONTCAR
ss = Structure.from_file(equi_contcar)
@@ -286,10 +286,10 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
)
# make confs
obtained_slab.to("POSCAR.tmp", "POSCAR")
- vasp.regulate_poscar("POSCAR.tmp", "POSCAR")
- vasp.sort_poscar("POSCAR", "POSCAR", ptypes)
+ vasp_utils.regulate_poscar("POSCAR.tmp", "POSCAR")
+ vasp_utils.sort_poscar("POSCAR", "POSCAR", ptypes)
if self.inter_param["type"] == "abacus":
- abacus.poscar2stru("POSCAR", self.inter_param, "STRU")
+ abacus_utils.poscar2stru("POSCAR", self.inter_param, "STRU")
os.remove("POSCAR")
# vasp.perturb_xz('POSCAR', 'POSCAR', self.pert_xz)
# record miller
diff --git a/apex/core/property/Interstitial.py b/apex/core/property/Interstitial.py
index a6347c1..aab33c1 100644
--- a/apex/core/property/Interstitial.py
+++ b/apex/core/property/Interstitial.py
@@ -9,8 +9,8 @@
from pymatgen.analysis.defects.generators import InterstitialGenerator
from pymatgen.core.structure import Structure
-import apex.core.calculator.lib.abacus as abacus
-import apex.core.calculator.lib.lammps as lammps
+from apex.core.calculator.lib import abacus_utils
+from apex.core.calculator.lib import lammps_utils
from apex.core.property.Property import Property
from apex.core.refine import make_refine
from apex.core.reproduce import make_repro, post_repro
@@ -171,7 +171,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
else:
if self.inter_param["type"] == "abacus":
- CONTCAR = abacus.final_stru(path_to_equi)
+ CONTCAR = abacus_utils.final_stru(path_to_equi)
POSCAR = "STRU"
else:
CONTCAR = "CONTCAR"
@@ -182,7 +182,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
raise RuntimeError("please do relaxation first")
if self.inter_param["type"] == "abacus":
- ss = abacus.stru2Structure(equi_contcar)
+ ss = abacus_utils.stru2Structure(equi_contcar)
else:
ss = Structure.from_file(equi_contcar)
@@ -370,7 +370,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
for ii in range(total_task):
output_task = os.path.join(self.path_to_work, "task.%06d" % ii)
os.chdir(output_task)
- abacus.poscar2stru("POSCAR", self.inter_param, "STRU")
+ abacus_utils.poscar2stru("POSCAR", self.inter_param, "STRU")
os.remove("POSCAR")
os.chdir(cwd)
@@ -424,7 +424,7 @@ def post_process(self, task_list):
conf_line = fin2.read().split("\n")
insert_line = conf_line[-2]
type_map = loadfn(inter)["type_map"]
- type_map_list = lammps.element_list(type_map)
+ type_map_list = lammps_utils.element_list(type_map)
if int(insert_line.split()[1]) > len(type_map_list):
type_num = type_map[insert_ele] + 1
conf_line[2] = str(len(type_map_list)) + " atom types"
diff --git a/apex/core/property/Phonon.py b/apex/core/property/Phonon.py
new file mode 100644
index 0000000..c425b56
--- /dev/null
+++ b/apex/core/property/Phonon.py
@@ -0,0 +1,449 @@
+import glob
+import json
+import logging
+import os
+import shutil
+import re
+import subprocess
+import dpdata
+from pathlib import Path
+from pymatgen.core.structure import Structure
+
+from apex.core.structure import StructureInfo
+from apex.core.calculator.calculator import LAMMPS_TYPE
+from apex.core.calculator.lib import abacus_utils
+from apex.core.calculator.lib import vasp_utils
+from apex.core.property.Property import Property
+from apex.core.refine import make_refine
+from apex.core.reproduce import make_repro, post_repro
+from dflow.python import upload_packages
+upload_packages.append(__file__)
+
+
+class Phonon(Property):
+ def __init__(self, parameter, inter_param=None):
+ parameter["reproduce"] = parameter.get("reproduce", False)
+ self.reprod = parameter["reproduce"]
+ if not self.reprod:
+ if not ("init_from_suffix" in parameter and "output_suffix" in parameter):
+ self.primitive = parameter.get('primitive', False)
+ self.approach = parameter.get('approach', 'linear')
+ self.supercell_size = parameter.get('supercell_size', [2, 2, 2])
+ self.MESH = parameter.get('MESH', None)
+ self.PRIMITIVE_AXES = parameter.get('PRIMITIVE_AXES', None)
+ self.BAND = parameter.get('BAND', None)
+ self.BAND_POINTS = parameter.get('BAND_POINTS', None)
+ self.BAND_CONNECTION = parameter.get('BAND_CONNECTION', True)
+ parameter["cal_type"] = parameter.get("cal_type", "relaxation")
+ self.cal_type = parameter["cal_type"]
+ default_cal_setting = {
+ "relax_pos": True,
+ "relax_shape": False,
+ "relax_vol": False,
+ }
+ if "cal_setting" not in parameter:
+ parameter["cal_setting"] = default_cal_setting
+ else:
+ if "relax_pos" not in parameter["cal_setting"]:
+ parameter["cal_setting"]["relax_pos"] = default_cal_setting[
+ "relax_pos"
+ ]
+ if "relax_shape" not in parameter["cal_setting"]:
+ parameter["cal_setting"]["relax_shape"] = default_cal_setting[
+ "relax_shape"
+ ]
+ if "relax_vol" not in parameter["cal_setting"]:
+ parameter["cal_setting"]["relax_vol"] = default_cal_setting[
+ "relax_vol"
+ ]
+ self.cal_setting = parameter["cal_setting"]
+ else:
+ parameter["cal_type"] = "static"
+ self.cal_type = parameter["cal_type"]
+ default_cal_setting = {
+ "relax_pos": False,
+ "relax_shape": False,
+ "relax_vol": False,
+ }
+ if "cal_setting" not in parameter:
+ parameter["cal_setting"] = default_cal_setting
+ else:
+ if "relax_pos" not in parameter["cal_setting"]:
+ parameter["cal_setting"]["relax_pos"] = default_cal_setting[
+ "relax_pos"
+ ]
+ if "relax_shape" not in parameter["cal_setting"]:
+ parameter["cal_setting"]["relax_shape"] = default_cal_setting[
+ "relax_shape"
+ ]
+ if "relax_vol" not in parameter["cal_setting"]:
+ parameter["cal_setting"]["relax_vol"] = default_cal_setting[
+ "relax_vol"
+ ]
+ self.cal_setting = parameter["cal_setting"]
+ parameter["init_from_suffix"] = parameter.get("init_from_suffix", "00")
+ self.init_from_suffix = parameter["init_from_suffix"]
+ self.parameter = parameter
+ self.inter_param = inter_param if inter_param is not None else {"type": "vasp"}
+
+ def make_confs(self, path_to_work, path_to_equi, refine=False):
+ path_to_work = os.path.abspath(path_to_work)
+ if os.path.exists(path_to_work):
+ #dlog.warning("%s already exists" % path_to_work)
+ logging.warning("%s already exists" % path_to_work)
+ else:
+ os.makedirs(path_to_work)
+ path_to_equi = os.path.abspath(path_to_equi)
+
+ if "start_confs_path" in self.parameter and os.path.exists(
+ self.parameter["start_confs_path"]
+ ):
+ init_path_list = glob.glob(
+ os.path.join(self.parameter["start_confs_path"], "*")
+ )
+ struct_init_name_list = []
+ for ii in init_path_list:
+ struct_init_name_list.append(ii.split("/")[-1])
+ struct_output_name = path_to_work.split("/")[-2]
+ assert struct_output_name in struct_init_name_list
+ path_to_equi = os.path.abspath(
+ os.path.join(
+ self.parameter["start_confs_path"],
+ struct_output_name,
+ "relaxation",
+ "relax_task",
+ )
+ )
+
+ task_list = []
+ cwd = os.getcwd()
+
+ if self.reprod:
+ print("phonon reproduce starts")
+ if "init_data_path" not in self.parameter:
+ raise RuntimeError("please provide the initial data path to reproduce")
+ init_data_path = os.path.abspath(self.parameter["init_data_path"])
+ task_list = make_repro(
+ self.inter_param,
+ init_data_path,
+ self.init_from_suffix,
+ path_to_work,
+ self.parameter.get("reprod_last_frame", True),
+ )
+ os.chdir(cwd)
+
+ else:
+ if refine:
+ print("phonon refine starts")
+ task_list = make_refine(
+ self.parameter["init_from_suffix"],
+ self.parameter["output_suffix"],
+ path_to_work,
+ )
+ os.chdir(cwd)
+
+ else:
+ if self.inter_param["type"] == "abacus":
+ CONTCAR = abacus_utils.final_stru(path_to_equi)
+ POSCAR = "STRU"
+ else:
+ CONTCAR = "CONTCAR"
+ POSCAR = "POSCAR"
+
+ equi_contcar = os.path.join(path_to_equi, CONTCAR)
+ if not os.path.exists(equi_contcar):
+ raise RuntimeError("please do relaxation first")
+
+ if self.inter_param["type"] == "abacus":
+ stru = dpdata.System(equi_contcar, fmt="stru")
+ stru.to("contcar", "CONTCAR.tmp")
+ ptypes = vasp_utils.get_poscar_types("CONTCAR.tmp")
+ ss = Structure.from_file("CONTCAR.tmp")
+ os.remove("CONTCAR.tmp")
+ else:
+ ptypes = vasp_utils.get_poscar_types(equi_contcar)
+ ss = Structure.from_file(equi_contcar)
+ # gen structure
+
+ # get user input parameter for specific structure
+ st = StructureInfo(ss)
+ self.structure_type = st.lattice_structure
+ type_param = self.parameter.get(self.structure_type, None)
+ if type_param:
+ self.primitive = type_param.get("primitive", self.primitive)
+ self.approach = type_param.get("approach", self.approach)
+ self.supercell_size = type_param.get("supercell_size", self.supercell_size)
+ self.MESH = type_param.get("MESH", self.MESH)
+ self.PRIMITIVE_AXES = type_param.get("PRIMITIVE_AXES", self.PRIMITIVE_AXES)
+ self.BAND = type_param.get("BAND", self.BAND)
+ self.BAND_POINTS = type_param.get("BAND_POINTS", self.BAND_POINTS)
+ self.BAND_CONNECTION = type_param.get("BAND_CONNECTION", self.BAND_CONNECTION)
+
+ os.chdir(path_to_work)
+ if os.path.isfile(POSCAR):
+ os.remove(POSCAR)
+ if os.path.islink(POSCAR):
+ os.remove(POSCAR)
+ os.symlink(os.path.relpath(equi_contcar), POSCAR)
+ # task_poscar = os.path.join(output, 'POSCAR')
+
+ if not self.BAND:
+ raise RuntimeError('No band_path input for phonon calculation!')
+ ret = ""
+ ret += "ATOM_NAME ="
+ for ii in ptypes:
+ ret += " %s" % ii
+ ret += "\n"
+ ret += "DIM = %s %s %s\n" % (
+ self.supercell_size[0],
+ self.supercell_size[1],
+ self.supercell_size[2]
+ )
+ if self.MESH:
+ ret += "MESH = %s %s %s\n" % (
+ self.MESH[0], self.MESH[1], self.MESH[2]
+ )
+ if self.PRIMITIVE_AXES:
+ ret += "PRIMITIVE_AXES = %s\n" % self.PRIMITIVE_AXES
+ ret += "BAND = %s\n" % self.BAND
+ if self.BAND_POINTS:
+ ret += "BAND_POINTS = %s\n" % self.BAND_POINTS
+ if self.BAND_CONNECTION:
+ ret += "BAND_CONNECTION = %s\n" % self.BAND_CONNECTION
+
+ ret_force_read = ret + "FORCE_CONSTANTS=READ\n"
+
+ task_list = []
+ # ------------make for abacus---------------
+ if self.inter_param["type"] == "abacus":
+ # make setting.conf
+ ret_sc = ""
+ ret_sc += "DIM=%s %s %s\n" % (
+ self.supercell_size[0],
+ self.supercell_size[1],
+ self.supercell_size[2]
+ )
+ ret_sc += "ATOM_NAME ="
+ for atom in ptypes:
+ ret_sc += " %s" % (atom)
+ ret_sc += "\n"
+ with open("setting.conf", "a") as fp:
+ fp.write(ret_sc)
+ # append NUMERICAL_ORBITAL to STRU after relaxation
+ orb_file = self.inter_param.get("orb_files", None)
+ abacus_utils.append_orb_file_to_stru("STRU", orb_file, prefix='pp_orb')
+ ## generate STRU-00x
+ cmd = "phonopy setting.conf --abacus -d"
+ subprocess.call(cmd, shell=True)
+
+ with open("band.conf", "a") as fp:
+ fp.write(ret)
+ # generate task.000*
+ stru_list = glob.glob("STRU-0*")
+ for ii in range(len(stru_list)):
+ task_path = os.path.join(path_to_work, 'task.%06d' % ii)
+ os.makedirs(task_path, exist_ok=True)
+ os.chdir(task_path)
+ task_list.append(task_path)
+ os.symlink(os.path.join(path_to_work, stru_list[ii]), 'STRU')
+ os.symlink(os.path.join(path_to_work, 'STRU'), 'STRU.ori')
+ os.symlink(os.path.join(path_to_work, 'band.conf'), 'band.conf')
+ os.symlink(os.path.join(path_to_work, 'phonopy_disp.yaml'), 'phonopy_disp.yaml')
+ try:
+ os.symlink(os.path.join(path_to_work, 'KPT'), 'KPT')
+ except:
+ pass
+ os.chdir(cwd)
+ return task_list
+
+ # ------------make for vasp and lammps------------
+ if self.primitive:
+ subprocess.call('phonopy --symmetry', shell=True)
+ subprocess.call('cp PPOSCAR POSCAR', shell=True)
+ shutil.copyfile("PPOSCAR", "POSCAR-unitcell")
+ else:
+ shutil.copyfile("POSCAR", "POSCAR-unitcell")
+
+ # make tasks
+ if self.inter_param["type"] == 'vasp':
+ cmd = "phonopy -d --dim='%d %d %d' -c POSCAR" % (
+ int(self.supercell_size[0]),
+ int(self.supercell_size[1]),
+ int(self.supercell_size[2])
+ )
+ subprocess.call(cmd, shell=True)
+ # linear response method
+ if self.approach == 'linear':
+ task_path = os.path.join(path_to_work, 'task.000000')
+ os.makedirs(task_path, exist_ok=True)
+ os.chdir(task_path)
+ task_list.append(task_path)
+ os.symlink(os.path.join(path_to_work, "SPOSCAR"), "POSCAR")
+ os.symlink(os.path.join(path_to_work, "POSCAR-unitcell"), "POSCAR-unitcell")
+ with open("band.conf", "a") as fp:
+ fp.write(ret_force_read)
+ # finite displacement method
+ elif self.approach == 'displacement':
+ poscar_list = glob.glob("POSCAR-0*")
+ for ii in range(len(poscar_list)):
+ task_path = os.path.join(path_to_work, 'task.%06d' % ii)
+ os.makedirs(task_path, exist_ok=True)
+ os.chdir(task_path)
+ task_list.append(task_path)
+ os.symlink(os.path.join(path_to_work, poscar_list[ii]), 'POSCAR')
+ os.symlink(os.path.join(path_to_work, "POSCAR-unitcell"), "POSCAR-unitcell")
+
+ os.chdir(path_to_work)
+ with open("band.conf", "a") as fp:
+ fp.write(ret)
+ shutil.copyfile("band.conf", "task.000000/band.conf")
+ shutil.copyfile("phonopy_disp.yaml", "task.000000/phonopy_disp.yaml")
+
+ else:
+ raise RuntimeError(
+ f'Unsupported phonon approach input: {self.approach}. '
+ f'Please choose from "linear" and "displacement".'
+ )
+ os.chdir(cwd)
+ return task_list
+ # ----------make for lammps-------------
+ elif self.inter_param["type"] in LAMMPS_TYPE:
+ task_path = os.path.join(path_to_work, 'task.000000')
+ os.makedirs(task_path, exist_ok=True)
+ os.chdir(task_path)
+ task_list.append(task_path)
+ os.symlink(os.path.join(path_to_work, "POSCAR-unitcell"), POSCAR)
+
+ with open("band.conf", "a") as fp:
+ fp.write(ret_force_read)
+ os.chdir(cwd)
+ return task_list
+ else:
+ raise RuntimeError(
+ f'Unsupported interaction type input: {self.inter_param["type"]}'
+ )
+
+ def post_process(self, task_list):
+ cwd = os.getcwd()
+ inter_type = self.inter_param["type"]
+ if inter_type in LAMMPS_TYPE:
+ # prepare in.lammps
+ for ii in task_list:
+ os.chdir(ii)
+ with open("in.lammps", 'r') as f1:
+ contents = f1.readlines()
+ for jj in range(len(contents)):
+ is_pair_coeff = re.search("pair_coeff", contents[jj])
+ if is_pair_coeff:
+ pair_line_id = jj
+ break
+ del contents[pair_line_id + 1:]
+
+ with open("in.lammps", 'w') as f2:
+ for jj in range(len(contents)):
+ f2.write(contents[jj])
+ # dump phonolammps command
+ phonolammps_cmd = "phonolammps in.lammps -c POSCAR --dim %s %s %s " %(
+ self.supercell_size[0], self.supercell_size[1], self.supercell_size[2]
+ )
+ with open("run_command", 'w') as f3:
+ f3.write(phonolammps_cmd)
+ elif inter_type == "vasp":
+ pass
+ elif inter_type == "abacus":
+ pass
+ os.chdir(cwd)
+
+ def task_type(self):
+ return self.parameter["type"]
+
+ def task_param(self):
+ return self.parameter
+
+ def _compute_lower(self, output_file, all_tasks, all_res):
+ cwd = Path.cwd()
+ work_path = Path(output_file).parent
+ output_file = os.path.abspath(output_file)
+ res_data = {}
+ ptr_data = os.path.dirname(output_file) + "\n"
+
+ if not self.reprod:
+ os.chdir(work_path)
+ if self.inter_param["type"] == 'abacus':
+ shutil.copyfile("task.000000/band.conf", "band.conf")
+ shutil.copyfile("task.000000/STRU.ori", "STRU")
+ shutil.copyfile("task.000000/phonopy_disp.yaml", "phonopy_disp.yaml")
+ os.system('phonopy -f task.0*/OUT.ABACUS/running_scf.log')
+ os.system('phonopy -f task.0*/OUT.ABACUS/running_scf.log')
+ if os.path.exists("FORCE_SETS"):
+ print('FORCE_SETS is created')
+ else:
+ print('FORCE_SETS can not be created')
+ os.system('phonopy band.conf --abacus')
+ os.system('phonopy-bandplot --gnuplot band.yaml > band.dat')
+
+ elif self.inter_param["type"] == 'vasp':
+ shutil.copyfile("task.000000/band.conf", "band.conf")
+ shutil.copyfile("task.000000/POSCAR-unitcell", "POSCAR-unitcell")
+
+ if self.approach == "linear":
+ os.chdir(all_tasks[0])
+ assert os.path.isfile('vasprun.xml'), "vasprun.xml not found"
+ os.system('phonopy --fc vasprun.xml')
+ assert os.path.isfile('FORCE_CONSTANTS'), "FORCE_CONSTANTS not created"
+ os.system('phonopy --dim="%s %s %s" -c POSCAR-unitcell band.conf' % (
+ self.supercell_size[0],
+ self.supercell_size[1],
+ self.supercell_size[2]))
+ os.system('phonopy-bandplot --gnuplot band.yaml > band.dat')
+ print('band.dat is created')
+ shutil.copyfile("band.dat", work_path/"band.dat")
+
+ elif self.approach == "displacement":
+ shutil.copyfile("task.000000/band.conf", "band.conf")
+ shutil.copyfile("task.000000/phonopy_disp.yaml", "phonopy_disp.yaml")
+ os.system('phonopy -f task.0*/vasprun.xml')
+ if os.path.exists("FORCE_SETS"):
+ print('FORCE_SETS is created')
+ else:
+ print('FORCE_SETS can not be created')
+ os.system('phonopy --dim="%s %s %s" -c POSCAR-unitcell band.conf' % (
+ self.supercell_size[0],
+ self.supercell_size[1],
+ self.supercell_size[2]))
+ os.system('phonopy-bandplot --gnuplot band.yaml > band.dat')
+
+ elif self.inter_param["type"] in LAMMPS_TYPE:
+ os.chdir(all_tasks[0])
+ assert os.path.isfile('FORCE_CONSTANTS'), "FORCE_CONSTANTS not created"
+ os.system('phonopy --dim="%s %s %s" -c POSCAR band.conf' % (
+ self.supercell_size[0], self.supercell_size[1], self.supercell_size[2])
+ )
+ os.system('phonopy-bandplot --gnuplot band.yaml > band.dat')
+ shutil.copyfile("band.dat", work_path/"band.dat")
+
+ else:
+ if "init_data_path" not in self.parameter:
+ raise RuntimeError("please provide the initial data path to reproduce")
+ init_data_path = os.path.abspath(self.parameter["init_data_path"])
+ res_data, ptr_data = post_repro(
+ init_data_path,
+ self.parameter["init_from_suffix"],
+ all_tasks,
+ ptr_data,
+ self.parameter.get("reprod_last_frame", True),
+ )
+
+ os.chdir(work_path)
+ with open('band.dat', 'r') as f:
+ ptr_data = f.read()
+
+ result_points = ptr_data.split('\n')[1][4:]
+ result_lines = ptr_data.split('\n')[2:]
+ res_data[result_points] = result_lines
+
+ with open(output_file, "w") as fp:
+ json.dump(res_data, fp, indent=4)
+
+ os.chdir(cwd)
+ return res_data, ptr_data
diff --git a/apex/core/property/Surface.py b/apex/core/property/Surface.py
index 4cd4506..cb6f0eb 100644
--- a/apex/core/property/Surface.py
+++ b/apex/core/property/Surface.py
@@ -10,8 +10,8 @@
from pymatgen.core.structure import Structure
from pymatgen.core.surface import generate_all_slabs
-import apex.core.calculator.lib.abacus as abacus
-import apex.core.calculator.lib.vasp as vasp
+from apex.core.calculator.lib import abacus_utils
+from apex.core.calculator.lib import vasp_utils
from apex.core.property.Property import Property
from apex.core.refine import make_refine
from apex.core.reproduce import make_repro, post_repro
@@ -166,7 +166,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
else:
if self.inter_param["type"] == "abacus":
- CONTCAR = abacus.final_stru(path_to_equi)
+ CONTCAR = abacus_utils.final_stru(path_to_equi)
POSCAR = "STRU"
else:
CONTCAR = "CONTCAR"
@@ -179,11 +179,11 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
if self.inter_param["type"] == "abacus":
stru = dpdata.System(equi_contcar, fmt="stru")
stru.to("contcar", "CONTCAR.tmp")
- ptypes = vasp.get_poscar_types("CONTCAR.tmp")
+ ptypes = vasp_utils.get_poscar_types("CONTCAR.tmp")
ss = Structure.from_file("CONTCAR.tmp")
os.remove("CONTCAR.tmp")
else:
- ptypes = vasp.get_poscar_types(equi_contcar)
+ ptypes = vasp_utils.get_poscar_types(equi_contcar)
# gen structure
ss = Structure.from_file(equi_contcar)
@@ -221,11 +221,11 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
)
# make confs
all_slabs[ii].to("POSCAR.tmp", "POSCAR")
- vasp.regulate_poscar("POSCAR.tmp", "POSCAR")
- vasp.sort_poscar("POSCAR", "POSCAR", ptypes)
- vasp.perturb_xz("POSCAR", "POSCAR", self.pert_xz)
+ vasp_utils.regulate_poscar("POSCAR.tmp", "POSCAR")
+ vasp_utils.sort_poscar("POSCAR", "POSCAR", ptypes)
+ vasp_utils.perturb_xz("POSCAR", "POSCAR", self.pert_xz)
if self.inter_param["type"] == "abacus":
- abacus.poscar2stru("POSCAR", self.inter_param, "STRU")
+ abacus_utils.poscar2stru("POSCAR", self.inter_param, "STRU")
os.remove("POSCAR")
# record miller
dumpfn(all_slabs[ii].miller_index, "miller.json")
diff --git a/apex/core/property/Vacancy.py b/apex/core/property/Vacancy.py
index c16af16..e92c2ee 100644
--- a/apex/core/property/Vacancy.py
+++ b/apex/core/property/Vacancy.py
@@ -9,7 +9,7 @@
from pymatgen.analysis.defects.generators import VacancyGenerator
from pymatgen.core.structure import Structure
-import apex.core.calculator.lib.abacus as abacus
+from apex.core.calculator.lib import abacus_utils
from apex.core.property.Property import Property
from apex.core.refine import make_refine
from apex.core.reproduce import make_repro, post_repro
@@ -156,7 +156,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
os.chdir(cwd)
else:
if self.inter_param["type"] == "abacus":
- CONTCAR = abacus.final_stru(path_to_equi)
+ CONTCAR = abacus_utils.final_stru(path_to_equi)
POSCAR = "STRU"
else:
CONTCAR = "CONTCAR"
@@ -167,7 +167,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
raise RuntimeError("please do relaxation first")
if self.inter_param["type"] == "abacus":
- ss = abacus.stru2Structure(equi_contcar)
+ ss = abacus_utils.stru2Structure(equi_contcar)
else:
ss = Structure.from_file(equi_contcar)
@@ -205,7 +205,7 @@ def make_confs(self, path_to_work, path_to_equi, refine=False):
task_list.append(output_task)
dss[ii].to("POSCAR", "POSCAR")
if self.inter_param["type"] == "abacus":
- abacus.poscar2stru("POSCAR", self.inter_param, "STRU")
+ abacus_utils.poscar2stru("POSCAR", self.inter_param, "STRU")
os.remove("POSCAR")
# np.savetxt('supercell.out', self.supercell, fmt='%d')
dumpfn(self.supercell, "supercell.json")
diff --git a/apex/core/refine.py b/apex/core/refine.py
index 3159229..3fb4124 100644
--- a/apex/core/refine.py
+++ b/apex/core/refine.py
@@ -2,7 +2,7 @@
import os
import re
-import apex.core.calculator.lib.abacus as abacus
+from apex.core.calculator.lib import abacus_utils
from dflow.python import upload_packages
upload_packages.append(__file__)
@@ -47,7 +47,7 @@ def make_refine(init_from_suffix, output_suffix, path_to_work):
os.path.join(init_from_task, "STRU")
):
# if there has INPUT and STRU files in this path, we believe this is a ABACUS job
- CONTCAR = abacus.final_stru(init_from_task)
+ CONTCAR = abacus_utils.final_stru(init_from_task)
POSCAR = "STRU"
else:
CONTCAR = "CONTCAR"
diff --git a/apex/core/reproduce.py b/apex/core/reproduce.py
index fb6690e..843d80a 100644
--- a/apex/core/reproduce.py
+++ b/apex/core/reproduce.py
@@ -4,7 +4,7 @@
import numpy as np
from monty.serialization import loadfn
-import apex.core.calculator.lib.abacus as abacus
+from apex.core.calculator.lib import abacus_utils
from dflow.python import upload_packages
upload_packages.append(__file__)
@@ -85,7 +85,7 @@ def make_repro(
else:
task_result.to("vasp/poscar", "POSCAR", frame_idx=jj)
if inter_param["type"] == "abacus":
- abacus.poscar2stru("POSCAR", inter_param, "STRU")
+ abacus_utils.poscar2stru("POSCAR", inter_param, "STRU")
os.remove("POSCAR")
os.chdir(cwd)
diff --git a/apex/flow.py b/apex/flow.py
index 0a3e0ae..8de33eb 100644
--- a/apex/flow.py
+++ b/apex/flow.py
@@ -21,6 +21,9 @@
from apex.op.relaxation_ops import RelaxMake, RelaxPost
from apex.op.property_ops import PropsMake, PropsPost
+from dflow.python import upload_packages
+upload_packages.append(__file__)
+
def json2dict(function):
def wrapper(*args, **kwargs):
diff --git a/apex/main.py b/apex/main.py
index 1980f8a..8113e60 100644
--- a/apex/main.py
+++ b/apex/main.py
@@ -4,9 +4,8 @@
header,
__version__,
)
-from .run_step import run_step
-from .submit import submit_workflow
-
+from apex.run_step import run_step
+from apex.submit import submit_workflow
def parse_args():
diff --git a/apex/op/RunLAMMPS.py b/apex/op/RunLAMMPS.py
index 060256b..7da9460 100644
--- a/apex/op/RunLAMMPS.py
+++ b/apex/op/RunLAMMPS.py
@@ -35,7 +35,11 @@ def get_output_sign(cls):
def execute(self, op_in: OPIO) -> OPIO:
cwd = os.getcwd()
os.chdir(op_in["input_lammps"])
- cmd = op_in["run_command"]
+ if os.path.exists("run_command"):
+ with open("run_command", 'r') as f:
+ cmd = f.read()
+ else:
+ cmd = op_in["run_command"]
exit_code = subprocess.call(cmd, shell=True)
if exit_code == 0:
print("Call Lammps command successfully!")
diff --git a/apex/op/property_ops.py b/apex/op/property_ops.py
index 7fa5444..39be3f7 100644
--- a/apex/op/property_ops.py
+++ b/apex/op/property_ops.py
@@ -1,4 +1,4 @@
-import os, glob, pathlib, shutil, subprocess
+import os, glob, pathlib, shutil, subprocess, logging
from pathlib import Path
from typing import List
from dflow.python import (
@@ -8,13 +8,8 @@
Artifact,
upload_packages
)
-try:
- from monty.serialization import loadfn
- from apex.utils import return_prop_list
- from apex.core.common_prop import make_property_instance
- from .utils import recursive_search
-except:
- pass
+
+from apex.op.utils import recursive_search
upload_packages.append(__file__)
@@ -139,8 +134,8 @@ def execute(
self,
op_in: OPIO,
) -> OPIO:
- from apex.core.common_prop import make_property_instance
- from apex.core.calculator.calculator import make_calculator
+ from ..core.common_prop import make_property_instance
+ from ..core.calculator.calculator import make_calculator
input_work_path = op_in["input_work_path"]
path_to_prop = op_in["path_to_prop"]
@@ -160,7 +155,7 @@ def execute(
poscar = os.path.join(kk, "POSCAR")
inter = make_calculator(inter_param, poscar)
inter.make_potential_files(kk)
- # dlog.debug(prop.task_type()) ### debug
+ logging.debug(prop.task_type()) ### debug
inter.make_input_file(kk, prop.task_type(), prop.task_param())
prop.post_process(
task_list
@@ -169,6 +164,7 @@ def execute(
task_list.sort()
os.chdir(input_work_path)
task_list_str = glob.glob(path_to_prop + '/' + 'task.*')
+ task_list_str.sort()
all_jobs = task_list
njobs = len(all_jobs)
@@ -213,7 +209,7 @@ def get_output_sign(cls):
@OP.exec_sign_check
def execute(self, op_in: OPIO) -> OPIO:
- from apex.core.common_prop import make_property_instance
+ from ..core.common_prop import make_property_instance
cwd = os.getcwd()
input_post = op_in["input_post"]
input_all = op_in["input_all"]
diff --git a/apex/op/relaxation_ops.py b/apex/op/relaxation_ops.py
index f2de913..3210b34 100644
--- a/apex/op/relaxation_ops.py
+++ b/apex/op/relaxation_ops.py
@@ -8,13 +8,8 @@
Artifact,
upload_packages
)
-try:
- from monty.serialization import loadfn
- from apex.utils import return_prop_list
- from apex.core.common_equi import (make_equi, post_equi)
- from .utils import recursive_search
-except:
- pass
+
+from apex.op.utils import recursive_search
upload_packages.append(__file__)
@@ -48,7 +43,7 @@ def execute(
self,
op_in: OPIO,
) -> OPIO:
- from apex.core.common_equi import make_equi
+ from ..core.common_equi import make_equi
cwd = os.getcwd()
os.chdir(op_in["input"])
@@ -113,7 +108,7 @@ def get_output_sign(cls):
@OP.exec_sign_check
def execute(self, op_in: OPIO) -> OPIO:
- from apex.core.common_equi import post_equi
+ from ..core.common_equi import post_equi
cwd = os.getcwd()
param_argv = op_in['param']
inter_param = param_argv["interaction"]
diff --git a/apex/submit.py b/apex/submit.py
index 17c2e00..61eb343 100644
--- a/apex/submit.py
+++ b/apex/submit.py
@@ -1,14 +1,15 @@
import glob
+import os.path
import tempfile
from typing import Type
from multiprocessing import Pool
from dflow import config, s3_config
from dflow.python import OP
from monty.serialization import loadfn
-import fpop, dpdata, apex
+import fpop, dpdata, apex, phonolammps
from apex.utils import get_task_type, get_flow_type
-from .config import Config
-from .flow import FlowFactory
+from apex.config import Config
+from apex.flow import FlowFactory
def judge_flow(parameter, specify) -> (Type[OP], str, str, dict, dict):
@@ -160,8 +161,9 @@ def submit_workflow(
executor = wf_config.get_executor(wf_config.dispatcher_config_dict)
upload_python_packages = wf_config.basic_config_dict["upload_python_packages"]
upload_python_packages.extend(list(apex.__path__))
- upload_python_packages.extend(list(dpdata.__path__))
upload_python_packages.extend(list(fpop.__path__))
+ upload_python_packages.extend(list(dpdata.__path__))
+ upload_python_packages.extend(list(phonolammps.__path__))
flow = FlowFactory(
make_image=make_image,
@@ -178,7 +180,7 @@ def submit_workflow(
# submit the workflows
work_dir_list = []
for ii in work_dir:
- glob_list = glob.glob(ii)
+ glob_list = glob.glob(os.path.abspath(ii))
work_dir_list.extend(glob_list)
if len(work_dir_list) > 1:
n_processes = len(work_dir_list)
@@ -193,5 +195,7 @@ def submit_workflow(
pool.join()
elif len(work_dir_list) == 1:
submit(flow, flow_type, work_dir_list[0], relax_param, props_param, labels=labels)
+ else:
+ raise RuntimeError('Empty work directory indicated, please check your argument')
print('Completed!')
diff --git a/apex/superop/PropertyFlow.py b/apex/superop/PropertyFlow.py
index 6f82568..79cc029 100644
--- a/apex/superop/PropertyFlow.py
+++ b/apex/superop/PropertyFlow.py
@@ -143,6 +143,7 @@ def _build(
name="Distributor",
template=PythonOPTemplate(DistributeProps,
image=make_image,
+ python_packages=upload_python_packages,
command=["python3"]),
artifacts={"input_work_path": self.inputs.artifacts["input_work_path"]},
parameters={"param": self.inputs.parameters["parameter"]},
@@ -199,6 +200,7 @@ def _build(
name="PropsCollector",
template=PythonOPTemplate(CollectProps,
image=make_image,
+ python_packages=upload_python_packages,
command=["python3"]),
artifacts={"input_all": self.inputs.artifacts["input_work_path"],
"input_post": propscal.outputs.artifacts["output_post"]},
diff --git a/apex/superop/RelaxationFlow.py b/apex/superop/RelaxationFlow.py
index 9a8799e..eeefc23 100644
--- a/apex/superop/RelaxationFlow.py
+++ b/apex/superop/RelaxationFlow.py
@@ -142,6 +142,7 @@ def _build(
name="Relaxmake",
template=PythonOPTemplate(make_op,
image=make_image,
+ python_packages=upload_python_packages,
command=["python3"]),
artifacts={"input": self.inputs.artifacts["input_work_path"]},
parameters={"param": self.inputs.parameters["parameter"]},
@@ -211,6 +212,7 @@ def _build(
pool_size=pool_size
),
image=run_image,
+ python_packages=upload_python_packages,
command=["python3"]
)
runcal = Step(
diff --git a/apex/superop/SimplePropertySteps.py b/apex/superop/SimplePropertySteps.py
index e56bd94..d10e918 100644
--- a/apex/superop/SimplePropertySteps.py
+++ b/apex/superop/SimplePropertySteps.py
@@ -140,8 +140,13 @@ def _build(
):
# Step for property make
make = Step(
- name="prop-make",
- template=PythonOPTemplate(make_op, image=make_image, command=["python3"]),
+ name="Props-make",
+ template=PythonOPTemplate(
+ make_op,
+ image=make_image,
+ python_packages=upload_python_packages,
+ command=["python3"]
+ ),
artifacts={"input_work_path": self.inputs.artifacts["input_work_path"]},
parameters={"prop_param": self.inputs.parameters["prop_param"],
"inter_param": self.inputs.parameters["inter_param"],
@@ -173,7 +178,8 @@ def _build(
parameters={
"run_image_config": {"command": run_command},
"task_name": make.outputs.parameters["task_names"],
- "backward_list": ["INCAR", "POSCAR", "OUTCAR", "CONTCAR"]
+ "backward_list": ["INCAR", "POSCAR", "OUTCAR", "CONTCAR",
+ "vasprun.xml"]
},
artifacts={
"task_path": make.outputs.artifacts["task_paths"]
@@ -211,6 +217,7 @@ def _build(
pool_size=pool_size
),
image=run_image,
+ python_packages=upload_python_packages,
command=["python3"]
)
runcal = Step(
@@ -232,6 +239,7 @@ def _build(
template=PythonOPTemplate(
post_op,
image=post_image,
+ python_packages=upload_python_packages,
command=["python3"]
),
artifacts={
diff --git a/docs/Dockerfile b/docs/Dockerfile
index 648eb5f..e105bef 100644
--- a/docs/Dockerfile
+++ b/docs/Dockerfile
@@ -4,6 +4,7 @@ RUN pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip install monty -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip install pymatgen>=2023.8.10 -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip install pymatgen.analysis.defects>=2023.8.22 -i https://pypi.tuna.tsinghua.edu.cn/simple
+RUN pip install phonopy -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip install dpdispatcher -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip install pydflow -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip install urllib3 -i https://pypi.tuna.tsinghua.edu.cn/simple
diff --git a/docs/images/apex_demo.png b/docs/images/apex_demo.png
index 0cf4847..53938bb 100644
Binary files a/docs/images/apex_demo.png and b/docs/images/apex_demo.png differ
diff --git a/docs/images/apex_demo_v1.0.png b/docs/images/apex_demo_v1.0.png
deleted file mode 100644
index b061666..0000000
Binary files a/docs/images/apex_demo_v1.0.png and /dev/null differ
diff --git a/examples/abacus_demo/confs/fcc-Al/STRU b/examples/abacus_demo/confs/fcc-Al/STRU
index 776f55a..22a10ab 100644
--- a/examples/abacus_demo/confs/fcc-Al/STRU
+++ b/examples/abacus_demo/confs/fcc-Al/STRU
@@ -1,20 +1,23 @@
ATOMIC_SPECIES
-Al 26.9815 pp_orb/Al_ONCV_PBE-1.0.upf
+Al 26.982 pp_orb/Al.PD04.PBE.UPF
+
+NUMERICAL_ORBITAL
+pp_orb/Al_gga_10au_100Ry_3s3p2d.orb
LATTICE_CONSTANT
-1.8897261254578281
+1.8897261254578281
LATTICE_VECTORS
-4.05 0.0 0.0
-0.0 4.05 0.0
-0.0 0.0 4.05
+4.04495 0.0 0.0
+0.0 4.04495 0.0
+0.0 0.0 4.04495
ATOMIC_POSITIONS
-Cartesian # Cartesian(Unit is LATTICE_CONSTANT)
+Direct
Al
-0.0
-4
-0.000000000000 0.000000000000 0.000000000000 1 1 1
-0.000000000000 2.025000000000 2.025000000000 1 1 1
-2.025000000000 0.000000000000 2.025000000000 1 1 1
-2.025000000000 2.025000000000 0.000000000000 1 1 1
+0.0
+4
+0.00 0.00 0.00 1 1 1
+0.50 0.50 0.00 1 1 1
+0.50 0.00 0.50 1 1 1
+0.00 0.50 0.50 1 1 1
diff --git a/examples/abacus_demo/global_bohrium.json b/examples/abacus_demo/global_bohrium.json
index 7885beb..c7d5f99 100644
--- a/examples/abacus_demo/global_bohrium.json
+++ b/examples/abacus_demo/global_bohrium.json
@@ -4,10 +4,10 @@
"email": "YOUR_EMAIL",
"password": "YOUR_PASSWD",
"program_id": 1234,
- "apex_image_name":"registry.dp.tech/dptech/prod-11045/apex-dependency:1.0",
- "abacus_image_name":"registry.dp.tech/dptech/prod-11461/abacus:phonopy",
- "abacus_run_command":"ulimit -s unlimited && ulimit -m unlimited && OMP_NUM_THREADS=1 mpirun -np 32 abacus > log",
+ "apex_image_name":"registry.dp.tech/dptech/prod-11045/apex-dependency:1.1.0",
+ "abacus_image_name":"registry.dp.tech/dptech/abacus:3.2.3",
+ "abacus_run_command":"mpirun -n 32 abacus",
"batch_type": "Bohrium",
"context_type": "Bohrium",
- "scass_type":"c32_m64_cpu"
+ "scass_type":"c64_m128_cpu"
}
diff --git a/examples/abacus_demo/param_props.json b/examples/abacus_demo/param_props.json
index 152f80b..208f11a 100644
--- a/examples/abacus_demo/param_props.json
+++ b/examples/abacus_demo/param_props.json
@@ -1,16 +1,16 @@
{
- "structures": ["confs/fcc-Al"],
- "interaction": {
- "type": "abacus",
- "incar": "abacus_input/INPUT",
- "potcar_prefix": "abacus_input",
- "potcars": {"Al": "Al_ONCV_PBE-1.0.upf"},
- "orb_files": {"Al":"Al_gga_9au_100Ry_4s4p1d.orb"}
- },
+ "structures": ["confs/fcc-Al"],
+ "interaction": {
+ "type": "abacus",
+ "incar": "abacus_input/INPUT_phonon",
+ "potcar_prefix": "abacus_input",
+ "potcars": {"Al": "Al.PD04.PBE.UPF"},
+ "orb_files": {"Al":"Al_gga_10au_100Ry_3s3p2d.orb"}
+ },
"properties": [
{
"type": "eos",
- "skip": false,
+ "skip": true,
"vol_start": 0.6,
"vol_end": 1.4,
"vol_step": 0.05
@@ -23,7 +23,7 @@
},
{
"type": "surface",
- "skip": false,
+ "skip": true,
"min_slab_size": 10,
"min_vacuum_size":11,
"max_miller": 2,
@@ -49,6 +49,21 @@
"vacuum_size": 15,
"add_fix": ["true","true","false"],
"n_steps": 20
+ },
+ {
+ "type": "phonon",
+ "skip": false,
+ "BAND": "0.5000 0.5000 0.5000 0.0000 0.0000 0.0000 0.5000 0.0000 0.5000 0.5000 0.2500 0.7500",
+ "supercell_size":[1,1,1],
+ "MESH":[8,8,8],
+ "PRIMITIVE_AXES": "0 1/2 1/2 1/2 0 1/2 1/2 1/2 0",
+ "BAND_POINTS":21,
+ "BAND_CONNECTION" :true,
+ "cal_setting": {
+ "K_POINTS": [6,6,6,0,0,0],
+ "input_prop": "abacus_input/INPUT_phonon"
}
+ }
+
]
}
diff --git a/examples/abacus_demo/param_relax.json b/examples/abacus_demo/param_relax.json
index 115ed6e..6919b20 100644
--- a/examples/abacus_demo/param_relax.json
+++ b/examples/abacus_demo/param_relax.json
@@ -4,8 +4,9 @@
"type": "abacus",
"incar": "abacus_input/INPUT",
"potcar_prefix": "abacus_input",
- "potcars": {"Al": "Al_ONCV_PBE-1.0.upf"},
- "orb_files": {"Al":"Al_gga_9au_100Ry_4s4p1d.orb"}
+ "potcars": {"Al": "Al.PD04.PBE.UPF"},
+ "orb_files": {"Al":"Al_gga_10au_100Ry_3s3p2d.orb"}
+
},
"relaxation": {
"cal_type": "relaxation",
diff --git a/examples/lammps_demo/global_bohrium.json b/examples/lammps_demo/global_bohrium.json
index 15eecb1..db9dcfa 100644
--- a/examples/lammps_demo/global_bohrium.json
+++ b/examples/lammps_demo/global_bohrium.json
@@ -1,15 +1,15 @@
{
"dflow_host": "https://workflows.deepmodeling.com",
"k8s_api_server": "https://workflows.deepmodeling.com",
- "email": "YOUR@EMAIL",
- "password": "YOURPASSWD",
+ "email": "YOUR_EMAIL",
+ "password": "YOUR_PASSWD",
"program_id": 1234,
- "apex_image_name":"registry.dp.tech/dptech/prod-11045/apex-dependency:1.0",
- "lammps_image_name": "registry.dp.tech/dptech/prod-11045/deepmd-kit:deepmd-kit2.1.1_cuda11.6_gpu",
- "group_size": 2,
+ "apex_image_name":"registry.dp.tech/dptech/prod-11045/apex-dependency:1.1.0",
+ "lammps_image_name": "registry.dp.tech/dptech/prod-11461/phonopy:v1.2",
+ "group_size": 4,
"pool_size": 1,
"run_command":"lmp -in in.lammps",
"batch_type": "Bohrium",
"context_type": "Bohrium",
- "scass_type":"c8_m31_1 * NVIDIA T4"
+ "scass_type":"c16_m62_1 * NVIDIA T4"
}
diff --git a/examples/lammps_demo/param_joint.json b/examples/lammps_demo/param_joint.json
index 46c6b82..6de5dc4 100644
--- a/examples/lammps_demo/param_joint.json
+++ b/examples/lammps_demo/param_joint.json
@@ -1,5 +1,5 @@
{
- "structures": ["confs/std-*"],
+ "structures": ["confs/std-bcc"],
"interaction": {
"type": "deepmd",
"model": "frozen_model.pb",
@@ -23,7 +23,7 @@
},
{
"type": "elastic",
- "skip": false,
+ "skip": true,
"norm_deform": 1e-2,
"shear_deform": 1e-2,
"cal_setting": {"etol": 0,
@@ -44,7 +44,6 @@
"insert_ele": ["Mo"]
},
{
- "type": "vacancy",
"skip": true,
"supercell": [2, 2, 2]
},
@@ -62,7 +61,13 @@
"vacuum_size": 15,
"add_fix": ["true","true","false"],
"n_steps": 20
- }
+ },
+ {
+ "type": "phonon",
+ "skip": false,
+ "BAND": "0.0000 0.0000 0.5000 0.0000 0.0000 0.0000 0.5000 -0.5000 0.5000 0.25000 0.2500 0.2500 0 0 0",
+ "supercell_size":[4,4,4],
+ "PRIMITIVE_AXES": "Auto"
+ }
]
-
}
diff --git a/examples/vasp_demo/global_bohrium.json b/examples/vasp_demo/global_bohrium.json
index ee1a079..64fef43 100644
--- a/examples/vasp_demo/global_bohrium.json
+++ b/examples/vasp_demo/global_bohrium.json
@@ -4,8 +4,8 @@
"email": "YOUR_EMAIL",
"password": "YOUR_PASSWD",
"program_id": 1234,
- "group_size": 2,
- "apex_image_name":"registry.dp.tech/dptech/prod-11045/apex-dependency:1.0",
+ "group_size": 1,
+ "apex_image_name":"registry.dp.tech/dptech/prod-11045/apex-dependency:1.1.0",
"vasp_image_name":"registry.dp.tech/dptech/vasp:5.4.4-dflow",
"vasp_run_command":"bash -c \"source /opt/intel/oneapi/setvars.sh && ulimit -s unlimited && mpirun -n 32 /opt/vasp.5.4.4/bin/vasp_std \"",
"batch_type": "Bohrium",
diff --git a/examples/vasp_demo/param_props.json b/examples/vasp_demo/param_props.json
index 4a8ae7d..c5c64be 100644
--- a/examples/vasp_demo/param_props.json
+++ b/examples/vasp_demo/param_props.json
@@ -1,5 +1,5 @@
{
- "structures": ["confs/std-*"],
+ "structures": ["confs/std-bcc"],
"interaction": {
"type": "vasp",
"incar": "vasp_input/INCAR",
@@ -9,14 +9,14 @@
"properties": [
{
"type": "eos",
- "skip": false,
+ "skip": true,
"vol_start": 0.6,
"vol_end": 1.4,
"vol_step": 0.4
},
{
"type": "eos",
- "skip": false,
+ "skip": true,
"suffix": "4_step",
"vol_start": 0.6,
"vol_end": 1.4,
@@ -56,6 +56,21 @@
"vacuum_size": 15,
"add_fix": ["true","true","false"],
"n_steps": 20
- }
+ },
+ {
+ "type": "phonon",
+ "skip": false,
+ "suffix": "linear",
+ "BAND": "0.0000 0.0000 0.5000 0.0000 0.0000 0.0000 0.5000 -0.5000 0.5000 0.25000 0.2500 0.2500 0 0 0",
+ "supercell_size":[2,2,2]
+ },
+ {
+ "type": "phonon",
+ "skip": false,
+ "suffix": "displacement",
+ "approach": "displacement",
+ "BAND": "0.0000 0.0000 0.5000 0.0000 0.0000 0.0000 0.5000 -0.5000 0.5000 0.25000 0.2500 0.2500 0 0 0",
+ "supercell_size":[2,2,2]
+ }
]
}
diff --git a/examples/vasp_demo/param_relax.json b/examples/vasp_demo/param_relax.json
index b2e9a50..4141a86 100644
--- a/examples/vasp_demo/param_relax.json
+++ b/examples/vasp_demo/param_relax.json
@@ -1,5 +1,5 @@
{
- "structures": ["confs/std-*"],
+ "structures": ["confs/std-bcc"],
"interaction": {
"type": "vasp",
"incar": "vasp_input/INCAR",
diff --git a/setup.py b/setup.py
index 4697ffe..849dfe9 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@
setuptools.setup(
name="apex-flow",
- version="1.0.2",
+ version="1.1.1",
author="Zhuoyuan Li, Tongqi Wen",
author_email="zhuoyli@outlook.com",
description="Alloy Properties EXplorer using simulations",
@@ -19,6 +19,8 @@
'pymatgen-analysis-defects>=2023.8.22',
"dpdata>=0.2.13",
"dpdispatcher",
+ "phonoLAMMPS",
+ "phonopy",
"matplotlib",
"seekpath",
"fpop>=0.0.7",
diff --git a/tests/context.py b/tests/context.py
index c858012..ecc35c3 100644
--- a/tests/context.py
+++ b/tests/context.py
@@ -1,6 +1,6 @@
import os
import sys
-from apex.core.calculator.lib.vasp import *
+from apex.core.calculator.lib.vasp_utils import *
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
diff --git a/tests/test_abacus.py b/tests/test_abacus.py
index a8de988..d0e29e1 100644
--- a/tests/test_abacus.py
+++ b/tests/test_abacus.py
@@ -7,7 +7,7 @@
from monty.serialization import loadfn
from apex.core.calculator.ABACUS import ABACUS
-from apex.core.calculator.lib import abacus
+from apex.core.calculator.lib import abacus_utils
from apex.core.calculator.lib import abacus_scf
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
@@ -90,7 +90,7 @@ def test_make_input_file_1(self):
self.assertEqual(abacus_input["calculation"].lower(), "cell-relax")
self.assertEqual(abacus_input["fixed_axes"].lower(), "volume")
self.assertTrue(
- abacus.check_stru_fixed(os.path.join(self.equi_path, "STRU"), fixed=False)
+ abacus_utils.check_stru_fixed(os.path.join(self.equi_path, "STRU"), fixed=False)
)
def test_make_input_file_2(self):
@@ -109,7 +109,7 @@ def test_make_input_file_2(self):
"fixed_axes" not in abacus_input or abacus_input["fixed_axes"] == "None"
)
self.assertTrue(
- abacus.check_stru_fixed(os.path.join(self.equi_path, "STRU"), fixed=False)
+ abacus_utils.check_stru_fixed(os.path.join(self.equi_path, "STRU"), fixed=False)
)
def test_make_input_file_3(self):
@@ -134,7 +134,7 @@ def test_make_input_file_3(self):
"fixed_axes" not in abacus_input or abacus_input["fixed_axes"] == "None"
)
self.assertTrue(
- abacus.check_stru_fixed(os.path.join(self.equi_path, "STRU"), fixed=False)
+ abacus_utils.check_stru_fixed(os.path.join(self.equi_path, "STRU"), fixed=False)
)
def test_make_input_file_4(self):
@@ -157,7 +157,7 @@ def test_make_input_file_4(self):
self.assertEqual(abacus_input["calculation"].lower(), "cell-relax")
self.assertEqual(abacus_input["fixed_axes"].lower(), "volume")
self.assertTrue(
- abacus.check_stru_fixed(os.path.join(self.equi_path, "STRU"), fixed=True)
+ abacus_utils.check_stru_fixed(os.path.join(self.equi_path, "STRU"), fixed=True)
)
def test_make_input_file_5(self):
@@ -182,7 +182,7 @@ def test_make_input_file_5(self):
"fixed_axes" not in abacus_input or abacus_input["fixed_axes"] == "None"
)
self.assertTrue(
- abacus.check_stru_fixed(os.path.join(self.equi_path, "STRU"), fixed=True)
+ abacus_utils.check_stru_fixed(os.path.join(self.equi_path, "STRU"), fixed=True)
)
def test_make_input_file_kspacing(self):
diff --git a/tests/test_lammps.py b/tests/test_lammps.py
index 38b49af..eda0e3c 100644
--- a/tests/test_lammps.py
+++ b/tests/test_lammps.py
@@ -10,7 +10,7 @@
from monty.serialization import dumpfn, loadfn
from apex.core.calculator.Lammps import Lammps
-from apex.core.calculator.lib.lammps import inter_deepmd
+from apex.core.calculator.lib.lammps_utils import inter_deepmd
#from .context import make_kspacing_kpoints, setUpModule
diff --git a/tests/test_phonon.py b/tests/test_phonon.py
new file mode 100644
index 0000000..2fa5c9b
--- /dev/null
+++ b/tests/test_phonon.py
@@ -0,0 +1,81 @@
+import glob
+import os
+import shutil
+import sys
+import unittest
+
+import dpdata
+import numpy as np
+from monty.serialization import loadfn
+from pymatgen.io.vasp import Incar
+from apex.core.property.Phonon import Phonon
+
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+__package__ = "tests"
+
+
+class TestPhonon(unittest.TestCase):
+ def setUp(self):
+ _jdata = {
+ "structures": ["confs/std-bcc"],
+ "interaction": {
+ "type": "vasp",
+ "potcar_prefix": "vasp_input",
+ "potcars": {"Mo": "POTCAR_Mo"},
+ },
+ "properties": [
+ {
+ "type": "phonon",
+ "skip": False,
+ "BAND": "0.0000 0.0000 0.5000 0.0000 0.0000 0.0000 0.5000 -0.5000 0.5000 0.25000 0.2500 0.2500 0 0 0",
+ "supercell_matrix": [2, 2, 2]
+ },
+ ],
+ }
+
+ self.equi_path = "confs/hp-Mo/relaxation/relax_task"
+ self.source_path = "equi/vasp"
+ self.target_path = "confs/hp-Mo/phonon_00"
+ self.res_data = "output/phonon_00/result.json"
+ self.ptr_data = "output/phonon_00/result.out"
+
+ if not os.path.exists(self.equi_path):
+ os.makedirs(self.equi_path)
+ if not os.path.exists(self.target_path):
+ os.makedirs(self.target_path)
+
+ self.confs = _jdata["structures"]
+ self.inter_param = _jdata["interaction"]
+ self.prop_param = _jdata["properties"]
+
+ self.phonon = Phonon(_jdata["properties"][0])
+
+ def tearDown(self):
+ if os.path.exists(self.equi_path):
+ shutil.rmtree(self.equi_path)
+ if os.path.exists(self.target_path):
+ shutil.rmtree(self.target_path)
+ if os.path.exists(self.res_data):
+ os.remove(self.res_data)
+ if os.path.exists(self.ptr_data):
+ os.remove(self.ptr_data)
+
+ def test_task_type(self):
+ self.assertEqual("phonon", self.phonon.task_type())
+
+ def test_task_param(self):
+ self.assertEqual(self.prop_param[0], self.phonon.task_param())
+
+ def test_make_phonon_conf(self):
+ if not os.path.exists(os.path.join(self.equi_path, "CONTCAR")):
+ with self.assertRaises(RuntimeError):
+ self.phonon.make_confs(self.target_path, self.equi_path)
+ shutil.copy(
+ os.path.join(self.source_path, "CONTCAR_Mo_bcc"),
+ os.path.join(self.equi_path, "CONTCAR"),
+ )
+ task_list = self.phonon.make_confs(self.target_path, self.equi_path)
+ dfm_dirs = glob.glob(os.path.join(self.target_path, "task.*"))
+ self.assertEqual(len(dfm_dirs), 1)
+ self.assertTrue(os.path.isfile(os.path.join(self.target_path, "phonopy_disp.yaml")))
+ self.assertTrue(os.path.isfile(os.path.join(self.target_path, "task.000000/band.conf")))
diff --git a/tests/test_vasp.py b/tests/test_vasp.py
index 16163c2..4f67ba8 100644
--- a/tests/test_vasp.py
+++ b/tests/test_vasp.py
@@ -13,7 +13,7 @@
__package__ = "tests"
from apex.core.calculator.VASP import VASP
-from apex.core.calculator.lib.vasp import incar_upper
+from apex.core.calculator.lib.vasp_utils import incar_upper
class TestVASP(unittest.TestCase):