diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..5855aef6c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + target-branch: "devel" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index acb7d8a4b..716008b30 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,9 @@ jobs: run: pip install -e .[test] - name: Test run: coverage run --source=./dpgen -m unittest -v && coverage report - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v4 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} pass: needs: [build] runs-on: ubuntu-latest diff --git a/.mailmap b/.mailmap new file mode 100644 index 000000000..6e14badd6 --- /dev/null +++ b/.mailmap @@ -0,0 +1 @@ +Jinzhe Zeng diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 75592b2db..c61a7fea0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: # there are many log files in tests # TODO: seperate py files and log files @@ -28,7 +28,7 @@ repos: # Python - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.3 + rev: v0.3.5 hooks: - id: ruff args: ["--fix"] diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..955ea233c --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,4 @@ +prune conda +prune doc +prune tests +prune examples diff --git a/README.md b/README.md index fb5ef39bc..b75939c2e 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,10 @@ Yuzhi Zhang, Haidi Wang, Weijie Chen, Jinzhe Zeng, Linfeng Zhang, Han Wang, and ## Download and Install -DP-GEN only supports Python 3.9 and above. You can use one of the following methods to install DP-GEN: +DP-GEN only supports Python 3.9 and above. You can [setup a conda/pip environment](https://docs.deepmodeling.com/faq/conda.html), and then use one of the following methods to install DP-GEN: - Install via pip: `pip install dpgen` -- Install via conda: `conda install -c conda-forge dpgen`` +- Install via conda: `conda install -c conda-forge dpgen` - Install from source code: `git clone https://github.com/deepmodeling/dpgen && pip install ./dpgen` To test if the installation is successful, you may execute diff --git a/dpgen/auto_test/lib/lammps.py b/dpgen/auto_test/lib/lammps.py index a1e387232..947f5df7f 100644 --- a/dpgen/auto_test/lib/lammps.py +++ b/dpgen/auto_test/lib/lammps.py @@ -189,9 +189,7 @@ def make_lammps_eval(conf, type_map, interaction, param): ret += ( "thermo_style custom step pe pxx pyy pzz pxy pxz pyz lx ly lz vol c_mype\n" ) - ret += ( - "dump 1 all custom 100 dump.relax id type xs ys zs fx fy fz\n" - ) # 06/09 give dump.relax + ret += "dump 1 all custom 100 dump.relax id type xs ys zs fx fy fz\n" # 06/09 give dump.relax ret += "run 0\n" ret += "variable N equal count(all)\n" ret += "variable V equal vol\n" diff --git a/dpgen/auto_test/lib/mfp_eosfit.py b/dpgen/auto_test/lib/mfp_eosfit.py index c28b5651f..227012844 100755 --- a/dpgen/auto_test/lib/mfp_eosfit.py +++ b/dpgen/auto_test/lib/mfp_eosfit.py @@ -1441,16 +1441,7 @@ def ext_velp( ) for i in range(ndata): fw.write( - "{:12.6f}\t{:12.6f}\t{:12.6f}\t{:12.6f}\t{:12.6f}\t{:12.6f}\t{:12.6f}\t{:12.6f}\n".format( - vv[i], - ee[i], - cellaa[i], - cellbb[i], - cellcc[i], - cellbaba[i], - cellcaca[i], - cellca_cal[i], - ) + f"{vv[i]:12.6f}\t{ee[i]:12.6f}\t{cellaa[i]:12.6f}\t{cellbb[i]:12.6f}\t{cellcc[i]:12.6f}\t{cellbaba[i]:12.6f}\t{cellcaca[i]:12.6f}\t{cellca_cal[i]:12.6f}\n" ) fw.flush() fw.close() @@ -1662,9 +1653,7 @@ def lsqfit_eos( ) for i in range(len(vol)): fve.write( - "{:20f}\t{:20f}\t{:20f}\t{:20f}\n".format( - vol[i], repro_en[i], en[i], 100 * np.abs((en[i] - repro_en[i]) / en[i]) - ) + f"{vol[i]:20f}\t{repro_en[i]:20f}\t{en[i]:20f}\t{100 * np.abs((en[i] - repro_en[i]) / en[i]):20f}\n" ) fve.flush() p_tmp = repro_press[i] diff --git a/dpgen/auto_test/lib/pwscf.py b/dpgen/auto_test/lib/pwscf.py index eb3efddcd..e53384003 100644 --- a/dpgen/auto_test/lib/pwscf.py +++ b/dpgen/auto_test/lib/pwscf.py @@ -72,12 +72,7 @@ def _make_pwscf_03_config(sys_data): cc = 0 for ii in range(ntypes): for jj in range(atom_numbs[ii]): - ret += "{} {:f} {:f} {:f}\n".format( - atom_names[ii], - coordinates[cc][0], - coordinates[cc][1], - coordinates[cc][2], - ) + ret += f"{atom_names[ii]} {coordinates[cc][0]:f} {coordinates[cc][1]:f} {coordinates[cc][2]:f}\n" cc += 1 return ret diff --git a/dpgen/auto_test/reproduce.py b/dpgen/auto_test/reproduce.py index ada3102fb..47c266d61 100644 --- a/dpgen/auto_test/reproduce.py +++ b/dpgen/auto_test/reproduce.py @@ -153,12 +153,7 @@ def post_repro( output_ener_tot.extend(output_task_result["energies"]) init_epa = init_ener[jj - idid] / natoms - ptr_data += "{} {:7.3f} {:7.3f} {:7.3f}\n".format( - ii, - init_epa, - output_epa, - output_epa - init_epa, - ) + ptr_data += f"{ii} {init_epa:7.3f} {output_epa:7.3f} {output_epa - init_epa:7.3f}\n" idid += nframe output_ener = np.array(output_ener) output_ener = np.reshape(output_ener, [-1, 1]) diff --git a/dpgen/collect/collect.py b/dpgen/collect/collect.py index 808341e6f..ab1cc9406 100644 --- a/dpgen/collect/collect.py +++ b/dpgen/collect/collect.py @@ -8,6 +8,7 @@ import dpdata from dpgen.generator.run import data_system_fmt +from dpgen.util import expand_sys_str def collect_data( @@ -18,7 +19,8 @@ def collect_data( # goto input cwd = os.getcwd() os.chdir(target_folder) - jdata = json.load(open(param_file)) + with open(param_file) as fp: + jdata = json.load(fp) sys_configs_prefix = jdata.get("sys_configs_prefix", "") sys_configs = jdata.get("sys_configs", []) if verbose: @@ -46,6 +48,7 @@ def collect_data( for ii in range(len(iters)): iter_data = glob.glob(os.path.join(iters[ii], "02.fp", "data.[0-9]*[0-9]")) iter_data.sort() + iter_data = sum([expand_sys_str(ii) for ii in iter_data], []) for jj in iter_data: sys = dpdata.LabeledSystem(jj, fmt="deepmd/npy") if merge: diff --git a/dpgen/data/surf.py b/dpgen/data/surf.py index 5194af5b3..2590f9a6b 100644 --- a/dpgen/data/surf.py +++ b/dpgen/data/surf.py @@ -415,7 +415,10 @@ def poscar_scale(poscar_in, poscar_out, scale): except AttributeError: poscar = Poscar.from_str("".join(lines)) with open(poscar_out, "w") as fout: - fout.write(poscar.get_string(direct=False)) + try: + fout.write(poscar.get_string(direct=False)) + except AttributeError: + fout.write(poscar.get_str(direct=False)) def make_scale(jdata): diff --git a/dpgen/data/tools/bcc.py b/dpgen/data/tools/bcc.py index 9c471e36b..3ba99aa6f 100644 --- a/dpgen/data/tools/bcc.py +++ b/dpgen/data/tools/bcc.py @@ -17,7 +17,7 @@ def poscar_unit(latt): ret += f"{box[0][0]:.16f} {box[0][1]:.16f} {box[0][2]:.16f}\n" ret += f"{box[1][0]:.16f} {box[1][1]:.16f} {box[1][2]:.16f}\n" ret += f"{box[2][0]:.16f} {box[2][1]:.16f} {box[2][2]:.16f}\n" - ret += "Type\n" + ret += "X\n" ret += "%d\n" % numb_atoms() ret += "Direct\n" ret += f"{0.0:.16f} {0.0:.16f} {0.0:.16f}\n" diff --git a/dpgen/data/tools/diamond.py b/dpgen/data/tools/diamond.py index f4a2b52a3..f7d82d01e 100644 --- a/dpgen/data/tools/diamond.py +++ b/dpgen/data/tools/diamond.py @@ -22,7 +22,7 @@ def poscar_unit(latt): ret += f"{box[0][0]:.16f} {box[0][1]:.16f} {box[0][2]:.16f}\n" ret += f"{box[1][0]:.16f} {box[1][1]:.16f} {box[1][2]:.16f}\n" ret += f"{box[2][0]:.16f} {box[2][1]:.16f} {box[2][2]:.16f}\n" - ret += "Type\n" + ret += "X\n" ret += "%d\n" % numb_atoms() ret += "Direct\n" ret += f"{0.12500000000000:.16f} {0.12500000000000:.16f} {0.12500000000000:.16f}\n" diff --git a/dpgen/data/tools/fcc.py b/dpgen/data/tools/fcc.py index 80f0b476b..a89ef5385 100644 --- a/dpgen/data/tools/fcc.py +++ b/dpgen/data/tools/fcc.py @@ -17,7 +17,7 @@ def poscar_unit(latt): ret += f"{box[0][0]:.16f} {box[0][1]:.16f} {box[0][2]:.16f}\n" ret += f"{box[1][0]:.16f} {box[1][1]:.16f} {box[1][2]:.16f}\n" ret += f"{box[2][0]:.16f} {box[2][1]:.16f} {box[2][2]:.16f}\n" - ret += "Type\n" + ret += "X\n" ret += "%d\n" % numb_atoms() ret += "Direct\n" ret += f"{0.0:.16f} {0.0:.16f} {0.0:.16f}\n" diff --git a/dpgen/data/tools/hcp.py b/dpgen/data/tools/hcp.py index aeea4afc3..bfd2fa3c4 100644 --- a/dpgen/data/tools/hcp.py +++ b/dpgen/data/tools/hcp.py @@ -20,7 +20,7 @@ def poscar_unit(latt): ret += f"{box[0][0]:.16f} {box[0][1]:.16f} {box[0][2]:.16f}\n" ret += f"{box[1][0]:.16f} {box[1][1]:.16f} {box[1][2]:.16f}\n" ret += f"{box[2][0]:.16f} {box[2][1]:.16f} {box[2][2]:.16f}\n" - ret += "Type\n" + ret += "X\n" ret += "%d\n" % numb_atoms() ret += "Direct\n" ret += f"{0:.16f} {0:.16f} {0:.16f}\n" diff --git a/dpgen/data/tools/ovito_file_convert.py b/dpgen/data/tools/ovito_file_convert.py index 252b70b22..b22f7e44d 100755 --- a/dpgen/data/tools/ovito_file_convert.py +++ b/dpgen/data/tools/ovito_file_convert.py @@ -2,6 +2,7 @@ """This Script is adapted from Alexander Stukowski, the author of OVITO. See: http://forum.ovito.org/index.php?topic=131.0 for details. """ + import argparse from ovito.io import export_file, import_file diff --git a/dpgen/data/tools/sc.py b/dpgen/data/tools/sc.py index fff019d6d..fdcbe0107 100644 --- a/dpgen/data/tools/sc.py +++ b/dpgen/data/tools/sc.py @@ -17,7 +17,7 @@ def poscar_unit(latt): ret += f"{box[0][0]:.16f} {box[0][1]:.16f} {box[0][2]:.16f}\n" ret += f"{box[1][0]:.16f} {box[1][1]:.16f} {box[1][2]:.16f}\n" ret += f"{box[2][0]:.16f} {box[2][1]:.16f} {box[2][2]:.16f}\n" - ret += "Type\n" + ret += "X\n" ret += "%d\n" % numb_atoms() ret += "Direct\n" ret += f"{0.0:.16f} {0.0:.16f} {0.0:.16f}\n" diff --git a/dpgen/generator/arginfo.py b/dpgen/generator/arginfo.py index e1d220e42..9ed6ba887 100644 --- a/dpgen/generator/arginfo.py +++ b/dpgen/generator/arginfo.py @@ -90,7 +90,7 @@ def training_args() -> list[Argument]: doc_numb_models = "Number of models to be trained in 00.train. 4 is recommend." doc_training_iter0_model_path = "The model used to init the first iter training. Number of element should be equal to numb_models." doc_training_init_model = "Iteration > 0, the model parameters will be initilized from the model trained at the previous iteration. Iteration == 0, the model parameters will be initialized from training_iter0_model_path." - doc_default_training_param = "Training parameters for deepmd-kit in 00.train. You can find instructions from here: (https://github.com/deepmodeling/deepmd-kit)." + doc_default_training_param = "Training parameters for deepmd-kit in 00.train. You can find instructions from `DeePMD-kit documentation `_." doc_dp_train_skip_neighbor_stat = "Append --skip-neighbor-stat flag to dp train." doc_dp_compress = "Use dp compress to compress the model." doc_training_reuse_iter = "The minimal index of iteration that continues training models from old models of last iteration." @@ -221,8 +221,8 @@ def model_devi_jobs_template_args() -> Argument: "Through user-defined template, any freedom (function) that is permitted by the engine " "software could be inherited (invoked) in the workflow." ) - doc_template_lmp = "The path to input.lammps template" - doc_template_plm = "The path to input.plumed template" + doc_template_lmp = "The path to input.lammps template. Instructions can be found in `LAMMPS documentation `_." + doc_template_plm = "The path to input.plumed template. Instructions can be found in `PLUMED documentation `_." args = [ Argument("lmp", str, optional=True, doc=doc_template_lmp), @@ -325,10 +325,12 @@ def model_devi_lmp_args() -> list[Argument]: doc_model_devi_f_trust_hi = "Upper bound of forces for the selection. If list or dict, should be set for each index in sys_configs, respectively." doc_model_devi_v_trust_lo = "Lower bound of virial for the selection. If list or dict, should be set for each index in sys_configs, respectively. Should be used with DeePMD-kit v2.x." doc_model_devi_v_trust_hi = "Upper bound of virial for the selection. If list or dict, should be set for each index in sys_configs, respectively. Should be used with DeePMD-kit v2.x." - doc_model_devi_adapt_trust_lo = "Adaptively determines the lower trust levels of force and virial. This option should be used together with model_devi_numb_candi_f, model_devi_numb_candi_v and optionally with model_devi_perc_candi_f and model_devi_perc_candi_v. dpgen will make two sets:\n\n\ + doc_model_devi_adapt_trust_lo = ( + "Adaptively determines the lower trust levels of force and virial. This option should be used together with model_devi_numb_candi_f, model_devi_numb_candi_v and optionally with model_devi_perc_candi_f and model_devi_perc_candi_v. dpgen will make two sets:\n\n\ - 1. From the frames with force model deviation lower than model_devi_f_trust_hi, select max(model_devi_numb_candi_f, model_devi_perc_candi_f*n_frames) frames with largest force model deviation. \n\n\ - 2. From the frames with virial model deviation lower than model_devi_v_trust_hi, select max(model_devi_numb_candi_v, model_devi_perc_candi_v*n_frames) frames with largest virial model deviation. \n\n\ The union of the two sets is made as candidate dataset." + ) doc_model_devi_numb_candi_f = "See model_devi_adapt_trust_lo." doc_model_devi_numb_candi_v = "See model_devi_adapt_trust_lo." doc_model_devi_perc_candi_f = "See model_devi_adapt_trust_lo." @@ -790,13 +792,14 @@ def fp_style_cp2k_args() -> list[Argument]: ] +# amber/diff def fp_style_amber_diff_args() -> list[Argument]: """Arguments for FP style amber/diff. Returns ------- list[dargs.Argument] - list of Gaussian fp style arguments + list of amber/diff fp style arguments """ doc_fp_params_gaussian = "Parameters for FP calculation." doc_high_level = ( @@ -827,13 +830,49 @@ def fp_style_amber_diff_args() -> list[Argument]: ] +# pwscf +def fp_style_pwscf_args() -> list[Argument]: + """Arguments for FP style pwscf (Quantum Espresso). + + Returns + ------- + list[dargs.Argument] + list of pwscf fp style arguments + """ + doc_fp_pp_path = "Directory of psuedo-potential file to be used for 02.fp exists." + doc_fp_pp_files = "Psuedo-potential file to be used for 02.fp. Note that the order of elements should correspond to the order in type_map." + doc_user_fp_params = "Parameters for pwscf calculation. Find details at https://www.quantum-espresso.org/Doc/INPUT_PW.html. When user_fp_params is set, the settings in fp_params will be ignored. If one wants to use user_fp_params, kspacing must be set in user_fp_params. kspacing is the spacing between kpoints, and helps to determin KPOINTS in pwscf." + doc_fp_params = ( + "Parameters for pwscf calculation. It has lower priority than user_fp_params." + ) + doc_ecut = "ecutwfc in pwscf." + doc_ediff = "conv_thr and ts_vdw_econv_thr in pwscf." + doc_kspacing = "The spacing between kpoints. Helps to determin KPOINTS in pwscf." + doc_smearing = "smearing in pwscf." + doc_sigma = "degauss in pwscf." + + args = [ + Argument("ecut", float, optional=False, doc=doc_ecut), + Argument("ediff", float, optional=False, doc=doc_ediff), + Argument("smearing", str, optional=False, doc=doc_smearing), + Argument("sigma", float, optional=False, doc=doc_sigma), + Argument("kspacing", float, optional=False, doc=doc_kspacing), + ] + return [ + Argument("fp_pp_path", str, optional=False, doc=doc_fp_pp_path), + Argument("fp_pp_files", list[str], optional=False, doc=doc_fp_pp_files), + Argument("fp_params", dict, args, [], optional=True, doc=doc_fp_params), + Argument("user_fp_params", dict, optional=True, doc=doc_user_fp_params), + ] + + def fp_style_custom_args() -> list[Argument]: """Arguments for FP style custom. Returns ------- list[dargs.Argument] - list of Gaussian fp style arguments + list of custom fp style arguments """ doc_fp_params_custom = "Parameters for FP calculation." doc_input_fmt = "Input dpdata format of the custom FP code. Such format should only need the first argument as the file name." @@ -883,7 +922,7 @@ def fp_style_variant_type_args() -> Variant: "amber/diff", dict, fp_style_amber_diff_args(), doc=doc_amber_diff ), Argument("pwmat", dict, [], doc="TODO: add doc"), - Argument("pwscf", dict, [], doc="TODO: add doc"), + Argument("pwscf", dict, fp_style_pwscf_args()), Argument("custom", dict, fp_style_custom_args(), doc=doc_custom), ], optional=False, diff --git a/dpgen/generator/lib/abacus_scf.py b/dpgen/generator/lib/abacus_scf.py index 561d84500..744147e88 100644 --- a/dpgen/generator/lib/abacus_scf.py +++ b/dpgen/generator/lib/abacus_scf.py @@ -401,9 +401,9 @@ def get_abacus_STRU(STRU, INPUT=None, n_ele=None): data["atom_types"] = types data["cells"] = cell data["coords"] = coords - data[ - "atom_masses" - ] = masses # Notice that this key is not defined in dpdata system. + data["atom_masses"] = ( + masses # Notice that this key is not defined in dpdata system. + ) data["pp_files"] = pp_files data["orb_files"] = orb_files data["dpks_descriptor"] = dpks_descriptor diff --git a/dpgen/generator/lib/cp2k.py b/dpgen/generator/lib/cp2k.py index 4ab9ae4c5..a73a94d7a 100644 --- a/dpgen/generator/lib/cp2k.py +++ b/dpgen/generator/lib/cp2k.py @@ -48,13 +48,15 @@ def update_dict(old_d, update_d): old_d[k] = update_d[k] -def iterdict(d, out_list, flag=None): - """:doc: a recursive expansion of dictionary into cp2k input +def iterdict(d, out_list, flag=None, indent=0): + """ + :doc: a recursive expansion of dictionary into cp2k input :k: current key :v: current value :d: current dictionary under expansion :flag: used to record dictionary state. if flag is None, it means we are in top level dict. flag is a string. + :indent: intent for current section. """ for k, v in d.items(): k = str(k) # cast key into string @@ -64,16 +66,17 @@ def iterdict(d, out_list, flag=None): if flag is None: out_list.append("&" + k) out_list.append("&END " + k) - iterdict(v, out_list, k) + iterdict(v, out_list, k, indent + 2) # flag is not None, now it has name of section else: - index = out_list.index("&END " + flag) - out_list.insert(index, "&" + k) - out_list.insert(index + 1, "&END " + k) - iterdict(v, out_list, k) + index = out_list.index(" " * (indent - 2) + "&END " + flag) + out_list.insert(index, " " * indent + "&" + k + " #" + flag) + out_list.insert(index + 1, " " * indent + "&END " + k + " #" + flag) + # the flag now contains its parent section name, separed by "#". + iterdict(v, out_list, k + " #" + flag, indent + 2) elif isinstance(v, list): # print("we have encountered the repeat section!") - index = out_list.index("&" + flag) + index = out_list.index(" " * (indent - 2) + "&" + flag) # delete the current constructed repeat section del out_list[index : index + 2] # do a loop over key and corresponding list @@ -83,14 +86,22 @@ def iterdict(d, out_list, flag=None): k_tmp_list.append(str(k_tmp)) v_list_tmp_list.append(v_tmp) for repeat_keyword in zip(*v_list_tmp_list): - out_list.insert(index, "&" + flag) - out_list.insert(index + 1, "&END " + flag) + out_list.insert(index, " " * (indent - 2) + "&" + flag) + out_list.insert(index + 1, " " * (indent - 2) + "&END " + flag) for idx, k_tmp in enumerate(k_tmp_list): if k_tmp == "_": - out_list[index] = "&" + flag + " " + repeat_keyword[idx] + out_list[index] = ( + " " * (indent - 2) + + "&" + + flag.split(" #")[0] + + " " + + repeat_keyword[idx] + ) else: - out_list.insert(index + 1, k_tmp + " " + repeat_keyword[idx]) - + out_list.insert( + index + 1, + " " * (indent) + k_tmp + " " + repeat_keyword[idx], + ) break else: @@ -100,12 +111,14 @@ def iterdict(d, out_list, flag=None): print(k, ":", v) else: if k == "_": - index = out_list.index("&" + flag) - out_list[index] = "&" + flag + " " + v + index = out_list.index(" " * (indent - 2) + "&" + flag) + out_list[index] = ( + " " * (indent - 2) + "&" + flag.split(" #")[0] + " " + v + ) else: - index = out_list.index("&END " + flag) - out_list.insert(index, k + " " + v) + index = out_list.index(" " * (indent - 2) + "&END " + flag) + out_list.insert(index, " " * indent + k + " " + v) def make_cp2k_input(sys_data, fp_params): diff --git a/dpgen/generator/lib/lammps.py b/dpgen/generator/lib/lammps.py index d9ff4a493..d96415a3f 100644 --- a/dpgen/generator/lib/lammps.py +++ b/dpgen/generator/lib/lammps.py @@ -169,11 +169,7 @@ def make_lammps_input( pka_vec = _sample_sphere() pka_vec *= pka_vn ret += "group first id 1\n" - ret += 'if "${{restart}} == 0" then "velocity first set {:f} {:f} {:f}"\n'.format( - pka_vec[0], - pka_vec[1], - pka_vec[2], - ) + ret += f'if "${{restart}} == 0" then "velocity first set {pka_vec[0]:f} {pka_vec[1]:f} {pka_vec[2]:f}"\n' ret += "fix 2 all momentum 1 linear 1 1 1\n" ret += "\n" if ensemble.split("-")[0] == "npt": diff --git a/dpgen/generator/lib/pwscf.py b/dpgen/generator/lib/pwscf.py index c4a86fc80..ebd8a2dc0 100644 --- a/dpgen/generator/lib/pwscf.py +++ b/dpgen/generator/lib/pwscf.py @@ -88,7 +88,7 @@ def _make_pwscf_02_species(sys_data, pps): assert ntypes == len(atom_masses) assert ntypes == len(pps) for ii in range(ntypes): - ret += "%s %d %s\n" % (atom_names[ii], atom_masses[ii], pps[ii]) + ret += f"{atom_names[ii]} {atom_masses[ii]} {pps[ii]}\n" return ret @@ -110,12 +110,7 @@ def _make_pwscf_03_config(sys_data): cc = 0 for ii in range(ntypes): for jj in range(atom_numbs[ii]): - ret += "{} {:f} {:f} {:f}\n".format( - atom_names[ii], - coordinates[cc][0], - coordinates[cc][1], - coordinates[cc][2], - ) + ret += f"{atom_names[ii]} {coordinates[cc][0]:f} {coordinates[cc][1]:f} {coordinates[cc][2]:f}\n" cc += 1 return ret diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index 034918efc..6d9f1c4e4 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -19,6 +19,7 @@ import queue import random import re +import shlex import shutil import sys import warnings @@ -590,21 +591,21 @@ def make_train(iter_index, jdata, mdata): if ( len(np.array(model_devi_activation_func).shape) == 2 ): # 2-dim list for emd/fitting net-resolved assignment of actF - jinput["model"]["descriptor"][ - "activation_function" - ] = model_devi_activation_func[ii][0] - jinput["model"]["fitting_net"][ - "activation_function" - ] = model_devi_activation_func[ii][1] + jinput["model"]["descriptor"]["activation_function"] = ( + model_devi_activation_func[ii][0] + ) + jinput["model"]["fitting_net"]["activation_function"] = ( + model_devi_activation_func[ii][1] + ) if ( len(np.array(model_devi_activation_func).shape) == 1 ): # for backward compatibility, 1-dim list, not net-resolved - jinput["model"]["descriptor"][ - "activation_function" - ] = model_devi_activation_func[ii] - jinput["model"]["fitting_net"][ - "activation_function" - ] = model_devi_activation_func[ii] + jinput["model"]["descriptor"]["activation_function"] = ( + model_devi_activation_func[ii] + ) + jinput["model"]["fitting_net"]["activation_function"] = ( + model_devi_activation_func[ii] + ) # dump the input.json with open(os.path.join(task_path, train_input_file), "w") as outfile: json.dump(jinput, outfile, indent=4) @@ -632,7 +633,10 @@ def make_train(iter_index, jdata, mdata): % numb_models ) for ii in range(len(iter0_models)): - old_model_files = glob.glob(os.path.join(iter0_models[ii], "model.ckpt*")) + old_model_path = os.path.join(iter0_models[ii], "model.ckpt*") + old_model_files = glob.glob(old_model_path) + if not len(old_model_files): + raise FileNotFoundError(f"{old_model_path} not found!") _link_old_models(work_path, old_model_files, ii) copied_models = next( ( @@ -763,7 +767,7 @@ def run_train(iter_index, jdata, mdata): init_flag = " --finetune old/init.pb" command = f"{train_command} train {train_input_file}{extra_flags}" command = f"{{ if [ ! -f model.ckpt.index ]; then {command}{init_flag}; else {command} --restart model.ckpt; fi }}" - command = "/bin/sh -c '%s'" % command + command = "/bin/sh -c %s" % shlex.quote(command) commands.append(command) command = "%s freeze" % train_command commands.append(command) @@ -1038,9 +1042,9 @@ def revise_lmp_input_dump(lmp_lines, trj_freq, model_devi_merge_traj=False): def revise_lmp_input_plm(lmp_lines, in_plm, out_plm="output.plumed"): idx = find_only_one_key(lmp_lines, ["fix", "dpgen_plm"]) - lmp_lines[ - idx - ] = f"fix dpgen_plm all plumed plumedfile {in_plm} outfile {out_plm}\n" + lmp_lines[idx] = ( + f"fix dpgen_plm all plumed plumedfile {in_plm} outfile {out_plm}\n" + ) return lmp_lines @@ -1811,9 +1815,10 @@ def _make_model_devi_amber( nsteps = jdata["nsteps"] for ii, pp in enumerate(mdin): - with open(pp) as f, open( - os.path.join(work_path, "init%d.mdin" % ii), "w" - ) as fw: + with ( + open(pp) as f, + open(os.path.join(work_path, "init%d.mdin" % ii), "w") as fw, + ): mdin_str = f.read() # freq, nstlim, qm_region, qm_theory, qm_charge, rcut, graph mdin_str = ( @@ -1879,9 +1884,10 @@ def _make_model_devi_amber( if not isinstance(r, Iterable) or isinstance(r, str): r = [r] # disang file should include RVAL, RVAL2, ... - with open(disang[sys_idx[sys_counter]]) as f, open( - "TEMPLATE.disang", "w" - ) as fw: + with ( + open(disang[sys_idx[sys_counter]]) as f, + open("TEMPLATE.disang", "w") as fw, + ): tl = f.read() for ii, rr in enumerate(r): if isinstance(rr, Iterable) and not isinstance(rr, str): @@ -1941,7 +1947,7 @@ def run_md_model_devi(iter_index, jdata, mdata): command = f"{{ if [ ! -f dpgen.restart.10000 ]; then {model_devi_exec} -i input.lammps -v restart 0; else {model_devi_exec} -i input.lammps -v restart 1; fi }}" else: command = f"{{ all_exist=true; for i in $(seq -w 1 {nbeads}); do [[ ! -f dpgen.restart${{i}}.10000 ]] && {{ all_exist=false; break; }}; done; $all_exist && {{ {model_devi_exec} -p {nbeads}x1 -i input.lammps -v restart 1; }} || {{ {model_devi_exec} -p {nbeads}x1 -i input.lammps -v restart 0; }} }}" - command = "/bin/bash -c '%s'" % command + command = "/bin/bash -c %s" % shlex.quote(command) commands = [command] forward_files = ["conf.lmp", "input.lammps"] @@ -1953,6 +1959,7 @@ def run_md_model_devi(iter_index, jdata, mdata): backward_files += [ f"model_devi{i+1:0{num_digits}d}.out" for i in range(nbeads) ] + backward_files += [f"log.lammps.{i:d}" for i in range(nbeads)] if model_devi_merge_traj: backward_files += ["all.lammpstrj"] else: @@ -1994,14 +2001,7 @@ def run_md_model_devi(iter_index, jdata, mdata): if ndx_filename: command += f'&& echo -e "{grp_name}\\n{grp_name}\\n" | {model_devi_exec} trjconv -s {ref_filename} -f {deffnm}.trr -n {ndx_filename} -o {traj_filename} -pbc mol -ur compact -center' else: - command += '&& echo -e "{}\\n{}\\n" | {} trjconv -s {} -f {}.trr -o {} -pbc mol -ur compact -center'.format( - grp_name, - grp_name, - model_devi_exec, - ref_filename, - deffnm, - traj_filename, - ) + command += f'&& echo -e "{grp_name}\\n{grp_name}\\n" | {model_devi_exec} trjconv -s {ref_filename} -f {deffnm}.trr -o {traj_filename} -pbc mol -ur compact -center' command += "&& if [ ! -d traj ]; then \n mkdir traj; fi\n" command += f"python -c \"import dpdata;system = dpdata.System('{traj_filename}', fmt='gromacs/gro'); [system.to_gromacs_gro('traj/%d.gromacstrj' % (i * {trj_freq}), frame_idx=i) for i in range(system.get_nframes())]; system.to_deepmd_npy('traj_deepmd')\"" command += f"&& dp model-devi -m ../graph.000.pb ../graph.001.pb ../graph.002.pb ../graph.003.pb -s traj_deepmd -o model_devi.out -f {trj_freq}" @@ -2163,10 +2163,11 @@ def _read_model_devi_file( model_devi_merge_traj: bool = False, ): model_devi_files = glob.glob(os.path.join(task_path, "model_devi*.out")) - model_devi_files_sorted = sorted( - model_devi_files, key=lambda x: int(re.search(r"(\d+)", x).group(1)) - ) - if len(model_devi_files_sorted) > 1: + if len(model_devi_files) > 1: + model_devi_files_sorted = sorted( + model_devi_files, + key=lambda x: int(re.search(r"model_devi(\d+)\.out", x).group(1)), + ) with open(model_devi_files_sorted[0]) as f: first_line = f.readline() if not (first_line.startswith("#")): @@ -2179,8 +2180,6 @@ def _read_model_devi_file( model_devi_content.shape[0] == model_devi_contents[0].shape[0] for model_devi_content in model_devi_contents ), "Not all beads generated the same number of lines in the model_devi$\{ibead\}.out file. Check your pimd task carefully." - for file in model_devi_files_sorted: - os.remove(file) last_step = model_devi_contents[0][-1, 0] for ibead in range(1, num_beads): model_devi_contents[ibead][:, 0] = model_devi_contents[ibead][ @@ -2504,9 +2503,7 @@ def _make_fp_vasp_inner( tot = len(summaryfmax) - nan_num candi_num = tot - acc_num - fail_num dlog.info( - "summary accurate_ratio: {:8.4f}% candidata_ratio: {:8.4f}% failed_ratio: {:8.4f}% in {:d} structures".format( - acc_num * 100 / tot, candi_num * 100 / tot, fail_num * 100 / tot, tot - ) + f"summary accurate_ratio: {acc_num * 100 / tot:8.4f}% candidata_ratio: {candi_num * 100 / tot:8.4f}% failed_ratio: {fail_num * 100 / tot:8.4f}% in {tot:d} structures" ) # -------------------------------------------------------------------------------------------------------------------------------------- @@ -2658,9 +2655,7 @@ def _trust_limitation_check(sys_idx, lim): continue for cc_key, cc_value in counter.items(): dlog.info( - "system {:s} {:9s} : {:6d} in {:6d} {:6.2f} %".format( - ss, cc_key, cc_value, fp_sum, cc_value / fp_sum * 100 - ) + f"system {ss:s} {cc_key:9s} : {cc_value:6d} in {fp_sum:6d} {cc_value / fp_sum * 100:6.2f} %" ) random.shuffle(fp_candidate) if detailed_report_make_fp: @@ -2734,15 +2729,7 @@ def _trust_limitation_check(sys_idx, lim): numb_task = 0 # ---------------------------------------------------------------------------- dlog.info( - "system {:s} accurate_ratio: {:8.4f} thresholds: {:6.4f} and {:6.4f} eff. task min and max {:4d} {:4d} number of fp tasks: {:6d}".format( - ss, - accurate_ratio, - fp_accurate_soft_threshold, - fp_accurate_threshold, - fp_task_min, - this_fp_task_max, - numb_task, - ) + f"system {ss:s} accurate_ratio: {accurate_ratio:8.4f} thresholds: {fp_accurate_soft_threshold:6.4f} and {fp_accurate_threshold:6.4f} eff. task min and max {fp_task_min:4d} {this_fp_task_max:4d} number of fp tasks: {numb_task:6d}" ) # make fp tasks @@ -2874,21 +2861,15 @@ def _trust_limitation_check(sys_idx, lim): os.chdir(cwd) if count_bad_box > 0: dlog.info( - "system {:s} skipped {:6d} confs with bad box, {:6d} remains".format( - ss, count_bad_box, numb_task - count_bad_box - ) + f"system {ss:s} skipped {count_bad_box:6d} confs with bad box, {numb_task - count_bad_box:6d} remains" ) if count_bad_cluster > 0: dlog.info( - "system {:s} skipped {:6d} confs with bad cluster, {:6d} remains".format( - ss, count_bad_cluster, numb_task - count_bad_cluster - ) + f"system {ss:s} skipped {count_bad_cluster:6d} confs with bad cluster, {numb_task - count_bad_cluster:6d} remains" ) if model_devi_engine == "calypso": dlog.info( - "summary accurate_ratio: {:8.4f}% candidata_ratio: {:8.4f}% failed_ratio: {:8.4f}% in {:d} structures".format( - acc_num * 100 / tot, candi_num * 100 / tot, fail_num * 100 / tot, tot - ) + f"summary accurate_ratio: {acc_num * 100 / tot:8.4f}% candidata_ratio: {candi_num * 100 / tot:8.4f}% failed_ratio: {fail_num * 100 / tot:8.4f}% in {tot:d} structures" ) if cluster_cutoff is None: cwd = os.getcwd() @@ -4727,6 +4708,8 @@ def run_iter(param_file, machine_file): ii = -1 while cont: ii += 1 + if ii < iter_rec[0]: + continue iter_name = make_iter_name(ii) sepline(iter_name, "=") for jj in range(numb_task): diff --git a/dpgen/gui.py b/dpgen/gui.py index f116ee246..4f92d43ec 100644 --- a/dpgen/gui.py +++ b/dpgen/gui.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: LGPL-3.0-or-later """DP-GUI entrypoint.""" + import argparse diff --git a/dpgen/simplify/arginfo.py b/dpgen/simplify/arginfo.py index 2fb4547f7..516b27e60 100644 --- a/dpgen/simplify/arginfo.py +++ b/dpgen/simplify/arginfo.py @@ -8,6 +8,7 @@ fp_style_cp2k_args, fp_style_custom_args, fp_style_gaussian_args, + fp_style_pwscf_args, fp_style_siesta_args, fp_style_vasp_args, training_args, @@ -112,6 +113,7 @@ def fp_style_variant_type_args() -> Variant: doc_fp_style = "Software for First Principles, if `labeled` is false." doc_fp_style_none = "No fp." doc_fp_style_vasp = "VASP." + doc_fp_style_pwscf = "pwscf (Quantum Espresso)." doc_fp_style_gaussian = "Gaussian. The command should be set as `g16 < input`." doc_custom = ( "Custom FP code. You need to provide the input and output file format and name. " @@ -136,7 +138,7 @@ def fp_style_variant_type_args() -> Variant: # "amber/diff", dict, fp_style_amber_diff_args(), doc=doc_amber_diff # ), Argument("pwmat", dict, [], doc="TODO: add doc"), - Argument("pwscf", dict, [], doc="TODO: add doc"), + Argument("pwscf", dict, fp_style_pwscf_args(), doc=doc_fp_style_pwscf), Argument("custom", dict, fp_style_custom_args(), doc=doc_custom), ], optional=True, diff --git a/dpgen/simplify/simplify.py b/dpgen/simplify/simplify.py index 98de7c5a8..eec08e8bf 100644 --- a/dpgen/simplify/simplify.py +++ b/dpgen/simplify/simplify.py @@ -8,6 +8,7 @@ 01: calculate model deviations of the rest dataset, pick up data with proper model deviaiton 02: fp (optional, if the original dataset do not have fp data, same as generator) """ + import glob import logging import os @@ -336,9 +337,10 @@ def post_model_devi(iter_index, jdata, mdata): "reach a place that should NOT be reached..." ) else: - with open(os.path.join(work_path, detail_file_name)) as f, open( - os.path.join(work_path, true_error_file_name) - ) as f_err: + with ( + open(os.path.join(work_path, detail_file_name)) as f, + open(os.path.join(work_path, true_error_file_name)) as f_err, + ): for line, line_err in zip(f, f_err): if line.startswith("# data.rest.old"): name = (line.split()[1]).split("/")[-1] @@ -389,9 +391,7 @@ def post_model_devi(iter_index, jdata, mdata): fp_sum = sum(counter.values()) for cc_key, cc_value in counter.items(): dlog.info( - "{:9s} : {:6d} in {:6d} {:6.2f} %".format( - cc_key, cc_value, fp_sum, cc_value / fp_sum * 100 - ) + f"{cc_key:9s} : {cc_value:6d} in {fp_sum:6d} {cc_value / fp_sum * 100:6.2f} %" ) if counter["candidate"] == 0 and counter["failed"] > 0: @@ -550,6 +550,8 @@ def run_iter(param_file, machine_file): ii = -1 while cont: ii += 1 + if ii < iter_rec[0]: + continue iter_name = make_iter_name(ii) sepline(iter_name, "=") for jj in range(numb_task): diff --git a/examples/run/dp2.x-lammps-pwscf/Al/Al_ONCV_PBE_sr.upf b/examples/run/dp2.x-lammps-pwscf/Al/Al_ONCV_PBE_sr.upf new file mode 100644 index 000000000..e819ad123 --- /dev/null +++ b/examples/run/dp2.x-lammps-pwscf/Al/Al_ONCV_PBE_sr.upf @@ -0,0 +1 @@ +You may download the needed pseudopotential files online. An example is https://github.com/pipidog/ONCVPSP. diff --git a/examples/run/dp2.x-lammps-pwscf/Al/param_al_all_gpu-deepmd-kit-2.x.json b/examples/run/dp2.x-lammps-pwscf/Al/param_al_all_gpu-deepmd-kit-2.x.json new file mode 100644 index 000000000..535a81d4c --- /dev/null +++ b/examples/run/dp2.x-lammps-pwscf/Al/param_al_all_gpu-deepmd-kit-2.x.json @@ -0,0 +1,452 @@ +{ + "type_map": [ + "Al" + ], + "mass_map": [ + 27 + ], + "init_data_prefix": "/data1/yfb222333/2_dpgen_gpu_multi/init/", + "init_data_sys": [ + "al.fcc.02x02x02/02.md/sys-0032/deepmd", + "al.hcp.02x02x02/02.md/sys-0016/deepmd", + "al.bcc.02x02x02/02.md/sys-0016/deepmd" + ], + "sys_configs": [ + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00000[0-4]/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00000[5-9]/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00001*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00002*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00003*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00004*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00005*/POSCAR", + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00006*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00007*/POSCAR", + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00008*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.hcp.02x02x02/01.scale_pert/sys-0016/scale-1.000/00000[0-4]/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.hcp.02x02x02/01.scale_pert/sys-0016/scale-1.000/00000[5-9]/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.hcp.02x02x02/01.scale_pert/sys-0016/scale-1.000/00001*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.hcp.02x02x02/01.scale_pert/sys-0016/scale-1.000/00002*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.hcp.02x02x02/01.scale_pert/sys-0016/scale-1.000/00003*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.hcp.02x02x02/01.scale_pert/sys-0016/scale-1.000/00004*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.hcp.02x02x02/01.scale_pert/sys-0016/scale-1.000/00005*/POSCAR", + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.hcp.02x02x02/01.scale_pert/sys-0016/scale-1.000/00006*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.hcp.02x02x02/01.scale_pert/sys-0016/scale-1.000/00007*/POSCAR", + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.hcp.02x02x02/01.scale_pert/sys-0016/scale-1.000/00008*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.bcc.02x02x02/01.scale_pert/sys-0016/scale-1.000/00000[0-4]/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.bcc.02x02x02/01.scale_pert/sys-0016/scale-1.000/00000[5-9]/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.bcc.02x02x02/01.scale_pert/sys-0016/scale-1.000/00001*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.bcc.02x02x02/01.scale_pert/sys-0016/scale-1.000/00002*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.bcc.02x02x02/01.scale_pert/sys-0016/scale-1.000/00003*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.bcc.02x02x02/01.scale_pert/sys-0016/scale-1.000/00004*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.bcc.02x02x02/01.scale_pert/sys-0016/scale-1.000/00005*/POSCAR", + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.bcc.02x02x02/01.scale_pert/sys-0016/scale-1.000/00006*/POSCAR" + ], + [ + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.bcc.02x02x02/01.scale_pert/sys-0016/scale-1.000/00007*/POSCAR", + "/data1/yfb222333/2_dpgen_gpu_multi/init/al.bcc.02x02x02/01.scale_pert/sys-0016/scale-1.000/00008*/POSCAR" + ] + ], + "_comment1": " 00.train ", + "numb_models": 4, + "default_training_param": { + "model": { + "_comment2": " model parameters", + "type_map": [ + "Al" + ], + "descriptor": { + "type": "se_a", + "sel": [ + 300 + ], + "rcut_smth": 2.0, + "rcut": 8.0, + "neuron": [ + 240, + 240, + 240 + ], + "resnet_dt": true, + "axis_neuron": 12, + "seed": 1 + }, + "fitting_net": { + "neuron": [ + 25, + 50, + 100 + ], + "resnet_dt": false, + "sedd": 1 + } + }, + "learning_rate": { + "type": "exp", + "start_lr": 0.001, + "decay_steps": 2000, + "stop_lr": 0.0005987369392383787 + }, + "loss": { + "start_pref_e": 0.02, + "limit_pref_e": 2, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0.0, + "limit_pref_v": 0.0 + }, + "training": { + "coord_norm": true, + "type_fitting_net": false, + "_comment3": " traing controls", + "stop_batch": 20000, + "seed": 0, + "_comment4": " display and restart", + "_comment5": " frequencies counted in batch", + "disp_file": "lcurve.out", + "disp_freq": 2000, + "save_freq": 2000, + "save_ckpt": "model.ckpt", + "disp_training": true, + "time_training": true, + "profiling": false, + "profiling_file": "timeline.json", + "_comment6": "that's all", + "training_data": { + "systems": [], + "set_prefix": "set", + "batch_size": 1 + } + } + }, + "_comment7": " 01.model_devi ", + "_comment8": "model_devi_skip: the first x of the recorded frames", + "model_devi_dt": 0.002, + "model_devi_skip": 0, + "model_devi_f_trust_lo": 0.05, + "model_devi_f_trust_hi": 0.2, + "model_devi_clean_traj": false, + "model_devi_jobs": [ + { + "_idx": 0, + "ensemble": "npt", + "nsteps": 1000, + "press": [ + 1.0, + 10.0, + 100.0, + 1000.0, + 5000.0, + 10000.0, + 20000.0, + 50000.0 + ], + "sys_idx": [ + 0, + 8, + 16 + ], + "temps": [ + 50, + 132.0, + 198.0, + 264.0 + ], + "trj_freq": 10 + }, + { + "_idx": 1, + "ensemble": "npt", + "nsteps": 1000, + "press": [ + 1.0, + 10.0, + 100.0, + 1000.0, + 5000.0, + 10000.0, + 20000.0, + 50000.0 + ], + "sys_idx": [ + 1, + 9, + 17 + ], + "temps": [ + 50, + 132.0, + 198.0, + 264.0 + ], + "trj_freq": 10 + }, + { + "_idx": 2, + "ensemble": "npt", + "nsteps": 3000, + "press": [ + 1.0, + 10.0, + 100.0, + 1000.0, + 5000.0, + 10000.0, + 20000.0, + 50000.0 + ], + "sys_idx": [ + 2, + 10, + 18 + ], + "temps": [ + 50, + 132.0, + 198.0, + 264.0 + ], + "trj_freq": 10 + }, + { + "_idx": 3, + "ensemble": "npt", + "nsteps": 3000, + "press": [ + 1.0, + 10.0, + 100.0, + 1000.0, + 5000.0, + 10000.0, + 20000.0, + 50000.0 + ], + "sys_idx": [ + 3, + 11, + 19 + ], + "temps": [ + 50, + 132.0, + 198.0, + 264.0 + ], + "trj_freq": 10 + }, + { + "_idx": 4, + "ensemble": "npt", + "nsteps": 3000, + "press": [ + 1.0, + 10.0, + 100.0, + 1000.0, + 5000.0, + 10000.0, + 20000.0, + 50000.0 + ], + "sys_idx": [ + 4, + 12, + 20 + ], + "temps": [ + 50, + 132.0, + 198.0, + 264.0 + ], + "trj_freq": 10 + }, + { + "_idx": 5, + "ensemble": "npt", + "nsteps": 3000, + "press": [ + 1.0, + 10.0, + 100.0, + 1000.0, + 5000.0, + 10000.0, + 20000.0, + 50000.0 + ], + "sys_idx": [ + 5, + 13, + 21 + ], + "temps": [ + 50, + 132.0, + 198.0, + 264.0 + ], + "trj_freq": 10 + }, + { + "_idx": 6, + "ensemble": "npt", + "nsteps": 3000, + "press": [ + 1.0, + 10.0, + 100.0, + 1000.0, + 5000.0, + 10000.0, + 20000.0, + 50000.0 + ], + "sys_idx": [ + 6, + 14, + 22 + ], + "temps": [ + 50, + 132.0, + 198.0, + 264.0 + ], + "trj_freq": 10 + }, + { + "_idx": 7, + "ensemble": "npt", + "nsteps": 3000, + "press": [ + 1.0, + 10.0, + 100.0, + 1000.0, + 5000.0, + 10000.0, + 20000.0, + 50000.0 + ], + "sys_idx": [ + 7, + 15, + 23 + ], + "temps": [ + 50, + 132.0, + 198.0, + 264.0 + ], + "trj_freq": 10 + }, + { + "_idx": 8, + "ensemble": "npt", + "nsteps": 1000, + "press": [ + 1.0, + 10.0, + 100.0, + 1000.0, + 5000.0, + 10000.0, + 20000.0, + 50000.0 + ], + "sys_idx": [ + 0, + 8, + 16 + ], + "temps": [ + 330.0, + 396.0, + 462.0, + 528.0, + 594.0 + ], + "trj_freq": 10 + } + ], + "fp_style": "pwscf", + "user_fp_params": { + "control": { + "calculation": "scf", + "tprnfor": true, + "outdir": "./", + "disk_io": "none", + "pseudo_dir": "./" + }, + "system": { + "ecutwfc": 110, + "input_dft": "revpbe", + "edir": 1, + "emaxpos": 0.6, + "vdw_corr": "dft-d3", + "ntyp": 1, + "nat": 192, + "ibrav": 0 + }, + "electrons": { + "electron_maxstep": 1000, + "mixing_beta": 0.5 + }, + "kspacing": 999 + }, + "shuffle_poscar": false, + "fp_task_max": 2000, + "fp_task_min": 5, + "fp_pp_path": "./", + "fp_pp_files": [ + "Al_ONCV_PBE_sr.upf" + ], + "_comment": " that's all " +} diff --git a/examples/run/dp2.x-lammps-pwscf/CH4/H_ONCV_PBE_sr.upf b/examples/run/dp2.x-lammps-pwscf/CH4/H_ONCV_PBE_sr.upf new file mode 100644 index 000000000..e819ad123 --- /dev/null +++ b/examples/run/dp2.x-lammps-pwscf/CH4/H_ONCV_PBE_sr.upf @@ -0,0 +1 @@ +You may download the needed pseudopotential files online. An example is https://github.com/pipidog/ONCVPSP. diff --git a/examples/run/dp2.x-lammps-pwscf/CH4/O_ONCV_PBE_sr.upf b/examples/run/dp2.x-lammps-pwscf/CH4/O_ONCV_PBE_sr.upf new file mode 100644 index 000000000..e819ad123 --- /dev/null +++ b/examples/run/dp2.x-lammps-pwscf/CH4/O_ONCV_PBE_sr.upf @@ -0,0 +1 @@ +You may download the needed pseudopotential files online. An example is https://github.com/pipidog/ONCVPSP. diff --git a/examples/run/dp2.x-lammps-pwscf/CH4/param_CH4_deepmd-kit-2.x.json b/examples/run/dp2.x-lammps-pwscf/CH4/param_CH4_deepmd-kit-2.x.json new file mode 100644 index 000000000..103179a7b --- /dev/null +++ b/examples/run/dp2.x-lammps-pwscf/CH4/param_CH4_deepmd-kit-2.x.json @@ -0,0 +1,160 @@ +{ + "type_map": [ + "H", + "C" + ], + "mass_map": [ + 1, + 12 + ], + "init_data_prefix": "/data1/yfb222333/2_dpgen_gpu_multi", + "init_data_sys": [ + "CH4.POSCAR.01x01x01/02.md/sys-0004-0001/deepmd" + ], + "sys_configs_prefix": "/data1/yfb222333/2_dpgen_gpu_multi", + "sys_configs": [ + [ + "CH4.POSCAR.01x01x01/01.scale_pert/sys-0004-0001/scale*/00000*/POSCAR" + ], + [ + "CH4.POSCAR.01x01x01/01.scale_pert/sys-0004-0001/scale*/00001*/POSCAR" + ] + ], + "_comment1": " that's all ", + "numb_models": 4, + "default_training_param": { + "model": { + "type_map": [ + "H", + "C" + ], + "descriptor": { + "type": "se_a", + "sel": [ + 16, + 4 + ], + "rcut_smth": 0.5, + "rcut": 5, + "neuron": [ + 120, + 120, + 120 + ], + "resnet_dt": true, + "axis_neuron": 12, + "seed": 1 + }, + "fitting_net": { + "neuron": [ + 25, + 50, + 100 + ], + "resnet_dt": false, + "seed": 1 + } + }, + "learning_rate": { + "type": "exp", + "start_lr": 0.001, + "decay_steps": 100, + "stop_lr": 0.0003584859224085419 + }, + "loss": { + "start_pref_e": 0.02, + "limit_pref_e": 2, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0.0, + "limit_pref_v": 0.0 + }, + "training": { + "stop_batch": 2000, + "disp_file": "lcurve.out", + "disp_freq": 1000, + "save_freq": 1000, + "save_ckpt": "model.ckpt", + "disp_training": true, + "time_training": true, + "profiling": false, + "profiling_file": "timeline.json", + "_comment2": "that's all", + "training_data": { + "set_prefix": "set", + "batch_size": 1 + } + } + }, + "model_devi_dt": 0.002, + "model_devi_skip": 0, + "model_devi_f_trust_lo": 0.05, + "model_devi_f_trust_hi": 0.15, + "model_devi_clean_traj": true, + "model_devi_jobs": [ + { + "sys_idx": [ + 0 + ], + "temps": [ + 100 + ], + "press": [ + 1.0 + ], + "trj_freq": 10, + "nsteps": 300, + "ensemble": "nvt", + "_idx": "00" + }, + { + "sys_idx": [ + 1 + ], + "temps": [ + 100 + ], + "press": [ + 1.0 + ], + "trj_freq": 10, + "nsteps": 3000, + "ensemble": "nvt", + "_idx": "01" + } + ], + "fp_style": "pwscf", + "user_fp_params": { + "control": { + "calculation": "scf", + "tprnfor": true, + "outdir": "./", + "disk_io": "none", + "pseudo_dir": "./" + }, + "system": { + "ecutwfc": 110, + "input_dft": "revpbe", + "edir": 1, + "emaxpos": 0.6, + "vdw_corr": "dft-d3", + "ntyp": 2, + "nat": 5, + "ibrav": 0 + }, + "electrons": { + "electron_maxstep": 1000, + "mixing_beta": 0.5 + }, + "kspacing": 999 + }, + "shuffle_poscar": false, + "fp_task_max": 2000, + "fp_task_min": 5, + "fp_pp_path": "./", + "fp_pp_files": [ + "C_ONCV_PBE_sr.upf", + "H_ONCV_PBE_sr.upf" + ], + "_comment": " that's all " +} diff --git a/examples/run/dp2.x-lammps-pwscf/param_CH4_deepmd-kit-2.0.1.json b/examples/run/dp2.x-lammps-pwscf/param_CH4_deepmd-kit-2.0.1.json new file mode 100644 index 000000000..4de2c3751 --- /dev/null +++ b/examples/run/dp2.x-lammps-pwscf/param_CH4_deepmd-kit-2.0.1.json @@ -0,0 +1,157 @@ +{ + "type_map": [ + "H", + "C" + ], + "mass_map": [ + 1, + 12 + ], + "init_data_prefix": "./", + "init_data_sys": [ + "CH4.POSCAR.01x01x01/02.md/sys-0004-0001/deepmd" + ], + "sys_configs_prefix": "./", + "sys_configs": [ + [ + "CH4.POSCAR.01x01x01/01.scale_pert/sys-0004-0001/scale*/00000*/POSCAR" + ], + [ + "CH4.POSCAR.01x01x01/01.scale_pert/sys-0004-0001/scale*/00001*/POSCAR" + ] + ], + "_comment1": " that's all ", + "numb_models": 4, + "default_training_param": { + "model": { + "type_map": [ + "H", + "C" + ], + "descriptor": { + "type": "se_a", + "sel": [ + 16, + 4 + ], + "rcut_smth": 0.5, + "rcut": 5.0, + "neuron": [ + 120, + 120, + 120 + ], + "resnet_dt": true, + "axis_neuron": 12, + "seed": 1 + }, + "fitting_net": { + "neuron": [ + 25, + 50, + 100 + ], + "resnet_dt": false, + "seed": 1 + } + }, + "learning_rate": { + "type": "exp", + "start_lr": 0.001, + "decay_steps": 100 + }, + "loss": { + "start_pref_e": 0.02, + "limit_pref_e": 2, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0.0, + "limit_pref_v": 0.0 + }, + "training": { + "set_prefix": "set", + "numb_steps": 2000, + "batch_size": 1, + "disp_file": "lcurve.out", + "disp_freq": 1000, + "save_freq": 1000, + "save_ckpt": "model.ckpt", + "disp_training": true, + "time_training": true, + "profiling": false, + "profiling_file": "timeline.json", + "_comment2": "that's all" + } + }, + "model_devi_dt": 0.002, + "model_devi_skip": 0, + "model_devi_f_trust_lo": 0.05, + "model_devi_f_trust_hi": 0.15, + "model_devi_clean_traj": true, + "model_devi_jobs": [ + { + "sys_idx": [ + 0 + ], + "temps": [ + 100 + ], + "press": [ + 1.0 + ], + "trj_freq": 10, + "nsteps": 300, + "ensemble": "nvt", + "_idx": "00" + }, + { + "sys_idx": [ + 1 + ], + "temps": [ + 100 + ], + "press": [ + 1.0 + ], + "trj_freq": 10, + "nsteps": 3000, + "ensemble": "nvt", + "_idx": "01" + } + ], + "fp_style": "pwscf", + "user_fp_params": { + "control": { + "calculation": "scf", + "tprnfor": true, + "outdir": "./", + "disk_io": "none", + "pseudo_dir": "./" + }, + "system": { + "ecutwfc": 110, + "input_dft": "revpbe", + "edir": 1, + "emaxpos": 0.6, + "vdw_corr": "dft-d3", + "ntyp": 2, + "nat": 5, + "ibrav": 0 + }, + "electrons": { + "electron_maxstep": 1000, + "mixing_beta": 0.5 + }, + "kspacing": 999 + }, + "shuffle_poscar": false, + "fp_task_max": 2000, + "fp_task_min": 5, + "fp_pp_path": "./CH4", + "fp_pp_files": [ + "C_ONCV_PBE_sr.upf", + "H_ONCV_PBE_sr.upf" + ], + "_comment": " that's all " +} diff --git a/tests/generator/cp2k_test_ref.inp b/tests/generator/cp2k_test_ref.inp index 6197bbb97..164964c61 100644 --- a/tests/generator/cp2k_test_ref.inp +++ b/tests/generator/cp2k_test_ref.inp @@ -1,60 +1,60 @@ &GLOBAL -PROJECT DPGEN + PROJECT DPGEN &END GLOBAL &FORCE_EVAL -METHOD QS -STRESS_TENSOR ANALYTICAL -&DFT -BASIS_SET_FILE_NAME ./cp2k_basis_pp_file/BASIS_MOLOPT -POTENTIAL_FILE_NAME ./cp2k_basis_pp_file/GTH_POTENTIALS -CHARGE 0 -UKS F -MULTIPLICITY 1 -&MGRID -CUTOFF 400 -REL_CUTOFF 50 -NGRIDS 4 -&END MGRID -&QS -EPS_DEFAULT 1.0E-12 -&END QS -&SCF -SCF_GUESS ATOMIC -EPS_SCF 1.0E-6 -MAX_SCF 50 -&OT -MINIMIZER DIIS -PRECONDITIONER FULL_SINGLE_INVERSE -&END OT -&END SCF -&XC -&XC_FUNCTIONAL PBE -&END XC_FUNCTIONAL -&END XC -&END DFT -&SUBSYS -&CELL -&END CELL -&COORD -@include coord.xyz -&END COORD -&KIND H -BASIS_SET DZVP-MOLOPT-GTH -POTENTIAL GTH-PBE-q1 -&END KIND -&KIND C -BASIS_SET DZVP-MOLOPT-GTH -POTENTIAL GTH-PBE-q4 -&END KIND -&KIND N -BASIS_SET DZVP-MOLOPT-GTH -POTENTIAL GTH-PBE-q5 -&END KIND -&END SUBSYS -&PRINT -&FORCES ON -&END FORCES -&STRESS_TENSOR ON -&END STRESS_TENSOR -&END PRINT -&END FORCE_EVAL + METHOD QS + STRESS_TENSOR ANALYTICAL + &DFT #FORCE_EVAL + BASIS_SET_FILE_NAME ./cp2k_basis_pp_file/BASIS_MOLOPT + POTENTIAL_FILE_NAME ./cp2k_basis_pp_file/GTH_POTENTIALS + CHARGE 0 + UKS F + MULTIPLICITY 1 + &MGRID #DFT #FORCE_EVAL + CUTOFF 400 + REL_CUTOFF 50 + NGRIDS 4 + &END MGRID #DFT #FORCE_EVAL + &QS #DFT #FORCE_EVAL + EPS_DEFAULT 1.0E-12 + &END QS #DFT #FORCE_EVAL + &SCF #DFT #FORCE_EVAL + SCF_GUESS ATOMIC + EPS_SCF 1.0E-6 + MAX_SCF 50 + &OT #SCF #DFT #FORCE_EVAL + MINIMIZER DIIS + PRECONDITIONER FULL_SINGLE_INVERSE + &END OT #SCF #DFT #FORCE_EVAL + &END SCF #DFT #FORCE_EVAL + &XC #DFT #FORCE_EVAL + &XC_FUNCTIONAL PBE + &END XC_FUNCTIONAL #XC #DFT #FORCE_EVAL + &END XC #DFT #FORCE_EVAL + &END DFT #FORCE_EVAL + &SUBSYS #FORCE_EVAL + &CELL #SUBSYS #FORCE_EVAL + &END CELL #SUBSYS #FORCE_EVAL + &COORD #SUBSYS #FORCE_EVAL + @include coord.xyz + &END COORD #SUBSYS #FORCE_EVAL + &KIND H + BASIS_SET DZVP-MOLOPT-GTH + POTENTIAL GTH-PBE-q1 + &END KIND #SUBSYS #FORCE_EVAL + &KIND C + BASIS_SET DZVP-MOLOPT-GTH + POTENTIAL GTH-PBE-q4 + &END KIND #SUBSYS #FORCE_EVAL + &KIND N + BASIS_SET DZVP-MOLOPT-GTH + POTENTIAL GTH-PBE-q5 + &END KIND #SUBSYS #FORCE_EVAL + &END SUBSYS #FORCE_EVAL + &PRINT #FORCE_EVAL + &FORCES ON + &END FORCES #PRINT #FORCE_EVAL + &STRESS_TENSOR ON + &END STRESS_TENSOR #PRINT #FORCE_EVAL + &END PRINT #FORCE_EVAL +&END FORCE_EVAL \ No newline at end of file diff --git a/tests/generator/test_make_fp.py b/tests/generator/test_make_fp.py index 7c9699e6d..e22199569 100644 --- a/tests/generator/test_make_fp.py +++ b/tests/generator/test_make_fp.py @@ -414,7 +414,10 @@ def _check_kpoints(testCase, idx): ret = make_kspacing_kpoints( os.path.join(os.path.join(ii, "POSCAR")), kspacing, gamma ) - kpoints_ref = Kpoints.from_string(ret) + try: + kpoints_ref = Kpoints.from_string(ret) + except AttributeError: + kpoints_ref = Kpoints.from_str(ret) testCase.assertEqual(repr(kpoints), repr(kpoints_ref)) @@ -496,12 +499,21 @@ def _check_incar_ele_temp(testCase, idx, ele_temp): tidx = int(bname.split(".")[2]) with open("INCAR") as fp: incar = fp.read() - incar0 = Incar.from_string(incar) + try: + incar0 = Incar.from_string(incar) + except AttributeError: + incar0 = Incar.from_str(incar) # make_fake_md: the frames in a system shares the same ele_temp - incar1 = Incar.from_string( - vasp_incar_ele_temp_ref - % (ele_temp[sidx][0] * pc.Boltzmann / pc.electron_volt) - ) + try: + incar1 = Incar.from_string( + vasp_incar_ele_temp_ref + % (ele_temp[sidx][0] * pc.Boltzmann / pc.electron_volt) + ) + except AttributeError: + incar1 = Incar.from_str( + vasp_incar_ele_temp_ref + % (ele_temp[sidx][0] * pc.Boltzmann / pc.electron_volt) + ) for ii in incar0.keys(): # skip checking nbands... if ii == "NBANDS": diff --git a/tests/generator/test_make_md.py b/tests/generator/test_make_md.py index bf09508ee..22c867a53 100644 --- a/tests/generator/test_make_md.py +++ b/tests/generator/test_make_md.py @@ -2,6 +2,7 @@ import glob import json import os +import re import shutil import sys import unittest @@ -205,6 +206,37 @@ def test_make_model_devi_nopbc_nvt(self): _check_pt(self, 0, jdata) # shutil.rmtree('iter.000000') + def test_run_model_devi(self): + if os.path.isdir("iter.000000"): + shutil.rmtree("iter.000000") + with open(param_file) as fp: + jdata = json.load(fp) + _make_fake_models(0, jdata["numb_models"]) + make_model_devi(0, jdata, {}) + with tempfile.TemporaryDirectory() as remote_root: + run_model_devi( + 0, + jdata, + { + "api_version": "1.0", + "model_devi_command": ( + "test -f input.lammps" + "&& touch model_devi.out log.lammps traj/0.lammpstrj" + "&& echo lmp" + ), + "model_devi_machine": { + "batch_type": "shell", + "local_root": "./", + "remote_root": remote_root, + "context_type": "local", + }, + "model_devi_resources": { + "group_size": 1, + }, + "model_devi_group_size": 1, + }, + ) + def test_run_model_devi_pimd(self): if os.path.isdir("iter.000000"): shutil.rmtree("iter.000000") @@ -221,7 +253,7 @@ def test_run_model_devi_pimd(self): { "api_version": "1.0", "model_devi_command": ( - "touch model_devi1.out model_devi2.out model_devi3.out model_devi4.out" + "touch model_devi1.out model_devi2.out model_devi3.out model_devi4.out log.lammps.0 log.lammps.1 log.lammps.2 log.lammps.3" "&& echo lmp" ), "model_devi_machine": { @@ -243,22 +275,36 @@ def test_read_model_devi_file_pimd(self): if os.path.isdir(path): shutil.rmtree(path) os.makedirs(path, exist_ok=True) + path = os.path.join(path, "iter.000000/01.model_devi/task.000.000000") os.makedirs(os.path.join(path, "traj"), exist_ok=True) for i in range(4): for j in range(0, 5, 2): - with open(os.path.join(path, f"traj/{j}.lammpstrj{i+1}"), "a"): - pass + with open(os.path.join(path, f"traj/{j}.lammpstrj{i+1}"), "a") as fp: + fp.write(f"{i} {j}\n") model_devi_array = np.zeros([3, 7]) model_devi_array[:, 0] = np.array([0, 2, 4]) + model_devi_total_array = np.zeros([12, 7]) + total_steps = np.array([0, 2, 4, 5, 7, 9, 10, 12, 14, 15, 17, 19]) + model_devi_total_array[:, 0] = total_steps for i in range(4): + model_devi_array[:, 4] = 0.1 * (i + 1) * np.arange(1, 4) + model_devi_total_array[i * 3 : (i + 1) * 3, 4] = model_devi_array[:, 4] np.savetxt( - os.path.join(path, f"model_devi{i+1}.out"), model_devi_array, fmt="%d" + os.path.join(path, f"model_devi{i+1}.out"), + model_devi_array, + fmt="%.12e", ) _read_model_devi_file(path) - model_devi_total_array = np.zeros([12, 7]) - total_steps = np.array([0, 2, 4, 5, 7, 9, 10, 12, 14, 15, 17, 19]) - model_devi_total_array[:, 0] = total_steps model_devi_out = np.loadtxt(os.path.join(path, "model_devi.out")) + traj_files = glob.glob(os.path.join(path, "traj/*.lammpstrj")) + traj_files = sorted( + traj_files, key=lambda x: int(re.search(r"(\d+).lammpstrj", x).group(1)) + ) + for idx, traj in enumerate(traj_files): + traj_content = np.loadtxt(traj) + ibead = idx // 3 + istep = (idx % 3) * 2 + np.testing.assert_array_almost_equal(traj_content, np.array([ibead, istep])) np.testing.assert_array_almost_equal(model_devi_out, model_devi_total_array) for istep in total_steps: self.assertTrue( diff --git a/tests/test_check_examples.py b/tests/test_check_examples.py index 8522e8568..3033740f2 100644 --- a/tests/test_check_examples.py +++ b/tests/test_check_examples.py @@ -1,6 +1,7 @@ """This module ensures input in the examples directory could pass the argument checking. """ + import json import unittest from pathlib import Path @@ -45,6 +46,10 @@ run_jdata, p_examples / "run" / "dp2.x-lammps-vasp" / "param_CH4_deepmd-kit-2.0.1.json", ), + ( + run_jdata, + p_examples / "run" / "dp2.x-lammps-pwscf" / "param_CH4_deepmd-kit-2.0.1.json", + ), ( run_jdata, p_examples / "run" / "dp2.x-lammps-cp2k" / "param_CH4_deepmd-kit-2.0.1.json", @@ -66,6 +71,22 @@ / "Al" / "param_al_all_gpu-deepmd-kit-2.x.json", ), + ( + run_jdata, + p_examples + / "run" + / "dp2.x-lammps-pwscf" + / "CH4" + / "param_CH4_deepmd-kit-2.x.json", + ), + ( + run_jdata, + p_examples + / "run" + / "dp2.x-lammps-pwscf" + / "Al" + / "param_al_all_gpu-deepmd-kit-2.x.json", + ), (run_jdata, p_examples / "run" / "dp2.x-lammps-vasp-et" / "param_elet.json"), ( run_jdata, diff --git a/tests/test_collect.py b/tests/test_collect.py new file mode 100644 index 000000000..99979697d --- /dev/null +++ b/tests/test_collect.py @@ -0,0 +1,37 @@ +import json +import tempfile +import unittest +from pathlib import Path + +import dpdata + +from dpgen.collect.collect import collect_data + + +class TestCollectData(unittest.TestCase): + def setUp(self): + self.data = dpdata.LabeledSystem( + Path(__file__).parent / "generator" / "data" / "deepmd", fmt="deepmd/npy" + ) + + def test_collect_data(self): + with ( + tempfile.TemporaryDirectory() as inpdir, + tempfile.TemporaryDirectory() as outdir, + tempfile.NamedTemporaryFile() as param_file, + ): + self.data.to_deepmd_npy(Path(inpdir) / "iter.000000" / "02.fp" / "data.000") + self.data.to_deepmd_npy( + Path(inpdir) / "iter.000001" / "02.fp" / "data.000" / "aa" + ) + self.data.to_deepmd_npy( + Path(inpdir) / "iter.000001" / "02.fp" / "data.000" / "bb" + ) + with open(param_file.name, "w") as fp: + json.dump( + {"sys_configs": ["sys1"], "model_devi_jobs": [{}, {}, {}]}, fp + ) + + collect_data(inpdir, param_file.name, outdir, verbose=True) + ms = dpdata.MultiSystems().from_deepmd_npy(outdir) + self.assertEqual(ms.get_nframes(), self.data.get_nframes() * 3)