Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] C API #83

Draft
wants to merge 23 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
625ccb1
Start C API, able to generate metadata and set/get npts from primitiv…
wavefunction91 Sep 23, 2023
3cfb79a
Dox++
wavefunction91 Sep 24, 2023
1f70975
Merge branch 'master' into feature/c_api
wavefunction91 Sep 24, 2023
055d822
Added ability to generate and destroy quadratures, tested with Unifor…
wavefunction91 Sep 24, 2023
504312e
Minor refactor of C impls
wavefunction91 Sep 24, 2023
10a0da3
Cleanup state on intxx_quad_end if required
wavefunction91 Sep 24, 2023
cdd4d0e
Added C API for Gauss{Legendre,Lobatto}
wavefunction91 Sep 24, 2023
43d9e1b
Added C API for GaussChebyshev{1,2,2Modified,3}
wavefunction91 Sep 24, 2023
0af91e5
Radial name added to C API and tested
wavefunction91 Sep 24, 2023
ff0f04c
Added generation of Radial quadratures to C API, includes storage of …
wavefunction91 Sep 24, 2023
253ae5c
Added C_API tests to CTest
wavefunction91 Sep 24, 2023
8da6d79
[CI] Install Valgrind in CI container to enable mem tests for C API
wavefunction91 Sep 24, 2023
092e19d
Added a C API getter for named parameters, added path for radial quad…
wavefunction91 Sep 24, 2023
7c377ee
Added ext_param setters for C API, tested paths for radial quadratures
wavefunction91 Sep 24, 2023
e1cf8df
Ammend 8da6d79016b0a27e2d861e017cf51a5dc2fde3f7
wavefunction91 Sep 24, 2023
faf09f4
Ammend e1cf8df69fade401b1ff863ed410a08568318d36
wavefunction91 Sep 24, 2023
3d31ea4
Make C_API_MEMORY test contingent on valgrind discovery, disable in CI
wavefunction91 Sep 25, 2023
b326aef
Refactor C API source
wavefunction91 Sep 25, 2023
f0c21cb
Added dim info to C API, added additional meta data checks to C API UTs
wavefunction91 Sep 25, 2023
8c02fc5
Added parameter UTs for remainer of radial quadratures
wavefunction91 Sep 25, 2023
775eaf8
Starting exposure of angular grids to C API
wavefunction91 Sep 25, 2023
16b382b
Expose custom npts setters in C API for angular grids + UTs
wavefunction91 Sep 25, 2023
7b7c3c6
Check angular quadrature generation in C API
wavefunction91 Sep 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,41 @@ cmake_minimum_required( VERSION 3.17 ) # Require CMake 3.17+
project( IntegratorXX VERSION 1.2.0 LANGUAGES CXX )


add_library( integratorxx INTERFACE )
add_library( IntegratorXX::IntegratorXX ALIAS integratorxx )

#option( INTEGRATORXX_ENABLE_TESTS "Enable Tets" ON )
option( INTEGRATORXX_ENABLE_C_API "Enable C Bindings" ON )


if(INTEGRATORXX_ENABLE_C_API)
set( INTEGRATORXX_HEADER_ONLY FALSE )
enable_language(C)
add_subdirectory(src/c_api)
else()
# Header only if no C-API
set( INTEGRATORXX_HEADER_ONLY TRUE )
add_library( integratorxx INTERFACE )
endif()
add_library( IntegratorXX::IntegratorXX ALIAS integratorxx )



# Target features
target_compile_features( integratorxx INTERFACE cxx_std_17 )
if(INTEGRATORXX_HEADER_ONLY)
set(INTEGRATORXX_PROPERTY_TYPE INTERFACE)
else()
set(INTEGRATORXX_PROPERTY_TYPE PUBLIC)
endif()
target_compile_features( integratorxx ${INTEGRATORXX_PROPERTY_TYPE} cxx_std_17 )
target_include_directories( integratorxx
INTERFACE
${INTEGRATORXX_PROPERTY_TYPE}
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
)

include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-Wno-missing-braces" INTEGRATORXX_HAS_NO_MISSING_BRACES )
if( INTEGRATORXX_HAS_NO_MISSING_BRACES )
target_compile_options( integratorxx INTERFACE $<$<COMPILE_LANGUAGE:CXX>: -Wno-missing-braces> )
target_compile_options( integratorxx ${INTEGRATORXX_PROPERTY_TYPE} $<$<COMPILE_LANGUAGE:CXX>: -Wno-missing-braces> )
endif()


Expand Down
146 changes: 146 additions & 0 deletions include/integratorxx/c_api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#pragma once
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a good idea to use the standard C approach here, as #pragma once appears to be compiler dependent..

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a compiler doesn't support pragma once, the rest of the stack won't compile either. This is a conscious design decision. Show me a modern compiler that doesn't support pragma once, and we can reconsider that choice. From this list, it seems that everything that we can reasonably support supports this paradigm

https://en.m.wikipedia.org/wiki/Pragma_once

NB, This may preclude some embedded compilers/platforms, but the fact that we're doing dynamic memory management (i.e. calls to malloc/new) already precludes them - if there's a reason to target these platforms, we'd have to do a rather large overhaul of everything and pragma once would be the least of our problems.


/*** Error codes ***/
#define INTXX_SUCCESS 0
#define INTXX_INVALID_QUAD -1
#define INTXX_NULL_QUADPTR -2
#define INTXX_NULL_INFOPTR -3
#define INTXX_INVALID_OPT -4
#define INTXX_INVALID_ARG -5
#define INTXX_INVALID_OUT -5

/*** Quadrature Classes ***/
#define INTXX_PRM_QUAD 1
#define INTXX_RAD_QUAD 2
#define INTXX_ANG_QUAD 3
#define INDXX_SPH_QUAD 4

/*** Primitive Quadratures ***/
#define INTXX_PRMQ_MASK 0x0000FF
#define INTXX_PRMQ_UNIFORM 0x000001
#define INTXX_PRMQ_GAUSSLEG 0x000002
#define INTXX_PRMQ_GAUSSCHEB_1 0x000003
#define INTXX_PRMQ_GAUSSCHEB_2 0x000004
#define INTXX_PRMQ_GAUSSCHEB_2MOD 0x000005
#define INTXX_PRMQ_GAUSSCHEB_3 0x000006
#define INTXX_PRMQ_GAUSSLOB 0x000007

/*** Radial Quadratures ***/
#define INTXX_RADQ_MASK 0x00FF00
#define INTXX_RADQ_BECKE 0x000100 // Becke
#define INTXX_RADQ_MHL 0x000200 // Murray-Handy-Laming
#define INTXX_RADQ_TA 0x000300 // Treuter-Ahlrichs
#define INTXX_RADQ_MK 0x000400 // Mura-Knowles

/*** Angular (S2) Quadratures ***/
#define INTXX_ANGQ_MASK 0xFF0000
#define INTXX_ANGQ_LEB 0x010000 // Lebedev-Laikov
#define INTXX_ANGQ_DEL 0x020000 // Delley
#define INTXX_ANGQ_AB 0x030000 // Ahrens-Beylkin
#define INTXX_ANGQ_WOM 0x040000 // Womersley

#ifdef __cplusplus
extern "C" {
#endif

// Forward defs of types
struct intxx_quad_type;

typedef struct {
int n; ///< Number of parameters

const char** names; ///< Names of the params
const char** descriptions; ///< Long descriptions of params
const double *values; ///< Default values of params

//void (*set)(struct intxx_quad_type* p, const double** v);
///< Set function
} intxx_quad_params_type;

typedef struct {
int number; ///< Quadrature identifier
int kind; ///< Type of quadrature (PRM, RAD, ANG, SPH)

const char* name; ///< Name of the functional, e.g. "Becke"
// TODO References

intxx_quad_params_type ext_params; ///< External params

int (*generate)(struct intxx_quad_type* p);
int (*destroy) (struct intxx_quad_type* p);
} intxx_quad_info_type;

struct intxx_quad_type {
int npoints;
const intxx_quad_info_type* info;
void* _state; ///< Internal state, NOT FOR PUBLIC USE
};

typedef struct intxx_quad_type intxx_quad_type;



/**
* @brief Initialize a specified quadrature
*
* See error code returns for how to interpret failures.
*
* @param[out] p Quadrature instance of the specified type
* @param[in] quad Type of the specified quadrature
*
* @returns INTXX_SUCCESS: no errors were encountered
* INTXX_NULL_QUADPTR: `p == NULL`
* INTXX_INVALID_QUAD: `quad` is invalid
*/
int intxx_quad_init(intxx_quad_type* p, int quad);

/// Frees a quadrature instance. No throw gurantee
void intxx_quad_end (intxx_quad_type* p);

/**
* @brief Set the number of quadrature points
*
* Sets the number of nodes for the passed quadrature
* instance. Only sensible for quadratures in which
* the size is a free parameter (most).
*
* See error code returns for how to interpret failures.
*
* @param[out] p The quadrature for which to set npts.
* @param[in] npts The number of points
*
* @returns INTXX_SUCCESS: no errors were encountered
* INTXX_NULL_QUADPTR: `p == NULL`
* INTXX_NULL_INFOPTR: `p->info == NULL` (uninit)
* INTXX_INVALID_ARG: invalid npts (e.g. npts < 0)
*/
int intxx_quad_set_npts(intxx_quad_type* p, int npts);

/**
* @brief Retrieve the number of points for a quadrature
*
* Retreieves the number of grid points for a specified
* quadrature. In necessicary, this will be initialized
* from the default parameters, otherwise it will be
* read from p->npoints.
*
* See error code returns for how to interpret failures.
*
* @param[in] p The quadrature for which to get npts.
* @param[out] npts The number of points
*
* @returns INTXX_SUCCESS: no errors were encountered
* INTXX_NULL_QUADPTR: `p == NULL`
* INTXX_NULL_INFOPTR: `p->info == NULL` (uninit)
* INTXX_INVALID_ARG: `npts == NULL`
* INTXX_INVALID_OUT: `npts` is not valid (npts < 0)
*/
int intxx_quad_get_npts(intxx_quad_type* p, int* npts);


int intxx_generate_quad(intxx_quad_type* p);
int intxx_destroy_quad(intxx_quad_type* p);

#ifdef __cplusplus
}
#endif
1 change: 1 addition & 0 deletions src/c_api/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_library( integratorxx c_api.c c_radial.cxx )
109 changes: 109 additions & 0 deletions src/c_api/c_api.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#include "c_internal.h"
#include <stdlib.h>
#include <assert.h>



int intxx_quad_init(intxx_quad_type* p, int quad) {
// Local type defs
typedef intxx_quad_info_type info_type;

// Sanity check
if(p == NULL) return INTXX_NULL_QUADPTR;
p->info = NULL;
p->_state = NULL;
p->npoints = -1;

if(quad < 0) return INTXX_INVALID_QUAD;

// Determine quadrature class
int is_prmq = quad & INTXX_PRMQ_MASK;
int is_radq = quad & INTXX_RADQ_MASK;
int is_angq = quad & INTXX_ANGQ_MASK;
int is_sphq = is_radq && is_angq;

// Passed quadrature had to be something sane
if(!is_prmq && !is_radq && !is_angq)
return INTXX_INVALID_QUAD;

// Primitive quadratures cannot be mixed with angular or
// radial quadratures
if(is_prmq && is_radq) return INTXX_INVALID_QUAD;
if(is_prmq && is_angq) return INTXX_INVALID_QUAD;

// Get info
info_type* finfo = (info_type*)malloc(sizeof(info_type));
intxx_default_quad_info(finfo); // set (invalid) state
p->info = finfo;

int error;
if(is_prmq) {
// Get primitive quadrature info
error = intxx_get_prmq_info(finfo, quad);
} else if(is_sphq) {
// TODO: Get spherical quadrature info
} else if(is_radq) {
// TODO: Get radial quadrature info
} else {
// Angular by exclusion
// TODO: Get angular quadrature info
}

return error;
}

void intxx_quad_end(intxx_quad_type* p) {
// Stateless - just bail
if(p == NULL || p->info == NULL) return;

wavefunction91 marked this conversation as resolved.
Show resolved Hide resolved
// Destroy quadrature state if populated
intxx_destroy_quad(p);

// Free info
free((void*)p->info);
p->info = NULL;
}



int intxx_quad_set_npts(intxx_quad_type* p, int npts) {
if(p == NULL) return INTXX_NULL_QUADPTR;
if(p->info == NULL) return INTXX_NULL_INFOPTR;

// NPTS must be > 0
if(npts <= 0) return INTXX_INVALID_ARG;

// TODO: Handle the case when NPTS is derived from params
p->npoints = npts;
return INTXX_SUCCESS;
}

int intxx_quad_get_npts(intxx_quad_type* p, int* npts) {
if(p == NULL) return INTXX_NULL_QUADPTR;
if(p->info == NULL) return INTXX_NULL_INFOPTR;

// Return memory must be valid
if(npts == NULL) return INTXX_INVALID_ARG;

// TODO: Handle the case when NPTS is derived from params
*npts = p->npoints;
return *npts > 0 ? INTXX_SUCCESS : INTXX_INVALID_OUT;
}

int intxx_generate_quad(intxx_quad_type* p) {
if(p == NULL) return INTXX_NULL_QUADPTR;
if(p->info == NULL) return INTXX_NULL_INFOPTR;

if(p->info->generate)
return p->info->generate(p);
else return INTXX_SUCCESS;
}

int intxx_destroy_quad(intxx_quad_type* p) {
if(p == NULL) return INTXX_NULL_QUADPTR;
if(p->info == NULL) return INTXX_NULL_INFOPTR;

if(p->info->destroy)
return p->info->destroy(p);
else return INTXX_SUCCESS;
}
16 changes: 16 additions & 0 deletions src/c_api/c_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once
#include <integratorxx/c_api.h>

#ifdef __cplusplus
extern "C" {
#endif

void intxx_default_quad_info(intxx_quad_info_type* p);
int intxx_get_radq_info(intxx_quad_info_type* p, int quad);
int intxx_get_angq_info(intxx_quad_info_type* p, int quad);
int intxx_get_prmq_info(intxx_quad_info_type* p, int quad);

#ifdef __cplusplus
}
#endif

Loading