htrdr

Solving radiative transfer in heterogeneous media
git clone git://git.meso-star.fr/htrdr.git
Log | Files | Refs | README | LICENSE

commit cd68cd1a70655d0d01ee23dd292ca5d28770d16a
parent 56b6f2b61cf556c1719af160f91071cd67863ac4
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 24 Mar 2021 18:39:22 +0100

Pursue the implementation of the combustion_compute_radiance_sw function

Diffstat:
Msrc/combustion/htrdr_combustion_c.h | 5++---
Msrc/combustion/htrdr_combustion_compute_radiance_sw.c | 519+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/combustion/htrdr_combustion_draw_map.c | 2+-
3 files changed, 380 insertions(+), 146 deletions(-)

diff --git a/src/combustion/htrdr_combustion_c.h b/src/combustion/htrdr_combustion_c.h @@ -80,14 +80,13 @@ extern LOCAL_SYM res_T combustion_draw_map (struct htrdr_combustion* cmd); -/* Return the shortwave radiance in W/m^2/sr/m */ +/* Return the shortwave radiance in W/m^2/sr */ extern LOCAL_SYM double combustion_compute_radiance_sw (struct htrdr_combustion* cmd, const size_t ithread, struct ssp_rng* rng, const double pos_in[3], - const double dir_in[3], - const double wlen); /* In nanometer */ + const double dir_in[3]); #endif /* HTRDR_COMBUSTION_C_H */ diff --git a/src/combustion/htrdr_combustion_compute_radiance_sw.c b/src/combustion/htrdr_combustion_compute_radiance_sw.c @@ -18,59 +18,95 @@ #include "combustion/htrdr_combustion_c.h" #include "combustion/htrdr_combustion_laser.h" +#include "core/htrdr.h" + #include <astoria/atrstm.h> +#include <star/ssf.h> #include <star/ssp.h> #include <rsys/double2.h> #include <rsys/double3.h> +#include <rsys/double4.h> +#include <rsys/dynamic_array.h> + +/* Define a position along the ray into the semi-transparent medium */ +struct position { + double distance; /* Distance up to the position */ + struct suvm_primitive prim; /* Volumetric primitive of the position */ + double bcoords[4]; /* Local coordinate of the position into `prim' */ +}; +#define POSITION_NULL__ { \ + DBL_MAX, /* Distance */ \ + SUVM_PRIMITIVE_NULL__, /* Primitive */ \ + {0, 0, 0, 0} /* Barycentric coordinates */ \ +} +static const struct position POSITION_NULL = POSITION_NULL__; + +/* Syntactic sugar to check if the position is valid */ +#define POSITION_NONE(Pos) ((Pos)->distance >= DBL_MAX) -struct transmissivity_context { - struct ssp_rng* rng; - struct atrstm* medium; - double wavelength; - enum atrstm_radcoef radcoef; +/* Common position but preferentially sampled within a limited range. + * Its associated ksi variable defines ??? TODO write the comment */ +struct position_limited { + struct position position; + double ksi; +}; +#define POSITION_LIMITED_NULL__ {POSITION_NULL__, 1} +static const struct position_limited POSITION_LIMITED_NULL = + POSITION_LIMITED_NULL__; + +struct sample_position_context { + /* Input data */ + struct ssp_rng* rng; /* Random Number Generator */ + struct atrstm* medium; /* Semi-transparent medium */ + double wavelength; /* Wavelength to handel in nanometer */ + enum atrstm_radcoef radcoef; /* Radiative coef used to sample a position */ + double Ts; /* Sampled optical thickness */ + + /* Output data */ + struct position position; }; -#define TRANSMISSIVITY_CONTEXT_NULL__ { \ +#define SAMPLE_POSITION_CONTEXT_NULL__ { \ NULL, /* RNG */ \ NULL, /* Medium */ \ 0, /* Wavelength */ \ - ATRSTM_RADCOEFS_COUNT__ /* Radiative coefficient */ \ + ATRSTM_RADCOEFS_COUNT__, /* Radiative coefficient */ \ + 0, /* Optical thickness */ \ + POSITION_NULL__ \ } -static const struct transmissivity_context TRANSMISSIVITY_CONTEXT_NULL = - TRANSMISSIVITY_CONTEXT_NULL__; +static const struct sample_position_context SAMPLE_POSITION_CONTEXT_NULL = + SAMPLE_POSITION_CONTEXT_NULL__; struct sample_scattering_limited_context { - struct ssp_rng* rng; - struct atrstm* medium; - double wavelength; - double traversal_dst; /* Distance traversed up to the collision */ - double ksi; + /* Input data */ + struct ssp_rng* rng; /* Random number generator to use */ + struct atrstm* medium; /* Semi transparent medium */ + double wavelength; /* Wavelength to handle in nanometer */ + + /* Local data updated during traversal */ + double ks_2hat; + + /* Output data */ + struct position_limited position_limited; }; #define SAMPLE_SCATTERING_LIMITED_CONTEXT_NULL__ { \ NULL, /* RNG */ \ NULL, /* Medium */ \ - 0, /* Wavelength */ \ - DBL_MAX, /* Traversal dst */ \ - 1, /* ksi */ \ + -1, /* Wavelength */ \ + -1, /* ks_2hat */ \ + POSITION_LIMITED_NULL__ \ } -static const struct sample_scattering_limited_context -SAMPLE_SCATTERING_LIMITED_CONTEXT_NULL = +static const struct sample_scattering_limited_context +SAMPLE_SCATTERING_LIMITED_CONTEXT_NULL = SAMPLE_SCATTERING_LIMITED_CONTEXT_NULL__; -struct laser_sheet_scattering { - double distance; /* Distance along the ray up to a scattering event */ - double ksi; -}; -#define LASER_SHEET_SCATTERING_NULL__ {0, 1} -static const struct laser_sheet_scattering LASER_SHEET_SCATTERING_NULL = - LASER_SHEET_SCATTERING_NULL__; - /******************************************************************************* - * Helper function + * Sample a position along a ray into the inhomogeneous medium for a given + * radiative coefficient ******************************************************************************/ static int -transmissivity_hit_filter +sample_position_hit_filter (const struct svx_hit* hit, const double org[3], const double dir[3], @@ -82,7 +118,7 @@ transmissivity_hit_filter ATRSTM_FETCH_RADCOEFS_ARGS_DEFAULT; struct atrstm_fetch_radcoefs_svx_voxel_args fetch_svx_args = ATRSTM_FETCH_RADCOEFS_SVX_VOXEL_ARGS_DEFAULT; - struct transmissivity_context* ctx = context; + struct sample_position_context* ctx = context; double k_min = 0; double k_max = 0; double traversal_dst = 0; @@ -112,83 +148,145 @@ transmissivity_hit_filter traversal_dst = hit->distance[0]; for(;;) { - atrstm_radcoefs_T radcoefs; - double collision_dst; - double tau; - double k; - double r; + /* Compute the optical thickness of the current leaf */ + const double vox_dst = hit->distance[1] - traversal_dst; + const double T = vox_dst * k_max; - /* Compute the distance up to the next collision to challenge */ - tau = ssp_ran_exp(ctx->rng, 1); - collision_dst = tau / k_max; - - /* Compute the traversed distance up to the challenged collision */ - traversal_dst += collision_dst; - - /* The collision to challenge lies behind the current voxel */ - if(traversal_dst > hit->distance[1]) { + /* A collision occurs behind the voxel */ + if(ctx->Ts > T) { + ctx->Ts -= T; pursue_traversal = 1; break; - } - ASSERT(traversal_dst >= hit->distance[0]); - - /* Compute the world space position where a collision may occur */ - fetch_raw_args.pos[0] = org[0] + traversal_dst * dir[0]; - fetch_raw_args.pos[1] = org[1] + traversal_dst * dir[1]; - fetch_raw_args.pos[2] = org[2] + traversal_dst * dir[2]; - - /* Fetch the radiative coefficient at the collision position */ - ATRSTM(fetch_radcoefs(ctx->medium, &fetch_raw_args, radcoefs)); - k = radcoefs[ctx->radcoef]; - r = ssp_rng_canonical(ctx->rng); - if(r < k/k_max) { /* Real collision => stop the traversal */ - pursue_traversal = 0; - break; + /* A collision occurs _in_ the voxel */ + } else { + const double vox_collision_dst = ctx->Ts / k_max; + atrstm_radcoefs_T radcoefs; + double x[3]; + double k; + double r; + + /* Compute the traversed distance up to the challenged collision */ + traversal_dst += vox_collision_dst; + + /* Compute the world space position where a collision may occur */ + x[0] = org[0] + traversal_dst * dir[0]; + x[1] = org[1] + traversal_dst * dir[1]; + x[2] = org[2] + traversal_dst * dir[2]; + + /* Fetch the radiative coefficient at the collision position */ + ATRSTM(at(ctx->medium, x, &fetch_raw_args.prim, fetch_raw_args.bcoords)); + ATRSTM(fetch_radcoefs(ctx->medium, &fetch_raw_args, radcoefs)); + k = radcoefs[ctx->radcoef]; + + r = ssp_rng_canonical(ctx->rng); + + if(r > k/k_max) { /* Null collision */ + ctx->Ts = ssp_ran_exp(ctx->rng, 1); + } else { /* Real collision */ + /* Setup output data */ + ctx->position.distance = traversal_dst; + ctx->position.prim = fetch_raw_args.prim; + d4_set(ctx->position.bcoords, fetch_raw_args.bcoords); + + /* Stop ray traversal */ + pursue_traversal = 0; + break; + } } } return pursue_traversal; } -static double -transmissivity +static void +sample_position (struct htrdr_combustion* cmd, struct ssp_rng* rng, const enum atrstm_radcoef radcoef, - const double wlen, /* In nanometer */ const double pos[3], const double dir[3], - const double range[2]) + const double range[2], + struct position* position) { struct atrstm_trace_ray_args args = ATRSTM_TRACE_RAY_ARGS_DEFAULT; - struct transmissivity_context transmissivity_ctx = TRANSMISSIVITY_CONTEXT_NULL; + struct sample_position_context sample_pos_ctx = SAMPLE_POSITION_CONTEXT_NULL; struct svx_hit svx_hit = SVX_HIT_NULL; - ASSERT(cmd && rng && wlen > 0 && pos && dir && range); + double wlen = 0; + ASSERT(cmd && rng && pos && dir && range); - /* Degenerated range => no attenuation along dir */ - if(range[1] <= range[0]) return 1; + wlen = htrdr_combustion_laser_get_wavelength(cmd->laser); - /* Setup the trace ray context */ - transmissivity_ctx.rng = rng; - transmissivity_ctx.medium = cmd->medium; - transmissivity_ctx.wavelength = wlen; - transmissivity_ctx.radcoef = radcoef; + /* Sample an optical thickness */ + sample_pos_ctx.Ts = ssp_ran_exp(rng, 1); - /* Setup input arguments for the ray tracing into the medium */ + /* Setup the arguments of the function invoked per voxel (i.e. the filter + * function) */ + sample_pos_ctx.rng = rng; + sample_pos_ctx.medium = cmd->medium; + sample_pos_ctx.wavelength = wlen; + sample_pos_ctx.radcoef = radcoef; + + /* Setup ray tracing arguments */ d3_set(args.ray_org, pos); d3_set(args.ray_dir, dir); d2_set(args.ray_range, range); - args.filter = transmissivity_hit_filter; - args.context = &transmissivity_ctx; + args.filter = sample_position_hit_filter; + args.context = &sample_pos_ctx; - /* Trace the ray into the medium to compute the transmissivity */ + /* Trace the ray into the heterogeneous medium */ ATRSTM(trace_ray(cmd->medium, &args, &svx_hit)); if(SVX_HIT_NONE(&svx_hit)) { - return 1; /* No collision with the medium */ + /* No collision with the medium was found */ + *position = POSITION_NULL; } else { - return 0; /* A collision occurs */ + /* A collision occurs into the medium */ + *position = sample_pos_ctx.position; + } +} + +/******************************************************************************* + * Preferentially sample a scattering position into an inhomogeneous medium + * according to a limited range + ******************************************************************************/ +/* Find the constant Ks max (named ks_2hat) along the traced ray */ +static int +sample_scattering_limited_find_ks_2hat + (const struct svx_hit* hit, + const double org[3], + const double dir[3], + const double range[2], + void* context) +{ + struct sample_scattering_limited_context* ctx = context; + struct atrstm_fetch_radcoefs_svx_voxel_args fetch_svx_args = + ATRSTM_FETCH_RADCOEFS_SVX_VOXEL_ARGS_DEFAULT; + atrstm_radcoefs_svx_T radcoefs_svx; + ASSERT(hit && org && dir && range && context); + (void)org, (void)dir; + + /* In all situations, initialise ks_2hat with the ks_max of the root node */ + if(hit->voxel.depth == 0) { + fetch_svx_args.voxel = hit->voxel; + fetch_svx_args.radcoefs_mask = ATRSTM_RADCOEF_FLAG_Ks; + fetch_svx_args.components_mask = ATRSTM_CPNTS_MASK_ALL; + fetch_svx_args.operations_mask = ATRSTM_SVX_OP_FLAG_MAX; + ATRSTM(fetch_radcoefs_svx_voxel(ctx->medium, &fetch_svx_args, radcoefs_svx)); + ctx->ks_2hat = radcoefs_svx[ATRSTM_RADCOEF_Ks][ATRSTM_SVX_OP_MAX]; + + /* Update ks_2hat with the ks_max of the current descending node until the ray + * range was no more included into this node */ + } else if(hit->distance[0] <= range[0] && range[1] <= hit->distance[1]) { + fetch_svx_args.voxel = hit->voxel; + fetch_svx_args.radcoefs_mask = ATRSTM_RADCOEF_FLAG_Ks; + fetch_svx_args.components_mask = ATRSTM_CPNTS_MASK_ALL; + fetch_svx_args.operations_mask = ATRSTM_SVX_OP_FLAG_MAX; + ATRSTM(fetch_radcoefs_svx_voxel(ctx->medium, &fetch_svx_args, radcoefs_svx)); + ctx->ks_2hat = radcoefs_svx[ATRSTM_RADCOEF_Ks][ATRSTM_SVX_OP_MAX]; } + + /* Do not stop here: keep diving up to the leaves */ + return 0; } static int @@ -209,6 +307,7 @@ sample_scattering_limited_hit_filter double ks_max = 0; double tau_max = 0; double traversal_dst = 0; + double Ume = 0; int pursue_traversal = 1; ASSERT(hit && org && dir && range && ctx); (void)range; @@ -222,6 +321,7 @@ sample_scattering_limited_hit_filter ks_min = radcoefs_svx[ATRSTM_RADCOEF_Ks][ATRSTM_SVX_OP_MIN]; ks_max = radcoefs_svx[ATRSTM_RADCOEF_Ks][ATRSTM_SVX_OP_MAX]; + ASSERT(ks_max <= ctx->ks_2hat); /* Setup the constants of the 'fetch' function for the current voxel */ fetch_raw_args.wavelength = ctx->wavelength; @@ -234,26 +334,26 @@ sample_scattering_limited_hit_filter * current ray enters into the current voxel */ traversal_dst = hit->distance[0]; - tau_max = (hit->distance[1] - hit->distance[0]) * ks_max; + tau_max = (range[1] - range[0]) * ctx->ks_2hat; + Ume = 1 - exp(-tau_max); for(;;) { atrstm_radcoefs_T radcoefs; - double collision_dst; + double vox_collision_dst; double tau; double ks; double r; - r = ssp_rng_canonical(ctx->rng); - /* Sampled optical thickness (preferential sampling) */ + r = ssp_rng_canonical(ctx->rng); tau = -log(1.0-r*(1.0-exp(-tau_max))); - collision_dst = tau / ks_max; + vox_collision_dst = tau / ks_max; /* Compute the traversed distance up to the challenged collision */ - traversal_dst += collision_dst; + traversal_dst += vox_collision_dst; /* Update the ksi output data */ - ctx->ksi *= 1 - exp(-tau_max); + ctx->position_limited.ksi *= Ume; /* The collision to challenge lies behind the current voxel */ if(traversal_dst > hit->distance[1]) { @@ -262,20 +362,32 @@ sample_scattering_limited_hit_filter } ASSERT(traversal_dst >= hit->distance[0]); - /* Compute the world space position where a collision may occur */ - fetch_raw_args.pos[0] = org[0] + traversal_dst * dir[0]; - fetch_raw_args.pos[1] = org[1] + traversal_dst * dir[1]; - fetch_raw_args.pos[2] = org[2] + traversal_dst * dir[2]; - - /* Fetch the radiative coefficient at the collision position */ - ATRSTM(fetch_radcoefs(ctx->medium, &fetch_raw_args, radcoefs)); - ks = radcoefs[ATRSTM_RADCOEF_Ks]; - r = ssp_rng_canonical(ctx->rng); - if(r < ks/ks_max) { /* Real collision => stop the traversal */ - ctx->traversal_dst = traversal_dst; - pursue_traversal = 0; - break; + if(r < ks_max / ctx->ks_2hat) { /* Collision with ks_max */ + double x[3]; + + /* Compute the world space position where a collision may occur */ + x[0] = org[0] + traversal_dst * dir[0]; + x[1] = org[1] + traversal_dst * dir[1]; + x[2] = org[2] + traversal_dst * dir[2]; + + /* Fetch the radiative coefficient at the collision position */ + ATRSTM(at(ctx->medium, x, &fetch_raw_args.prim, fetch_raw_args.bcoords)); + ATRSTM(fetch_radcoefs(ctx->medium, &fetch_raw_args, radcoefs)); + ks = radcoefs[ATRSTM_RADCOEF_Ks]; + + r = ssp_rng_canonical(ctx->rng); + + if(r < ks/ks_max) { /* Real collision */ + /* Setup output data */ + ctx->position_limited.position.distance = traversal_dst; + ctx->position_limited.position.prim = fetch_raw_args.prim; + d4_set(ctx->position_limited.position.bcoords, fetch_raw_args.bcoords); + + /* Stop ray traversal */ + pursue_traversal = 0; + break; + } } } return pursue_traversal; @@ -285,88 +397,190 @@ static void sample_scattering_limited (struct htrdr_combustion* cmd, struct ssp_rng* rng, - const double wlen, const double pos[3], const double dir[3], const double range[2], - struct laser_sheet_scattering* sample) + struct position_limited* position) { struct atrstm_trace_ray_args args = ATRSTM_TRACE_RAY_ARGS_DEFAULT; - struct sample_scattering_limited_context sample_scattering_limited_ctx = + struct sample_scattering_limited_context sample_scattering_limited_ctx = SAMPLE_SCATTERING_LIMITED_CONTEXT_NULL; struct svx_hit svx_hit = SVX_HIT_NULL; - ASSERT(cmd && rng && wlen >= 0 && pos && dir && sample); + double wlen = 0; + ASSERT(cmd && rng && pos && dir && position); + + wlen = htrdr_combustion_laser_get_wavelength(cmd->laser); /* Setup the trace ray context */ sample_scattering_limited_ctx.rng = rng; sample_scattering_limited_ctx.medium = cmd->medium; sample_scattering_limited_ctx.wavelength = wlen; - sample_scattering_limited_ctx.traversal_dst = 0; - sample_scattering_limited_ctx.ksi = 1; + sample_scattering_limited_ctx.ks_2hat = 0; + sample_scattering_limited_ctx.position_limited = POSITION_LIMITED_NULL; /* Setup the input arguments for the ray tracing into the medium */ d3_set(args.ray_org, pos); d3_set(args.ray_dir, dir); d2_set(args.ray_range, range); + args.challenge = sample_scattering_limited_find_ks_2hat; args.filter = sample_scattering_limited_hit_filter; args.context = &sample_scattering_limited_ctx; /* Trace the ray into the medium to compute the transmissivity */ ATRSTM(trace_ray(cmd->medium, &args, &svx_hit)); - if(SVX_HIT_NONE(&svx_hit)) { /* No collision with the medium */ - sample->distance = INF; - sample->ksi = 0; - } else { /* A collision occurs */ - sample->distance = sample_scattering_limited_ctx.traversal_dst; - sample->ksi = sample_scattering_limited_ctx.ksi; + if(SVX_HIT_NONE(&svx_hit)) { + /* No scattering event was found */ + *position = POSITION_LIMITED_NULL; + } else { + /* A scattering event occurs into the medium */ + *position = sample_scattering_limited_ctx.position_limited; + } +} + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static double +transmissivity + (struct htrdr_combustion* cmd, + struct ssp_rng* rng, + const enum atrstm_radcoef radcoef, + const double pos[3], + const double dir[3], + const double range[2]) +{ + struct position position = POSITION_NULL; + + /* Degenerated range => no attenuation along dir */ + if(range[1] <= range[0]) return 1; + + sample_position(cmd, rng, radcoef, pos, dir, range, &position); + + if(POSITION_NONE(&position)) { + return 1; /* No collision with the medium */ + } else { + return 0; /* A collision occurs */ } } +/* This function computes the contribution of the in-laser scattering for the + * current scattering position of the reverse optical path 'pos' and current + * direction 'dir'. One contribution has to be computed for each scattering + * position in order to compute the value of the Monte-Carlo weight for the + * optical path (weight of the statistical realization). */ static double laser_once_scattered (struct htrdr_combustion* cmd, + const size_t ithread, struct ssp_rng* rng, - const double wlen, /* In nanometer */ const double pos[3], const double dir[3]) { - #define HIT_NONE(Dst) (Dst >= DBL_MAX) - - struct laser_sheet_scattering sample = LASER_SHEET_SCATTERING_NULL; + /* RDG-FA phase function */ + struct atrstm_rdgfa rdgfa_param = ATRSTM_RDGFA_NULL; + struct atrstm_fetch_rdgfa_args fetch_rdgfa_args = + ATRSTM_FETCH_RDGFA_ARGS_DEFAULT; + struct ssf_phase_rdgfa_setup_args setup_rdgfa_args = + SSF_PHASE_RDGFA_SETUP_ARGS_DEFAULT; + struct ssf_phase* rdgfa = NULL; + + /* Scattering position into the laser sheet */ + struct position_limited sc_sample = POSITION_LIMITED_NULL; + double xsc[3] = {0, 0, 0}; /* World space position */ + + /* The transmissivities to compute */ + double Tr_ext_pos_xin = 0; + double Tr_ext_xsc_lse = 0; + double Tr_abs_xin_xsc = 0; + + /* Laser data */ double laser_hit_dst[2] = {0, 0}; + double laser_flux_density = 0; /* In W/m^2 */ + double wlen = 0; /* In nm */ + + /* Miscellaneous varbale */ + double wi[3] = {0, 0, 0}; + double wo[3] = {0, 0, 0}; double range[2] = {0, DBL_MAX}; - double Tr_pos_xin = 0; - double Tr_xin_xs = 0; - double L = 0; /* Radiance in W/m^2/sr/m */ - ASSERT(cmd && rng && wlen >= 0 && pos && dir); + double R = 0; - /* Find the intersections along dir with the laser sheet */ - htrdr_combustion_laser_trace_ray(cmd->laser, pos, dir, range, laser_hit_dst); + /* Radiance to compute in W/m^2/sr */ + double L = 0; - /* No intersection with the laser sheet => no laser contribution */ - if(HIT_NONE(laser_hit_dst[0])) return 0; + ASSERT(cmd && rng && pos && dir); - /* Sample the scattering position into the laser sheet */ - range[0] = laser_hit_dst[0]; - range[1] = laser_hit_dst[1]; - sample_scattering_limited(cmd, rng, wlen, pos, dir, range, &sample); + /* Fetch the laser wavelength */ + wlen = htrdr_combustion_laser_get_wavelength(cmd->laser); - /* No scattering in the laser sheet => no laser contribution */ - if(HIT_NONE(sample.distance)) return 0; + /* Find the intersections along dir with the laser sheet */ + htrdr_combustion_laser_trace_ray(cmd->laser, pos, dir, range, laser_hit_dst); - /* Compute the transmissivity due to absorption from 'xin' to 'xs' */ - range[0] = laser_hit_dst[0]; - range[1] = sample.distance; - Tr_xin_xs = transmissivity(cmd, rng, ATRSTM_RADCOEF_Ka, wlen, pos, dir, range); + /* No intersection with the laser sheet => no laser contribution */ + if(HTRDR_COMBUSTION_LASER_HIT_NONE(laser_hit_dst)) return 0; /* Compute the transmissivity from 'pos' to 'xin' */ range[0] = 0; range[1] = laser_hit_dst[0]; - Tr_pos_xin = transmissivity(cmd, rng, ATRSTM_RADCOEF_Kext, wlen, pos, dir, range); - - (void)Tr_xin_xs, (void)Tr_pos_xin; + Tr_ext_pos_xin = transmissivity(cmd, rng, ATRSTM_RADCOEF_Kext, pos, dir, range); + if(Tr_ext_pos_xin == 0) return 0; /* no laser contribution */ + /* Sample the scattering position into the laser sheet */ + range[0] = laser_hit_dst[0]; + range[1] = laser_hit_dst[1]; + sample_scattering_limited(cmd, rng, pos, dir, range, &sc_sample); + if(POSITION_NONE(&sc_sample.position)) return 0; /* No laser contribution */ + ASSERT(laser_hit_dst[0] <= sc_sample.position.distance); + ASSERT(laser_hit_dst[1] >= sc_sample.position.distance); + + /* Compute the transmissivity from 'xin' to 'xsc' */ + range[0] = laser_hit_dst[0]; /* <=> xin */ + range[1] = sc_sample.position.distance; /* <=> xsc */ + Tr_abs_xin_xsc = transmissivity(cmd, rng, ATRSTM_RADCOEF_Ka, pos, dir, range); + if(Tr_abs_xin_xsc == 0) return 0; /* No laser contribution */ + + /* Compute the scattering position */ + xsc[0] = pos[0] + dir[0] * sc_sample.position.distance; + xsc[1] = pos[1] + dir[1] * sc_sample.position.distance; + xsc[2] = pos[2] + dir[2] * sc_sample.position.distance; + + /* Retrieve the direction toward the laser surface emission */ + htrdr_combustion_laser_get_direction(cmd->laser, wi); + d3_minus(wi, wi); + + /* Compute the transmissivity from xsc to the laser surface emission */ + range[0] = 0; + range[1] = htrdr_combustion_laser_compute_surface_plane_distance + (cmd->laser, xsc); + ASSERT(range[1] >= 0); + Tr_ext_xsc_lse = transmissivity(cmd, rng, ATRSTM_RADCOEF_Kext, xsc, wi, range); + if(Tr_ext_xsc_lse == 0) return 0; /* No aser contribution */ + + /* Retrieve the RDG-FA phase function parameters from the semi transparent + * medium */ + fetch_rdgfa_args.wavelength = wlen; + fetch_rdgfa_args.prim = sc_sample.position.prim; + d4_set(fetch_rdgfa_args.bcoords, sc_sample.position.bcoords); + ATRSTM(fetch_rdgfa(cmd->medium, &fetch_rdgfa_args, &rdgfa_param)); + + /* Setup the RDG-FA phase function */ + rdgfa = cmd->rdgfa_phase_functions[ithread]; + setup_rdgfa_args.wavelength = rdgfa_param.wavelength; + setup_rdgfa_args.fractal_dimension = rdgfa_param.fractal_dimension; + setup_rdgfa_args.gyration_radius = rdgfa_param.gyration_radius; + SSF(phase_rdgfa_setup(rdgfa, &setup_rdgfa_args)); + + /* Evaluate the phase function at the scattering position */ + d3_minus(wo, dir); /* Ensure SSF convention */ + R = ssf_phase_eval(rdgfa, wo, wi); /* In sr^-1 */ + + laser_flux_density = htrdr_combustion_laser_get_flux_density(cmd->laser); + + L = Tr_ext_pos_xin + * Tr_abs_xin_xsc + * sc_sample.ksi * R + * Tr_ext_xsc_lse + * laser_flux_density; return L; } @@ -379,27 +593,48 @@ combustion_compute_radiance_sw const size_t ithread, struct ssp_rng* rng, const double pos_in[3], - const double dir_in[3], - const double wlen) /* In nanometer */ + const double dir_in[3]) { double pos[3]; double dir[3]; double range[2]; - double ksi; /* Throughput */ double weight; + + /* Transmissivity due to absorption between two consecutive scattering + * positions */ + double Tr_abs; + ASSERT(cmd && rng && pos_in && dir_in); - (void)cmd, (void)ithread, (void)rng, (void)pos_in, (void)dir_in, (void)wlen; - (void)ksi, (void)laser_once_scattered; + (void)cmd, (void)ithread, (void)rng, (void)pos_in, (void)dir_in; + (void)Tr_abs, (void)laser_once_scattered; d3_set(pos, pos_in); d3_set(dir, dir_in); d2(range, 0, FLT_MAX); - ksi = 1; + Tr_abs = 1; weight = 0; - /* TODO Radiative random walk */ + for(;;) { + struct position scattering = POSITION_NULL; + double laser_sheet_emissivity = 0; /* In W/m^2/sr */ + double Tr_abs_pos_xsc = 0; + + laser_sheet_emissivity = laser_once_scattered(cmd, ithread, rng, pos, dir); + weight += Tr_abs * laser_sheet_emissivity; + /* Sample a scattering position */ + sample_position(cmd, rng, ATRSTM_RADCOEF_Ks, pos, dir, range, &scattering); + if(POSITION_NONE(&scattering)) break; + + /* Compute the absorption transmissivity */ + range[0] = 0; + range[1] = scattering.distance; + Tr_abs_pos_xsc = transmissivity(cmd, rng, ATRSTM_RADCOEF_Ka, pos, dir, range); + if(Tr_abs_pos_xsc == 0) break; + + /* TODO */ + } return weight; } diff --git a/src/combustion/htrdr_combustion_draw_map.c b/src/combustion/htrdr_combustion_draw_map.c @@ -69,7 +69,7 @@ draw_pixel /* Backward trace the path */ weight = combustion_compute_radiance_sw(cmd, args->ithread, args->rng, - ray_org, ray_dir, cmd->wavelength); + ray_org, ray_dir); /* End the registration of the per realisation time */ time_sub(&t0, time_current(&t1), &t0);