star-schiff

Library for estimating radiative properties
git clone git://git.meso-star.com/star-schiff.git
Log | Files | Refs | README | LICENSE

commit ae3f5f8178fb7c601a061671d03a1a7ada6f092f
parent 3ff881a2accdc907ad9b5d7de412e8ab88d366a0
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  2 Mar 2016 15:24:32 +0100

Conditionally discard phase function evaluation

Do not estimate the differential cross section [cumulative] if no valid
limit scattering angle can be found.

Diffstat:
Msrc/sschiff_estimator.c | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/test_sschiff_estimator_sphere.c | 2+-
2 files changed, 96 insertions(+), 42 deletions(-)

diff --git a/src/sschiff_estimator.c b/src/sschiff_estimator.c @@ -50,6 +50,7 @@ #include <gsl/gsl_multiroots.h> #define MAX_FAILURES 10 +#define INVALID_LIMIT_ANGLE SIZE_MAX /* Accumulator of double precision values */ struct accum { @@ -120,6 +121,7 @@ struct sschiff_estimator { struct mc_accum* accums; /* Monte Carlo estimation */ size_t nrealisations; /* # realisation used by MC estimations */ + int no_phase_function; /* Set to 1 when no phase function is computed */ struct sschiff_device* dev; ref_T ref; @@ -366,6 +368,10 @@ accum_differential_cross_section double tmp; size_t iangle; + /* Avoid evaluating the differential cross sections for wavelengths with no + * valid limit scattering angle */ + if(ctx->estimator->limit_angles[iwlen] == INVALID_LIMIT_ANGLE) continue; + /* Fetch optical properties */ k_e = ctx->estimator->wavenumbers[iwlen]; n_r = ctx->estimator->properties[iwlen].relative_real_refractive_index; @@ -400,7 +406,7 @@ accum_differential_cross_section ctx->accums[iwlen].differential_cross_section[iangle] += weight; bessel_j1 = gsl_sf_bessel_J1(k_e_angle_delta_r); - weight = 2*PI * ctx->estimator->angles[iangle] * bessel_j1 / k_e_delta_r * tmp; + weight = 2*PI*ctx->estimator->angles[iangle]*bessel_j1/k_e_delta_r*tmp; ctx->accums[iwlen].differential_cross_section_cumulative[iangle] += weight; } } @@ -464,6 +470,9 @@ accum_monte_carlo_weight /* Compute and accumulate the cross section weight */ accum_cross_section(ctx, plane_area, path_length[0]); + /* Avoid the estimation of the phase function */ + if(ctx->estimator->no_phase_function) break; + /* Uniformly sample a position onto the projection plane and use it as the * origin of the 2nd ray to trace */ sample[0] = ssp_rng_uniform_double(ctx->rng, -1.0, 1.0); @@ -542,6 +551,9 @@ radiative_properties ctx->accums[iwlen].scattering_cross_section = 0; ctx->accums[iwlen].avg_projected_area = 0; + /* Do not clean up accumulators of invalid differential cross section */ + if(ctx->estimator->limit_angles[iwlen] == INVALID_LIMIT_ANGLE) continue; + /* Clean up to "limit_angle" since great angles are analytically computed */ memset(ctx->accums[iwlen].differential_cross_section, 0, sizeof(double)*ctx->estimator->limit_angles[iwlen]); @@ -592,6 +604,9 @@ radiative_properties MC_ACCUM(scattering_cross_section); MC_ACCUM(avg_projected_area); + if(ctx->estimator->limit_angles[iwlen] == INVALID_LIMIT_ANGLE) + continue; + /* Accum up to "limit angle" since great angles are analitically computed */ FOR_EACH(iangle, 0, ctx->estimator->limit_angles[iwlen]) { MC_ACCUM(differential_cross_section[iangle]); @@ -608,10 +623,14 @@ error: ctx->mc_accums[iwlen].absorption_cross_section = MC_DATA_NULL; ctx->mc_accums[iwlen].scattering_cross_section = MC_DATA_NULL; ctx->mc_accums[iwlen].avg_projected_area = MC_DATA_NULL; + + if(ctx->estimator->limit_angles[iwlen] == INVALID_LIMIT_ANGLE) + continue; + memset(ctx->mc_accums[iwlen].differential_cross_section, 0, - sizeof(double)*ctx->nangles); + sizeof(double)*ctx->estimator->limit_angles[iwlen]); memset(ctx->mc_accums[iwlen].differential_cross_section_cumulative, 0, - sizeof(double)*ctx->nangles); + sizeof(double)*ctx->estimator->limit_angles[iwlen]); } goto exit; } @@ -872,7 +891,7 @@ compute_phase_function if(n < 2 || n > 4) { log_warning(estimator->dev, "The wide scattering angles phase function model parameter `n' is not in\n" -"[0, 4]. One might increase the number of realisations.\n" +"[2, 4]. One might increase the number of realisations.\n" " n = %g\n" " scattering cross section = %g +/- %g\n" " differential cross section = %g +/- %g\n" @@ -919,7 +938,7 @@ compute_phase_function /* Check the post condition of the cumulative differential cross section */ /*ASSERT(eq_eps (estimator->accums[iwlen].differential_cross_section_cumulative[nangles-1].weight, - scattering_cross_section, 1.e-3));*/ + scattering_cross_section.E, 1.e-3));*/ /* Compute the [cumulative] phase function for small angles */ rcp_scattering_cross_section = 1.0/scattering_cross_section.E; @@ -961,6 +980,8 @@ compute_phase_function exit: return res; error: + memset(estimator->phase_functions[iwlen].values, 0, nangles); + memset(estimator->phase_functions[iwlen].cumulative, 0, nangles); goto exit; } @@ -1087,11 +1108,16 @@ integrator_context_init } (void)0 RESIZE(ctx->accums, nwavelengths); FOR_EACH(iwlen, 0, nwavelengths) { + /* Do not allocate the accumulators if no limit angle was found */ + if(estimator->limit_angles[iwlen] == INVALID_LIMIT_ANGLE) continue; RESIZE(ctx->accums[iwlen].differential_cross_section, nangles); RESIZE(ctx->accums[iwlen].differential_cross_section_cumulative, nangles); } + RESIZE(ctx->mc_accums, nwavelengths); FOR_EACH(iwlen, 0, nwavelengths) { + /* Do not allocate the accumulators if no limit angle was found */ + if(estimator->limit_angles[iwlen] == INVALID_LIMIT_ANGLE) continue; RESIZE(ctx->mc_accums[iwlen].differential_cross_section, nangles); RESIZE(ctx->mc_accums[iwlen].differential_cross_section_cumulative, nangles); } @@ -1202,6 +1228,7 @@ estimator_create struct sschiff_estimator* estimator = NULL; double rcp_PI_Lc; size_t i; + int hold_valid_limit_angle = 0; res_T res = RES_OK; ASSERT(dev && distrib && wavelengths && nwavelengths); ASSERT(angles_distrib && nangles && out_estimator); @@ -1288,54 +1315,69 @@ estimator_create /* Search for limit scattering angle */ theta_l = sqrt(lambda_e * rcp_PI_Lc); if(theta_l <= 0 || theta_l >= PI) { - log_error(dev, + log_warning(dev, "Invalid theta limit, i.e. angle between small and wide scattering angles\n" "`%g'. The phase function for the wavelengths `%g' and its [inverse]\n" "cumulative will be not computed.\n", theta_l, estimator->wavelengths[i]); - res = RES_BAD_ARG; - goto error; - } - angle = search_lower_bound(&theta_l, estimator->angles, nangles, - sizeof(double), cmp_double); - if(!angle) { - log_error(dev, + estimator->limit_angles[i] = INVALID_LIMIT_ANGLE; + } else { + angle = search_lower_bound(&theta_l, estimator->angles, nangles, + sizeof(double), cmp_double); + if(!angle) { + log_error(dev, "Can't find a limit scattering angle for theta limit `%g'.\n", theta_l); - res = RES_BAD_ARG; - goto error; - } - if(eq_eps(*angle, PI, 1.e-6)) { - log_error(dev, "Invalid limit scattering angle `%g'.\n", *angle); - res = RES_BAD_ARG; - goto error; + res = RES_BAD_ARG; + goto error; + } + if(eq_eps(*angle, PI, 1.e-6)) { + log_error(dev, "Invalid limit scattering angle `%g'.\n", *angle); + res = RES_BAD_ARG; + goto error; + } + /* Define the index of the first "wide scattering angle" */ + estimator->limit_angles[i] = (size_t)(angle - estimator->angles); + ASSERT(estimator->limit_angles[i] < nangles); + hold_valid_limit_angle = 1; } - /* Define the index of the first "wide scattering angle" */ - estimator->limit_angles[i] = (size_t)(angle - estimator->angles); - ASSERT(estimator->limit_angles[i] < nangles); + } + estimator->no_phase_function = !hold_valid_limit_angle; + if(estimator->no_phase_function) { + /* No phase function => The scattering angles are useless */ + sa_release(estimator->angles); + estimator->angles = NULL; } /* Allocate the estimator accumulators */ RESIZE(estimator->accums, nwavelengths, "Couldn't allocate the Monte Carlo accumulator of the estimator.\n"); - memset(estimator->accums, 0, sizeof(estimator->accums[0])*nwavelengths); - FOR_EACH(i, 0, nwavelengths) { - RESIZE(estimator->accums[i].differential_cross_section, nangles, - "Couldn't allocate the differential cross sections to estimate.\n"); - RESIZE(estimator->accums[i].differential_cross_section_cumulative, nangles, - "Couldn't allocate the cumulative differential cross sections to estimate.\n"); + if(!estimator->no_phase_function) { + FOR_EACH(i, 0, nwavelengths) { + /* Do not allocate the MC accumulator if no limit angle was found */ + if(estimator->limit_angles[i] == INVALID_LIMIT_ANGLE) continue; + RESIZE(estimator->accums[i].differential_cross_section, nangles, + "Couldn't allocate the differential cross sections to estimate.\n"); + RESIZE(estimator->accums[i].differential_cross_section_cumulative, nangles, + "Couldn't allocate the cumulative differential cross sections to estimate.\n"); + } } - /* Allocate the phase function data */ - RESIZE(estimator->phase_functions, nwavelengths, - "Couldn't allocate the per wavelength phase functions data.\n"); - FOR_EACH(i, 0, nwavelengths) { - RESIZE(estimator->phase_functions[i].values, nangles, - "Couldn't allocate the per angle phase function values.\n"); - RESIZE(estimator->phase_functions[i].cumulative, nangles, - "Couldn't allocate the per angle cumulative phase function.\n"); + if(!estimator->no_phase_function) { + /* Allocate the phase function data */ + RESIZE(estimator->phase_functions, nwavelengths, + "Couldn't allocate the per wavelength phase functions data.\n"); + FOR_EACH(i, 0, nwavelengths) { + /* Do not allocate the phase functions data if no limit angle was found */ + if(estimator->limit_angles[i] == INVALID_LIMIT_ANGLE) continue; + RESIZE(estimator->phase_functions[i].values, nangles, + "Couldn't allocate the per angle phase function values.\n"); + RESIZE(estimator->phase_functions[i].cumulative, nangles, + "Couldn't allocate the per angle cumulative phase function.\n"); + } } #undef RESIZE + exit: *out_estimator = estimator; return res; @@ -1461,6 +1503,9 @@ sschiff_integrate MC_ACCUM(scattering_cross_section); MC_ACCUM(avg_projected_area); + /* Discard differential cross section accumulation for invalid angle */ + if(estimator->limit_angles[iwlen] == INVALID_LIMIT_ANGLE) continue; + /* Accum up to "limit angle"; Great angles are analitically computed */ FOR_EACH(iangle, 0, estimator->limit_angles[iwlen]) { MC_ACCUM(differential_cross_section[iangle]); @@ -1469,13 +1514,12 @@ sschiff_integrate } } -#if 1 /* TODO use parallelism */ FOR_EACH(i, 0, nwavelengths) { - res = compute_phase_function(dev, i, nangles, estimator); - if(res != RES_OK) goto error; + if(estimator->limit_angles[i] == INVALID_LIMIT_ANGLE) continue; + /* Do not handle phase function errors */ + compute_phase_function(dev, i, nangles, estimator); } -#endif exit: if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy)); @@ -1599,6 +1643,9 @@ sschiff_estimator_get_phase_function { if(!estimator || !states || iwlen >= sa_size(estimator->wavelengths)) return RES_BAD_ARG; + /* No phase function was computed */ + if(estimator->limit_angles[iwlen] == INVALID_LIMIT_ANGLE) + return RES_OK; *states = estimator->phase_functions[iwlen].values; return RES_OK; } @@ -1612,6 +1659,9 @@ sschiff_estimator_get_phase_function_cumulative { if(!estimator || !states || iwlen >= sa_size(estimator->wavelengths)) return RES_BAD_ARG; + /* No phase function cumulative was computed */ + if(estimator->limit_angles[iwlen] == INVALID_LIMIT_ANGLE) + return RES_OK; *states = estimator->phase_functions[iwlen].cumulative; return RES_OK; } @@ -1636,6 +1686,10 @@ sschiff_estimator_inverse_cumulative_phase_function goto error; } + /* No phase function cumulative is computed => nothing to inverse */ + if(estimator->limit_angles[iwlen] == INVALID_LIMIT_ANGLE) + goto exit; + /* Allocate the "filtered" phase function cumulative of small angles, i.e. * the increasing cumulative defined from the Monte-Carlo estimation. */ nsmall_angles = estimator->limit_angles[iwlen]; diff --git a/src/test_sschiff_estimator_sphere.c b/src/test_sschiff_estimator_sphere.c @@ -161,7 +161,7 @@ check_schiff_estimation CHECK(eq_eps(val->E, results[i].scattering_cross_section, 4*val->SE), 1); val = &cross_section.average_projected_area; - printf(" Averavege projected area = %12.6g +/- %12.7g\n", val->E, val->SE); + printf(" Averavege projected area = %12.7g +/- %12.7g\n", val->E, val->SE); CHECK(sschiff_estimator_ref_put(estimator), RES_OK); }