1
0
mirror of https://github.com/TREX-CoE/trexio.git synced 2024-11-03 12:43:55 +01:00

Merge pull request #129 from TREX-CoE/rust

Rust interface
This commit is contained in:
Evgeny Posenitskiy 2023-10-25 14:08:22 +02:00 committed by GitHub
commit 2d3080a0ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 2205 additions and 11 deletions

View File

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
# Initialize the CMake project. # Initialize the CMake project.
project(Trexio project(Trexio
VERSION 2.4.0 VERSION 2.4.2
DESCRIPTION "TREX I/O library" DESCRIPTION "TREX I/O library"
LANGUAGES C Fortran LANGUAGES C Fortran
) )

View File

@ -6,6 +6,9 @@ CHANGES
- Added state/energy - Added state/energy
- Made state/id an index instead of an int - Made state/id an index instead of an int
- Added JSON configuration data as a C variable in trexio.h
- Added JSON configuration file in tar.gz release
- Added Rust interface
2.3 2.3
--- ---

View File

@ -34,10 +34,9 @@
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
CLEANFILES = trexio.mod CLEANFILES = trexio.mod
BUILT_SOURCES = trex.json
if HAVE_FORTRAN if HAVE_FORTRAN
BUILT_SOURCES = trexio.mod BUILT_SOURCES += trexio.mod
else
BUILT_SOURCES =
endif endif
EXTRA_DIST = .git_hash EXTRA_DIST = .git_hash
@ -87,14 +86,63 @@ src_libtrexio_la_SOURCES = $(trexio_h) $(SOURCES)
# Include CMake-related files in the distribution. # Include CMake-related files in the distribution.
EXTRA_DIST += CMakeLists.txt \ EXTRA_DIST += CMakeLists.txt \
trex.json \
src/CMakeLists.txt \ src/CMakeLists.txt \
tests/CMakeLists.txt \ tests/CMakeLists.txt \
tests/test_macros.h \
cmake/cmake_uninstall.cmake.in \ cmake/cmake_uninstall.cmake.in \
cmake/FindTREXIO.cmake cmake/FindTREXIO.cmake
# =============== TESTS =============== # # =============== TESTS =============== #
TEST_FILES = \
tests/delete_group.c \
tests/delete_group_hdf5.c \
tests/delete_group_text.c \
tests/io_all.c \
tests/io_determinant.c \
tests/io_determinant_hdf5.c \
tests/io_determinant_text.c \
tests/io_dset_float.c \
tests/io_dset_float_hdf5.c \
tests/io_dset_float_text.c \
tests/io_dset_int.c \
tests/io_dset_int_hdf5.c \
tests/io_dset_int_text.c \
tests/io_dset_sparse.c \
tests/io_dset_sparse_hdf5.c \
tests/io_dset_sparse_text.c \
tests/io_dset_str.c \
tests/io_dset_str_hdf5.c \
tests/io_dset_str_text.c \
tests/io_jastrow.c \
tests/io_jastrow_hdf5.c \
tests/io_jastrow_text.c \
tests/io_num.c \
tests/io_num_hdf5.c \
tests/io_num_text.c \
tests/io_safe_dset_float.c \
tests/io_safe_dset_float_hdf5.c \
tests/io_safe_dset_float_text.c \
tests/io_str.c \
tests/io_str_hdf5.c \
tests/io_str_text.c \
tests/open.c \
tests/open_hdf5.c \
tests/open_text.c \
tests/overwrite_all.c \
tests/overwrite_all_hdf5.c \
tests/overwrite_all_text.c \
tests/pre_close.c \
tests/template_hdf5.c \
tests/template_text.c \
tests/test_f.f90 \
tests/test_macros.h \
tests/trexio_f.f90
EXTRA_DIST += $(TEST_FILES)
TESTS_C = \ TESTS_C = \
tests/open_text \ tests/open_text \
tests/io_num_text \ tests/io_num_text \
@ -221,6 +269,8 @@ src/trexio.c: $(trexio_h)
$(trexio_h): $(ORG_FILES) $(GENERATOR_FILES) $(trexio_h): $(ORG_FILES) $(GENERATOR_FILES)
cd $(srcdir)/tools && ./build_trexio.sh cd $(srcdir)/tools && ./build_trexio.sh
trex.json: $(trexio_h)
$(htmlizer): $(ORG_FILES) $(srcdir)/src/README.org $(htmlizer): $(ORG_FILES) $(srcdir)/src/README.org
touch $(htmlizer) touch $(htmlizer)
cd $(srcdir)/tools && ./build_doc.sh cd $(srcdir)/tools && ./build_doc.sh

View File

@ -5,7 +5,7 @@
[![build](https://github.com/TREX-CoE/trexio/actions/workflows/actions.yml/badge.svg)](https://github.com/TREX-CoE/trexio/actions/workflows/actions.yml) [![build](https://github.com/TREX-CoE/trexio/actions/workflows/actions.yml/badge.svg)](https://github.com/TREX-CoE/trexio/actions/workflows/actions.yml)
![GitHub release (latest by date)](https://img.shields.io/github/v/release/TREX-CoE/trexio) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/TREX-CoE/trexio)
TREXIO is an open-source file format and library developed for the storage and manipulation of data produced by quantum chemistry calculations. It is designed with the goal of providing a reliable and efficient method of storing and exchanging wave function parameters and matrix elements, making it an important tool for researchers in the field of quantum chemistry. In this work, we present an overview of the TREXIO file format and library. The library consists of a front-end implemented in the C programming language and two different back-ends: a text back-end and a binary back-end utilizing the HDF5 library which enables fast read and write operations. It is compatible with a variety of platforms and has interfaces for the Fortran, Python, and OCaml programming languages. In addition, a suite of tools has been developed to facilitate the use of the TREXIO format and library, including converters for popular quantum chemistry codes and utilities for validating and manipulating data stored in TREXIO files. The simplicity, versatility, and ease of use of TREXIO make it a valuable resource for researchers working with quantum chemistry data. TREXIO is an open-source file format and library developed for the storage and manipulation of data produced by quantum chemistry calculations. It is designed with the goal of providing a reliable and efficient method of storing and exchanging wave function parameters and matrix elements. The library consists of a front-end implemented in the C programming language and two different back-ends: a text back-end and a binary back-end utilizing the HDF5 library which enables fast read and write operations. It is compatible with a variety of platforms and has interfaces for the Fortran, Python, OCaml and Rust programming languages.
## Minimal requirements (for users): ## Minimal requirements (for users):
@ -191,6 +191,34 @@ make python-test
We highly recommend to use virtual environments to avoid compatibility issues and to improve reproducibility. We highly recommend to use virtual environments to avoid compatibility issues and to improve reproducibility.
## Rust API
The Rust API is available on Crates.io, so you can simply run
```
cargo add trexio
```
to your Rust project.
If you prefer to install the Rust API provided with this repository:
```
cargo add --path /path/to/trexio/rust/trexio
```
## OCaml API
The TREXIO OCaml API is available in OPAM:
```
opam install trexio
```
If you prefer to install it from this repository,
```
cd ocaml/trexio
make
opam install .
```
## Tutorial ## Tutorial
TREXIO tutorials in Jupyter notebook format can be found in the TREXIO tutorials in Jupyter notebook format can be found in the

View File

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69]) AC_PREREQ([2.69])
AC_INIT([trexio],[2.4.0],[https://github.com/TREX-CoE/trexio/issues]) AC_INIT([trexio],[2.4.2],[https://github.com/TREX-CoE/trexio/issues])
AC_CONFIG_SRCDIR([Makefile.in]) AC_CONFIG_SRCDIR([Makefile.in])
AC_CONFIG_HEADERS([include/config.h]) AC_CONFIG_HEADERS([include/config.h])

View File

@ -10,6 +10,7 @@ lib/trexio.h:
sources: lib/trexio.ml lib/trexio.h sources: lib/trexio.ml lib/trexio.h
clean: clean:
rm lib/trexio.h lib/trexio.ml lib/trexio.mli lib/trexio_stubs.c
dune clean dune clean
.PHONY: sources default .PHONY: sources default

View File

@ -1,7 +1,7 @@
(lang dune 3.1) (lang dune 3.1)
(name trexio) (name trexio)
(version 2.3.2) (version 2.4.2)
(generate_opam_files false) (generate_opam_files false)

View File

@ -7,6 +7,21 @@ stubs_file= "trexio_stubs.c"
ml_file = "trexio.ml" ml_file = "trexio.ml"
mli_file = ml_file+"i" mli_file = ml_file+"i"
def check_version():
with open('trexio.opam','r') as f:
for line in f:
if line.startswith("version"):
ocaml_version = line.split(':')[1].strip()[1:-1]
break
with open('../../configure.ac','r') as f:
for line in f:
if line.startswith("AC_INIT"):
trexio_version = line.split(',')[1].strip()[1:-1]
break
if ocaml_version != trexio_version:
print(f"Inconsistent versions:\nTREXIO:{trexio_version}\nOCaml: {ocaml_version}\n")
raise
def write_stubs(data): def write_stubs(data):
with open("src/"+stubs_file,'r') as f: with open("src/"+stubs_file,'r') as f:
@ -643,10 +658,12 @@ def write_ml(data):
def main(): def main():
check_version()
with open(json_file,'r') as f: with open(json_file,'r') as f:
data = json.load(f) data = json.load(f)
for group in data: for group in data:
for element in data[group]: for element in data[group]:
print(f"{group}_{element}")
if data[group][element][0] == "str": if data[group][element][0] == "str":
data[group][element][0] = "string" data[group][element][0] = "string"

Binary file not shown.

View File

@ -1,6 +1,6 @@
# This file is generated by dune, edit dune-project instead # This file is generated by dune, edit dune-project instead
opam-version: "2.0" opam-version: "2.0"
version: "2.3.2" version: "2.4.2"
synopsis: "Binding for the TREXIO Input/Output library" synopsis: "Binding for the TREXIO Input/Output library"
description: description:
"TREXIO is a file format and library for storing wave functions and integrals for quantum chemistry." "TREXIO is a file format and library for storing wave functions and integrals for quantum chemistry."

View File

@ -1 +1 @@
__version__ = "2.4.0" __version__ = "2.4.2"

5
rust/trexio/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
Cargo.lock
src/generated.rs
target/
wrapper.h

26
rust/trexio/Cargo.toml Normal file
View File

@ -0,0 +1,26 @@
[package]
name = "trexio"
version = "2.4.2"
edition = "2021"
license = "BSD-3-Clause"
authors = ["Anthony Scemama <scemama@irsamc.ups-tlse.fr>", "Evgeny Posenitskiy"]
description = "TREXIO is an open-source file format and library developed for the storage and manipulation of data produced by quantum chemistry calculations. It is designed with the goal of providing a reliable and efficient method of storing and exchanging wave function parameters and matrix elements."
repository = "https://github.com/trex-coe/trexio"
keywords = ["quantum", "chemistry"]
readme = "README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
bindgen = "0.65.1"
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
reqwest = { version = "0.11", features = ["blocking", "rustls-tls"] }
tar = "0.4"
flate2 = "1.0"
[lib]
doctest = false
[dependencies]
hdf5 = "0.8.1"

10
rust/trexio/Makefile Normal file
View File

@ -0,0 +1,10 @@
default: src/generated.rs
cargo build
cargo test
src/generated.rs: build.py
python3 build.py
test: default
- cargo test -- --show-output

42
rust/trexio/README.md Normal file
View File

@ -0,0 +1,42 @@
# TREXIO
<img src="https://trex-coe.eu/sites/default/files/styles/responsive_no_crop/public/2022-01/TREXIO%20Code.png" width=200>
TREXIO is an open-source file format and library developed for the storage and
manipulation of data produced by quantum chemistry calculations. It is designed
with the goal of providing a reliable and efficient method of storing and
exchanging wave function parameters and matrix elements.
This crate is the Rust binding for the TREXIO C library:
![GitHub release (latest by date)](https://img.shields.io/github/v/release/TREX-CoE/trexio)
## Documentation
[TREXIO Documentation.](https://trex-coe.github.io/trexio/)
## Citation
The journal article reference describing TREXIO can be cited as follows:
```
@article{10.1063/5.0148161,
author = {Posenitskiy, Evgeny and Chilkuri, Vijay Gopal and Ammar, Abdallah and Hapka, Michał and Pernal, Katarzyna and Shinde, Ravindra and Landinez Borda, Edgar Josué and Filippi, Claudia and Nakano, Kosuke and Kohulák, Otto and Sorella, Sandro and de Oliveira Castro, Pablo and Jalby, William and Ríos, Pablo López and Alavi, Ali and Scemama, Anthony},
title = "{TREXIO: A file format and library for quantum chemistry}",
journal = {The Journal of Chemical Physics},
volume = {158},
number = {17},
year = {2023},
month = {05},
issn = {0021-9606},
doi = {10.1063/5.0148161},
url = {https://doi.org/10.1063/5.0148161},
note = {174801},
eprint = {https://pubs.aip.org/aip/jcp/article-pdf/doi/10.1063/5.0148161/17355866/174801\_1\_5.0148161.pdf},
}
```
Journal paper: [![doi](https://img.shields.io/badge/doi-10.1063/5.0148161-5077AB.svg)](https://doi.org/10.1063/5.0148161)
ArXiv paper: [![arXiv](https://img.shields.io/badge/arXiv-2302.14793-b31b1b.svg)](https://arxiv.org/abs/2302.14793)

729
rust/trexio/build.rs Normal file
View File

@ -0,0 +1,729 @@
extern crate reqwest;
extern crate tar;
extern crate flate2;
const WRAPPER_H: &str = "wrapper.h";
const GENERATED_RS: &str = "generated.rs";
use std::env;
use std::path::PathBuf;
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Write};
use serde_json::Value;
use flate2::read::GzDecoder;
use tar::Archive;
fn download_trexio() -> PathBuf {
let version = env::var("CARGO_PKG_VERSION").unwrap();
println!("Version : {}", version);
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let trexio_url = format!("https://github.com/TREX-CoE/trexio/releases/download/v{version}/trexio-{version}.tar.gz");
// Download the .tar.gz archive
let tar_gz = out_path.join("trexio.tar.gz");
let trexio_dir= out_path.join("trexio_dir");
let mut resp = reqwest::blocking::get(trexio_url).expect("Failed to download the archive");
let mut out = File::create(tar_gz.clone()).expect("Failed to create archive file");
std::io::copy(&mut resp, &mut out).expect("Failed to copy content");
// Unpack the .tar.gz archive
let tar_gz = File::open(tar_gz).unwrap();
let tar = GzDecoder::new(tar_gz);
let mut archive = Archive::new(tar);
archive.unpack(trexio_dir.clone()).expect("Failed to unpack");
// Assume that the archive extracts to a directory named 'trexio-0.1.0'
trexio_dir.join(format!("trexio-{}", version))
}
fn install_trexio(trexio_dir: &PathBuf) -> PathBuf {
println!("{}", trexio_dir.display());
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let install_path = out_path.join("trexio_install");
// Run configure script
let configure_status = std::process::Command::new("./configure")
.arg(format!("--prefix={}",install_path.display()))
.arg("--without-fortran")
.current_dir(&trexio_dir)
.status()
.unwrap();
assert!(configure_status.success());
// Run make
let make_status = std::process::Command::new("make")
.arg("install")
.current_dir(&trexio_dir)
.status()
.unwrap();
assert!(make_status.success());
install_path
}
/// This function reads from `trexio.h`, extracts the exit codes and backends, and writes them to `wrapper.h`.
fn make_interface(trexio_h: &PathBuf) -> io::Result<()> {
let mut err = HashMap::new();
let mut be = HashMap::new();
let trexio_file = File::open(trexio_h)?;
let trexio_reader = BufReader::new(trexio_file);
for line in trexio_reader.lines() {
let line = line?;
let buf = line.trim_start();
if buf.starts_with("#define TREXIO_") && buf.contains("(trexio_exit_code)") {
let buf2 = buf.replace(")", "");
let buf2 = buf2.replace("(", "");
let buf2: Vec<&str> = buf2.split_whitespace().collect();
err.insert(buf2[1].to_string(), buf2[3].trim().parse::<i32>().unwrap());
}
if buf.starts_with("#define TREXIO_") && buf.contains("(back_end_t)") {
let buf2 = buf.replace(")", "");
let buf2 = buf2.replace("(", "");
let buf2: Vec<&str> = buf2.split_whitespace().collect();
be.insert(buf2[1].to_string(), buf2[3].trim().parse::<i32>().unwrap());
}
}
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let wrapper_h = out_path.join(WRAPPER_H);
let mut wrapper_file = File::create(wrapper_h)?;
write!(&mut wrapper_file, "#include <trexio.h>\n")?;
for (k, v) in &err {
write!(&mut wrapper_file, "#undef {}\n", k)?;
write!(&mut wrapper_file, "const trexio_exit_code {} = {};\n", k, v)?;
}
for (k, v) in &be {
write!(&mut wrapper_file, "#undef {}\n", k)?;
write!(&mut wrapper_file, "const back_end_t {} = {};\n", k, v)?;
}
write!(&mut wrapper_file, "#undef TREXIO_AUTO\n")?;
write!(&mut wrapper_file, "const back_end_t TREXIO_AUTO = TREXIO_INVALID_BACK_END;\n")?;
Ok(())
}
/// Type conversions for Rust API
fn convert_r(typ: &str) -> String {
match typ {
"int" => "i64",
"int special" => "usize",
"float" | "float sparse" | "float buffered" => "f64",
"dim" | "dim readonly" | "index" => "usize",
"str" => "str",
_ => panic!("Unknown type to convert: {}", typ)
}.to_string()
}
/// Type conversion to call C functions
fn convert_c(typ: &str) -> String {
match typ {
"int" | "int special" | "dim" | "dim readonly" | "index" => "i64",
"float" | "float sparse" | "float buffered" => "f64",
"str" => "str",
_ => panic!("Unknown type to convert: {}", typ)
}.to_string()
}
/// Generate has-functions for checking the existence of groups and elements in a TREXIO file.
///
/// # Parameters
/// * `data` - The JSON-like data containing the groups and elements.
///
/// # Returns
/// A `Vec<String>` containing the generated Rust code as strings.
fn make_has_functions(data: &Value) -> Vec<String> {
let mut r = Vec::new();
if let Value::Object(groups) = data {
for (group, elements) in groups.iter() {
let group_l = group.to_lowercase();
let has_group_func = format!(
"/// Checks if the group `{group}` exists in the file.
/// # Parameters
///
/// None
///
/// # Returns
///
/// * `Result<bool, ExitCode>` - Returns `Ok(true)` if the element exists in the file,
/// otherwise returns `Ok(false)`. An error during the execution results in `Err(ExitCode)`.
pub fn has_{group_l}(&self) -> Result<bool, ExitCode> {{
let rc = unsafe {{ c::trexio_has_{group}(self.ptr) }};
match rc {{
c::TREXIO_SUCCESS => Ok(true),
c::TREXIO_HAS_NOT => Ok(false),
x => Err(ExitCode::from(x)),
}}
}}");
r.push(has_group_func);
if let Value::Object(elements_map) = elements {
for (element, _types_value) in elements_map.iter() {
let element_l = element.to_lowercase();
let has_element_func = format!(
"/// Checks if the element `{element}` of the group `{group}` exists in the file.
///
/// # Parameters
///
/// None
///
/// # Returns
///
/// * `Result<bool, ExitCode>` - Returns `Ok(true)` if the element exists in the file,
/// otherwise returns `Ok(false)`. An error during the execution results in `Err(ExitCode)`.
pub fn has_{group_l}_{element_l}(&self) -> Result<bool, ExitCode> {{
let rc = unsafe {{ c::trexio_has_{group}_{element}(self.ptr) }};
match rc {{
c::TREXIO_SUCCESS => Ok(true),
c::TREXIO_HAS_NOT => Ok(false),
x => Err(ExitCode::from(x)),
}}
}}");
r.push(has_element_func);
}
}
}
}
r
}
fn make_scalar_functions(data: &serde_json::Value) -> Vec<String> {
let mut r: Vec<String> = Vec::new();
for group in data.as_object().unwrap().keys() {
let group_l = group.to_lowercase();
for (element, attributes) in data[group].as_object().unwrap() {
let typ = attributes[0].as_str().unwrap();
let type_c = convert_c(typ);
let type_r = convert_r(typ);
let element_l = element.to_lowercase();
if attributes[1].as_array().unwrap().is_empty() {
match typ {
"int" | "float" | "dim" | "index" => {
let s = format!(r#"
/// Reads the scalar element `{element}` from the group `{group}` in the file.
///
/// # Parameters
///
/// None
///
/// # Returns
///
/// * `Result<{type_r}, ExitCode>` - Returns the scalar element as a `{type_r}` upon successful
/// operation. If the operation fails, it returns `Err(ExitCode)`.
pub fn read_{group_l}_{element_l}(&self) -> Result<{type_r}, ExitCode> {{
let mut data_c: {type_c} = 0{type_c};
let (rc, data) = unsafe {{
let rc = c::trexio_read_{group}_{element}_64(self.ptr, &mut data_c);
(rc, data_c.try_into().expect("try_into failed in read_{group_l}_{element_l}"))
}};
rc_return(data, rc)
}}
/// Writes the scalar element `{element}` into the group `{group}` in the file.
///
/// # Parameters
///
/// * `data: {type_r}` - A `{type_r}` scalar element that will be written into `{element}` in the group `{group}`.
///
/// # Returns
///
/// * `Result<(), ExitCode>` - Returns `Ok(())` upon successful operation, otherwise returns `Err(ExitCode)`.
pub fn write_{group_l}_{element_l}(&self, data: {type_r}) -> Result<(), ExitCode> {{
let data: {type_c} = data.try_into().expect("try_into failed in write_{group_l}_{element_l}");
let rc = unsafe {{ c::trexio_write_{group}_{element}_64(self.ptr, data) }};
rc_return((), rc)
}}
"#);
r.push(s);
},
"str" => {
let s = format!(r#"
/// Reads the string attribute `{element}` contained in the group `{group}`.
/// # Parameters
///
/// * `capacity: usize` - The maximum buffer size allocated for the string to be read.
///
/// # Returns
///
/// * `Result<String, ExitCode>` - Returns the attribute as a `String` upon successful operation.
/// If the operation fails, it returns `Err(ExitCode)`.
pub fn read_{group_l}_{element_l}(&self, capacity: usize) -> Result<String, ExitCode> {{
let data_c = CString::new(vec![ b' ' ; capacity]).expect("CString::new failed");
let (rc, data) = unsafe {{
let data_c = data_c.into_raw() as *mut c_char;
let rc = c::trexio_read_{group}_{element}(self.ptr, data_c, capacity.try_into().expect("try_into failed in read_{group_l}_{element_l}"));
(rc, CString::from_raw(data_c))
}};
let result : String = CString::into_string(data).expect("into_string failed in read_{group_l}_{element_l}");
rc_return(result, rc)
}}
/// Writes the string attribute `{element}` into the group `{group}`.
///
/// # Parameters
///
/// * `data: &str` - The string attribute that will be written into the `{element}` field in the `{group}` group.
///
/// # Returns
///
/// * `Result<(), ExitCode>` - Returns `Ok(())` upon successful operation.
/// If the operation fails, it returns `Err(ExitCode)`.
pub fn write_{group_l}_{element_l}(&self, data: &str) -> Result<(), ExitCode> {{
let size : i32 = data.len().try_into().expect("try_into failed in write_{group_l}_{element_l}");
let data = string_to_c(data);
let data = data.as_ptr() as *const c_char;
let rc = unsafe {{ c::trexio_write_{group}_{element}(self.ptr, data, size) }};
rc_return((), rc)
}}
"#);
r.push(s);
},
"dim readonly" => {
let s = format!(r#"
/// Reads the dimensioning variable `{element}` from the group `{group}`.
///
/// # Parameters
///
/// None.
///
/// # Returns
///
/// * `Result<{type_r}, ExitCode>` - Returns the dimensioning variable `{element}` of type `{type_r}`
/// upon successful operation. If the operation fails, it returns `Err(ExitCode)`.
pub fn read_{group_l}_{element_l}(&self) -> Result<{type_r}, ExitCode> {{
let mut data_c: {type_c} = 0{type_c};
let (rc, data) = unsafe {{
let rc = c::trexio_read_{group}_{element}_64(self.ptr, &mut data_c);
(rc, data_c.try_into().expect("try_into failed in read_{group_l}_{element_l}"))
}};
rc_return(data, rc)
}}
"#);
r.push(s);
},
_ => {}
}
}
}
}
r
}
fn make_array_functions(data: &serde_json::Value) -> Vec<String> {
let mut r: Vec<String> = Vec::new();
for group in data.as_object().unwrap().keys() {
let group_l = group.to_lowercase();
for (element, attributes) in data[group].as_object().unwrap() {
let typ = attributes[0].as_str().unwrap();
let type_c = convert_c(typ);
let type_r = convert_r(typ);
let element_l = element.to_lowercase();
let dimensions = attributes[1].as_array().unwrap();
let dimensions: Vec<&str> = dimensions.iter().map(|x| x.as_str().unwrap()).collect();
let dimensions_str = format!("{:?}", dimensions).replace("\"","");
if ! dimensions.is_empty() {
match typ {
"int" | "float" | "dim" | "index" => {
r.push(format!(r#"
/// Reads the `{element}` array from the group `{group}` in the file.
///
/// # Dimensions
///
/// The array is of dimension `{dimensions_str}`.
///
/// # Returns
///
/// * `Result<Vec<{type_r}>, ExitCode>` - Returns a flattened one-dimensional vector that contains
/// the elements of the `{element}` array. If the operation is unsuccessful, it returns `Err(ExitCode)`.
///
///"#));
if dimensions.len() > 1 {
r.push(format!(r#"
/// # Example
///
/// To reshape the one-dimensional vector back into a two-dimensional array, you can use the [`chunks`] method:
///
/// ```text
/// let one_d_array = trexio_file.read_{}_{}()?;"#, group_l, element_l));
if let Some(dim) = dimensions.first() {
if dim.contains('.') {
let parts: Vec<&str> = dim.split('.').collect();
r.push(format!("/// let {}_{} = trexio_file.read_{}_{}()?;", parts[0], parts[1], parts[0], parts[1]));
r.push(format!("/// let two_d_array: Vec<_> = one_d_array.chunks({}_{}).collect();", parts[0], parts[1]));
} else {
r.push(format!("/// let two_d_array: Vec<_> = one_d_array.chunks({}).collect();", dim));
}
}
r.push(String::from("/// ```"));
r.push(String::from("///\n/// [`chunks`]: slice::chunks"));
}
r.push(format!(r#"pub fn read_{}_{}(&self) -> Result<Vec<{}>, ExitCode> {{
let mut size = 1;"#, group_l, element_l, type_r));
for dim in &dimensions {
if dim.contains('.') {
let parts: Vec<&str> = dim.split('.').collect();
r.push(format!(" size *= self.read_{}_{}()?;", parts[0], parts[1]));
} else {
r.push(format!(" size *= {};", dim));
}
}
r.push(format!(r#" let mut data: Vec<{type_r}> = Vec::with_capacity(size);
let rc = unsafe {{
let data_c = data.as_mut_ptr() as *mut {type_c};
let rc = c::trexio_read_safe_{group}_{element}_64(self.ptr, data_c, size.try_into().expect("try_into failed in read_{group}_{element} (size)"));
data.set_len(size);
rc
}};
rc_return(data, rc)
}}"#));
r.push(format!(r#"
/// Writes the `{element}` array into the group `{group}` in the file.
///
/// # Parameters
///
/// * `data: &[{type_r}]` - A one-dimensional vector that contains the elements of the `{element}` array
/// to be written into the file. The vector should be flattened from a two-dimensional array with
/// dimensions `{dimensions_str}`.
///
/// # Returns
///
/// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful,
/// otherwise returns `Err(ExitCode)`.""", """\
pub fn write_{group_l}_{element_l}(&self, data: &[{type_r}]) -> Result<(), ExitCode> {{
let size: i64 = data.len().try_into().expect("try_into failed in write_{group_l}_{element_l}");
let data = data.as_ptr() as *const {type_c};
let rc = unsafe {{ c::trexio_write_safe_{group}_{element}_64(self.ptr, data, size) }};
rc_return((), rc)
}}
"#));
}
,
"str" => {
r.push(format!(r#"
/// Reads the `{element}` array from the group `{group}` in the file.
///
/// # Dimensions
///
/// The array is of dimension `{dimensions_str}`.
///
/// # Returns
///
/// * `Result<Vec<{type_r}>, ExitCode>` - Returns a flattened one-dimensional vector that contains
/// the elements of the `{element}` array. If the operation is unsuccessful, it returns `Err(ExitCode)`.
///
/// "#));
if dimensions.len() > 1 {
r.push(format!(r#"/// # Example
///
/// To reshape the one-dimensional vector back into a two-dimensional array, you can use the [`chunks`] method:
///
/// ```text
/// let one_d_array = trexio_file.read_{}_{}()?;"#, group_l, element_l));
if let Some(dim) = dimensions.first() {
if dim.contains('.') {
let parts: Vec<&str> = dim.split('.').collect();
r.push(format!("/// let {}_{} = trexio_file.read_{}_{}()?;", parts[0], parts[1], parts[0], parts[1]));
r.push(format!("/// let two_d_array: Vec<_> = one_d_array.chunks({}_{}).collect();", parts[0], parts[1]));
} else {
r.push(format!("/// let two_d_array: Vec<_> = one_d_array.chunks({}).collect();", dim));
}
}
r.push(String::from("/// ```"));
r.push(String::from("///\n/// [`chunks`]: slice::chunks"));
}
r.push(format!(r#"pub fn read_{}_{}(&self, capacity: usize) -> Result<Vec<String>, ExitCode> {{
let mut size = 1;"#, group_l, element_l));
for dim in &dimensions {
if dim.contains('.') {
let parts: Vec<&str> = dim.split('.').collect();
r.push(format!(" size *= self.read_{}_{}()?;", parts[0], parts[1]));
} else {
r.push(format!(" size *= {};", dim));
}
}
r.push(format!(r#" // Allocate an array of *mut i8 pointers (initialized to null)
let mut dset_out: Vec<*mut i8> = vec![std::ptr::null_mut(); size];
// Allocate C-style strings and populate dset_out
for item in dset_out.iter_mut().take(size) {{
let c_str: *mut i8 = unsafe {{ std::alloc::alloc_zeroed(std::alloc::Layout::array::<i8>(capacity).unwrap()) as *mut i8 }};
if c_str.is_null() {{
return Err(ExitCode::AllocationFailed);
}}
*item = c_str;
}}
let rc = unsafe {{
c::trexio_read_{group}_{element}(self.ptr, dset_out.as_mut_ptr(), capacity.try_into().expect("try_into failed in read_{group}_{element} (capacity)") )
}};
// Convert the populated C strings to Rust Strings
let mut rust_strings = Vec::new();
for &c_str in &dset_out {{
let rust_str = unsafe {{
std::ffi::CStr::from_ptr(c_str)
.to_string_lossy()
.into_owned()
}};
rust_strings.push(rust_str);
}}
// Clean up allocated C strings
for &c_str in &dset_out {{
unsafe {{ std::alloc::dealloc(c_str as *mut u8, std::alloc::Layout::array::<i8>(capacity).unwrap()) }};
}}
rc_return(rust_strings, rc)
}}
/// Writes the `{element}` array into the group `{group}` in the file.
///
/// # Parameters
///
/// * `data: &[{type_r}]` - A one-dimensional vector that contains the elements of the `{element}` array
/// to be written into the file. The vector should be flattened from a two-dimensional array with
/// dimensions `{dimensions_str}`.
///
/// # Returns
///
/// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful,
/// otherwise returns `Err(ExitCode)`.
pub fn write_{group_l}_{element_l}(&self, data: &[&str]) -> Result<(), ExitCode> {{
let mut size = 0;
// Find longest string
for s in data {{
let l = s.len();
size = if l>size {{l}} else {{size}};
}}
size += 1;
let data_c : Vec<CString> = data.iter().map(|&x| string_to_c(x)).collect::<Vec<_>>();
let data_c : Vec<*const c_char> = data_c.iter().map(|x| x.as_ptr() as *const c_char).collect::<Vec<_>>();
let size : i32 = size.try_into().expect("try_into failed in write_{group}_{element} (size)");
let data_c = data_c.as_ptr() as *mut *const c_char;
let rc = unsafe {{ c::trexio_write_{group}_{element}(self.ptr, data_c, size) }};
rc_return((), rc)
}}
"#));
},
"float sparse" => {
let size = dimensions.len();
let typ = [ "(", (vec![ "usize" ; size ]).join(", ").as_str(),", f64)"].join("");
r.push(format!(r#"
/// Reads a buffer of {element} from group {group}.
///
/// # Parameters
///
/// * `offset: usize` - The starting point in the array from which data will be read.
/// * `buffer_size: usize` - The size of the buffer in which read data will be stored.
///
/// # Returns
///
/// * `Result<Vec<{typ}>, ExitCode>` - Returns a vector of tuples containing
/// the indices and the value of the element. The vector has a length of at most `buffer_size`.
///
/// # Notes
///
/// The reading process is a buffered operation, meaning that only a segment of the full array
/// is read into the memory.
pub fn read_{group_l}_{element_l}(&self, offset: usize, buffer_size:usize) -> Result<Vec<{typ}>, ExitCode> {{
let mut idx = Vec::<i32>::with_capacity({size}*buffer_size);
let mut val = Vec::<f64>::with_capacity(buffer_size);
let idx_ptr = idx.as_ptr() as *mut i32;
let val_ptr = val.as_ptr() as *mut f64;
let offset: i64 = offset.try_into().expect("try_into failed in read_{group}_{element} (offset)");
let mut buffer_size_read: i64 = buffer_size.try_into().expect("try_into failed in read_{group}_{element} (buffer_size)");
let rc = unsafe {{ c::trexio_read_safe_{group}_{element}(self.ptr,
offset, &mut buffer_size_read, idx_ptr, buffer_size_read, val_ptr, buffer_size_read)
}};
let rc = match ExitCode::from(rc) {{
ExitCode::End => ExitCode::to_c(&ExitCode::Success),
_ => rc
}};
let buffer_size_read: usize = buffer_size_read.try_into().expect("try_into failed in read_{group}_{element} (buffer_size)");
unsafe {{ idx.set_len({size}*buffer_size_read) }};
unsafe {{ val.set_len(buffer_size_read) }};
let idx: Vec::<&[i32]> = idx.chunks({size}).collect();
let mut result = Vec::<{typ}>::with_capacity(buffer_size);
for (i, v) in zip(idx, val) {{
result.push( ("#));
let mut x = Vec::new();
for k in 0..size {
x.push(format!("i[{k}].try_into().unwrap()"))
};
x.push("v));\n }\n rc_return(result, rc)\n}".to_string());
r.push(x.join(", "));
r.push(format!(r#"/// Writes a buffer of {element} from group {group}.
///
/// # Parameters
///
/// * `offset: usize` - The starting point in the array at which data will be written.
/// * `data: &[{typ}]` - A slice of tuples containing the indices and the value of the element.
///
/// # Returns
///
/// * `Result<(), ExitCode>` - Returns `Ok(())` if the writing operation is successful,
/// otherwise returns `Err(ExitCode)`.
///
/// # Notes
///
/// The writing process is a buffered operation, meaning that only a segment of the full array
/// is written into the file.
pub fn write_{group_l}_{element_l}(&self, offset: usize, data: &[{typ}]) -> Result<(), ExitCode> {{
let mut idx = Vec::<i32>::with_capacity({size}*data.len());
let mut val = Vec::<f64>::with_capacity(data.len());
for d in data {{ "#));
let mut x = Vec::new();
for k in 0..size {
x.push(format!(" idx.push(d.{k}.try_into().unwrap());"))
};
r.push(x.join("\n"));
r.push(format!(r#"
val.push(d.{size});
}}
let size_max: i64 = data.len().try_into().expect("try_into failed in write_{group}_{element} (size_max)");
let buffer_size = size_max;
let idx_ptr = idx.as_ptr() as *const i32;
let val_ptr = val.as_ptr() as *const f64;
let offset: i64 = offset.try_into().expect("try_into failed in write_{group}_{element} (offset)");
let rc = unsafe {{ c::trexio_write_safe_{group}_{element}(self.ptr,
offset, buffer_size, idx_ptr, size_max, val_ptr, size_max) }};
rc_return((), rc)
}}"#));
},
_ => {}
}
}
}
}
r
}
/// Reads the JSON file, processes its contents, and generates Rust functions according to the specifications in the JSON data.
fn make_functions(json_path: &PathBuf) -> std::io::Result<()> {
let file = File::open(json_path).unwrap();
let data: Value = serde_json::from_reader(file).unwrap();
let mut r: Vec<String> = vec![
String::from("
use std::ffi::CString;
use std::iter::zip;
/// This implementation block includes additional functions automatically generated from tables.
/// For more details, refer to [TREXIO tables documentation](https://trex-coe.github.io/trexio/trex.html).
impl File {
#![allow(clippy::unnecessary_cast)]
#![allow(clippy::useless_conversion)]
#![allow(clippy::type_complexity)]
"),
];
r.append(&mut make_has_functions(&data));
r.append(&mut make_scalar_functions(&data));
r.append(&mut make_array_functions(&data));
r.push(String::from("}"));
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let generated_rs = out_path.join(GENERATED_RS);
let mut f = File::create(&generated_rs)?;
f.write_all(r.join("\n").as_bytes())?;
Ok(())
}
fn main() {
let source_path = download_trexio();
println!("source path: {}", source_path.display());
let install_path = install_trexio(&source_path);
println!("install path: {}", install_path.display());
// Tell cargo to look for shared libraries in the specified directory
println!("cargo:rustc-link-search={}/lib", install_path.display());
// Tell cargo to tell rustc to link the system trexio shared library.
println!("cargo:rustc-link-lib=trexio");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let trexio_h = install_path.join("include").join("trexio.h");
println!("trexio.h: {}", trexio_h.display());
make_interface(&trexio_h).unwrap();
// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let wrapper_h = out_path.join(WRAPPER_H);
println!("wrapper.h: {}", wrapper_h.display());
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header(wrapper_h.to_str().unwrap())
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let bindings_path = out_path.join("bindings.rs");
println!("bindings.rs: {}", bindings_path.display());
bindings
.write_to_file(&bindings_path)
.expect("Couldn't write bindings!");
let json_path = source_path.join("trex.json");
println!("json path: {}", json_path.display());
make_functions(&json_path).unwrap();
}

View File

@ -0,0 +1,35 @@
use crate::c;
#[derive(Debug, PartialEq)]
pub enum BackEnd {
/// The TREXIO "file" is a directory with text files for each group.
/// A fallback when HDF5 is not available.
Text,
/// Should be used for production. The TREXIO file is a single HDF5 file.
Hdf5,
/// Automatic discovery of the appropriate backend
Auto,
}
impl BackEnd {
/// Creation from a C value
pub fn from(b: c::back_end_t) -> Self {
match b {
c::TREXIO_TEXT => Self::Text,
c::TREXIO_HDF5 => Self::Hdf5,
c::TREXIO_AUTO => Self::Auto,
_ => panic!("Invalid backend"),
}
}
/// Conversion to a C value
pub fn to_c(self) -> c::back_end_t {
match self {
Self::Text => c::TREXIO_TEXT,
Self::Hdf5 => c::TREXIO_HDF5,
Self::Auto => c::TREXIO_AUTO,
}
}
}

208
rust/trexio/src/bitfield.rs Normal file
View File

@ -0,0 +1,208 @@
#[derive(Debug, PartialEq)]
pub struct Bitfield {
data: Vec<i64>,
}
use crate::c;
use crate::ExitCode;
impl Bitfield {
/// Creates a new bitfield , using a number of i64 elements consistent
/// with the number of MOs in the TREXIO file.
pub fn from(n_int: usize, orb_list: &[usize]) -> (Self, f64) {
let orb_list: Vec<i32> = orb_list.iter().map(|&x| x as i32).collect();
let occ_num = orb_list
.len()
.try_into()
.expect("try_into failed in Bitfield::from");
let orb_list_ptr: *const i32 = orb_list.as_ptr();
let n_int32: i32 = n_int.try_into().expect("try_into failed in Bitfield::from");
let mut b = vec![0i64; n_int];
let bit_list = b.as_mut_ptr() as *mut c::bitfield_t;
std::mem::forget(b);
let rc = unsafe { c::trexio_to_bitfield_list(orb_list_ptr, occ_num, bit_list, n_int32) };
let data = unsafe { Vec::from_raw_parts(bit_list, n_int, n_int) };
let result = Bitfield { data };
match ExitCode::from(rc) {
ExitCode::Success => (result, 1.0),
ExitCode::PhaseChange => (result, -1.0),
x => panic!("TREXIO Error {}", x),
}
}
pub fn from_vec(v: &[i64]) -> Bitfield {
Bitfield { data: v.to_vec() }
}
pub fn from_alpha_beta(alpha: &Bitfield, beta: &Bitfield) -> Bitfield {
if alpha.data.len() != beta.data.len() {
panic!("alpha and beta parts have different lengths");
};
let mut data = alpha.data.clone();
data.extend_from_slice(&beta.data);
Bitfield { data }
}
/// Returns the alpha part
pub fn alpha(&self) -> Bitfield {
let n_int = self.data.len() / 2;
Bitfield {
data: (self.data[0..n_int]).to_vec(),
}
}
/// Returns the beta part
pub fn beta(&self) -> Bitfield {
let n_int = self.data.len() / 2;
Bitfield {
data: (self.data[n_int..2 * n_int]).to_vec(),
}
}
/// Converts to a format usable in the C library
pub fn as_ptr(&self) -> *const c::bitfield_t {
let len = self.data.len();
let result = &self.data[0..len];
result.as_ptr() as *const c::bitfield_t
}
/// Converts to a format usable in the C library
pub fn as_mut_ptr(&mut self) -> *mut c::bitfield_t {
let len = self.data.len();
let result = &mut self.data[0..len];
result.as_mut_ptr() as *mut c::bitfield_t
}
/// Converts the bitfield into a list of orbital indices (0-based)
pub fn to_orbital_list(&self) -> Vec<usize> {
let n_int: i32 = self
.data
.len()
.try_into()
.expect("try_into failed in to_orbital_list");
let d1 = self.as_ptr();
let cap = self.data.len() * 64;
let mut list = vec![0i32; cap];
let list_c: *mut i32 = list.as_mut_ptr();
std::mem::forget(list);
let mut occ_num: i32 = 0;
let rc = unsafe { c::trexio_to_orbital_list(n_int, d1, list_c, &mut occ_num) };
match ExitCode::from(rc) {
ExitCode::Success => (),
x => panic!("TREXIO Error {}", x),
};
let occ_num = occ_num as usize;
let list = unsafe { Vec::from_raw_parts(list_c, occ_num, cap) };
let mut result: Vec<usize> = Vec::with_capacity(occ_num);
for i in list.iter() {
result.push(*i as usize);
}
result
}
/// Converts the bitfield into a vector
pub fn as_vec(&self) -> &[i64] {
&self.data
}
/// Converts the determinant into a list of orbital indices (0-based)
pub fn to_orbital_list_up_dn(&self) -> (Vec<usize>, Vec<usize>) {
let n_int: i32 = (self.data.len() / 2)
.try_into()
.expect("try_into failed in to_orbital_list");
let d1 = self.as_ptr();
let cap = self.data.len() / 2 * 64;
let mut b = vec![0i32; cap];
let list_up_c: *mut i32 = b.as_mut_ptr();
std::mem::forget(b);
let mut b = vec![0i32; cap];
let list_dn_c: *mut i32 = b.as_mut_ptr();
std::mem::forget(b);
let mut occ_num_up: i32 = 0;
let mut occ_num_dn: i32 = 0;
let rc = unsafe {
c::trexio_to_orbital_list_up_dn(
n_int,
d1,
list_up_c,
list_dn_c,
&mut occ_num_up,
&mut occ_num_dn,
)
};
match ExitCode::from(rc) {
ExitCode::Success => (),
x => panic!("TREXIO Error {}", x),
};
let occ_num_up = occ_num_up as usize;
let occ_num_dn = occ_num_dn as usize;
let list_up = unsafe { Vec::from_raw_parts(list_up_c, occ_num_up, cap) };
let list_dn = unsafe { Vec::from_raw_parts(list_dn_c, occ_num_dn, cap) };
let mut result_up: Vec<usize> = Vec::with_capacity(occ_num_up);
for i in list_up.iter() {
result_up.push(*i as usize);
}
let mut result_dn: Vec<usize> = Vec::with_capacity(occ_num_dn);
for i in list_dn.iter() {
result_dn.push(*i as usize);
}
(result_up, result_dn)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn creation_from_list() {
let list0 = vec![0, 1, 2, 3, 4];
let list1 = vec![0, 1, 2, 4, 3];
let list2 = vec![0, 1, 4, 2, 3];
let (alpha0, phase0) = Bitfield::from(2, &list0);
let list = alpha0.to_orbital_list();
assert_eq!(list, list0);
let (alpha1, phase1) = Bitfield::from(2, &list1);
let list = alpha1.to_orbital_list();
assert_eq!(list, list0);
assert_eq!(phase1, -phase0);
let (alpha2, phase2) = Bitfield::from(2, &list2);
let list = alpha2.to_orbital_list();
assert_eq!(list, list0);
assert_eq!(phase2, phase0);
}
#[test]
fn creation_alpha_beta() {
let (alpha, _) = Bitfield::from(2, &[0, 1, 2, 3, 4]);
let (beta, _) = Bitfield::from(2, &[0, 1, 2, 4, 5]);
let det = Bitfield::from_alpha_beta(&alpha, &beta);
let list = det.to_orbital_list();
assert_eq!(list, [0, 1, 2, 3, 4, 128, 129, 130, 132, 133]);
assert_eq!(det.alpha(), alpha);
assert_eq!(det.beta(), beta);
}
#[test]
#[should_panic]
fn creation_alpha_beta_with_different_nint() {
let (alpha, _) = Bitfield::from(1, &[0, 1, 2, 3, 4]);
let (beta, _) = Bitfield::from(2, &[0, 1, 2, 4, 5]);
let _ = Bitfield::from_alpha_beta(&alpha, &beta);
}
}

6
rust/trexio/src/c.rs Normal file
View File

@ -0,0 +1,6 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

View File

@ -0,0 +1,219 @@
use crate::c;
#[derive(Debug, PartialEq)]
pub enum ExitCode {
/// Unknown failure
Failure,
/// Everything went fine
Success,
/// Invalid argument
InvalidArg(usize),
/// End of file
End,
/// Read-only file
ReadOnly,
/// Error returned by Errno
Errno,
/// Invalid ID
InvalidId,
/// Allocation failed
AllocationFailed,
/// Element absent
HasNot,
/// Invalid (negative or 0) dimension
InvalidNum,
/// Attribute already exists
AttrAlreadyExists,
/// Dataset already exists
DsetAlreadyExists,
/// Error opening file
OpenError,
/// Error locking file
LockError,
/// Error unlocking file
UnlockError,
/// Invalid file
FileError,
/// Error reading group
GroupReadError,
/// Error writing group
GroupWriteError,
/// Error reading element
ElemReadError,
/// Error writing element
ElemWriteError,
/// Access to memory beyond allocated
UnsafeArrayDim,
/// Attribute does not exist in the file
AttrMissing,
/// Dataset does not exist in the file
DsetMissing,
/// Requested back end is disabled
BackEndMissing,
/// Invalid max_str_len
InvalidStrLen,
/// Possible integer overflow
IntSizeOverflow,
/// Unsafe operation in safe mode
SafeMode,
/// Inconsistent number of electrons
InvalidElectronNum,
/// Inconsistent number of determinants
InvalidDeterminantNum,
/// Inconsistent state of the file
InvalidState,
/// Failed to parse package_version
VersionParsingIssue,
/// The function succeeded with a change of sign
PhaseChange,
}
impl ExitCode {
/// Creation from a C value
pub fn from(rc: c::trexio_exit_code) -> Self {
match rc {
c::TREXIO_FAILURE => Self::Failure,
c::TREXIO_SUCCESS => Self::Success,
c::TREXIO_INVALID_ARG_1 => Self::InvalidArg(1),
c::TREXIO_INVALID_ARG_2 => Self::InvalidArg(2),
c::TREXIO_INVALID_ARG_3 => Self::InvalidArg(3),
c::TREXIO_INVALID_ARG_4 => Self::InvalidArg(4),
c::TREXIO_INVALID_ARG_5 => Self::InvalidArg(5),
c::TREXIO_END => Self::End,
c::TREXIO_READONLY => Self::ReadOnly,
c::TREXIO_ERRNO => Self::Errno,
c::TREXIO_INVALID_ID => Self::InvalidId,
c::TREXIO_ALLOCATION_FAILED => Self::AllocationFailed,
c::TREXIO_HAS_NOT => Self::HasNot,
c::TREXIO_INVALID_NUM => Self::InvalidNum,
c::TREXIO_ATTR_ALREADY_EXISTS => Self::AttrAlreadyExists,
c::TREXIO_DSET_ALREADY_EXISTS => Self::DsetAlreadyExists,
c::TREXIO_OPEN_ERROR => Self::OpenError,
c::TREXIO_LOCK_ERROR => Self::LockError,
c::TREXIO_UNLOCK_ERROR => Self::UnlockError,
c::TREXIO_FILE_ERROR => Self::FileError,
c::TREXIO_GROUP_READ_ERROR => Self::GroupReadError,
c::TREXIO_GROUP_WRITE_ERROR => Self::GroupWriteError,
c::TREXIO_ELEM_READ_ERROR => Self::ElemReadError,
c::TREXIO_ELEM_WRITE_ERROR => Self::ElemWriteError,
c::TREXIO_UNSAFE_ARRAY_DIM => Self::UnsafeArrayDim,
c::TREXIO_ATTR_MISSING => Self::AttrMissing,
c::TREXIO_DSET_MISSING => Self::DsetMissing,
c::TREXIO_BACK_END_MISSING => Self::BackEndMissing,
c::TREXIO_INVALID_ARG_6 => Self::InvalidArg(6),
c::TREXIO_INVALID_ARG_7 => Self::InvalidArg(7),
c::TREXIO_INVALID_ARG_8 => Self::InvalidArg(8),
c::TREXIO_INVALID_STR_LEN => Self::InvalidStrLen,
c::TREXIO_INT_SIZE_OVERFLOW => Self::IntSizeOverflow,
c::TREXIO_SAFE_MODE => Self::SafeMode,
c::TREXIO_INVALID_ELECTRON_NUM => Self::InvalidElectronNum,
c::TREXIO_INVALID_DETERMINANT_NUM => Self::InvalidDeterminantNum,
c::TREXIO_INVALID_STATE => Self::InvalidState,
c::TREXIO_VERSION_PARSING_ISSUE => Self::VersionParsingIssue,
c::TREXIO_PHASE_CHANGE => Self::PhaseChange,
_ => panic!("Unknown exit code"),
}
}
/// Conversion to a C value
pub fn to_c(&self) -> c::trexio_exit_code {
match self {
Self::Failure => c::TREXIO_FAILURE,
Self::Success => c::TREXIO_SUCCESS,
Self::InvalidArg(1) => c::TREXIO_INVALID_ARG_1,
Self::InvalidArg(2) => c::TREXIO_INVALID_ARG_2,
Self::InvalidArg(3) => c::TREXIO_INVALID_ARG_3,
Self::InvalidArg(4) => c::TREXIO_INVALID_ARG_4,
Self::InvalidArg(5) => c::TREXIO_INVALID_ARG_5,
Self::End => c::TREXIO_END,
Self::ReadOnly => c::TREXIO_READONLY,
Self::Errno => c::TREXIO_ERRNO,
Self::InvalidId => c::TREXIO_INVALID_ID,
Self::AllocationFailed => c::TREXIO_ALLOCATION_FAILED,
Self::HasNot => c::TREXIO_HAS_NOT,
Self::InvalidNum => c::TREXIO_INVALID_NUM,
Self::AttrAlreadyExists => c::TREXIO_ATTR_ALREADY_EXISTS,
Self::DsetAlreadyExists => c::TREXIO_DSET_ALREADY_EXISTS,
Self::OpenError => c::TREXIO_OPEN_ERROR,
Self::LockError => c::TREXIO_LOCK_ERROR,
Self::UnlockError => c::TREXIO_UNLOCK_ERROR,
Self::FileError => c::TREXIO_FILE_ERROR,
Self::GroupReadError => c::TREXIO_GROUP_READ_ERROR,
Self::GroupWriteError => c::TREXIO_GROUP_WRITE_ERROR,
Self::ElemReadError => c::TREXIO_ELEM_READ_ERROR,
Self::ElemWriteError => c::TREXIO_ELEM_WRITE_ERROR,
Self::UnsafeArrayDim => c::TREXIO_UNSAFE_ARRAY_DIM,
Self::AttrMissing => c::TREXIO_ATTR_MISSING,
Self::DsetMissing => c::TREXIO_DSET_MISSING,
Self::BackEndMissing => c::TREXIO_BACK_END_MISSING,
Self::InvalidArg(6) => c::TREXIO_INVALID_ARG_6,
Self::InvalidArg(7) => c::TREXIO_INVALID_ARG_7,
Self::InvalidArg(8) => c::TREXIO_INVALID_ARG_8,
Self::InvalidStrLen => c::TREXIO_INVALID_STR_LEN,
Self::IntSizeOverflow => c::TREXIO_INT_SIZE_OVERFLOW,
Self::SafeMode => c::TREXIO_SAFE_MODE,
Self::InvalidElectronNum => c::TREXIO_INVALID_ELECTRON_NUM,
Self::InvalidDeterminantNum => c::TREXIO_INVALID_DETERMINANT_NUM,
Self::InvalidState => c::TREXIO_INVALID_STATE,
Self::VersionParsingIssue => c::TREXIO_VERSION_PARSING_ISSUE,
Self::PhaseChange => c::TREXIO_PHASE_CHANGE,
_ => panic!("Unknown exit code"),
}
}
pub fn to_str(&self) -> Result<&'static str, Utf8Error> {
let c_error = self.to_c();
let c_buf: *const c_char = unsafe { c::trexio_string_of_error(c_error) };
let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) };
c_str.to_str()
}
}
use std::error::Error;
use std::ffi::c_char;
use std::ffi::CStr;
use std::fmt;
use std::str::Utf8Error;
impl fmt::Display for ExitCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_str().unwrap())
}
}
impl Error for ExitCode {
fn description(&self) -> &str {
self.to_str().unwrap()
}
}

261
rust/trexio/src/lib.rs Normal file
View File

@ -0,0 +1,261 @@
//! TREXIO is an open-source file format and library developed for the storage and manipulation of
//! data produced by quantum chemistry calculations. It was designed with the goal of providing a
//! reliable and efficient method of storing and exchanging wave function parameters and matrix
//! elements.
//!
//! For comprehensive documentation, consult: [TREXIO Documentation](https://trex-coe.github.io/trexio/)
//!
//! The C library source code is available on GitHub: [TREXIO GitHub Repository](https://github.com/trex-coe/trexio)
//!
use ::std::os::raw::c_char;
mod c;
/// Enumeration representing the various error codes that might be returned by function calls.
/// These error codes are mapped to those defined in the original C TREXIO library.
pub mod exit_code;
pub use exit_code::ExitCode;
use exit_code::ExitCode::InvalidArg;
/// Enum representing the different backends that TREXIO can employ for data storage.
pub mod back_end;
pub use back_end::BackEnd;
/// Structure representing bit fields. Mainly utilized for encapsulating determinant descriptions.
pub mod bitfield;
pub use bitfield::Bitfield;
/// A constant string representing the package version of the linked C TREXIO library.
pub const PACKAGE_VERSION: &str =
unsafe { std::str::from_utf8_unchecked(c::TREXIO_PACKAGE_VERSION) };
/// Utility function to convert Rust results into TREXIO exit codes.
fn rc_return<T>(result: T, rc: c::trexio_exit_code) -> Result<T, ExitCode> {
let rc = ExitCode::from(rc);
match rc {
ExitCode::Success => Ok(result),
x => Err(x),
}
}
/// Utility function to convert Rust string to C-compatible string.
fn string_to_c(s: &str) -> std::ffi::CString {
std::ffi::CString::new(s).unwrap()
}
/// Function to print out diagnostic information about the linked C TREXIO library.
pub fn info() -> Result<(), ExitCode> {
let rc = unsafe { c::trexio_info() };
rc_return((), rc)
}
/// Type representing a TREXIO file. Wraps a pointer to the underlying C structure.
pub struct File {
ptr: *mut c::trexio_t,
}
impl File {
/// Opens a TREXIO file. Returns a `File` instance that can be used for subsequent I/O operations.
///
/// # Parameters
/// - `file_name`: The path to the TREXIO file.
/// - `mode`: Specifies the file access mode. `'r'` for read-only, `'w'` for safe write (write
/// if the data doesn't exist), `'u'` for unsafe write (update existing data).
/// - `back_end`: Specifies the backend used for data storage.
///
/// # Returns
/// - `Result<File, ExitCode>`: `File` instance or an error code.
pub fn open(file_name: &str, mode: char, back_end: BackEnd) -> Result<File, ExitCode> {
let file_name_c = string_to_c(file_name);
let file_name_c = file_name_c.as_ptr() as *const c_char;
let mode = mode as c_char;
let back_end = back_end.to_c();
let rc: *mut c::trexio_exit_code = &mut c::TREXIO_SUCCESS.clone();
let result = unsafe { c::trexio_open(file_name_c, mode, back_end, rc) };
let rc = unsafe { *rc };
rc_return(File { ptr: result }, rc)
}
/// Closes the current TREXIO file and releases associated resources.
///
/// # Returns
/// - `Result<(), ExitCode>`: An error code in case of failure.
pub fn close(self) -> Result<(), ExitCode> {
let rc = unsafe { c::trexio_close(self.ptr) };
rc_return((), rc)
}
/// Inquires if a file with the specified name exists.
///
/// # Parameters
///
/// * `file_name: &str` - The name of the file to inquire about.
///
/// # Returns
///
/// * `Result<bool, ExitCode>` - Returns `Ok(true)` if the file exists,
/// `Ok(false)` otherwise. Returns `Err(ExitCode)` if an error occurs
/// during the operation.
pub fn inquire(file_name: &str) -> Result<bool, ExitCode> {
let file_name_c = string_to_c(file_name);
let file_name_c = file_name_c.as_ptr() as *const c_char;
let rc = unsafe { c::trexio_inquire(file_name_c) };
match ExitCode::from(rc) {
ExitCode::Failure => Ok(false),
ExitCode::Success => Ok(true),
x => Err(x),
}
}
/// Retrieves the ID of the electronic state stored in the file.
///
/// # Parameters
///
/// None
///
/// # Returns
///
/// * `Result<usize, ExitCode>` - Returns the ID as `Ok(usize)` if the operation is successful,
/// otherwise returns `Err(ExitCode)`.
pub fn get_state(&self) -> Result<usize, ExitCode> {
let mut num = 0i32;
let rc = unsafe { c::trexio_get_state(self.ptr, &mut num) };
let result: usize = num.try_into().expect("try_into failed in get_state");
rc_return(result, rc)
}
/// Sets the ID of the electronic state to be stored in the file.
///
/// # Parameters
///
/// * `num: usize` - The ID of the electronic state.
///
/// # Returns
///
/// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful,
/// otherwise returns `Err(ExitCode)`.
pub fn set_state(&self, num: usize) -> Result<(), ExitCode> {
let num: i32 = num.try_into().expect("try_into failed in set_state");
let rc = unsafe { c::trexio_set_state(self.ptr, num) };
rc_return((), rc)
}
/// Retrieves the number of `i64` required to store a determinant as a bit-field.
/// This corresponds to \(\frac{\text{mo\_num}}{64}+1\).
///
/// # Parameters
///
/// None
///
/// # Returns
///
/// * `Result<usize, ExitCode>` - Returns the number of `i64` as `Ok(usize)` if the operation is successful,
/// otherwise returns `Err(ExitCode)`.
pub fn get_int64_num(&self) -> Result<usize, ExitCode> {
let mut num = 0i32;
let rc = unsafe { c::trexio_get_int64_num(self.ptr, &mut num) };
let num: usize = num.try_into().expect("try_into failed in get_int64_num");
rc_return(num, rc)
}
/// Writes a vector of determinants, represented as [Bitfield] objects.
///
/// # Parameters
///
/// * `offset: usize` - The number of determinants to skip in the file before writing.
/// * `determinants: &[Bitfield]` - The array of determinants to write.
///
/// # Returns
///
/// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful,
/// otherwise returns `Err(ExitCode)`.
pub fn write_determinant_list(
&self,
offset: usize,
determinants: &[Bitfield],
) -> Result<(), ExitCode> {
let n_int = self.get_int64_num()?;
match determinants.len() {
0 => return Ok(()),
_ => {
if determinants[0].as_vec().len() != 2 * n_int {
return Err(InvalidArg(3));
}
}
};
let offset: i64 = offset
.try_into()
.expect("try_into failed in write_determinant_list");
let buffer_size: i64 = determinants
.len()
.try_into()
.expect("try_into failed in write_determinant_list");
let mut one_d_array: Vec<i64> = Vec::with_capacity(determinants.len() * n_int);
for det in determinants {
for i in det.as_vec() {
one_d_array.push(*i);
}
}
let dset: *const i64 = one_d_array.as_ptr();
let rc = unsafe { c::trexio_write_determinant_list(self.ptr, offset, buffer_size, dset) };
rc_return((), rc)
}
/// Reads a vector of determinants, represented as [Bitfield] objects.
///
/// # Parameters
///
/// * `offset: usize` - The number of determinants to skip in the file before reading.
/// * `buffer_size: usize` - The number of determinants to read.
///
/// # Returns
///
/// * `Result<Vec<Bitfield>, ExitCode>` - Returns the read determinants as `Ok(Vec<Bitfield>)`
/// if the operation is successful, otherwise returns `Err(ExitCode)`.
pub fn read_determinant_list(
&self,
offset: usize,
buffer_size: usize,
) -> Result<Vec<Bitfield>, ExitCode> {
let n_int = self.get_int64_num()?;
let mut one_d_array: Vec<i64> = Vec::with_capacity(buffer_size * 2 * n_int);
let one_d_array_ptr = one_d_array.as_ptr() as *mut i64;
let rc = unsafe {
let offset: i64 = offset
.try_into()
.expect("try_into failed in read_determinant_list (offset)");
let mut buffer_size_read: i64 = buffer_size
.try_into()
.expect("try_into failed in read_determinant_list (buffer_size)");
let rc = c::trexio_read_determinant_list(
self.ptr,
offset,
&mut buffer_size_read,
one_d_array_ptr,
);
let buffer_size_read: usize = buffer_size_read
.try_into()
.expect("try_into failed in read_determinant_list (buffer_size)");
one_d_array.set_len(n_int * 2usize * buffer_size_read);
match ExitCode::from(rc) {
ExitCode::End => ExitCode::to_c(&ExitCode::Success),
ExitCode::Success => {
assert_eq!(buffer_size_read, buffer_size);
rc
}
_ => rc,
}
};
let result: Vec<Bitfield> = one_d_array
.chunks(2 * n_int)
.collect::<Vec<_>>()
.iter()
.map(|x| (Bitfield::from_vec(x)))
.collect::<Vec<_>>();
rc_return(result, rc)
}
}
include!(concat!(env!("OUT_DIR"), "/generated.rs"));

View File

@ -0,0 +1,292 @@
use trexio::back_end::BackEnd;
use trexio::bitfield::Bitfield;
fn write(file_name: &str, back_end: BackEnd) -> Result<(), trexio::ExitCode> {
// Prepare data to be written
let nucleus_num = 12;
let state_id = 2;
let charge = vec![6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.0f64];
let coord = vec![
[0.00000000f64, 1.39250319, 0.00],
[-1.20594314, 0.69625160, 0.00],
[-1.20594314, -0.69625160, 0.00],
[0.00000000, -1.39250319, 0.00],
[1.20594314, -0.69625160, 0.00],
[1.20594314, 0.69625160, 0.00],
[-2.14171677, 1.23652075, 0.00],
[-2.14171677, -1.23652075, 0.00],
[0.00000000, -2.47304151, 0.00],
[2.14171677, -1.23652075, 0.00],
[2.14171677, 1.23652075, 0.00],
[0.00000000, 2.47304151, 0.00],
];
let flat_coord = coord.into_iter().flatten().collect::<Vec<f64>>();
let mo_num = 150;
let ao_num = 1000;
let basis_shell_num = 24;
let basis_nucleus_index: Vec<usize> = (0..24).collect();
let label = vec![
"C", "Na", "C", "C 66", "C", "C", "H 99", "Ru", "H", "H", "H", "H",
];
let sym_str = "B3U with some comments";
println!("Write {}", file_name);
assert!(!trexio::File::inquire(file_name)?);
let trex_file = trexio::File::open(file_name, 'w', back_end)?;
assert!(!trex_file.has_nucleus()?);
assert!(!trex_file.has_nucleus_num()?);
assert!(!trex_file.has_nucleus_charge()?);
assert!(!trex_file.has_ao_2e_int()?);
assert!(!trex_file.has_ao_2e_int_eri()?);
assert!(!trex_file.has_determinant_list()?);
trex_file.write_nucleus_num(nucleus_num)?;
trex_file.write_nucleus_charge(&charge)?;
trex_file.write_nucleus_point_group(sym_str)?;
trex_file.write_nucleus_coord(&flat_coord)?;
trex_file.write_nucleus_label(&label)?;
trex_file.write_basis_shell_num(basis_shell_num)?;
trex_file.write_basis_nucleus_index(&basis_nucleus_index)?;
trex_file.write_state_id(state_id)?;
if !trex_file.has_ao_num()? {
trex_file.write_ao_num(ao_num)?;
}
if !trex_file.has_mo_num()? {
trex_file.write_mo_num(mo_num)?;
}
let mut energy = Vec::with_capacity(mo_num);
for i in 0..mo_num {
let e: f64 = i as f64 - 100.0f64;
energy.push(e);
}
trex_file.write_mo_energy(&energy)?;
let mut spin = vec![0; mo_num];
for i in mo_num / 2..mo_num {
spin[i] = 1;
}
trex_file.write_mo_spin(&spin)?;
// Integrals
let nmax = 100;
let mut ao_2e_int_eri = Vec::<(usize, usize, usize, usize, f64)>::with_capacity(nmax);
let n_buffers = 5;
let bufsize = nmax / n_buffers;
for i in 0..100 {
// Quadruplet of indices + value
let data = (4 * i, 4 * i + 1, 4 * i + 2, 4 * i + 3, 3.14 + (i as f64));
ao_2e_int_eri.push(data);
}
let mut offset = 0;
for _ in 0..n_buffers {
trex_file.write_ao_2e_int_eri(offset, &ao_2e_int_eri[offset..offset + bufsize])?;
offset += bufsize;
}
// Determinants
let det_num = 50;
let mut det_list = Vec::with_capacity(det_num);
for i in 0..det_num {
let mut d = [0i64; 6];
for j in 0..6 {
d[j] = 6 * (i as i64) + (j as i64);
}
det_list.push(Bitfield::from_vec(&d));
}
let n_buffers = 5;
let bufsize = 50 / n_buffers;
let mut offset = 0;
for _ in 0..n_buffers {
trex_file.write_determinant_list(offset, &det_list[offset..offset + bufsize])?;
offset += bufsize;
}
trex_file.close()
}
fn read(file_name: &str, back_end: BackEnd) -> Result<(), trexio::ExitCode> {
println!("Read {}", file_name);
assert!(trexio::File::inquire(file_name)?);
let trex_file = trexio::File::open(file_name, 'r', back_end)?;
assert!(trex_file.has_nucleus()?);
assert!(trex_file.has_nucleus_num()?);
assert!(trex_file.has_nucleus_charge()?);
assert!(trex_file.has_ao_2e_int()?);
assert!(trex_file.has_ao_2e_int_eri()?);
assert!(trex_file.has_determinant_list()?);
let nucleus_num = trex_file.read_nucleus_num()?;
assert_eq!(nucleus_num, 12);
let sym_str = trex_file.read_nucleus_point_group(64)?;
assert_eq!(sym_str, "B3U with some comments");
let charge = trex_file.read_nucleus_charge()?;
assert_eq!(
charge,
vec![6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.0f64]
);
let coord = trex_file.read_nucleus_coord()?;
assert_eq!(
coord,
vec![
0.00000000f64,
1.39250319,
0.00,
-1.20594314,
0.69625160,
0.00,
-1.20594314,
-0.69625160,
0.00,
0.00000000,
-1.39250319,
0.00,
1.20594314,
-0.69625160,
0.00,
1.20594314,
0.69625160,
0.00,
-2.14171677,
1.23652075,
0.00,
-2.14171677,
-1.23652075,
0.00,
0.00000000,
-2.47304151,
0.00,
2.14171677,
-1.23652075,
0.00,
2.14171677,
1.23652075,
0.00,
0.00000000,
2.47304151,
0.00
]
);
let label = trex_file.read_nucleus_label(6)?;
assert_eq!(
label,
vec!["C", "Na", "C", "C 66", "C", "C", "H 99", "Ru", "H", "H", "H", "H"]
);
let basis_shell_num = trex_file.read_basis_shell_num()?;
assert_eq!(basis_shell_num, 24);
let basis_nucleus_index = trex_file.read_basis_nucleus_index()?;
let ref_val: Vec<usize> = (0..24).collect();
assert_eq!(basis_nucleus_index, ref_val);
let state_id = trex_file.read_state_id()?;
assert_eq!(state_id, 2);
let ao_num = trex_file.read_ao_num()?;
assert_eq!(ao_num, 1000);
let mo_num = trex_file.read_mo_num()?;
assert_eq!(mo_num, 150);
let mut energy_ref = Vec::with_capacity(mo_num);
for i in 0..mo_num {
let e: f64 = i as f64 - 100.0f64;
energy_ref.push(e);
}
let energy = trex_file.read_mo_energy()?;
assert_eq!(energy, energy_ref);
let mut spin_ref = vec![0; mo_num];
for i in mo_num / 2..mo_num {
spin_ref[i] = 1;
}
let spin = trex_file.read_mo_spin()?;
assert_eq!(spin, spin_ref);
// Integrals
let nmax = 100;
let mut ao_2e_int_eri_ref = Vec::<(usize, usize, usize, usize, f64)>::with_capacity(nmax);
let n_buffers = 8;
let bufsize = nmax / n_buffers + 10;
for i in 0..100 {
// Quadruplet of indices + value
let data = (4 * i, 4 * i + 1, 4 * i + 2, 4 * i + 3, 3.14 + (i as f64));
ao_2e_int_eri_ref.push(data);
}
let mut offset = 0;
let mut ao_2e_int_eri = Vec::<(usize, usize, usize, usize, f64)>::with_capacity(nmax);
for _ in 0..n_buffers {
let buffer = trex_file.read_ao_2e_int_eri(offset, bufsize)?;
offset += buffer.len();
ao_2e_int_eri.extend(buffer);
}
assert_eq!(ao_2e_int_eri_ref, ao_2e_int_eri);
// Determinants
let det_num = trex_file.read_determinant_num()?;
assert_eq!(det_num, 50);
let mut det_list_ref = Vec::with_capacity(det_num);
for i in 0..det_num {
let mut d = [0i64; 6];
for j in 0..6 {
d[j] = 6 * (i as i64) + (j as i64);
}
det_list_ref.push(Bitfield::from_vec(&d));
}
let n_buffers = 8;
let bufsize = det_num / n_buffers + 20;
let mut offset = 0;
let mut det_list: Vec<Bitfield> = Vec::with_capacity(det_num);
for _ in 0..n_buffers {
let buffer = trex_file.read_determinant_list(offset, bufsize)?;
offset += buffer.len();
det_list.extend(buffer);
}
assert_eq!(det_list_ref, det_list);
trex_file.close()
}
#[test]
pub fn info() {
let _ = trexio::info();
}
use std::fs;
#[test]
pub fn text_backend() {
let _ = write("tmp/test_write.dir", trexio::BackEnd::Text).unwrap();
let _ = read("tmp/test_write.dir", trexio::BackEnd::Text).unwrap();
fs::remove_dir_all("tmp/test_write.dir").unwrap()
}
#[test]
pub fn hdf5_backend() {
let _ = write("tmp/test_write.hdf5", trexio::BackEnd::Hdf5).unwrap();
let _ = read("tmp/test_write.hdf5", trexio::BackEnd::Hdf5).unwrap();
fs::remove_file("tmp/test_write.hdf5").unwrap()
}

1
rust/trexio/tmp/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*

View File

@ -20,6 +20,258 @@
** C ** C
We include in thr trexio.h file a text variable that contains the
contents of the ~trex.json~ confguration file, generated from the
~trex.org~ file.
#+NAME: trex_json
#+begin_src python :results drawer
res = "/* JSON configuration\n"
with open('../../trex.json','r') as f:
for line in f:
res += line.rstrip()+'\n'
res += "*/"
return res
#+end_src
#+RESULTS: trex_json
:results:
/* JSON configuration
{
"metadata": {
"code_num" : [ "dim", [] ]
, "code" : [ "str", [ "metadata.code_num" ] ]
, "author_num" : [ "dim", [] ]
, "author" : [ "str", [ "metadata.author_num" ] ]
, "package_version" : [ "str", [] ]
, "description" : [ "str", [] ]
, "unsafe" : [ "int", [] ]
} ,
"nucleus": {
"num" : [ "dim" , [] ]
, "charge" : [ "float", [ "nucleus.num" ] ]
, "coord" : [ "float", [ "nucleus.num", "3" ] ]
, "label" : [ "str" , [ "nucleus.num" ] ]
, "point_group" : [ "str" , [] ]
, "repulsion" : [ "float", [] ]
} ,
"cell": {
"a" : [ "float", [ "3" ] ]
, "b" : [ "float", [ "3" ] ]
, "c" : [ "float", [ "3" ] ]
, "G_a" : [ "float", [ "3" ] ]
, "G_b" : [ "float", [ "3" ] ]
, "G_c" : [ "float", [ "3" ] ]
, "two_pi" : [ "int" , [] ]
} ,
"pbc": {
"periodic" : [ "int" , [] ]
, "k_point" : [ "float", [ "3" ] ]
} ,
"electron": {
"num" : [ "dim", [] ]
, "up_num" : [ "int", [] ]
, "dn_num" : [ "int", [] ]
} ,
"state": {
"num" : [ "dim" , [] ]
, "id" : [ "index", [] ]
, "energy" : [ "float", [] ]
, "current_label" : [ "str" , [] ]
, "label" : [ "str" , [ "state.num" ] ]
, "file_name" : [ "str" , [ "state.num" ] ]
} ,
"basis": {
"type" : [ "str" , [] ]
, "prim_num" : [ "dim" , [] ]
, "shell_num" : [ "dim" , [] ]
, "nao_grid_num" : [ "dim" , [] ]
, "interp_coeff_cnt" : [ "dim" , [] ]
, "nucleus_index" : [ "index", [ "basis.shell_num" ] ]
, "shell_ang_mom" : [ "int" , [ "basis.shell_num" ] ]
, "shell_factor" : [ "float", [ "basis.shell_num" ] ]
, "r_power" : [ "int" , [ "basis.shell_num" ] ]
, "nao_grid_start" : [ "index", [ "basis.shell_num" ] ]
, "nao_grid_size" : [ "dim" , [ "basis.shell_num" ] ]
, "shell_index" : [ "index", [ "basis.prim_num" ] ]
, "exponent" : [ "float", [ "basis.prim_num" ] ]
, "coefficient" : [ "float", [ "basis.prim_num" ] ]
, "prim_factor" : [ "float", [ "basis.prim_num" ] ]
, "e_cut" : [ "float", [] ]
, "nao_grid_radius" : [ "float", [ "basis.nao_grid_num" ] ]
, "nao_grid_phi" : [ "float", [ "basis.nao_grid_num" ] ]
, "nao_grid_grad" : [ "float", [ "basis.nao_grid_num" ] ]
, "nao_grid_lap" : [ "float", [ "basis.nao_grid_num" ] ]
, "interpolator_kind" : [ "str" , [] ]
, "interpolator_phi" : [ "float", [ "basis.nao_grid_num", "basis.interp_coeff_cnt" ] ]
, "interpolator_grad" : [ "float", [ "basis.nao_grid_num", "basis.interp_coeff_cnt" ] ]
, "interpolator_lap" : [ "float", [ "basis.nao_grid_num", "basis.interp_coeff_cnt" ] ]
} ,
"ecp": {
"max_ang_mom_plus_1" : [ "int" , [ "nucleus.num" ] ]
, "z_core" : [ "int" , [ "nucleus.num" ] ]
, "num" : [ "dim" , [] ]
, "ang_mom" : [ "int" , [ "ecp.num" ] ]
, "nucleus_index" : [ "index", [ "ecp.num" ] ]
, "exponent" : [ "float", [ "ecp.num" ] ]
, "coefficient" : [ "float", [ "ecp.num" ] ]
, "power" : [ "int" , [ "ecp.num" ] ]
} ,
"grid": {
"description" : [ "str" , [] ]
, "rad_precision" : [ "float", [] ]
, "num" : [ "dim" , [] ]
, "max_ang_num" : [ "int" , [] ]
, "min_ang_num" : [ "int" , [] ]
, "coord" : [ "float", [ "grid.num" ] ]
, "weight" : [ "float", [ "grid.num" ] ]
, "ang_num" : [ "dim" , [] ]
, "ang_coord" : [ "float", [ "grid.ang_num" ] ]
, "ang_weight" : [ "float", [ "grid.ang_num" ] ]
, "rad_num" : [ "dim" , [] ]
, "rad_coord" : [ "float", [ "grid.rad_num" ] ]
, "rad_weight" : [ "float", [ "grid.rad_num" ] ]
} ,
"ao": {
"cartesian" : [ "int" , [] ]
, "num" : [ "dim" , [] ]
, "shell" : [ "index", [ "ao.num" ] ]
, "normalization" : [ "float", [ "ao.num" ] ]
} ,
"ao_1e_int": {
"overlap" : [ "float", [ "ao.num", "ao.num" ] ]
, "kinetic" : [ "float", [ "ao.num", "ao.num" ] ]
, "potential_n_e" : [ "float", [ "ao.num", "ao.num" ] ]
, "ecp" : [ "float", [ "ao.num", "ao.num" ] ]
, "core_hamiltonian" : [ "float", [ "ao.num", "ao.num" ] ]
, "overlap_im" : [ "float", [ "ao.num", "ao.num" ] ]
, "kinetic_im" : [ "float", [ "ao.num", "ao.num" ] ]
, "potential_n_e_im" : [ "float", [ "ao.num", "ao.num" ] ]
, "ecp_im" : [ "float", [ "ao.num", "ao.num" ] ]
, "core_hamiltonian_im" : [ "float", [ "ao.num", "ao.num" ] ]
} ,
"ao_2e_int": {
"eri" : [ "float sparse", [ "ao.num", "ao.num", "ao.num", "ao.num" ] ]
, "eri_lr" : [ "float sparse", [ "ao.num", "ao.num", "ao.num", "ao.num" ] ]
, "eri_cholesky_num" : [ "dim" , [] ]
, "eri_cholesky" : [ "float sparse", [ "ao_2e_int.eri_cholesky_num", "ao.num", "ao.num" ] ]
, "eri_lr_cholesky_num" : [ "dim" , [] ]
, "eri_lr_cholesky" : [ "float sparse", [ "ao_2e_int.eri_lr_cholesky_num", "ao.num", "ao.num" ] ]
} ,
"mo": {
"type" : [ "str" , [] ]
, "num" : [ "dim" , [] ]
, "coefficient" : [ "float", [ "mo.num", "ao.num" ] ]
, "coefficient_im" : [ "float", [ "mo.num", "ao.num" ] ]
, "class" : [ "str" , [ "mo.num" ] ]
, "symmetry" : [ "str" , [ "mo.num" ] ]
, "occupation" : [ "float", [ "mo.num" ] ]
, "energy" : [ "float", [ "mo.num" ] ]
, "spin" : [ "int" , [ "mo.num" ] ]
} ,
"mo_1e_int": {
"overlap" : [ "float", [ "mo.num", "mo.num" ] ]
, "kinetic" : [ "float", [ "mo.num", "mo.num" ] ]
, "potential_n_e" : [ "float", [ "mo.num", "mo.num" ] ]
, "ecp" : [ "float", [ "mo.num", "mo.num" ] ]
, "core_hamiltonian" : [ "float", [ "mo.num", "mo.num" ] ]
, "overlap_im" : [ "float", [ "mo.num", "mo.num" ] ]
, "kinetic_im" : [ "float", [ "mo.num", "mo.num" ] ]
, "potential_n_e_im" : [ "float", [ "mo.num", "mo.num" ] ]
, "ecp_im" : [ "float", [ "mo.num", "mo.num" ] ]
, "core_hamiltonian_im" : [ "float", [ "mo.num", "mo.num" ] ]
} ,
"mo_2e_int": {
"eri" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ]
, "eri_lr" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ]
, "eri_cholesky_num" : [ "dim" , [] ]
, "eri_cholesky" : [ "float sparse", [ "mo_2e_int.eri_cholesky_num", "mo.num", "mo.num" ] ]
, "eri_lr_cholesky_num" : [ "dim" , [] ]
, "eri_lr_cholesky" : [ "float sparse", [ "mo_2e_int.eri_lr_cholesky_num", "mo.num", "mo.num" ] ]
} ,
"determinant": {
"num" : [ "dim readonly" , [] ]
, "list" : [ "int special" , [ "determinant.num" ] ]
, "coefficient" : [ "float buffered", [ "determinant.num" ] ]
} ,
"csf": {
"num" : [ "dim readonly" , [] ]
, "coefficient" : [ "float buffered", [ "csf.num" ] ]
, "det_coefficient" : [ "float sparse" , [ "csf.num", "determinant.num" ] ]
} ,
"amplitude": {
"single" : [ "float sparse", [ "mo.num", "mo.num" ] ]
, "single_exp" : [ "float sparse", [ "mo.num", "mo.num" ] ]
, "double" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ]
, "double_exp" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ]
, "triple" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num" ] ]
, "triple_exp" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num" ] ]
, "quadruple" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num" ] ]
, "quadruple_exp" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num" ] ]
} ,
"rdm": {
"1e" : [ "float" , [ "mo.num", "mo.num" ] ]
, "1e_up" : [ "float" , [ "mo.num", "mo.num" ] ]
, "1e_dn" : [ "float" , [ "mo.num", "mo.num" ] ]
, "2e" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ]
, "2e_upup" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ]
, "2e_dndn" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ]
, "2e_updn" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ]
, "2e_cholesky_num" : [ "dim" , [] ]
, "2e_cholesky" : [ "float sparse", [ "rdm.2e_cholesky_num", "mo.num", "mo.num" ] ]
, "2e_upup_cholesky_num" : [ "dim" , [] ]
, "2e_upup_cholesky" : [ "float sparse", [ "rdm.2e_upup_cholesky_num", "mo.num", "mo.num" ] ]
, "2e_dndn_cholesky_num" : [ "dim" , [] ]
, "2e_dndn_cholesky" : [ "float sparse", [ "rdm.2e_dndn_cholesky_num", "mo.num", "mo.num" ] ]
, "2e_updn_cholesky_num" : [ "dim" , [] ]
, "2e_updn_cholesky" : [ "float sparse", [ "rdm.2e_updn_cholesky_num", "mo.num", "mo.num" ] ]
} ,
"jastrow": {
"type" : [ "str" , [] ]
, "en_num" : [ "dim" , [] ]
, "ee_num" : [ "dim" , [] ]
, "een_num" : [ "dim" , [] ]
, "en" : [ "float" , [ "jastrow.en_num" ] ]
, "ee" : [ "float" , [ "jastrow.ee_num" ] ]
, "een" : [ "float" , [ "jastrow.een_num" ] ]
, "en_nucleus" : [ "index" , [ "jastrow.en_num" ] ]
, "een_nucleus" : [ "index" , [ "jastrow.een_num" ] ]
, "ee_scaling" : [ "float" , [] ]
, "en_scaling" : [ "float" , [ "nucleus.num" ] ]
} ,
"qmc": {
"num" : [ "dim" , [] ]
, "point" : [ "float", [ "qmc.num", "electron.num", "3" ] ]
, "psi" : [ "float", [ "qmc.num" ] ]
, "e_loc" : [ "float", [ "qmc.num" ] ]
}
}
*/
:end:
#+begin_src c :tangle prefix_front.h :noweb yes #+begin_src c :tangle prefix_front.h :noweb yes
<<header>> <<header>>
#ifndef TREXIO_H #ifndef TREXIO_H
@ -32,6 +284,7 @@ extern "C" {
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
<<trex_json()>>
typedef int32_t trexio_exit_code; typedef int32_t trexio_exit_code;
#+end_src #+end_src

View File

@ -1327,7 +1327,7 @@ power = [
#+name: jastrow #+name: jastrow
| Variable | Type | Dimensions | Description | | Variable | Type | Dimensions | Description |
|---------------+----------+---------------------+-----------------------------------------------------------------| |---------------+----------+---------------------+-----------------------------------------------------------------|
| ~type~ | ~string~ | | Type of Jastrow factor: ~CHAMP~ or ~Mu~ | | ~type~ | ~str~ | | Type of Jastrow factor: ~CHAMP~ or ~Mu~ |
| ~en_num~ | ~dim~ | | Number of Electron-nucleus parameters | | ~en_num~ | ~dim~ | | Number of Electron-nucleus parameters |
| ~ee_num~ | ~dim~ | | Number of Electron-electron parameters | | ~ee_num~ | ~dim~ | | Number of Electron-electron parameters |
| ~een_num~ | ~dim~ | | Number of Electron-electron-nucleus parameters | | ~een_num~ | ~dim~ | | Number of Electron-electron-nucleus parameters |
@ -1345,7 +1345,7 @@ power = [
:results: :results:
#+begin_src python :tangle trex.json #+begin_src python :tangle trex.json
"jastrow": { "jastrow": {
"type" : [ "string", [] ] "type" : [ "str" , [] ]
, "en_num" : [ "dim" , [] ] , "en_num" : [ "dim" , [] ]
, "ee_num" : [ "dim" , [] ] , "ee_num" : [ "dim" , [] ]
, "een_num" : [ "dim" , [] ] , "een_num" : [ "dim" , [] ]

8
version_memo.txt Normal file
View File

@ -0,0 +1,8 @@
To update the version, change:
- configure.ac
- CMakeLists.txt
- ocaml/trexio/trexio.opam
- python/pytrexio/_version.py
- rust/trexio/Cargo.toml