1
0
mirror of https://github.com/TREX-CoE/trexio.git synced 2024-12-22 12:23:54 +01:00

Library compiles

This commit is contained in:
Anthony Scemama 2021-02-20 17:12:38 +01:00
parent d56de54275
commit 43bbcfcdbf
2 changed files with 736 additions and 0 deletions

52
src/Makefile Normal file
View File

@ -0,0 +1,52 @@
COMPILER=GNU
#COMPILER=INTEL
#COMPILER=LLVM
ifeq ($(COMPILER),GNU)
CC=gcc -g
CFLAGS=-fPIC -fexceptions -Wall -Werror -Wpedantic -Wextra
LIBS= #-lgfortran -lm
endif
ifeq ($(COMPILER),INTEL)
CC=icc -xHost
CFLAGS=-fPIC -g -O2
FC=ifort -xHost
FFLAGS=-fPIC -g -O2
LIBS= #-lm
endif
#TODO
ifeq ($(COMPILER),LLVM)
CC=clang
CFLAGS=-fPIC -g -O2
FC=flang
FFLAGS=fPIC -g -O2
LIBS=-lm
endif
OBJECT_FILES= trio.o trio_text.o
HEADER_FILES= trio.h trio_text.h trio_s.h
export CC CFLAGS LIBS
.PHONY: clean
libtrio.so: $(OBJECT_FILES) $(HEADER_FILES)
$(CC) -shared $(OBJECT_FILES) -o libtrio.so
test: libtrio.so test.c
$(CC) $(CFLAGS) -Wl,-rpath,$(PWD) -L. test.c -ltrio $(LIBS) -o test
clean:
rm -f *.o libtrio.so
%.o: %.c $(HEADER_FILES)
$(CC) $(CFLAGS) -c $*.c -o $*.o

684
src/trio.org Normal file
View File

@ -0,0 +1,684 @@
#+TITLE: TREX Input/Ouput library (TRIO)
* File prefixes :noxport:
#+begin_src c :tangle trio.h
#ifndef _TRIO_H
#define _TRIO_H
#include <stdint.h>
#+end_src
#+begin_src c :tangle trio.c
#include <pthread.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "trio.h"
#include "trio_s.h"
#include "trio_text.h"
/*
#include "trio_hdf5.h"
#include "trio_json.h"
,*/
#+end_src
#+begin_src c :tangle trio_s.h
#ifndef _TRIO_S_H
#define _TRIO_S_H
#include "trio.h"
#include <pthread.h>
#include <assert.h>
#+end_src
#+begin_src c :tangle trio_text.h
#ifndef _TRIO_TEXT_H
#define _TRIO_TEXT_H
#include "trio.h"
#include "trio_s.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#+end_src
#+begin_src c :tangle trio_text.c
#include "trio_text.h"
#+end_src
* Coding conventions
- integer types will be defined using types given in ~stdint.h~
- pointers are always initialized to ~NULL~
- when memory is freed, the pointer is set to ~NULL~
- ~assert.h~ should be used extensively
- variable names are in lower case
- ~#define~ constants are in upper case
- structs are suffixed by ~_s~
- types are suffixed by ~_t~
* Front end
All calls to TRIO are thread-safe.
** Error handling
#+begin_src c :tangle trio.h
typedef int32_t trio_exit_code;
#define TRIO_SUCCESS ( (trio_exit_code) 0 )
#define TRIO_FAILURE ( (trio_exit_code) 1 )
#+end_src
** Back ends
#+begin_src c :tangle trio.h
typedef uint32_t back_end_t;
#define TRIO_HDF5 ( (back_end_t) 0 )
#define TRIO_TEXT ( (back_end_t) 1 )
#define TRIO_JSON ( (back_end_t) 2 )
#define TRIO_INVALID_BACK_END ( (back_end_t) 3 )
#+end_src
** Read/write behavior
Every time a reading function is called, the data is read from the
disk. If data needs to be cached, this is left to the user of the
library.
Writing to TRIO files is done with transactions (all-or-nothing
effect) in a per-group fashion. File writes are attempted by
calling explicitly the flush function, or when the TRIO file is
closed. If writing is impossible because the data is not valid, no
data is written.
The order in which the data is written is not necessarily consistent
with the order in which the function calls were made.
The TRIO files are supposed to be opened by only one program at a
time: if the same TRIO file is modified simultaneously by multiple
concurrent programs, the behavior is not specified.
** TRIO file type
~trio_s~ is the the main type for TRIO files, visible to the users
of the library. This type is kept opaque, and all modifications to
the files will be necessarily done through the use of functions,
taking such a type as argument.
File creation and opening functions will return /TRIO file handles/,
namely pointers to ~trio_s~ types. All functions accessing to the
TRIO files will have as a first argument the TRIO file handle.
#+begin_src c :tangle trio.h
typedef struct trio_s trio_t;
#+end_src
#+begin_src c :tangle trio_s.h
struct trio_s {
char* file_name;
pthread_mutex_t thread_lock;
back_end_t back_end;
char mode;
char padding[7]; /* Ensures the proper alignment of back-ends */
};
#+end_src
** Polymorphism of the file handle
Polymorphism of the ~trio_t~ type is handled by ensuring that the
corresponding types for all back ends can be safely casted to
~trio_t~. This is done by making the back end structs start with
~struct trio_s~:
#+begin_src c
struct trio_back_end_s {
trio_t parent ;
/* add below specific back end data */
}
#+end_src
** File creation and opening
#+begin_src c :tangle trio.h
trio_t* trio_create(const char* file_name, back_end_t back_end);
#+end_src
#+begin_src c :tangle trio.c
trio_t* trio_create(const char* file_name, back_end_t back_end) {
/* Check that file name is not NULL or empty */
assert (file_name != NULL);
assert (file_name[0] != '\0');
/* Check that back_end is valid */
assert (back_end < TRIO_INVALID_BACK_END);
trio_t* result = NULL;
switch (back_end) {
case TRIO_TEXT:
result = (trio_t*) malloc (sizeof(trio_text_t));
break;
/*
case TRIO_HDF5:
result = (trio_t*) malloc (sizeof(trio_hdf5_t));
break;
case TRIO_JSON:
result = (trio_t*) malloc (sizeof(trio_json_t));
break;
,*/
default:
assert (1 == 0); /* Impossible case */
}
/* TODO: Error handling */
assert (result != NULL);
result->file_name = (char*) calloc(strlen(file_name)+1,sizeof(char));
strcpy(result->file_name, file_name);
result->back_end = back_end;
result->mode = 'w'; /* Upon creation, mode=write */
pthread_mutex_init ( &(result->thread_lock), NULL);
trio_exit_code rc = TRIO_FAILURE;
switch (back_end) {
case TRIO_TEXT:
rc = trio_text_init(result);
break;
/*
case TRIO_HDF5:
rc = trio_hdf5_init(result);
break;
case TRIO_JSON:
rc = trio_json_init(result);
break;
*/
default:
assert (1 == 0); /* Impossible case */
}
assert (rc == TRIO_SUCCESS);
return result;
}
#+end_src
** Reading/writing data
#+begin_src c :tangle trio.h
trio_exit_code trio_read_nucleus_num(trio_t* file, int64_t* num);
#+end_src
#+begin_src c :tangle trio.c
trio_exit_code trio_read_nucleus_num(trio_t* file, int64_t* num) {
if (file == NULL) return TRIO_FAILURE;
switch (file->back_end) {
case TRIO_TEXT:
return trio_text_read_nucleus_num(file, num);
break;
/*
case TRIO_HDF5:
return trio_hdf5_read_nucleus_num(file, num);
break;
case TRIO_JSON:
return trio_json_read_nucleus_num(file, num);
break;
*/
default:
return TRIO_FAILURE; /* Impossible case */
}
}
#+end_src
#+begin_src c :tangle trio.h
trio_exit_code trio_read_nucleus_coord(trio_t* file, double* coord);
#+end_src
#+begin_src c :tangle trio.c
trio_exit_code trio_read_nucleus_coord(trio_t* file, double* coord) {
if (file == NULL) return TRIO_FAILURE;
switch (file->back_end) {
case TRIO_TEXT:
return trio_text_read_nucleus_coord(file, coord);
break;
/*
case TRIO_HDF5:
return trio_hdf5_read_nucleus_coord(file, coord);
break;
case TRIO_JSON:
return trio_json_read_nucleus_coord(file, coord);
break;
*/
default:
return TRIO_FAILURE; /* Impossible case */
}
}
#+end_src
#+begin_src c :tangle trio.h
trio_exit_code trio_read_nucleus_charge(trio_t* file, double* charge);
#+end_src
#+begin_src c :tangle trio.c
trio_exit_code trio_read_nucleus_charge(trio_t* file, double* charge) {
if (file == NULL) return TRIO_FAILURE;
switch (file->back_end) {
case TRIO_TEXT:
return trio_text_read_nucleus_charge(file, charge);
break;
/*
case TRIO_HDF5:
return trio_hdf5_read_nucleus_charge(file, charge);
break;
case TRIO_JSON:
return trio_json_read_nucleus_charge(file, charge);
break;
*/
default:
return TRIO_FAILURE; /* Impossible case */
}
}
#+end_src
* Back ends
TRIO has multiple possible back ends:
- HDF5: The most efficient back-end, by default
- Text files: not to be used for production, but useful for debugging
- JSON: for portability
** TEXT Back end
#+begin_src c :tangle trio_text.h
typedef struct nucleus_s {
double* coord;
double* charge;
int64_t num;
} nucleus_t;
typedef struct electron_s {
int64_t alpha_num;
int64_t beta_num;
} electron_t;
typedef struct trio_text_s {
trio_t parent ;
char* nucleus_file_name;
char* electron_file_name;
} trio_text_t;
#+end_src
#+begin_src c :tangle trio_text.h
trio_exit_code trio_text_init(trio_t* file);
#+end_src
#+begin_src c :tangle trio_text.c
trio_exit_code trio_text_init(trio_t* file) {
trio_text_t* f = (trio_text_t*) file;
const char* nucleus_file_name = "/nucleus.txt";
f->nucleus_file_name = (char*)
calloc( strlen(file->file_name) + strlen(nucleus_file_name) + 1,
sizeof(char));
assert (f->nucleus_file_name != NULL);
strcat (f->nucleus_file_name, nucleus_file_name);
const char* electron_file_name = "/electron.txt";
f->nucleus_file_name = (char*)
calloc( strlen(file->file_name) + strlen(electron_file_name) + 1,
sizeof(char));
assert (f->nucleus_file_name != NULL);
strcat (f->nucleus_file_name, electron_file_name);
return TRIO_SUCCESS;
}
#+end_src
#+begin_src c :tangle trio_text.h
trio_exit_code trio_text_finalize(trio_t* file);
#+end_src
#+begin_src c :tangle trio_text.c
trio_exit_code trio_text_finalize(trio_t* file) {
trio_text_t* f = (trio_text_t*) file;
free (f->nucleus_file_name);
f->nucleus_file_name = NULL;
free (f->electron_file_name);
f->electron_file_name = NULL;
return TRIO_SUCCESS;
}
#+end_src
*** Read/write the nucleus struct
#+begin_src c :tangle trio_text.c
nucleus_t* trio_text_read_nucleus(const trio_text_t* file) {
/* Allocate the data structure */
nucleus_t* nucleus = (nucleus_t*) malloc(sizeof(nucleus_t));
assert (nucleus != NULL);
nucleus->num = 0;
nucleus->coord = NULL;
nucleus->charge = NULL;
/* Try to open the file. If the file does not exist, return */
FILE* f = fopen(file->nucleus_file_name,"r");
if (f == NULL) {
return nucleus;
}
/* Find size of file to allocate the max size of the string buffer */
fseek(f, 0L, SEEK_END);
size_t sz = ftell(f);
fseek(f, 0L, SEEK_SET);
char* buffer = (char*) malloc(sz*sizeof(char));
/* Read the dimensioning variables */
fscanf(f, "%s", buffer);
assert (strcmp(buffer, "num") == 0);
fscanf(f, "%ld", &(nucleus->num));
assert (nucleus->num > 0);
/* Allocate arrays */
nucleus->charge = (double*) calloc(nucleus->num, sizeof(double));
assert (nucleus->charge != NULL);
nucleus->coord = (double*) calloc(3 * nucleus->num, sizeof(double));
assert (nucleus->coord != NULL);
/* Read arrays */
fscanf(f, "%s", buffer);
assert (strcmp(buffer, "charge") == 0);
for (int i=0 ; i<nucleus->num ; i++) {
fscanf(f, "%lf", &(nucleus->charge[i]));
}
fscanf(f, "%s", buffer);
assert (strcmp(buffer, "coord") == 0);
for (int i=0 ; i<3*nucleus->num ; i++) {
fscanf(f, "%lf", &(nucleus->coord[i]));
}
free(buffer);
fclose(f);
return nucleus;
}
trio_exit_code trio_text_write_nucleus(const trio_text_t* file, nucleus_t* nucleus) {
assert (nucleus != NULL);
FILE* f = fopen(file->nucleus_file_name,"w");
assert (f != NULL);
/* Write the dimensioning variables */
fprintf(f, "num %ld\n", nucleus->num);
/* Write arrays */
fprintf(f, "charge\n");
for (int i=0 ; i<nucleus->num ; i++) {
fprintf(f, "%lf\n", nucleus->charge[i]);
}
fprintf(f, "coord\n");
for (int i=0 ; i<3*nucleus->num ; i++) {
fprintf(f, "%lf\n", nucleus->coord[i]);
}
fclose(f);
return TRIO_SUCCESS;
}
#+end_src
*** Free memory
Memory is allocated when reading. The followig function frees memory.
#+begin_src c :tangle trio_text.c
trio_exit_code trio_text_free_nucleus(nucleus_t* nucleus) {
if (nucleus == NULL) {
return TRIO_FAILURE;
}
if (nucleus->coord != NULL) {
free (nucleus->coord);
}
nucleus->coord = NULL;
if (nucleus->charge != NULL) {
free (nucleus->charge);
}
nucleus->charge = NULL;
free (nucleus);
return TRIO_SUCCESS;
}
#+end_src
*** Read/Write the num attribute
#+begin_src c :tangle trio_text.h
trio_exit_code trio_text_read_nucleus_num(const trio_t* file, int64_t* num);
trio_exit_code trio_text_write_nucleus_num(const trio_t* file, const int64_t num);
#+end_src
#+begin_src c :tangle trio_text.c
trio_exit_code trio_text_read_nucleus_num(const trio_t* file, int64_t* num) {
assert (file != NULL);
assert (num != NULL);
nucleus_t* nucleus = trio_text_read_nucleus((trio_text_t*) file);
if (nucleus == NULL) {
return TRIO_FAILURE;
}
/**/ *num = nucleus->num;
trio_text_free_nucleus(nucleus);
return TRIO_SUCCESS;
}
trio_exit_code trio_text_write_nucleus_num(const trio_t* file, const int64_t num) {
assert (num > 0L);
assert (file != NULL);
nucleus_t* nucleus = trio_text_read_nucleus((trio_text_t*) file);
assert (nucleus != NULL);
if (nucleus->num != num) {
nucleus->num = num;
if (nucleus->charge != NULL) free(nucleus->charge);
nucleus->charge = NULL;
nucleus->charge = (double*) calloc(num, sizeof(double));
assert (nucleus->charge != NULL);
if (nucleus->coord != NULL) free(nucleus->coord );
nucleus->coord = NULL;
nucleus->coord = (double*) calloc(3*num, sizeof(double));
assert (nucleus->coord != NULL);
} else {
nucleus->num = num;
}
trio_exit_code rc = trio_text_write_nucleus((trio_text_t*) file, nucleus);
assert (rc == TRIO_SUCCESS);
trio_text_free_nucleus(nucleus);
return TRIO_SUCCESS;
}
#+end_src
*** Read/Write the coord attribute
The ~coord~ array is assumed allocated with the appropriate size.
#+begin_src c :tangle trio_text.h
trio_exit_code trio_text_read_nucleus_coord(const trio_t* file, double* coord);
trio_exit_code trio_text_write_nucleus_coord(const trio_t* file, const double* coord);
#+end_src
#+begin_src c :tangle trio_text.c
trio_exit_code trio_text_read_nucleus_coord(const trio_t* file, double* coord) {
assert (file != NULL);
assert (file != NULL);
nucleus_t* nucleus = trio_text_read_nucleus((trio_text_t*) file);
if (nucleus == NULL) {
return TRIO_FAILURE;
}
assert (coord != NULL);
for (int i=0 ; i<3*nucleus->num ; i++) {
coord[i] = nucleus->coord[i];
}
trio_text_free_nucleus(nucleus);
return TRIO_SUCCESS;
}
trio_exit_code trio_text_write_nucleus_coord(const trio_t* file, const double* coord) {
assert (coord != NULL);
assert (file != NULL);
nucleus_t* nucleus = trio_text_read_nucleus((trio_text_t*) file);
assert (nucleus != NULL);
for (int i=0 ; i<3*nucleus->num ; i++) {
nucleus->coord[i] = coord[i];
}
trio_exit_code rc = trio_text_write_nucleus((trio_text_t*) file, nucleus);
assert (rc == TRIO_SUCCESS);
trio_text_free_nucleus(nucleus);
return TRIO_SUCCESS;
}
#+end_src
*** Read/Write the charge attribute
The ~charge~ array is assumed allocated with the appropriate size.
#+begin_src c :tangle trio_text.h
trio_exit_code trio_text_read_nucleus_charge(const trio_t* file, double* coord);
trio_exit_code trio_text_write_nucleus_charge(const trio_t* file, const double* coord);
#+end_src
#+begin_src c :tangle trio_text.c
trio_exit_code trio_text_read_nucleus_charge(const trio_t* file, double* charge) {
assert (file != NULL);
assert (file != NULL);
nucleus_t* nucleus = trio_text_read_nucleus((trio_text_t*)file);
if (nucleus == NULL) {
return TRIO_FAILURE;
}
assert (charge != NULL);
for (int i=0 ; i<nucleus->num ; i++) {
charge[i] = nucleus->charge[i];
}
trio_text_free_nucleus(nucleus);
return TRIO_SUCCESS;
}
trio_exit_code trio_text_write_nucleus_charge(const trio_t* file, const double* charge) {
assert (charge != NULL);
assert (file != NULL);
nucleus_t* nucleus = trio_text_read_nucleus((trio_text_t*)file);
assert (nucleus != NULL);
for (int i=0 ; i<nucleus->num ; i++) {
nucleus->charge[i] = charge[i];
}
trio_exit_code rc = trio_text_write_nucleus((trio_text_t*) file, nucleus);
assert (rc == TRIO_SUCCESS);
trio_text_free_nucleus(nucleus);
return TRIO_SUCCESS;
}
#+end_src
** HDF5 Back end
* File suffixes :noxport:
#+begin_src c :tangle trio.h
#endif
#+end_src
#+begin_src c :tangle trio_s.h
#endif
#+end_src
#+begin_src c :tangle trio_text.h
#endif
#+end_src
* TODO Things to be done :noexport:
- [ ] Thread safety
- [ ] Error handling with errno