Repository: TREX-CoE/trexio (language: python)

Issue:
add fortran interface



Discussion / hints:

Fix patch:
diff --git a/src/.gitignore b/src/.gitignore
index 9b3b8671..a22dab16 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,5 +1,6 @@
 templates_front/*.c
 templates_front/*.h
+templates_front/*.f90
 templates_front/populated/
 
 templates_hdf5/*.c
@@ -16,8 +17,11 @@ libtrexio.so
 trexio.c
 trexio_text.c
 trexio_hdf5.c
+trexio_f.f90
+trexio.mod
 
 test
-test_write.h5
+test_f
+*.h5
 trexio_test/
 
diff --git a/src/Makefile b/src/Makefile
index 2222872c..7cac3bc6 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -6,7 +6,10 @@ ifeq ($(COMPILER),GNU)
 CC=gcc -g
 CFLAGS=-fPIC -fexceptions -Wall -Werror -Wpedantic -Wextra
 
-LIBS= -L/usr/lib/x86_64-linux-gnu/hdf5/serial/ -lz -lm -lhdf5 -lhdf5_hl #-lgfortran
+FS=gfortran -g
+FFLAGS=-fPIC -fcheck=all -Waliasing -Wampersand -Wconversion -Wsurprising -Wintrinsics-std -Wno-tabs -Wintrinsic-shadow -Wline-truncation -Wreal-q-constant -Wuninitialized  -fbacktrace -ffpe-trap=zero,overflow,underflow -finit-real=nan
+
+LIBS= -L/usr/lib/x86_64-linux-gnu/hdf5/serial/ -lz -lm -lhdf5 -lhdf5_hl -lgfortran
 INCLUDE     = -I/usr/include/hdf5/serial
 endif
 
@@ -31,23 +34,36 @@ FFLAGS=fPIC -g -O2
 LIBS=-lm
 endif
 
+RM=rm -f
 
 OBJECT_FILES= trexio.o trexio_text.o trexio_hdf5.o
 HEADER_FILES= trexio.h trexio_text.h trexio_hdf5.h trexio_s.h
 
-export CC CFLAGS LIBS
+export CC CFLAGS FC FFLAGS LIBS
 
 .PHONY: clean
 
 libtrexio.so: $(OBJECT_FILES) $(HEADER_FILES)
 	$(CC) -shared $(OBJECT_FILES) -o libtrexio.so
 
-test: libtrexio.so test.c
-	$(CC) $(CFLAGS) $(INCLUDE) -Wl,-rpath,$(PWD) -L. test.c -ltrexio $(LIBS) -o test
+fortran: libtrexio.so trexio_f.f90
+	$(FC) $(FFLAGS) -c trexio_f.f90 -o trexio_f.o
+
+test_c: libtrexio.so test.c
+	$(CC) $(CFLAGS) $(INCLUDE) -Wl,-rpath,$(PWD) -L. test.c -ltrexio $(LIBS) -o test_c
+
+test_f: libtrexio.so test.f90 trexio_f.o
+	$(CC) $(CFLAGS) $(INCLUDE) -Wl,-rpath,$(PWD) -L. test.f90 trexio_f.o -ltrexio $(LIBS) -o test_f
+
+test: test_c test_f
+	$(RM) -r trexio_test
+	$(RM) -r trexio_test_fort
+	./test_c
+	./test_f
 
 clean:
-	rm -f *.o libtrexio.so test test_*.h5 
-	rm -r trexio_test/
+	$(RM) *.o libtrexio.so test_*.h5 test_f test_c
+	$(RM) -r trexio_test/ trexio_test_fort/
 
 %.o: %.c $(HEADER_FILES)
 	$(CC) $(CFLAGS) $(INCLUDE) -c $*.c -o $*.o
diff --git a/src/build_trex.sh b/src/build_trex.sh
index 8d7b0cab..c10636fc 100755
--- a/src/build_trex.sh
+++ b/src/build_trex.sh
@@ -17,7 +17,7 @@ mkdir -p templates_hdf5/populated
 # not options. It is safer.
 
 echo "remove existing templates"
-rm -f -- templates_front/*.{c,h}
+rm -f -- templates_front/*.{c,h,f90}
 rm -f -- templates_text/*.{c,h} 
 rm -f -- templates_hdf5/*.{c,h} 
 
diff --git a/src/generator.py b/src/generator.py
index 973de2c6..420523de 100644
--- a/src/generator.py
+++ b/src/generator.py
@@ -82,6 +82,7 @@
 files_exclude = ['prefix_hdf5.c', 'prefix_hdf5.h', 'suffix_hdf5.h', 
                  'prefix_text.c', 'prefix_text.h', 'suffix_text.h', 
                  'prefix_front.c', 'prefix_front.h', 'suffix_front.h', 
+                 'prefix_fortran.f90', 'suffix_fortran.f90',
                  'prefix_s_front.h', 'suffix_s_front.h',
                  'templator_front.org', 'templator_hdf5.org', 'templator_text.org']
 
@@ -259,12 +260,16 @@
 
                         if params['dtype'] == 'double':
                             h5_dtype = 'double'
+                            f_dtype = 'real(8)'
                         elif params['dtype'] == 'int64_t':
                             h5_dtype = 'long'
+                            f_dtype = 'integer(8)'
 
                         templine1 = templine2.replace('$group_dset_h5_dtype$', h5_dtype)
                         templine2 = templine1.replace('$group_dset_h5_dtype$'.upper(), h5_dtype.upper())
 
+                        templine1 = templine2.replace('$group_dset_f_dtype$', f_dtype)
+                        templine2 = templine1.replace('$group_dset_f_dtype$'.upper(), f_dtype.upper())
 
                         templine1 = templine2.replace('$group_dset_rank$', str(params['rank']))
                         templine2 = templine1
diff --git a/src/templates_front/build.sh b/src/templates_front/build.sh
index 5a37440e..f20f78ab 100644
--- a/src/templates_front/build.sh
+++ b/src/templates_front/build.sh
@@ -1,15 +1,20 @@
 #!/bin/bash
 
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+# prefixes
+cat prefix_front.c   > trexio.c
+cat prefix_front.h   > trexio.h
+cat prefix_s_front.h > trexio_s.h
+cat prefix_fortran.f90   > trexio_f.f90
 
-cat $DIR/prefix_front.c   > trexio.c
-cat $DIR/prefix_front.h   > trexio.h
-cat $DIR/prefix_s_front.h > trexio_s.h
+# c front end
+cat populated/pop_*.c >> trexio.c
+cat populated/pop_*.h >> trexio.h
 
-cat $DIR/populated/pop_*.c >> trexio.c
-cat $DIR/populated/pop_*.h >> trexio.h
-
-cat $DIR/suffix_s_front.h >> trexio_s.h
-cat $DIR/suffix_front.h   >> trexio.h
+# fortran front end
+cat populated/pop_*.f90  >> trexio_f.f90
 
+# suffixes
+cat suffix_s_front.h >> trexio_s.h
+cat suffix_front.h   >> trexio.h
+cat suffix_fortran.f90 >> trexio_f.f90
 
diff --git a/src/templates_front/templator_front.org b/src/templates_front/templator_front.org
index 278de8d2..6b00cd17 100644
--- a/src/templates_front/templator_front.org
+++ b/src/templates_front/templator_front.org
@@ -2,17 +2,29 @@
 
 * Constant file prefixes (not used by generator)                    :noxport:
 
-** Prefixes
-
   #+NAME:header
   #+begin_src c 
-/* This file was generated from the trexio.org org-mode file.
+/* This file was generated from the templator_front.org org-mode file.
    To generate it, open trexio.org in Emacs and execute
    M-x org-babel-tangle
 */
 
   #+end_src
 
+  #+begin_src fortran :tangle prefix_fortran.f90 :noweb yes
+
+module trexio
+
+  use, intrinsic :: iso_c_binding
+  implicit none 
+
+  integer, parameter :: TREXIO_HDF5 = 0
+  integer, parameter :: TREXIO_TEXT = 1
+! integer, parameter :: TREXIO_JSON = 2
+  integer, parameter :: TREXIO_INVALID_BACK_END = 3
+  
+  #+end_src
+
   #+begin_src c :tangle prefix_front.h :noweb yes
 <<header>>
 #ifndef _TREXIO_H
@@ -80,6 +92,7 @@
 #define FREE(X) { free(X) ; (X)=NULL; }
    #+end_src
 
+
 * Front end
 
  All calls to TREXIO are thread-safe.
@@ -175,7 +188,7 @@ struct trexio_back_end_s {
    #+end_src
    
 ** File opening
-   
+
    #+begin_src c :tangle prefix_front.h
 trexio_t* trexio_open(const char* file_name, const char mode, const back_end_t back_end);
    #+end_src
@@ -279,9 +292,20 @@ trexio_t* trexio_open(const char* file_name, const char mode, const back_end_t b
   return result;
 }
    #+end_src
+
+   #+begin_src fortran :tangle prefix_fortran.f90
+interface
+   integer(8) function trexio_open_c (filename, mode, backend) bind(C, name="trexio_open")
+     use, intrinsic :: iso_c_binding
+     character(kind=c_char), dimension(*)  :: filename
+     character, intent(in), value          :: mode
+     integer, intent(in), value            :: backend
+   end function trexio_open_c
+end interface   
+   #+end_src
    
 ** File closing
-   
+ 
    #+begin_src c :tangle prefix_front.h
 trexio_exit_code trexio_close(trexio_t* file);
    #+end_src
@@ -354,9 +378,16 @@ trexio_exit_code trexio_close(trexio_t* file) {
 }
    #+end_src
 
+   #+begin_src fortran :tangle prefix_fortran.f90
+interface
+   integer function trexio_close (trex_file) bind(C)
+     use, intrinsic :: iso_c_binding
+     integer(8), intent(in), value :: trex_file
+   end function trexio_close
+end interface   
+   #+end_src
 
 * Templates for front end
-
 ** Template for frontend read/write a number
    
      #+begin_src c :tangle rw_num_front.h
@@ -424,6 +455,32 @@ trexio_exit_code trexio_write_$group_num$(trexio_t* file, const int64_t num) {
      #+end_src
 
 
+     #+begin_src fortran :tangle write_num_front_fortran.f90
+
+interface
+   integer function trexio_write_$group_num$ (trex_file, num) bind(C)
+     use, intrinsic :: iso_c_binding
+     integer(8), intent(in), value :: trex_file
+     integer(8), intent(in), value :: num
+   end function trexio_write_$group_num$
+end interface
+
+     #+end_src
+
+
+     #+begin_src fortran :tangle read_num_front_fortran.f90
+     
+interface
+   integer function trexio_read_$group_num$ (trex_file, num) bind(C)
+     use, intrinsic :: iso_c_binding
+     integer(8), intent(in), value :: trex_file
+     integer(8), intent(out) :: num
+   end function trexio_read_$group_num$
+end interface
+
+     #+end_src
+
+
 ** Template for frontend read/write a dataset
 
      #+begin_src c :tangle rw_dset_front.h
@@ -531,7 +588,30 @@ trexio_exit_code trexio_write_$group$_$group_dset$(trexio_t* file, const $group_
   }
 }
      #+end_src
-    
+   
+     #+begin_src fortran :tangle write_dset_front_fortran.f90
+
+interface
+   integer function trexio_write_$group$_$group_dset$ (trex_file, dset) bind(C)
+     use, intrinsic :: iso_c_binding
+     integer(8), intent(in), value :: trex_file
+     $group_dset_f_dtype$, intent(in) :: dset(*)
+   end function trexio_write_$group$_$group_dset$
+end interface
+
+     #+end_src
+
+     #+begin_src fortran :tangle read_dset_front_fortran.f90
+     
+interface
+   integer function trexio_read_$group$_$group_dset$ (trex_file, dset) bind(C)
+     use, intrinsic :: iso_c_binding
+     integer(8), intent(in), value :: trex_file
+     $group_dset_f_dtype$, intent(out) :: dset(*)
+   end function trexio_read_$group$_$group_dset$
+end interface
+
+     #+end_src
 
 * Back ends
   
@@ -541,6 +621,25 @@ trexio_exit_code trexio_write_$group$_$group_dset$(trexio_t* file, const $group_
    - Text files: not to be used for production, but useful for debugging
    - JSON: for portability
      
+
+* Fortran helper/wrapper functions
+
+  #+begin_src fortran :tangle suffix_fortran.f90
+contains
+   integer(8) function trexio_open (filename, mode, backend)
+     use, intrinsic :: iso_c_binding
+     implicit none
+     character(len=*)      :: filename
+     character, intent(in), value :: mode
+     integer, intent(in), value   :: backend
+     character(len=len_trim(filename)+1) :: filename_c
+    
+     filename_c = trim(filename) // c_null_char
+     trexio_open = trexio_open_c(filename_c, mode, backend)
+   end function trexio_open
+  #+end_src
+
+
 * File suffixes                                                     :noxport:
 
   #+begin_src c :tangle suffix_front.h
@@ -551,5 +650,9 @@ trexio_exit_code trexio_write_$group$_$group_dset$(trexio_t* file, const $group_
 #endif
   #+end_src
 
+  #+begin_src fortran :tangle suffix_fortran.f90
+end module trexio
+  #+end_src
+
 
   
diff --git a/src/templates_hdf5/build.sh b/src/templates_hdf5/build.sh
index 213bdb3c..e9bb94b1 100644
--- a/src/templates_hdf5/build.sh
+++ b/src/templates_hdf5/build.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
 cat prefix_hdf5.c   > trexio_hdf5.c
 cat prefix_hdf5.h   > trexio_hdf5.h
diff --git a/src/templates_text/build.sh b/src/templates_text/build.sh
index 2835dd39..e8e1918d 100644
--- a/src/templates_text/build.sh
+++ b/src/templates_text/build.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
 cat prefix_text.c   > trexio_text.c
 cat prefix_text.h   > trexio_text.h


Test patch:
diff --git a/src/test.f90 b/src/test.f90
new file mode 100644
index 00000000..1116b086
--- /dev/null
+++ b/src/test.f90
@@ -0,0 +1,106 @@
+program test_trexio
+
+  call test_write()
+  call test_read()
+
+end program test_trexio
+
+subroutine test_write()
+   
+  use trexio
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  integer(8) :: trex_file
+
+  integer :: rc = 1
+  integer(8) :: num
+
+  double precision :: charge(12)
+  double precision :: coord(36)
+
+  num = 12
+  charge = (/6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1. /)
+  coord = (/ 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 /)
+
+!  trex_file = trexio_open('trexio_test_fort', 'w', TREXIO_TEXT)
+  trex_file = trexio_open('test_hdf5_fort.h5', 'w', TREXIO_HDF5)
+
+  rc = trexio_write_nucleus_num(trex_file, num)
+  if (rc == 0) write(*,*) 'SUCCESS WRITE NUM'
+
+  rc = trexio_write_nucleus_charge(trex_file, charge)
+  if (rc == 0) write(*,*) 'SUCCESS WRITE CHARGE'
+
+  rc = trexio_write_nucleus_coord(trex_file, coord)
+  if (rc == 0) write(*,*) 'SUCCESS WRITE COORD'
+
+  rc = trexio_close(trex_file)
+  if (rc == 0) write(*,*) 'SUCCESS CLOSE' 
+
+! ---------------------------------- !
+! to modify fiels of existing file:
+! text backend -> open with 'w'
+! hdf5 backend -> open with 'a'
+! ---------------------------------- !
+
+!!  trex_file = trexio_open('trexio_test_fort', 'w', TREXIO_TEXT);
+!!  trex_file = trexio_open('test_hdf5_fort.h5', 'a', TREXIO_HDF5)
+  
+!  coord(1) = 666.666
+
+!  rc = trexio_write_nucleus_coord(trex_file,coord)
+!  if (rc == 0) write(*,*) 'SUCCESS MODIFY COORD'
+
+!  rc = trexio_close(trex_file)
+!  if (rc == 0) write(*,*) 'SUCCESS CLOSE' 
+
+end subroutine test_write
+
+subroutine test_read()
+
+  use trexio
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  integer(8) :: trex_file
+
+  integer :: rc = 1
+  integer(8) :: num, num_read
+
+  double precision :: charge(12) 
+  double precision :: coord(36) 
+
+  num = 12
+
+!  trex_file = trexio_open('trexio_test_fort', 'r', TREXIO_TEXT)
+  trex_file = trexio_open('test_hdf5_fort.h5', 'r', TREXIO_HDF5)
+
+  rc = trexio_read_nucleus_num(trex_file, num_read)
+
+  if (rc == 0 .and. num_read == num) write(*,*) 'SUCCESS READ NUM'
+
+  rc = trexio_read_nucleus_charge(trex_file, charge)
+   
+  if (rc == 0 .and. (abs (charge(11) - 1.0) < 1.0D-8) ) write(*,*) 'SUCCESS READ CHARGE'
+
+  rc = trexio_read_nucleus_coord(trex_file, coord)
+   
+  if (rc == 0 .and. (abs (coord(2) - 1.39250319) < 1.0D-8) ) write(*,*) 'SUCCESS READ COORD'
+
+  rc = trexio_close(trex_file)
+  if (rc == 0) write(*,*) 'SUCCESS CLOSE' 
+
+end subroutine test_read
+