diff --git a/.github/workflows/publish_doc_pages.yml b/.github/workflows/publish_doc_pages.yml new file mode 100644 index 00000000..a2f77650 --- /dev/null +++ b/.github/workflows/publish_doc_pages.yml @@ -0,0 +1,50 @@ +name: Publish Document Pages for SPARC-X-API + +on: + push: + branches: + - master + - 'docs/**' + pull_request: + branches: + - master + paths: + - 'docs/**' + + workflow_dispatch: + +jobs: + sphinx-build: + defaults: + run: + shell: bash -l {0} + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: conda-incubator/setup-miniconda@v3 + with: + python-version: "3.11" + mamba-version: "*" + channels: conda-forge,defaults + channel-priority: true + activate-environment: sparc-api-build-doc + - name: Install doc-build dependencies + run: | + pip install -e ".[doc]" + - name: Build sphix doc + run: | + sphinx-build docs docs/_build + - name: Deploy to github pages + uses: peaceiris/actions-gh-pages@v4 + if: github.ref == 'refs/heads/master' && github.event_name == 'push' + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh_pages + publish_dir: docs/_build + - name: Upload preview when creating pull request + if: github.event_name == 'pull_request' + uses: actions/upload-artifact@v3 + with: + name: docs_build_preview + path: docs/_build diff --git a/README.md b/README.md index f1caa64b..fbfa7af8 100644 --- a/README.md +++ b/README.md @@ -1,543 +1,74 @@ -# `SPARC-X-API`: A Python API for the SPARC-X DFT Code +# SPARC-X-API: A Python API for the SPARC-X DFT Code [![Package](https://raw.githubusercontent.com/SPARC-X/SPARC-X-API/badges/badges/package.svg)](https://raw.githubusercontent.com/SPARC-X/SPARC-X-API/badges/badges/package.svg) [![Coverage](https://raw.githubusercontent.com/SPARC-X/SPARC-X-API/badges/badges/coverage.svg)](https://raw.githubusercontent.com/SPARC-X/SPARC-X-API/badges/badges/coverage.svg) [![Unit tests](https://github.com/SPARC-X/SPARC-X-API/actions/workflows/installation_test.yml/badge.svg)](https://github.com/SPARC-X/SPARC-X-API/actions/workflows/installation_test.yml) [![JSON-API](https://raw.githubusercontent.com/SPARC-X/SPARC-X-API/badges/badges/api_version.svg)](https://raw.githubusercontent.com/SPARC-X/SPARC-X-API/badges/badges/api_version.svg) -# Table of Contents -- [Installation](#installation) -- [Setting Up Environment](#setting-up-the-environment) -- [Basic Usage](#basic-usage-of-the-python-api) -- [Advanced Usage: Socket Interface](#advanced-usage-sparc-x-api-as-a-socket-interface) -- [Troubleshooting](#troubleshooting) -- [Advanced Topics](#advanced-topics) -- [Support and Contribution](#how-to-contribute) -`SPARC-X-API` is an [ASE](https://wiki.fysik.dtu.dk/ase/)-compatible Python API for the density functional theory (DFT) code [SPARC](https://github.com/SPARC-X/SPARC). It offers: +SPARC-X-API is a versatile Python API for the real-space density +functional (DFT) package [SPARC](https://github.com/SPARC-X/SPARC) +(**S**imulation **P**ackage for **A**b-initio **R**eal-**S**pace +**C**alculations) distributed under the GPLv3 license. +SPARC-X-API +leverages the powerful Atomic Simulation Environment +([ASE](https://wiki.fysik.dtu.dk/ase/)) framework for manipulating +input / output files, as well as running DFT calculations and analysis +via the SPARC code written in C/C++. Key features include: 1. ASE-compatible I/O format for SPARC files -2. A JSON Schema interfacing with SPARC's C-code for parameter validation and conversion -3. A comprehensive calculator interface for SPARC with socket-communication support. +2. A JSON Schema interfacing with SPARC's C/C++-code for parameter validation and conversion +3. A comprehensive calculator interface for SPARC with file I/O and socket-communication support. +## Quick start -[Fig. 1](#fig-1-schematic-drawing-for-the-architecture-of-the-sparc-x-api-package) provides an overlook of the components of `SPARC-X-API` and its relation with the SPARC C-code. +## How to cite +If you find SPARC-X-API help, please consider cite the relevant +publications below: +- **TBD** To cite the SPARC-X-API package itself: **TBD JOSS** +- The SPARC C/C++ code + - v2.0 [Zhang 2024](https://doi.org/10.1016/j.simpa.2024.100649) + - v1.0 [Xu 2021](https://doi.org/10.1016/j.softx.2021.100709) +- The M-SPARC Matlab code + - v2.0 [Zhang 2023](https://doi.org/10.1016/j.softx.2022.101295) + - v1.0 [Xu 2020](https://doi.org/10.1016/j.softx.2020.100423) -#### Fig. 1 Schematic drawing for the architecture of the `SPARC-X-API` package -![scheme-sparc-api-outlook](doc/img/scheme_api_architecture.png) +For a full list of publications in the SPARC-X project please refer to: +- [SPARC developement](https://github.com/SPARC-X/SPARC?tab=readme-ov-file#6-citation) +- [M-SPARC development](https://github.com/SPARC-X/M-SPARC?tab=readme-ov-file#6-citation) +- [Pseudopotentials](https://github.com/SPARC-X/SPMS-psps?tab=readme-ov-file#citation) +## Documentation +Please check the [full +documentation](https://sparc-x.github.io/sparc-x-api) for details +regarding installation, usage, troubleshooting and contribution +guidelines. -## Installation: +## Acknowledgment +The authors gratefully acknowledge the support of the U.S. Department +of Energy, Office of Science, under Grant No. DE-SC0019410 and +DE-SC0023445. -The Python API may be installed via either of the following approaches: -### 1. Via `anaconda` or `miniconda` (recommended) -Set up a [conda environment](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-with-commands) and install the Python API, -which includes the pseudopotential files: + -```bash -# Change 'sparc-env' to your desired name if needed -conda create -n sparc-env -conda activate sparc-env -conda install -c conda-forge sparc-x-api -``` + + -On Linux platforms (x86_64, aarch64), you can also install the -precompiled `sparc` DFT binaries alongside the API: -```bash -conda install -c conda-forge sparc-x -conda activate sparc-env # Re-activate to have the env variables effective -``` -### 2. Manual installation from source with `pip` -```bash -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`: + + -```bash -python -m sparc.download_data -``` + + + + -To utilize the API for drive SPARC calculations, please -following the [SPARC manual](https://github.com/SPARC-X/SPARC) for -compilation and installation of the SPARC DFT code itself. - -### Post-installation check - -We recommend the users to run a simple test after installation and setup: - -```bash -python -m sparc.quicktest -``` - -A proper setup will display the following sections at the output's conclusion: - -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 -run SPARC calculations, all tests must pass. - -Please refer to the [Setting Up the -Environment](#setting-up-the-environment) or guidance on correctly -configuring the environment variables. If you run into further problems, consult our -[Trouble Shooting](doc/troubleshooting.md). - -## Setting up the environment -`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: - -### A) Pseudopotential files -Pseudopotential files (in `Abinit` psp8 format) are loaded in the following -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-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: -```bash -export SPARC_PSP_PATH="/path/to/your/psp8/directory" -``` - -To determine the default location of psp8 files (as per option 3), run the following code: -```bash -python -c "from sparc.common import psp_dir; print(psp_dir)" -``` - -### B) JSON schema -`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 - -```json -"FD_GRID": { - "symbol": "FD_GRID", - "label": "FD_GRID", - "type": "integer array", - "default": null, - "unit": "No unit", - "example": "FD_GRID: 26 26 30", - "description": "#", - "allow_bool_input": false, - "category": "system" - }, -``` - -The schema file is generated from SPARC's LaTeX documentation. In -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. By default, the JSON schema is packaged under -`sparc/sparc_json_api` directory. If you have another version of SPARC -source code, you can set the environment variable `$SPARC_DOC_PATH` to -the directory containing the LaTeX codes for the documentation, such -as `/doc/.LaTeX`. If you obtain `sparc-x` from -the conda method as mentioned above, By default, the JSON schema is -packaged under `sparc/sparc_json_api` directory. If you have another -version of SPARC source code, you can set the environment variable -`$SPARC_DOC_PATH` is automatically set to -`/share/doc/sparc/.LaTeX`. Setting up the environment -variable `$SPARC_DOC_PATH` helps loading the correct JSON schame that -is compatible with your SPARC binary code. - -### C) SPARC Command Configuration - -The command to execute SPARC calculations is determined based on the following priority: - -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-X-API` looks for the SPARC binary under current `$PATH` and combine with the suitable `mpi` command prefix. - -Example: - -1. Using `mpirun` (e.g. on a single test machine) -```bash -export ASE_SPARC_COMMAND="mpirun -n 8 -mca orte_abort_on_non_zero_status 1 /path/to/sparc -name PREFIX" -``` - -2. Using `srun` (e.g. in HPC slurm job system) -```bash -export ASE_SPARC_COMMAND="srun -n 8 --kill-on-bad-exit /path/to/sparc -name PREFIX" -``` - -*Notes*: -1. The `-name PREFIX` part can be omitted the `label` property of the `sparc.SPARC` calculator is set (which is the default behavior). Any extra features of the SPARC code (e.g. GPU acceleration) should be specified in the command. - -2. We recommend adding kill switches for your MPI commands like the examples above when running `sparc` to avoid unexpected behaviors with exit signals. - - -## Basic usage of the Python API -### 1. Read / write SPARC files - -In contrast to many other DFT codes, where the ASE I/O formats refer -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: - -- Reading from a SPARC bundle - -```python -import sparc -from ase.io import read, write -atoms = read("test.sparc", index=-1) -``` -*Note*: To read multiple output files from the same directory, e.g., SPARC.aimd, SPARC.aimd\_01, pass the keyword argument `include_all_files=True` to `read()` - -- Writing a minimal SPARC bundle from atoms - -```python -import sparc -from ase.io import read, write -from ase.build import Bulk -atoms = Bulk("Al") * [4, 4, 4] -atoms.write("test.sparc") -``` - -For a deeper dive into the bundle I/O format, see [Advanced Topics](doc/advanced_topics.md). - -### 2. JSON Schema for SPARC calculator - -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-X-API` handles DFT parameters through a -JSON schema translated from SPARC's LaTeX documentation. Each release -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. - -If you've obtained the full SPARC [source -code](https://github.com/SPARC-X/SPARC), you can generate a copy of -the schema by the following code: -```bash -python -m sparc.docparser /doc/.LaTeX -``` -which produces a `parameters.json` file. - -To learn more about the JSON schema design, please refer to [Advanced -Topics](doc/advanced_topics.md). - - -### 3. Calculator interface (File-IO mode) - -`SPARC-X-API` offers a calculator interface based on file I/O 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: - -1. Single point calculation -```python -from sparc.calculator import SPARC -from ase.build import molecule -atoms = molecule("H2", cell=(10, 10, 10), pbc=True, directory="run_sp") -atoms.calc = SPARC(h=0.25) -atoms.get_potential_energy() -atoms.get_forces() -``` - -This example sets up a calculation for H2 atoms in a 10 Å x 10 Å x 10 -Å PBC cell with default parameters (PBE exchange correlation -functional, and a grid spacing (`h`) of 0.25 Å). Note by calling -`atoms.get_forces`, the calculator will automatically sets the flags -for printing the forces. - -2. Geometric optimization (using SPARC's internal routines) -```python -from sparc.calculator import SPARC -from ase.build import bulk -atoms = bulk("Al", cubic=True) -atoms.rattle(0.05) -atoms.calc = SPARC(h=0.25, kpts=(3, 3, 3), relax_flag=True, directory="run_opt") -atoms.get_potential_energy() -atoms.get_forces() -``` - -This example sets up a calculation for a rattled Aluminum primitive -unit cell, calculate with PBE functional, grid spacing of 0.25 Å, and -3 x 3 x 3 k-point grid. Optimization of ionic positions is handled -with SPARC's default LBFGS routine. - -3. AIMD in SPARC - -```python -from sparc.calculator import SPARC -from ase.build import bulk -md_params = dict(md_flag=True, ion_temp=800, md_method="NVE", md_timestep=0.6, md_nstep=5) -atoms = bulk("Al") * (3, 3, 3) -atoms.rattle() -atoms.calc = SPARC(h=0.25, kpts=(1, 1, 1), directory="run_aimd", **md_params) -atoms.get_potential_energy() -``` - -This example runs a short NVE MD simulation (5 steps) at 800 K for 27 Al atoms. -If you want to extract more information about the MD simulation steps, take a look at `SPARC.raw_results`. - -4. Geometric optimization using ASE's optimizers - -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 -from ase.build import bulk -from ase.optimize import LBFGS -atoms = bulk("Al", cubic=True) -atoms.rattle(0.05) -atoms.calc = SPARC(h=0.25, kpts=(3, 3, 3), directory="run_opt_ase") -opt = LBFGS(atoms, alpha=90) -opt.run(fmax=0.02) -``` - -### 4. Command-line tools - -A simple command wrapper `sparc-ase` is provided 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 -formats. As an example, use `sparc-ase gui path/to/your/bundle.sparc` -for the visualization of atomistic structures. Depending on the -bundle's contents, this could display individual atoms or multiple -images. - -[Fig. 2](#fig-2-a-screenshot-of-the-sparc-ase-program) is a screenshot showing the usage of `sparc-ase gui` to visualize a -short [MD trajectory](tests/outputs/NH3_sort_lbfgs_opt.sparc). - -#### Fig 2. A screenshot of the `sparc-ase` program -image - -### 5. Parameters and 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. - -When you set up a calculator as below: -```python -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-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` | `MESH_GRID: 0.38` (in Bohr) | -| `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}` | `TOL_SCF: 3e-6` | -| | `relax` (forces) eV/Å | `convergence={"relax": 1e-2}` | `TOL_RELAX: 2e-4` | -| | `density` e/atom | `convergence={`density`: 1e-6}`| `TOL_PSEUDOCHARGE: 1e-6` | - -Users from other DFT codes can easily port their ASE codes to `SPARC-X-API` using the special parameters with minimal modification: - -Example 1: VASP vs SPARC - -```python -# Using VASP -from ase.calculators.vasp import Vasp -calc = Vasp(xc="rpbe", kpts=(9, 9, 9), directory="vasp-calc") -``` -vs -```python -# Using SPARC -from sparc.calculator import SPARC -calc = SPARC(xc="rpbe", kpts=(9, 9, 9), directory="sparc-calc.sparc") -``` - -Example 2: GPAW (another real-space DFT code) vs SPARC -```python -# Using GPAW -from gpaw import GPAW -calc = GPAW(xc="PBE", kpts=(9, 9, 9), h=0.25, directory="vasp-calc", convergence={"energy": 1.e-4}) -``` -vs -```python -# Using SPARC -from sparc.calculator import SPARC -calc = SPARC(xc="PBE", kpts=(9, 9, 9), h=0.25, directory="sparc-calc.sparc", convergence={"energy": 1.e-4}) -``` - -## Advanced Usage: SPARC-X-API as a Socket Interface - -*Disclaimer: The socket communication feature in SPARC and SPARC-X-API are experimental and subject to changes until the release of v2.0 SPARC-X-API.* - -### Overview -Experienced users can harness the power of SPARC and SPARC-X-API's -socket communication layer to build efficient and flexible -computational workflows. By integrating a socket communication -interface directly into SPARC, users can significantly reduce the -overhead typically associated with file I/O during calculation -restarts. This feature is particularly beneficial for tasks involving -repetitive operations like structural optimization and saddle point -searches, where traditional file-based communication can become a -bottleneck. The underlying software architecture is shown in [Fig. 3](#fig-3-sparc-electronic-calculations-with-socket-communication-across-hybrid-computing-platforms): - -#### Fig. 3. SPARC electronic calculations with socket communication across hybrid computing platforms - -![scheme-sparc-socket](doc/img/scheme_socket_hetero.png) - - - - -**Requirements**: the SPARC binary must be manually compiled from the source -code with [socket -support](https://github.com/alchem0x2A/SPARC/tree/socket) and with the -`USE_SOCKET=1` flag enabled (see the [installation -instructions](https://github.com/alchem0x2A/SPARC/tree/socket). - -### Usage -The socket communication layer in SPARC and SPARC-X-API are designed for: -- **Efficiency:** Eliminates the need for intermediate file I/O, directly streaming data between processes. -- **Speed:** Enhances the performance of iterative calculations, crucial for large-scale simulations. -- **Flexibility:** Allows dynamic modification of calculation parameters without the need to restart the process. - -The communication protocol implemented in SPARC and SPARC-X-API -adheres to the [i-PI protocol](https://github.com/i-pi/i-pi) -standard. Specifically, we implement the original i-PI protocol within -the SPARC C-source code, while the python SPARC-X-API uses a -backward-compatible protocol based on i-PI. The dual-mode design is aimed for both low-level and -high-level interfacing of the DFT codes, providing the following features as shown in [Fig. 4](#fig-4-overview-of-the-sparc-protocol-as-an-extension-to-the-standard-i-pi-protocol): - -#### Fig. 4. Overview of the SPARC protocol as an extension to the standard i-PI protocol. -![scheme-sparc-protocol](doc/img/scheme_sparc_protocol.png) - -Based on the scenarios, the socket communication layer can be accessed via the following approaches as shown in [Fig. 5](#fig-5-different-ways-of-using-sparcs-socket-mode): - -#### Fig. 5. Different ways of using SPARC's socket mode. -![scheme-sparc-modes](doc/img/scheme-SPARC-socket-modes.png) - - -1. **SPARC binary only** ([Fig. 5](#fig-5-different-ways-of-using-sparcs-socket-mode) **a**) - - SPARC binary with socket support can be readily coupled with any i-PI compatible socker server, such as - `ase.calculators.socketio.SocketIOCalculator`, for example - - ```python - from ase.calculators.socketio import SocketIOCalculator - from subprocess import Popen - calc = SocketIOCalculator(port=31415) - with calc: - # Start sparc at background - process = Popen("mpirun -n 8 sparc -name SPARC -socket localhost:31415", shell=True) - # Single point calculations - process.kill() - ``` - - The end user is responsible for generating the input files and - making sure the same atoms structures are used by - `SocketIOCalculator` and the SPARC binary. The mode is also limited - to be run on a single computer system. - - -2. **Local-only Mode** ([Fig. 5](#fig-5-different-ways-of-using-sparcs-socket-mode) **b**) - - Ideal for standalone calculations, this mode simulates a conventional calculator while benefiting from socket-based efficiency. - - ```python - with SPARC(use_socket=True, **normal_parameters) as calc: - # Execute single-point calculations - ``` - For most users we recommend using this mode when performing a calculation on a single HPC node. - -3. **Client (Relay) Mode** ([Fig. 5](#fig-5-different-ways-of-using-sparcs-socket-mode) **c**) - - In this mode, the `sparc.SPARC` calculator servers as a passive - client which listens to a remote i-PI-compatible server. When - messages are received on the client side, it relays the relevant - message to a local SPARC binary and send results back through the - socket pipe. The server side can either be a normal i-PI compatible - server (such as `SocketIOCalculator`) or server-mode `sparc.SPARC` (see 4). - - Start the client by: - ```python - client = SPARC(use_socket=True, - socket_params=dict(host="host.address.com", port=31415)) - with client: - client.run() - ``` - - Or via Command-Line: - ```bash - python -m sparc.client -s host:port - ``` - - Note: when running SPARC-X-API as a socket client, the atoms object - can be ommitted (is the server also runs the SPARC protocol). When - new atoms positions and parameters arrive, the client will - automatically determine if it is necessary to restart the SPARC - subprocess. - -4. **Server Mode** ([Fig. 5](#fig-5-different-ways-of-using-sparcs-socket-mode) **d**) - - Paired with the client mode in (3), SPARC-X-API can be run as a - socket server, isolated from the node that performs the - computation. This can be useful for highly-distributed - computational workflows. - - On the server node, run: - ```python - server_calc = SPARC(use_socket=True, socket_params=dict(port=31415, server_only=True), **normal_parameters) - with server_calc: - # Execute single point calculations for atoms_1 - # Execute single point calculations for atoms_2 - ``` - - In this case, the server will opens `0.0.0.0:31415` for - connection. Make sure your server is directly accessible from the - clients and the port is not occupied. The socker server is capable - of receiving `raw_results` directly from the clients, making it - possible to access `server_calc.raw_results` without access to the - file systems on the client side. - - -### (In-progress) Controlling SPARC routines from socket interface - -As shown in [Fig. 4](#fig-4-overview-of-the-sparc-protocol-as-an-extension-to-the-standard-i-pi-protocol), -the SPARC socket protocol designs allows bidirectional control of -internal SPARC routines. Local- or server-mode `sparc.SPARC` -calculators can communicate with the SPARC binary via functions like -`set_params`. This can be useful for applications like on-the-fly -force field learning, electron density fitting, setting up boundary -conditions etc. Applications will be updated in both SPARC and -SPARC-X-API repositories. - - - -## Troubleshooting -Please refer to the [troubleshooting](doc/troubleshooting.md) guidelines - -## Advanced topics -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-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/index.md b/doc/index.md new file mode 100644 index 00000000..d5ae649d --- /dev/null +++ b/doc/index.md @@ -0,0 +1,6 @@ +# `SPARC-X-API`: A Python API for the Real-Space SPARC-X DFT Code + +The `SPARC-X-API` is a versatile Python API for the real-space density +functional package SPARC (**S**imulation **P**ackage for **A**b-initio +**R**eal-**S**pace **C**alculations) distributed under the GPLv3 +license. diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/advanced_socket.md b/docs/advanced_socket.md new file mode 100644 index 00000000..427daecf --- /dev/null +++ b/docs/advanced_socket.md @@ -0,0 +1,143 @@ +# Advanced Usage: SPARC-X-API as a Socket Interface + +*Disclaimer: The socket communication feature in SPARC and SPARC-X-API are experimental and subject to changes until the release of v2.0 SPARC-X-API.* + +### Overview +Experienced users can harness the power of SPARC and SPARC-X-API's +socket communication layer to build efficient and flexible +computational workflows. By integrating a socket communication +interface directly into SPARC, users can significantly reduce the +overhead typically associated with file I/O during calculation +restarts. This feature is particularly beneficial for tasks involving +repetitive operations like structural optimization and saddle point +searches, where traditional file-based communication can become a +bottleneck. The underlying software architecture is shown in [Fig. 3](#fig-3-sparc-electronic-calculations-with-socket-communication-across-hybrid-computing-platforms): + +#### Fig. 3. SPARC electronic calculations with socket communication across hybrid computing platforms + +![scheme-sparc-socket](doc/img/scheme_socket_hetero.png) + + + + +**Requirements**: the SPARC binary must be manually compiled from the source +code with [socket +support](https://github.com/alchem0x2A/SPARC/tree/socket) and with the +`USE_SOCKET=1` flag enabled (see the [installation +instructions](https://github.com/alchem0x2A/SPARC/tree/socket). + +### Usage +The socket communication layer in SPARC and SPARC-X-API are designed for: +- **Efficiency:** Eliminates the need for intermediate file I/O, directly streaming data between processes. +- **Speed:** Enhances the performance of iterative calculations, crucial for large-scale simulations. +- **Flexibility:** Allows dynamic modification of calculation parameters without the need to restart the process. + +The communication protocol implemented in SPARC and SPARC-X-API +adheres to the [i-PI protocol](https://github.com/i-pi/i-pi) +standard. Specifically, we implement the original i-PI protocol within +the SPARC C-source code, while the python SPARC-X-API uses a +backward-compatible protocol based on i-PI. The dual-mode design is aimed for both low-level and +high-level interfacing of the DFT codes, providing the following features as shown in [Fig. 4](#fig-4-overview-of-the-sparc-protocol-as-an-extension-to-the-standard-i-pi-protocol): + +#### Fig. 4. Overview of the SPARC protocol as an extension to the standard i-PI protocol. +![scheme-sparc-protocol](doc/img/scheme_sparc_protocol.png) + +Based on the scenarios, the socket communication layer can be accessed via the following approaches as shown in [Fig. 5](#fig-5-different-ways-of-using-sparcs-socket-mode): + +#### Fig. 5. Different ways of using SPARC's socket mode. +![scheme-sparc-modes](doc/img/scheme-SPARC-socket-modes.png) + + +1. **SPARC binary only** ([Fig. 5](#fig-5-different-ways-of-using-sparcs-socket-mode) **a**) + + SPARC binary with socket support can be readily coupled with any i-PI compatible socker server, such as + `ase.calculators.socketio.SocketIOCalculator`, for example + + ```python + from ase.calculators.socketio import SocketIOCalculator + from subprocess import Popen + calc = SocketIOCalculator(port=31415) + with calc: + # Start sparc at background + process = Popen("mpirun -n 8 sparc -name SPARC -socket localhost:31415", shell=True) + # Single point calculations + process.kill() + ``` + + The end user is responsible for generating the input files and + making sure the same atoms structures are used by + `SocketIOCalculator` and the SPARC binary. The mode is also limited + to be run on a single computer system. + + +2. **Local-only Mode** ([Fig. 5](#fig-5-different-ways-of-using-sparcs-socket-mode) **b**) + + Ideal for standalone calculations, this mode simulates a conventional calculator while benefiting from socket-based efficiency. + + ```python + with SPARC(use_socket=True, **normal_parameters) as calc: + # Execute single-point calculations + ``` + For most users we recommend using this mode when performing a calculation on a single HPC node. + +3. **Client (Relay) Mode** ([Fig. 5](#fig-5-different-ways-of-using-sparcs-socket-mode) **c**) + + In this mode, the `sparc.SPARC` calculator servers as a passive + client which listens to a remote i-PI-compatible server. When + messages are received on the client side, it relays the relevant + message to a local SPARC binary and send results back through the + socket pipe. The server side can either be a normal i-PI compatible + server (such as `SocketIOCalculator`) or server-mode `sparc.SPARC` (see 4). + + Start the client by: + ```python + client = SPARC(use_socket=True, + socket_params=dict(host="host.address.com", port=31415)) + with client: + client.run() + ``` + + Or via Command-Line: + ```bash + python -m sparc.client -s host:port + ``` + + Note: when running SPARC-X-API as a socket client, the atoms object + can be ommitted (is the server also runs the SPARC protocol). When + new atoms positions and parameters arrive, the client will + automatically determine if it is necessary to restart the SPARC + subprocess. + +4. **Server Mode** ([Fig. 5](#fig-5-different-ways-of-using-sparcs-socket-mode) **d**) + + Paired with the client mode in (3), SPARC-X-API can be run as a + socket server, isolated from the node that performs the + computation. This can be useful for highly-distributed + computational workflows. + + On the server node, run: + ```python + server_calc = SPARC(use_socket=True, socket_params=dict(port=31415, server_only=True), **normal_parameters) + with server_calc: + # Execute single point calculations for atoms_1 + # Execute single point calculations for atoms_2 + ``` + + In this case, the server will opens `0.0.0.0:31415` for + connection. Make sure your server is directly accessible from the + clients and the port is not occupied. The socker server is capable + of receiving `raw_results` directly from the clients, making it + possible to access `server_calc.raw_results` without access to the + file systems on the client side. + + +### (In-progress) Controlling SPARC routines from socket interface + +As shown in [Fig. 4](#fig-4-overview-of-the-sparc-protocol-as-an-extension-to-the-standard-i-pi-protocol), +the SPARC socket protocol designs allows bidirectional control of +internal SPARC routines. Local- or server-mode `sparc.SPARC` +calculators can communicate with the SPARC binary via functions like +`set_params`. This can be useful for applications like on-the-fly +force field learning, electron density fitting, setting up boundary +conditions etc. Applications will be updated in both SPARC and +SPARC-X-API repositories. diff --git a/docs/advanced_topics.md b/docs/advanced_topics.md new file mode 100644 index 00000000..03893f65 --- /dev/null +++ b/docs/advanced_topics.md @@ -0,0 +1,134 @@ +# Advanced Topics + +## Advanced Topics +The design of `SPARC-X-API` is schematically shown in the following figure +image + +### Behind the bundle file format + +Instead of parsing individual `.ion` and `.inpt` files, +the bundle format (recognized by ASE by `format="sparc"`) will +gather information from all files and check if atomic information +and calculation results can be retrieved. +The central piece for handling the bundle format is +`sparc.io.SpardBundle` class. You can use it to parse an existing bundle + +```python +from sparc.io import SparcBundle +bundle = SparcBundle("path/to/your-calc.sparc", mode="r") +images = bundle.convert_to_ase(index=":") +``` + +or write an `Atoms` object to a bundle with a minimal set of `.ion` and `.inpt` +files. + +```python +from sparc.io import SparcBundle +from ase.io import read +atoms = read("some-externalfile.xyz") +bundle = SparcBundle("path/to/your-calc.sparc", mode="w") +bundle._write_ion_and_inpt(atoms, label="SPARC") +``` + +For each individual SPARC file (e.g. `.ion`, `.inpt`, `.static`, `.geopt`, `.aimd`), +file-specific parsers are in `sparc.sparc_parsers.` files. +Each `_read_` method will return the structured raw-data dictionary of the files. +Similarly, `_write_` takes the structured dictionary as input and write the file +using only relevant data. + +### Behind the JSON API + +The JSON API are directly parsed from the `SPARC` documentation [LaTeX files](https://github.com/SPARC-X/SPARC/tree/master/doc/.LaTeX). +The JSON API file (`sparc/sparc_json_api/parameters.json`) distributed by `SPARC-X-API` is generated by: + +```bash +git clone https://github.com/SPARC-X/SPARC.git +python -m sparc.docparser SPARC/doc/.LaTeX +``` + +You can use `sparc.api.SparcAPI` together with the generated JSON API schema: +1. Load the latest SPARC api +```python +from sparc.api import SparcAPI +sis = SparcAPI() +print(sis.sparc_version) +``` + + +2. Check if a variable is available +```python +from sparc.api import SparcAPI +sis = SparcAPI() +# A typo will be detected (actual parameter is CALC_PRESS) +assert "CALC_PRESSURE" not in sis.parameters +``` + +3. Convert string <--> valid value +```python +from sparc.api import SparcAPI +sis = SparcAPI() +latvec = sis.convert_string_to_value("LATVEC", "1.0 0 0\n 0 1.0 0\n 0 0 1.0") +latvec_string = sis.convert_value_to_string("LATVEC", latvec) +``` + +4. Provide help info for a given parameter +```python +from sparc.api import SparcAPI +sis = SparcAPI() +``` + +### Retriving parameters from old SPARC calculations + +`sparc.SPARC` calculator supports the `restart` mode which will reconstruct all +parameters, psp files and atomic information from an existing SPARC calculation and +rerun them. + +```python +from sparc import SPARC +calc = SPARC(restart=True, directory="old-calc.sparc") +old_atoms = calc.atoms.copy() +# Redo the calculation with updated parameters +old_atoms.rattle() +calc.set(h=0.2, directory="new-calc.sparc") +old_atoms.calc = calc +old_atoms.get_potential_energy() +``` + + + +### Rules for input parameters in `sparc.SPARC` calculator + +When constructing the `sparc.SPARC` calculator using the syntax +```python +calc = SPARC(directory="", **kwargs) +``` +the parameters are handled in the following priority: +1) Parameters available to `.inpt` files (i.e. **CAPITALIZED**) have highest priority and overwrite all special inputs. They should be set directly using the atomic unit values (i.e the same value as they appear in the `.inpt` files). +2) Special inputs (i.e, `h`, `kpts`, `gpts`, `xc`, `convergence`) have second highest priority and overwrite default values. They are using the ASE unit system (i.e. Å, eV, GPa, fs). +3) If none of the parameters are provided, `SPARC` uses its default parameter set, currently +```python +{"xc": "pbe", "h": 0.25, "kpts": (1, 1, 1)} +``` + +We accept parameters in both upper and lower cases, in other words, `FD_GRID=[10, 10, 10]` and `fd_grid=[10, 10, 10]` are equivalent. +Additionally, boolean inputs (i.e. `PRINT_FORCES`) can be written in both integer or boolean values. + + +### Multiple occurance of output files + +In a typical SPARC calculation, there may be multiple result files in the SPARC bundle, with different suffixes (e.g. `.out`, `.out_01`, `.out_02` etc.). +These files can be a result of restarted geometry optimization / AIMD or written by an ASE optimizer. + +When using `read_sparc` to access the files, you can add `include_all_files=True` option to parse +trajectories from all files. + +```python +from sparc.io import read_sparc +# Read all images from .static, .static_01, .static_02 etc. +images = read_sparc("path/to/calc.sparc", index=":", include_all_files=True) + +# Read only from .static_02 +last_atoms = read_sparc("path/to/calc.sparc", include_all_files=False) +``` + +By default, `sparc.SPARC` calculator only access the last image of last output file when reading the calculation results. diff --git a/docs/api_changes.md b/docs/api_changes.md new file mode 100644 index 00000000..69a113d7 --- /dev/null +++ b/docs/api_changes.md @@ -0,0 +1,51 @@ +# Changes in API +## Major changes from `SPARC-X-API` [v0.1](https://github.com/SPARC-X/SPARC-X-API/tree/eac557f214b402122a506f88f38c7a8767283503) + +`SPARC-X-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. 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 +# END ASE-SORT +``` +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. 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. + +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 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])` | +| `interpret_downsampling_input` | deprecated | Manual setting not recommended | +| `interpret_kpoint_shift` | deprecated | `calc.set(kpoint_shift=[0, 0, 0])` | +| `get_pseudopotential_directory` | deprecated | `calc.psp_dir` | +| `get_nstates` | maintained | | +| `setup_parallel_env` | deprecated | Manual set | +| `generate_command` | deprecated | `calc._make_command()` | +| `estimate_memory` | maintained | | +| `get_scf_steps` | maintained | | +| `get_geometric_steps` | deprecated | `calc.get_number_of_ionic_steps()`| +| `get_runtime` | maintained | | +| `get_fermi_level` | maintained | | +| `concatinate_output` | deprecated | Use `sparc.SparcBundle` instead | +| `read_line` | deprecated | Use `sparc.SparcBundle` instead | +| `parse_output` | deprecated | `calc.read_results()` | +| `parse_relax` | deprecated | `calc.read_results()` | +| `parse_md` | deprecated | `calc.read_results()` | +| `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` | diff --git a/docs/basic_usage.md b/docs/basic_usage.md new file mode 100644 index 00000000..12085eae --- /dev/null +++ b/docs/basic_usage.md @@ -0,0 +1,206 @@ +# Basic Usage + +### 1. Read / write SPARC files + +In contrast to many other DFT codes, where the ASE I/O formats refer +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: + +- Reading from a SPARC bundle + +```python +import sparc +from ase.io import read, write +atoms = read("test.sparc", index=-1) +``` +*Note*: To read multiple output files from the same directory, e.g., SPARC.aimd, SPARC.aimd\_01, pass the keyword argument `include_all_files=True` to `read()` + +- Writing a minimal SPARC bundle from atoms + +```python +import sparc +from ase.io import read, write +from ase.build import Bulk +atoms = Bulk("Al") * [4, 4, 4] +atoms.write("test.sparc") +``` + +For a deeper dive into the bundle I/O format, see [Advanced Topics](doc/advanced_topics.md). + +### 2. JSON Schema for SPARC calculator + +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-X-API` handles DFT parameters through a +JSON schema translated from SPARC's LaTeX documentation. Each release +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. + +If you've obtained the full SPARC [source +code](https://github.com/SPARC-X/SPARC), you can generate a copy of +the schema by the following code: +```bash +python -m sparc.docparser /doc/.LaTeX +``` +which produces a `parameters.json` file. + +To learn more about the JSON schema design, please refer to [Advanced +Topics](doc/advanced_topics.md). + + +### 3. Calculator interface (File-IO mode) + +`SPARC-X-API` offers a calculator interface based on file I/O 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: + +1. Single point calculation +```python +from sparc.calculator import SPARC +from ase.build import molecule +atoms = molecule("H2", cell=(10, 10, 10), pbc=True, directory="run_sp") +atoms.calc = SPARC(h=0.25) +atoms.get_potential_energy() +atoms.get_forces() +``` + +This example sets up a calculation for H2 atoms in a 10 Å x 10 Å x 10 +Å PBC cell with default parameters (PBE exchange correlation +functional, and a grid spacing (`h`) of 0.25 Å). Note by calling +`atoms.get_forces`, the calculator will automatically sets the flags +for printing the forces. + +2. Geometric optimization (using SPARC's internal routines) +```python +from sparc.calculator import SPARC +from ase.build import bulk +atoms = bulk("Al", cubic=True) +atoms.rattle(0.05) +atoms.calc = SPARC(h=0.25, kpts=(3, 3, 3), relax_flag=True, directory="run_opt") +atoms.get_potential_energy() +atoms.get_forces() +``` + +This example sets up a calculation for a rattled Aluminum primitive +unit cell, calculate with PBE functional, grid spacing of 0.25 Å, and +3 x 3 x 3 k-point grid. Optimization of ionic positions is handled +with SPARC's default LBFGS routine. + +3. AIMD in SPARC + +```python +from sparc.calculator import SPARC +from ase.build import bulk +md_params = dict(md_flag=True, ion_temp=800, md_method="NVE", md_timestep=0.6, md_nstep=5) +atoms = bulk("Al") * (3, 3, 3) +atoms.rattle() +atoms.calc = SPARC(h=0.25, kpts=(1, 1, 1), directory="run_aimd", **md_params) +atoms.get_potential_energy() +``` + +This example runs a short NVE MD simulation (5 steps) at 800 K for 27 Al atoms. +If you want to extract more information about the MD simulation steps, take a look at `SPARC.raw_results`. + +4. Geometric optimization using ASE's optimizers + +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 +from ase.build import bulk +from ase.optimize import LBFGS +atoms = bulk("Al", cubic=True) +atoms.rattle(0.05) +atoms.calc = SPARC(h=0.25, kpts=(3, 3, 3), directory="run_opt_ase") +opt = LBFGS(atoms, alpha=90) +opt.run(fmax=0.02) +``` + +### 4. Command-line tools + +A simple command wrapper `sparc-ase` is provided 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 +formats. As an example, use `sparc-ase gui path/to/your/bundle.sparc` +for the visualization of atomistic structures. Depending on the +bundle's contents, this could display individual atoms or multiple +images. + +[Fig. 2](#fig-2-a-screenshot-of-the-sparc-ase-program) is a screenshot showing the usage of `sparc-ase gui` to visualize a +short [MD trajectory](tests/outputs/NH3_sort_lbfgs_opt.sparc). + +#### Fig 2. A screenshot of the `sparc-ase` program +image + +### 5. Parameters and 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. + +When you set up a calculator as below: +```python +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-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` | `MESH_GRID: 0.38` (in Bohr) | +| `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}` | `TOL_SCF: 3e-6` | +| | `relax` (forces) eV/Å | `convergence={"relax": 1e-2}` | `TOL_RELAX: 2e-4` | +| | `density` e/atom | `convergence={`density`: 1e-6}`| `TOL_PSEUDOCHARGE: 1e-6` | + +Users from other DFT codes can easily port their ASE codes to `SPARC-X-API` using the special parameters with minimal modification: + +Example 1: VASP vs SPARC + +```python +# Using VASP +from ase.calculators.vasp import Vasp +calc = Vasp(xc="rpbe", kpts=(9, 9, 9), directory="vasp-calc") +``` +vs +```python +# Using SPARC +from sparc.calculator import SPARC +calc = SPARC(xc="rpbe", kpts=(9, 9, 9), directory="sparc-calc.sparc") +``` + +Example 2: GPAW (another real-space DFT code) vs SPARC +```python +# Using GPAW +from gpaw import GPAW +calc = GPAW(xc="PBE", kpts=(9, 9, 9), h=0.25, directory="vasp-calc", convergence={"energy": 1.e-4}) +``` +vs +```python +# Using SPARC +from sparc.calculator import SPARC +calc = SPARC(xc="PBE", kpts=(9, 9, 9), h=0.25, directory="sparc-calc.sparc", convergence={"energy": 1.e-4}) +``` diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..6beb53be --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,35 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "SPARC-X-API" +copyright = "2024, SPARC-X Developmers" +author = "Tian Tian" + + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + "sphinx.ext.githubpages", + "myst_parser", +] + +source_suffix = { + ".md": "markdown", + ".txt": "markdown", +} + +templates_path = ["_templates"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "sphinx_rtd_theme" +html_static_path = ["_static"] diff --git a/docs/contribute.md b/docs/contribute.md new file mode 100644 index 00000000..90b2bda7 --- /dev/null +++ b/docs/contribute.md @@ -0,0 +1,104 @@ +# How to Contribute + +## Submitting issues and pull requests +We welcome users of SPARC-X and SPARC-X-API to submit issues and pull requests via github. +When reporting a bug, please make sure to include the following information: + +- `SPARC` version (if available. Should look like "Month Day, Year" in the `.out` file) +- `SPARC-X-API` version or commit hash +- Minimal example for reproducing the error +- Error trace message + +## Notes for developers + +We recommend the following steps to setup the test environment and modify codes + +### Setting up environment + +Pip installation from github's master branch (or your own fork), and download +a copy of the latest pseudopotential files. + +```python +git clone https://github.com/SPARC-X/SPARC-X-API.git +pip install -e "sparc-x-api[test]" +python -m sparc.download_data +``` + +If you need to test running DFT using the API, compile or install the `sparc` executables following the [manual](https://github.com/SPARC-X/SPARC/blob/master/README.md). + + +### Running tests + +All unit tests are based on `pytest` and inside `tests/` directory. +To run all tests (no heavy DFT calculations): +```python +python -m pytest -svv tests/ +``` + +If you are on a HPC environment, you can opt to run a comprehensive test suite with DFT calculations: +```python +python -m pytest -svv tests/test_all_dft.py +``` + +(*Draft, to be implemented later*) + +### Adding examples + +All examples are listed in `examples/` directory. Please add examples that are important +for demonstrating the functionalities of `SPARC-X-API` while the calculations can be +finished using moderate computating power (e.g. a few minutes with 4 CPU cores). + +The examples can have the name in the format `ex[Number]-[purpose].py`. + +### Code structure + +Below is a brief overview of the modules in `SPARC-X-API` with simple explanations +``` +sparc +├── __init__.py +├── api.py # Includes SparcAPI class for parameter validation +├── calculator.py # Interface to the SPARC DFT code +├── cli.py # `sparc-ase` interface +├── common.py # Definition of common directories +├── docparser.py # Function and cli interface for parsing the SPARC DFT document +├── download_data.py # Cli tool to download pseudopotential files +├── io.py # Provides `SparcBundle` class, `read_sparc` and `write_sparc` functions +├── quicktest.py # Cli tool for post-installation sanity check +├── utils.py # Common utilities +├── psp/ # Place-holder directory for pseudopotentials (used for `download_data.py`) +├── sparc_json_api # Directory for maintaining the JSON API +│   └── parameters.json +├── sparc_parsers # Parsers for individual SPARC in-/output formats +│   ├── __init__.py +│   ├── aimd.py +│   ├── atoms.py +│   ├── geopt.py +│   ├── inpt.py +│   ├── ion.py +│   ├── out.py +│   ├── pseudopotential.py +│   ├── static.py +│   └── utils.py +``` + +### CI/CD by Github Actions + +The repo contains a few CI/CD pipelines based on Github Actions. You +may need to take care of the settings if you're one of the +maintainers. For normal code contributors, this section may be +omitted. + +- Unit test + +The steps are described [here](.github/workflows/installation_test.yml). +Please make sure to exclude any computationally-heavy tests from the step "Test with pytest". + +- Coverage + +The CI workflow contains a coverage report step based on the unit test +and generates a [coverage +badge](https://github.com/SPARC-X/SPARC-X-API/blob/badges/badges/coverage.svg) +on the [`badges` +branch](https://github.com/SPARC-X/SPARC-X-API/tree/badges). + +For repo maintainers, please make sure the `badges` branch is present and **do not merge to this branch**. diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 00000000..df635b4e --- /dev/null +++ b/docs/examples.md @@ -0,0 +1 @@ +# Examples diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..8469fc21 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,31 @@ +```{include} ../README.md +:language: md +``` + + + + + + + + + + + + +```{toctree} +:maxdepth: 2 +:caption: Contents: +introduction.md +installation.md +setup_environment.md +basic_usage.md +advanced_socket.md +examples.md +package_components.md +advanced_topics.md +api_changes.md +troubleshooting.md +contribute.md +maintainers.md +``` diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 00000000..e51d0e9b --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,62 @@ +# Installation + +The Python API may be installed via either of the following approaches: + +### 1. Via `anaconda` or `miniconda` (recommended) + +Set up a [conda environment](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-with-commands) and install the Python API, +which includes the pseudopotential files: + +```bash +# Change 'sparc-env' to your desired name if needed +conda create -n sparc-env +conda activate sparc-env +conda install -c conda-forge sparc-x-api +``` + +On Linux platforms (x86_64, aarch64), you can also install the +precompiled `sparc` DFT binaries alongside the API: + +```bash +conda install -c conda-forge sparc-x +conda activate sparc-env # Re-activate to have the env variables effective +``` + +### 2. Manual installation from source with `pip` + + +```bash +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`: + +```bash +python -m sparc.download_data +``` + + +To utilize the API for drive SPARC calculations, please +following the [SPARC manual](https://github.com/SPARC-X/SPARC) for +compilation and installation of the SPARC DFT code itself. + +### Post-installation check + +We recommend the users to run a simple test after installation and setup: + +```bash +python -m sparc.quicktest +``` + +A proper setup will display the following sections at the output's conclusion: + +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 +run SPARC calculations, all tests must pass. + +Please refer to the [Setting Up the +Environment](#setting-up-the-environment) or guidance on correctly +configuring the environment variables. If you run into further problems, consult our +[Trouble Shooting](doc/troubleshooting.md). diff --git a/docs/introduction.md b/docs/introduction.md new file mode 100644 index 00000000..e10b99d0 --- /dev/null +++ b/docs/introduction.md @@ -0,0 +1 @@ +# Introduction diff --git a/docs/maintainers.md b/docs/maintainers.md new file mode 100644 index 00000000..7306015c --- /dev/null +++ b/docs/maintainers.md @@ -0,0 +1 @@ +# Documentation for Maintainers diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..954237b9 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/package_components.md b/docs/package_components.md new file mode 100644 index 00000000..0ae1726e --- /dev/null +++ b/docs/package_components.md @@ -0,0 +1 @@ +# SPARC-X-API Package Components diff --git a/docs/setup_environment.md b/docs/setup_environment.md new file mode 100644 index 00000000..a6c192dc --- /dev/null +++ b/docs/setup_environment.md @@ -0,0 +1,87 @@ +# Setup Environment for SPARC-X-API + +`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: + +### A) Pseudopotential files +Pseudopotential files (in `Abinit` psp8 format) are loaded in the following +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-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: +```bash +export SPARC_PSP_PATH="/path/to/your/psp8/directory" +``` + +To determine the default location of psp8 files (as per option 3), run the following code: +```bash +python -c "from sparc.common import psp_dir; print(psp_dir)" +``` + +### B) JSON schema +`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 + +```json +"FD_GRID": { + "symbol": "FD_GRID", + "label": "FD_GRID", + "type": "integer array", + "default": null, + "unit": "No unit", + "example": "FD_GRID: 26 26 30", + "description": "#", + "allow_bool_input": false, + "category": "system" + }, +``` + +The schema file is generated from SPARC's LaTeX documentation. In +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. By default, the JSON schema is packaged under +`sparc/sparc_json_api` directory. If you have another version of SPARC +source code, you can set the environment variable `$SPARC_DOC_PATH` to +the directory containing the LaTeX codes for the documentation, such +as `/doc/.LaTeX`. If you obtain `sparc-x` from +the conda method as mentioned above, By default, the JSON schema is +packaged under `sparc/sparc_json_api` directory. If you have another +version of SPARC source code, you can set the environment variable +`$SPARC_DOC_PATH` is automatically set to +`/share/doc/sparc/.LaTeX`. Setting up the environment +variable `$SPARC_DOC_PATH` helps loading the correct JSON schame that +is compatible with your SPARC binary code. + +### C) SPARC Command Configuration + +The command to execute SPARC calculations is determined based on the following priority: + +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-X-API` looks for the SPARC binary under current `$PATH` and combine with the suitable `mpi` command prefix. + +Example: + +1. Using `mpirun` (e.g. on a single test machine) +```bash +export ASE_SPARC_COMMAND="mpirun -n 8 -mca orte_abort_on_non_zero_status 1 /path/to/sparc -name PREFIX" +``` + +2. Using `srun` (e.g. in HPC slurm job system) +```bash +export ASE_SPARC_COMMAND="srun -n 8 --kill-on-bad-exit /path/to/sparc -name PREFIX" +``` + +*Notes*: +1. The `-name PREFIX` part can be omitted the `label` property of the `sparc.SPARC` calculator is set (which is the default behavior). Any extra features of the SPARC code (e.g. GPU acceleration) should be specified in the command. + +2. We recommend adding kill switches for your MPI commands like the examples above when running `sparc` to avoid unexpected behaviors with exit signals. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 00000000..006115a3 --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,6 @@ +# Troubleshooting +### Known issues +*This is a list of known bugs with the current SPARC-X-API, remove them when PRs are contributed* +- [ ] `sparc-ase` command currently does not support multi-image yet +- [ ] `SPARC` calculator may occasionally require more DFT steps than needed during optimization +- [ ] Raw result parsing from SPARC files may need to be re-factored in a generator form diff --git a/setup.py b/setup.py index 0e5782c2..2ad56b99 100644 --- a/setup.py +++ b/setup.py @@ -17,6 +17,12 @@ "pre-commit", ] +doc_requires = [ + "sphinx_rtd_theme", + "sphinx_tabs", + "myst-parser", +] + setup( name="sparc-x-api", version="1.0.4", @@ -45,6 +51,7 @@ }, extras_require={ "test": test_requires, + "doc": test_requires + doc_requires, }, package_data={"sparc": ["psp/*", "sparc_json_api/*.json"]}, include_package_data=True, diff --git a/sparc/io.py b/sparc/io.py index eefc6611..c682e468 100644 --- a/sparc/io.py +++ b/sparc/io.py @@ -331,6 +331,10 @@ def read_raw_results(self, include_all_files=False): Sets: self.raw_results (dict or List): the same as the return value + + #TODO: @TT 2024-11-01 allow accepting indices + #TODO: @TT last_image is a bad name, it should refer to the occurance of images + the same goes with num_calculations """ # Find the max output index out_files = self.directory.glob(f"{self.label}.out*") @@ -381,7 +385,8 @@ def read_raw_results(self, include_all_files=False): def _read_results_from_index(self, index, d_format="{:02d}"): """Read the results from one calculation index, and return a - single raw result dict + single raw result dict, e.g. for index=0 --> .static + and index=1 --> .static_01. Arguments: index (int): Index of image to return the results @@ -390,6 +395,8 @@ def _read_results_from_index(self, index, d_format="{:02d}"): Returns: dict: Results for single image + #TODO: @TT should we call index --> occurance? + """ results_dict = {} @@ -436,6 +443,8 @@ def convert_to_ase(self, index=-1, include_all_files=False, **kwargs): """ # Convert to images! + # TODO: @TT 2024-11-01 read_raw_results should implement a more + # robust behavior handling index, as it is the entry point for all rs = self.read_raw_results(include_all_files=include_all_files) if isinstance(rs, dict): raw_results = [rs] @@ -535,7 +544,9 @@ def _extract_static_results(self, raw_results, index=":"): partial_results["forces"] = static_results["forces"][self.resort] if "atomic_magnetization" in static_results: - partial_results["magmoms"] = static_results["atomic_magnetization"][self.resort] + partial_results["magmoms"] = static_results["atomic_magnetization"][ + self.resort + ] if "net_magnetization" in static_results: partial_results["magmom"] = static_results["net_magnetization"] diff --git a/sparc/sparc_parsers/static.py b/sparc/sparc_parsers/static.py index bba410d6..9e0773ca 100644 --- a/sparc/sparc_parsers/static.py +++ b/sparc/sparc_parsers/static.py @@ -27,7 +27,8 @@ def _read_static(fileobj): """ Read the .static file content - Each .static file should only host 1 or more images (is socket mode is enabled), but the output may vary + Each .static file should only host 1 or more images + (if socket mode is enabled), but the output may vary a lot depending on the flags (e.g. PRINT_ATOMS, PRINT_FORCES etc) """ contents = fileobj.read()