star-line

Structure for accelerating line importance sampling
git clone git://git.meso-star.fr/star-line.git
Log | Files | Refs | README | LICENSE

commit 90a512e2d9cd6b7b56f03574c40cfba31db4dee6
parent 9468a804126acd6ba536ba8894c5532ef957bace
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 12 Mar 2026 16:33:04 +0100

sln-slab: preparation for Monte Carlo simulation

Setup the parallel estimation of the Monte Carlo algorithm, which
currently calculates 4+1. With a verbosity of 3, a computation progress
message is displayed.

The next step is to implement the actual function for performing the
radiative transfer algorithm.

Diffstat:
MMakefile | 30++++++++++++++++++++++++------
Mconfig.mk | 1+
Msrc/sln_slab.c | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 167 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile @@ -70,6 +70,7 @@ libsln.o: $(OBJ) $(PKG_CONFIG) --atleast-version $(LBLU_VERSION) lblu $(PKG_CONFIG) --atleast-version $(RSYS_VERSION) rsys $(PKG_CONFIG) --atleast-version $(SHTR_VERSION) shtr + $(PKG_CONFIG) --atleast-version $(SSP_VERSION) star-sp echo "config done" > $@ .SUFFIXES: .c .d .o @@ -90,15 +91,26 @@ PKG_CONFIG_LOCAL = PKG_CONFIG_PATH="./:$${PKG_CONFIG_PATH}" $(PKG_CONFIG) INCS_UTIL = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --cflags rsys sln-local shtr) LIBS_UTIL = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --libs rsys sln-local shtr) - CFLAGS_UTIL = -std=c89 $(CFLAGS_EXE) $(INCS_UTIL) LDFLAGS_UTIL = $(LDFLAGS_EXE) $(LIBS_UTIL) -utils: library $(UTIL_DEP) +INCS_SLAB = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --cflags rsys sln-local shtr star-sp) +LIBS_SLAB = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --libs rsys sln-local shtr star-sp) -lm +CFLAGS_SLAB = -std=c89 $(CFLAGS_EXE) $(INCS_SLAB) -fopenmp +LDFLAGS_SLAB = $(LDFLAGS_EXE) $(LIBS_SLAB) + +utils: library $(UTIL_DEP) .config @$(MAKE) -fMakefile \ $$(for i in $(UTIL_DEP); do printf -- '-f%s\n' "$${i}"; done) \ sln-build sln-get sln-slab +$(UTIL_DEP) $(UTIL_OBJ): config.mk sln-local.pc + + +src/sln_build.d src/sln_build.o: src/sln_build.c +src/sln_get.d src/sln_get.o: src/sln_get.c +src/sln_slab.d src/sln_slab.o: src/sln_slab.c + sln-build: config.mk sln-local.pc src/sln_build.o $(LIBNAME) $(CC) $(CFLAGS_UTIL) -o $@ src/sln_build.o $(LDFLAGS_UTIL) @@ -106,16 +118,22 @@ sln-get: config.mk sln-local.pc src/sln_get.o $(LIBNAME) $(CC) $(CFLAGS_UTIL) -o $@ src/sln_get.o $(LDFLAGS_UTIL) sln-slab: config.mk sln-local.pc src/sln_slab.o $(LIBNAME) - $(CC) $(CFLAGS_UTIL) -o $@ src/sln_slab.o $(LDFLAGS_UTIL) + $(CC) $(CFLAGS_SLAB) -o $@ src/sln_slab.o $(LDFLAGS_SLAB) -$(UTIL_DEP): config.mk sln-local.pc +src/sln_build.d src/sln_get.d: @$(CC) $(CFLAGS_UTIL) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@ -$(UTIL_OBJ): config.mk sln-local.pc +src/sln_slab.d: + @$(CC) $(CFLAGS_SLAB) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@ + +src/sln_build.o src/sln_get.o: $(CC) $(CFLAGS_UTIL) -c $(@:.o=.c) -o $@ +src/sln_slab.o: + $(CC) $(CFLAGS_SLAB) -c $(@:.o=.c) -o $@ + clean_utils: - rm -f $(UTIL_OBJ) $(UTIL_DEP) sln-build + rm -f $(UTIL_OBJ) $(UTIL_DEP) sln-build sln-get sln-slab ################################################################################ # Installation diff --git a/config.mk b/config.mk @@ -31,6 +31,7 @@ PCFLAGS = $(PCFLAGS_$(LIB_TYPE)) LBLU_VERSION = 0.0.1 RSYS_VERSION = 0.14 SHTR_VERSION = 0 +SSP_VERSION = 0.15 # Dependency for the sln-slab util INCS = $$($(PKG_CONFIG) $(PCFLAGS) --cflags lblu rsys shtr) LIBS = $$($(PKG_CONFIG) $(PCFLAGS) --libs lblu rsys shtr) -lm diff --git a/src/sln_slab.c b/src/sln_slab.c @@ -21,10 +21,13 @@ #include "sln.h" #include <star/shtr.h> +#include <star/ssp.h> #include <rsys/cstr.h> #include <rsys/mem_allocator.h> +#include <omp.h> + #include <unistd.h> /* getopt */ struct args { @@ -49,10 +52,19 @@ struct cmd { struct args args; struct sln_tree* tree; + unsigned nthreads; }; #define CMD_NULL__ {0} static const struct cmd CMD_NULL = CMD_NULL__; +struct accum { + double sum; + double sum2; + size_t count; +}; +#define ACCUM_NULL__ {0} +static const struct accum ACCUM_NULL = ACCUM_NULL__; + /******************************************************************************* * Helper functions ******************************************************************************/ @@ -159,6 +171,50 @@ error: goto exit; } +static void +delete_per_thread_rngs(const struct cmd* cmd, struct ssp_rng* rngs[]) +{ + unsigned i = 0; + ASSERT(cmd && rngs); + + FOR_EACH(i, 0, cmd->nthreads) { + if(rngs[i]) SSP(rng_ref_put(rngs[i])); + } + mem_rm(rngs); +} + +static res_T +create_per_thread_rngs(const struct cmd* cmd, struct ssp_rng** out_rngs[]) +{ + struct ssp_rng_proxy* proxy = NULL; + struct ssp_rng** rngs = NULL; + size_t i = 0; + res_T res = RES_OK; + ASSERT(cmd); + + rngs = mem_calloc(cmd->nthreads, sizeof(*rngs)); + if(!rngs) { res = RES_MEM_ERR; goto error; } + + res = ssp_rng_proxy_create(NULL, SSP_RNG_THREEFRY, cmd->nthreads, &proxy); + if(res != RES_OK) goto error; + + FOR_EACH(i, 0, cmd->nthreads) { + res = ssp_rng_proxy_create_rng(proxy, i, &rngs[i]); + if(res != RES_OK) goto error; + } + +exit: + *out_rngs = rngs; + if(proxy) SSP(rng_proxy_ref_put(proxy)); + return res; +error: + fprintf(stderr, + "Error creating the list of per thread RNG -- %s\n", + res_to_cstr(res)); + if(rngs) delete_per_thread_rngs(cmd, rngs); + rngs = NULL; + goto exit; +} static void cmd_release(struct cmd* cmd) @@ -182,6 +238,7 @@ cmd_init(struct cmd* cmd, const struct args* args) struct shtr_line_list* lines = NULL; /* Miscellaneous */ + unsigned nthreads_max = 0; res_T res = RES_OK; ASSERT(cmd && args); @@ -208,7 +265,9 @@ cmd_init(struct cmd* cmd, const struct args* args) res = sln_tree_read(sln, &tree_args, &cmd->tree); if(res != RES_OK) goto error; + nthreads_max = (unsigned)MMAX(omp_get_max_threads(), omp_get_num_procs()); cmd->args = *args; + cmd->nthreads = MMIN(cmd->args.nthreads_hint, nthreads_max); exit: if(sln) SLN(device_ref_put(sln)); @@ -222,6 +281,88 @@ error: goto exit; } +static double +realisation(const struct cmd* cmd, struct ssp_rng* rng) +{ + ASSERT(cmd && rng); + (void)cmd; /* Avoid unused variable warning */ + + if(ssp_rng_canonical(rng) < 0.5) { + return 2.0; + } else { + return 8.0; + } +} + +static res_T +cmd_run(const struct cmd* cmd) +{ + /* Random Number Generator */ + struct ssp_rng** rngs = NULL; + + /* Monte Carlo */ + struct accum accum = ACCUM_NULL; + double E = 0; /* Expected value */ + double V = 0; /* Variance */ + double SE = 0; /* Standard Error */ + int64_t i = 0; /* Index of the realisation */ + + /* Progress */ + size_t nrealisations = 0; + size_t realisation_done = 0; + int progress = 0; + int progress_pcent = 10; + + res_T res = RES_OK; + ASSERT(cmd); + + res = create_per_thread_rngs(cmd, &rngs); + if(res != RES_OK) goto error; + + if(cmd->args.verbose) fprintf(stderr, "%3d%%\n", progress); + + nrealisations = cmd->args.nrealisations; + + #pragma omp parallel for schedule(static) + for(i = 0; i < (int64_t)nrealisations; ++i) { + const int ithread = omp_get_thread_num(); + int pcent = 0; + double w = 0; + + w = realisation(cmd, rngs[ithread]); + + #pragma omp critical + { + /* Update the Monte Carlo accumulator */ + accum.sum += w; + accum.sum2 += w*w; + accum.count += 1; + + if(cmd->args.verbose) { + /* Update progress */ + realisation_done += 1; + pcent = (int)((double)realisation_done*100.0/(double)nrealisations+0.5); + if(pcent/progress_pcent > progress/progress_pcent) { + progress = pcent; + fprintf(stderr, "%3d%%\n", progress); + } + } + } + } + + E = accum.sum / (double)accum.count; + V = accum.sum2 / (double)accum.count - E*E; + SE = sqrt(V/(double)accum.count); + + printf("%g %g\n", E, SE); + +exit: + delete_per_thread_rngs(cmd, rngs); + return res; +error: + goto exit; +} + /******************************************************************************* * Main function ******************************************************************************/ @@ -237,6 +378,7 @@ main(int argc, char** argv) if(args.quit) goto exit; if((res = cmd_init(&cmd, &args)) != RES_OK) goto error; + if((res = cmd_run(&cmd)) != RES_OK) goto error; exit: cmd_release(&cmd);