1
0
mirror of https://github.com/TREX-CoE/trexio.git synced 2024-08-25 06:31:43 +02:00

Merge pull request #56 from TREX-CoE/swig-python

TREXIO Python API
This commit is contained in:
Anthony Scemama 2021-09-14 11:39:17 +02:00 committed by GitHub
commit 55c2c052b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 5837 additions and 184 deletions

View File

@ -30,7 +30,19 @@ jobs:
- name: check TREXIO
run: make check
- name: create virtual environment
run: |
python3 -m venv --clear pytrexio-venv
source pytrexio-venv/bin/activate
- name: install Python API
run: make python-install
# alternatively we can also run pip install trexio to check PyPI installation
- name: check Python API
run: make python-test
- name: clean
run: make clean

6
.gitignore vendored
View File

@ -5,6 +5,11 @@
*/*.la
*/*.lo
aclocal.m4
m4/libtool.m4
m4/ltoptions.m4
m4/ltsugar.m4
m4/ltversion.m4
m4/lt~obsolete.m4
autom4te.cache/
compile
config.guess
@ -16,6 +21,7 @@ config.h.in
config.h
depcomp
include/config.h.in
include/config.h.in~
include/stamp-h1
install-sh
libtool

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "docs/org-html-themes"]
path = docs/org-html-themes
url = https://github.com:fniessen/org-html-themes.git
[submodule "python/examples"]
path = python/examples
url = git@github.com:TREX-CoE/trexio-tutorials.git

View File

@ -87,6 +87,8 @@ TESTS_C = \
tests/io_dset_float_text \
tests/io_dset_int_hdf5 \
tests/io_dset_int_text \
tests/io_safe_dset_float_hdf5 \
tests/io_safe_dset_float_text \
tests/io_str_hdf5 \
tests/io_str_text \
tests/io_dset_str_hdf5 \
@ -114,6 +116,8 @@ tests_io_dset_float_hdf5_LDFLAGS = -no-install
tests_io_dset_float_text_LDFLAGS = -no-install
tests_io_dset_int_hdf5_LDFLAGS = -no-install
tests_io_dset_int_text_LDFLAGS = -no-install
tests_io_safe_dset_float_hdf5_LDFLAGS = -no-install
tests_io_safe_dset_float_text_LDFLAGS = -no-install
tests_io_str_hdf5_LDFLAGS = -no-install
tests_io_str_text_LDFLAGS = -no-install
tests_io_dset_str_hdf5_LDFLAGS = -no-install
@ -133,7 +137,7 @@ tests_test_f_SOURCES = $(test_trexio_f) tests/test_f.f90
tests_test_f_LDFLAGS = -no-install
clean-local:
-rm -rf -- *.dir/ *.h5
-rm -rf -- *.dir/ *.h5 __pycache__/
# =============== DOCUMENTATION =============== #
@ -153,6 +157,11 @@ $(HTML_FILES): docs/index.html
# =============== DEVELOPER MODE =============== #
SWIG = @SWIG@
HDF5_LDFLAGS = @HDF5_LDFLAGS@
HDF5_CFLAGS = @HDF5_CFLAGS@
HDF5_CPPFLAGS = @HDF5_CPPFLAGS@
if TREXIO_DEVEL
CLEANFILES += $(SOURCES) $(trexio_f) $(trexio_h)
@ -179,7 +188,52 @@ cppcheck.out: $(trexio_h)
--language=c --std=c99 -rp --platform=unix64 \
-I../include *.c *.h 2>../$@
.PHONY: cppcheck
setup_py = $(srcdir)/python/setup.py
setup_cfg = $(srcdir)/python/setup.cfg
pytrexio_py = $(srcdir)/python/pytrexio/pytrexio.py
trexio_py = $(srcdir)/python/trexio.py
TEST_PY = python/test/test_api.py
pytrexio_c = $(srcdir)/src/pytrexio_wrap.c
pytrexio_i = $(srcdir)/src/pytrexio.i
numpy_i = $(srcdir)/src/numpy.i
python-test: $(TEST_PY)
python3 $(TEST_PY)
$(RM) -r -- __pycache__
python-install: $(pytrexio_py) $(setup_py) $(setup_cfg)
cd python && \
./install_pytrexio.sh $(HDF5_CFLAGS) $(HDF5_CPPFLAGS) $(HDF5_LDFLAGS)
python-sdist: $(pytrexio_py) $(setup_py) $(setup_cfg)
cd python && \
python setup.py sdist
$(pytrexio_py): $(pytrexio_c)
cd tools && ./prepare_python.sh
# Build Python module and C wrapper code for TREXIO using SWIG
# [?] swig -python -threads pytrexio.i ----> Add thread support for all the interface
$(pytrexio_c): $(ORG_FILES) $(trexio_h) $(pytrexio_i) $(numpy_i)
cp $(trexio_h) src/
cd src/ && \
$(SWIG) -python -py3 -o pytrexio_wrap.c pytrexio.i
$(RM) -- src/trexio.h
$(numpy_i):
wget https://raw.githubusercontent.com/numpy/numpy/main/tools/swig/numpy.i -O $(numpy_i)
check-numpy:
cd tools && ./check_numpy_i.sh
CLEANFILES += $(pytrexio_c) \
$(pytrexio_py) \
$(trexio_py) \
python/src/*.c \
python/src/*.h
.PHONY: cppcheck python-test python-install python-sdist check-numpy
endif

View File

@ -4,12 +4,12 @@
[![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)
TREX library fo efficient I/O.
TREX library for efficient I/O.
## Minimal requirements (for users):
- Autotools (autoconf, automake, libtool)
- Autotools (autoconf >= 2.69, automake >= 1.11, libtool >= 2.2)
- C compiler (gcc/icc/clang)
- Fortran compiler (gfortran/ifort)
- HDF5 library (>= 1.8)
@ -33,7 +33,7 @@ TREX library fo efficient I/O.
- python3 (>= 3.6)
- Emacs (>= 26.0)
- SWIG (>= 4.0)
## Installation procedure from the GitHub repo clone (for developers):
@ -56,7 +56,8 @@ The primary TREXIO API is composed of the following functions:
- `trexio_has_[group]_[variable]`
- `trexio_close`
where `[group]` and `[variable]` substitutions correspond to the contents of the `trex.json` configuration file (for more details, see the corresponding [documentation](https://trex-coe.github.io/trexio/trex.html) page).
where `[group]` and `[variable]` substitutions correspond to the contents of the `trex.json` configuration file
(for more details, see the corresponding [documentation](https://trex-coe.github.io/trexio/trex.html) page).
For example, consider the `coord` variable (array), which belongs to the `nucleus` group. The TREXIO user can write or read it using `trexio_write_nucleus_coord` or `trexio_read_nucleus_coord` functions, respectively.
Note: the `[variable]` names have to be unique only within the corresponding parent `[group]`.
@ -64,9 +65,20 @@ There is no naming conflict when, for example, `num` variable exists both in the
These quantities can be accessed using the corresponding `trexio_[has|read|write]_nucleus_num` and `trexio_[has|read|write]_mo_num`, respectively.
## Python API
For more details regarding the installation and usage of the TREXIO Python API,
see [this page](python/README.md).
## Tutorial
**TODO**
TREXIO tutorials in Jupyter notebook format can be found in the
[corresponding GitHub repository](https://github.com/TREX-CoE/trexio-tutorials)
or on [Binder](https://mybinder.org/v2/gh/TREX-CoE/trexio-tutorials/HEAD).
For example, the tutorial covering TREXIO basics using benzene molecule as an example can be viewed and executed online by clicking on this badge:
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/TREX-CoE/trexio-tutorials/HEAD?filepath=notebooks%2Ftutorial_benzene.ipynb)
## Technical documentation
@ -76,8 +88,9 @@ These quantities can be accessed using the corresponding `trexio_[has|read|write
### Miscellaneous
Note: The code should be compliant with the C99 [CERT C coding
standard](https://resources.sei.cmu.edu/downloads/secure-coding/assets/sei-cert-c-coding-standard-2016-v01.pdf). This can be checked with the `cppcheck` tool.
Note: The code should be compliant with the C99
[CERT C coding standard](https://resources.sei.cmu.edu/downloads/secure-coding/assets/sei-cert-c-coding-standard-2016-v01.pdf).
This can be checked with the `cppcheck` tool.

View File

@ -50,6 +50,7 @@ AC_FC_LIBRARY_LDFLAGS
# pkg-config
PKG_PROG_PKG_CONFIG()
PKG_CFLAGS=""
PKG_LIBS=""
AC_PROG_INSTALL
AC_PROG_LIBTOOL
@ -94,18 +95,29 @@ CPPFLAGS="${HDF5_CPPFLAGS} ${CPPFLAGS}"
LDFLAGS="${HDF5_LDFLAGS} ${LDFLAGS}"
LIBS="${HDF5_LIBS} ${LIBS}"
# Check if HDF5 if available with pkg-config
# Check if HDF5 is available with pkg-config.
PKG_CHECK_MODULES([HDF5], [hdf5 >= 1.8], [
PKG_HDF5="hdf5"
],[
PKG_HDF5=""
])
PKG_CFLAGS="${PKG_CFLAGS}"
PKG_CFLAGS="${HDF5_CFLAGS}"
PKG_LIBS="${HDF5_LIBS}"
AC_SUBST([PKG_HDF5])
AC_SUBST([PKG_CFLAGS])
AC_SUBST([PKG_LIBS])
# The block below should only execute if the ax_lib_hdf5.m4 macro failed to find HDF5.
# It is only needed to manually build Python API because setup.py depends on HDF5.
if test "$HDF5_LDFLAGS" = "" || "$HDF5_CFLAGS" = ""; then
HDF5_LDFLAGS="${PKG_LIBS}"
HDF5_CFLAGS="${PKG_CFLAGS}"
AC_SUBST([HDF5_CFLAGS])
AC_SUBST([HDF5_LDFLAGS])
fi
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_INT32_T
@ -126,6 +138,10 @@ if test "x${TREXIO_DEVEL}" != "x"; then
AC_PROG_AWK
AM_PATH_PYTHON([3.0])
AX_PKG_SWIG(4.0.0, [], AC_MSG_WARN([SWIG is required to build Python API.]) )
# The macro below performs Python benchmarks, but overlapping with AM_PATH_PYTHON
#AX_SWIG_PYTHON
AC_CHECK_PROGS([EMACS],[emacs26 emacs],[no])
if test x${EMACS} == xno ; then
AC_MSG_ERROR([

2
docker/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
tmp*
trexio-*

45
docker/README Normal file
View File

@ -0,0 +1,45 @@
First, make sure to place the source code distribution (suffixed with .tar.gz) of the TREXIO Python API in this directory.
TODO: the scripts have to be adapted for an arbitrary version of TREXIO and Python !
Outside Docker image:
# Build containers with hdf5 inside:
# for manylinux2014_x86_64
sudo docker build -t hdf5_1_12_on_2014_x86_64 . -f Dockerfile_2014_x86_64
# for manylinux_2_24_x86_64
sudo docker build -t hdf5_1_12_on_2_24_x86_64 . -f Dockerfile_2_24_x86_64
# (create an image using HDF5 containers, see https://github.com/h5py/hdf5-manylinux)
# -t hdf5_1_12_on_${PLATFORM} builds an image with a custom name (hdf5_1_12_1)
# Run one of the produced containers in the interactive mode
# for manylinux2014_x86_64
sudo docker run --rm -it -e PLAT=manylinux2014_x86_64 -v `pwd`:/tmp hdf5_1_12_on_2014_x86_64 /bin/bash
# for manylinux_2_24_x86_64
sudo docker run --rm -it -e PLAT=manylinux_2_24_x86_64 -v `pwd`:/tmp hdf5_1_12_on_2_24_x86_64 /bin/bash
#(PLAT specifies the base platform tag for manilinux)
#-i (run docker container interactively)
#-t f8e4232fa208 (run an image using ID if the image is not named)
#/bin/bash (a binary to run inside a container environment)
In the Docker image:
cd tmp && ./build_manylinux_wheels_py_36_37_38.sh
# (creates virtual environments, installs things with pip, produces conventional wheels and repairs them with auditwheel)
# auditwheel repair trexio-0.1.0/dist/trexio-0.1.0-cp37-cp37m-linux_x86_64.whl
# (repairs wheel and produces manylinux one)
After Docker container execution:
# the produced manylinux wheels are in trexio-0.1.0/wheelhouse directory
# ALTERNATIVELY: one can copy the produced manylinux wheel from the container back to the host system
sudo docker cp $CONTAINER_ID:/tmp/trexio-0.1.0/wheelhouse/MANYLINUX_NAME.whl directory-on-the-user-machine/

View File

@ -0,0 +1,188 @@
#!/bin/bash
set -x
set -e
export H5_LDFLAGS=-L/usr/local/lib
export H5_CFLAGS=-I/usr/local/include
# install emacs for Debian
#apt-get update
#apt install software-properties-common -y
#apt-get install wget -y
#wget -q http://emacs.ganneff.de/apt.key -O- | apt-key add
#add-apt-repository "deb http://emacs.ganneff.de/ stretch main"
#apt-get update
#apt-get install emacs-snapshot -y
#update-alternatives --config emacsclient
# ===============================
# install TREXIO in the container from the GitHub repo clone
#apt-get install git -y
#git clone https://github.com/TREX-CoE/trexio.git
#cd trexio
#git checkout swig-python
#./autogen.sh
#TREXIO_DEVEL=1 ./configure --enable-silent-rules
#make
#make check
# ===============================
# alternatively: build wheel directly from developer-provided .tar.gz of TREXIO (generated with `python setup.py sdist`)
# note: trexio-VERSION.tar.gz has to be in the root directory of the host machine
# process input: first argument is the name of the .tar.gz with the source code of the Python API
if [[ -z "$1" ]]; then
echo "Please specify the name of the TREXIO source code distribution (with .tar.gz suffix)"
exit 1
fi
TREXIO_SOURCE=${1}
# remove prefix that ends with "-"
tmp=${TREXIO_SOURCE#*-}
# remove suffix that ends with ".tar.gz"
TR_VERSION=${tmp%.tar.gz*}
echo "TREXIO VERSION:" ${TR_VERSION}
# unzip and enter the folder with TREXIO Python API
gzip -cd /tmp/trexio-${TR_VERSION}.tar.gz | tar xvf -
cd trexio-${TR_VERSION}
# create and activate a virtual environment based on CPython version 3.6
/opt/python/cp36-cp36m/bin/python3 -m venv --clear trexio-manylinux-py36
source trexio-manylinux-py36/bin/activate
python3 --version
# upgrade pip, otherwise it complains that manylinux wheel is "...not supported wheel on this platform"
pip install --upgrade pip
# install dependencies needed to build manylinux wheel
pip install --upgrade setuptools wheel auditwheel numpy
# set an environment variable needed to locate numpy header files
source tools/set_NUMPY_INCLUDEDIR.sh
# produce conventional (non-manylinux) wheel
python3 setup.py bdist_wheel
# use auditwheel from PyPA to repair all wheels and make them manylinux-compatible
auditwheel repair dist/trexio-${TR_VERSION}-cp36-cp36m-*.whl
# install the produced manylinux wheel in the virtual environment
python3 -m pip install wheelhouse/trexio-${TR_VERSION}-cp36-cp36m-manylinux*.whl
# run test script
cd test && python3 test_api.py && cd ..
# cleaning
rm -rf -- dist/ build/ trexio.egg-info/
# deactivate the current environment
deactivate
# create and activate a virtual environment based on CPython version 3.7
/opt/python/cp37-cp37m/bin/python3 -m venv --clear trexio-manylinux-py37
source trexio-manylinux-py37/bin/activate
python3 --version
# upgrade pip, otherwise it complains that manylinux wheel is "...not supported wheel on this platform"
pip install --upgrade pip
# install dependencies needed to build manylinux wheel
pip install --upgrade setuptools wheel auditwheel numpy
# set an environment variable needed to locate numpy header files
source tools/set_NUMPY_INCLUDEDIR.sh
# produce conventional (non-manylinux) wheel
python3 setup.py bdist_wheel
# use auditwheel from PyPA to repair all wheels and make them manylinux-compatible
auditwheel repair dist/trexio-${TR_VERSION}-cp37-cp37m-*.whl
# install the produced manylinux wheel in the virtual environment
python3 -m pip install wheelhouse/trexio-${TR_VERSION}-cp37-cp37m-manylinux*.whl
# run test script
cd test && python3 test_api.py && cd ..
# cleaning
rm -rf -- dist/ build/ trexio.egg-info/
# deactivate the current environment
deactivate
# create and activate a virtual environment based on CPython version 3.8
# NOTE: starting from CPython 3.8 there is no need to add m in the abi-tag, e.g. use cp38-cp38 instead of cp38-cp38m
/opt/python/cp38-cp38/bin/python3 -m venv --clear trexio-manylinux-py38
source trexio-manylinux-py38/bin/activate
python3 --version
# upgrade pip, otherwise it complains that manylinux wheel is "...not supported wheel on this platform"
pip install --upgrade pip
# install dependencies needed to build manylinux wheel
pip3 install --upgrade setuptools wheel auditwheel numpy
# set an environment variable needed to locate numpy header files
source tools/set_NUMPY_INCLUDEDIR.sh
# produce conventional (non-manylinux) wheel
python3 setup.py bdist_wheel
# use auditwheel from PyPA to repair all wheels and make them manylinux-compatible
auditwheel repair dist/trexio-${TR_VERSION}-cp38-cp38-*.whl
# install the produced manylinux wheel in the virtual environment
python3 -m pip install wheelhouse/trexio-${TR_VERSION}-cp38-cp38-manylinux*.whl
# run test script
cd test && python3 test_api.py && cd ..
# cleaning
rm -rf -- dist/ build/ trexio.egg-info/
# deactivate the current environment
deactivate
# create and activate a virtual environment based on CPython version 3.8
/opt/python/cp39-cp39/bin/python3 -m venv --clear trexio-manylinux-py39
source trexio-manylinux-py39/bin/activate
python3 --version
# upgrade pip, otherwise it complains that manylinux wheel is "...not supported wheel on this platform"
pip install --upgrade pip
# install dependencies needed to build manylinux wheel
pip3 install --upgrade setuptools wheel auditwheel numpy
# produce conventional (non-manylinux) wheel
python3 setup.py bdist_wheel
# use auditwheel from PyPA to repair all wheels and make them manylinux-compatible
auditwheel repair dist/trexio-${TR_VERSION}-cp39-cp39-*.whl
# install the produced manylinux wheel in the virtual environment
python3 -m pip install wheelhouse/trexio-${TR_VERSION}-cp39-cp39-manylinux*.whl
# run test script
cd test && python3 test_api.py && cd ..
# cleaning
rm -rf -- dist/ build/ trexio.egg-info/
# deactivate the current environment
deactivate
# remove all virtual environments used to produce the wheels
rm -rf -- trexio-manylinux-py39 \
trexio-manylinux-py38 \
trexio-manylinux-py37 \
trexio-manylinux-py36

139
m4/ax_pkg_swig.m4 Normal file
View File

@ -0,0 +1,139 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PKG_SWIG([major.minor.micro], [action-if-found], [action-if-not-found])
#
# DESCRIPTION
#
# This macro searches for a SWIG installation on your system. If found,
# then SWIG is AC_SUBST'd; if not found, then $SWIG is empty. If SWIG is
# found, then SWIG_LIB is set to the SWIG library path, and AC_SUBST'd.
#
# You can use the optional first argument to check if the version of the
# available SWIG is greater than or equal to the value of the argument. It
# should have the format: N[.N[.N]] (N is a number between 0 and 999. Only
# the first N is mandatory.) If the version argument is given (e.g.
# 1.3.17), AX_PKG_SWIG checks that the swig package is this version number
# or higher.
#
# As usual, action-if-found is executed if SWIG is found, otherwise
# action-if-not-found is executed.
#
# In configure.in, use as:
#
# AX_PKG_SWIG(1.3.17, [], [ AC_MSG_ERROR([SWIG is required to build..]) ])
# AX_SWIG_ENABLE_CXX
# AX_SWIG_MULTI_MODULE_SUPPORT
# AX_SWIG_PYTHON
#
# LICENSE
#
# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
# Copyright (c) 2008 Alan W. Irwin
# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
# Copyright (c) 2008 Andrew Collier
# Copyright (c) 2011 Murray Cumming <murrayc@openismus.com>
# Copyright (c) 2021 Vincent Danjean <Vincent.Danjean@ens-lyon.org>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 14
AC_DEFUN([AX_PKG_SWIG],[
# Find path to the "swig" executable.
AC_PATH_PROGS([SWIG],[swig swig3.0 swig2.0])
if test -z "$SWIG" ; then
m4_ifval([$3],[$3],[:])
elif test -z "$1" ; then
m4_ifval([$2],[$2],[:])
else
AC_MSG_CHECKING([SWIG version])
[swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
AC_MSG_RESULT([$swig_version])
if test -n "$swig_version" ; then
# Calculate the required version number components
[required=$1]
[required_major=`echo $required | sed 's/[^0-9].*//'`]
if test -z "$required_major" ; then
[required_major=0]
fi
[required=`echo $required. | sed 's/[0-9]*[^0-9]//'`]
[required_minor=`echo $required | sed 's/[^0-9].*//'`]
if test -z "$required_minor" ; then
[required_minor=0]
fi
[required=`echo $required. | sed 's/[0-9]*[^0-9]//'`]
[required_patch=`echo $required | sed 's/[^0-9].*//'`]
if test -z "$required_patch" ; then
[required_patch=0]
fi
# Calculate the available version number components
[available=$swig_version]
[available_major=`echo $available | sed 's/[^0-9].*//'`]
if test -z "$available_major" ; then
[available_major=0]
fi
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
[available_minor=`echo $available | sed 's/[^0-9].*//'`]
if test -z "$available_minor" ; then
[available_minor=0]
fi
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
[available_patch=`echo $available | sed 's/[^0-9].*//'`]
if test -z "$available_patch" ; then
[available_patch=0]
fi
# Convert the version tuple into a single number for easier comparison.
# Using base 100 should be safe since SWIG internally uses BCD values
# to encode its version number.
required_swig_vernum=`expr $required_major \* 10000 \
\+ $required_minor \* 100 \+ $required_patch`
available_swig_vernum=`expr $available_major \* 10000 \
\+ $available_minor \* 100 \+ $available_patch`
if test $available_swig_vernum -lt $required_swig_vernum; then
AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version.])
SWIG=''
m4_ifval([$3],[$3],[])
else
AC_MSG_CHECKING([for SWIG library])
SWIG_LIB=`$SWIG -swiglib`
AC_MSG_RESULT([$SWIG_LIB])
m4_ifval([$2],[$2],[])
fi
else
AC_MSG_WARN([cannot determine SWIG version])
SWIG=''
m4_ifval([$3],[$3],[])
fi
fi
AC_SUBST([SWIG_LIB])
])

8
python/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
AUTHORS
LICENSE
src/
build/
dist/
*.egg-info/
__pycache__/

9
python/MANIFEST.in Normal file
View File

@ -0,0 +1,9 @@
include src/*.c
include src/trexio*.h
include examples/notebooks/*
include examples/README.md
include requirements.txt tools/set_NUMPY_INCLUDEDIR.sh
exclude examples/LICENSE
exclude examples/requirements.txt
exclude examples/runtime.txt

97
python/README.md Normal file
View File

@ -0,0 +1,97 @@
# TREXIO Python API
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/TREX-CoE/trexio-tutorials/HEAD)
TREXIO provides a Python API, which enables interactive calls to the library.
It facilitates the development of interfaces between different codes and
can be used to convert data from one input/output file format into another.
## Requirements
- python3 (>= 3.6)
- numpy
- C compiler (gcc/icc)
## Installation from PyPI
In short, you can run the following command:
`pip install trexio`
However, it is good practice to first check for updates of the build-system packages. This can be achieved by running
`python3 -m pip install --upgrade pip setuptools wheel`
**Note: we highly recommend to use virtual environments to avoid compatibility issues and to improve reproducibility.**
For more details, see the corresponding part of the [Python documentation](https://docs.python.org/3/library/venv.html#creating-virtual-environments).
## Additional requirements (for installation from source)
- HDF5 library (>= 1.8)
- pkgconfig (Python package)
## Installation from source
1. Download the `trexio-<version>.tar.gz` file with the latest Python API
2. `gzip -cd trexio-<version>.tar.gz | tar xvf -`
3. `cd trexio-<version>`
4. `pip3 install -r requirements.txt` (this installs all required python dependencies)
5. Export custom environment variables needed for the installation following the procedure below and replacing `/path/to/hdf5/` with your paths.
Steps (i) and (ii) can be skipped if HDF5 is properly configured for `pkg-config` (i.e. if executing `pkg-config --libs hdf5` returns a list of options).
1. `export H5_CFLAGS=-I/path/to/hdf5/include`
2. `export H5_LDFLAGS=-L/path/to/hdf5/lib`
3. `source tools/set_NUMPY_INCLUDEDIR.sh`
6. `pip3 install .` (this installs `trexio` in your environment)
7. `cd test && python3 test_api.py` (this executes several tests that verify the installation)
You are ready to go!
**Note:**
installation based on `pip` compiles its own C extension (shared library) called `pytrexio`.
This extension is built from the TREXIO source files coupled to the wrapper code generated by [SWIG](http://www.swig.org/).
The compiler options during this installation may differ from the ones used to compile the primary TREXIO API in C.
Furthermore, custom compiler flags provided to `./configure` or `make` are not applied to the Python API.
## Examples
An interactive Jupyter notebook called `tutorial_benzene.ipynb` is provided in the `examples` directory.
The notebook can be lauched either locally (see [next section](#Running-the-notebook) for details) or using [pre-built environment on Binder](https://mybinder.org/v2/gh/TREX-CoE/trexio-tutorials/HEAD?filepath=notebooks%2Ftutorial_benzene.ipynb).
Jupyter can be installed using `pip install jupyter`. If you are not familiar with it, feel free to consult the [Jupyter documentation](https://jupyter-notebook.readthedocs.io/en/stable/notebook.html).
### Running the notebook
The example notebook can be launched using the following command:
`jupyter notebook tutorial_benzene.ipynb`
### Additional steps needed to run a custom virtual environment in Jupyter notebooks
In some cases, it may happen that the Jupyter kernels in the activated virtual environment (e.g. `myvenv`) still point to the system-wide python binaries and not to the environment ones.
This will result in `ImportError` when importing `trexio` in the notebook cell. In order to avoid this, the `myvenv` has to be installed as an additional kernel.
This requires `ipykernel` python package, which usually comes together with the Jupyter installation. If this is not the case, run `pip install ipykernel`.
You can install `myvenv` as a kernel by executing the following command:
`python3 -m ipykernel install --user --name=myvenv`
Now you can launch a Jupyter notebook. Once it is open, make sure that your virtual environment is selected as the current kernel.
If this is not the case, try this:
1. Press the `Kernel` button in the navigation panel
2. In the output list of options select `Change kernel`
3. Find the name of your virtual environment (e.g. `myvenv`) in the list and select it
That's it, you have activated the custom virtual environment called `myvenv` in your notebook.
To uninstall the kernel named `myvenv`, execute the following command:
`jupyter kernelspec uninstall myvenv`

1
python/examples Submodule

@ -0,0 +1 @@
Subproject commit b631619698a4b608a8778c75a9a359731bfa682a

77
python/install_pytrexio.sh Executable file
View File

@ -0,0 +1,77 @@
#!/bin/bash
set -x
set -e
# the parser below is needed when ./configure outputs several HDF5-related flags, which are then provided as input arguments to this script
for arg in "$@"
do
if [[ $arg == "-L"* ]] && [[ $arg == *"hdf5"* ]]; then
H5_LDFLAGS_LOCAL=$arg
elif [[ $arg == "-I"* ]] && [[ $arg == *"hdf5"* ]]; then
H5_CFLAGS_LOCAL=$arg
fi
done
# check that both variables are set
if [[ -z ${H5_LDFLAGS_LOCAL} ]] || [[ -z ${H5_CFLAGS_LOCAL} ]]; then
if [[ -z ${H5_LDFLAGS} ]] || [[ -z ${H5_CFLAGS} ]]; then
echo "Paths to the HDF5 installation are not provided. pkgconfig will try to detect them."
else
echo "Using exported H5_LDFLAGS and H5_CFLAGS environment variables."
fi
else
export H5_LDFLAGS=${H5_LDFLAGS_LOCAL}
export H5_CFLAGS=${H5_CFLAGS_LOCAL}
fi
# Install/upgrade packages required for the installation
python3 -m pip install --upgrade setuptools wheel twine
python3 -m pip install -r requirements.txt
# export NUMPY_INCLUDEDIR environment variable needed for the proper setup
source tools/set_NUMPY_INCLUDEDIR.sh
if [[ -z ${NUMPY_INCLUDEDIR} ]] ; then
echo "NUMPY_INCLUDEDIR is not set. Check that numpy is installed (e.g. call pip freeze)."
exit 1
fi
# Create build directory and compile extension files (*.c)
# --no-user-cfg disables custom .cfg files of the user machine, so that only setup.cfg is used
python3 -s setup.py --no-user-cfg build
# Local inplace build of the .so module with SWIG-produced pytrexio_wrap.c (from the SWIG documentation)
#python3 setup.py build_ext --inplace --swig-opts="-modern"
# Create distributions:
# 1) sdist produces .tar.gz with all files necessary for manual compilation;
# 2) bdist_whell produces .whl wheel distribution (see https://www.python.org/dev/peps/pep-0425/).
python3 setup.py sdist bdist_wheel
# Install pytrexio in the current environment from the aforementioned wheel
# --force-reinstall is needed here because build-system pre-installs pytrexio in the environment
# but does not install things in the corresponding site-packages directory
python3 -m pip install dist/trexio-*.whl --force-reinstall
# Run the command below in the root directory to install the package in 'editable' (-e) mode without dependencies (--no-deps)
#python -m pip install -e . --no-deps
# Uninstall pytrexio: this only works from the pytrexio root directory
#python3 -m pip uninstall trexio
# Test the current release by uploading to TestPyPI sandbox
#python3 -m twine upload --repository testpypi dist/trexio-*.tar.gz
# Upload updated version of PyTREXIO to PyPI
#python3 -m twine upload dist/trexio-*.tar.gz
# Cleaning
rm -rf build dist trexio.egg-info
# Additional information related to the installation of the TREXIO Python API
#Removing MANIFEST.in leads to issues in the installation. In particular, the .c and .h source files do not get copied
#from the src/ directory into the tar.gz which is produced by setup sdist command.
#These source files are required to build the pytrexio.so extension module, which is needed for the Python API.

7
python/pyproject.toml Normal file
View File

@ -0,0 +1,7 @@
[build-system]
requires = [
"setuptools>=42",
"wheel",
"pkgconfig"
]
build-backend = "setuptools.build_meta"

View File

@ -0,0 +1 @@
#from ._version import __version__

View File

@ -0,0 +1 @@
__version__ = "0.1.0"

3
python/requirements.txt Normal file
View File

@ -0,0 +1,3 @@
setuptools>=42
pkgconfig
numpy

11
python/setup.cfg Normal file
View File

@ -0,0 +1,11 @@
[metadata]
long_description = file: README.md
licence_file = LICENSE
project_urls =
Bug Tracker = https://github.com/TREX-CoE/trexio/issues
license = BSD 3-Clause License
[options]
zip_safe = False
python_requires = >=3.6

119
python/setup.py Normal file
View File

@ -0,0 +1,119 @@
#!/usr/bin/env python3
"""
setup.py file for TREXIO Python package
"""
import os
from setuptools import setup, Extension
# this was recommended to solve the problem of the missing numpy header files
# bit it causes `pip install .` to fail with numpy module not found error
#try:
# import numpy
#except ImportError:
# raise Exception("numpy Python package cannot be imported.")
#numpy_includedir = numpy.get_include()
# this does not cause aforementioned issue but the includedir points to system-wide numpy and not to venv-wide
#from distutils.sysconfig import get_python_inc
#numpy_includedir = os.path.join(get_python_inc(plat_specific=1), 'numpy')
# dirty workaround: get numpy includedir from the environment variable that can be pre-set using set_NUMPY_INCLUDEDIR.sh
numpy_includedir = os.environ.get("NUMPY_INCLUDEDIR", None)
numpy_isUndefined = numpy_includedir is None or numpy_includedir==""
if numpy_isUndefined:
raise Exception("NUMPY_INCLUDEDIR environment variable is not specified. Please do it manually or execute set_NUMPY_INCLUDEDIR.sh script.")
rootpath = os.path.dirname(os.path.abspath(__file__))
srcpath = os.path.join(rootpath, 'src')
c_files = ['trexio.c', 'trexio_hdf5.c', 'trexio_text.c', 'pytrexio_wrap.c']
with open("README.md", "r") as fh:
long_description = fh.read()
VERSIONFILE = "pytrexio/_version.py"
try:
exec(open(VERSIONFILE).read())
except:
raise IOError("Could not open the version file %s." % (VERSIONFILE, ))
version_r = __version__
if not version_r:
raise RuntimeError("Unable to find a version string in %s." % (VERSIONFILE, ))
# =========================== Start of the HDF5 block =========================== #
# The block below is needed to derive additional flags related to the HDF5 library,
# which is required to build pytrexio extension module during the setup.py execution
h5_ldflags_withl = os.environ.get("H5_LDFLAGS", None)
h5_cflags_withI = os.environ.get("H5_CFLAGS", None)
h5_ldflags_isUndefined = h5_ldflags_withl is None or h5_ldflags_withl==""
h5_cflags_isUndefined = h5_cflags_withI is None or h5_cflags_withI==""
if h5_ldflags_isUndefined or h5_cflags_isUndefined:
try:
import pkgconfig as pk
except ImportError:
raise Exception("pkgconfig Python package cannot be imported.")
try:
assert pk.exists('hdf5')
except AssertionError:
raise Exception("pkg-config could not locate HDF5")
h5_cflags_withI = pk.cflags('hdf5')
h5_ldflags_withl = pk.libs('hdf5')
h5_cflags = h5_cflags_withI.replace("-I","").split(" ")[0]
h5_ldflags = h5_ldflags_withl.split(" ")[0]
# ============================ End of the HDF5 block ============================ #
# Define pytrexio extension module based on TREXIO source codes + SWIG-generated wrapper
pytrexio_module = Extension('pytrexio._pytrexio',
sources = [os.path.join(srcpath, code) for code in c_files],
include_dirs = [h5_cflags, srcpath, numpy_includedir],
libraries = ['hdf5', 'hdf5_hl'],
extra_compile_args = ['-Wno-discarded-qualifiers'],
extra_link_args = [h5_ldflags]
)
setup(name = 'trexio',
version = version_r,
author = "TREX-CoE",
author_email = "posenitskiy@irsamc.ups-tlse.fr",
description = """Python API of the TREXIO library""",
long_description = long_description,
long_description_content_type = "text/markdown",
ext_modules = [pytrexio_module],
py_modules = ['trexio'],
packages = ['pytrexio'],
url = 'https://github.com/TREX-CoE/trexio',
license = 'BSD',
classifiers=[
"Intended Audience :: Science/Research",
"Intended Audience :: Developers",
"Topic :: Scientific/Engineering",
"Programming Language :: C",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: Implementation :: CPython",
"License :: OSI Approved :: BSD License",
"Operating System :: POSIX",
"Operating System :: Unix",
"Operating System :: MacOS"
],
python_requires = ">=3.6",
setup_requires = ['numpy', 'pkgconfig'],
install_requires = ['numpy']
)

217
python/test/test_api.py Normal file
View File

@ -0,0 +1,217 @@
#!/usr/bin/env python3
import os
import shutil
import numpy as np
import trexio
#=========================================================#
#======== SETUP THE BACK END AND OUTPUT FILE NAME ========#
#=========================================================#
# 0: TREXIO_HDF5 ; 1: TREXIO_TEXT
TEST_TREXIO_BACKEND = 0
OUTPUT_FILENAME_TEXT = 'test_py_swig.dir'
OUTPUT_FILENAME_HDF5 = 'test_py_swig.h5'
# define TREXIO file name
if TEST_TREXIO_BACKEND == trexio.TREXIO_HDF5:
output_filename = OUTPUT_FILENAME_HDF5
elif TEST_TREXIO_BACKEND == trexio.TREXIO_TEXT:
output_filename = OUTPUT_FILENAME_TEXT
else:
raise ValueError ('Specify one of the supported back ends as TEST_TREXIO_BACKEND')
# remove TREXIO file if exists in the current directory
try:
if TEST_TREXIO_BACKEND == trexio.TREXIO_HDF5:
os.remove(output_filename)
elif TEST_TREXIO_BACKEND == trexio.TREXIO_TEXT:
shutil.rmtree(output_filename)
except:
print ('Nothing to remove.')
#=========================================================#
#============ WRITE THE DATA IN THE TEST FILE ============#
#=========================================================#
# create TREXIO file and open it for writing
test_file = trexio.File(output_filename, mode='w', back_end=TEST_TREXIO_BACKEND)
# Print docstring of the trexio.open function
#print(trexio.open.__doc__)
nucleus_num = 12
try:
trexio.write_nucleus_num(test_file, -100)
except trexio.Error:
print("Writing negative nucleus_num: checked.")
# write nucleus_num in the file
try:
trexio.write_nucleus_num(test_file, nucleus_num)
except:
raise
try:
trexio.write_nucleus_num(test_file, nucleus_num*2)
except trexio.Error:
print("Attempt to overwrite nucleus_num: checked.")
# initialize charge arrays as a list and convert it to numpy array
charges = [6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.]
#charges_np = np.array(charges, dtype=np.float32)
charges_np = np.array(charges, dtype=np.int32)
# function call below works with both lists and numpy arrays, dimension needed for memory-safety is derived
# from the size of the list/array by SWIG using typemaps from numpy.i
trexio.write_nucleus_charge(test_file, charges_np)
# initialize arrays of nuclear indices as a list and convert it to numpy array
indices = [i for i in range(nucleus_num)]
# type cast is important here because by default numpy transforms a list of integers into int64 array
indices_np = np.array(indices, dtype=np.int64)
# function call below works with both lists and numpy arrays, dimension needed for memory-safety is derived
# from the size of the list/array by SWIG using typemacs from numpy.i
trexio.write_basis_nucleus_index(test_file, indices_np)
# initialize a list of nuclear coordinates
coords = [
[ 0.00000000 , 1.39250319 , 0.00000000 ],
[-1.20594314 , 0.69625160 , 0.00000000 ],
[-1.20594314 , -0.69625160 , 0.00000000 ],
[ 0.00000000 , -1.39250319 , 0.00000000 ],
[ 1.20594314 , -0.69625160 , 0.00000000 ],
[ 1.20594314 , 0.69625160 , 0.00000000 ],
[-2.14171677 , 1.23652075 , 0.00000000 ],
[-2.14171677 , -1.23652075 , 0.00000000 ],
[ 0.00000000 , -2.47304151 , 0.00000000 ],
[ 2.14171677 , -1.23652075 , 0.00000000 ],
[ 2.14171677 , 1.23652075 , 0.00000000 ],
[ 0.00000000 , 2.47304151 , 0.00000000 ],
]
# write coordinates in the file
trexio.write_nucleus_coord(test_file, coords)
point_group = 'B3U'
# write nucleus_point_group in the file
trexio.write_nucleus_point_group(test_file, point_group)
labels = [
'C',
'C',
'C',
'C',
'C',
'C',
'H',
'H',
'H',
'H',
'H',
'H']
# write nucleus_label in the file
trexio.write_nucleus_label(test_file,labels)
# close TREXIO file
# this call is no longer needed as we introduced TREXIO_File class which has a desctructor that closes the file
#trexio.close(test_file)
# without calling destructor on test_file the TREXIO_FILE is not getting created and the data is not written when using TEXT back end.
# This, the user still has to explicitly call destructor on test_file object instead of the trexio.close function.
# This is only an issue when the data is getting written and read in the same session (e.g. in Jupyter notebook)
del test_file
#==========================================================#
#============ READ THE DATA FROM THE TEST FILE ============#
#==========================================================#
# open previously created TREXIO file, now in 'read' mode
test_file2 = trexio.File(output_filename, 'r', TEST_TREXIO_BACKEND)
# check for existence of some of the previously written variables
assert trexio.has_nucleus_num
assert trexio.has_nucleus_charge
assert trexio.has_nucleus_coord
assert trexio.has_nucleus_label
assert trexio.has_nucleus_point_group
# read nucleus_num from file
rnum = trexio.read_nucleus_num(test_file2)
assert rnum==nucleus_num
# safe call to read_nucleus_charge array of float values
rcharges_np = trexio.read_nucleus_charge(test_file2, dim=nucleus_num)
assert rcharges_np.dtype is np.dtype(np.float64)
np.testing.assert_array_almost_equal(rcharges_np, charges_np, decimal=8)
# unsafe call to read_safe should fail with error message corresponding to TREXIO_UNSAFE_ARRAY_DIM
try:
rcharges_fail = trexio.read_nucleus_charge(test_file2, dim=nucleus_num*5)
except trexio.Error:
print("Unsafe call to safe API: checked")
# safe call to read array of int values (nuclear indices)
rindices_np_16 = trexio.read_basis_nucleus_index(test_file2, dim=nucleus_num, dtype=np.int16)
assert rindices_np_16.dtype is np.dtype(np.int16)
for i in range(nucleus_num):
assert rindices_np_16[i]==indices_np[i]
rindices_np_32 = trexio.read_basis_nucleus_index(test_file2, dim=nucleus_num, dtype=np.int32)
assert rindices_np_32.dtype is np.dtype(np.int32)
for i in range(nucleus_num):
assert rindices_np_32[i]==indices_np[i]
rindices_np_64 = trexio.read_basis_nucleus_index(test_file2)
assert rindices_np_64.dtype is np.dtype(np.int64)
assert rindices_np_64.size==nucleus_num
for i in range(nucleus_num):
assert rindices_np_64[i]==indices_np[i]
# read nuclear coordinates without providing optional argument dim
rcoords_np = trexio.read_nucleus_coord(test_file2)
assert rcoords_np.size==nucleus_num*3
np.testing.assert_array_almost_equal(rcoords_np, np.array(coords).reshape(nucleus_num,3), decimal=8)
# set doReshape to False to get a flat 1D array (e.g. when reading matrices like nuclear coordinates)
#rcoords_reshaped_2 = trexio.read_nucleus_coord(test_file2, doReshape=False)
# read array of nuclear labels
rlabels_2d = trexio.read_nucleus_label(test_file2, dim=nucleus_num)
print(rlabels_2d)
for i in range(nucleus_num):
assert rlabels_2d[i]==labels[i]
# read a string corresponding to nuclear point group
rpoint_group = trexio.read_nucleus_point_group(test_file2)
assert rpoint_group==point_group
# another way to read only if the variable exists
if trexio.has_mo_num(test_file2):
rmo_num = trexio.read_mo_num(test_file2)
else:
print("Not reading the non-existing variable mo_num.")
# close TREXIO file
#trexio.close(test_file2)
# cleaning (remove the TREXIO file)
try:
if TEST_TREXIO_BACKEND == trexio.TREXIO_HDF5:
os.remove(output_filename)
elif TEST_TREXIO_BACKEND == trexio.TREXIO_TEXT:
shutil.rmtree(output_filename)
except:
print (f'No output file {output_filename} has been produced')
#==========================================================#

View File

@ -0,0 +1,160 @@
import os
import shutil
import numpy as np
from pytrexio.pytrexio import *
#=========================================================#
#======== SETUP THE BACK END AND OUTPUT FILE NAME ========#
#=========================================================#
# 0: TREXIO_HDF5 ; 1: TREXIO_TEXT
TEST_TREXIO_BACKEND = 1
OUTPUT_FILENAME_TEXT = 'test_py_swig.dir'
OUTPUT_FILENAME_HDF5 = 'test_py_swig.h5'
if TEST_TREXIO_BACKEND == 0:
output_filename = OUTPUT_FILENAME_HDF5
elif TEST_TREXIO_BACKEND == 1:
output_filename = OUTPUT_FILENAME_TEXT
else:
raise ValueError ('Specify one of the supported back ends as TEST_TREXIO_BACKEND')
try:
if TEST_TREXIO_BACKEND == 0:
os.remove(output_filename)
elif TEST_TREXIO_BACKEND == 1:
shutil.rmtree(output_filename)
except:
print ('Nothing to remove.')
#=========================================================#
#============ WRITE THE DATA IN THE TEST FILE ============#
#=========================================================#
test_file = trexio_open(output_filename, 'w', TEST_TREXIO_BACKEND)
nucleus_num = 12
rc = trexio_write_nucleus_num(test_file, nucleus_num)
assert rc==0
# initialize charge arrays as a list and convert it to numpy array
charges = [6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.]
charges_np = np.array(charges, dtype=np.float64)
# function call below works with both lists and numpy arrays, dimension needed for memory-safety is derived
# from the size of the list/array by SWIG using typemaps from numpy.i
rc = trexio_write_safe_nucleus_charge(test_file, charges_np)
assert rc==0
# less Python-ic way to read/write arrays using Array classes (probably more portable to other languages)
#charges = doubleArray(nucleus_num)
#for i in range(nucleus_num):
# if i < nucleus_num/2:
# charges[i] = 6.
# else:
# charges[i] = 1.
#rc = trexio_write_nucleus_charge(test_file, charges)
# initialize arrays of nuclear indices as a list and convert it to numpy array
indices = [i for i in range(nucleus_num)]
# type cast is important here because by default numpy transforms a list of integers into int64 array
indices_np = np.array(indices, dtype=np.int32)
# function call below works with both lists and numpy arrays, dimension needed for memory-safety is derived
# from the size of the list/array by SWIG using typemacs from numpy.i
rc = trexio_write_safe_basis_nucleus_index(test_file, indices_np)
assert rc==0
point_group = 'B3U'
rc = trexio_write_nucleus_point_group(test_file, point_group, 10)
assert rc==0
labels = [
'C',
'C',
'C',
'C',
'C',
'C',
'H',
'H',
'H',
'H',
'H',
'H']
rc = trexio_write_nucleus_label(test_file, labels, 10)
assert rc==0
rc = trexio_close(test_file)
assert rc==0
#==========================================================#
#============ READ THE DATA FROM THE TEST FILE ============#
#==========================================================#
test_file2 = trexio_open(output_filename, 'r', TEST_TREXIO_BACKEND)
result = trexio_read_nucleus_num(test_file2)
assert result[0]==0
assert result[1]==nucleus_num
# safe call to read_safe array of float values
rc, rcharges_np = trexio_read_safe_nucleus_charge(test_file2, nucleus_num)
assert rc==0
assert rcharges_np.dtype is np.dtype(np.float64)
np.testing.assert_array_almost_equal(rcharges_np, charges_np, decimal=8)
# unsafe call to read_safe should not only have return code = TREXIO_UNSAFE_ARRAY_DIM
# TODO: it should not return numpy array filled with garbage
rc, rcharges_fail = trexio_read_safe_nucleus_charge(test_file2, nucleus_num*5)
assert rc==23
# less Python-ic way to read/write arrays using Array classes (probably more portable to other languages)
#charges2 = doubleArray(nucleus_num)
#for i in range(nucleus_num):
# charges2[i] = -1.
#rc = trexio_read_nucleus_charge(test_file2, charges2)
#assert rc==0
#for i in range(nucleus_num):
# assert charges2[i]==charges[i]
# safe call to read_safe array of int values
rc, rindices_np = trexio_read_safe_basis_nucleus_index(test_file2, nucleus_num)
assert rc==0
assert rindices_np.dtype is np.dtype(np.int32)
for i in range(nucleus_num):
assert rindices_np[i]==indices_np[i]
# currently only low-level routines (return one long string instead of an array of strings) work
rc, labels_1d = trexio_read_nucleus_label_low(test_file2, 10)
assert rc==0
labels_2d = [label for label in labels_1d.split(TREXIO_DELIM) if label]
print('Read and parsed nuclear labels:\n', labels_2d)
for i in range(nucleus_num):
assert labels_2d[i]==labels[i]
rc, rpoint_group = trexio_read_nucleus_point_group(test_file2, 3)
print(f'Read point group: {rpoint_group}')
assert rc==0
assert rpoint_group==point_group
rc = trexio_close(test_file2)
assert rc==0
try:
if TEST_TREXIO_BACKEND == 0:
os.remove(output_filename)
elif TEST_TREXIO_BACKEND == 1:
shutil.rmtree(output_filename)
except:
print (f'No output file {output_filename} has been produced')
#==========================================================#

View File

@ -0,0 +1,4 @@
INCLUDEDIR=`python -c 'import numpy; print(numpy.get_include())'`
export NUMPY_INCLUDEDIR=${INCLUDEDIR}

14
src/.gitignore vendored
View File

@ -2,6 +2,7 @@ templates_front/*.c
templates_front/*.h
templates_front/*.f90
templates_front/*.fh_90
templates_front/*.py
templates_front/*.dump
templates_front/populated/
@ -15,20 +16,21 @@ templates_text/*.h
templates_text/*.dump
templates_text/populated/
libtrexio.so
*.so
*.o
*.h
*.dump
*.cppcheck
trexio.c
trexio_text.c
trexio_hdf5.c
trexio_f.f90
trexio.mod
test_c
test_f
*.h5
trexio_test/
trexio_test_fort/
pytrexio.py
pytrexio_wrap.c
*.h5
*.dir/
__pycache__/

3028
src/numpy.i Normal file

File diff suppressed because it is too large Load Diff

126
src/pytrexio.i Normal file
View File

@ -0,0 +1,126 @@
%module pytrexio
/* Define SWIGWORDSIZE in order to properly align long integers on 64-bit system */
#define SWIGWORDSIZE64
%{
#define SWIG_FILE_WITH_INIT
/* Include the headers in the wrapper code */
#include "trexio_s.h"
#include "trexio.h"
%}
/* Include stdint to recognize types from stdint.h */
%include <stdint.i>
/* NOTE:
carrays was useful before numpy.i was introduced.
For Python interface it's better to use numpy arrays instead of carrays, because the latter are less python-ic.
On the other hand, carrays might be more portable to other target languages.
// Include carrays to work with C pointers to arrays
%include "carrays.i"
// Include classes that correspond to integer and float arrays
%array_class(double, doubleArray);
%array_class(float, floatArray);
%array_class(int32_t, int32Array);
%array_class(int64_t, int64Array);
*/
/* Include typemaps to play with input/output re-casting
Useful when working with C pointers
*/
%include typemaps.i
/* Redefine the int32_t* and int64_t* num to be output
Useful for TREXIO read_num functions where the
num variable is modified by address
*/
%apply int *OUTPUT { int32_t* const num};
%apply int *OUTPUT { int64_t* const num};
/* Does not work for arrays (SIGSEGV) */
/* This enables access to trexio_[...]_read_dset_str_low set of functions
in order to return one long string with TREXIO_DELIM delimeter as 2-nd argument of output tuple
*/
%include <cstring.i>
/* This enables read of long strings with TREXIO_DELIM delimeters that can be further converted into an array of string */
%cstring_bounded_output(char* dset_out, 4096);
/* This enables read of single string attributes with pre-defined max_str_len
for Python we pre-define max_str_len = PYTREXIO_MAX_STR_LENGTH everywhere for simplicity
*/
%cstring_output_maxsize(char* const str_out, const int32_t max_str_len);
/* [WIP] TREXIO back ends and exit codes can be redefined in the SWIG target language
using %ignore and further #define statements (instead of disabling the type cast in the trexio.h file)
*/
/*
%ignore TREXIO_HDF5; // Ignore a macro in the header file
%ignore TREXIO_TEST; // Ignore a macro in the header file
#define TREXIO_HDF5 0
#define TREXIO_TEXT 0
*/
/* This is an attempt to make SWIG treat double * dset_out|_in, int64_t dim_out|_in pattern
as a special case in order to return the NumPy array to Python from C pointer to array
provided by trexio_read_safe_[dset_num] function.
NOTE: numpy.i is currently not part of SWIG but included in the numpy distribution (under numpy/tools/swig/numpy.i)
This means that the interface file have to be provided to SWIG during compilation either by
copying it to the local working directory or by providing -l/path/to/numpy.i flag upon SWIG compilation
*/
%include "numpy.i"
%init %{
import_array();
%}
/* Typemaps below change the type of numpy array dimensions from int to int64_t */
%numpy_typemaps(double, NPY_DOUBLE, int64_t)
%numpy_typemaps(float, NPY_FLOAT, int64_t)
%numpy_typemaps(int32_t, NPY_INT32, int64_t)
%numpy_typemaps(int64_t, NPY_INT64, int64_t)
/* Enable write|read_safe functions to convert numpy arrays from/to double arrays */
%apply (double* ARGOUT_ARRAY1, int64_t DIM1) {(double * const dset_out, const int64_t dim_out)};
%apply (double* IN_ARRAY1, int64_t DIM1) {(const double * dset_in, const int64_t dim_in)};
/* Enable write|read_safe functions to convert numpy arrays from/to float arrays */
%apply (float* ARGOUT_ARRAY1, int64_t DIM1) {(float * const dset_out, const int64_t dim_out)};
%apply (float* IN_ARRAY1, int64_t DIM1) {(const float * dset_in, const int64_t dim_in)};
/* Enable write|read_safe functions to convert numpy arrays from/to int32 arrays */
%apply (int32_t* ARGOUT_ARRAY1, int64_t DIM1) {(int32_t * const dset_out, const int64_t dim_out)};
%apply (int32_t* IN_ARRAY1, int64_t DIM1) {(const int32_t * dset_in, const int64_t dim_in)};
/* Enable write|read_safe functions to convert numpy arrays from/to int64 arrays */
%apply (int64_t* ARGOUT_ARRAY1, int64_t DIM1) {(int64_t * const dset_out, const int64_t dim_out)};
%apply (int64_t* IN_ARRAY1, int64_t DIM1) {(const int64_t * dset_in, const int64_t dim_in)};
/* This tells SWIG to treat char ** dset_in pattern as a special case
Enables access to trexio_[...]_write_dset_str set of functions directly, i.e.
by converting input list of strings from Python into char ** of C
*/
%typemap(in) char ** dset_in {
/* Check if is a list */
if (PyList_Check($input)) {
int size = PyList_Size($input);
Py_ssize_t i = 0;
$1 = (char **) malloc((size+1)*sizeof(char *));
for (i = 0; i < size; i++) {
PyObject *o = PyList_GetItem($input, i);
if (PyUnicode_Check(o)) {
$1[i] = PyUnicode_AsUTF8(PyList_GetItem($input,i));
} else {
PyErr_Format(PyExc_TypeError, "list must contain strings. %d/%d element was not string.", i, size);
free($1);
return NULL;
}
}
$1[i] = 0;
} else {
PyErr_SetString(PyExc_TypeError, "not a list");
return NULL;
}
}
/* This cleans up the char ** array we malloc-ed before */
%typemap(freearg) char ** dset_in {
free((char *) $1);
}
/* Parse the header files to generate wrappers */
%include "trexio_s.h"
%include "trexio.h"

View File

@ -10,6 +10,7 @@ echo "" >> trexio.h
cat prefix_s_front.h > trexio_s.h
cat prefix_fortran.f90 > trexio_f.f90
cat prefix_python.py > trexio.py
# c front end
cat populated/pop_*.c >> trexio.c
@ -21,6 +22,10 @@ cat populated/pop_*.f90 >> trexio_f.f90
cat helper_fortran.f90 >> trexio_f.f90
cat populated/pop_*.fh_90 >> trexio_f.f90
# python front end
cat basic_python.py >> trexio.py
cat populated/pop_*.py >> trexio.py
# suffixes
cat suffix_s_front.h >> trexio_s.h
cat suffix_front.h >> trexio.h

File diff suppressed because it is too large Load Diff

View File

@ -64,9 +64,8 @@
#+begin_src c :tangle struct_hdf5.h
typedef struct trexio_hdf5_s {
trexio_t parent ;
hid_t file_id;
hid_t $group$_group;
const char* file_name;
hid_t file_id;
hid_t $group$_group;
} trexio_hdf5_t;
#+end_src
@ -537,15 +536,22 @@ trexio_hdf5_write_$group_dset$ (trexio_t* const file, const char** $group_dset$,
/* we are going to write variable-length strings */
hid_t memtype = H5Tcopy (H5T_C_S1);
if (memtype <= 0) return TREXIO_INVALID_ID;
status = H5Tset_size (memtype, H5T_VARIABLE);
if (status < 0) return TREXIO_FAILURE;
if ( H5LTfind_dataset(f->$group$_group, $GROUP_DSET$_NAME) != 1 ) {
/* code to create dataset */
hid_t filetype = H5Tcopy (H5T_FORTRAN_S1);
if (filetype <= 0) return TREXIO_INVALID_ID;
status = H5Tset_size (filetype, H5T_VARIABLE);
if (status < 0) return TREXIO_FAILURE;
hid_t dspace = H5Screate_simple( (int) rank, (const hsize_t*) dims, NULL);
if (dspace <= 0) return TREXIO_INVALID_ID;
dset_id = H5Dcreate (f->$group$_group, $GROUP_DSET$_NAME, filetype, dspace,
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);

View File

@ -456,8 +456,6 @@ trexio_text_read_$group$ (trexio_text_t* const file)
}
// END REPEAT GROUP_DSET_NUM
size_t tmp_len;
// START REPEAT GROUP_DSET_STR
/* Allocate arrays */
$group$->$group_dset$ = CALLOC(size_$group_dset$, $group_dset_dtype$);
@ -485,7 +483,7 @@ trexio_text_read_$group$ (trexio_text_t* const file)
,*/
char* tmp_$group_dset$;
if(size_$group_dset$ != 0) tmp_$group_dset$ = CALLOC(size_$group_dset$*32, char);
tmp_len = 0;
for (uint64_t i=0 ; i<size_$group_dset$ ; ++i) {
$group$->$group_dset$[i] = tmp_$group_dset$;
/* conventional fcanf with "%s" only return the string before the first space character
@ -501,8 +499,8 @@ trexio_text_read_$group$ (trexio_text_t* const file)
return NULL;
}
tmp_len = strlen($group$->$group_dset$[i]);
tmp_$group_dset$ += tmp_len + 1;
size_t tmp_$group_dset$_len = strlen($group$->$group_dset$[i]);
tmp_$group_dset$ += tmp_$group_dset$_len + 1;
}
// END REPEAT GROUP_DSET_STR
@ -852,9 +850,8 @@ trexio_text_write_$group_dset$ (trexio_t* const file, const char** dset, const u
char* tmp_str = CALLOC(dims[0]*32 + 1, char);
if (tmp_str == NULL) return TREXIO_ALLOCATION_FAILED;
size_t tmp_len = 0;
for (uint64_t i=0 ; i<dims[0] ; ++i) {
tmp_len = strlen(dset[i]);
size_t tmp_len = strlen(dset[i]);
$group$->$group_dset$[i] = tmp_str;
strncpy(tmp_str, dset[i], tmp_len);
tmp_str += tmp_len + 1;

View File

@ -0,0 +1,165 @@
#include "trexio.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define TEST_BACKEND TREXIO_HDF5
#define TREXIO_FILE "test_safe_dset_f.h5"
#define RM_COMMAND "rm -rf " TREXIO_FILE
static int test_write_dset (const char* file_name, const back_end_t backend) {
/* Try to write a dataset with floating point values into the TREXIO file using safe API */
trexio_t* file = NULL;
trexio_exit_code rc;
// parameters to be written
int num = 12;
double coord[36] = {
0.00000000 , 1.39250319 , 0.00000000 ,
-1.20594314 , 0.69625160 , 0.00000000 ,
-1.20594314 , -0.69625160 , 0.00000000 ,
0.00000000 , -1.39250319 , 0.00000000 ,
1.20594314 , -0.69625160 , 0.00000000 ,
1.20594314 , 0.69625160 , 0.00000000 ,
-2.14171677 , 1.23652075 , 0.00000000 ,
-2.14171677 , -1.23652075 , 0.00000000 ,
0.00000000 , -2.47304151 , 0.00000000 ,
2.14171677 , -1.23652075 , 0.00000000 ,
2.14171677 , 1.23652075 , 0.00000000 ,
0.00000000 , 2.47304151 , 0.00000000 ,
};
/*================= START OF TEST ==================*/
// open file in 'write' mode
file = trexio_open(file_name, 'w', backend);
assert (file != NULL);
// write numerical attribute in an empty file
rc = trexio_write_nucleus_num(file, num);
assert (rc == TREXIO_SUCCESS);
/* write numerical dataset with an unsafe dimension
* this should return TREXIO_UNSAFE_ARRAY_DIM indicating
* that access beyong allocated memory is likely to occur */
uint64_t dim_unsafe = num * 12;
rc = trexio_write_safe_nucleus_coord(file, coord, dim_unsafe);
assert (rc == TREXIO_UNSAFE_ARRAY_DIM);
/* write numerical dataset with a safe dimension
* this should return TREXIO_SUCCESS */
uint64_t dim_safe = num * 3;
rc = trexio_write_safe_nucleus_coord(file, coord, dim_safe);
assert (rc == TREXIO_SUCCESS);
// close current session
rc = trexio_close(file);
assert (rc == TREXIO_SUCCESS);
/*================= END OF TEST ==================*/
return 0;
}
static int test_has_dset (const char* file_name, const back_end_t backend) {
/* Try to check the existence of a dataset in the TREXIO file */
trexio_t* file = NULL;
trexio_exit_code rc;
/*================= START OF TEST ==================*/
// open file in 'read' mode
file = trexio_open(file_name, 'r', backend);
assert (file != NULL);
// check that the previously written dataset exists
rc = trexio_has_nucleus_coord(file);
assert (rc == TREXIO_SUCCESS);
// close current session
rc = trexio_close(file);
assert (rc == TREXIO_SUCCESS);
/*================= END OF TEST ==================*/
return 0;
}
static int test_read_dset (const char* file_name, const back_end_t backend) {
/* Try to read a dataset with floating point values from the TREXIO file using safe API */
trexio_t* file = NULL;
trexio_exit_code rc;
// parameters to be read
int num;
double* coord;
/*================= START OF TEST ==================*/
// open file in 'read' mode
file = trexio_open(file_name, 'r', backend);
assert (file != NULL);
// read numerical attribute from the file
rc = trexio_read_nucleus_num(file, &num);
assert (rc == TREXIO_SUCCESS);
assert (num == 12);
// read numerical (floating point) dataset from the file
coord = (double*) calloc(3*num, sizeof(double));
/* write numerical dataset with an unsafe dimension
* this should return TREXIO_UNSAFE_ARRAY_DIM indicating
* that access beyong allocated memory is likely to occur */
uint64_t dim_unsafe = num * 12;
rc = trexio_read_safe_nucleus_coord(file, coord, dim_unsafe);
assert (rc == TREXIO_UNSAFE_ARRAY_DIM);
/* write numerical dataset with a safe dimension
* this should return TREXIO_SUCCESS */
uint64_t dim_safe = num * 3;
rc = trexio_read_safe_nucleus_coord(file, coord, dim_safe);
assert (rc == TREXIO_SUCCESS);
double x = coord[30] - 2.14171677;
assert( x*x < 1.e-14 );
free(coord);
// close current session
rc = trexio_close(file);
assert (rc == TREXIO_SUCCESS);
/*================= END OF TEST ==================*/
return 0;
}
int main(void) {
/*============== Test launcher ================*/
int rc;
rc = system(RM_COMMAND);
assert (rc == 0);
test_write_dset (TREXIO_FILE, TEST_BACKEND);
test_has_dset (TREXIO_FILE, TEST_BACKEND);
test_read_dset (TREXIO_FILE, TEST_BACKEND);
rc = system(RM_COMMAND);
assert (rc == 0);
return 0;
}

View File

@ -0,0 +1,165 @@
#include "trexio.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define TEST_BACKEND TREXIO_TEXT
#define TREXIO_FILE "test_safe_dset_f.dir"
#define RM_COMMAND "rm -rf " TREXIO_FILE
static int test_write_dset (const char* file_name, const back_end_t backend) {
/* Try to write a dataset with floating point values into the TREXIO file using safe API */
trexio_t* file = NULL;
trexio_exit_code rc;
// parameters to be written
int num = 12;
double coord[36] = {
0.00000000 , 1.39250319 , 0.00000000 ,
-1.20594314 , 0.69625160 , 0.00000000 ,
-1.20594314 , -0.69625160 , 0.00000000 ,
0.00000000 , -1.39250319 , 0.00000000 ,
1.20594314 , -0.69625160 , 0.00000000 ,
1.20594314 , 0.69625160 , 0.00000000 ,
-2.14171677 , 1.23652075 , 0.00000000 ,
-2.14171677 , -1.23652075 , 0.00000000 ,
0.00000000 , -2.47304151 , 0.00000000 ,
2.14171677 , -1.23652075 , 0.00000000 ,
2.14171677 , 1.23652075 , 0.00000000 ,
0.00000000 , 2.47304151 , 0.00000000 ,
};
/*================= START OF TEST ==================*/
// open file in 'write' mode
file = trexio_open(file_name, 'w', backend);
assert (file != NULL);
// write numerical attribute in an empty file
rc = trexio_write_nucleus_num(file, num);
assert (rc == TREXIO_SUCCESS);
/* write numerical dataset with an unsafe dimension
* this should return TREXIO_UNSAFE_ARRAY_DIM indicating
* that access beyong allocated memory is likely to occur */
uint64_t dim_unsafe = num * 12;
rc = trexio_write_safe_nucleus_coord(file, coord, dim_unsafe);
assert (rc == TREXIO_UNSAFE_ARRAY_DIM);
/* write numerical dataset with a safe dimension
* this should return TREXIO_SUCCESS */
uint64_t dim_safe = num * 3;
rc = trexio_write_safe_nucleus_coord(file, coord, dim_safe);
assert (rc == TREXIO_SUCCESS);
// close current session
rc = trexio_close(file);
assert (rc == TREXIO_SUCCESS);
/*================= END OF TEST ==================*/
return 0;
}
static int test_has_dset (const char* file_name, const back_end_t backend) {
/* Try to check the existence of a dataset in the TREXIO file */
trexio_t* file = NULL;
trexio_exit_code rc;
/*================= START OF TEST ==================*/
// open file in 'read' mode
file = trexio_open(file_name, 'r', backend);
assert (file != NULL);
// check that the previously written dataset exists
rc = trexio_has_nucleus_coord(file);
assert (rc == TREXIO_SUCCESS);
// close current session
rc = trexio_close(file);
assert (rc == TREXIO_SUCCESS);
/*================= END OF TEST ==================*/
return 0;
}
static int test_read_dset (const char* file_name, const back_end_t backend) {
/* Try to read a dataset with floating point values from the TREXIO file using safe API */
trexio_t* file = NULL;
trexio_exit_code rc;
// parameters to be read
int num;
double* coord;
/*================= START OF TEST ==================*/
// open file in 'read' mode
file = trexio_open(file_name, 'r', backend);
assert (file != NULL);
// read numerical attribute from the file
rc = trexio_read_nucleus_num(file, &num);
assert (rc == TREXIO_SUCCESS);
assert (num == 12);
// read numerical (floating point) dataset from the file
coord = (double*) calloc(3*num, sizeof(double));
/* write numerical dataset with an unsafe dimension
* this should return TREXIO_UNSAFE_ARRAY_DIM indicating
* that access beyong allocated memory is likely to occur */
uint64_t dim_unsafe = num * 12;
rc = trexio_read_safe_nucleus_coord(file, coord, dim_unsafe);
assert (rc == TREXIO_UNSAFE_ARRAY_DIM);
/* write numerical dataset with a safe dimension
* this should return TREXIO_SUCCESS */
uint64_t dim_safe = num * 3;
rc = trexio_read_safe_nucleus_coord(file, coord, dim_safe);
assert (rc == TREXIO_SUCCESS);
double x = coord[30] - 2.14171677;
assert( x*x < 1.e-14 );
free(coord);
// close current session
rc = trexio_close(file);
assert (rc == TREXIO_SUCCESS);
/*================= END OF TEST ==================*/
return 0;
}
int main(void) {
/*============== Test launcher ================*/
int rc;
rc = system(RM_COMMAND);
assert (rc == 0);
test_write_dset (TREXIO_FILE, TEST_BACKEND);
test_has_dset (TREXIO_FILE, TEST_BACKEND);
test_read_dset (TREXIO_FILE, TEST_BACKEND);
rc = system(RM_COMMAND);
assert (rc == 0);
return 0;
}

32
tools/check_numpy_i.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/bash
# Check that script is executed from tools directory
if [[ $(basename $PWD) != "tools" ]] ; then
echo "This script should run in the tools directory"
exit -1
fi
TREXIO_ROOT=$(dirname "${PWD}../")
# First define readonly global variables.
readonly SRC=${TREXIO_ROOT}/src
readonly TOOLS=${TREXIO_ROOT}/tools
# We want the script to crash on the 1st error:
set -e
NUMPY_SRC=${SRC}/numpy.i
NUMPY_LATEST=${TOOLS}/numpy.i
# Download the latest numpy.i file from NumPy GitHub
wget https://raw.githubusercontent.com/numpy/numpy/main/tools/swig/numpy.i -O ${NUMPY_LATEST}
# Execute diff to check if the numpy.i file in the src/ directory is updated
if ! diff -q ${NUMPY_LATEST} ${NUMPY_SRC} &>/dev/null; then
>&2 echo "numpy.i SWIG interface file in the source tree is outdated; replacing ..."
mv ${NUMPY_LATEST} ${NUMPY_SRC}
else
>&2 echo "numpy.i SWIG interface file in the source tree is up-to-date."
rm ${NUMPY_LATEST}
fi

View File

@ -100,7 +100,7 @@ def recursive_populate_file(fname: str, paths: dict, detailed_source: dict) -> N
fname_new = join('populated',f'pop_{fname}')
templ_path = get_template_path(fname, paths)
triggers = ['group_dset_dtype', 'group_dset_h5_dtype', 'default_prec', 'is_index',
triggers = ['group_dset_dtype', 'group_dset_py_dtype', 'group_dset_h5_dtype', 'default_prec', 'is_index',
'group_dset_f_dtype_default', 'group_dset_f_dtype_double', 'group_dset_f_dtype_single',
'group_dset_dtype_default', 'group_dset_dtype_double', 'group_dset_dtype_single',
'group_dset_rank', 'group_dset_dim_list', 'group_dset_f_dims',
@ -111,25 +111,27 @@ def recursive_populate_file(fname: str, paths: dict, detailed_source: dict) -> N
with open(join(templ_path,fname_new), 'a') as f_out :
num_written = []
for line in f_in :
# special case to add error handling for read/write of dimensioning variables
if '$group_dset_dim$' in line:
rc_line = 'if (rc != TREXIO_SUCCESS) return rc;\n'
indentlevel = len(line) - len(line.lstrip())
for dim in detailed_source[item]['dims']:
if not dim.isdigit() and not dim in num_written:
num_written.append(dim)
templine = line.replace('$group_dset_dim$', dim)
if '_read' in templine and (not 'fortran' in fname):
line_toadd = indentlevel*" " + rc_line
templine += line_toadd
# special case to add error handling for read/write of dimensioning variables
if '$group_dset_dim$' in line:
rc_line = 'if (rc != TREXIO_SUCCESS) return rc;\n'
indentlevel = len(line) - len(line.lstrip())
for dim in detailed_source[item]['dims']:
if not dim.isdigit() and not dim in num_written:
num_written.append(dim)
templine = line.replace('$group_dset_dim$', dim)
if '_read' in templine and (not 'fortran' in fname):
line_toadd = indentlevel*" " + rc_line
templine += line_toadd
f_out.write(templine)
num_written = []
continue
# general case of recursive replacement of inline triggers
else:
populated_line = recursive_replace_line(line, triggers, detailed_source[item])
f_out.write(populated_line)
f_out.write(templine)
num_written = []
continue
# general case of recursive replacement of inline triggers
else:
populated_line = recursive_replace_line(line, triggers, detailed_source[item])
f_out.write(populated_line)
f_out.write("\n")
def recursive_replace_line (input_line: str, triggers: list, source: dict) -> str:
@ -214,6 +216,8 @@ def iterative_populate_file (filename: str, paths: dict, groups: dict, datasets:
f_out.write(populated_line)
else:
f_out.write(line)
f_out.write("\n")
def iterative_replace_line (input_line: str, case: str, source: dict, add_line: str) -> str:
@ -403,6 +407,8 @@ def special_populate_text_group(fname: str, paths: dict, group_dict: dict, detai
else:
loop_body += line
f_out.write("\n")
def get_template_path (filename: str, path_dict: dict) -> str:
"""
@ -542,6 +548,7 @@ def split_dset_dict_detailed (datasets: dict) -> tuple:
default_prec = '64'
group_dset_std_dtype_out = '24.16e'
group_dset_std_dtype_in = 'lf'
group_dset_py_dtype = 'float'
elif v[0] in ['int', 'index']:
datatype = 'int64_t'
group_dset_h5_dtype = 'native_int64'
@ -554,6 +561,7 @@ def split_dset_dict_detailed (datasets: dict) -> tuple:
default_prec = '32'
group_dset_std_dtype_out = '" PRId64 "'
group_dset_std_dtype_in = '" SCNd64 "'
group_dset_py_dtype = 'int'
elif v[0] == 'str':
datatype = 'char*'
group_dset_h5_dtype = ''
@ -566,6 +574,7 @@ def split_dset_dict_detailed (datasets: dict) -> tuple:
default_prec = ''
group_dset_std_dtype_out = 's'
group_dset_std_dtype_in = 's'
group_dset_py_dtype = 'str'
# add the dset name for templates
tmp_dict['group_dset'] = k
@ -587,6 +596,7 @@ def split_dset_dict_detailed (datasets: dict) -> tuple:
tmp_dict['default_prec'] = default_prec
tmp_dict['group_dset_std_dtype_in'] = group_dset_std_dtype_in
tmp_dict['group_dset_std_dtype_out'] = group_dset_std_dtype_out
tmp_dict['group_dset_py_dtype'] = group_dset_py_dtype
# add the rank
tmp_dict['rank'] = len(v[1])
tmp_dict['group_dset_rank'] = str(tmp_dict['rank'])

34
tools/prepare_python.sh Executable file
View File

@ -0,0 +1,34 @@
#!/bin/bash
# Check that script is executed from tools directory
if [[ $(basename $PWD) != "tools" ]] ; then
echo "This script should run in the tools directory"
exit -1
fi
TREXIO_ROOT=$(dirname "${PWD}../")
# First define readonly global variables.
readonly SRC=${TREXIO_ROOT}/src
readonly INCLUDIR=${TREXIO_ROOT}/include
readonly TOOLS=${TREXIO_ROOT}/tools
readonly PYDIR=${TREXIO_ROOT}/python
readonly PYTREXIODIR=${PYDIR}/pytrexio
# We want the script to crash on the 1st error:
set -e
# Create src and trexio directories in the python folder if not yet done
mkdir -p ${PYDIR}/src
mkdir -p ${PYTREXIODIR}
# Copy all the source code and header files in the corresponding python directory
cp ${SRC}/pytrexio.py ${PYTREXIODIR}/pytrexio.py
cp ${SRC}/trexio.py ${PYDIR}/trexio.py
cp ${SRC}/*.c ${PYDIR}/src
cp ${SRC}/*.h ${PYDIR}/src
cp ${INCLUDIR}/trexio.h ${PYDIR}/src
# Copy additional info
cp ${TREXIO_ROOT}/AUTHORS ${TREXIO_ROOT}/LICENSE ${PYDIR}