htrdr

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

commit 7b5b0d50f6859aa72f7f73b2bd6e3b7ed7fe97d5
parent a4051bb164313e51cc6c8a5bac2a034223aaa0ab
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 10 Aug 2018 10:28:36 +0200

Use the grid to store the precomputed cloud voxels data

Diffstat:
Msrc/htrdr.c | 4++--
Msrc/htrdr_grid.c | 25+++++++++++++++++++++++--
Msrc/htrdr_sky.c | 256++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
3 files changed, 173 insertions(+), 112 deletions(-)

diff --git a/src/htrdr.c b/src/htrdr.c @@ -238,7 +238,7 @@ htrdr_init goto error; } - /* Disable the Star-3D verbosity since the Embree backend print some messages + /* Disable the Star-3D verbosity since the Embree backend prints some messages * on stdout rather than stderr. This is annoying since stdout may be used by * htrdr to write output data */ res = s3d_device_create @@ -501,7 +501,7 @@ is_file_updated(struct htrdr* htrdr, const char* filename, int* out_upd) fd = open(str_cget(&str), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); CHK_IO(fd, "could not open/create the file"); - CHK_IO(n = read(fd, &mtime, sizeof(mtime)), "could read the `mtime' data"); + CHK_IO(n = read(fd, &mtime, sizeof(mtime)), "could not read the `mtime' data"); upd = (size_t)n != sizeof(mtime) ||mtime.tv_nsec != statbuf.st_mtim.tv_nsec diff --git a/src/htrdr_grid.c b/src/htrdr_grid.c @@ -48,7 +48,11 @@ grid_release(ref_T* ref) struct htrdr_grid* grid; ASSERT(ref); grid = CONTAINER_OF(ref, struct htrdr_grid, ref); - if(grid->fp) fclose(grid->fp); + if(grid->fp) { + const int is_finalized = 1; + CHK(fwrite(&is_finalized, sizeof(int), 1, grid->fp) == 1); + fclose(grid->fp); + } if(grid->data) { size_t grid_sz; grid_sz = @@ -82,6 +86,7 @@ htrdr_grid_create struct htrdr_grid* grid = NULL; size_t grid_sz; long grid_offset; + int is_finalized = 0; int n; res_T res = RES_OK; ASSERT(htrdr && out_grid && filename && definition); @@ -126,9 +131,12 @@ htrdr_grid_create goto error; \ } \ } (void)0 + is_finalized = 0; + WRITE(&is_finalized, 1, "is_finalized"); WRITE(&grid->pagesize, 1, "pagesize"); WRITE(&grid->cell_sz, 1, "cell_sz"); WRITE(grid->definition, 3, "definition"); + WRITE(grid->definition, 3, "definition"); /* Align the grid data on pagesize */ n = fseek @@ -197,6 +205,7 @@ htrdr_grid_open size_t grid_offset; size_t pagesize; int fd = -1; + int is_finalized = 0; res_T res = RES_OK; ASSERT(htrdr && filename && out_grid); @@ -216,7 +225,7 @@ htrdr_grid_open res = RES_IO_ERR; goto error; } - CHK(grid->fp = fdopen(fd, "rw")); + CHK(grid->fp = fdopen(fd, "w+")); #define READ(Var, N, Name) { \ if(fread((Var), sizeof(*(Var)), (N), grid->fp) != (N)) { \ @@ -226,6 +235,13 @@ htrdr_grid_open goto error; \ } \ } (void)0 + READ(&is_finalized, 1, "is_finalized"); + if(!is_finalized) { + htrdr_log_err(htrdr, "%s:%s: invalid grid.\n", FUNC_NAME, filename); + res = RES_BAD_ARG; + goto error; + } + READ(&pagesize, 1, "pagesize"); if(pagesize != grid->pagesize) { htrdr_log_err(htrdr, "%s:%s: invalid pagesize `%lu'.\n", FUNC_NAME, @@ -252,6 +268,7 @@ htrdr_grid_open res = RES_BAD_ARG; goto error; } + #undef READ grid_offset = ALIGN_SIZE((size_t)ftell(grid->fp), grid->pagesize); grid_sz = @@ -271,6 +288,10 @@ htrdr_grid_open goto error; } + rewind(grid->fp); + is_finalized = 0; + CHK(fwrite(&is_finalized, sizeof(int), 1, grid->fp) == 1); + exit: *out_grid = grid; return res; diff --git a/src/htrdr_sky.c b/src/htrdr_sky.c @@ -55,8 +55,16 @@ struct build_octree_context { double dst_max; /* Max traversal distance */ double tau_threshold; /* Threshold criteria for the merge process */ size_t iband; /* Index of the band that overlaps the CIE XYZ color space */ + + /* Precomputed voxel data of the finest level. May be NULL <=> compute the + * voxel data at runtime. */ + struct htrdr_grid* grid; }; +#define BUILD_OCTREE_CONTEXT_NULL__ { NULL, 0, 0, 0, NULL } +static const struct build_octree_context BUILD_OCTREE_CONTEXT_NULL = + BUILD_OCTREE_CONTEXT_NULL__; + struct vertex { double x; double y; @@ -82,8 +90,8 @@ vertex_eq(const struct vertex* v0, const struct vertex* v1) struct octree_data { struct htable_vertex vertex2id; /* Map a coordinate to its vertex id */ struct darray_double vertices; /* Array of unique vertices */ - struct darray_double data; - struct darray_size_t cells; + struct darray_double data; /* List of registered leaf data */ + struct darray_size_t cells; /* Ids of the cell vertices */ size_t iband; /* Index of the band that overlaps the CIE XYZ color space */ size_t iquad; /* Index of the quadrature point into the band */ const struct htrdr_sky* sky; @@ -104,9 +112,6 @@ struct sw_band_prop { struct cloud { struct svx_tree* octree; struct svx_tree_desc octree_desc; - - /* Cached data used to speed up the octree building */ - struct htrdr_grid* grid; }; struct htrdr_sky { @@ -152,7 +157,7 @@ cloud_dry_air_density /* Compute the water molar fraction */ static FINLINE double -cloud_water_molar_fraction +cloud_water_vapor_molar_fraction (const struct htcp_desc* desc, const size_t ivox[3]) { @@ -346,7 +351,8 @@ vox_get_gas /* Define the xH2O range from the LES data */ if(!ctx->sky->htcp_desc.irregular_z) { /* 1 LES voxel <=> 1 SVX voxel */ - const double x_h2o = cloud_water_molar_fraction(&ctx->sky->htcp_desc, xyz); + double x_h2o; + x_h2o = cloud_water_vapor_molar_fraction(&ctx->sky->htcp_desc, xyz); x_h2o_range[0] = x_h2o_range[1] = x_h2o; } else { /* A SVX voxel can be overlapped by 2 LES voxels */ size_t ivox[3]; @@ -357,7 +363,7 @@ vox_get_gas ivox[1] = xyz[1]; ivox[2] = darray_split_cdata_get(&ctx->sky->svx2htcp_z)[xyz[2]].index; - x_h2o_range[0] = cloud_water_molar_fraction(&ctx->sky->htcp_desc, ivox); + x_h2o_range[0] = cloud_water_vapor_molar_fraction(&ctx->sky->htcp_desc, ivox); /* Define if the SVX voxel is overlapped by 2 HTCP voxels */ ivox_next = xyz[2] + 1 < darray_split_size_get(&ctx->sky->svx2htcp_z) @@ -369,7 +375,8 @@ vox_get_gas } else { /* Overlap */ ASSERT(ivox[2] < ivox_next); ivox[2] = ivox_next; - x_h2o_range[1] = cloud_water_molar_fraction(&ctx->sky->htcp_desc, ivox); + x_h2o_range[1] = + cloud_water_vapor_molar_fraction(&ctx->sky->htcp_desc, ivox); if(x_h2o_range[0] > x_h2o_range[1]) SWAP(double, x_h2o_range[0], x_h2o_range[1]); } @@ -425,12 +432,21 @@ vox_get_gas } static void -vox_get(const size_t xyz[3], void* dst, void* ctx) +vox_get(const size_t xyz[3], void* dst, void* context) { - float* par = (float*)dst + 0*NFLOATS_PER_COMPONENT; /* Particles properties */ - float* gas = (float*)dst + 1*NFLOATS_PER_COMPONENT; /* Gas properties */ - vox_get_particle(xyz, par, ctx); - vox_get_gas(xyz, gas, ctx); + struct build_octree_context* ctx = context; + ASSERT(context); + + if(ctx->grid) { /* Fetch voxel data from precomputed grid */ + const float* vox_data = htrdr_grid_at(ctx->grid, xyz); + memcpy(dst, vox_data, NFLOATS_PER_COMPONENT*2*sizeof(float)); + } else { + /* No precomputed grid. Compute the voxel data at runtime */ + float* par = (float*)dst + 0*NFLOATS_PER_COMPONENT; /* Particles properties */ + float* gas = (float*)dst + 1*NFLOATS_PER_COMPONENT; /* Gas properties */ + vox_get_particle(xyz, par, ctx); + vox_get_gas(xyz, gas, ctx); + } } static INLINE void @@ -512,11 +528,107 @@ vox_challenge_merge && vox_challenge_merge_component(vox, nvoxs, 1*NFLOATS_PER_COMPONENT, ctx); } +/* Create/load a grid of cloud data used by SVX to build the octree. The grid + * is saved in the directory where htrdr is run with a name generated from the + * "htcp_filename" path. If a grid with the same name exists, the function + * tries to load it except if the force_update flag is set. Even though the + * grid is loaded from disk, the function will recompute and store it if the + * definition of the loaded grid is different from the submitted definition. */ static res_T -setup_clouds(struct htrdr_sky* sky) +setup_cloud_grid + (struct htrdr_sky* sky, + const size_t definition[3], + const size_t iband, + const char* htcp_filename, + const int force_update, + struct htrdr_grid** out_grid) +{ + struct htrdr_grid* grid = NULL; + struct str str; + struct build_octree_context ctx = BUILD_OCTREE_CONTEXT_NULL; + size_t sizeof_cell; + size_t xyz[3]; + char buf[16]; + res_T res = RES_OK; + ASSERT(sky && definition && htcp_filename && out_grid); + ASSERT(definition[0] && definition[1] && definition[2]); + ASSERT(iband >= sky->sw_bands_range[0] && iband <= sky->sw_bands_range[1]); + + CHK((size_t)snprintf(buf, sizeof(buf), ".%lu", iband) < sizeof(buf)); + + /* Build the grid name */ + str_init(sky->htrdr->allocator, &str); + CHK(RES_OK == str_set(&str, htcp_filename)); + CHK(RES_OK == str_set(&str, basename(str_get(&str)))); + CHK(RES_OK == str_insert(&str, 0, ".htrdr_")); + CHK(RES_OK == str_append(&str, ".grid")); + CHK(RES_OK == str_append(&str, buf)); + + if(!force_update) { + /* Try to open the saved grid */ + res = htrdr_grid_open(sky->htrdr, str_cget(&str), &grid); + if(res != RES_OK) { + htrdr_log_warn(sky->htrdr, "cannot open the grid `%s'.\n", str_cget(&str)); + } else { + size_t grid_def[3]; + + /* Check that the definition is the loaded grid is the same of the + * submitted grid definition */ + htrdr_grid_get_definition(grid, grid_def); + if(grid_def[0] == definition[0] + && grid_def[1] == definition[1] + && grid_def[2] == definition[2]) { + htrdr_log(sky->htrdr, + "Use the precomputed grid `%s'.\n", str_cget(&str)); + goto exit; /* No more work to do. The loaded data seems valid */ + } + + /* The grid is no more valid. Update it! */ + htrdr_grid_ref_put(grid); + grid = NULL; + } + } + + sizeof_cell = NFLOATS_PER_COMPONENT * 2/*gas & particle*/ * sizeof(float); + + htrdr_log(sky->htrdr, "Compute the grid `%s'.\n", str_cget(&str)); + + res = htrdr_grid_create + (sky->htrdr, definition, sizeof_cell, str_cget(&str), 1, &grid); + if(res != RES_OK) goto error; + + ctx.sky = sky; + ctx.dst_max = DBL_MAX; /* Unused for grid construction */ + ctx.tau_threshold = DBL_MAX; /* Unused for grid construction */ + ctx.iband = iband; + + FOR_EACH(xyz[2], 0, definition[2]) { + FOR_EACH(xyz[1], 0, definition[1]) { + FOR_EACH(xyz[0], 0, definition[0]) { + float* data = htrdr_grid_at(grid, xyz); + vox_get(xyz, data, &ctx); + }}} + +exit: + *out_grid = grid; + str_release(&str); + return res; +error: + if(grid) { + htrdr_grid_ref_put(grid); + grid = NULL; + } + goto exit; +} + +static res_T +setup_clouds + (struct htrdr_sky* sky, + const char* htcp_filename, + const int force_cache_update) { struct svx_voxel_desc vox_desc = SVX_VOXEL_DESC_NULL; - struct build_octree_context ctx; + struct build_octree_context ctx = BUILD_OCTREE_CONTEXT_NULL; size_t nvoxs[3]; double low[3]; double upp[3]; @@ -537,7 +649,7 @@ setup_clouds(struct htrdr_sky* sky) nvoxs[1] = sky->htcp_desc.spatial_definition[1]; nvoxs[2] = sky->htcp_desc.spatial_definition[2]; - /* Define the octree AABB exepted for the Z dimension */ + /* Define the octree AABB excepted for the Z dimension */ low[0] = sky->htcp_desc.lower[0]; low[1] = sky->htcp_desc.lower[1]; low[2] = sky->htcp_desc.lower[2]; @@ -616,6 +728,11 @@ setup_clouds(struct htrdr_sky* sky) FOR_EACH(i, 0, nbands) { ctx.iband = i + sky->sw_bands_range[0]; + /* Compute raw grid */ + res = setup_cloud_grid(sky, nvoxs, ctx.iband, htcp_filename, + force_cache_update, &ctx.grid); + if(res != RES_OK) goto error; + /* Create the octree */ res = svx_octree_create (sky->htrdr->svx, low, upp, nvoxs, &vox_desc, &sky->clouds[i].octree); @@ -628,11 +745,17 @@ setup_clouds(struct htrdr_sky* sky) /* Fetch the octree descriptor for future use */ SVX(tree_get_desc (sky->clouds[i].octree, &sky->clouds[i].octree_desc)); + + if(ctx.grid) { + htrdr_grid_ref_put(ctx.grid); + ctx.grid = NULL; + } } exit: return res; error: + if(ctx.grid) htrdr_grid_ref_put(ctx.grid); if(sky->clouds) { FOR_EACH(i, 0, nbands) { if(sky->clouds[i].octree) { @@ -647,88 +770,6 @@ error: } static res_T -setup_cloud_grid - (struct htrdr_sky* sky, - const size_t definition[3], - const size_t iband, - const char* htcp_filename, - const int force_update, - struct htrdr_grid** out_grid) -{ - struct htrdr_grid* grid = NULL; - struct str str; - struct build_octree_context ctx; - size_t sizeof_cell; - size_t xyz[3]; - char buf[16]; - res_T res = RES_OK; - ASSERT(sky && definition && htcp_filename && out_grid); - ASSERT(definition[0] && definition[1] && definition[2]); - ASSERT(iband >= sky->sw_bands_range[0] && iband <= sky->sw_bands_range[1]); - - CHK((size_t)snprintf(buf, sizeof(buf), "_%lu_", iband) < sizeof(buf)); - - /* Build the grid name */ - str_init(sky->htrdr->allocator, &str); - CHK(RES_OK == str_set(&str, htcp_filename)); - CHK(RES_OK == str_set(&str, basename(str_get(&str)))); - CHK(RES_OK == str_insert(&str, 0, ".htrdr_")); - CHK(RES_OK == str_append(&str, buf)); - CHK(RES_OK == str_append(&str, ".grid")); - - if(!force_update) { - /* Try to open the saved grid */ - res = htrdr_grid_open(sky->htrdr, str_cget(&str), &grid); - if(res != RES_OK) { - htrdr_log_warn(sky->htrdr, "cannot open the grid `%s'.\n", str_cget(&str)); - } else { - size_t grid_def[3]; - - /* Check that the definition is the loaded grid is the same of the - * submitted grid definition */ - htrdr_grid_get_definition(grid, grid_def); - if(grid_def[0] == definition[0] - && grid_def[1] == definition[1] - && grid_def[2] == definition[2]) - goto exit; /* No more work to do. The loaded data seems valid */ - - /* The grid is no more valid. Update it! */ - htrdr_grid_ref_put(grid); - grid = NULL; - } - } - - sizeof_cell = NFLOATS_PER_COMPONENT * 2/*gas & particle*/ * sizeof(float); - - res = htrdr_grid_create - (sky->htrdr, definition, sizeof_cell, str_cget(&str), 1, &grid); - if(res != RES_OK) goto error; - - ctx.sky = sky; - ctx.dst_max = DBL_MAX; /* Unused for grid construction */ - ctx.tau_threshold = DBL_MAX; /* Unused for grid construction */ - ctx.iband = iband; - - FOR_EACH(xyz[2], 0, definition[2]) { - FOR_EACH(xyz[1], 0, definition[1]) { - FOR_EACH(xyz[0], 0, definition[0]) { - float* data = htrdr_grid_at(grid, xyz); - vox_get(xyz, data, &ctx); - }}} - -exit: - *out_grid = grid; - str_release(&str); - return res; -error: - if(grid) { - htrdr_grid_ref_put(grid); - grid = NULL; - } - goto exit; -} - -static res_T setup_sw_bands_properties(struct htrdr_sky* sky) { res_T res = RES_OK; @@ -845,6 +886,7 @@ htrdr_sky_create int htcp_upd = 1; int htmie_upd = 1; int htgop_upd = 1; + int force_upd = 1; res_T res = RES_OK; ASSERT(htrdr && sun && htcp_filename && htmie_filename && out_sky); @@ -901,21 +943,19 @@ htrdr_sky_create goto error; } + res = setup_sw_bands_properties(sky); + if(res != RES_OK) goto error; + + /* Define if the cached grid data must be updated */ res = is_file_updated(sky->htrdr, htcp_filename, &htcp_upd); if(res != RES_OK) goto error; res = is_file_updated(sky->htrdr, htmie_filename, &htmie_upd); if(res != RES_OK) goto error; res = is_file_updated(sky->htrdr, htgop_filename, &htgop_upd); if(res != RES_OK) goto error; + force_upd = htcp_upd || htmie_upd || htgop_upd; - if(htcp_upd || htmie_upd || htgop_upd) { - htrdr_log(sky->htrdr, "Cloud grid needs to be rebuid.\n"); - } - - res = setup_sw_bands_properties(sky); - if(res != RES_OK) goto error; - - res = setup_clouds(sky); + res = setup_clouds(sky, htcp_filename, force_upd); if(res != RES_OK) goto error; exit: @@ -1035,7 +1075,7 @@ htrdr_sky_fetch_raw_property struct htgop_layer layer; struct htgop_layer_sw_spectral_interval band; struct htgop_layer_sw_spectral_interval_tab tab; - const double x_h2o = cloud_water_molar_fraction(&sky->htcp_desc, ivox); + const double x_h2o = cloud_water_vapor_molar_fraction(&sky->htcp_desc, ivox); size_t ilayer = 0; /* Retrieve the quadrature point into the spectral band of the layer into