htrdr

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

commit 85104c6689bd65b7ec264d261d0c446f83e68981
parent 5f233619d87c1bc6abfd06bd138b38dacf908974
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 19 Feb 2025 13:02:09 +0100

planets: solve the volumic radiative budget

Implement the estimation of the volumic radiative budget of a
tetrahedron. Note that the calculation is neither tested nor validated.

Diffstat:
Msrc/planets/htrdr_planets_solve_volrad_budget.c | 221++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 207 insertions(+), 14 deletions(-)

diff --git a/src/planets/htrdr_planets_solve_volrad_budget.c b/src/planets/htrdr_planets_solve_volrad_budget.c @@ -22,24 +22,222 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "planets/htrdr_planets_c.h" +#include "planets/htrdr_planets_source.h" #include "core/htrdr_accum.h" #include "core/htrdr_log.h" +#include "core/htrdr_ran_wlen_discrete.h" +#include "core/htrdr_ran_wlen_planck.h" #include "core/htrdr_solve_buffer.h" -#include <rsys/clock_time.h> - +#include <star/smsh.h> #include <star/ssp.h> +#include <rsys/clock_time.h> + /******************************************************************************* * Helper functions ******************************************************************************/ static void +spectral_sampling + (struct htrdr_planets* cmd, + const struct htrdr_solve_item_args* args, + double* out_wlen, /* Sampled wavelength [nm] */ + double* out_wlen_pdf, /* [nm^-1] */ + size_t* out_iband, /* Spectral band in which the sampled wavelength falls */ + size_t* out_iquad) /* Sampled quadrature point in the spectral band */ +{ + size_t iband_range[2] = {0, 0}; + size_t iband = 0; + size_t iquad = 0; + double r0, r1, r2; /* Random Numbers */ + double wlen[2] = {0,0}; /* [nm] */ + double pdf = 0; /* [nm^1] */ + + /* Preconditions */ + ASSERT(cmd && args && out_wlen && out_wlen_pdf && out_iband && out_iquad); + + r0 = ssp_rng_canonical(args->rng); + r1 = ssp_rng_canonical(args->rng); + r2 = ssp_rng_canonical(args->rng); + + /* Sample a wavelength with respect to the type of spectral integration */ + switch(cmd->spectral_domain.type) { + /* Longwave */ + case HTRDR_SPECTRAL_LW: + wlen[0] = htrdr_ran_wlen_planck_sample(cmd->planck, r0, r1, &pdf); + break; + /* Shortwave */ + case HTRDR_SPECTRAL_SW: + if(htrdr_planets_source_does_radiance_vary_spectrally(cmd->source)) { + wlen[0] = htrdr_ran_wlen_discrete_sample(cmd->discrete, r0, r1, &pdf); + } else { + wlen[0] = htrdr_ran_wlen_planck_sample(cmd->planck, r0, r1, &pdf); + } + break; + default: FATAL("Unreachable code\n"); break; + } + wlen[0] = wlen[1]; + + /* Find the band the wavelength belongs to */ + RNATM(find_bands(cmd->atmosphere, wlen, iband_range)); + ASSERT(iband_range[0] == iband_range[1]); + iband = iband_range[0]; + + /* Sample a quadrature point */ + RNATM(band_sample_quad_pt(cmd->atmosphere, r2, iband, &iquad)); + + *out_wlen = wlen[0]; + *out_wlen_pdf = pdf; + *out_iband = iband; + *out_iquad = iquad; +} + +static INLINE void +position_sampling + (const struct htrdr_solve_item_args* args, + const struct smsh_desc* desc, + double pos[3]) +{ + const double* v0 = NULL; + const double* v1 = NULL; + const double* v2 = NULL; + const double* v3 = NULL; + + /* Preconditions */ + ASSERT(args && desc && pos); + + /* Retrieve the vertices of the tetrahedron */ + v0 = desc->nodes + desc->cells[args->item_id*4/*#vertices*/+0]*3/*#coords*/; + v1 = desc->nodes + desc->cells[args->item_id*4/*#vertices*/+1]*3/*#coords*/; + v2 = desc->nodes + desc->cells[args->item_id*4/*#vertices*/+2]*3/*#coords*/; + v3 = desc->nodes + desc->cells[args->item_id*4/*#vertices*/+3]*3/*#coords*/; + + ssp_ran_tetrahedron_uniform(args->rng, v0, v1, v2, v3, pos, NULL/*pdf*/); +} + +static double /* [W/m^2/sr/m] */ +get_source + (struct htrdr_planets* cmd, + const double pos[3], + const double wlen) /* [nm] */ +{ + struct rnatm_cell_pos cell_pos = RNATM_CELL_POS_NULL; + double temperature = 0; /* [K] */ + double source = 0; /* [W/m^2/sr/m] */ + const double wlen_m = wlen * 1.e-9; /* Wavelength [m] */ + ASSERT(cmd && pos); + + switch(cmd->spectral_domain.type) { + case HTRDR_SPECTRAL_SW: + /* In shortwave, the source is external to the system */ + source = 0; + break; + + case HTRDR_SPECTRAL_LW: + RNATM(fetch_cell(cmd->atmosphere, pos, RNATM_GAS, &cell_pos)); + RNATM(cell_get_gas_temperature(cmd->atmosphere, &cell_pos, &temperature)); + source = htrdr_planck_monochromatic(wlen_m, temperature); /* [W/m^2/sr/m] */ + break; + + default: FATAL("Unreachable code\n"); break; + } + + return source; +} + +/* Return the total absorption coefficient, + * i.e. the sum of the gas and aerosol ka */ +static double +get_ka + (struct htrdr_planets* cmd, + const double pos[3], + const size_t iband, /* Spectral band */ + const size_t iquad) /* Quadrature point */ +{ + struct rnatm_cell_pos cells[RNATM_MAX_COMPONENTS_COUNT]; + struct rnatm_get_radcoef_args get_k_args = RNATM_GET_RADCOEF_ARGS_NULL; + double ka = 0; + + ASSERT(cmd && pos); + + get_k_args.cells = cells; + get_k_args.iband = iband; + get_k_args.iquad = iquad; + get_k_args.radcoef = RNATM_RADCOEF_Ka; + + /* Retrieve the list of aerosol and gas cells in which pos lies */ + RNATM(fetch_cell_list(cmd->atmosphere, pos, get_k_args.cells, NULL)); + + /* Retrive the total absorption coefficient */ + RNATM(get_radcoef(cmd->atmosphere, &get_k_args, &ka)); + + return ka; +} + +static double +realisation + (struct htrdr_planets* cmd, + const struct htrdr_solve_item_args* args, + const struct smsh_desc* volrad_mesh_desc) +{ + struct planets_compute_radiance_args rad_args = + PLANETS_COMPUTE_RADIANCE_ARGS_NULL; + + /* Spectral integration */ + double wlen = 0; /* Wavelength [nm] */ + double wlen_pdf_nm = 0; /* Wavelength pdf [nm^-1] */ + double wlen_pdf_m = 0; /* Wavelength pdf [m^-1] */ + size_t iband = 0; /* Spectral band */ + size_t iquad = 0; /* Quadrature point */ + + /* Spatial & angular integration */ + double dir[3] = {0,0,0}; + double pos[3] = {0,0,0}; + + double S = 0; /* Source [W/m^2/sr/m] */ + double L = 0; /* Radiance [W/m^2/sr/m] */ + double ka = 0; /* Absorption coefficient */ + + /* Monte Carlo weight */ + double weight = 0; /* weight [W/m^3] */ + + /* Preconditions */ + ASSERT(cmd && args && volrad_mesh_desc); + ASSERT(cmd->output_type == HTRDR_PLANETS_ARGS_OUTPUT_VOLUMIC_RADIATIVE_BUDGET); + + spectral_sampling(cmd, args, &wlen, &wlen_pdf_nm, &iband, &iquad); + position_sampling(args, volrad_mesh_desc, pos); + ssp_ran_sphere_uniform(args->rng, dir, NULL/*pdf*/); + + /* Compute the radiance in W/m^2/sr/m */ + d3_set(rad_args.path_org, pos); + d3_set(rad_args.path_dir, dir); + rad_args.rng = args->rng; + rad_args.ithread = args->ithread; + rad_args.wlen = wlen; /* [nm] */ + rad_args.iband = iband; + rad_args.iquad = iquad; + L = planets_compute_radiance(cmd, &rad_args); /* [W/m^2/sr/m] */ + + S = get_source(cmd, pos, wlen); /* [W/m^2/sr/m] */ + + ka = get_ka(cmd, pos, iband, iquad); + wlen_pdf_m = wlen_pdf_nm * 1.e9; /* Transform pdf from nm^-1 to m^-1 */ + + weight = ka * (L - S) * 4*PI / wlen_pdf_m; /* [W/m^3] */ + return weight; +} + +static void solve_volumic_radiative_budget (struct htrdr* htrdr, const struct htrdr_solve_item_args* args, void* data) { + /* Volumic mesh on which volumic radiative budget is estimated */ + struct smsh_desc volrad_mesh_desc = SMSH_DESC_NULL; + /* Monte Carlo accumulators */ struct htrdr_accum budget = HTRDR_ACCUM_NULL; struct htrdr_accum time = HTRDR_ACCUM_NULL; @@ -57,26 +255,21 @@ solve_volumic_radiative_budget ASSERT(cmd); ASSERT(cmd->output_type == HTRDR_PLANETS_ARGS_OUTPUT_VOLUMIC_RADIATIVE_BUDGET); + SMSH(get_desc(cmd->volrad_mesh, &volrad_mesh_desc)); + FOR_EACH(i, 0, args->nrealisations) { /* Time recording */ struct time t0, t1; - double usec = 0; - /* Miscellaneous */ - double w = 0; - double r = 0; + /* Monte Carlo weights */ + double w = 0; /* [W/m^3] */ + double usec = 0; /* [us] */ /* Start of realisation time recording */ time_current(&t0); - /* For now, the realisation statistically evaluates 4+1 - * TODO implement the actual calculation */ - r = ssp_rng_canonical(args->rng); - if(r < 0.5) { - w = 2; - } else { - w = 8; - } + /* Run the realisation */ + w = realisation(cmd, args, &volrad_mesh_desc); /* Stop time recording */ time_sub(&t0, time_current(&t1), &t0);