From f82f3cd55417d6890c33f24cb54770c5695ea02f Mon Sep 17 00:00:00 2001 From: hztttt <940755193@qq.com> Date: Wed, 13 Mar 2024 19:39:52 +0800 Subject: [PATCH 1/9] add deltaspin poscar support --- .DS_Store | Bin 8196 -> 0 bytes dpdata/data_type.py | 6 ++ dpdata/plugins/vasp_deltaspin.py | 138 ++++++++++++++++++++++++++++++ dpdata/system.py | 20 +++++ dpdata/vasp_deltaspin/__init__.py | 0 dpdata/vasp_deltaspin/poscar.py | 116 +++++++++++++++++++++++++ 6 files changed, 280 insertions(+) delete mode 100644 .DS_Store create mode 100644 dpdata/plugins/vasp_deltaspin.py create mode 100644 dpdata/vasp_deltaspin/__init__.py create mode 100644 dpdata/vasp_deltaspin/poscar.py diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 2e4079314f0b25fae89affecb6ac29a2a3d5a047..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHM&2Jk;6n~St&AOrKCe0TWNGp6nYH&jmRYVBYbrM1NN*YHcQCr;onAqE{XRO_I z++aoW6_5~TkoXIbIMRQBBUcVw_y;&}LgGZ<%P$5A-n@AqGrxJW>)8MR zsdl`#0Tuwjz$&OYfz263jEg!{#uCXiQiArd6>!%HxPyIjNLvdu0vZ90fJQ(gpb_{# zAb{^|QH*om`)X9T8Uc;KONoGZK3G@IgVEn{l22g9EgmJev-%}xuKBc;z2B_4y2-}ZZ!fLfnfy1 z-Ms*1Xn+rK?*4uU$IAc8A`RzKJ$MTo2*8FGP~?5IX22noJ<%RPl=Jmd&e!;@MYG-2QY`)If%%e>^nUjmNYvCWR5$7v<3=ZYI%Wy2$5#+r6lk+x(-o(mm z@X$vSIS;+K5TX1`4`Yp-heB#G7zqT*KV(q8gnDhPHpa1Yx&p;>b)9b1PQJeU?6dCj1dn&hDNNLViBv0P5uU28n6|dqA;*YEc%ru3LM^&S!wBh+{r-U+hBj-^>hZ(C zc4)B8syvQ)OK1vjxR9NY3Qsapt!=wLYm{#PCDDaaWhZ6cRE!BF#Q+X||E=VWnN*Ze zvd1{1#bT-QQ6e$m2Bz(Yc(j_(g>T?H_z|ALFYr7334fCUnImtI8)TKdM{bi3$X&8a zT+$>yd93Wm(qk>2-kCxo>}0k%cc?R(njI+u7gV%`38b6nfBzrpoOCdafJR`n2#~@? zZKH}Y(+7Ayytr#ySRY{(Mdo`(*9Y=cl4@2ZFR24Rrg!UCh36_z62*~_S P(C>f!{+CJk5;o5P3s@$& diff --git a/dpdata/data_type.py b/dpdata/data_type.py index b5141a4e..b1880636 100644 --- a/dpdata/data_type.py +++ b/dpdata/data_type.py @@ -16,6 +16,8 @@ class Axis(Enum): NFRAMES = "nframes" NATOMS = "natoms" NTYPES = "ntypes" + NTYPES_SPIN = 'ntypes_spin' + NSPIN = 'nspin' NBONDS = "nbonds" @@ -66,6 +68,10 @@ def real_shape(self, system: "System") -> Tuple[int]: shape.append(system.get_nframes()) elif ii is Axis.NTYPES: shape.append(system.get_ntypes()) + elif ii is Axis.NTYPES_SPIN: + shape.append(system.get_ntypes_spin()) + elif ii is Axis.NSPIN: + shape.append(system.get_nspin()) elif ii is Axis.NATOMS: shape.append(system.get_natoms()) elif ii is Axis.NBONDS: diff --git a/dpdata/plugins/vasp_deltaspin.py b/dpdata/plugins/vasp_deltaspin.py new file mode 100644 index 00000000..2c52e558 --- /dev/null +++ b/dpdata/plugins/vasp_deltaspin.py @@ -0,0 +1,138 @@ +import numpy as np +import re + +import dpdata.vasp_deltaspin.outcar +import dpdata.vasp_deltaspin.poscar +import dpdata.vasp_deltaspin.xml +from dpdata.format import Format +from dpdata.utils import uniq_atom_names + + +@Format.register("vasp_deltaspin/poscar") +@Format.register("vasp_deltaspin/contcar") +class VASPPoscarFormat(Format): + @Format.post("rot_lower_triangular") + def from_system(self, file_name, **kwargs): + with open(file_name) as fp: + lines = [line.rstrip("\n") for line in fp] + with open(file_name[:-6] + 'INCAR') as fp: + lines_incar = [line.rstrip("\n") for line in fp] + data = dpdata.vasp_deltaspin.poscar.to_system_data(lines, lines_incar) + data = uniq_atom_names(data) + return data + + def to_system(self, data, file_name, frame_idx=0, **kwargs): + """Dump the system in vasp POSCAR format. + + Parameters + ---------- + data : dict + The system data + file_name : str + The output file name + frame_idx : int + The index of the frame to dump + **kwargs : dict + other parameters + """ + w_str, m_str = VASPStringFormat().to_system(data, frame_idx=frame_idx) + with open(file_name, "w") as fp: + fp.write(w_str) + + with open(file_name[:-6] + 'INCAR') as fp: + tmp_incar = fp.read() + res_incar = re.sub(r'MAGMOM[\s\S]*?\n\nM_CONST[\s\S]*?\n\n', m_str, tmp_incar, re.S) + with open(file_name[:-6] + 'INCAR', 'w') as fp: + fp.write(res_incar) + + +@Format.register("vasp/string") +class VASPStringFormat(Format): + def to_system(self, data, frame_idx=0, **kwargs): + """Dump the system in vasp POSCAR format string. + + Parameters + ---------- + data : dict + The system data + frame_idx : int + The index of the frame to dump + **kwargs : dict + other parameters + """ + assert frame_idx < len(data["coords"]) + return dpdata.vasp_deltaspin.poscar.from_system_data(data, frame_idx) + + +# rotate the system to lammps convention +@Format.register("outcar") +@Format.register("vasp/outcar") +class VASPOutcarFormat(Format): + @Format.post("rot_lower_triangular") + def from_labeled_system( + self, file_name, begin=0, step=1, convergence_check=True, **kwargs + ): + data = {} + ml = kwargs.get("ml", False) + ( + data["atom_names"], + data["atom_numbs"], + data["atom_types"], + data["cells"], + data["coords"], + data["energies"], + data["forces"], + tmp_virial, + ) = dpdata.vasp.outcar.get_frames( + file_name, + begin=begin, + step=step, + ml=ml, + convergence_check=convergence_check, + ) + if tmp_virial is not None: + data["virials"] = tmp_virial + # scale virial to the unit of eV + if "virials" in data: + v_pref = 1 * 1e3 / 1.602176621e6 + for ii in range(data["cells"].shape[0]): + vol = np.linalg.det(np.reshape(data["cells"][ii], [3, 3])) + data["virials"][ii] *= v_pref * vol + data = uniq_atom_names(data) + return data + + +# rotate the system to lammps convention +@Format.register("xml") +@Format.register("vasp/xml") +class VASPXMLFormat(Format): + @Format.post("rot_lower_triangular") + def from_labeled_system(self, file_name, begin=0, step=1, **kwargs): + data = {} + ( + data["atom_names"], + data["atom_types"], + data["cells"], + data["coords"], + data["energies"], + data["forces"], + tmp_virial, + ) = dpdata.vasp.xml.analyze( + file_name, type_idx_zero=True, begin=begin, step=step + ) + data["atom_numbs"] = [] + for ii in range(len(data["atom_names"])): + data["atom_numbs"].append(sum(data["atom_types"] == ii)) + # the vasp xml assumes the direct coordinates + # apply the transform to the cartesan coordinates + for ii in range(data["cells"].shape[0]): + data["coords"][ii] = np.matmul(data["coords"][ii], data["cells"][ii]) + # scale virial to the unit of eV + if tmp_virial.size > 0: + data["virials"] = tmp_virial + v_pref = 1 * 1e3 / 1.602176621e6 + for ii in range(data["cells"].shape[0]): + vol = np.linalg.det(np.reshape(data["cells"][ii], [3, 3])) + data["virials"][ii] *= v_pref * vol + data = uniq_atom_names(data) + return data diff --git a/dpdata/system.py b/dpdata/system.py index a75e0e88..14a64bf0 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -72,11 +72,14 @@ class System(MSONable): DTYPES = ( DataType("atom_numbs", list, (Axis.NTYPES,)), + DataType("atom_numbs_spin", np.ndarray, (Axis.NTYPES_SPIN,), required=False), DataType("atom_names", list, (Axis.NTYPES,)), + DataType("atom_names_spin", np.ndarray, (Axis.NTYPES_SPIN,), required=False), DataType("atom_types", np.ndarray, (Axis.NATOMS,)), DataType("orig", np.ndarray, (3,)), DataType("cells", np.ndarray, (Axis.NFRAMES, 3, 3)), DataType("coords", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3)), + DataType("spin", np.ndarray, (Axis.NFRAMES, Axis.NSPIN, 3), required=False), DataType( "real_atom_types", np.ndarray, (Axis.NFRAMES, Axis.NATOMS), required=False ), @@ -168,11 +171,14 @@ def __init__( """ self.data = {} self.data["atom_numbs"] = [] + self.data["atom_numbs_spin"] = [] self.data["atom_names"] = [] + self.data["atom_names_spin"] = [] self.data["atom_types"] = [] self.data["orig"] = np.array([0, 0, 0]) self.data["cells"] = [] self.data["coords"] = [] + self.data['spin'] = [] if data: self.data = data @@ -355,6 +361,10 @@ def get_atom_names(self): """Returns name of atoms.""" return self.data["atom_names"] + def get_atom_names_spin(self): + """Returns name of atoms.""" + return self.data["atom_names_spin"] + def get_atom_types(self): """Returns type of atoms.""" return self.data["atom_types"] @@ -371,10 +381,18 @@ def get_natoms(self): """Returns total number of atoms in the system.""" return len(self.data["atom_types"]) + def get_nspin(self): + """Returns total number of magnetic atoms in the system.""" + return sum(self.data['atom_numbs'][:self.get_ntypes_spin()]) + def get_ntypes(self) -> int: """Returns total number of atom types in the system.""" return len(self.data["atom_names"]) + def get_ntypes_spin(self) -> int: + """Returns total number of magnetic atom types in the system.""" + return len(self.data["atom_names_spin"]) + def copy(self): """Returns a copy of the system.""" return self.__class__.from_dict({"data": deepcopy(self.data)}) @@ -1667,3 +1685,5 @@ def to_format(self, *args, **kwargs): add_format_methods() + +# %% diff --git a/dpdata/vasp_deltaspin/__init__.py b/dpdata/vasp_deltaspin/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/dpdata/vasp_deltaspin/poscar.py b/dpdata/vasp_deltaspin/poscar.py new file mode 100644 index 00000000..229a6f75 --- /dev/null +++ b/dpdata/vasp_deltaspin/poscar.py @@ -0,0 +1,116 @@ +#!/usr/bin/python3 + +import numpy as np + + +def _to_system_data_lower(lines, lines_incar, cartesian=True): + """Treat as cartesian poscar.""" + system = {} + system["atom_names"] = [str(ii) for ii in lines[5].split()] + system["atom_numbs"] = [int(ii) for ii in lines[6].split()] + scale = float(lines[1]) + cell = [] + for ii in range(2, 5): + boxv = [float(jj) for jj in lines[ii].split()] + boxv = np.array(boxv) * scale + cell.append(boxv) + system["cells"] = [np.array(cell)] + natoms = sum(system["atom_numbs"]) + coord = [] + for ii in range(8, 8 + natoms): + tmpv = [float(jj) for jj in lines[ii].split()[:3]] + if cartesian: + tmpv = np.array(tmpv) * scale + else: + tmpv = np.matmul(np.array(tmpv), system["cells"][0]) + coord.append(tmpv) + system["coords"] = [np.array(coord)] + system["orig"] = np.zeros(3) + atom_types = [] + for idx, ii in enumerate(system["atom_numbs"]): + for jj in range(ii): + atom_types.append(idx) + system["atom_types"] = np.array(atom_types, dtype=int) + system["cells"] = np.array(system["cells"]) + system["coords"] = np.array(system["coords"]) + + for idx, incar_param in enumerate(lines_incar): + if 'MAGMOM' in incar_param: + start_index = idx + elif 'M_CONSTR' in incar_param: + end_index = idx + spin_idx = np.where(np.cumsum(system['atom_numbs']) <= (end_index - start_index)) + system['atom_numbs_spin'] = np.array(system['atom_numbs'])[spin_idx] + system['atom_names_spin'] = np.array(system['atom_names'])[spin_idx] + system['spin'] = [lines_incar[start_index].strip().split(' ')[1:4]] + for idx in range(start_index+1, end_index-1): + system['spin'].append(lines_incar[idx].strip().split(' ')[:3]) + system['spin'] = np.array([system['spin']]).astype('float64') + return system + + +def to_system_data(lines, lines_incar): + # remove the line that has 'selective dynamics' + if lines[7][0] == "S" or lines[7][0] == "s": + lines.pop(7) + is_cartesian = lines[7][0] in ["C", "c", "K", "k"] + if not is_cartesian: + if lines[7][0] not in ["d", "D"]: + raise RuntimeError( + "seem not to be a valid POSCAR of vasp 5.x, may be a POSCAR of vasp 4.x?" + ) + return _to_system_data_lower(lines, lines_incar, is_cartesian) + + +def from_system_data(system, f_idx=0, skip_zeros=True): + ret = "" + for ii, name in zip(system["atom_numbs"], system["atom_names"]): + if ii == 0: + continue + ret += "%s%d " % (name, ii) + ret += "\n" + ret += "1.0\n" + for ii in system["cells"][f_idx]: + for jj in ii: + ret += "%.16e " % jj + ret += "\n" + for idx, ii in enumerate(system["atom_names"]): + if system["atom_numbs"][idx] == 0: + continue + ret += "%s " % ii + ret += "\n" + for ii in system["atom_numbs"]: + if ii == 0: + continue + ret += "%d " % ii + ret += "\n" + # should use Cartesian for VESTA software + ret += "Cartesian\n" + atype = system["atom_types"] + posis = system["coords"][f_idx] + # atype_idx = [[idx,tt] for idx,tt in enumerate(atype)] + # sort_idx = np.argsort(atype, kind = 'mergesort') + sort_idx = np.lexsort((np.arange(len(atype)), atype)) + atype = atype[sort_idx] + posis = posis[sort_idx] + posi_list = [] + for ii in posis: + posi_list.append(f"{ii[0]:15.10f} {ii[1]:15.10f} {ii[2]:15.10f}") + posi_list.append("") + ret += "\n".join(posi_list) + + magmom_incar = "MAGMOM = " + mconstr_incar = "M_CONSTR = " + for idx, tmp_spin in enumerate(system['spin'][f_idx]): + if idx == 0: + magmom_incar += f"{tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" + mconstr_incar += f"{tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" + elif idx == len(system['spin'] - 1): + magmom_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \n" + mconstr_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \n" + else: + magmom_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" + mconstr_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" + magmom_incar += '\n' + mconstr_incar + '\n' + + return ret, magmom_incar From 3b2a4b901d9efd37f056d852756941ae24096ed9 Mon Sep 17 00:00:00 2001 From: hztttt <940755193@qq.com> Date: Thu, 14 Mar 2024 16:50:22 +0800 Subject: [PATCH 2/9] fix poscar & add outcar and lammps spin support --- dpdata/data_type.py | 6 - dpdata/lammps/dump.py | 44 +++++++ dpdata/lammps/lmp.py | 55 +++++++-- dpdata/plugins/vasp_deltaspin.py | 42 +------ dpdata/system.py | 20 +--- dpdata/vasp_deltaspin/outcar.py | 195 +++++++++++++++++++++++++++++++ dpdata/vasp_deltaspin/poscar.py | 11 +- 7 files changed, 299 insertions(+), 74 deletions(-) create mode 100644 dpdata/vasp_deltaspin/outcar.py diff --git a/dpdata/data_type.py b/dpdata/data_type.py index b1880636..b5141a4e 100644 --- a/dpdata/data_type.py +++ b/dpdata/data_type.py @@ -16,8 +16,6 @@ class Axis(Enum): NFRAMES = "nframes" NATOMS = "natoms" NTYPES = "ntypes" - NTYPES_SPIN = 'ntypes_spin' - NSPIN = 'nspin' NBONDS = "nbonds" @@ -68,10 +66,6 @@ def real_shape(self, system: "System") -> Tuple[int]: shape.append(system.get_nframes()) elif ii is Axis.NTYPES: shape.append(system.get_ntypes()) - elif ii is Axis.NTYPES_SPIN: - shape.append(system.get_ntypes_spin()) - elif ii is Axis.NSPIN: - shape.append(system.get_nspin()) elif ii is Axis.NATOMS: shape.append(system.get_natoms()) elif ii is Axis.NBONDS: diff --git a/dpdata/lammps/dump.py b/dpdata/lammps/dump.py index 906fed9e..0ea6127c 100644 --- a/dpdata/lammps/dump.py +++ b/dpdata/lammps/dump.py @@ -125,6 +125,42 @@ def safe_get_posi(lines, cell, orig=np.zeros(3), unwrap=False): ) # Convert scaled coordinates back to Cartesien coordinates with wraping at periodic boundary conditions +def get_spintype(keys): + key_sp = ["sp", "spx", "spy", "spz"] + key_csp = ["c_spin[1]", "c_spin[2]", "c_spin[3]", "c_spin[4]"] + lmp_sp_type = [key_sp, key_csp] + for k in range(2): + if all(i in keys for i in lmp_sp_type[k]): + return lmp_sp_type[k] + + +def safe_get_spin_force(lines): + blk, head = _get_block(lines, "ATOMS") + keys = head.split() + sp_type = get_spintype(keys) + assert sp_type is not None, "Dump file does not contain spin!" + id_idx = keys.index("id") - 2 + sp = keys.index(sp_type[0]) - 2 + spx = keys.index(sp_type[1]) - 2 + spy = keys.index(sp_type[2]) - 2 + spz = keys.index(sp_type[3]) - 2 + sp_force = [] + for ii in blk: + words = ii.split() + sp_force.append( + [ + float(words[id_idx]), + float(words[sp]), + float(words[spx]), + float(words[spy]), + float(words[spz]), + ] + ) + sp_force.sort() + sp_force = np.array(sp_force)[:, 1:] + return sp_force + + def get_dumpbox(lines): blk, h = _get_block(lines, "BOX BOUNDS") bounds = np.zeros([3, 2]) @@ -209,6 +245,12 @@ def system_data(lines, type_map=None, type_idx_zero=True, unwrap=False): system["cells"] = [np.array(cell)] system["atom_types"] = get_atype(lines, type_idx_zero=type_idx_zero) system["coords"] = [safe_get_posi(lines, cell, np.array(orig), unwrap)] + contain_spin = False + blk, head = _get_block(lines, "ATOMS") + if 'sp' in head: + contain_spin = True + spin_force = safe_get_spin_force(lines) + system['spin'] = [spin_force[:, :1] * spin_force[:, 1:4]] for ii in range(1, len(array_lines)): bounds, tilt = get_dumpbox(array_lines[ii]) orig, cell = dumpbox2box(bounds, tilt) @@ -221,6 +263,8 @@ def system_data(lines, type_map=None, type_idx_zero=True, unwrap=False): system["coords"].append( safe_get_posi(array_lines[ii], cell, np.array(orig), unwrap)[idx] ) + if contain_spin: + system['spin'].append(safe_get_spin_force(array_lines[ii])[:, :1] * safe_get_spin_force(array_lines[ii])[:, 1:4]) system["cells"] = np.array(system["cells"]) system["coords"] = np.array(system["coords"]) return system diff --git a/dpdata/lammps/lmp.py b/dpdata/lammps/lmp.py index 317b30ed..85883d87 100644 --- a/dpdata/lammps/lmp.py +++ b/dpdata/lammps/lmp.py @@ -125,6 +125,17 @@ def get_posi(lines): posis.append([float(jj) for jj in ii.split()[2:5]]) return np.array(posis) +def get_spin(lines): + atom_lines = get_atoms(lines) + if len(atom_lines[0].split()) < 8: + return None + spin_ori = [] + spin_norm = [] + for ii in atom_lines: + spin_ori.append([float(jj) for jj in ii.split()[5:8]]) + spin_norm.append([float(jj) for jj in ii.split()[-1:]]) + spin = np.array(spin_ori) * np.array(spin_norm) + return spin def get_lmpbox(lines): box_info = [] @@ -150,6 +161,9 @@ def get_lmpbox(lines): def system_data(lines, type_map=None, type_idx_zero=True): system = {} system["atom_numbs"] = get_natoms_vec(lines) + spin = get_spin(lines) + if spin is not None: + system['spin'] = np.array([spin]) system["atom_names"] = [] if type_map is None: for ii in range(len(system["atom_numbs"])): @@ -215,14 +229,41 @@ def from_system_data(system, f_idx=0): + ptr_float_fmt + "\n" ) - for ii in range(natoms): - ret += coord_fmt % ( - ii + 1, - system["atom_types"][ii] + 1, - system["coords"][f_idx][ii][0] - system["orig"][0], - system["coords"][f_idx][ii][1] - system["orig"][1], - system["coords"][f_idx][ii][2] - system["orig"][2], + if 'spin' in system.keys(): + coord_fmt = ( + coord_fmt.strip('\n') + + " " + + ptr_float_fmt + + " " + + ptr_float_fmt + + " " + + ptr_float_fmt + + " " + + ptr_float_fmt + + "\n" ) + spin_norm = np.linalg.norm(system['spin'][f_idx], axis=1) + for ii in range(natoms): + if 'spin' in system.keys(): + ret += coord_fmt % ( + ii + 1, + system["atom_types"][ii] + 1, + system["coords"][f_idx][ii][0] - system["orig"][0], + system["coords"][f_idx][ii][1] - system["orig"][1], + system["coords"][f_idx][ii][2] - system["orig"][2], + system['spin'][f_idx][ii][0]/spin_norm[ii], + system['spin'][f_idx][ii][1]/spin_norm[ii], + system['spin'][f_idx][ii][2]/spin_norm[ii], + spin_norm[ii], + ) + else: + ret += coord_fmt % ( + ii + 1, + system["atom_types"][ii] + 1, + system["coords"][f_idx][ii][0] - system["orig"][0], + system["coords"][f_idx][ii][1] - system["orig"][1], + system["coords"][f_idx][ii][2] - system["orig"][2], + ) return ret diff --git a/dpdata/plugins/vasp_deltaspin.py b/dpdata/plugins/vasp_deltaspin.py index 2c52e558..4f96fe72 100644 --- a/dpdata/plugins/vasp_deltaspin.py +++ b/dpdata/plugins/vasp_deltaspin.py @@ -3,7 +3,6 @@ import dpdata.vasp_deltaspin.outcar import dpdata.vasp_deltaspin.poscar -import dpdata.vasp_deltaspin.xml from dpdata.format import Format from dpdata.utils import uniq_atom_names @@ -65,8 +64,7 @@ def to_system(self, data, frame_idx=0, **kwargs): # rotate the system to lammps convention -@Format.register("outcar") -@Format.register("vasp/outcar") +@Format.register("vasp_deltaspin/outcar") class VASPOutcarFormat(Format): @Format.post("rot_lower_triangular") def from_labeled_system( @@ -80,10 +78,12 @@ def from_labeled_system( data["atom_types"], data["cells"], data["coords"], + data['spin'], data["energies"], data["forces"], + data['mag_forces'], tmp_virial, - ) = dpdata.vasp.outcar.get_frames( + ) = dpdata.vasp_deltaspin.outcar.get_frames( file_name, begin=begin, step=step, @@ -102,37 +102,3 @@ def from_labeled_system( return data -# rotate the system to lammps convention -@Format.register("xml") -@Format.register("vasp/xml") -class VASPXMLFormat(Format): - @Format.post("rot_lower_triangular") - def from_labeled_system(self, file_name, begin=0, step=1, **kwargs): - data = {} - ( - data["atom_names"], - data["atom_types"], - data["cells"], - data["coords"], - data["energies"], - data["forces"], - tmp_virial, - ) = dpdata.vasp.xml.analyze( - file_name, type_idx_zero=True, begin=begin, step=step - ) - data["atom_numbs"] = [] - for ii in range(len(data["atom_names"])): - data["atom_numbs"].append(sum(data["atom_types"] == ii)) - # the vasp xml assumes the direct coordinates - # apply the transform to the cartesan coordinates - for ii in range(data["cells"].shape[0]): - data["coords"][ii] = np.matmul(data["coords"][ii], data["cells"][ii]) - # scale virial to the unit of eV - if tmp_virial.size > 0: - data["virials"] = tmp_virial - v_pref = 1 * 1e3 / 1.602176621e6 - for ii in range(data["cells"].shape[0]): - vol = np.linalg.det(np.reshape(data["cells"][ii], [3, 3])) - data["virials"][ii] *= v_pref * vol - data = uniq_atom_names(data) - return data diff --git a/dpdata/system.py b/dpdata/system.py index 14a64bf0..97036c5f 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -72,14 +72,12 @@ class System(MSONable): DTYPES = ( DataType("atom_numbs", list, (Axis.NTYPES,)), - DataType("atom_numbs_spin", np.ndarray, (Axis.NTYPES_SPIN,), required=False), DataType("atom_names", list, (Axis.NTYPES,)), - DataType("atom_names_spin", np.ndarray, (Axis.NTYPES_SPIN,), required=False), DataType("atom_types", np.ndarray, (Axis.NATOMS,)), DataType("orig", np.ndarray, (3,)), DataType("cells", np.ndarray, (Axis.NFRAMES, 3, 3)), DataType("coords", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3)), - DataType("spin", np.ndarray, (Axis.NFRAMES, Axis.NSPIN, 3), required=False), + DataType("spin", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3), required=False), DataType( "real_atom_types", np.ndarray, (Axis.NFRAMES, Axis.NATOMS), required=False ), @@ -171,14 +169,11 @@ def __init__( """ self.data = {} self.data["atom_numbs"] = [] - self.data["atom_numbs_spin"] = [] self.data["atom_names"] = [] - self.data["atom_names_spin"] = [] self.data["atom_types"] = [] self.data["orig"] = np.array([0, 0, 0]) self.data["cells"] = [] self.data["coords"] = [] - self.data['spin'] = [] if data: self.data = data @@ -361,10 +356,6 @@ def get_atom_names(self): """Returns name of atoms.""" return self.data["atom_names"] - def get_atom_names_spin(self): - """Returns name of atoms.""" - return self.data["atom_names_spin"] - def get_atom_types(self): """Returns type of atoms.""" return self.data["atom_types"] @@ -381,18 +372,10 @@ def get_natoms(self): """Returns total number of atoms in the system.""" return len(self.data["atom_types"]) - def get_nspin(self): - """Returns total number of magnetic atoms in the system.""" - return sum(self.data['atom_numbs'][:self.get_ntypes_spin()]) - def get_ntypes(self) -> int: """Returns total number of atom types in the system.""" return len(self.data["atom_names"]) - def get_ntypes_spin(self) -> int: - """Returns total number of magnetic atom types in the system.""" - return len(self.data["atom_names_spin"]) - def copy(self): """Returns a copy of the system.""" return self.__class__.from_dict({"data": deepcopy(self.data)}) @@ -1121,6 +1104,7 @@ class LabeledSystem(System): DTYPES = System.DTYPES + ( DataType("energies", np.ndarray, (Axis.NFRAMES,)), DataType("forces", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3)), + DataType("mag_forces", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3)), DataType("virials", np.ndarray, (Axis.NFRAMES, 3, 3), required=False), DataType("atom_pref", np.ndarray, (Axis.NFRAMES, Axis.NATOMS), required=False), ) diff --git a/dpdata/vasp_deltaspin/outcar.py b/dpdata/vasp_deltaspin/outcar.py new file mode 100644 index 00000000..d0ec375d --- /dev/null +++ b/dpdata/vasp_deltaspin/outcar.py @@ -0,0 +1,195 @@ +import re +import warnings + +import numpy as np + + +def system_info(lines, type_idx_zero=False): + atom_names = [] + atom_numbs = None + nelm = None + for ii in lines: + ii_word_list = ii.split() + if "TITEL" in ii: + # get atom names from POTCAR info, tested only for PAW_PBE ... + _ii = ii.split()[3] + if "_" in _ii: + # for case like : TITEL = PAW_PBE Sn_d 06Sep2000 + atom_names.append(_ii.split("_")[0]) + else: + atom_names.append(_ii) + # a stricker check for "NELM"; compatible with distingct formats in different versions(6 and older, newers_expect-to-work) of vasp + elif nelm is None: + m = re.search(r"NELM\s*=\s*(\d+)", ii) + if m: + nelm = int(m.group(1)) + if "ions per type" in ii: + atom_numbs_ = [int(s) for s in ii.split()[4:]] + if atom_numbs is None: + atom_numbs = atom_numbs_ + else: + assert atom_numbs == atom_numbs_, "in consistent numb atoms in OUTCAR" + assert nelm is not None, "cannot find maximum steps for each SC iteration" + assert atom_numbs is not None, "cannot find ion type info in OUTCAR" + atom_names = atom_names[: len(atom_numbs)] + atom_types = [] + for idx, ii in enumerate(atom_numbs): + for jj in range(ii): + if type_idx_zero: + atom_types.append(idx) + else: + atom_types.append(idx + 1) + return atom_names, atom_numbs, np.array(atom_types, dtype=int), nelm + + +def get_outcar_block(fp, ml=False): + blk = [] + energy_token = ["free energy TOTEN", "free energy ML TOTEN"] + ml_index = int(ml) + for ii in fp: + if not ii: + return blk + blk.append(ii.rstrip("\n")) + if energy_token[ml_index] in ii: + return blk + return blk + + +# we assume that the force is printed ... +def get_frames(fname, begin=0, step=1, ml=False, convergence_check=True): + fp = open(fname) + blk = get_outcar_block(fp) + + atom_names, atom_numbs, atom_types, nelm = system_info(blk, type_idx_zero=True) + ntot = sum(atom_numbs) + + all_coords = [] + all_spins = [] + all_cells = [] + all_energies = [] + all_forces = [] + all_mag_forces = [] + all_virials = [] + + cc = 0 + rec_failed = [] + while len(blk) > 0: + if cc >= begin and (cc - begin) % step == 0: + coord, cell, energy, force, virial, is_converge = analyze_block( + blk, ntot, nelm, ml + ) + if len(coord) == 0: + break + if is_converge or not convergence_check: + all_coords.append(coord) + all_cells.append(cell) + all_energies.append(energy) + all_forces.append(force) + if virial is not None: + all_virials.append(virial) + if not is_converge: + rec_failed.append(cc + 1) + + blk = get_outcar_block(fp, ml) + cc += 1 + + with open(fname[:-6] + 'OSZICAR') as f: + oszicar_blk = f.read() + mag_blk = re.findall(r'Magnetic Force(.*?)\n \n', oszicar_blk, re.S)[-1].split('\n') + mag_force = [list(map(float, ss.split()[-3:])) for ss in mag_blk[1:]] + spin_blk = re.findall(r'MW_current(.*?)\n lambda', oszicar_blk, re.S)[-1].split('\n') + spin = [list(map(float, ss.split()[1:4])) for ss in spin_blk[1:]] + all_mag_forces.append(mag_force) + all_spins.append(spin) + + if len(rec_failed) > 0: + prt = ( + "so they are not collected." + if convergence_check + else "but they are still collected due to the requirement for ignoring convergence checks." + ) + warnings.warn( + f"The following structures were unconverged: {rec_failed}; " + prt + ) + + if len(all_virials) == 0: + all_virials = None + else: + all_virials = np.array(all_virials) + fp.close() + return ( + atom_names, + atom_numbs, + atom_types, + np.array(all_cells), + np.array(all_coords), + np.array(all_spins), + np.array(all_energies), + np.array(all_forces), + np.array(all_mag_forces), + all_virials, + ) + + +def analyze_block(lines, ntot, nelm, ml=False): + coord = [] + cell = [] + energy = None + force = [] + virial = None + is_converge = True + sc_index = 0 + # select different searching tokens based on the ml label + energy_token = ["free energy TOTEN", "free energy ML TOTEN"] + energy_index = [4, 5] + virial_token = ["FORCE on cell =-STRESS in cart. coord. units", "ML FORCE"] + virial_index = [14, 4] + cell_token = ["VOLUME and BASIS", "ML FORCE"] + cell_index = [5, 12] + ml_index = int(ml) + for idx, ii in enumerate(lines): + # if set ml == True, is_converged will always be True + if ("Iteration" in ii) and (not ml): + sc_index = int(ii.split()[3][:-1]) + if sc_index >= nelm: + is_converge = False + elif energy_token[ml_index] in ii: + energy = float(ii.split()[energy_index[ml_index]]) + if len(force) == 0: + raise ValueError("cannot find forces in OUTCAR block") + if len(coord) == 0: + raise ValueError("cannot find coordinates in OUTCAR block") + if len(cell) == 0: + raise ValueError("cannot find cell in OUTCAR block") + return coord, cell, energy, force, virial, is_converge + elif cell_token[ml_index] in ii: + for dd in range(3): + tmp_l = lines[idx + cell_index[ml_index] + dd] + cell.append([float(ss) for ss in tmp_l.replace("-", " -").split()[0:3]]) + elif virial_token[ml_index] in ii: + in_kB_index = virial_index[ml_index] + while idx + in_kB_index < len(lines) and ( + not lines[idx + in_kB_index].split()[0:2] == ["in", "kB"] + ): + in_kB_index += 1 + assert idx + in_kB_index < len( + lines + ), 'ERROR: "in kB" is not found in OUTCAR. Unable to extract virial.' + tmp_v = [float(ss) for ss in lines[idx + in_kB_index].split()[2:8]] + virial = np.zeros([3, 3]) + virial[0][0] = tmp_v[0] + virial[1][1] = tmp_v[1] + virial[2][2] = tmp_v[2] + virial[0][1] = tmp_v[3] + virial[1][0] = tmp_v[3] + virial[1][2] = tmp_v[4] + virial[2][1] = tmp_v[4] + virial[0][2] = tmp_v[5] + virial[2][0] = tmp_v[5] + elif "TOTAL-FORCE" in ii and (("ML" in ii) == ml): + for jj in range(idx + 2, idx + 2 + ntot): + tmp_l = lines[jj] + info = [float(ss) for ss in tmp_l.split()] + coord.append(info[:3]) + force.append(info[3:6]) + return coord, cell, energy, force, virial, is_converge diff --git a/dpdata/vasp_deltaspin/poscar.py b/dpdata/vasp_deltaspin/poscar.py index 229a6f75..99607fde 100644 --- a/dpdata/vasp_deltaspin/poscar.py +++ b/dpdata/vasp_deltaspin/poscar.py @@ -39,13 +39,14 @@ def _to_system_data_lower(lines, lines_incar, cartesian=True): start_index = idx elif 'M_CONSTR' in incar_param: end_index = idx - spin_idx = np.where(np.cumsum(system['atom_numbs']) <= (end_index - start_index)) - system['atom_numbs_spin'] = np.array(system['atom_numbs'])[spin_idx] - system['atom_names_spin'] = np.array(system['atom_names'])[spin_idx] - system['spin'] = [lines_incar[start_index].strip().split(' ')[1:4]] + system['spin'] = [lines_incar[start_index].replace('=', '').strip().split()[1:4]] for idx in range(start_index+1, end_index-1): - system['spin'].append(lines_incar[idx].strip().split(' ')[:3]) + system['spin'].append(lines_incar[idx].strip().split()[:3]) system['spin'] = np.array([system['spin']]).astype('float64') + count = np.sum(np.linalg.norm(system['spin'][0], axis=1) > 0) + spin_idx = np.where(np.cumsum(system['atom_numbs']) <= count) + system['atom_numbs_spin'] = np.array(system['atom_numbs'])[spin_idx] + system['atom_names_spin'] = np.array(system['atom_names'])[spin_idx] return system From c3096e8b4e7ed5c8bc9571266ee8a7b6a0808810 Mon Sep 17 00:00:00 2001 From: hztttt <940755193@qq.com> Date: Thu, 14 Mar 2024 19:34:42 +0800 Subject: [PATCH 3/9] support deepmd raw/npy --- dpdata/deepmd/comp.py | 30 ++++++++++++++++++++++++++++-- dpdata/deepmd/raw.py | 20 ++++++++++++++++++++ dpdata/system.py | 2 +- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/dpdata/deepmd/comp.py b/dpdata/deepmd/comp.py index 7b909b16..e7f820d0 100644 --- a/dpdata/deepmd/comp.py +++ b/dpdata/deepmd/comp.py @@ -25,8 +25,10 @@ def _load_set(folder, nopbc: bool): cells = np.load(os.path.join(folder, "box.npy")) eners = _cond_load_data(os.path.join(folder, "energy.npy")) forces = _cond_load_data(os.path.join(folder, "force.npy")) + mag_forces = _cond_load_data(os.path.join(folder, "force_mag.npy")) virs = _cond_load_data(os.path.join(folder, "virial.npy")) - return cells, coords, eners, forces, virs + spin = _cond_load_data(os.path.join(folder, "spin.npy")) + return cells, coords, eners, forces, virs, mag_forces, spin def to_system_data(folder, type_map=None, labels=True): @@ -40,12 +42,16 @@ def to_system_data(folder, type_map=None, labels=True): all_coords = [] all_eners = [] all_forces = [] + all_mag_forces = [] all_virs = [] + all_spin = [] for ii in sets: - cells, coords, eners, forces, virs = _load_set(ii, data.get("nopbc", False)) + cells, coords, eners, forces, virs, mag_forces, spin = _load_set(ii, data.get("nopbc", False)) nframes = np.reshape(cells, [-1, 3, 3]).shape[0] all_cells.append(np.reshape(cells, [nframes, 3, 3])) all_coords.append(np.reshape(coords, [nframes, -1, 3])) + if spin is not None: + all_spin.append(np.reshape(spin, [nframes, -1, 3])) if eners is not None: eners = np.reshape(eners, [nframes]) if labels: @@ -55,14 +61,20 @@ def to_system_data(folder, type_map=None, labels=True): all_forces.append(np.reshape(forces, [nframes, -1, 3])) if virs is not None and virs.size > 0: all_virs.append(np.reshape(virs, [nframes, 3, 3])) + if mag_forces is not None and mag_forces.size > 0: + all_mag_forces.append(np.reshape(mag_forces, [nframes, -1, 3])) data["cells"] = np.concatenate(all_cells, axis=0) data["coords"] = np.concatenate(all_coords, axis=0) + if len(all_spin) > 0: + data["spin"] = np.concatenate(all_spin, axis=0) if len(all_eners) > 0: data["energies"] = np.concatenate(all_eners, axis=0) if len(all_forces) > 0: data["forces"] = np.concatenate(all_forces, axis=0) if len(all_virs) > 0: data["virials"] = np.concatenate(all_virs, axis=0) + if len(all_mag_forces) > 0: + data["mag_forces"] = np.concatenate(all_mag_forces, axis=0) # allow custom dtypes if labels: for dtype in dpdata.system.LabeledSystem.DTYPES: @@ -79,6 +91,8 @@ def to_system_data(folder, type_map=None, labels=True): "energies", "forces", "virials", + "spin", + "mag_forces" ): # skip as these data contains specific rules continue @@ -136,6 +150,8 @@ def dump(folder, data, set_size=5000, comp_prec=np.float32, remove_sets=True): eners = None forces = None virials = None + mag_forces = None + spin = None if "energies" in data: eners = np.reshape(data["energies"], [nframes]).astype(comp_prec) if "forces" in data: @@ -144,6 +160,10 @@ def dump(folder, data, set_size=5000, comp_prec=np.float32, remove_sets=True): virials = np.reshape(data["virials"], [nframes, 9]).astype(comp_prec) if "atom_pref" in data: atom_pref = np.reshape(data["atom_pref"], [nframes, -1]).astype(comp_prec) + if "mag_forces" in data: + mag_forces = np.reshape(data["mag_forces"], [nframes, -1]).astype(comp_prec) + if "spin" in data: + spin = np.reshape(data["spin"], [nframes, -1]).astype(comp_prec) # dump frame properties: cell, coord, energy, force and virial nsets = nframes // set_size if set_size * nsets < nframes: @@ -163,6 +183,10 @@ def dump(folder, data, set_size=5000, comp_prec=np.float32, remove_sets=True): np.save(os.path.join(set_folder, "virial"), virials[set_stt:set_end]) if "atom_pref" in data: np.save(os.path.join(set_folder, "atom_pref"), atom_pref[set_stt:set_end]) + if mag_forces is not None: + np.save(os.path.join(set_folder, "force_mag"), mag_forces[set_stt:set_end]) + if spin is not None: + np.save(os.path.join(set_folder, "spin"), spin[set_stt:set_end]) try: os.remove(os.path.join(folder, "nopbc")) except OSError: @@ -185,6 +209,8 @@ def dump(folder, data, set_size=5000, comp_prec=np.float32, remove_sets=True): "energies", "forces", "virials", + "mag_forces", + "spin" ): # skip as these data contains specific rules continue diff --git a/dpdata/deepmd/raw.py b/dpdata/deepmd/raw.py index c7a64ec4..479459d9 100644 --- a/dpdata/deepmd/raw.py +++ b/dpdata/deepmd/raw.py @@ -58,6 +58,12 @@ def to_system_data(folder, type_map=None, labels=True): if os.path.exists(os.path.join(folder, "virial.raw")): data["virials"] = np.loadtxt(os.path.join(folder, "virial.raw")) data["virials"] = np.reshape(data["virials"], [nframes, 3, 3]) + if os.path.exists(os.path.join(folder, "spin.raw")): + data["spin"] = np.loadtxt(os.path.join(folder, "spin.raw")) + data["spin"] = np.reshape(data["spin"], [nframes, -1, 3]) + if os.path.exists(os.path.join(folder, "force_mag.raw")): + data["mag_forces"] = np.loadtxt(os.path.join(folder, "force_mag.raw")) + data["mag_forces"] = np.reshape(data["mag_forces"], [nframes, -1, 3]) if os.path.isfile(os.path.join(folder, "nopbc")): data["nopbc"] = True # allow custom dtypes @@ -76,6 +82,8 @@ def to_system_data(folder, type_map=None, labels=True): "energies", "forces", "virials", + "mag_forces", + "spin" ): # skip as these data contains specific rules continue @@ -134,6 +142,16 @@ def dump(folder, data): os.path.join(folder, "virial.raw"), np.reshape(data["virials"], [nframes, 9]), ) + if "spin" in data: + np.savetxt( + os.path.join(folder, "spin.raw"), + np.reshape(data["spin"], [nframes, -1]), + ) + if "mag_forces" in data: + np.savetxt( + os.path.join(folder, "force_mag.raw"), + np.reshape(data["mag_forces"], [nframes, -1]), + ) try: os.remove(os.path.join(folder, "nopbc")) except OSError: @@ -156,6 +174,8 @@ def dump(folder, data): "energies", "forces", "virials", + "mag_forces", + "spin" ): # skip as these data contains specific rules continue diff --git a/dpdata/system.py b/dpdata/system.py index 97036c5f..6d903ba8 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -1104,7 +1104,7 @@ class LabeledSystem(System): DTYPES = System.DTYPES + ( DataType("energies", np.ndarray, (Axis.NFRAMES,)), DataType("forces", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3)), - DataType("mag_forces", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3)), + DataType("mag_forces", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3), required=False), DataType("virials", np.ndarray, (Axis.NFRAMES, 3, 3), required=False), DataType("atom_pref", np.ndarray, (Axis.NFRAMES, Axis.NATOMS), required=False), ) From 6fe4418d271ad4bd35837c6fb951d62a8f0ae635 Mon Sep 17 00:00:00 2001 From: hztttt <940755193@qq.com> Date: Wed, 20 Mar 2024 09:04:27 +0800 Subject: [PATCH 4/9] fix bug --- dpdata/lammps/dump.py | 2 ++ dpdata/vasp_deltaspin/poscar.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dpdata/lammps/dump.py b/dpdata/lammps/dump.py index 0ea6127c..cc74a6f3 100644 --- a/dpdata/lammps/dump.py +++ b/dpdata/lammps/dump.py @@ -265,6 +265,8 @@ def system_data(lines, type_map=None, type_idx_zero=True, unwrap=False): ) if contain_spin: system['spin'].append(safe_get_spin_force(array_lines[ii])[:, :1] * safe_get_spin_force(array_lines[ii])[:, 1:4]) + if contain_spin: + system["spin"] = np.array(system["spin"]) system["cells"] = np.array(system["cells"]) system["coords"] = np.array(system["coords"]) return system diff --git a/dpdata/vasp_deltaspin/poscar.py b/dpdata/vasp_deltaspin/poscar.py index 99607fde..3289b4e1 100644 --- a/dpdata/vasp_deltaspin/poscar.py +++ b/dpdata/vasp_deltaspin/poscar.py @@ -106,7 +106,7 @@ def from_system_data(system, f_idx=0, skip_zeros=True): if idx == 0: magmom_incar += f"{tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" mconstr_incar += f"{tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" - elif idx == len(system['spin'] - 1): + elif idx == len(system['spin'][f_idx]) - 1: magmom_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \n" mconstr_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \n" else: From 4110f134b0fddb6f553bf80718a66f45bcd3f0ab Mon Sep 17 00:00:00 2001 From: hztttt <940755193@qq.com> Date: Thu, 28 Mar 2024 11:56:04 +0800 Subject: [PATCH 5/9] fix outcar --- dpdata/vasp_deltaspin/outcar.py | 2 +- dpdata/vasp_deltaspin/poscar.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/dpdata/vasp_deltaspin/outcar.py b/dpdata/vasp_deltaspin/outcar.py index d0ec375d..822e1ef1 100644 --- a/dpdata/vasp_deltaspin/outcar.py +++ b/dpdata/vasp_deltaspin/outcar.py @@ -97,7 +97,7 @@ def get_frames(fname, begin=0, step=1, ml=False, convergence_check=True): oszicar_blk = f.read() mag_blk = re.findall(r'Magnetic Force(.*?)\n \n', oszicar_blk, re.S)[-1].split('\n') mag_force = [list(map(float, ss.split()[-3:])) for ss in mag_blk[1:]] - spin_blk = re.findall(r'MW_current(.*?)\n lambda', oszicar_blk, re.S)[-1].split('\n') + spin_blk = re.findall(r'MW_current(.*?)\n ion', oszicar_blk, re.S)[-1].split('\n') spin = [list(map(float, ss.split()[1:4])) for ss in spin_blk[1:]] all_mag_forces.append(mag_force) all_spins.append(spin) diff --git a/dpdata/vasp_deltaspin/poscar.py b/dpdata/vasp_deltaspin/poscar.py index 3289b4e1..ba6ed839 100644 --- a/dpdata/vasp_deltaspin/poscar.py +++ b/dpdata/vasp_deltaspin/poscar.py @@ -45,8 +45,6 @@ def _to_system_data_lower(lines, lines_incar, cartesian=True): system['spin'] = np.array([system['spin']]).astype('float64') count = np.sum(np.linalg.norm(system['spin'][0], axis=1) > 0) spin_idx = np.where(np.cumsum(system['atom_numbs']) <= count) - system['atom_numbs_spin'] = np.array(system['atom_numbs'])[spin_idx] - system['atom_names_spin'] = np.array(system['atom_names'])[spin_idx] return system From 5cf335c496e1faf252ada0c07c60d30c6f8a538a Mon Sep 17 00:00:00 2001 From: hztttt <940755193@qq.com> Date: Wed, 24 Apr 2024 10:55:22 +0800 Subject: [PATCH 6/9] fix lmp bug for zero spin norm --- dpdata/lammps/lmp.py | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/dpdata/lammps/lmp.py b/dpdata/lammps/lmp.py index 85883d87..df615884 100644 --- a/dpdata/lammps/lmp.py +++ b/dpdata/lammps/lmp.py @@ -245,17 +245,30 @@ def from_system_data(system, f_idx=0): spin_norm = np.linalg.norm(system['spin'][f_idx], axis=1) for ii in range(natoms): if 'spin' in system.keys(): - ret += coord_fmt % ( - ii + 1, - system["atom_types"][ii] + 1, - system["coords"][f_idx][ii][0] - system["orig"][0], - system["coords"][f_idx][ii][1] - system["orig"][1], - system["coords"][f_idx][ii][2] - system["orig"][2], - system['spin'][f_idx][ii][0]/spin_norm[ii], - system['spin'][f_idx][ii][1]/spin_norm[ii], - system['spin'][f_idx][ii][2]/spin_norm[ii], - spin_norm[ii], - ) + if spin_norm[ii] != 0: + ret += coord_fmt % ( + ii + 1, + system["atom_types"][ii] + 1, + system["coords"][f_idx][ii][0] - system["orig"][0], + system["coords"][f_idx][ii][1] - system["orig"][1], + system["coords"][f_idx][ii][2] - system["orig"][2], + system['spin'][f_idx][ii][0]/spin_norm[ii], + system['spin'][f_idx][ii][1]/spin_norm[ii], + system['spin'][f_idx][ii][2]/spin_norm[ii], + spin_norm[ii], + ) + else: + ret += coord_fmt % ( + ii + 1, + system["atom_types"][ii] + 1, + system["coords"][f_idx][ii][0] - system["orig"][0], + system["coords"][f_idx][ii][1] - system["orig"][1], + system["coords"][f_idx][ii][2] - system["orig"][2], + system['spin'][f_idx][ii][0], + system['spin'][f_idx][ii][1], + system['spin'][f_idx][ii][2], + spin_norm[ii], + ) else: ret += coord_fmt % ( ii + 1, From 01fd3752fa25baef69e7ec7b8968151689c0e211 Mon Sep 17 00:00:00 2001 From: hztttt <940755193@qq.com> Date: Thu, 30 May 2024 12:24:33 +0800 Subject: [PATCH 7/9] fix spin rot and lmp sp norm zero bug. --- dpdata/lammps/lmp.py | 2 +- dpdata/system.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dpdata/lammps/lmp.py b/dpdata/lammps/lmp.py index df615884..12a8ae66 100644 --- a/dpdata/lammps/lmp.py +++ b/dpdata/lammps/lmp.py @@ -266,7 +266,7 @@ def from_system_data(system, f_idx=0): system["coords"][f_idx][ii][2] - system["orig"][2], system['spin'][f_idx][ii][0], system['spin'][f_idx][ii][1], - system['spin'][f_idx][ii][2], + system['spin'][f_idx][ii][2]+1, spin_norm[ii], ) else: diff --git a/dpdata/system.py b/dpdata/system.py index c65a82f8..85297c96 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -643,6 +643,10 @@ def affine_map(self, trans, f_idx=0): assert np.linalg.det(trans) != 0 self.data["cells"][f_idx] = np.matmul(self.data["cells"][f_idx], trans) self.data["coords"][f_idx] = np.matmul(self.data["coords"][f_idx], trans) + try: + self.data["spin"][f_idx] = np.matmul(self.data["spin"][f_idx], trans) + except: + pass @post_funcs.register("shift_orig_zero") def _shift_orig_zero(self): From 6233b8facbb23ec8cf722b7c859118fe9987433c Mon Sep 17 00:00:00 2001 From: yangtengleo Date: Mon, 9 Sep 2024 13:59:20 +0800 Subject: [PATCH 8/9] change related variable name from 'spin' to 'spins' --- dpdata/deepmd/comp.py | 28 ++++++++++---------- dpdata/deepmd/raw.py | 10 ++++---- dpdata/lammps/dump.py | 6 ++--- dpdata/lammps/lmp.py | 44 ++++++++++++++++---------------- dpdata/plugins/vasp_deltaspin.py | 2 +- dpdata/system.py | 4 +-- dpdata/vasp_deltaspin/poscar.py | 14 +++++----- 7 files changed, 54 insertions(+), 54 deletions(-) diff --git a/dpdata/deepmd/comp.py b/dpdata/deepmd/comp.py index eb5f4e48..72b43de2 100644 --- a/dpdata/deepmd/comp.py +++ b/dpdata/deepmd/comp.py @@ -30,8 +30,8 @@ def _load_set(folder, nopbc: bool): forces = _cond_load_data(os.path.join(folder, "force.npy")) mag_forces = _cond_load_data(os.path.join(folder, "force_mag.npy")) virs = _cond_load_data(os.path.join(folder, "virial.npy")) - spin = _cond_load_data(os.path.join(folder, "spin.npy")) - return cells, coords, eners, forces, virs, mag_forces, spin + spins = _cond_load_data(os.path.join(folder, "spin.npy")) + return cells, coords, eners, forces, virs, mag_forces, spins def to_system_data(folder, type_map=None, labels=True): @@ -47,14 +47,14 @@ def to_system_data(folder, type_map=None, labels=True): all_forces = [] all_mag_forces = [] all_virs = [] - all_spin = [] + all_spins = [] for ii in sets: - cells, coords, eners, forces, virs, mag_forces, spin = _load_set(ii, data.get("nopbc", False)) + cells, coords, eners, forces, virs, mag_forces, spins = _load_set(ii, data.get("nopbc", False)) nframes = np.reshape(cells, [-1, 3, 3]).shape[0] all_cells.append(np.reshape(cells, [nframes, 3, 3])) all_coords.append(np.reshape(coords, [nframes, -1, 3])) - if spin is not None: - all_spin.append(np.reshape(spin, [nframes, -1, 3])) + if spins is not None: + all_spins.append(np.reshape(spins, [nframes, -1, 3])) if eners is not None: eners = np.reshape(eners, [nframes]) if labels: @@ -68,8 +68,8 @@ def to_system_data(folder, type_map=None, labels=True): all_mag_forces.append(np.reshape(mag_forces, [nframes, -1, 3])) data["cells"] = np.concatenate(all_cells, axis=0) data["coords"] = np.concatenate(all_coords, axis=0) - if len(all_spin) > 0: - data["spin"] = np.concatenate(all_spin, axis=0) + if len(all_spins) > 0: + data["spins"] = np.concatenate(all_spins, axis=0) if len(all_eners) > 0: data["energies"] = np.concatenate(all_eners, axis=0) if len(all_forces) > 0: @@ -156,7 +156,7 @@ def dump(folder, data, set_size=5000, comp_prec=np.float32, remove_sets=True): forces = None virials = None mag_forces = None - spin = None + spins = None if "energies" in data: eners = np.reshape(data["energies"], [nframes]).astype(comp_prec) if "forces" in data: @@ -167,8 +167,8 @@ def dump(folder, data, set_size=5000, comp_prec=np.float32, remove_sets=True): atom_pref = np.reshape(data["atom_pref"], [nframes, -1]).astype(comp_prec) if "mag_forces" in data: mag_forces = np.reshape(data["mag_forces"], [nframes, -1]).astype(comp_prec) - if "spin" in data: - spin = np.reshape(data["spin"], [nframes, -1]).astype(comp_prec) + if "spins" in data: + spins = np.reshape(data["spins"], [nframes, -1]).astype(comp_prec) # dump frame properties: cell, coord, energy, force and virial nsets = nframes // set_size if set_size * nsets < nframes: @@ -190,8 +190,8 @@ def dump(folder, data, set_size=5000, comp_prec=np.float32, remove_sets=True): np.save(os.path.join(set_folder, "atom_pref"), atom_pref[set_stt:set_end]) if mag_forces is not None: np.save(os.path.join(set_folder, "force_mag"), mag_forces[set_stt:set_end]) - if spin is not None: - np.save(os.path.join(set_folder, "spin"), spin[set_stt:set_end]) + if spins is not None: + np.save(os.path.join(set_folder, "spins"), spins[set_stt:set_end]) try: os.remove(os.path.join(folder, "nopbc")) except OSError: @@ -219,7 +219,7 @@ def dump(folder, data, set_size=5000, comp_prec=np.float32, remove_sets=True): "forces", "virials", "mag_forces", - "spin" + "spins" ): # skip as these data contains specific rules continue diff --git a/dpdata/deepmd/raw.py b/dpdata/deepmd/raw.py index 643bb3b6..92bf9686 100644 --- a/dpdata/deepmd/raw.py +++ b/dpdata/deepmd/raw.py @@ -60,8 +60,8 @@ def to_system_data(folder, type_map=None, labels=True): data["virials"] = np.loadtxt(os.path.join(folder, "virial.raw")) data["virials"] = np.reshape(data["virials"], [nframes, 3, 3]) if os.path.exists(os.path.join(folder, "spin.raw")): - data["spin"] = np.loadtxt(os.path.join(folder, "spin.raw")) - data["spin"] = np.reshape(data["spin"], [nframes, -1, 3]) + data["spins"] = np.loadtxt(os.path.join(folder, "spin.raw")) + data["spins"] = np.reshape(data["spins"], [nframes, -1, 3]) if os.path.exists(os.path.join(folder, "force_mag.raw")): data["mag_forces"] = np.loadtxt(os.path.join(folder, "force_mag.raw")) data["mag_forces"] = np.reshape(data["mag_forces"], [nframes, -1, 3]) @@ -144,10 +144,10 @@ def dump(folder, data): os.path.join(folder, "virial.raw"), np.reshape(data["virials"], [nframes, 9]), ) - if "spin" in data: + if "spins" in data: np.savetxt( os.path.join(folder, "spin.raw"), - np.reshape(data["spin"], [nframes, -1]), + np.reshape(data["spins"], [nframes, -1]), ) if "mag_forces" in data: np.savetxt( @@ -182,7 +182,7 @@ def dump(folder, data): "forces", "virials", "mag_forces", - "spin" + "spins" ): # skip as these data contains specific rules continue diff --git a/dpdata/lammps/dump.py b/dpdata/lammps/dump.py index 0496ab6d..1c1fc246 100644 --- a/dpdata/lammps/dump.py +++ b/dpdata/lammps/dump.py @@ -257,7 +257,7 @@ def system_data(lines, type_map=None, type_idx_zero=True, unwrap=False): if 'sp' in head: contain_spin = True spin_force = safe_get_spin_force(lines) - system['spin'] = [spin_force[:, :1] * spin_force[:, 1:4]] + system['spins'] = [spin_force[:, :1] * spin_force[:, 1:4]] for ii in range(1, len(array_lines)): bounds, tilt = get_dumpbox(array_lines[ii]) orig, cell = dumpbox2box(bounds, tilt) @@ -271,9 +271,9 @@ def system_data(lines, type_map=None, type_idx_zero=True, unwrap=False): safe_get_posi(array_lines[ii], cell, np.array(orig), unwrap)[idx] ) if contain_spin: - system['spin'].append(safe_get_spin_force(array_lines[ii])[:, :1] * safe_get_spin_force(array_lines[ii])[:, 1:4]) + system['spins'].append(safe_get_spin_force(array_lines[ii])[:, :1] * safe_get_spin_force(array_lines[ii])[:, 1:4]) if contain_spin: - system["spin"] = np.array(system["spin"]) + system["spins"] = np.array(system["spins"]) system["cells"] = np.array(system["cells"]) system["coords"] = np.array(system["coords"]) return system diff --git a/dpdata/lammps/lmp.py b/dpdata/lammps/lmp.py index 16e191b0..4f8c1f8f 100644 --- a/dpdata/lammps/lmp.py +++ b/dpdata/lammps/lmp.py @@ -126,17 +126,17 @@ def get_posi(lines): posis.append([float(jj) for jj in ii.split()[2:5]]) return np.array(posis) -def get_spin(lines): +def get_spins(lines): atom_lines = get_atoms(lines) if len(atom_lines[0].split()) < 8: return None - spin_ori = [] - spin_norm = [] + spins_ori = [] + spins_norm = [] for ii in atom_lines: - spin_ori.append([float(jj) for jj in ii.split()[5:8]]) - spin_norm.append([float(jj) for jj in ii.split()[-1:]]) - spin = np.array(spin_ori) * np.array(spin_norm) - return spin + spins_ori.append([float(jj) for jj in ii.split()[5:8]]) + spins_norm.append([float(jj) for jj in ii.split()[-1:]]) + spins = np.array(spins_ori) * np.array(spins_norm) + return spins def get_lmpbox(lines): box_info = [] @@ -162,9 +162,9 @@ def get_lmpbox(lines): def system_data(lines, type_map=None, type_idx_zero=True): system = {} system["atom_numbs"] = get_natoms_vec(lines) - spin = get_spin(lines) - if spin is not None: - system['spin'] = np.array([spin]) + spins = get_spins(lines) + if spins is not None: + system['spins'] = np.array([spins]) system["atom_names"] = [] if type_map is None: for ii in range(len(system["atom_numbs"])): @@ -230,7 +230,7 @@ def from_system_data(system, f_idx=0): + ptr_float_fmt + "\n" ) - if 'spin' in system.keys(): + if 'spins' in system.keys(): coord_fmt = ( coord_fmt.strip('\n') + " " @@ -243,20 +243,20 @@ def from_system_data(system, f_idx=0): + ptr_float_fmt + "\n" ) - spin_norm = np.linalg.norm(system['spin'][f_idx], axis=1) + spins_norm = np.linalg.norm(system['spins'][f_idx], axis=1) for ii in range(natoms): - if 'spin' in system.keys(): - if spin_norm[ii] != 0: + if 'spins' in system.keys(): + if spins_norm[ii] != 0: ret += coord_fmt % ( ii + 1, system["atom_types"][ii] + 1, system["coords"][f_idx][ii][0] - system["orig"][0], system["coords"][f_idx][ii][1] - system["orig"][1], system["coords"][f_idx][ii][2] - system["orig"][2], - system['spin'][f_idx][ii][0]/spin_norm[ii], - system['spin'][f_idx][ii][1]/spin_norm[ii], - system['spin'][f_idx][ii][2]/spin_norm[ii], - spin_norm[ii], + system['spins'][f_idx][ii][0]/spins_norm[ii], + system['spins'][f_idx][ii][1]/spins_norm[ii], + system['spins'][f_idx][ii][2]/spins_norm[ii], + spins_norm[ii], ) else: ret += coord_fmt % ( @@ -265,10 +265,10 @@ def from_system_data(system, f_idx=0): system["coords"][f_idx][ii][0] - system["orig"][0], system["coords"][f_idx][ii][1] - system["orig"][1], system["coords"][f_idx][ii][2] - system["orig"][2], - system['spin'][f_idx][ii][0], - system['spin'][f_idx][ii][1], - system['spin'][f_idx][ii][2]+1, - spin_norm[ii], + system['spins'][f_idx][ii][0], + system['spins'][f_idx][ii][1], + system['spins'][f_idx][ii][2]+1, + spins_norm[ii], ) else: ret += coord_fmt % ( diff --git a/dpdata/plugins/vasp_deltaspin.py b/dpdata/plugins/vasp_deltaspin.py index 4f96fe72..1638dd63 100644 --- a/dpdata/plugins/vasp_deltaspin.py +++ b/dpdata/plugins/vasp_deltaspin.py @@ -78,7 +78,7 @@ def from_labeled_system( data["atom_types"], data["cells"], data["coords"], - data['spin'], + data['spins'], data["energies"], data["forces"], data['mag_forces'], diff --git a/dpdata/system.py b/dpdata/system.py index 953e0e65..7ee18a07 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -93,7 +93,7 @@ class System: DataType("orig", np.ndarray, (3,)), DataType("cells", np.ndarray, (Axis.NFRAMES, 3, 3)), DataType("coords", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3)), - DataType("spin", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3), required=False), + DataType("spins", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3), required=False), DataType( "real_atom_types", np.ndarray, (Axis.NFRAMES, Axis.NATOMS), required=False ), @@ -712,7 +712,7 @@ def affine_map(self, trans, f_idx: int | numbers.Integral = 0): self.data["cells"][f_idx] = np.matmul(self.data["cells"][f_idx], trans) self.data["coords"][f_idx] = np.matmul(self.data["coords"][f_idx], trans) try: - self.data["spin"][f_idx] = np.matmul(self.data["spin"][f_idx], trans) + self.data["spins"][f_idx] = np.matmul(self.data["spins"][f_idx], trans) except: pass diff --git a/dpdata/vasp_deltaspin/poscar.py b/dpdata/vasp_deltaspin/poscar.py index ba6ed839..932d32c3 100644 --- a/dpdata/vasp_deltaspin/poscar.py +++ b/dpdata/vasp_deltaspin/poscar.py @@ -39,12 +39,12 @@ def _to_system_data_lower(lines, lines_incar, cartesian=True): start_index = idx elif 'M_CONSTR' in incar_param: end_index = idx - system['spin'] = [lines_incar[start_index].replace('=', '').strip().split()[1:4]] + system['spins'] = [lines_incar[start_index].replace('=', '').strip().split()[1:4]] for idx in range(start_index+1, end_index-1): - system['spin'].append(lines_incar[idx].strip().split()[:3]) - system['spin'] = np.array([system['spin']]).astype('float64') - count = np.sum(np.linalg.norm(system['spin'][0], axis=1) > 0) - spin_idx = np.where(np.cumsum(system['atom_numbs']) <= count) + system['spins'].append(lines_incar[idx].strip().split()[:3]) + system['spins'] = np.array([system['spins']]).astype('float64') + count = np.sum(np.linalg.norm(system['spins'][0], axis=1) > 0) + spins_idx = np.where(np.cumsum(system['atom_numbs']) <= count) return system @@ -100,11 +100,11 @@ def from_system_data(system, f_idx=0, skip_zeros=True): magmom_incar = "MAGMOM = " mconstr_incar = "M_CONSTR = " - for idx, tmp_spin in enumerate(system['spin'][f_idx]): + for idx, tmp_spin in enumerate(system['spins'][f_idx]): if idx == 0: magmom_incar += f"{tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" mconstr_incar += f"{tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" - elif idx == len(system['spin'][f_idx]) - 1: + elif idx == len(system['spins'][f_idx]) - 1: magmom_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \n" mconstr_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \n" else: From 4339232ea167c9947cb8e7cccb290387e750ca3b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 17:32:54 +0000 Subject: [PATCH 9/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- dpdata/lammps/dump.py | 13 +++++++----- dpdata/lammps/lmp.py | 26 +++++++++++++----------- dpdata/plugins/vasp_deltaspin.py | 21 +++++++++++-------- dpdata/system.py | 4 +++- dpdata/vasp_deltaspin/outcar.py | 10 ++++++--- dpdata/vasp_deltaspin/poscar.py | 35 ++++++++++++++++++-------------- 6 files changed, 64 insertions(+), 45 deletions(-) diff --git a/dpdata/lammps/dump.py b/dpdata/lammps/dump.py index 1c1fc246..d3d0e4a8 100644 --- a/dpdata/lammps/dump.py +++ b/dpdata/lammps/dump.py @@ -133,7 +133,7 @@ def safe_get_posi(lines, cell, orig=np.zeros(3), unwrap=False): def get_spintype(keys): - key_sp = ["sp", "spx", "spy", "spz"] + key_sp = ["sp", "spx", "spy", "spz"] key_csp = ["c_spin[1]", "c_spin[2]", "c_spin[3]", "c_spin[4]"] lmp_sp_type = [key_sp, key_csp] for k in range(2): @@ -147,7 +147,7 @@ def safe_get_spin_force(lines): sp_type = get_spintype(keys) assert sp_type is not None, "Dump file does not contain spin!" id_idx = keys.index("id") - 2 - sp = keys.index(sp_type[0]) - 2 + sp = keys.index(sp_type[0]) - 2 spx = keys.index(sp_type[1]) - 2 spy = keys.index(sp_type[2]) - 2 spz = keys.index(sp_type[3]) - 2 @@ -254,10 +254,10 @@ def system_data(lines, type_map=None, type_idx_zero=True, unwrap=False): system["coords"] = [safe_get_posi(lines, cell, np.array(orig), unwrap)] contain_spin = False blk, head = _get_block(lines, "ATOMS") - if 'sp' in head: + if "sp" in head: contain_spin = True spin_force = safe_get_spin_force(lines) - system['spins'] = [spin_force[:, :1] * spin_force[:, 1:4]] + system["spins"] = [spin_force[:, :1] * spin_force[:, 1:4]] for ii in range(1, len(array_lines)): bounds, tilt = get_dumpbox(array_lines[ii]) orig, cell = dumpbox2box(bounds, tilt) @@ -271,7 +271,10 @@ def system_data(lines, type_map=None, type_idx_zero=True, unwrap=False): safe_get_posi(array_lines[ii], cell, np.array(orig), unwrap)[idx] ) if contain_spin: - system['spins'].append(safe_get_spin_force(array_lines[ii])[:, :1] * safe_get_spin_force(array_lines[ii])[:, 1:4]) + system["spins"].append( + safe_get_spin_force(array_lines[ii])[:, :1] + * safe_get_spin_force(array_lines[ii])[:, 1:4] + ) if contain_spin: system["spins"] = np.array(system["spins"]) system["cells"] = np.array(system["cells"]) diff --git a/dpdata/lammps/lmp.py b/dpdata/lammps/lmp.py index 4f8c1f8f..e78443c3 100644 --- a/dpdata/lammps/lmp.py +++ b/dpdata/lammps/lmp.py @@ -126,6 +126,7 @@ def get_posi(lines): posis.append([float(jj) for jj in ii.split()[2:5]]) return np.array(posis) + def get_spins(lines): atom_lines = get_atoms(lines) if len(atom_lines[0].split()) < 8: @@ -138,6 +139,7 @@ def get_spins(lines): spins = np.array(spins_ori) * np.array(spins_norm) return spins + def get_lmpbox(lines): box_info = [] tilt = np.zeros(3) @@ -163,8 +165,8 @@ def system_data(lines, type_map=None, type_idx_zero=True): system = {} system["atom_numbs"] = get_natoms_vec(lines) spins = get_spins(lines) - if spins is not None: - system['spins'] = np.array([spins]) + if spins is not None: + system["spins"] = np.array([spins]) system["atom_names"] = [] if type_map is None: for ii in range(len(system["atom_numbs"])): @@ -230,9 +232,9 @@ def from_system_data(system, f_idx=0): + ptr_float_fmt + "\n" ) - if 'spins' in system.keys(): + if "spins" in system.keys(): coord_fmt = ( - coord_fmt.strip('\n') + coord_fmt.strip("\n") + " " + ptr_float_fmt + " " @@ -243,9 +245,9 @@ def from_system_data(system, f_idx=0): + ptr_float_fmt + "\n" ) - spins_norm = np.linalg.norm(system['spins'][f_idx], axis=1) + spins_norm = np.linalg.norm(system["spins"][f_idx], axis=1) for ii in range(natoms): - if 'spins' in system.keys(): + if "spins" in system.keys(): if spins_norm[ii] != 0: ret += coord_fmt % ( ii + 1, @@ -253,9 +255,9 @@ def from_system_data(system, f_idx=0): system["coords"][f_idx][ii][0] - system["orig"][0], system["coords"][f_idx][ii][1] - system["orig"][1], system["coords"][f_idx][ii][2] - system["orig"][2], - system['spins'][f_idx][ii][0]/spins_norm[ii], - system['spins'][f_idx][ii][1]/spins_norm[ii], - system['spins'][f_idx][ii][2]/spins_norm[ii], + system["spins"][f_idx][ii][0] / spins_norm[ii], + system["spins"][f_idx][ii][1] / spins_norm[ii], + system["spins"][f_idx][ii][2] / spins_norm[ii], spins_norm[ii], ) else: @@ -265,9 +267,9 @@ def from_system_data(system, f_idx=0): system["coords"][f_idx][ii][0] - system["orig"][0], system["coords"][f_idx][ii][1] - system["orig"][1], system["coords"][f_idx][ii][2] - system["orig"][2], - system['spins'][f_idx][ii][0], - system['spins'][f_idx][ii][1], - system['spins'][f_idx][ii][2]+1, + system["spins"][f_idx][ii][0], + system["spins"][f_idx][ii][1], + system["spins"][f_idx][ii][2] + 1, spins_norm[ii], ) else: diff --git a/dpdata/plugins/vasp_deltaspin.py b/dpdata/plugins/vasp_deltaspin.py index 1638dd63..2a9d74df 100644 --- a/dpdata/plugins/vasp_deltaspin.py +++ b/dpdata/plugins/vasp_deltaspin.py @@ -1,6 +1,9 @@ -import numpy as np +from __future__ import annotations + import re +import numpy as np + import dpdata.vasp_deltaspin.outcar import dpdata.vasp_deltaspin.poscar from dpdata.format import Format @@ -14,7 +17,7 @@ class VASPPoscarFormat(Format): def from_system(self, file_name, **kwargs): with open(file_name) as fp: lines = [line.rstrip("\n") for line in fp] - with open(file_name[:-6] + 'INCAR') as fp: + with open(file_name[:-6] + "INCAR") as fp: lines_incar = [line.rstrip("\n") for line in fp] data = dpdata.vasp_deltaspin.poscar.to_system_data(lines, lines_incar) data = uniq_atom_names(data) @@ -38,10 +41,12 @@ def to_system(self, data, file_name, frame_idx=0, **kwargs): with open(file_name, "w") as fp: fp.write(w_str) - with open(file_name[:-6] + 'INCAR') as fp: + with open(file_name[:-6] + "INCAR") as fp: tmp_incar = fp.read() - res_incar = re.sub(r'MAGMOM[\s\S]*?\n\nM_CONST[\s\S]*?\n\n', m_str, tmp_incar, re.S) - with open(file_name[:-6] + 'INCAR', 'w') as fp: + res_incar = re.sub( + r"MAGMOM[\s\S]*?\n\nM_CONST[\s\S]*?\n\n", m_str, tmp_incar, re.S + ) + with open(file_name[:-6] + "INCAR", "w") as fp: fp.write(res_incar) @@ -78,10 +83,10 @@ def from_labeled_system( data["atom_types"], data["cells"], data["coords"], - data['spins'], + data["spins"], data["energies"], data["forces"], - data['mag_forces'], + data["mag_forces"], tmp_virial, ) = dpdata.vasp_deltaspin.outcar.get_frames( file_name, @@ -100,5 +105,3 @@ def from_labeled_system( data["virials"][ii] *= v_pref * vol data = uniq_atom_names(data) return data - - diff --git a/dpdata/system.py b/dpdata/system.py index 6174458d..2f4414f3 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -1215,7 +1215,9 @@ class LabeledSystem(System): DataType( "forces", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3), deepmd_name="force" ), - DataType("mag_forces", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3), required=False), + DataType( + "mag_forces", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3), required=False + ), DataType( "virials", np.ndarray, diff --git a/dpdata/vasp_deltaspin/outcar.py b/dpdata/vasp_deltaspin/outcar.py index 822e1ef1..192106b1 100644 --- a/dpdata/vasp_deltaspin/outcar.py +++ b/dpdata/vasp_deltaspin/outcar.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re import warnings @@ -93,11 +95,13 @@ def get_frames(fname, begin=0, step=1, ml=False, convergence_check=True): blk = get_outcar_block(fp, ml) cc += 1 - with open(fname[:-6] + 'OSZICAR') as f: + with open(fname[:-6] + "OSZICAR") as f: oszicar_blk = f.read() - mag_blk = re.findall(r'Magnetic Force(.*?)\n \n', oszicar_blk, re.S)[-1].split('\n') + mag_blk = re.findall(r"Magnetic Force(.*?)\n \n", oszicar_blk, re.S)[-1].split( + "\n" + ) mag_force = [list(map(float, ss.split()[-3:])) for ss in mag_blk[1:]] - spin_blk = re.findall(r'MW_current(.*?)\n ion', oszicar_blk, re.S)[-1].split('\n') + spin_blk = re.findall(r"MW_current(.*?)\n ion", oszicar_blk, re.S)[-1].split("\n") spin = [list(map(float, ss.split()[1:4])) for ss in spin_blk[1:]] all_mag_forces.append(mag_force) all_spins.append(spin) diff --git a/dpdata/vasp_deltaspin/poscar.py b/dpdata/vasp_deltaspin/poscar.py index 932d32c3..7c7905fb 100644 --- a/dpdata/vasp_deltaspin/poscar.py +++ b/dpdata/vasp_deltaspin/poscar.py @@ -1,4 +1,5 @@ #!/usr/bin/python3 +from __future__ import annotations import numpy as np @@ -35,16 +36,16 @@ def _to_system_data_lower(lines, lines_incar, cartesian=True): system["coords"] = np.array(system["coords"]) for idx, incar_param in enumerate(lines_incar): - if 'MAGMOM' in incar_param: + if "MAGMOM" in incar_param: start_index = idx - elif 'M_CONSTR' in incar_param: + elif "M_CONSTR" in incar_param: end_index = idx - system['spins'] = [lines_incar[start_index].replace('=', '').strip().split()[1:4]] - for idx in range(start_index+1, end_index-1): - system['spins'].append(lines_incar[idx].strip().split()[:3]) - system['spins'] = np.array([system['spins']]).astype('float64') - count = np.sum(np.linalg.norm(system['spins'][0], axis=1) > 0) - spins_idx = np.where(np.cumsum(system['atom_numbs']) <= count) + system["spins"] = [lines_incar[start_index].replace("=", "").strip().split()[1:4]] + for idx in range(start_index + 1, end_index - 1): + system["spins"].append(lines_incar[idx].strip().split()[:3]) + system["spins"] = np.array([system["spins"]]).astype("float64") + count = np.sum(np.linalg.norm(system["spins"][0], axis=1) > 0) + spins_idx = np.where(np.cumsum(system["atom_numbs"]) <= count) return system @@ -100,16 +101,20 @@ def from_system_data(system, f_idx=0, skip_zeros=True): magmom_incar = "MAGMOM = " mconstr_incar = "M_CONSTR = " - for idx, tmp_spin in enumerate(system['spins'][f_idx]): + for idx, tmp_spin in enumerate(system["spins"][f_idx]): if idx == 0: - magmom_incar += f"{tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" - mconstr_incar += f"{tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" - elif idx == len(system['spins'][f_idx]) - 1: - magmom_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \n" + magmom_incar += ( + f"{tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" + ) + mconstr_incar += ( + f"{tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" + ) + elif idx == len(system["spins"][f_idx]) - 1: + magmom_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \n" mconstr_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \n" else: - magmom_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" + magmom_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" mconstr_incar += f" {tmp_spin[0]:10.5f} {tmp_spin[1]:10.5f} {tmp_spin[2]:10.5f} \ \n" - magmom_incar += '\n' + mconstr_incar + '\n' + magmom_incar += "\n" + mconstr_incar + "\n" return ret, magmom_incar