htrdr

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

commit fec112abc16950412ad6386b8be9fe78bdaac916
parent b063c15a54b6586cf520999e7b908924b588a6fd
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 10 Mar 2021 16:20:14 +0100

Begin the implementation of combustion_compute_radiance_sw

Diffstat:
Msrc/combustion/htrdr_combustion_compute_radiance_sw.c | 353++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/core/htrdr_rectangle.h | 2+-
2 files changed, 352 insertions(+), 3 deletions(-)

diff --git a/src/combustion/htrdr_combustion_compute_radiance_sw.c b/src/combustion/htrdr_combustion_compute_radiance_sw.c @@ -15,11 +15,360 @@ * 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 "htrdr_combustion_c.h" +#include "combustion/htrdr_combustion_c.h" + +#include <astoria/atrstm.h> + +#include <star/ssp.h> #include <rsys/double2.h> #include <rsys/double3.h> +struct transmissivity_context { + struct ssp_rng* rng; + struct atrstm* medium; + double wavelength; + enum atrstm_radcoef radcoef; +}; +#define TRANSMISSIVITY_CONTEXT_NULL__ { \ + NULL, /* RNG */ \ + NULL, /* Medium */ \ + 0, /* Wavelength */ \ + ATRSTM_RADCOEFS_COUNT__ /* Radiative coefficient */ \ +} +static const struct transmissivity_context TRANSMISSIVITY_CONTEXT_NULL = + TRANSMISSIVITY_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; +}; +#define SAMPLE_SCATTERING_LIMITED_CONTEXT_NULL__ { \ + NULL, /* RNG */ \ + NULL, /* Medium */ \ + 0, /* Wavelength */ \ + DBL_MAX, /* Traversal dst */ \ + 1, /* ksi */ \ +} +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 + ******************************************************************************/ +static int +transmissivity_hit_filter + (const struct svx_hit* hit, + const double org[3], + const double dir[3], + const double range[2], + void* context) +{ + atrstm_radcoefs_svx_T radcoefs_svx; + struct atrstm_fetch_radcoefs_args fetch_raw_args = + 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; + double k_min = 0; + double k_max = 0; + double traversal_dst = 0; + int pursue_traversal = 1; + ASSERT(hit && org && dir && range && ctx); + (void)range; + + /* Fetch the K<min|max> of the current traversed voxel */ + fetch_svx_args.voxel = hit->voxel; + fetch_svx_args.radcoefs_mask = BIT(ctx->radcoef); + fetch_svx_args.components_mask = ATRSTM_CPNTS_MASK_ALL; + fetch_svx_args.operations_mask = ATRSTM_SVX_OP_FLAG_MIN | ATRSTM_SVX_OP_FLAG_MAX; + ATRSTM(fetch_radcoefs_svx_voxel(ctx->medium, &fetch_svx_args, radcoefs_svx)); + + k_min = radcoefs_svx[ctx->radcoef][ATRSTM_SVX_OP_MIN]; + k_max = radcoefs_svx[ctx->radcoef][ATRSTM_SVX_OP_MAX]; + + /* Setup the constants of the 'fetch' function for the current voxel */ + fetch_raw_args.wavelength = ctx->wavelength; + fetch_raw_args.radcoefs_mask = BIT(ctx->radcoef); + fetch_raw_args.components_mask = ATRSTM_CPNTS_MASK_ALL; + fetch_raw_args.k_min[ctx->radcoef] = k_min; + fetch_raw_args.k_max[ctx->radcoef] = k_max; + + /* Initialised the already traversed distance to the distance from which the + * current ray enters into the current voxel */ + traversal_dst = hit->distance[0]; + + for(;;) { + atrstm_radcoefs_T radcoefs; + double collision_dst; + double tau; + double k; + double r; + + /* 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]) { + 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; + } + } + return pursue_traversal; +} + +static double +transmissivity + (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]) +{ + struct atrstm_trace_ray_args args = ATRSTM_TRACE_RAY_ARGS_DEFAULT; + struct transmissivity_context transmissivity_ctx = TRANSMISSIVITY_CONTEXT_NULL; + struct svx_hit svx_hit = SVX_HIT_NULL; + ASSERT(cmd && rng && wlen > 0 && pos && dir && range); + + /* Degenerated range => no attenuation along dir */ + if(range[1] <= range[0]) return 1; + + /* Setup the trace ray context */ + transmissivity_ctx.rng = rng; + transmissivity_ctx.medium = cmd->medium; + transmissivity_ctx.wavelength = wlen; + transmissivity_ctx.radcoef = radcoef; + + /* Setup 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.filter = transmissivity_hit_filter; + args.context = &transmissivity_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)) { + return 1; /* No collision with the medium */ + } else { + return 0; /* A collision occurs */ + } +} + +static int +sample_scattering_limited_hit_filter + (const struct svx_hit* hit, + const double org[3], + const double dir[3], + const double range[2], + void* context) +{ + atrstm_radcoefs_svx_T radcoefs_svx; + struct atrstm_fetch_radcoefs_args fetch_raw_args = + ATRSTM_FETCH_RADCOEFS_ARGS_DEFAULT; + struct atrstm_fetch_radcoefs_svx_voxel_args fetch_svx_args = + ATRSTM_FETCH_RADCOEFS_SVX_VOXEL_ARGS_DEFAULT; + struct sample_scattering_limited_context* ctx = context; + double ks_min = 0; + double ks_max = 0; + double tau_max = 0; + double traversal_dst = 0; + int pursue_traversal = 1; + ASSERT(hit && org && dir && range && ctx); + (void)range; + + /* Fetch the Ks<min|max> of the current traversed voxel */ + 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_MIN | ATRSTM_SVX_OP_FLAG_MAX; + ATRSTM(fetch_radcoefs_svx_voxel(ctx->medium, &fetch_svx_args, radcoefs_svx)); + + ks_min = radcoefs_svx[ATRSTM_RADCOEF_Ks][ATRSTM_SVX_OP_MIN]; + ks_max = radcoefs_svx[ATRSTM_RADCOEF_Ks][ATRSTM_SVX_OP_MAX]; + + /* Setup the constants of the 'fetch' function for the current voxel */ + fetch_raw_args.wavelength = ctx->wavelength; + fetch_raw_args.radcoefs_mask = ATRSTM_RADCOEF_FLAG_Ks; + fetch_raw_args.components_mask = ATRSTM_CPNTS_MASK_ALL; + fetch_raw_args.k_min[ATRSTM_RADCOEF_Ks] = ks_min; + fetch_raw_args.k_max[ATRSTM_RADCOEF_Ks] = ks_max; + + /* Initialised the already traversed distance to the distance from which the + * current ray enters into the current voxel */ + traversal_dst = hit->distance[0]; + + tau_max = (hit->distance[1] - hit->distance[0]) * ks_max; + + for(;;) { + atrstm_radcoefs_T radcoefs; + double collision_dst; + double tau; + double ks; + double r; + + r = ssp_rng_canonical(ctx->rng); + + /* Sampled optical thickness (preferential sampling) */ + tau = -log(1.0-r*(1.0-exp(-tau_max))); + collision_dst = tau / ks_max; + + /* Compute the traversed distance up to the challenged collision */ + traversal_dst += collision_dst; + + /* Update the ksi output data */ + ctx->ksi *= 1 - exp(-tau_max); + + /* The collision to challenge lies behind the current voxel */ + if(traversal_dst > hit->distance[1]) { + 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)); + 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; + } + } + return pursue_traversal; +} + +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 atrstm_trace_ray_args args = ATRSTM_TRACE_RAY_ARGS_DEFAULT; + 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); + + /* 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; + + /* 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.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; + } +} + +static double +laser_once_scattered + (struct htrdr_combustion* cmd, + 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; + double laser_hit_dst[2] = {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); + + /* Find the intersections along dir with the laser sheet TODO */ + /* htrdr_combustion_laser_trace_ray(cmd->laser, pos, dir, range, laser_hit_dst); */ + + /* No intersection with the laser sheet => no laser contribution */ + if(HIT_NONE(laser_hit_dst[0])) return 0; + + /* 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); + + /* No scattering in the laser sheet => no laser contribution */ + if(HIT_NONE(sample.distance)) return 0; + + /* 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); + + /* 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; + + return L; +} + /******************************************************************************* * Local functions ******************************************************************************/ @@ -39,7 +388,7 @@ combustion_compute_radiance_sw double weight; ASSERT(cmd && rng && pos_in && dir_in); (void)cmd, (void)ithread, (void)rng, (void)pos_in, (void)dir_in, (void)wlen; - (void)ksi; + (void)ksi, (void)laser_once_scattered; d3_set(pos, pos_in); d3_set(dir, dir_in); diff --git a/src/core/htrdr_rectangle.h b/src/core/htrdr_rectangle.h @@ -32,7 +32,7 @@ htrdr_rectangle_create (struct htrdr* htrdr, const double sz[2], /* Size of the rectangle along its local X and Y axis */ const double pos[3], /* World space position of the rectangle center */ - const double tgt[3], /* Vector orthognal to the rectangle plane */ + const double tgt[3], /* Targeted point */ const double up[3], /* vector orthogonal to the rectangle X axis */ struct htrdr_rectangle** rect);