rnatm

Load and structure data describing an atmosphere
git clone git://git.meso-star.fr/rnatm.git
Log | Files | Refs | README | LICENSE

commit 909e743399ed2d7d5fc512e0496b5d8420644c2d
parent 6c0a54868890874ed5518a695fd206c81ed1b55d
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri,  4 Nov 2022 12:31:25 +0100

Add the rnatm_sample_component function

Diffstat:
Msrc/rnatm.h | 20++++++++++++++++++++
Msrc/rnatm_properties.c | 162++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 164 insertions(+), 18 deletions(-)

diff --git a/src/rnatm.h b/src/rnatm.h @@ -120,6 +120,20 @@ struct rnatm_get_radcoef_args { static const struct rnatm_get_radcoef_args RNATM_GET_RADCOEF_ARGS_NULL = RNATM_GET_RADCOEF_ARGS_NULL__; +struct rnatm_sample_component_args { + double pos[3]; /* Position to be queried */ + size_t iband; /* Index of the spectral band to consider */ + size_t iquad; /* Index of the quadrature point to consider */ + + enum rnatm_radcoef radcoef; + + double r; /* Random number uniformaly distributed in [0, 1[ */ + + /* For debug: check that the retrieved radcoef is in [k_min, k_max] */ + double k_min; + double k_max; +}; + struct rnatm_cell_get_radcoef_args { struct rnatm_cell cell; /* Cell to query */ double barycentric_coords[4]; /* Position into and relative to the cell */ @@ -271,6 +285,12 @@ rnatm_get_radcoef double* k); RNATM_API res_T +rnatm_sample_component + (const struct rnatm* atm, + const struct rnatm_sample_component_args* args, + size_t* cpnt); + +RNATM_API res_T rnatm_fetch_cell (const struct rnatm* atm, const double pos[3], diff --git a/src/rnatm_properties.c b/src/rnatm_properties.c @@ -34,6 +34,9 @@ #include <rsys/clock_time.h> #include <rsys/cstr.h> +#define CUMULATIVE_SIZE_MAX 32 +typedef double (cumulative_T)[CUMULATIVE_SIZE_MAX]; + /******************************************************************************* * Helper functions ******************************************************************************/ @@ -70,6 +73,42 @@ check_rnatm_get_radcoef_args } static res_T +check_rnatm_sample_component_args + (const struct rnatm* atm, + const struct rnatm_sample_component_args* args) +{ + size_t i, n; + + if(!args) return RES_BAD_ARG; + + /* Invalid band index */ + n = darray_band_size_get(&atm->bands) - 1; + if(args->iband < darray_band_cdata_get(&atm->bands)[0].index + || args->iband > darray_band_cdata_get(&atm->bands)[n].index) + return RES_BAD_ARG; + + /* Invalid quadrature point index */ + i = args->iband - darray_band_cdata_get(&atm->bands)[0].index; + ASSERT(i <= n && args->iband == darray_band_cdata_get(&atm->bands)[i].index); + if(args->iquad >= darray_band_cdata_get(&atm->bands)[i].nquad_pts) + return RES_BAD_ARG; + + /* Invalid radiative coefficient */ + if((unsigned)args->radcoef >= RNATM_RADCOEFS_COUNT__) + return RES_BAD_ARG; + + /* Invalid random number */ + if(args->r < 0 || args->r >= 1) + return RES_BAD_ARG; + + /* Invalid K range */ + if(args->k_min > args->k_max) + return RES_BAD_ARG; + + return RES_OK; +} + +static res_T check_rnatm_cell_get_radcoef_args (const struct rnatm* atm, const struct rnatm_cell_get_radcoef_args* args) @@ -923,37 +962,42 @@ error: goto exit; } -/******************************************************************************* - * Exported functions - ******************************************************************************/ -res_T -rnatm_get_radcoef +static res_T +compute_unnormalized_cumulative_radcoef (const struct rnatm* atm, - const struct rnatm_get_radcoef_args* args, - double* out_k) + const enum rnatm_radcoef radcoef, + const double pos[3], + const size_t iband, + const size_t iquad, + cumulative_T cumulative, + size_t* cumulative_sz) { struct rnatm_cell_get_radcoef_args cell_args = RNATM_CELL_GET_RADCOEF_ARGS_NULL; size_t cpnt = RNATM_GAS; + size_t naerosols = 0; + size_t icumul = 0; double k = 0; res_T res = RES_OK; + ASSERT(atm && (unsigned)radcoef < RNATM_RADCOEFS_COUNT__); + ASSERT(cumulative && cumulative_sz); - if(!atm || !out_k) { res = RES_BAD_ARG; goto error; } - res = check_rnatm_get_radcoef_args(atm, args); - if(res != RES_OK) goto error; + naerosols = darray_aerosol_size_get(&atm->aerosols); + if(naerosols+1/*gas*/ > CUMULATIVE_SIZE_MAX) { + res = RES_MEM_ERR; + goto error; + } - /* Setup the arguments common to all component */ - cell_args.iband = args->iband; - cell_args.iquad = args->iquad; - cell_args.radcoef = args->radcoef; - cell_args.k_min = args->k_min; - cell_args.k_max = args->k_max; + /* Setup the arguments common to all components */ + cell_args.iband = iband; + cell_args.iquad = iquad; + cell_args.radcoef = radcoef; do { double per_cell_k; /* Retrieve the cell of the component */ res = rnatm_fetch_cell - (atm, args->pos, cpnt, &cell_args.cell, cell_args.barycentric_coords); + (atm, pos, cpnt, &cell_args.cell, cell_args.barycentric_coords); if(res != RES_OK) goto error; /* This component does not exist here */ @@ -965,8 +1009,45 @@ rnatm_get_radcoef k += per_cell_k; - } while(++cpnt < darray_aerosol_size_get(&atm->aerosols)); + cumulative[icumul] = k; + ++icumul; + + } while(++cpnt < naerosols); + *cumulative_sz = naerosols + 1; +exit: + return res; +error: + goto exit; +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +rnatm_get_radcoef + (const struct rnatm* atm, + const struct rnatm_get_radcoef_args* args, + double* out_k) +{ + cumulative_T cumul; + size_t cumul_sz; + double k = 0; + res_T res = RES_OK; + + if(!atm || !out_k) { res = RES_BAD_ARG; goto error; } + res = check_rnatm_get_radcoef_args(atm, args); + if(res != RES_OK) goto error; + + /* Calculate the cumulative (unormalized) of radiative coefficients. Its last + * entry is the sum of the radiative coefficients of each component, which is + * the atmospheric radiative coefficient to be returned. */ + res = compute_unnormalized_cumulative_radcoef + (atm, args->radcoef, args->pos, args->iband, args->iquad, cumul, &cumul_sz); + if(res != RES_OK) goto error; + ASSERT(cumul_sz >= 1); + + k = cumul[cumul_sz-1]; ASSERT(args->k_min <= k && k <= args->k_max); exit: @@ -977,6 +1058,51 @@ error: } res_T +rnatm_sample_component + (const struct rnatm* atm, + const struct rnatm_sample_component_args* args, + size_t* cpnt) +{ + cumulative_T cumul; + double rcp_norm; + size_t cumul_sz; + size_t i; + res_T res = RES_OK; + + if(!atm || !cpnt) { res = RES_BAD_ARG; goto error; } + res = check_rnatm_sample_component_args(atm, args); + if(res != RES_OK) goto error; + + /* Discard the calculation of the cumulative if there is only gas */ + if(!darray_aerosol_size_get(&atm->aerosols)) { + *cpnt = RNATM_GAS; + goto exit; + } + + res = compute_unnormalized_cumulative_radcoef + (atm, args->radcoef, args->pos, args->iband, args->iquad, cumul, &cumul_sz); + if(res != RES_OK) goto error; + ASSERT(cumul_sz >= 1); + + /* Normalize the cumulative */ + rcp_norm = 1.0/cumul[cumul_sz-1]; + FOR_EACH(i, 0, cumul_sz) cumul[i] *= rcp_norm; + cumul[cumul_sz-1] = 1.0; /* Handle precision issues */ + + /* Use a simple linear search to sample the component since there are + * usually very few aerosols to consider */ + FOR_EACH(i, 0, cumul_sz) if(args->r < cumul[i]) break; + + *cpnt = i-1; + ASSERT(*cpnt == RNATM_GAS || *cpnt < darray_aerosol_size_get(&atm->aerosols)); + +exit: + return res; +error: + goto exit; +} + +res_T rnatm_cell_get_radcoef (const struct rnatm* atm, const struct rnatm_cell_get_radcoef_args* args,