diff --git a/.gitignore b/.gitignore index 10eb59c0..cc5cbc82 100644 --- a/.gitignore +++ b/.gitignore @@ -782,3 +782,5 @@ examples/ex1-ase/ /*.psp8 /test-1/ /test-2/ +*.pt +/README.html diff --git a/README.md b/README.md index bcbdda33..cf8e4767 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,27 @@ [![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: 1. ASE-compatible I/O format for SPARC files -2. A JSON API interfacing with SPARC's C-code for parameter validation and conversion -3. A comprehensive calculator interface for SPARC. +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. + + +[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. + +#### Fig. 1 Schematic drawing for the architecture of the `SPARC-X-API` package +![scheme-sparc-api-outlook](doc/img/scheme_api_architecture.png) + ## Installation: @@ -53,7 +69,7 @@ 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 +### Post-installation check We recommend the users to run a simple test after installation and setup: @@ -206,9 +222,9 @@ To learn more about the JSON schema design, please refer to [Advanced Topics](doc/advanced_topics.md). -### 3. Calculator interface +### 3. Calculator interface (File-IO mode) -`SPARC-X-API` offers a calculator interface that aligns with many +`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: @@ -277,7 +293,7 @@ opt.run(fmax=0.02) ### 4. Command-line tools -`SPARC-X-API` provides a simple command wrapper `sparc-ase` to add +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 @@ -286,9 +302,10 @@ for the visualization of atomistic structures. Depending on the bundle's contents, this could display individual atoms or multiple images. -Below is a screenshot showing the usage of `sparc-ase gui` to visualize a +[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` @@ -362,7 +379,7 @@ calc = SPARC(xc="PBE", kpts=(9, 9, 9), h=0.25, directory="sparc-calc.sparc", con *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 now harness the power of SPARC and SPARC-X-API's +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 @@ -370,7 +387,14 @@ 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. +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 @@ -389,15 +413,18 @@ 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: +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): -1. **Unified Interface**: A consistent interface for both client and server codes, simplifying user interaction across different modes. -2. **Versatile Operation Modes:** Supports various modes (Local-only, Client, Server) to cater to diverse computational needs. -3. **Seamless Calculation Restart:** Automates the restarting process on the client side, enhancing user convenience. +#### Fig. 5. Different ways of using SPARC's socket mode. +![scheme-sparc-modes](doc/img/scheme-SPARC-socket-modes.png) -Based on the user scenarios, the socket communication layer can be accessed via the following approaches: -1. **SPARC binary only** +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 @@ -419,7 +446,7 @@ Based on the user scenarios, the socket communication layer can be accessed via to be run on a single computer system. -2. **Local-only Mode** +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. @@ -429,7 +456,7 @@ Based on the user scenarios, the socket communication layer can be accessed via ``` For most users we recommend using this mode when performing a calculation on a single HPC node. -3. **Client (Relay) Mode** +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 @@ -457,7 +484,7 @@ Based on the user scenarios, the socket communication layer can be accessed via automatically determine if it is necessary to restart the SPARC subprocess. -4. **Server Mode** +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 @@ -482,7 +509,8 @@ Based on the user scenarios, the socket communication layer can be accessed via ### (In-progress) Controlling SPARC routines from socket interface -Our SPARC socket protocol designs allows bidirectional control of +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 diff --git a/doc/img/scheme-SPARC-socke-modes.svg b/doc/img/scheme-SPARC-socke-modes.svg new file mode 100644 index 00000000..45147876 --- /dev/null +++ b/doc/img/scheme-SPARC-socke-modes.svg @@ -0,0 +1,867 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a + b + c + d + + SPARC binary (client) + SPARC-X-API Server + i-PI-compatible Server + SocketIOCalculator( **parameters) + + + SocketIOCalculator( **parameters) + + SPARC( use_socket=True, **parameters) + python -m sparc.client \ -s $host:$port + mpirun -np $Ncore \sparc -name $fname \ -socket $sname + + + SPARC binary (client) + + Process auto-managedvia$ASE_SPARC_COMMAND + • Manual input generation• Manual process management + INET or UNIXsocket + Computating Platform Boundary + • Same API as SPARC-X-API as file I/O calculator on local file systemLocal testing / homogeneous computing platforms + EphemeralUNIX socket + + + Socket-awareSPARC process + + SPARC-X-API client + + + + + + + + i-PI-compatible Server + • Assimilate as a standard i-PI client with i-PI protocolPipelining SPARC with external codes (i-PI, PLUMED, etc) + + + + • Client-server communication with SPARC protocolProduction / hybrid-architecture computating platform + + + + SPARC( use_socket=True, socket_params={ port=31415, server_only=True, }, **parameters) + + + python -m sparc.client \ -s $host:$port + + + Socket-awareSPARC process + + SPARC-X-API client + SPARC-X-API Server + + + + + + + + + SPARCProtocol + + i-PIProtocol + + diff --git a/doc/img/scheme-SPARC-socket-modes.png b/doc/img/scheme-SPARC-socket-modes.png new file mode 100644 index 00000000..a3e47ede Binary files /dev/null and b/doc/img/scheme-SPARC-socket-modes.png differ diff --git a/doc/img/scheme_api_architecture.png b/doc/img/scheme_api_architecture.png new file mode 100644 index 00000000..4e575334 Binary files /dev/null and b/doc/img/scheme_api_architecture.png differ diff --git a/doc/img/scheme_api_architecture.svg b/doc/img/scheme_api_architecture.svg new file mode 100644 index 00000000..e456aa1c --- /dev/null +++ b/doc/img/scheme_api_architecture.svg @@ -0,0 +1,675 @@ + + + +SPARCJSON Schema"CALC_STRESS": { "symbol": "CALC_STRESS", "label": "CALC_STRESS", "type": "integer", "default": 0, "unit": "No unit", "example": "CALC_STRESS: 1", "description": "Flag for calculation ...", "remark": "", "allow_bool_input": true, "default_remark": "0", "description_raw": "Flag for calculation ...", "remark_raw": "%", "category": "stress calculation" },LaTeX DocumentationSPARC (C)SPARC-X-API (Python package sparc)Bohr-Hartree-systemAngström-eV-systemGround truthSparcAPISparcBundleValidatorFile I/OSocket communicationASE-calculator.inpt.out.ion.staticSPARC files bundle• Compatibility check• Parameter validation• Value conversion• SPARC version match diff --git a/doc/img/scheme_socket_hetero.png b/doc/img/scheme_socket_hetero.png new file mode 100644 index 00000000..9a33a890 Binary files /dev/null and b/doc/img/scheme_socket_hetero.png differ diff --git a/doc/img/scheme_socket_hetero.svg b/doc/img/scheme_socket_hetero.svg new file mode 100644 index 00000000..031001f9 --- /dev/null +++ b/doc/img/scheme_socket_hetero.svg @@ -0,0 +1,1493 @@ + + + + + + + + + + + + + + + ++ + + + + + + + + + + + + + + + + + + + + + + + +.inpt.out.ion.staticHardwareSoftwareINET socketserver:31415SPARC protocol(extending i-PI )(No file access)Server Node (AWS instance, GPU node, etc)Native i-PI Protocol/tmp/ipi_sparc_*Local file I/OComputational Nodes (CPU-intensive)SPARC C-binarympirun -np 256 sparc \ -n 8 -c 32 \ -name $fname \ -socket $sname:unixSPARC-X-API (Socket Client)Pickle dataExtra-info parsingE, F, SSPARCCalculatorSPARC-X-API (Socket Server)• ML models• Sampling algorithmsPickle dataSPARCCalculatorTraining Inferencehead nodenode groupsUNIX socketClient 1Client N...... diff --git a/doc/img/scheme_sparc_protocol.png b/doc/img/scheme_sparc_protocol.png new file mode 100644 index 00000000..4df1fb8a Binary files /dev/null and b/doc/img/scheme_sparc_protocol.png differ diff --git a/doc/img/scheme_sparc_protocol.svg b/doc/img/scheme_sparc_protocol.svg new file mode 100644 index 00000000..0507ee32 --- /dev/null +++ b/doc/img/scheme_sparc_protocol.svg @@ -0,0 +1,1181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Socket Client (SPARC-X-API) + Socket Server + + + atoms, params + + + + + "STATUS" + + + + "READY" + + + + + "POSDATA" + + + + cell,icell,n,pos + + + + + Extra routines* + (optional) + + + + "GETFORCE" + + + + E,F,virial + + + + raw_results + + + + + "STATUS" + + + + "NEEDINIT" + + + + idx, init_bytes + + + + "INIT" + + + + Recv header string + + Send message string + + Send/Recv binary datai-PI protocol + + Send/Recv pickle objectsSPARC protocol + + i-PI protocol + + SPARC protocol + + SPARCprotocol + + + "STATUS" + + + + "READY" + + + + "FORCEREADY" + + + + + + + + + + + + + + + + + Determinesystem_changes + + + Restartprocess + Restartprocess? + + + + + + + + + Modify SPARCinternal states + + + + + + + + + + + Relay socketmessages + + + + + + Standardi-PI protocol + SPARC protocol + + + + Y + + + + N + + + + + "NEWPROTO" in Init_bytes? + + + + Example python codes + calc = SPARC(**params) + calc.atoms = atomscalc.set(key=value) + + calc.raw_results + calc.results["energy"] + SPARC Client (C binary) + calc.SendParam() + calc.calculate(atoms) + + diff --git a/examples/active_learning/example_finetuna_minimal.py b/examples/active_learning/example_finetuna_minimal.py new file mode 100644 index 00000000..ab74a70f --- /dev/null +++ b/examples/active_learning/example_finetuna_minimal.py @@ -0,0 +1,93 @@ +"""A minimal example combining active learning library like Finetuna with SPARC + +usage +First download the checkpoint from the url https://dl.fbaipublicfiles.com/opencatalystproject/models/2021_08/s2ef/gemnet_t_direct_h512_all.pt + +python example_finetuna_minimal.py +""" +import torch +import os +import yaml +from pathlib import Path +from ase.io.trajectory import Trajectory +from ase.optimize import BFGS +from ase.constraints import FixAtoms +from finetuna.ml_potentials.finetuner_ensemble_calc import FinetunerEnsembleCalc +import ase +from ase.cluster.cubic import FaceCenteredCubic +from finetuna.online_learner.online_learner import OnlineLearner +import argparse +from sparc.calculator import SPARC + +from ase.build import molecule + +cpu = not torch.cuda.is_available() +curdir = Path(__file__).parent +config_file = curdir / "ft_config_gemnet_gpu.yml" +with open(config_file, "r") as fd: + configs = yaml.load(fd, Loader=yaml.FullLoader) + +checkpoint = os.environ.get("CHECKPOINT_PATH", None) +if checkpoint is None: + # Use default (relative path) + checkpoint = curdir / configs["ocp"]["checkpoint_path_list"][0] +checkpoint = Path(checkpoint) + +if not checkpoint.is_file(): + raise FileNotFoundError("Cannot found the model checkpoint file!") + +finetuner = configs["finetuner"] +finetuner[0].update(cpu=cpu) +learner = configs["learner"] + +ml_potential = FinetunerEnsembleCalc( + checkpoint_paths=[checkpoint], + mlp_params=finetuner, +) + + +<<<<<<< HEAD +# init_molecule = molecule("H2O", pbc=False, cell=[8, 8, 8]) +# init_molecule.center() +# init_molecule.rattle() + + +surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)] +layers = [1, 2, 1] +lc = 3.61000 + +# init_atoms = molecule("CH4", pbc=True, cell=[8, 8, 8]) +# init_atoms.constraints = [FixAtoms([0])] +# init_atoms.center() +# init_atoms.rattle(0.05) + +init_atoms = FaceCenteredCubic('Cu', surfaces, layers, latticeconstant=lc) +init_atoms.cell = [12, 12, 12] +init_atoms.center() +init_atoms.pbc = False +init_atoms.rattle(0.05) + + +sparc_params = {"xc": "pbe", "h": 0.13} +# with SPARC(directory="pure_BFGS", **sparc_params) as calc: +# atoms = init_atoms.copy() +# atoms.calc = calc +# dyn = BFGS(atoms, maxstep=0.2, trajectory="pure_bfgs.traj") +# dyn.run(fmax=0.03) + + +with SPARC(directory="online_coldstart", **sparc_params) as parent_calc: + atoms = init_atoms.copy() +======= +init_molecule = molecule("H2O", pbc=False, cell=[8, 8, 8]) +init_molecule.center() +init_molecule.rattle() + +sparc_params = {"directory": curdir, "xc": "pbe", "h": 0.22} +with SPARC(**sparc_params) as parent_calc: +>>>>>>> f703ec5 (use smaller mesh size) + onlinecalc = OnlineLearner(learner, [], ml_potential, parent_calc) + atoms.calc = onlinecalc + dyn = BFGS(atoms, + maxstep=0.2) + dyn.run(fmax=0.03) diff --git a/examples/active_learning/ft_config_gemnet_gpu.yml b/examples/active_learning/ft_config_gemnet_gpu.yml new file mode 100644 index 00000000..e2bafef3 --- /dev/null +++ b/examples/active_learning/ft_config_gemnet_gpu.yml @@ -0,0 +1,73 @@ +finetuner: +- cpu: false + optim: + batch_size: 1 + break_below_lr: 1.0e-07 + checkpoint_every: 100000 + eps: 1.0e-08 + eval_every: 1 + factor: 0.9 + force_coefficient: 100 + lr_initial: 0.0003 + max_epochs: 400 + num_workers: 0 + optimizer_params: + eps: 1.0e-08 + weight_decay: 0 + patience: 3 + # print_loss_and_lr: true + scheduler_loss: train + weight_decay: 0 + task: + primary_metric: loss + tuner: + num_threads: 8 + unfreeze_blocks: + - out_blocks.3.seq_forces + - out_blocks.3.scale_rbf_F + - out_blocks.3.dense_rbf_F + - out_blocks.3.out_forces + - out_blocks.2.seq_forces + - out_blocks.2.scale_rbf_F + - out_blocks.2.dense_rbf_F + - out_blocks.2.out_forces + - out_blocks.1.seq_forces + - out_blocks.1.scale_rbf_F + - out_blocks.1.dense_rbf_F + - out_blocks.1.out_forces +learner: + dyn_avg_steps: 15 + dyn_uncertain_tol: 1000000 # Dynamic uncertainty tolerance + fmax_verify_threshold: 0.03 # Fmax threshold for calling VASP single point calculation + initial_points_to_keep: [] + # logger: + # pca_quantify: true # Log PCA on wandb + # uncertainty_quantify: false + num_initial_points: 1 # Number of VASP calls at the beginning of the relaxation + partial_fit: true + query_every_n_steps: 30 # K-steps querying strategy: query every 100 steps + stat_uncertain_tol: 1000000 # Static uncertainty tolerance + tolerance_selection: min + # valset_system_id: '1498818' + # wandb_init: + # entity: ulissi-group + # project: project + # group: group + # name: name + # notes: notes + # wandb_log: false # Wandb disabled +# optional_config: +# links: +# traj: /path/to/vasp/reference/traj +ocp: + model_class_list: + - gemnet + checkpoint_path_list: + - "gemnet_t_direct_h512_all.pt" +# relaxation: +# # fmax: 0.03 +# max_parent_calls: null +# maxstep: 0.2 +# replay_method: parent_only +# steps: null +# trajname: oal_relaxation.traj diff --git a/sparc/calculator.py b/sparc/calculator.py index c8faf82b..2b6bfec1 100644 --- a/sparc/calculator.py +++ b/sparc/calculator.py @@ -276,14 +276,14 @@ def ensure_socket(self): def __enter__(self): """Reset upon entering the context.""" - IOContext.__enter__() + IOContext.__enter__(self) self.reset() self.close() return self def __exit__(self, type, value, traceback): """Exiting the context manager and reset process""" - IOContext.__exit__(type, value, traceback) + IOContext.__exit__(self, type, value, traceback) self.close() return @@ -770,13 +770,14 @@ def execute(self): def close(self, keep_out_socket=False): """Close the socket communication, the SPARC process etc""" + if not self.use_socket: + return if self.in_socket is not None: self.in_socket.close() if (self.out_socket is not None) and (not keep_out_socket): self.out_socket.close() - # import pdb; pdb.set_trace() # In most cases if in_socket is closed, the SPARC process should also exit if self.process: with time_limit(5):