C#
The C API uses an opaque type sphericart_calculator_t
to hold a reference to the
C++ implementation of a SphericalHarmonics
object. Several functions that mimic
the methods of the class can be called to compute spherical harmonics and their
derivatives.
/** @file example.c
* @brief Usage example for the C API
*/
#include "math.h"
#include "sphericart.h"
#include "stdio.h"
#include "stdlib.h"
int main(int argc, char* argv[]) {
/* ===== set up the calculation ===== */
// hard-coded parameters for the example
size_t n_samples = 10000;
size_t l_max = 10;
// initializes samples
double* xyz = malloc(n_samples * 3 * sizeof(double));
for (size_t i = 0; i < n_samples * 3; ++i) {
xyz[i] = (double)rand() / (double)RAND_MAX * 2.0 - 1.0;
}
// to avoid unnecessary allocations, the class assumes pre-allocated arrays
size_t sph_size = n_samples * (l_max + 1) * (l_max + 1);
double* sph = malloc(sph_size * sizeof(double));
size_t dsph_size = n_samples * 3 * (l_max + 1) * (l_max + 1);
double* dsph = malloc(dsph_size * sizeof(double));
size_t ddsph_size = n_samples * 9 * (l_max + 1) * (l_max + 1);
double* ddsph = malloc(ddsph_size * sizeof(double));
// float versions
float* xyz_f = malloc(n_samples * 3 * sizeof(float));
for (size_t i = 0; i < n_samples * 3; ++i) {
xyz_f[i] = xyz[i];
}
float* sph_f = malloc(sph_size * sizeof(float));
float* dsph_f = malloc(dsph_size * sizeof(float));
float* ddsph_f = malloc(ddsph_size * sizeof(float));
/* ===== API calls ===== */
// opaque pointer declaration: initializes buffers and numerical factors
sphericart_calculator_t* calculator = sphericart_new(l_max, 0);
// function calls
// without derivatives
sphericart_compute_array(calculator, xyz, 3 * n_samples, sph, sph_size);
// with derivatives
sphericart_compute_array_with_gradients(
calculator, xyz, 3 * n_samples, sph, sph_size, dsph, dsph_size
);
// with second derivatives
sphericart_compute_array_with_hessians(
calculator, xyz, 3 * n_samples, sph, sph_size, dsph, dsph_size, ddsph, ddsph_size
);
// per-sample calculation - we reuse the same arrays for simplicity, but
// only the first item is computed
sphericart_compute_sample(calculator, xyz, 3, sph, sph_size);
sphericart_compute_sample_with_gradients(calculator, xyz, 3, sph, sph_size, dsph, dsph_size);
sphericart_compute_sample_with_hessians(
calculator, xyz, 3, sph, sph_size, dsph, dsph_size, ddsph, ddsph_size
);
// float version
sphericart_calculator_f_t* calculator_f = sphericart_new_f(l_max, 0);
sphericart_compute_array_with_gradients_f(
calculator_f, xyz_f, 3 * n_samples, sph_f, sph_size, dsph_f, dsph_size
);
/* ===== check results ===== */
double sph_error = 0.0, sph_norm = 0.0;
for (size_t i = 0; i < n_samples * (l_max + 1) * (l_max + 1); ++i) {
sph_error += (sph_f[i] - sph[i]) * (sph_f[i] - sph[i]);
sph_norm += sph[i] * sph[i];
}
printf("Float vs double relative error: %12.8e\n", sqrt(sph_error / sph_norm));
/* ===== clean up ===== */
// frees up data arrays and sph object pointers
sphericart_delete(calculator);
free(xyz);
free(sph);
free(dsph);
sphericart_delete_f(calculator_f);
free(xyz_f);
free(sph_f);
free(dsph_f);
}