stardis-test

Test Stardis behaviors
git clone git://git.meso-star.fr/stardis-test.git
Log | Files | Refs | README | LICENSE

commit e55cfac6479bbda902b28103a7bc7d5a90cdc631
parent 9536d411e29aa3f31367f305ef5cee0da8d69771
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 22 Feb 2024 14:56:43 +0100

Define a project acronym

Update function names, structure names and file names for the coding
convention and acronym.

Diffstat:
M.gitignore | 4++--
MMakefile | 26++++++++++++--------------
MREADME.md | 4++--
Dsrc/prog_trilinear_profile.c | 248-------------------------------------------------------------------------------
Asrc/sadist.h | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sadist_lib_trilinear_profile.c | 248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sadist_probe_boundary.c | 272+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/stardis_test.h | 87-------------------------------------------------------------------------------
Dsrc/test_stardis_probe_boundary.c | 273-------------------------------------------------------------------------------
9 files changed, 625 insertions(+), 626 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -6,5 +6,5 @@ *.txt .config tags -test_* -!test_*.[ch] +sadist_* +!sadist_*.[ch] diff --git a/Makefile b/Makefile @@ -18,8 +18,7 @@ include config.mk -TESTS = test_stardis_probe_boundary -PROGS = libtriprof.so +TESTS = sadist_probe_boundary # Default target default: .config $(TESTS) @@ -33,28 +32,27 @@ default: .config $(TESTS) clean: rm -f .config sphere.stl sshape.stl scene.txt src/*.o src/*.d - rm -f $(PROGS) $(TESTS) + rm -f libsadist-triprof.so $(TESTS) -src/prog_trilinear_profile.o:\ +src/sadist_lib_trilinear_profile.o:\ config.mk\ - src/prog_trilinear_profile.c\ - src/stardis_test.h + src/sadist.h\ + src/sadist_lib_trilinear_profile.c $(CC) $(CFLAGS_SO) $(RSYS_CFLAGS) -c $(@:.o=.c) -o $@ -libtriprof.so: src/prog_trilinear_profile.o - $(CC) $(CFLAGS_SO) $(RSYS_CFLAGS) -o $@ src/prog_trilinear_profile.o \ +libsadist-triprof.so: src/sadist_lib_trilinear_profile.o + $(CC) $(CFLAGS_SO) $(RSYS_CFLAGS) -o $@ src/sadist_lib_trilinear_profile.o \ $(LDFLAGS_SO) $(RSYS_LIBS) - -src/test_stardis_probe_boundary.o:\ +src/sadist_probe_boundary.o:\ config.mk\ - src/test_stardis_probe_boundary.c\ - src/stardis_test.h + src/sadist.h\ + src/sadist_probe_boundary.c $(CC) $(CFLAGS_EXE) $(S3DUT_CFLAGS) $(RSYS_CFLAGS) -c $(@:.o=.c) -o $@ -test_stardis_probe_boundary: src/test_stardis_probe_boundary.o libtriprof.so +sadist_probe_boundary: src/sadist_probe_boundary.o libsadist-triprof.so $(CC) $(CFLAGS_EXE) $(S3DUT_CFLAGS) $(RSYS_CFLAGS) -o $@ src/$@.o \ $(LDFLAGS_EXE) $(S3DUT_LIBS) $(RSYS_LIBS) test: $(TESTS) - ./test_stardis_probe_boundary + ./sadist_probe_boundary diff --git a/README.md b/README.md @@ -1,6 +1,6 @@ -# Stardis Tests +# StArDIS Tests -Set of programs and that test the behavior of the +Set of programs that test the behavior of the [Stardis](https://gitlab.com/meso-star/stardis.git) program. ## License diff --git a/src/prog_trilinear_profile.c b/src/prog_trilinear_profile.c @@ -1,248 +0,0 @@ -/* Copyright (C) 2024 |Méso|Star> (contact@meso-star.com) - * - * 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 3 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 <http://www.gnu.org/licenses/>. */ - -#include "stardis_test.h" - -#include <stardis/stardis-prog-properties.h> - -#include <rsys/cstr.h> -#include <rsys/rsys.h> -#include <rsys/mem_allocator.h> - -#include <stdarg.h> /* va_list */ -#include <getopt.h> - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static void -log_err(const char* msg, ...) -{ - va_list vargs_list; - ASSERT(msg); - - va_start(vargs_list, msg); - vfprintf(stderr, msg, vargs_list); - va_end(vargs_list); -} - -static void -print_usage(FILE* stream, const char* name) -{ - fprintf(stream, -"usage: %s [-h] [-b lower_xyz,upper_xyz]\n" -" [-t max_Tx,max_Ty,max_Tz]\n", - name); -} - -static res_T -parse_spatial_range(struct trilinear_profile* profile, const char* str) -{ - double range[2] = {0, 0}; - size_t len = 0; - res_T res = RES_OK; - ASSERT(profile && str); - - res = cstr_to_list_double(str, ',', range, &len, 2); - if(res == RES_OK && len != 2) res = RES_BAD_ARG; - if(res != RES_OK) { - log_err("%s:%lu: unable to parse spatial range parameter `%s' -- %s\n", - __FILE__, __LINE__, str, res_to_cstr(res)); - goto error; - } - - if(range[0] >= range[1]) { - log_err("%s:%lu: invalid spatial range [%g, %g]\n", - __FILE__, __LINE__, range[0], range[1]); - res = RES_BAD_ARG; - goto error; - } - - profile->lower[0] = profile->lower[1] = profile->lower[2] = range[0]; - profile->upper[0] = profile->upper[1] = profile->upper[2] = range[1]; - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_max_temperatures(struct trilinear_profile* profile, const char* str) -{ - double abc[3] = {0, 0, 0}; - size_t len = 0; - res_T res = RES_OK; - ASSERT(profile && str); - - res = cstr_to_list_double(str, ',', abc, &len, 3); - if(res == RES_OK && len != 3) res = RES_BAD_ARG; - if(res != RES_OK) { - log_err("%s:%lu: unable to parse maximum temperatures `%s' -- %s\n", - __FILE__, __LINE__, str, res_to_cstr(res)); - goto error; - } - - if(abc[0] < 0 || abc[1] < 0 || abc[2] < 0) { - log_err - ("%s:%lu: invalid maximum temperatures (X = %g K, Y = %g K, Z = %g K)\n", - __FILE__, __LINE__, str, abc[0], abc[1], abc[2]); - res = RES_BAD_ARG; - goto error; - } - - profile->a[1] = abc[0]; - profile->b[1] = abc[1]; - profile->c[1] = abc[2]; - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_args - (const struct stardis_description_create_context* ctx, - struct trilinear_profile* profile, - int argc, - char* argv[]) -{ - int opt; - res_T res = RES_OK; - ASSERT(ctx && profile); - - optind = 1; - while((opt = getopt(argc, argv, "b:ht:")) != -1) { - switch(opt) { - case 'b': - res = parse_spatial_range(profile, optarg); - if(res != RES_OK) goto error; - break; - case 'h': - print_usage(stdout, ctx->name); - break; - case 't': - res = parse_max_temperatures(profile, optarg); - if(res != RES_OK) goto error; - break; - default: res = RES_BAD_ARG; break; - } - } - -exit: - return res; -error: - goto exit; -} - -/******************************************************************************* - * Legal notices - ******************************************************************************/ -const char* -get_copyright_notice(void* data) -{ - (void)data; /* Avoid "unused variable" warnings */ - return "Copyright (C) 2024 |Méso|Star> (contact@meso-star.com)"; -} - -const char* -get_license_short(void* data) -{ - (void)data; /* Avoid "unused variable" warnings */ - return "GNU GPL version 3 or later <http://www.gnu.org/licenses/>"; -} - -const char* -get_license_text(void* data) -{ - (void)data; /* Avoid "unused variable" warnings */ - return - "This is free software released under the GPL v3+ license: GNU GPL\n" - "version 3 or later. You are welcome to redistribute it under certain\n" - "conditions; refer to <http://www.gnu.org/licenses/> for details."; -} - -/******************************************************************************* - * Create data - ******************************************************************************/ -void* -stardis_create_data - (const struct stardis_description_create_context* ctx, - void* libdata, - size_t argc, - char* argv[]) -{ - struct trilinear_profile* profile = NULL; - res_T res = RES_OK; - (void)libdata; - - profile = mem_alloc(sizeof(*profile)); - if(!profile) { - log_err("%s:%lu: error allocating the trilinear profile.\n", - __FILE__, __LINE__); - goto error; - } - - *profile = TRILINEAR_PROFILE_NULL; - - res = parse_args(ctx, profile, (int)argc, argv); - if(res != RES_OK) goto error; - -exit: - return profile; -error: - if(profile) { - mem_rm(profile); - profile = NULL; - } - goto exit; -} - -void -stardis_release_data(void* data) -{ - ASSERT(data); - mem_rm(data); -} - -/******************************************************************************* - * Boundary condition - ******************************************************************************/ -double -stardis_boundary_temperature - (const struct stardis_interface_fragment* frag, - void* data) -{ - ASSERT(frag && data); - return trilinear_profile(data, frag->P); -} - -double* -stardis_t_range(void* data, double range[2]) -{ - struct trilinear_profile* profile = data; - ASSERT(data && range); - - range[0] = MMIN(profile->a[0], profile->a[1]); - range[0] = MMIN(MMIN(profile->b[0], profile->b[1]), range[0]); - range[0] = MMIN(MMIN(profile->c[0], profile->c[1]), range[0]); - - range[1] = MMAX(profile->a[0], profile->a[1]); - range[1] = MMAX(MMAX(profile->b[0], profile->b[1]), range[0]); - range[1] = MMAX(MMAX(profile->c[0], profile->c[1]), range[0]); - - return range; -} diff --git a/src/sadist.h b/src/sadist.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2024 |Méso|Star> (contact@meso-star.com) + * + * 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 3 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 <http://www.gnu.org/licenses/>. */ + +#ifndef SADIST_H +#define SADIST_H + +#include <rsys/rsys.h> +#include <errno.h> /* EINVAL */ + +struct sadist_trilinear_profile { + /* Spatial range in which the trilinear profile is defined */ + double lower[3]; + double upper[3]; + + double a[2]; /* Interpolated values along X */ + double b[2]; /* Interpolated values along Y */ + double c[2]; /* Interpolated values along Z */ +}; +#define SADIST_TRILINEAR_PROFILE_NULL__ {{0,0,0}, {0,0,0}, {0,0}, {0,0}, {0,0}} +static const struct sadist_trilinear_profile SADIST_TRILINEAR_PROFILE_NULL = + SADIST_TRILINEAR_PROFILE_NULL__; + +static INLINE int +sadist_trilinear_profile_check(const struct sadist_trilinear_profile* profile) +{ + ASSERT(profile); + if(profile->lower[0] >= profile->upper[0] + || profile->lower[1] >= profile->upper[1] + || profile->lower[2] >= profile->upper[2]) + return EINVAL; + + return 0; +} + +static INLINE double +sadist_trilinear_profile + (const struct sadist_trilinear_profile* profile, + const double p[3]) +{ + double u, v, w; + ASSERT(profile && p); + u = (p[0] - profile->lower[0]) / (profile->upper[0] - profile->lower[0]); + v = (p[1] - profile->lower[1]) / (profile->upper[1] - profile->lower[1]); + w = (p[2] - profile->lower[2]) / (profile->upper[2] - profile->lower[2]); + return u * (profile->a[1] - profile->a[0]) + profile->a[0] + + v * (profile->b[1] - profile->b[0]) + profile->b[0] + + w * (profile->c[1] - profile->c[0]) + profile->c[0]; +} + +static INLINE void +sadist_write_stl + (FILE* stream, + const double* positions, + const size_t nvertices, + const size_t* indices, + const size_t ntriangles) +{ + size_t itri; + (void)nvertices; + + fprintf(stream, "solid ascii\n"); + FOR_EACH(itri, 0, ntriangles) { + const double* v0 = positions + indices[itri*3+0]*3; + const double* v1 = positions + indices[itri*3+1]*3; + const double* v2 = positions + indices[itri*3+2]*3; + fprintf(stream, "facet normal 0 1 0\n"); + fprintf(stream, "\touter loop\n"); + fprintf(stream, "\t\tvertex %g %g %g\n", SPLIT3(v0)); + fprintf(stream, "\t\tvertex %g %g %g\n", SPLIT3(v1)); + fprintf(stream, "\t\tvertex %g %g %g\n", SPLIT3(v2)); + fprintf(stream, "\tendloop\n"); + fprintf(stream, "endfacet\n"); + } + fprintf(stream, "endsolid\n"); +} + +#endif /* SADIST_H */ diff --git a/src/sadist_lib_trilinear_profile.c b/src/sadist_lib_trilinear_profile.c @@ -0,0 +1,248 @@ +/* Copyright (C) 2024 |Méso|Star> (contact@meso-star.com) + * + * 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 3 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 <http://www.gnu.org/licenses/>. */ + +#include "sadist.h" + +#include <stardis/stardis-prog-properties.h> + +#include <rsys/cstr.h> +#include <rsys/rsys.h> +#include <rsys/mem_allocator.h> + +#include <stdarg.h> /* va_list */ +#include <getopt.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +log_err(const char* msg, ...) +{ + va_list vargs_list; + ASSERT(msg); + + va_start(vargs_list, msg); + vfprintf(stderr, msg, vargs_list); + va_end(vargs_list); +} + +static void +print_usage(FILE* stream, const char* name) +{ + fprintf(stream, +"usage: %s [-h] [-b lower_xyz,upper_xyz]\n" +" [-t max_Tx,max_Ty,max_Tz]\n", + name); +} + +static res_T +parse_spatial_range(struct sadist_trilinear_profile* profile, const char* str) +{ + double range[2] = {0, 0}; + size_t len = 0; + res_T res = RES_OK; + ASSERT(profile && str); + + res = cstr_to_list_double(str, ',', range, &len, 2); + if(res == RES_OK && len != 2) res = RES_BAD_ARG; + if(res != RES_OK) { + log_err("%s:%lu: unable to parse spatial range parameter `%s' -- %s\n", + __FILE__, __LINE__, str, res_to_cstr(res)); + goto error; + } + + if(range[0] >= range[1]) { + log_err("%s:%lu: invalid spatial range [%g, %g]\n", + __FILE__, __LINE__, range[0], range[1]); + res = RES_BAD_ARG; + goto error; + } + + profile->lower[0] = profile->lower[1] = profile->lower[2] = range[0]; + profile->upper[0] = profile->upper[1] = profile->upper[2] = range[1]; + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_max_temperatures(struct sadist_trilinear_profile* profile, const char* str) +{ + double abc[3] = {0, 0, 0}; + size_t len = 0; + res_T res = RES_OK; + ASSERT(profile && str); + + res = cstr_to_list_double(str, ',', abc, &len, 3); + if(res == RES_OK && len != 3) res = RES_BAD_ARG; + if(res != RES_OK) { + log_err("%s:%lu: unable to parse maximum temperatures `%s' -- %s\n", + __FILE__, __LINE__, str, res_to_cstr(res)); + goto error; + } + + if(abc[0] < 0 || abc[1] < 0 || abc[2] < 0) { + log_err + ("%s:%lu: invalid maximum temperatures (X = %g K, Y = %g K, Z = %g K)\n", + __FILE__, __LINE__, str, abc[0], abc[1], abc[2]); + res = RES_BAD_ARG; + goto error; + } + + profile->a[1] = abc[0]; + profile->b[1] = abc[1]; + profile->c[1] = abc[2]; + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_args + (const struct stardis_description_create_context* ctx, + struct sadist_trilinear_profile* profile, + int argc, + char* argv[]) +{ + int opt; + res_T res = RES_OK; + ASSERT(ctx && profile); + + optind = 1; + while((opt = getopt(argc, argv, "b:ht:")) != -1) { + switch(opt) { + case 'b': + res = parse_spatial_range(profile, optarg); + if(res != RES_OK) goto error; + break; + case 'h': + print_usage(stdout, ctx->name); + break; + case 't': + res = parse_max_temperatures(profile, optarg); + if(res != RES_OK) goto error; + break; + default: res = RES_BAD_ARG; break; + } + } + +exit: + return res; +error: + goto exit; +} + +/******************************************************************************* + * Legal notices + ******************************************************************************/ +const char* +get_copyright_notice(void* data) +{ + (void)data; /* Avoid "unused variable" warnings */ + return "Copyright (C) 2024 |Méso|Star> (contact@meso-star.com)"; +} + +const char* +get_license_short(void* data) +{ + (void)data; /* Avoid "unused variable" warnings */ + return "GNU GPL version 3 or later <http://www.gnu.org/licenses/>"; +} + +const char* +get_license_text(void* data) +{ + (void)data; /* Avoid "unused variable" warnings */ + return + "This is free software released under the GPL v3+ license: GNU GPL\n" + "version 3 or later. You are welcome to redistribute it under certain\n" + "conditions; refer to <http://www.gnu.org/licenses/> for details."; +} + +/******************************************************************************* + * Create data + ******************************************************************************/ +void* +stardis_create_data + (const struct stardis_description_create_context* ctx, + void* libdata, + size_t argc, + char* argv[]) +{ + struct sadist_trilinear_profile* profile = NULL; + res_T res = RES_OK; + (void)libdata; + + profile = mem_alloc(sizeof(*profile)); + if(!profile) { + log_err("%s:%lu: error allocating the trilinear profile.\n", + __FILE__, __LINE__); + goto error; + } + + *profile = SADIST_TRILINEAR_PROFILE_NULL; + + res = parse_args(ctx, profile, (int)argc, argv); + if(res != RES_OK) goto error; + +exit: + return profile; +error: + if(profile) { + mem_rm(profile); + profile = NULL; + } + goto exit; +} + +void +stardis_release_data(void* data) +{ + ASSERT(data); + mem_rm(data); +} + +/******************************************************************************* + * Boundary condition + ******************************************************************************/ +double +stardis_boundary_temperature + (const struct stardis_interface_fragment* frag, + void* data) +{ + ASSERT(frag && data); + return sadist_trilinear_profile(data, frag->P); +} + +double* +stardis_t_range(void* data, double range[2]) +{ + struct sadist_trilinear_profile* profile = data; + ASSERT(data && range); + + range[0] = MMIN(profile->a[0], profile->a[1]); + range[0] = MMIN(MMIN(profile->b[0], profile->b[1]), range[0]); + range[0] = MMIN(MMIN(profile->c[0], profile->c[1]), range[0]); + + range[1] = MMAX(profile->a[0], profile->a[1]); + range[1] = MMAX(MMAX(profile->b[0], profile->b[1]), range[1]); + range[1] = MMAX(MMAX(profile->c[0], profile->c[1]), range[1]); + + return range; +} diff --git a/src/sadist_probe_boundary.c b/src/sadist_probe_boundary.c @@ -0,0 +1,272 @@ +/* Copyright (C) 2024 |Méso|Star> (contact@meso-star.com) + * + * 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 3 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 <http://www.gnu.org/licenses/>. */ + +#define _POSIX_C_SOURCE 200112L /* popen */ + +#include "sadist.h" + +#include <stardis/stardis-prog-properties.h> + +#include <star/s3dut.h> + +#include <rsys/double2.h> +#include <rsys/double3.h> +#include <rsys/math.h> +#include <rsys/mem_allocator.h> + +#include <errno.h> +#include <float.h> +#include <string.h> /* strerror */ + +/* Axis Aligned Bounding Box */ +struct aabb { + double lower[3]; + double upper[3]; +}; +#define AABB_NULL__ {{DBL_MAX,DBL_MAX,DBL_MAX}, {-DBL_MAX,-DBL_MAX,-DBL_MAX}} +static const struct aabb AABB_NULL = AABB_NULL__; + +/* + * The system is a trilinear profile of the temperature at steady state, i.e. at + * each point of the system we can calculate the temperature analytically. Two + * forms are immersed in this temperature field: a super shape and a sphere + * included in the super shape. On the Monte Carlo side, the temperature is + * unknown everywhere except on the surface of the super shape whose + * temperature is defined from the aformentionned trilinear profile. We will + * estimate the temperature at the sphere boundary at a probe points. We + * should find by Monte Carlo the temperature of the trilinear profile at the + * position of the probe. It's the test. + * + * /\ <-- T(x,y,z) + * ___/ \___ + * T(z) \ __ / + * | T(y) \ / \ / + * |/ T=? *__/ \ + * o--- T(x) /_ __ _\ + * \/ \/ + */ + +#define FILENAME_SSHAPE "sshape.stl" +#define FILENAME_SPHERE "sphere.stl" +#define FILENAME_SCENE "scene.txt" + +/* Temperature at the upper bound of the X, Y and Z axis. The temperature at the + * lower bound is implicitly 0 K */ +#define TX 333.0 /* [K] */ +#define TY 432.0 /* [K] */ +#define TZ 579.0 /* [K] */ + +/* Probe position */ +#define PX 1.0 +#define PY 0.0 +#define PZ 0.0 + +/* The executed command */ +#define COMMAND "stardis -V3 -P "STR(PX)","STR(PY)","STR(PZ)" -M "FILENAME_SCENE + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +aabb_update(struct aabb* aabb, const struct s3dut_mesh_data* mesh) +{ + size_t ivertex = 0; + ASSERT(aabb); + + FOR_EACH(ivertex, 0, mesh->nvertices) { + const double* vertex = mesh->positions + ivertex*3; + aabb->lower[0] = MMIN(aabb->lower[0], vertex[0]); + aabb->lower[1] = MMIN(aabb->lower[1], vertex[1]); + aabb->lower[2] = MMIN(aabb->lower[2], vertex[2]); + aabb->upper[0] = MMAX(aabb->upper[0], vertex[0]); + aabb->upper[1] = MMAX(aabb->upper[1], vertex[1]); + aabb->upper[2] = MMAX(aabb->upper[2], vertex[2]); + } +} + +static void +setup_sshape(FILE* stream, struct aabb* aabb) +{ + struct s3dut_mesh* sshape = NULL; + struct s3dut_mesh_data sshape_data; + struct s3dut_super_formula f0 = S3DUT_SUPER_FORMULA_NULL; + struct s3dut_super_formula f1 = S3DUT_SUPER_FORMULA_NULL; + const double radius = 2; + const unsigned nslices = 256; + + f0.A = 1.5; f0.B = 1; f0.M = 11.0; f0.N0 = 1; f0.N1 = 1; f0.N2 = 2.0; + f1.A = 1.0; f1.B = 2; f1.M = 3.6; f1.N0 = 1; f1.N1 = 2; f1.N2 = 0.7; + S3DUT(create_super_shape(NULL, &f0, &f1, radius, nslices, nslices/2, &sshape)); + S3DUT(mesh_get_data(sshape, &sshape_data)); + + aabb_update(aabb, &sshape_data); + sadist_write_stl(stream, sshape_data.positions, sshape_data.nvertices, + sshape_data.indices, sshape_data.nprimitives); + + S3DUT(mesh_ref_put(sshape)); +} + +static void +setup_sphere(FILE* stream, struct aabb* aabb) +{ + struct s3dut_mesh* sphere = NULL; + struct s3dut_mesh_data sphere_data; + const double radius = 1; + const unsigned nslices = 128; + + S3DUT(create_sphere(NULL, radius, nslices, nslices/2, &sphere)); + S3DUT(mesh_get_data(sphere, &sphere_data)); + + aabb_update(aabb, &sphere_data); + sadist_write_stl(stream, sphere_data.positions, sphere_data.nvertices, + sphere_data.indices, sphere_data.nprimitives); + + S3DUT(mesh_ref_put(sphere)); +} + +static void +setup_scene + (FILE* fp, + const char* sshape, + const char* sphere, + const struct aabb* aabb, + struct sadist_trilinear_profile* profile) +{ + double low, upp; + ASSERT(sshape && sphere && aabb && profile); + + fprintf(fp, "PROGRAM trilinear_profile libsadist-triprof.so\n"); + fprintf(fp, "SOLID SuperShape 25 7500 500 0.05 0 UNKNOWN 0 BACK %s FRONT %s\n", + sshape, sphere); + fprintf(fp, "SOLID Sphere 25 7500 500 0.05 0 UNKNOWN 0 BACK %s\n", sphere); + + low = MMIN(MMIN(aabb->lower[0], aabb->lower[1]), aabb->lower[2]); + upp = MMAX(MMAX(aabb->upper[0], aabb->upper[1]), aabb->upper[2]); + fprintf(fp, "T_BOUNDARY_FOR_SOLID_PROG Dirichlet trilinear_profile %s", sshape); + fprintf(fp, " PROG_PARAMS dummy -b %g,%g -t %g,%g,%g\n", low, upp, TX, TY, TZ); + + d3_splat(profile->lower, low); + d3_splat(profile->upper, upp); + d2(profile->a, 0, TX); + d2(profile->b, 0, TY); + d2(profile->c, 0, TZ); +} + +static int +init(struct sadist_trilinear_profile* profile) +{ + struct aabb aabb = AABB_NULL; + FILE* fp_sshape = NULL; + FILE* fp_sphere = NULL; + FILE* fp_scene = NULL; + int err = 0; + + if((fp_sshape = fopen(FILENAME_SSHAPE, "w")) == NULL) { + fprintf(stderr, "Error opening the `"FILENAME_SSHAPE"' file -- %s\n", + strerror(errno)); + err = errno; + goto error; + } + if((fp_sphere = fopen(FILENAME_SPHERE, "w")) == NULL) { + fprintf(stderr, "Error opening the `"FILENAME_SPHERE"' file -- %s\n", + strerror(errno)); + err = errno; + goto error; + } + if((fp_scene = fopen(FILENAME_SCENE, "w")) == NULL) { + fprintf(stderr, "Error opening the `"FILENAME_SCENE"' file -- %s\n", + strerror(errno)); + err = errno; + goto error; + } + + setup_sshape(fp_sshape, &aabb); + setup_sphere(fp_sphere, &aabb); + setup_scene(fp_scene, FILENAME_SSHAPE, FILENAME_SPHERE, &aabb, profile); + +exit: + if(fp_sshape && fclose(fp_sshape)) { perror("fclose"); if(!err) err = errno; } + if(fp_sphere && fclose(fp_sphere)) { perror("fclose"); if(!err) err = errno; } + if(fp_scene && fclose(fp_scene)) { perror("fclose"); if(!err) err = errno; } + return err; +error: + goto exit; +} + +static int +run(const struct sadist_trilinear_profile* profile) +{ + const double P[3] = {PX, PY, PZ}; + FILE* output = NULL; + double ref = 0; + double E = 0; + double SE = 0; + int n = 0; + int err = 0; + + printf(COMMAND"\n"); + + if(!(output = popen(COMMAND, "r"))) { + fprintf(stderr, "Error executing stardis -- %s\n", strerror(errno)); + fprintf(stderr, "\t"COMMAND"\n"); + err = errno; + goto error; + } + + if((n = fscanf(output, "%lf %lf", &E, &SE)), n != 2 && n != EOF) { + fprintf(stderr, "Error reading the output stream -- %s\n", strerror(errno)); + err = errno; + goto error; + } + + /* Check command exit status */ + if((err = pclose(output))) goto error; + + ref = sadist_trilinear_profile(profile, P); + printf("T = %g ~ %g +/- %g\n", ref, E, SE); + if(!eq_eps(ref, E, SE*3)) { + fprintf(stderr, "Test failed\n"); + err = 1; + goto error; + } + +exit: + return err; +error: + goto exit; +} + +/******************************************************************************* + * The test + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct sadist_trilinear_profile profile = SADIST_TRILINEAR_PROFILE_NULL; + int err = 0; + (void)argc, (void)argv; + + if((err = init(&profile))) goto error; + if((err = run(&profile))) goto error; + +exit: + if(mem_allocated_size() != 0) { + fprintf(stderr, "Memory leaks: %lu bytes\n", mem_allocated_size()); + if(!err) err = -1; + } + return err; +error: + goto exit; +} diff --git a/src/stardis_test.h b/src/stardis_test.h @@ -1,87 +0,0 @@ -/* Copyright (C) 2024 |Méso|Star> (contact@meso-star.com) - * - * 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 3 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 <http://www.gnu.org/licenses/>. */ - -#ifndef STARDIS_TEST_H -#define STARDIS_TEST_H - -#include <rsys/rsys.h> -#include <errno.h> /* EINVAL */ - -struct trilinear_profile { - /* Spatial range in which the trilinear profile is defined */ - double lower[3]; - double upper[3]; - - double a[2]; /* Interpolated values along X */ - double b[2]; /* Interpolated values along Y */ - double c[2]; /* Interpolated values along Z */ -}; -#define TRILINEAR_PROFILE_NULL__ {{0,0,0}, {0,0,0}, {0,0}, {0,0}, {0,0}} -static const struct trilinear_profile TRILINEAR_PROFILE_NULL = - TRILINEAR_PROFILE_NULL__; - -static INLINE int -check_trilinear_profile(const struct trilinear_profile* profile) -{ - ASSERT(profile); - if(profile->lower[0] >= profile->upper[0] - || profile->lower[1] >= profile->upper[1] - || profile->lower[2] >= profile->upper[2]) - return EINVAL; - - return 0; -} - -static INLINE double -trilinear_profile(const struct trilinear_profile* profile, const double p[3]) -{ - double u, v, w; - ASSERT(profile && p); - u = (p[0] - profile->lower[0]) / (profile->upper[0] - profile->lower[0]); - v = (p[1] - profile->lower[1]) / (profile->upper[1] - profile->lower[1]); - w = (p[2] - profile->lower[2]) / (profile->upper[2] - profile->lower[2]); - return u * (profile->a[1] - profile->a[0]) + profile->a[0] - + v * (profile->b[1] - profile->b[0]) + profile->b[0] - + w * (profile->c[1] - profile->c[0]) + profile->c[0]; -} - -static INLINE void -write_stl - (FILE* stream, - const double* positions, - const size_t nvertices, - const size_t* indices, - const size_t ntriangles) -{ - size_t itri; - (void)nvertices; - - fprintf(stream, "solid ascii\n"); - FOR_EACH(itri, 0, ntriangles) { - const double* v0 = positions + indices[itri*3+0]*3; - const double* v1 = positions + indices[itri*3+1]*3; - const double* v2 = positions + indices[itri*3+2]*3; - fprintf(stream, "facet normal 0 1 0\n"); - fprintf(stream, "\touter loop\n"); - fprintf(stream, "\t\tvertex %g %g %g\n", SPLIT3(v0)); - fprintf(stream, "\t\tvertex %g %g %g\n", SPLIT3(v1)); - fprintf(stream, "\t\tvertex %g %g %g\n", SPLIT3(v2)); - fprintf(stream, "\tendloop\n"); - fprintf(stream, "endfacet\n"); - } - fprintf(stream, "endsolid\n"); -} - -#endif /* STARDIS_TEST_H */ diff --git a/src/test_stardis_probe_boundary.c b/src/test_stardis_probe_boundary.c @@ -1,273 +0,0 @@ -/* Copyright (C) 2024 |Méso|Star> (contact@meso-star.com) - * - * 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 3 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 <http://www.gnu.org/licenses/>. */ - -#define _POSIX_C_SOURCE 200112L /* popen */ - -#include "stardis_test.h" - -#include <stardis/stardis-prog-properties.h> - -#include <star/s3dut.h> - -#include <rsys/double2.h> -#include <rsys/double3.h> -#include <rsys/math.h> -#include <rsys/mem_allocator.h> - -#include <errno.h> -#include <float.h> -#include <string.h> /* strerror */ - -/* Axis Aligned Bounding Box */ -struct aabb { - double lower[3]; - double upper[3]; -}; -#define AABB_NULL__ {{DBL_MAX,DBL_MAX,DBL_MAX}, {-DBL_MAX,-DBL_MAX,-DBL_MAX}} -static const struct aabb AABB_NULL = AABB_NULL__; - -/* - * The system is a trilinear profile of the temperature at steady state, i.e. at - * each point of the system we can calculate the temperature analytically. Two - * forms are immersed in this temperature field: a super shape and a sphere - * included in the super shape. On the Monte Carlo side, the temperature is - * unknown everywhere except on the surface of the super shape whose - * temperature is defined from the aformentionned trilinear profile. We will - * estimate the temperature at the sphere boundary at a probe points. We - * should find by Monte Carlo the temperature of the trilinear profile at the - * position of the probe. It's the test. - * - * /\ <-- T(x,y,z) - * ___/ \___ - * T(z) \ __ / - * | T(y) \ / \ / - * |/ T=? *__/ \ - * o--- T(x) /_ __ _\ - * \/ \/ - */ - -#define FILENAME_SSHAPE "sshape.stl" -#define FILENAME_SPHERE "sphere.stl" -#define FILENAME_SCENE "scene.txt" - -/* Temperature at the upper bound of the X, Y and Z axis. The temperature at the - * lower bound is implicitly 0 K */ -#define TX 333.0 /* [K] */ -#define TY 432.0 /* [K] */ -#define TZ 579.0 /* [K] */ - -/* Probe position */ -#define PX 1.0 -#define PY 0.0 -#define PZ 0.0 - -/* The executed command */ -#define COMMAND "stardis -V3 -P "STR(PX)","STR(PY)","STR(PZ)" -M "FILENAME_SCENE - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static void -aabb_update(struct aabb* aabb, const struct s3dut_mesh_data* mesh) -{ - size_t ivertex = 0; - ASSERT(aabb); - - FOR_EACH(ivertex, 0, mesh->nvertices) { - const double* vertex = mesh->positions + ivertex*3; - aabb->lower[0] = MMIN(aabb->lower[0], vertex[0]); - aabb->lower[1] = MMIN(aabb->lower[1], vertex[1]); - aabb->lower[2] = MMIN(aabb->lower[2], vertex[2]); - aabb->upper[0] = MMAX(aabb->upper[0], vertex[0]); - aabb->upper[1] = MMAX(aabb->upper[1], vertex[1]); - aabb->upper[2] = MMAX(aabb->upper[2], vertex[2]); - } -} - -static void -setup_sshape(FILE* stream, struct aabb* aabb) -{ - struct s3dut_mesh* sshape = NULL; - struct s3dut_mesh_data sshape_data; - struct s3dut_super_formula f0 = S3DUT_SUPER_FORMULA_NULL; - struct s3dut_super_formula f1 = S3DUT_SUPER_FORMULA_NULL; - const double radius = 2; - const unsigned nslices = 256; - - f0.A = 1.5; f0.B = 1; f0.M = 11.0; f0.N0 = 1; f0.N1 = 1; f0.N2 = 2.0; - f1.A = 1.0; f1.B = 2; f1.M = 3.6; f1.N0 = 1; f1.N1 = 2; f1.N2 = 0.7; - S3DUT(create_super_shape(NULL, &f0, &f1, radius, nslices, nslices/2, &sshape)); - S3DUT(mesh_get_data(sshape, &sshape_data)); - - aabb_update(aabb, &sshape_data); - write_stl(stream, sshape_data.positions, sshape_data.nvertices, - sshape_data.indices, sshape_data.nprimitives); - - S3DUT(mesh_ref_put(sshape)); -} - -static void -setup_sphere(FILE* stream, struct aabb* aabb) -{ - struct s3dut_mesh* sphere = NULL; - struct s3dut_mesh_data sphere_data; - const double radius = 1; - const unsigned nslices = 128; - - S3DUT(create_sphere(NULL, radius, nslices, nslices/2, &sphere)); - S3DUT(mesh_get_data(sphere, &sphere_data)); - - aabb_update(aabb, &sphere_data); - write_stl(stream, sphere_data.positions, sphere_data.nvertices, - sphere_data.indices, sphere_data.nprimitives); - - S3DUT(mesh_ref_put(sphere)); -} - -static void -setup_scene - (FILE* fp, - const char* sshape, - const char* sphere, - const struct aabb* aabb, - struct trilinear_profile* profile) -{ - double low, upp; - ASSERT(sshape && sphere && aabb && profile); - - fprintf(fp, "PROGRAM trilinear_profile libtriprof.so\n"); - fprintf(fp, "SOLID SuperShape 25 7500 500 0.05 0 UNKNOWN 0 BACK %s FRONT %s\n", - sshape, sphere); - fprintf(fp, "SOLID Sphere 25 7500 500 0.05 0 UNKNOWN 0 BACK %s\n", sphere); - - low = MMIN(MMIN(aabb->lower[0], aabb->lower[1]), aabb->lower[2]); - upp = MMAX(MMAX(aabb->upper[0], aabb->upper[1]), aabb->upper[2]); - fprintf(fp, "T_BOUNDARY_FOR_SOLID_PROG Dirichlet trilinear_profile %s", sshape); - fprintf(fp, " PROG_PARAMS dummy -b %g,%g -t %g,%g,%g\n", low, upp, TX, TY, TZ); - - d3_splat(profile->lower, low); - d3_splat(profile->upper, upp); - d2(profile->a, 0, TX); - d2(profile->b, 0, TY); - d2(profile->c, 0, TZ); - -} - -static int -init(struct trilinear_profile* profile) -{ - struct aabb aabb = AABB_NULL; - FILE* fp_sshape = NULL; - FILE* fp_sphere = NULL; - FILE* fp_scene = NULL; - int err = 0; - - if((fp_sshape = fopen(FILENAME_SSHAPE, "w")) == NULL) { - fprintf(stderr, "Error opening the `"FILENAME_SSHAPE"' file -- %s\n", - strerror(errno)); - err = errno; - goto error; - } - if((fp_sphere = fopen(FILENAME_SPHERE, "w")) == NULL) { - fprintf(stderr, "Error opening the `"FILENAME_SPHERE"' file -- %s\n", - strerror(errno)); - err = errno; - goto error; - } - if((fp_scene = fopen(FILENAME_SCENE, "w")) == NULL) { - fprintf(stderr, "Error opening the `"FILENAME_SCENE"' file -- %s\n", - strerror(errno)); - err = errno; - goto error; - } - - setup_sshape(fp_sshape, &aabb); - setup_sphere(fp_sphere, &aabb); - setup_scene(fp_scene, FILENAME_SSHAPE, FILENAME_SPHERE, &aabb, profile); - -exit: - if(fp_sshape && fclose(fp_sshape)) { perror("fclose"); if(!err) err = errno; } - if(fp_sphere && fclose(fp_sphere)) { perror("fclose"); if(!err) err = errno; } - if(fp_scene && fclose(fp_scene)) { perror("fclose"); if(!err) err = errno; } - return err; -error: - goto exit; -} - -static int -run(const struct trilinear_profile* profile) -{ - const double P[3] = {PX, PY, PZ}; - FILE* output = NULL; - double ref = 0; - double E = 0; - double SE = 0; - int n = 0; - int err = 0; - - printf(COMMAND"\n"); - - if(!(output = popen(COMMAND, "r"))) { - fprintf(stderr, "Error executing stardis -- %s\n", strerror(errno)); - fprintf(stderr, "\t"COMMAND"\n"); - err = errno; - goto error; - } - - if((n = fscanf(output, "%lf %lf", &E, &SE)), n != 2 && n != EOF) { - fprintf(stderr, "Error reading the output stream -- %s\n", strerror(errno)); - err = errno; - goto error; - } - - /* Check command exit status */ - if((err = pclose(output))) goto error; - - ref = trilinear_profile(profile, P); - printf("T = %g ~ %g +/- %g\n", ref, E, SE); - if(!eq_eps(ref, E, SE*3)) { - fprintf(stderr, "Test failed\n"); - err = 1; - goto error; - } - -exit: - return err; -error: - goto exit; -} - -/******************************************************************************* - * The test - ******************************************************************************/ -int -main(int argc, char** argv) -{ - struct trilinear_profile profile = TRILINEAR_PROFILE_NULL; - int err = 0; - (void)argc, (void)argv; - - if((err = init(&profile))) goto error; - if((err = run(&profile))) goto error; - -exit: - if(mem_allocated_size() != 0) { - fprintf(stderr, "Memory leaks: %lu bytes\n", mem_allocated_size()); - if(!err) err = -1; - } - return err; -error: - goto exit; -}