diff --git a/interfaces/ASE_interface/README.md b/interfaces/ASE_interface/README.md index 824e69900de..47d0780aa02 100644 --- a/interfaces/ASE_interface/README.md +++ b/interfaces/ASE_interface/README.md @@ -32,6 +32,7 @@ Please refer to the example scripts in the `examples` folder. Recommended learni 7. **constraintmd.py** - Constrained molecular dynamics simulation 8. **metadynamics.py** - Metadynamics simulation 9. **neb.py** - Nudged Elastic Band (NEB) calculation +10. **examples/atst_tools/README.md** - optional ATST-Tools workflow examples that use abacuslite for relax, NEB, Sella, CCQN, MD, and ABACUS input helpers More usage examples will be provided in future versions. @@ -54,4 +55,4 @@ Thanks to the ABACUS development team for their support and contributions. If you have any questions or suggestions, please contact us through: -- GitHub: [deepmodeling/abacus-develop](https://github.com/deepmodeling/abacus-develop) \ No newline at end of file +- GitHub: [deepmodeling/abacus-develop](https://github.com/deepmodeling/abacus-develop) diff --git a/interfaces/ASE_interface/examples/atst_tools/README.md b/interfaces/ASE_interface/examples/atst_tools/README.md new file mode 100644 index 00000000000..a183e838a78 --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/README.md @@ -0,0 +1,51 @@ +# Optional ATST-Tools Workflow Examples + +These examples show how ATST-Tools can use abacuslite as the ABACUS ASE +calculator backend. They are an optional workflow layer on top of abacuslite: +abacuslite itself does not depend on ATST-Tools. + +Install the optional workflow package in an environment where this checkout is +available: + +```bash +pip install atst-tools +``` + +Each case is intentionally small and uses pseudopotential and orbital files from +`tests/PP_ORB`. Run commands from the case directory so relative structure and +PP/ORB paths resolve as written. + +| Case | Workflow | Purpose | +| --- | --- | --- | +| `relax_si` | `calculation.type: relax` | Basic geometry optimization through `atst run`. | +| `neb_si` | `calculation.type: neb` | Generated Si path with a short two-stage NEB setup. | +| `sella_h2` | `calculation.type: sella` | Standalone single-ended saddle search syntax. | +| `ccqn_h2` | `calculation.type: ccqn` | CCQN with an explicit reactive bond. | +| `md_si` | `calculation.type: md` | ASE-driven MD and ABACUS-native MD templates. | +| `abacus_helper` | `atst abacus prepare/collect` | INPUT/KPT/STRU preparation and conservative output collection. | + +General workflow: + +```bash +cd interfaces/ASE_interface/examples/atst_tools/relax_si +python make_inputs.py +atst config validate config.yaml --print-normalized +atst run --dry-run config.yaml +atst run config.yaml +``` + +For SAI GPU runs, keep the same YAML structure but change +`calculator.abacus.parameters.ks_solver` from `genelpa` to `cusolver` if the +loaded ABACUS build requires the GPU solver. + +The helper case does not launch ABACUS: + +```bash +cd interfaces/ASE_interface/examples/atst_tools/abacus_helper +python make_inputs.py +atst abacus prepare config.yaml --structure inputs/init.extxyz --output-dir prepared_abacus --force +atst abacus collect prepared_abacus --output abacus_results.json +``` + +`collect` is normally useful after ABACUS has populated a run directory; using it +on `prepared_abacus` only exercises the conservative file-summary path. diff --git a/interfaces/ASE_interface/examples/atst_tools/abacus_helper/config.yaml b/interfaces/ASE_interface/examples/atst_tools/abacus_helper/config.yaml new file mode 100644 index 00000000000..a7e3ba1ab9b --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/abacus_helper/config.yaml @@ -0,0 +1,34 @@ +calculation: + type: relax + init_structure: inputs/init.extxyz + fmax: 0.10 + max_steps: 1 + optimizer: BFGS + trajectory: helper_relax.traj + logfile: helper_relax.log + +calculator: + name: abacus + abacus: + command: abacus + mpi: 1 + omp: 1 + directory: helper_abacus_run + kpts: [1, 1, 1] + parameters: + calculation: scf + basis_type: lcao + ks_solver: genelpa + ecutwfc: 100 + dft_functional: pbe + symmetry: 0 + scf_thr: 1e-6 + scf_nmax: 100 + cal_force: 1 + cal_stress: 0 + pseudo_dir: ../../../../../tests/PP_ORB + orbital_dir: ../../../../../tests/PP_ORB + pseudopotentials: + Si: Si_ONCV_PBE-1.0.upf + basissets: + Si: Si_gga_8au_100Ry_2s2p1d.orb diff --git a/interfaces/ASE_interface/examples/atst_tools/abacus_helper/make_inputs.py b/interfaces/ASE_interface/examples/atst_tools/abacus_helper/make_inputs.py new file mode 100644 index 00000000000..b9235b433e2 --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/abacus_helper/make_inputs.py @@ -0,0 +1,19 @@ +from pathlib import Path + +from ase.build import bulk +from ase.io import write + + +HERE = Path(__file__).resolve().parent +INPUTS = HERE / "inputs" + + +def main(): + INPUTS.mkdir(exist_ok=True) + atoms = bulk("Si", "diamond", a=5.43) + write(INPUTS / "init.extxyz", atoms) + print(f"Wrote {INPUTS / 'init.extxyz'}") + + +if __name__ == "__main__": + main() diff --git a/interfaces/ASE_interface/examples/atst_tools/ccqn_h2/config.yaml b/interfaces/ASE_interface/examples/atst_tools/ccqn_h2/config.yaml new file mode 100644 index 00000000000..0db9e97a36d --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/ccqn_h2/config.yaml @@ -0,0 +1,45 @@ +calculation: + type: ccqn + init_structure: inputs/ts_guess.extxyz + fmax: 0.05 + max_steps: 5 + trajectory: ccqn_h2.traj + logfile: ccqn_h2.log + final_structure: ccqn_h2_final.extxyz + artifact_manifest: atst_artifacts_ccqn_h2.json + e_vector_method: ic + reactive_bonds: "1-2" + ic_mode: democratic + cos_phi: 0.5 + trust_radius_uphill: 0.05 + trust_radius_saddle_initial: 0.03 + accept_initial_converged: false + mode_manifest: ccqn_h2_mode_manifest.json + diagnostics_file: ccqn_h2_diagnostics.json + directory: run_ccqn_h2 + +calculator: + name: abacus + abacus: + command: abacus + mpi: 1 + omp: 1 + directory: run_ccqn_h2 + kpts: [1, 1, 1] + parameters: + calculation: scf + basis_type: lcao + ks_solver: genelpa + ecutwfc: 100 + dft_functional: pbe + symmetry: 0 + scf_thr: 1e-6 + scf_nmax: 100 + cal_force: 1 + cal_stress: 0 + pseudo_dir: ../../../../../tests/PP_ORB + orbital_dir: ../../../../../tests/PP_ORB + pseudopotentials: + H: H_ONCV_PBE-1.0.upf + basissets: + H: H_gga_8au_100Ry_2s1p.orb diff --git a/interfaces/ASE_interface/examples/atst_tools/ccqn_h2/make_inputs.py b/interfaces/ASE_interface/examples/atst_tools/ccqn_h2/make_inputs.py new file mode 100644 index 00000000000..5ccbb6b578d --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/ccqn_h2/make_inputs.py @@ -0,0 +1,24 @@ +from pathlib import Path + +from ase import Atoms +from ase.io import write + + +HERE = Path(__file__).resolve().parent +INPUTS = HERE / "inputs" + + +def main(): + INPUTS.mkdir(exist_ok=True) + atoms = Atoms( + "H2", + positions=[(4.0, 4.0, 3.50), (4.0, 4.0, 4.50)], + cell=[8.0, 8.0, 8.0], + pbc=True, + ) + write(INPUTS / "ts_guess.extxyz", atoms) + print(f"Wrote {INPUTS / 'ts_guess.extxyz'}") + + +if __name__ == "__main__": + main() diff --git a/interfaces/ASE_interface/examples/atst_tools/md_si/config_abacus_native.yaml b/interfaces/ASE_interface/examples/atst_tools/md_si/config_abacus_native.yaml new file mode 100644 index 00000000000..9021919bcd9 --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/md_si/config_abacus_native.yaml @@ -0,0 +1,54 @@ +calculation: + type: md + driver: abacus_native + init_structure: inputs/init.traj + steps: 5 + directory: run_md_si_abacus_native + trajectory: md_si_abacus_native.traj + summary_file: md_si_abacus_native_summary.json + final_structure: md_si_abacus_native_final.traj + artifact_manifest: atst_artifacts_md_si_abacus_native.json + poll_interval_seconds: 5.0 + postprocess: + summary: + enabled: true + output: md_si_abacus_native_post_summary.json + convert: + enabled: false + format: extxyz + output_prefix: md_si_abacus_native_post + +calculator: + name: abacus + abacus: + command: abacus + mpi: 1 + omp: 1 + directory: run_md_si_abacus_native + kpts: [1, 1, 1] + parameters: + calculation: md + basis_type: lcao + ks_solver: genelpa + ecutwfc: 100 + dft_functional: pbe + symmetry: 0 + scf_thr: 1e-6 + scf_nmax: 100 + smearing_method: gaussian + smearing_sigma: 0.001 + mixing_type: broyden + cal_force: 1 + cal_stress: 1 + init_wfc: atomic + init_chg: atomic + md_type: nvt + md_nstep: 5 + md_dt: 0.5 + md_tfirst: 300 + pseudo_dir: ../../../../../tests/PP_ORB + orbital_dir: ../../../../../tests/PP_ORB + pseudopotentials: + Si: Si_ONCV_PBE-1.0.upf + basissets: + Si: Si_gga_8au_100Ry_2s2p1d.orb diff --git a/interfaces/ASE_interface/examples/atst_tools/md_si/config_ase_abacus.yaml b/interfaces/ASE_interface/examples/atst_tools/md_si/config_ase_abacus.yaml new file mode 100644 index 00000000000..b3aa2ea7a9e --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/md_si/config_ase_abacus.yaml @@ -0,0 +1,53 @@ +calculation: + type: md + driver: ase + init_structure: inputs/init.traj + ensemble: nvt + algorithm: langevin + steps: 5 + timestep_fs: 0.5 + temperature_K: 300.0 + friction_fs_inv: 0.01 + seed: 7 + trajectory: md_si_ase_abacus.traj + logfile: md_si_ase_abacus.log + summary_file: md_si_ase_abacus_summary.json + final_structure: md_si_ase_abacus_final.traj + artifact_manifest: atst_artifacts_md_si_ase_abacus.json + postprocess: + summary: + enabled: true + output: md_si_ase_abacus_post_summary.json + convert: + enabled: false + format: extxyz + output_prefix: md_si_ase_abacus_post + +calculator: + name: abacus + abacus: + command: abacus + mpi: 1 + omp: 1 + directory: run_md_si_ase_abacus + kpts: [1, 1, 1] + parameters: + calculation: scf + basis_type: lcao + ks_solver: genelpa + ecutwfc: 100 + dft_functional: pbe + symmetry: 0 + scf_thr: 1e-6 + scf_nmax: 100 + smearing_method: gaussian + smearing_sigma: 0.001 + mixing_type: broyden + cal_force: 1 + cal_stress: 1 + pseudo_dir: ../../../../../tests/PP_ORB + orbital_dir: ../../../../../tests/PP_ORB + pseudopotentials: + Si: Si_ONCV_PBE-1.0.upf + basissets: + Si: Si_gga_8au_100Ry_2s2p1d.orb diff --git a/interfaces/ASE_interface/examples/atst_tools/md_si/make_inputs.py b/interfaces/ASE_interface/examples/atst_tools/md_si/make_inputs.py new file mode 100644 index 00000000000..87f7889d07c --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/md_si/make_inputs.py @@ -0,0 +1,19 @@ +from pathlib import Path + +from ase.build import bulk +from ase.io import write + + +HERE = Path(__file__).resolve().parent +INPUTS = HERE / "inputs" + + +def main(): + INPUTS.mkdir(exist_ok=True) + atoms = bulk("Si", "diamond", a=5.43, cubic=True) + write(INPUTS / "init.traj", atoms) + print(f"Wrote {INPUTS / 'init.traj'}") + + +if __name__ == "__main__": + main() diff --git a/interfaces/ASE_interface/examples/atst_tools/neb_si/config.yaml b/interfaces/ASE_interface/examples/atst_tools/neb_si/config.yaml new file mode 100644 index 00000000000..2398af5a257 --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/neb_si/config.yaml @@ -0,0 +1,42 @@ +calculation: + type: neb + init_chain: inputs/init_neb_chain.traj + climb: true + two_stage: true + stage1_steps: 2 + stage1_fmax: 0.20 + fmax: 0.10 + k: 0.1 + algorism: improvedtangent + parallel: false + optimizer: FIRE + max_steps: 5 + trajectory: neb_si.traj + artifact_manifest: atst_artifacts_neb_si.json + endpoint_singlepoint: auto + +calculator: + name: abacus + abacus: + command: abacus + mpi: 1 + omp: 1 + directory: run_neb_si + kpts: [1, 1, 1] + parameters: + calculation: scf + basis_type: lcao + ks_solver: genelpa + ecutwfc: 100 + dft_functional: pbe + symmetry: 0 + scf_thr: 1e-6 + scf_nmax: 100 + cal_force: 1 + cal_stress: 0 + pseudo_dir: ../../../../../tests/PP_ORB + orbital_dir: ../../../../../tests/PP_ORB + pseudopotentials: + Si: Si_ONCV_PBE-1.0.upf + basissets: + Si: Si_gga_8au_100Ry_2s2p1d.orb diff --git a/interfaces/ASE_interface/examples/atst_tools/neb_si/make_inputs.py b/interfaces/ASE_interface/examples/atst_tools/neb_si/make_inputs.py new file mode 100644 index 00000000000..18a3cf04e97 --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/neb_si/make_inputs.py @@ -0,0 +1,31 @@ +from pathlib import Path + +from ase.build import bulk +from ase.io import write +from ase.mep import NEB + + +HERE = Path(__file__).resolve().parent +INPUTS = HERE / "inputs" + + +def main(): + INPUTS.mkdir(exist_ok=True) + initial = bulk("Si", "diamond", a=5.43) + final = initial.copy() + final.positions[1, 0] += 0.35 + + images = [initial.copy()] + images.extend(initial.copy() for _ in range(3)) + images.append(final.copy()) + neb = NEB(images, method="improvedtangent") + neb.interpolate(method="linear") + + write(INPUTS / "init.extxyz", initial) + write(INPUTS / "final.extxyz", final) + write(INPUTS / "init_neb_chain.traj", images) + print(f"Wrote {INPUTS / 'init_neb_chain.traj'}") + + +if __name__ == "__main__": + main() diff --git a/interfaces/ASE_interface/examples/atst_tools/relax_si/config.yaml b/interfaces/ASE_interface/examples/atst_tools/relax_si/config.yaml new file mode 100644 index 00000000000..ed205391a5a --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/relax_si/config.yaml @@ -0,0 +1,34 @@ +calculation: + type: relax + init_structure: inputs/init.extxyz + fmax: 0.05 + max_steps: 5 + optimizer: BFGS + trajectory: relax_si.traj + logfile: relax_si.log + +calculator: + name: abacus + abacus: + command: abacus + mpi: 1 + omp: 1 + directory: run_relax_si + kpts: [1, 1, 1] + parameters: + calculation: scf + basis_type: lcao + ks_solver: genelpa + ecutwfc: 100 + dft_functional: pbe + symmetry: 0 + scf_thr: 1e-6 + scf_nmax: 100 + cal_force: 1 + cal_stress: 0 + pseudo_dir: ../../../../../tests/PP_ORB + orbital_dir: ../../../../../tests/PP_ORB + pseudopotentials: + Si: Si_ONCV_PBE-1.0.upf + basissets: + Si: Si_gga_8au_100Ry_2s2p1d.orb diff --git a/interfaces/ASE_interface/examples/atst_tools/relax_si/make_inputs.py b/interfaces/ASE_interface/examples/atst_tools/relax_si/make_inputs.py new file mode 100644 index 00000000000..c0b9e187bba --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/relax_si/make_inputs.py @@ -0,0 +1,20 @@ +from pathlib import Path + +from ase.build import bulk +from ase.io import write + + +HERE = Path(__file__).resolve().parent +INPUTS = HERE / "inputs" + + +def main(): + INPUTS.mkdir(exist_ok=True) + atoms = bulk("Si", "diamond", a=5.43) + atoms.rattle(stdev=0.02, seed=7) + write(INPUTS / "init.extxyz", atoms) + print(f"Wrote {INPUTS / 'init.extxyz'}") + + +if __name__ == "__main__": + main() diff --git a/interfaces/ASE_interface/examples/atst_tools/sella_h2/config.yaml b/interfaces/ASE_interface/examples/atst_tools/sella_h2/config.yaml new file mode 100644 index 00000000000..efa26d1fff5 --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/sella_h2/config.yaml @@ -0,0 +1,34 @@ +calculation: + type: sella + init_structure: inputs/ts_guess.extxyz + fmax: 0.05 + max_steps: 5 + trajectory: sella_h2.traj + eta: 0.002 + order: 1 + +calculator: + name: abacus + abacus: + command: abacus + mpi: 1 + omp: 1 + directory: run_sella_h2 + kpts: [1, 1, 1] + parameters: + calculation: scf + basis_type: lcao + ks_solver: genelpa + ecutwfc: 100 + dft_functional: pbe + symmetry: 0 + scf_thr: 1e-6 + scf_nmax: 100 + cal_force: 1 + cal_stress: 0 + pseudo_dir: ../../../../../tests/PP_ORB + orbital_dir: ../../../../../tests/PP_ORB + pseudopotentials: + H: H_ONCV_PBE-1.0.upf + basissets: + H: H_gga_8au_100Ry_2s1p.orb diff --git a/interfaces/ASE_interface/examples/atst_tools/sella_h2/make_inputs.py b/interfaces/ASE_interface/examples/atst_tools/sella_h2/make_inputs.py new file mode 100644 index 00000000000..bb2edb47f2d --- /dev/null +++ b/interfaces/ASE_interface/examples/atst_tools/sella_h2/make_inputs.py @@ -0,0 +1,24 @@ +from pathlib import Path + +from ase import Atoms +from ase.io import write + + +HERE = Path(__file__).resolve().parent +INPUTS = HERE / "inputs" + + +def main(): + INPUTS.mkdir(exist_ok=True) + atoms = Atoms( + "H2", + positions=[(4.0, 4.0, 3.55), (4.0, 4.0, 4.45)], + cell=[8.0, 8.0, 8.0], + pbc=True, + ) + write(INPUTS / "ts_guess.extxyz", atoms) + print(f"Wrote {INPUTS / 'ts_guess.extxyz'}") + + +if __name__ == "__main__": + main()