rnatm

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

commit c46c63425cf1be297a5d333c3ad0258e660bfefb
parent 16a6c702b23d0f0154e9584813315826d288a493
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu,  8 Sep 2022 11:54:13 +0200

Add support for octree loading

Diffstat:
Msrc/rnatm.c | 5++++-
Msrc/rnatm.h | 8+++++++-
Msrc/rnatm_octree.c | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/rnatm_octrees_storage.c | 72+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/rnatm_octrees_storage.h | 7++++++-
Msrc/test_rnatm.c | 16+++++++++++++---
6 files changed, 171 insertions(+), 27 deletions(-)

diff --git a/src/rnatm.c b/src/rnatm.c @@ -91,6 +91,10 @@ check_rnatm_create_args(const struct rnatm_create_args* args) if(args->spectral_range[0] > args->spectral_range[1]) return RES_BAD_ARG; + /* Invalid requirements for loading octrees */ + if(!args->octrees_storage && args->load_octrees_from_storage) + return RES_BAD_ARG; + /* Check miscalleneous arguments */ if(!args->name || args->optical_thickness < 0 @@ -134,7 +138,6 @@ create_rnatm ref_init(&atm->ref); atm->allocator = allocator; atm->verbose = args->verbose; - atm->octrees_storage = args->octrees_storage; str_init(atm->allocator, &atm->name); gas_init(atm->allocator, &atm->gas); darray_aerosol_init(atm->allocator, &atm->aerosols); diff --git a/src/rnatm.h b/src/rnatm.h @@ -86,9 +86,14 @@ struct rnatm_create_args { char* name; /* Name of the atmosphere */ /* Read/write file where octrees are offloaded. May be NULL => octrees are - * kept in memory */ + * built at runtime and kept in memory */ FILE* octrees_storage; + /* Defines whether the octrees to be taken into account have already been + * unloaded into 'octrees_storage' at a previous run and, therefore, can be + * loaded from the provided file rather than built from scratch */ + int load_octrees_from_storage; + /* Spectral range to consider (in nanometers). Limits are inclusive */ double spectral_range[2]; double optical_thickness; /* Threshold used during octree building */ @@ -109,6 +114,7 @@ struct rnatm_create_args { "atmosphere", /* Name */ \ \ NULL, /* octrees storage */ \ + 0, \ \ {380, 780}, /* Spectral range */ \ 1, /* Optical thickness */ \ diff --git a/src/rnatm_octree.c b/src/rnatm_octree.c @@ -1157,6 +1157,47 @@ vx_challenge_merge } static res_T +init_octrees_storage(struct rnatm* atm, const struct rnatm_create_args* args) +{ + struct octrees_storage_desc desc; + res_T res = RES_OK; + ASSERT(atm && args); + + if(!args->octrees_storage) goto exit; + + /* Register the storage file */ + atm->octrees_storage = args->octrees_storage; + + res = setup_octrees_storage_desc(atm, &desc); + if(res != RES_OK) goto error; + + /* Save the computed descriptor in the storage */ + if(!args->load_octrees_from_storage) { + res = write_octrees_storage_desc(atm, &desc, atm->octrees_storage); + if(res != RES_OK) goto error; + + /* The octrees must be loaded from storage. Verify that the data and settings + * used by the saved octrees are the same as the current parameters */ + } else { + struct octrees_storage_desc saved_desc; + res = read_octrees_storage_desc(atm, &saved_desc, args->octrees_storage); + if(res != RES_OK) goto error; + if(!octrees_storage_desc_eq(&desc, &saved_desc)) { + log_err(atm, + "unable to load octrees from the supplied storage. The saved " + "octrees are built from different data\n"); + res = RES_BAD_ARG; + goto error; + } + } + +exit: + return res; +error: + goto exit; +} + +static res_T create_storage_toc(struct rnatm* atm, fpos_t* toc) { int err = 0; @@ -1255,10 +1296,6 @@ build_octrees ATOMIC res = RES_OK; ASSERT(atm && args && pool); - res = svx_device_create - (atm->logger, &atm->svx_allocator, atm->verbose, &atm->svx); - if(res != RES_OK) goto error; - /* Recover the AABB from the atmosphere. Note that we have already made sure * when setting up the meshes of the gas and aerosols that the aerosols are * included in the gas. Therefore, the AABB of the gas is the same as the @@ -1416,8 +1453,6 @@ create_octrees res = create_pool(atm, &pool, nbands); if(res != RES_OK) goto error; - res = setup_accel_structs(atm, bands); - if(res != RES_OK) goto error; res = build_sync_init(&sync); if(res != RES_OK) goto error; @@ -1464,13 +1499,29 @@ error: goto exit; } +static INLINE res_T +load_octrees(struct rnatm* atm) +{ + res_T res = RES_OK; + ASSERT(atm && atm->octrees_storage); + + /* Only load the storage table of content. The octrees will be loaded on + * demand */ + res = read_octrees_storage_toc(atm, atm->octrees_storage); + if(res != RES_OK) goto error; + +exit: + return res; +error: + goto exit; +} + /******************************************************************************* * Local functions ******************************************************************************/ res_T setup_octrees(struct rnatm* atm, const struct rnatm_create_args* args) { - struct octrees_storage_desc desc; char buf[128]; size_t bands[2]; struct time t0, t1; @@ -1481,6 +1532,11 @@ setup_octrees(struct rnatm* atm, const struct rnatm_create_args* args) /* Start time recording */ time_current(&t0); + /* Create the Star-VoXel device */ + res = svx_device_create + (atm->logger, &atm->svx_allocator, atm->verbose, &atm->svx); + if(res != RES_OK) goto error; + /* Setup miscellaneous parameters */ atm->spectral_range[0] = args->spectral_range[0]; atm->spectral_range[1] = args->spectral_range[1]; @@ -1489,18 +1545,24 @@ setup_octrees(struct rnatm* atm, const struct rnatm_create_args* args) res = compute_grid_definition(atm, args); if(res != RES_OK) goto error; - if(atm->octrees_storage) { - res = setup_octrees_storage_desc(atm, &desc); - if(res != RES_OK) goto error; - res = write_octrees_storage_desc(atm, &desc, atm->octrees_storage); - if(res != RES_OK) goto error; - } + /* Initialize storage *after* calculating the grid definition since it is + * saved in the storage file */ + res = init_octrees_storage(atm, args); + if(res != RES_OK) goto error; res = find_band_range(atm, atm->spectral_range, bands); if(res != RES_OK) goto error; - res = create_octrees(atm, args, bands); + res = setup_accel_structs(atm, bands); if(res != RES_OK) goto error; + if(args->load_octrees_from_storage) { + res = load_octrees(atm); + if(res != RES_OK) goto error; + } else { + res = create_octrees(atm, args, bands); + if(res != RES_OK) goto error; + } + /* Log elapsed time */ time_sub(&t0, time_current(&t1), &t0); time_dump(&t0, TIME_ALL, NULL, buf, sizeof(buf)); diff --git a/src/rnatm_octrees_storage.c b/src/rnatm_octrees_storage.c @@ -238,6 +238,22 @@ error: } res_T +octrees_storage_desc_eq + (const struct octrees_storage_desc* desc0, + const struct octrees_storage_desc* desc1) +{ + ASSERT(desc0 && desc1); + return desc0->spectral_range[0] == desc1->spectral_range[0] + && desc0->spectral_range[1] == desc1->spectral_range[1] + && desc0->optical_thickness == desc1->optical_thickness + && desc0->grid_definition[0] == desc1->grid_definition[0] + && desc0->grid_definition[1] == desc1->grid_definition[1] + && desc0->grid_definition[2] == desc1->grid_definition[2] + && hash256_eq(desc0->signature, desc1->signature) + && desc0->version == desc1->version; +} + +res_T read_octrees_storage_desc (const struct rnatm* atm, struct octrees_storage_desc* desc, @@ -259,6 +275,10 @@ read_octrees_storage_desc } \ } (void)0 READ(&desc->version, 1); + if(desc->version != OCTREES_STORAGE_VERSION) { /* Basic versioning */ + res = RES_BAD_ARG; + goto error; + } READ(desc->spectral_range, 2); READ(&desc->optical_thickness, 1); READ(desc->grid_definition, 3); @@ -268,7 +288,8 @@ read_octrees_storage_desc exit: return res; error: - log_err(atm, "unable to read tree storage descriptor\n"); + log_err(atm, "unable to read tree storage descriptor -- %s\n", + res_to_cstr(res)); goto exit; } @@ -329,17 +350,54 @@ write_octrees_storage_toc(const struct rnatm* atm, FILE* stream) exit: return res; error: - log_err(atm, "error writing octree table of content\n"); + log_err(atm, "error writing octree storage table of content -- %s\n", + res_to_cstr(res)); goto exit; } res_T -read_octrees_storage_toc(const struct rnatm* atm, FILE* stream) +read_octrees_storage_toc(struct rnatm* atm, FILE* stream) { - /* TODO */ - (void)atm, (void)stream; - FATAL("Not implemented\n"); - return RES_BAD_OP; + size_t noctrees = 0; + size_t ioctree = 0; + res_T res = RES_OK; + ASSERT(atm && stream); + + noctrees = darray_accel_struct_size_get(&atm->accel_structs); + + #define READ(Var) { \ + if(fread((Var), sizeof(*(Var)), (1), stream) != (1)) { \ + if(feof(stream)) { \ + res = RES_BAD_ARG; \ + } else if(ferror(stream)) { \ + res = RES_IO_ERR; \ + } else { \ + res = RES_UNKNOWN_ERR; \ + } \ + goto error; \ + } \ + } (void)0 + + /* Read the number of toc entries and check that it matches to expected one */ + READ(&noctrees); + if(noctrees != darray_accel_struct_size_get(&atm->accel_structs)) { + res = RES_BAD_ARG; + goto error; + } + FOR_EACH(ioctree, 0, noctrees) { + struct accel_struct* accel_struct = + darray_accel_struct_data_get(&atm->accel_structs) + ioctree; + READ(&accel_struct->fpos); + } + + #undef READ + +exit: + return res; +error: + log_err(atm, "error reading octree storage table of content -- %s\n", + res_to_cstr(res)); + goto exit; } extern LOCAL_SYM res_T diff --git a/src/rnatm_octrees_storage.h b/src/rnatm_octrees_storage.h @@ -45,6 +45,11 @@ setup_octrees_storage_desc (const struct rnatm* atm, struct octrees_storage_desc* desc); +extern LOCAL_SYM int +octrees_storage_desc_eq + (const struct octrees_storage_desc* desc0, + const struct octrees_storage_desc* desc1); + extern LOCAL_SYM res_T write_octrees_storage_desc (const struct rnatm* atm, @@ -69,7 +74,7 @@ write_octrees_storage_toc extern LOCAL_SYM res_T read_octrees_storage_toc - (const struct rnatm* atm, + (struct rnatm* atm, FILE* stream); extern LOCAL_SYM res_T diff --git a/src/test_rnatm.c b/src/test_rnatm.c @@ -80,6 +80,8 @@ print_help(const char* cmd) printf( " -h display this help and exit\n"); printf( +" -i file octrees are loaded from file\n"); + printf( " -N precompute_normals the tetrahedra normals\n"); printf( " -o file offload octrees to file\n"); @@ -335,7 +337,7 @@ args_init(struct args* args, int argc, char** argv) *args = ARGS_DEFAULT; - while((opt = getopt(argc, argv, "a:d:g:hNo:s:T:t:V:v")) != -1) { + while((opt = getopt(argc, argv, "a:d:g:hi:No:s:T:t:V:v")) != -1) { switch(opt) { case 'a': sa_add(args->rnatm.aerosols, 1); @@ -353,7 +355,14 @@ args_init(struct args* args, int argc, char** argv) args->quit = 1; goto exit; case 'N': args->rnatm.precompute_normals = 1; break; - case 'o': storage_filename = optarg; break; + case 'o': + args->rnatm.load_octrees_from_storage = 0; + storage_filename = optarg; + break; + case 'i': + args->rnatm.load_octrees_from_storage = 1; + storage_filename = optarg; + break; case 's': res = parse_spectral_range(args, optarg); break; @@ -382,7 +391,8 @@ args_init(struct args* args, int argc, char** argv) } if(storage_filename) { - args->rnatm.octrees_storage = fopen(storage_filename, "w+"); + const char* mode = args->rnatm.load_octrees_from_storage ? "r" : "w+"; + args->rnatm.octrees_storage = fopen(storage_filename, mode); if(!args->rnatm.octrees_storage) { fprintf(stderr, "Unable to open octree storage file %s\n", storage_filename);