rnatm

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

commit 6c7aa5ceb2fcb86d382e4e17e561ea28ad231b5c
parent e931a643301a4874ec132a8fe0b5bec2a46a5d72
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 25 Aug 2022 18:32:26 +0200

Consider aerosols when building octrees

Diffstat:
Msrc/rnatm_octree.c | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 170 insertions(+), 17 deletions(-)

diff --git a/src/rnatm_octree.c b/src/rnatm_octree.c @@ -24,6 +24,7 @@ #include "rnatm_log.h" #include "rnatm_voxel_partition.h" +#include <star/sars.h> #include <star/sck.h> #include <star/suvm.h> #include <star/svx.h> @@ -32,6 +33,7 @@ #include <rsys/condition.h> #include <rsys/cstr.h> #include <rsys/double3.h> +#include <rsys/float4.h> #include <rsys/math.h> #include <rsys/morton.h> #include <rsys/mutex.h> @@ -40,6 +42,7 @@ #include <math.h> /* lround */ #include <omp.h> +#define GAS SIZE_MAX #define VOXELIZE_MSG "voxelize atmosphere: %3d%%\r" /* Structure used to synchronise the voxelization and the build threads */ @@ -138,6 +141,7 @@ struct voxelize_args { const struct accel_struct* accel_structs; size_t batch_size; /* #spectral items */ + }; #define VOXELIZE_ARGS_NULL__ { \ NULL, /* Tetra ids */ \ @@ -448,7 +452,7 @@ compute_grid_definition(struct rnatm* atm, const struct rnatm_create_args* args) } static INLINE void -setup_tetra_radcoefs +setup_tetra_radcoefs_gas (struct rnatm* atm, const struct suvm_primitive* tetra, const size_t iband, @@ -490,6 +494,110 @@ setup_tetra_radcoefs radcoefs->kext_max = MMAX(MMAX(kext[0], kext[1]), MMAX(kext[2], kext[3])); } +static void +setup_tetra_radcoefs_aerosol + (struct rnatm* atm, + const struct suvm_primitive* tetra, + const size_t iband, + const size_t iquad_pt, + const struct aerosol* aerosol, + struct radcoefs* radcoefs) +{ + struct sck_band gas_band; + struct sars_band ars_band; + double gas_spectral_range[2]; /* In cm^-1 */ + size_t ars_ibands[2]; + ASSERT(atm && aerosol && tetra && radcoefs); + + /* Look for the aerosol bands covered by the gas band */ + SCK(get_band(atm->gas.ck, iband, &gas_band)); + gas_spectral_range[0] = gas_band.lower; + gas_spectral_range[1] = gas_band.upper; + SARS(find_overlaped_bands(aerosol->sars, gas_spectral_range, ars_ibands)); + + /* TODO ask VE what to do if: + * - the spectral meshes have holes + * - no aerosol band is overlaid by the gas band + * - the aerosol bands are entirely included in the gas band + * - gas/an aerosol band is degenerated (i.e. lower == upper) */ + + /* Aerosol spectral data is not overlaid by the gas band */ + if(ars_ibands[0] > ars_ibands[1]) FATAL("Not implemented yet!\n"); + + SARS(get_band(aerosol->sars, ars_ibands[0], &ars_band)); + + /* The gas band is included in an aerosol band: use gas spectral data */ + if(ars_ibands[0] == ars_ibands[1] + && ars_band.lower <= gas_band.lower + && ars_band.upper >= gas_band.upper) { + setup_tetra_radcoefs_gas(atm, tetra, iband, iquad_pt, radcoefs); + + /* The gas band overlaid N aerosol bands (N >= 1) */ + } else { + float tau_ka[4] = {0, 0, 0, 0}; + float tau_ks[4] = {0, 0, 0, 0}; + float ka[4], ks[4], kext[4]; + float rcp_gas_band_len; + size_t iars_band; + + FOR_EACH(iars_band, ars_ibands[0], ars_ibands[1]+1) { + double lambda_min; + double lambda_max; + float lambda_len; + + SARS(get_band(aerosol->sars, iars_band, &ars_band)); + lambda_min = MMIN(gas_band.lower, ars_band.lower); + lambda_max = MMAX(gas_band.upper, ars_band.upper); + lambda_len = (float)(lambda_max - lambda_min); + + tau_ks[0] += ars_band.ks_list[tetra->indices[0]] * lambda_len; + tau_ks[1] += ars_band.ks_list[tetra->indices[1]] * lambda_len; + tau_ks[2] += ars_band.ks_list[tetra->indices[2]] * lambda_len; + tau_ks[3] += ars_band.ks_list[tetra->indices[3]] * lambda_len; + + tau_ka[0] += ars_band.ka_list[tetra->indices[0]] * lambda_len; + tau_ka[1] += ars_band.ka_list[tetra->indices[1]] * lambda_len; + tau_ka[2] += ars_band.ka_list[tetra->indices[2]] * lambda_len; + tau_ka[3] += ars_band.ka_list[tetra->indices[3]] * lambda_len; + } + + /* Compute the radiative coefficients of the tetrahedron */ + ASSERT(gas_band.upper != gas_band.lower); /* FIXME is it possible? */ + rcp_gas_band_len = 1.f / (float)(gas_band.upper - gas_band.lower); + f4_mulf(ks, tau_ks, rcp_gas_band_len); + f4_mulf(ka, tau_ka, rcp_gas_band_len); + f4_add(kext, ka, ks); + + /* Compute the radiative coefficients range of the tetrahedron */ + radcoefs->ks_min = MMIN(MMIN(ks[0], ks[1]), MMIN(ks[2], ks[3])); + radcoefs->ks_max = MMAX(MMAX(ks[0], ks[1]), MMAX(ks[2], ks[3])); + radcoefs->ka_min = MMIN(MMIN(ka[0], ka[1]), MMIN(ka[2], ka[3])); + radcoefs->ka_max = MMAX(MMAX(ka[0], ka[1]), MMAX(ka[2], ka[3])); + radcoefs->kext_min = MMIN(MMIN(kext[0], kext[1]), MMIN(kext[2], kext[3])); + radcoefs->kext_max = MMAX(MMAX(kext[0], kext[1]), MMAX(kext[2], kext[3])); + } +} + +static INLINE void +setup_tetra_radcoefs + (struct rnatm* atm, + const struct suvm_primitive* tetra, + const size_t iband, + const size_t iquad_pt, + const size_t cpnt, + struct radcoefs* radcoefs) +{ + ASSERT(atm && tetra && radcoefs); + ASSERT(cpnt == GAS || cpnt < darray_aerosol_size_get(&atm->aerosols)); + + if(cpnt == GAS) { + setup_tetra_radcoefs_gas(atm, tetra, iband, iquad_pt, radcoefs); + } else { + const struct aerosol* aerosol = darray_aerosol_cdata_get(&atm->aerosols)+cpnt; + setup_tetra_radcoefs_aerosol(atm, tetra, iband, iquad_pt, aerosol, radcoefs); + } +} + static INLINE void update_voxel (struct rnatm* atm, @@ -530,10 +638,22 @@ update_voxel } static res_T -voxelize_gas(struct rnatm* atm, const struct voxelize_args* args) +voxelize_tetra + (struct rnatm* atm, + const struct voxelize_args* args, + const size_t cpnt) { + const struct suvm_volume* volume = NULL; size_t i; ASSERT(atm && check_voxelize_args(args) == RES_OK); + ASSERT(cpnt == GAS || cpnt < darray_aerosol_size_get(&atm->aerosols)); + + /* Fetch the component volumetric mesh */ + if(cpnt == GAS) { + volume = atm->gas.volume; + } else { + volume = darray_aerosol_cdata_get(&atm->aerosols)[cpnt].volume; + } partition_clear_voxels(args->part); @@ -553,7 +673,7 @@ voxelize_gas(struct rnatm* atm, const struct voxelize_args* args) enum suvm_intersection_type intersect; /* Recover the tetrahedron and setup its polyhedron */ - SUVM(volume_get_primitive(atm->gas.volume, itetra, &tetra)); + SUVM(volume_get_primitive(volume, itetra, &tetra)); SUVM(primitive_setup_polyhedron(&tetra, &poly)); ASSERT(poly.lower[0] <= args->part_upp[0]); ASSERT(poly.lower[1] <= args->part_upp[1]); @@ -586,7 +706,7 @@ voxelize_gas(struct rnatm* atm, const struct voxelize_args* args) const size_t iband = args->accel_structs[iitem].iband; const size_t iquad_pt = args->accel_structs[iitem].iquad_pt; struct radcoefs* radcoefs = args->per_item_radcoefs + iitem; - setup_tetra_radcoefs(atm, &tetra, iband, iquad_pt, radcoefs); + setup_tetra_radcoefs(atm, &tetra, iband, iquad_pt, cpnt, radcoefs); } /* Iterate voxels intersected by the AABB of the polyedron */ @@ -622,31 +742,64 @@ voxelize_gas(struct rnatm* atm, const struct voxelize_args* args) } static res_T -voxelize_partition(struct rnatm* atm, const struct voxelize_args* args) +voxelize_partition_component + (struct rnatm* atm, + const struct voxelize_args* args, + const size_t cpnt) { + struct suvm_volume* volume = NULL; res_T res = RES_OK; - ASSERT(atm && check_voxelize_args(args) == RES_OK); + ASSERT(atm && args); + ASSERT(cpnt == GAS || cpnt < darray_aerosol_size_get(&atm->aerosols)); + + /* Get the volumetric mesh of the component */ + if(cpnt == GAS) { + volume = atm->gas.volume; + } else { + volume = darray_aerosol_cdata_get(&atm->aerosols)[cpnt].volume; + } /* Find the list of gas tetrahedra that overlap the partition */ darray_size_t_clear(args->tetra_ids); res = suvm_volume_intersect_aabb - (atm->gas.volume, - args->part_low, - args->part_upp, - register_tetra, - args->tetra_ids); + (volume, args->part_low, args->part_upp, register_tetra, args->tetra_ids); if(res != RES_OK) goto error; - /* The partition is not covered by any tetrahedron */ - if(darray_size_t_size_get(args->tetra_ids) == 0) { - partition_empty(args->part); - goto exit; + if(darray_size_t_size_get(args->tetra_ids) != 0) { + res = voxelize_tetra(atm, args, cpnt); + if(res != RES_OK) goto error; } - res = voxelize_gas(atm, args); +exit: + return res; +error: + goto exit; +} + +static res_T +voxelize_partition(struct rnatm* atm, const struct voxelize_args* args) +{ + size_t iaerosol = 0; + size_t naerosols = 0; + int part_is_empty = 1; + res_T res = RES_OK; + ASSERT(atm && check_voxelize_args(args) == RES_OK); + + /* Voxelize the gas */ + res = voxelize_partition_component(atm, args, GAS); if(res != RES_OK) goto error; + part_is_empty = part_is_empty && !darray_size_t_size_get(args->tetra_ids); + + /* Voxelize the aerosols */ + naerosols = darray_aerosol_size_get(&atm->aerosols); + FOR_EACH(iaerosol, 0, naerosols) { + res = voxelize_partition_component(atm, args, iaerosol); + if(res != RES_OK) goto error; + part_is_empty = part_is_empty && !darray_size_t_size_get(args->tetra_ids); + } - /* TODO voxelise aerosols */ + /* The partition is not overlaped by any tetrahedron */ + if(part_is_empty) partition_empty(args->part); exit: return res;