commit e03b02486597aabc4ffaa48edeffca7182fcbd5e
parent e9f711caabd8d9bc9b36ab208033b91db40ed7c7
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 23 Feb 2024 18:19:42 +0100
Test the resolution of several boundary probes
The sadist_probe_boundary test now offers an option for defining the
number of probe points to be resolved. When this is greater than 1,
invoke stardis with the -L option to define a list of probe points to be
resolved.
Diffstat:
2 files changed, 196 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile
@@ -52,7 +52,8 @@ src/sadist_probe_boundary.o:\
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)
+ $(LDFLAGS_EXE) $(S3DUT_LIBS) $(RSYS_LIBS) -lm
test: $(TESTS)
./sadist_probe_boundary
+ ./sadist_probe_boundary -p 4
diff --git a/src/sadist_probe_boundary.c b/src/sadist_probe_boundary.c
@@ -21,6 +21,7 @@
#include <star/s3dut.h>
+#include <rsys/cstr.h>
#include <rsys/double2.h>
#include <rsys/double3.h>
#include <rsys/math.h>
@@ -28,6 +29,7 @@
#include <errno.h>
#include <float.h>
+#include <getopt.h>
#include <string.h> /* strerror */
/* Axis Aligned Bounding Box */
@@ -38,6 +40,13 @@ struct aabb {
#define AABB_NULL__ {{DBL_MAX,DBL_MAX,DBL_MAX}, {-DBL_MAX,-DBL_MAX,-DBL_MAX}}
static const struct aabb AABB_NULL = AABB_NULL__;
+struct args {
+ unsigned nprobes; /* Number of probes to solve */
+ int quit;
+};
+#define ARGS_DEFAULT__ {1, 0}
+static const struct args ARGS_DEFAULT = ARGS_DEFAULT__;
+
/*
* 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
@@ -60,6 +69,7 @@ static const struct aabb AABB_NULL = AABB_NULL__;
#define FILENAME_SSHAPE "sshape.stl"
#define FILENAME_SPHERE "sphere.stl"
+#define FILENAME_PROBES "probes.txt"
#define FILENAME_SCENE "scene.txt"
/* Temperature at the upper bound of the X, Y and Z axis. The temperature at the
@@ -73,12 +83,31 @@ static const struct aabb AABB_NULL = AABB_NULL__;
#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
+/* Commands to calculate 1 or N probes */
+#define COMMAND1 "stardis -V3 -P "STR(PX)","STR(PY)","STR(PZ)" -M "FILENAME_SCENE
+#define COMMANDN "stardis -V3 -L "FILENAME_PROBES" -M "FILENAME_SCENE
/*******************************************************************************
* Helper functions
******************************************************************************/
+static double
+rand_canonic(void)
+{
+ return (double)rand() / (double)((long)RAND_MAX - 1);
+}
+
+static void
+sample_unit_sphere(double p[3])
+{
+ const double phi = rand_canonic() * 2*PI;
+ const double v = rand_canonic();
+ const double cos_theta = 1 - 2*v;
+ const double sin_theta = 2 * sqrt(v*(1-v));
+ p[0] = cos(phi) * sin_theta;
+ p[1] = sin(phi) * sin_theta;
+ p[2] = cos_theta;
+}
+
static void
aabb_update(struct aabb* aabb, const struct s3dut_mesh_data* mesh)
{
@@ -164,6 +193,48 @@ setup_scene
d2(profile->c, 0, TZ);
}
+static void
+usage(const char* name, FILE* stream)
+{
+ ASSERT(name && stream);
+ fprintf(stream, "usage: %s [-h] [-p probes_count]\n", name);
+}
+
+static int
+args_init(struct args* args, int argc, char** argv)
+{
+ int opt = 0;
+ int err = 0;
+
+ ASSERT(args);
+ while((opt = getopt(argc, argv, "hp:")) != -1) {
+ switch(opt) {
+ case 'h':
+ usage(argv[0], stdout);
+ args->quit = 1;
+ break;
+ case 'p':
+ err = (cstr_to_uint(optarg, &args->nprobes) != RES_OK);
+ if(!err && args->nprobes == 0) err = 1;
+ break;
+ default: err = 1; break;
+ }
+ if(err) {
+ if(optarg) {
+ fprintf(stderr, "%s: invalid option argument `%s' -- `%c'\n",
+ argv[0], optarg, opt);
+ }
+ goto error;
+ }
+ }
+
+exit:
+ return err;
+error:
+ usage(argv[0], stderr);
+ goto exit;
+}
+
static int
init(struct sadist_trilinear_profile* profile)
{
@@ -206,7 +277,38 @@ error:
}
static int
-run(const struct sadist_trilinear_profile* profile)
+init_probe_list(double* probes, const size_t nprobes)
+{
+ FILE* fp_probes = NULL;
+ size_t i = 0;
+ int err = 0;
+ ASSERT(probes && nprobes);
+
+ if((fp_probes = fopen(FILENAME_PROBES, "w")) == NULL) {
+ fprintf(stderr, "Error opening `"FILENAME_PROBES"' file -- %s\n",
+ strerror(errno));
+ err = errno;
+ goto error;
+ }
+
+ FOR_EACH(i, 0, nprobes) {
+ sample_unit_sphere(probes+i*3);
+ if(fprintf(fp_probes, "%g,%g,%g\n", SPLIT3(probes+i*3)) < 0) {
+ fprintf(stderr, "Error writing probes -- %s\n", strerror(errno));
+ err = errno;
+ goto error;
+ }
+ }
+
+exit:
+ if(fp_probes && fclose(fp_probes)) { perror("fclose"); if(!err) err = errno; }
+ return err;
+error:
+ goto exit;
+}
+
+static int
+run1(const struct sadist_trilinear_profile* profile)
{
const double P[3] = {PX, PY, PZ};
FILE* output = NULL;
@@ -216,16 +318,16 @@ run(const struct sadist_trilinear_profile* profile)
int n = 0;
int err = 0;
- printf(COMMAND"\n");
+ printf(COMMAND1"\n");
- if(!(output = popen(COMMAND, "r"))) {
+ if(!(output = popen(COMMAND1, "r"))) {
fprintf(stderr, "Error executing stardis -- %s\n", strerror(errno));
- fprintf(stderr, "\t"COMMAND"\n");
+ fprintf(stderr, "\t"COMMAND1"\n");
err = errno;
goto error;
}
- if((n = fscanf(output, "%lf %lf", &E, &SE)), n != 2 && n != EOF) {
+ if((n = fscanf(output, "%lf %lf %*d %*d", &E, &SE)), n != 2 && n != EOF) {
fprintf(stderr, "Error reading the output stream -- %s\n", strerror(errno));
err = errno;
goto error;
@@ -233,16 +335,90 @@ run(const struct sadist_trilinear_profile* profile)
/* Check command exit status */
if((err = pclose(output))) goto error;
+ output = NULL;
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:
+ if(output) pclose(output);
+ return err;
+error:
+ goto exit;
+}
+
+static int
+runN(const struct sadist_trilinear_profile* profile, const size_t nprobes)
+{
+ double* probes = NULL; /* Positions */
+ double* results = NULL; /* Expected values and standard deviations */
+ FILE* output = NULL;
+ size_t i = 0;
+ int err = 0;
+ ASSERT(profile && nprobes);
+
+ if(!(probes = mem_calloc(nprobes, sizeof(double)*3))) {
+ err = errno = ENOMEM;
+ perror("mem_calloc");
+ goto error;
+ }
+
+ if(!(results = mem_calloc(nprobes, sizeof(double)*2))) {
+ err = errno = ENOMEM;
+ perror("mem_calloc");
+ goto error;
+ }
+
+ if((err = init_probe_list(probes, nprobes))) goto error;
+
+ printf(COMMANDN"\n");
+
+ if(!(output = popen(COMMANDN, "r"))) {
+ fprintf(stderr, "Error executing stardis -- %s\n", strerror(errno));
+ fprintf(stderr, "\t"COMMAND1"\n");
+ err = errno;
+ goto error;
+ }
+
+ /* Fetch the result */
+ FOR_EACH(i, 0, nprobes) {
+ double* E = results + i*2 + 0;
+ double* SE = results + i*2 + 1;
+ int n = 0;
+
+ if((n = fscanf(output, "%lf %lf %*d %*d", E, SE)), n != 2 && n != EOF) {
+ perror("fscanf");
+ err = errno;
+ goto error;
+ }
+ }
+
+ /* Check command exit status */
+ if((err = pclose(output))) goto error;
+ output = NULL;
+
+ /* Validate the calculations */
+ FOR_EACH(i, 0, nprobes) {
+ const double* P = probes + i*3;
+ const double E = results[i*2 + 0];
+ const double SE = results[i*2 + 1];
+ const double ref = sadist_trilinear_profile(profile, P);
+
+ printf("T = %g ~ %g +/- %g\n", ref, E, SE);
+ if(!eq_eps(ref, E, SE*3)) {
+ err = 1;
+ goto error;
+ }
+ }
+
+exit:
+ if(probes) mem_rm(probes);
+ if(results) mem_rm(results);
+ if(output) pclose(output);
return err;
error:
goto exit;
@@ -254,12 +430,21 @@ error:
int
main(int argc, char** argv)
{
+ struct args args = ARGS_DEFAULT;
struct sadist_trilinear_profile profile = SADIST_TRILINEAR_PROFILE_NULL;
int err = 0;
(void)argc, (void)argv;
+ if((err = args_init(&args, argc, argv))) goto error;
+ if(args.quit) goto exit;
+
if((err = init(&profile))) goto error;
- if((err = run(&profile))) goto error;
+
+ if(args.nprobes == 1) {
+ if((err = run1(&profile))) goto error;
+ } else {
+ if((err = runN(&profile, args.nprobes))) goto error;
+ }
exit:
if(mem_allocated_size() != 0) {