star-gs

Literate program for a geometric sensitivity calculation
git clone git://git.meso-star.fr/star-gs.git
Log | Files | Refs | README | LICENSE

commit 443e383981221ca0213d60caedd46123a0336138
parent 3cfa90f7822b98c68b202d5c72363da08623e3c5
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon,  3 May 2021 16:27:35 +0200

Add the compute_4v_s function

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/sgs.c | 5+++--
Asrc/sgs_compute_4v_s.c | 183+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 187 insertions(+), 2 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -54,6 +54,7 @@ set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SGS_FILES_SRC sgs_args.c sgs.c + sgs_compute_4v_s.c sgs_geometry.c sgs_geometry_box.c sgs_geometry_slope.c diff --git a/src/sgs.c b/src/sgs.c @@ -50,7 +50,7 @@ sgs_create goto error; } sgs->allocator = allocator; - sgs->nrealisations = (size_t)sgs->nrealisations; + sgs->nrealisations = (size_t)args->nrealisations; sgs->nthreads = args->nthreads; sgs->verbose = args->verbose; sgs->dump_geometry = args->dump_geometry; @@ -144,7 +144,8 @@ sgs_run(struct sgs* sgs) res = sgs_geometry_dump_vtk(sgs->geom, stdout); if(res != RES_OK) goto error; } else { - /* TODO Monte Carlo computation */ + res = compute_4v_s(sgs); + if(res != RES_OK) goto error; } exit: diff --git a/src/sgs_compute_4v_s.c b/src/sgs_compute_4v_s.c @@ -0,0 +1,183 @@ +/* Copyright (C) 2021 + * CNRS/RAPSODEE, + * CNRS/LMAP, + * |Meso|Star> (contact@meso-star.com), + * UPS/Laplace. + * + * 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 "sgs_c.h" +#include "sgs_geometry.h" +#include "sgs_log.h" + +#include <star/smc.h> +#include <star/ssp.h> + +#include <rsys/double2.h> +#include <rsys/double3.h> +#include <rsys/cstr.h> + +/******************************************************************************* + * Helper function + ******************************************************************************/ +/* Reflect the vector V wrt the normal N. By convention V points outward the + * surface. */ +static INLINE double* +reflect(double res[3], const double V[3], const double N[3]) +{ + double tmp[3]; + double cos_V_N; + ASSERT(res && V && N); + ASSERT(d3_is_normalized(V) && d3_is_normalized(N)); + cos_V_N = d3_dot(V, N); + d3_muld(tmp, N, 2*cos_V_N); + d3_sub(res, tmp, V); + return res; +} + +static res_T +realisation(void* weight, struct ssp_rng* rng, const unsigned ithread, void* ctx) +{ + struct sgs_fragment frag = SGS_FRAGMENT_NULL; + struct sgs_hit hit = SGS_HIT_NULL; + + double vec[3] = {0, 0, 0}; + double pos[3] = {0, 0, 0}; + double dir[3] = {0, 0, 0}; + double range[2] = {0, 0}; + + struct sgs_s3d_position* pos_from = NULL; + struct sgs* sgs = ctx; + + double len = 0; + + int sampling_mask = 0; + res_T res = RES_OK; + + ASSERT(weight && rng && ctx); + (void)ithread; + + sampling_mask = sgs_geometry_get_sampling_mask(sgs->geom); + + /* Sample the emissive surface */ + sgs_geometry_sample(sgs->geom, rng, &frag); + pos_from = &frag.s3d_pos; + + /* Cosine weighted sampling of the hemisphere around the sampled normal */ + ssp_ran_hemisphere_cos(rng, frag.normal, dir, NULL); + + pos[0] = frag.position[0]; + pos[1] = frag.position[1]; + pos[2] = frag.position[2]; + + range[0] = 0; + range[1] = INF; + + for(;;) { + sgs_geometry_trace_ray(sgs->geom, pos, dir, range, pos_from, &hit); + if(SGS_HIT_NONE(&hit)) { /* Unexpected error */ + res = RES_BAD_OP; + goto error; + } + + len += hit.distance; + + if(((int)hit.surface_type & sampling_mask) != 0) + break; /* Stop random walk */ + + /* Move to the intersection */ + d3_muld(vec, dir, hit.distance); + d3_add(pos, pos, vec); + + /* Reflect the direction with respect to the intersection normal */ + d3_minus(dir, dir); /* Ensure reflect convention */ + reflect(dir, dir, hit.normal); + + pos_from = &hit.s3d_pos; + } +exit: + SMC_DOUBLE(weight) = len; + return res; +error: + len = NaN; + goto exit; +} + + +/******************************************************************************* + * Local function + ******************************************************************************/ +res_T +compute_4v_s(struct sgs* sgs) +{ + struct smc_integrator integrator; + struct smc_estimator_status status; + struct smc_device* smc = NULL; + struct smc_estimator* estimator = NULL; + double V; + double S; + res_T res = RES_OK; + ASSERT(sgs); + + /* Create the Star-MonteCarlo device */ + res = smc_device_create + (&sgs->logger, sgs->allocator, sgs->nthreads, &ssp_rng_mt19937_64, &smc); + if(res != RES_OK) { + sgs_log_err(sgs, "Could not create the Star-MonteCarlo device -- %s.\n", + res_to_cstr(res)); + goto error; + } + + /* Setup the integrator */ + integrator.integrand = realisation; + integrator.type = &smc_double; + integrator.max_realisations = sgs->nrealisations; + integrator.max_failures = (size_t)((double)sgs->nrealisations*0.01); + + /* Run Monte-Carlo integration */ + res = smc_solve(smc, &integrator, sgs, &estimator); + if(res != RES_OK) { + sgs_log_err(sgs, "Error while solving 4V/S -- %s.\n", + res_to_cstr(res)); + goto error; + } + + /* Retrieve the estimated result */ + SMC(estimator_get_status(estimator, &status)); + if(status.NF == integrator.max_failures) { + sgs_log_err(sgs, "Too many failures: %lu\n", (unsigned long)status.NF); + res = RES_BAD_OP; + goto error; + } + + /* Fetch the reference values */ + V = sgs_geometry_compute_volume(sgs->geom); + S = sgs_geometry_compute_sampling_area(sgs->geom); + sgs_log(sgs, "V = %g; S = %g\n", V, S); + + /* Print the result */ + sgs_log(sgs, "4V/S = %g ~ %g +/- %g; #failures = %lu/%lu\n", + 4*V/S, + SMC_DOUBLE(status.E), + SMC_DOUBLE(status.SE), + (unsigned long)status.NF, + (unsigned long)sgs->nrealisations); + +exit: + if(smc) SMC(device_ref_put(smc)); + if(estimator) SMC(estimator_ref_put(estimator)); + return res; +error: + goto exit; +}