From 8fdd30d38914be75b6c6adec2063cacfdab82f65 Mon Sep 17 00:00:00 2001 From: "T.Tian" Date: Thu, 28 Sep 2023 16:21:54 +0800 Subject: [PATCH] add calculator xc param and doc --- README.md | 68 ++++++++++++++++++++++---------- doc/advanced_topics.md | 18 --------- doc/changes_v0.1.md | 10 ++--- setup.py | 2 +- sparc/calculator.py | 25 +++++++++++- tests/test_calculator.py | 85 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 162 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index dba1ac1f..73039579 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# `sparc-dft-api`: A Python API for the SPARC DFT Code +# `SPARC-X-API`: A Python API for the SPARC-X DFT Code [![Package](https://raw.githubusercontent.com/alchem0x2A/sparc-dft-api/badges/badges/package.svg)](https://raw.githubusercontent.com/alchem0x2A/sparc-dft-api/badges/badges/package.svg) [![Coverage](https://raw.githubusercontent.com/alchem0x2A/sparc-dft-api/badges/badges/coverage.svg)](https://raw.githubusercontent.com/alchem0x2A/sparc-dft-api/badges/badges/coverage.svg) [![Unit tests](https://github.com/alchem0x2A/sparc-dft-api/actions/workflows/installation_test.yml/badge.svg)](https://github.com/alchem0x2A/sparc-dft-api/actions/workflows/installation_test.yml) @@ -23,7 +23,7 @@ which includes the pseudopotential files: # Change 'sparc-env' to your desired name if needed conda create -n sparc-env conda activate sparc-env -conda install -c alchem0x2a sparc-dft-api +conda install -c alchem0x2a sparc-x-api ``` On Linux platforms (x86_64, aarch64), you can also install the @@ -34,13 +34,13 @@ conda install -c alchem0x2a sparc conda activate sparc-env # Re-activate to have the env variables effective ``` -*Note: Packaging of sparc-dft-api on conda-forge is in progress.* +*Note: Packaging of SPARC-X-API on conda-forge is in progress.* ### 2. Manual installation from source with `pip` ```bash -python -m pip install git+https://github.com/SPARC-X/sparc-dft-api +python -m pip install git+https://github.com/SPARC-X/SPARC-X-API ``` Optionally, you can download the latest SPMS pseudopotentials and unpacks the pseudopotential files into `/site-packages/sparc/psp`: @@ -64,7 +64,7 @@ python -m sparc.quicktest A proper setup will display the following sections at the output's conclusion: -image +image For using the API to parse SPARC input and output files, it's essential that the "Import" and "JSON API" tests are successful. For @@ -76,7 +76,7 @@ configuring the environment variables. If you run into further problems, consult [Trouble Shooting](doc/troubleshooting.md). ## Setting up the environment -`sparc-dft-api` is designed to automate the discovery of +`SPARC-X-API` is designed to automate the discovery of pseudopotential files, the JSON API, and the SPARC binary. However, you can exert fine-grained control over their setup: @@ -87,7 +87,7 @@ order: 1) Via the `psp_dir` argument passed to the `sparc.SPARC` calculator. 2) Through the environment variables `$SPARC_PSP_PATH` or `$SPARC_PP_PATH` (this is the method employed by [`conda` installation](#1-via-anaconda-or-miniconda-recommended)). -3) By using `psp8` files bundled with the sparc-dft-api installation (see the +3) By using `psp8` files bundled with the SPARC-X-API installation (see the [manual installation](#2-manual-installation-from-source-with-pip)). To specify a custom path for your psp8 files, set the `$SPARC_PSP_PATH` or `$SPARC_PP_PATH` variable as follows: @@ -101,7 +101,7 @@ python -c "from sparc.common import psp_dir; print(psp_dir)" ``` ### B) JSON schema -`sparc-dft-api` is engineered for compatibility with the SPARC +`SPARC-X-API` is engineered for compatibility with the SPARC C-code. It achieves this by loading a JSON schema for parameter validation and unit conversion. You can review the default schema used by the API at sparc.sparc_json_api.default_json_api @@ -121,7 +121,7 @@ schema used by the API at sparc.sparc_json_api.default_json_api ``` The schema file is generated from SPARC's LaTeX documentation. In -upcoming releases of `sparc-dft-api`, we're aiming to provide users +upcoming releases of `SPARC-X-API`, we're aiming to provide users the flexibility to use their own custom schema files. This would be particularly useful for those who might be testing a development branch of SPARC. @@ -132,7 +132,7 @@ The command to execute SPARC calculations is determined based on the following p 1) The command argument provided directly to the `sparc.SPARC` calculator. 2) The environment variable `$ASE_SPARC_COMMAND` -3) If neither of the above is defined, `sparc-dft-api` looks for the SPARC binary under current `$PATH` and combine with the suitable `mpi` command prefix. +3) If neither of the above is defined, `SPARC-X-API` looks for the SPARC binary under current `$PATH` and combine with the suitable `mpi` command prefix. Example: ```bash @@ -146,7 +146,7 @@ export ASE_SPARC_COMMAND="mpirun -n 8 /path/to/sparc -name PREFIX" ### 1. Read / write SPARC files In contrast to many other DFT codes, where the ASE I/O formats refer -to a single file, `sparc-dft-api` operates on the whole calculation +to a single file, `SPARC-X-API` operates on the whole calculation directory, also known as a "SPARC bundle". This API integrates seamlessly with ASE, allowing for the automatic detection of the SPARC file format: @@ -177,9 +177,9 @@ For a deeper dive into the bundle I/O format, see [Advanced Topics](doc/advanced A recurring challenge of Python interfaces to DFT codes it the inconsistencies between low-level codes (Fortran/C/C++) and outdated upper-level APIs regarding parameter sets and default values. To -address this issue, `sparc-dft-api` handles DFT parameters through a +address this issue, `SPARC-X-API` handles DFT parameters through a JSON schema translated from SPARC's LaTeX documentation. Each release -of `sparc-dft-api` is linked with a specific version of the SPARC +of `SPARC-X-API` is linked with a specific version of the SPARC source code, ensuring compatibility and consistency with the default parameter set. The main driver of this feature is the `sparc.api.SparcAPI` class. @@ -198,7 +198,7 @@ Topics](doc/advanced_topics.md). ### 3. Calculator interface -`sparc-dft-api` offers a calculator interface that aligns with many +`SPARC-X-API` offers a calculator interface that aligns with many other ASE calculators. If you've worked with ASE modules like `Vasp`, `QuantumEspresso`, or `GPAW`, you'll find this package intuitive, as shown in the following examples: @@ -252,7 +252,7 @@ If you want to extract more information about the MD simulation steps, take a lo 4. Geometric optimization using ASE's optimizers -The power of `sparc-dft-api` is to combine single point `SPARC` calculations with advanced ASE optimizers, such as BFGS, FIRE or GPMin. Example 2 can be re-written as: +The power of `SPARC-X-API` is to combine single point `SPARC` calculations with advanced ASE optimizers, such as BFGS, FIRE or GPMin. Example 2 can be re-written as: ```python from sparc.calculator import SPARC @@ -267,7 +267,7 @@ opt.run(fmax=0.02) ### 4. Command-line tools -`sparc-dft-api` provides a simple command wrapper `sparc-ase` to add +`SPARC-X-API` provides a simple command wrapper `sparc-ase` to add support of SPARC file formats to the `ase` cli tools. Simple replace `ase [subcommand] [args]` with `sparc-ase [subcommand] [args]` to access your SPARC bundle files as you would use for other file @@ -279,9 +279,9 @@ images. Below is a screenshot showing the usage of `sparc-ase gui` to visualize a short [MD trajectory](tests/outputs/NH3_sort_lbfgs_opt.sparc). -image +image -### 5. Units used in `sparc-dft-api` +### 5. Units used in `SPARC-X-API` In the SPARC DFT code, all input parameters conventionally employ atomic units, such as Hartree and Bohr. Conversely, ASE objects (like `Atoms.positions`, `Atoms.cell`, `Atoms.get_potential_energy()`) utilize eV/Angstrom units. @@ -291,7 +291,35 @@ atoms.calc = SPARC(h=0.25, REFERENCE_CUTOFF=0.5, EXX_RANGE_PBE=0.16, **params) ``` inputs following ASE's convention (e.g., `h`) adopt eV/Angstrom units (thus the same setting can be applied to other DFT calculators), On the other hand, all SPARC-specific parameters, which can often be recognized by their capitalized format (like `REFERENCE_CUTOFF`, `EXX_RANGE_PBE`), retain their original values consistent with their representation in the `.inpt` files. -The reasoning and details about unit conversion can be found in the [Rules for Input Parameters](https://github.com/alchem0x2A/sparc-dft-api/blob/master/doc/advanced_topics.md#rules-for-input-parameters-in-sparcsparc-calculator) in Advanced Topics. +The reasoning and details about unit conversion can be found in the [Rules for Input Parameters](https://github.com/alchem0x2A/SPARC-X-API/blob/master/doc/advanced_topics.md#rules-for-input-parameters-in-sparcsparc-calculator) in Advanced Topics. + + +In order for `SPARC-X-API` to be compatible with other ASE-based DFT calculators, +there is a list of special parameters consistent with the ASE convention and uses Å / eV / GPa / fs +unit system: + +| parameter name | meaning | example | equivalent `SPARC` input | +|----------------|---------------------------------|----------------|--------------------------| +| `xc` | Exchange-correlation functional | `xc=pbe` | `EXCHANGE_CORRELATION: GGA_PBE` | +| | | `xc=lda` | `EXCHANGE_CORRELATION: LDA_PZ` | +| | | `xc=rpbe` | `EXCHANGE_CORRELATION: GGA_RPBE` | +| | | `xc=pbesol` | `EXCHANGE_CORRELATION: GGA_PBEsol` | +| | | `xc=pbe0` | `EXCHANGE_CORRELATION: PBE0` | +| | | `xc=hf` | `EXCHANGE_CORRELATION: HF` | +| | | `xc=hse` or `xc=hse03` | `EXCHANGE_CORRELATION: HSE` | +| | | `xc=vdwdf1` or `xc=vdw-df` | `EXCHANGE_CORRELATION: vdWDF1` | +| | | `xc=vdwdf2` or `xc=vdw-df2` | `EXCHANGE_CORRELATION: vdWDF2` | +| | | `xc=scan` | `EXCHANGE_CORRELATION: SCAN` | +|----------------|---------------------------------|----------------|--------------------------| +| `h` | Real grid spacing (Å) | `h=0.2` | `FD_GRID: Nx Ny Nz` (nearest int value) | +| `gpts` | Explicit grid points | `gpts=[10, 10, 10]` | `FD_GRID: 10 10 10` | +| `kpts` | Kpoint mesh | `kpts=[3, 3, 3]` | `KPOINT_GRID: 3 3 3` | +| `convergence` | Dict of convergence criteria (see below) | | | +| | `energy` eV/atom | `convergence={"energy": 1e-4}` | `SCF_ENERGY_ACC: 3e-6` | +| | `forces` eV/Å | `convergence={"forces": 1e-2}` | `TOL_RELAX: 2e-4` | +| | `density` e/atom | `convergence={`density`: 1e-6}`| `TOL_PSEUDOCHARGE: 1e-6` | +|----------------|---------------------------------|----------------|--------------------------| + ## Troubleshooting Please refer to the [troubleshooting](doc/troubleshooting.md) guidelines @@ -300,7 +328,7 @@ Please refer to the [troubleshooting](doc/troubleshooting.md) guidelines A detailed description about how the API works can be found [here](doc/advanced_topics.md) ## API changes -The API changes compared to the older release ([v0.1](https://github.com/SPARC-X/sparc-dft-api/tree/eac557f214b402122a506f88f38c7a8767283503)) are summarized [here](doc/changes_v0.1.md) +The API changes compared to the older release ([v0.1](https://github.com/SPARC-X/SPARC-X-API/tree/eac557f214b402122a506f88f38c7a8767283503)) are summarized [here](doc/changes_v0.1.md) ## How to contribute Please refer to our [guidelines for contributors](doc/contribution_guideline.md) diff --git a/doc/advanced_topics.md b/doc/advanced_topics.md index 2a3612a0..347bf04b 100644 --- a/doc/advanced_topics.md +++ b/doc/advanced_topics.md @@ -93,24 +93,6 @@ old_atoms.get_potential_energy() ``` -### Special inputs for `sparc.SPARC` calculator - -The following input parameters have special meaning in `sparc.SPARC` calculator, -they are consistent with definitions in other ASE calculators and uses Å / eV / GPa / fs -unit system: - -| parameter name | meaning | example | equivalent `SPARC` input | -|----------------|---------------------------------|----------------|--------------------------| -| `xc` | Exchange-correlation functional | `xc=pbe` | `EXCHANGE_CORRELATION: GGA_PBE` | -| `h` | Real grid spacing (Å) | `h=0.2` | `FD_GRID: Nx Ny Nz` (calculated values) | -| `gpts` | Explicit grid points | `gpts=[10, 10, 10]` | `FD_GRID: 10 10 10` | -| `kpts` | Kpoint mesh | `kpts=[3, 3, 3]` | `KPOINT_GRID: 3 3 3` | -| `convergence` | Dict of convergence criteria (see below) | | | -| | `energy` eV/atom | `convergence={"energy": 1e-4}` | `SCF_ENERGY_ACC: 3e-6` | -| | `forces` eV/Å | `convergence={"forces": 1e-2}` | `TOL_RELAX: 2e-4` | -| | `density` e/atom | `convergence={`density`: 1e-6}`| `TOL_PSEUDOCHARGE: 1e-6` | - -*WIP*: support more advanced settings like D3, HSE and DFT+U in `xc` settings ### Rules for input parameters in `sparc.SPARC` calculator diff --git a/doc/changes_v0.1.md b/doc/changes_v0.1.md index a63a88d0..07ca9741 100644 --- a/doc/changes_v0.1.md +++ b/doc/changes_v0.1.md @@ -1,12 +1,12 @@ ## Major changes from `sparc-dft-api` [v0.1](https://github.com/SPARC-X/sparc-dft-api/tree/eac557f214b402122a506f88f38c7a8767283503) -`sparc-dft-api` has been heavily refactored in v0.2. If you're using legacy Python codes +`sparc-dft-api` has been heavily refactored in v1.0. If you're using legacy Python codes that are written under v0.1 API, there are a few major changes that require your attention: 1. Support for single `.ion` file format is deprecated. Instead, `v0.2` API treats the whole SPARC directory as a bundle format. Please use `read_sparc` and `write_sparc` methods for basic file I/O instead. Nevertheless, reading calculation results generated by a v0.1 API code will not be affected. -2. v0.2 API uses a different mapping scheme for the sorting of ASE atoms objects (similar to `Vasp`), add a comment section in `.ion` file similar to follows: +2. v1.0 API uses a different mapping scheme for the sorting of ASE atoms objects (similar to `Vasp`), add a comment section in `.ion` file similar to follows: ```python # ASE-SORT: # 3 2 1 0 @@ -14,7 +14,7 @@ Nevertheless, reading calculation results generated by a v0.1 API code will not ``` which maps atoms 3, 2, 1, 0 from the SPARC .ion file order to atoms 0, 1, 2, 3 in ASE order. This is useful for systems that are constructed by ASE's `add_adsorbate` method. -3. v0.2 API accepts all SPARC internal parameters (i.e. **CAPITALIZED**) in *atomic units* for consistency reason. +3. v1.0 API accepts all SPARC internal parameters (i.e. **CAPITALIZED**) in *atomic units* for consistency reason. However, we also keep a list of "special input params" that are conventionally used in other ASE calculators, that use Å / eV / GPa / fs unit system. 4. Defining `LATVEC`, `LATVEC_SCALE`, or `CELL` via the calculator parameters is no longer encouraged. Instead, all structure changes should be made to the `Atoms` object. @@ -24,7 +24,7 @@ For more discussion please see [Advanced Topic] section. Below are a list of v0.1 method of the `SPARC` calculator and their current status in v0.2 API. `calc` is an instance of `sparc.SPARC`. -| old methods | status in v0.2 API | alternatives | +| old methods | status in v1.0 API | alternatives | |------------------------|--------------------|------------------------------------| | `interpret_grid_input` | deprecated | `calc.set(fd_grid=[20, 20, 20])` | | `interpret_kpoint_input` | deprecated | `calc.set(kpts=[3, 3, 3])` | @@ -47,4 +47,4 @@ Below are a list of v0.1 method of the `SPARC` calculator and their current stat | `parse_input_args` | deprecated | `calc.set(**kwargs)` | | `recover_index_order_from_ion_file` | deprecated | Use `calc.sort` and `calc.resort` | | `atoms_dict` | deprecated | Use third party library like `bson` | -| `dict_atoms` | deprecated | Use third party library like `bson` | \ No newline at end of file +| `dict_atoms` | deprecated | Use third party library like `bson` | diff --git a/setup.py b/setup.py index c2e67be3..f7911f68 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ description="Python API for the SPARC DFT Code", author="Tian Tian, Ben Comer", author_email="alchem0x2a@gmail.com, ben.comer@gatech.edu", - url="https://github.com/SPARC-X/sparc-x-api", + url="https://github.com/SPARC-X/SPARC-X-API", packages=find_packages(), install_requires=["ase>=3.22.0"], entry_points={ diff --git a/sparc/calculator.py b/sparc/calculator.py index 90510a2e..b401d0a0 100644 --- a/sparc/calculator.py +++ b/sparc/calculator.py @@ -472,13 +472,34 @@ def _convert_special_params(self, atoms=None): params = self.special_params.copy() # xc --> EXCHANGE_CORRELATION - # TODO: more XC options if "xc" in params: xc = params.pop("xc") if xc.lower() == "pbe": converted_sparc_params["EXCHANGE_CORRELATION"] = "GGA_PBE" elif xc.lower() == "lda": - converted_sparc_params["EXCHANGE_CORRELATION"] = "LDA_PW" + converted_sparc_params["EXCHANGE_CORRELATION"] = "LDA_PZ" + elif xc.lower() == "rpbe": + converted_sparc_params["EXCHANGE_CORRELATION"] = "GGA_RPBE" + elif xc.lower() == "pbesol": + converted_sparc_params["EXCHANGE_CORRELATION"] = "GGA_PBEsol" + elif xc.lower() == "pbe0": + converted_sparc_params["EXCHANGE_CORRELATION"] = "PBE0" + elif xc.lower() == "hf": + converted_sparc_params["EXCHANGE_CORRELATION"] = "HF" + # backward compatibility for HSE03. Note HSE06 is not supported yet + elif (xc.lower() == "hse") or (xc.lower() == "hse03"): + converted_sparc_params["EXCHANGE_CORRELATION"] = "HSE" + # backward compatibility for VASP-style XCs + elif (xc.lower() == "vdwdf1") or (xc.lower() == "vdw-df") or (xc.lower() == "vdw-df1"): + converted_sparc_params["EXCHANGE_CORRELATION"] = "vdWDF1" + elif (xc.lower() == "vdwdf2") or (xc.lower() == "vdw-df2"): + converted_sparc_params["EXCHANGE_CORRELATION"] = "vdWDF2" + elif xc.lower() == "scan": + converted_sparc_params["EXCHANGE_CORRELATION"] = "SCAN" + else: + # TODO: alternative exception + raise ValueError(f"xc keyword value {xc} is invalid!") + # h --> gpts if "h" in params: diff --git a/tests/test_calculator.py b/tests/test_calculator.py index a577d270..0ae60519 100644 --- a/tests/test_calculator.py +++ b/tests/test_calculator.py @@ -36,6 +36,91 @@ def test_h_parameter(): assert "FD_GRID: 25 25 25" in filecontent +def test_xc_parameter(): + from sparc.calculator import SPARC + from ase.build import bulk + atoms = bulk("Al", cubic=True) + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: GGA_PBE" in filecontent + + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(xc="pbe", directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: GGA_PBE" in filecontent + + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(xc="lda", directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: LDA_PZ" in filecontent + + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(xc="lda", directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: LDA_PZ" in filecontent + + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(xc="rpbe", directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: GGA_RPBE" in filecontent + + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(xc="pbesol", directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: GGA_PBEsol" in filecontent + + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(xc="pbe0", directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: PBE0" in filecontent + + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(xc="hf", directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: HF" in filecontent + + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(xc="hse", directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: HSE" in filecontent + + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(xc="hse03", directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: HSE" in filecontent + + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(xc="vdw-df", directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: vdWDF1" in filecontent + + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(xc="vdw-df2", directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: vdWDF2" in filecontent + + with tempfile.TemporaryDirectory() as tmpdir: + calc = SPARC(xc="scan", directory=tmpdir) + calc.write_input(atoms) + filecontent = open(Path(tmpdir) / "SPARC.inpt", "r").read() + assert "EXCHANGE_CORRELATION: SCAN" in filecontent + + + + def test_conflict_param(): from sparc.calculator import SPARC from ase.build import bulk