rnatm

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

commit e0c41bfab79971106eb4112763b0a8facdbdb92a
parent d030170bf319776fb481c0cda38cba6ab67d1a13
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 29 Aug 2022 16:50:22 +0200

Begin the implementation of octree offloading

Diffstat:
Msrc/rnatm.c | 3+++
Msrc/rnatm.h | 4++++
Msrc/rnatm_c.h | 2++
Msrc/rnatm_octree.c | 172++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
4 files changed, 176 insertions(+), 5 deletions(-)

diff --git a/src/rnatm.c b/src/rnatm.c @@ -450,6 +450,7 @@ accel_struct_init accel_struct->octree = NULL; accel_struct->iband = 0; accel_struct->iquad_pt = 0; + memset(&accel_struct->fpos, 0, sizeof(accel_struct->fpos)); return RES_OK; } @@ -466,6 +467,7 @@ accel_struct_copy(struct accel_struct* dst, const struct accel_struct* src) ASSERT(dst && src); if(dst->octree) SVX(tree_ref_put(dst->octree)); dst->octree = src->octree; + dst->fpos = src->fpos; dst->iband = src->iband; dst->iquad_pt = src->iquad_pt; if(dst->octree) SVX(tree_ref_get(dst->octree)); @@ -478,6 +480,7 @@ accel_struct_copy_and_release(struct accel_struct* dst, struct accel_struct* src ASSERT(dst && src); if(dst->octree) SVX(tree_ref_put(dst->octree)); dst->octree = src->octree; + dst->fpos = src->fpos; dst->iband = src->iband; dst->iquad_pt = src->iquad_pt; src->octree = NULL; diff --git a/src/rnatm.h b/src/rnatm.h @@ -85,6 +85,8 @@ struct rnatm_create_args { size_t naerosols; char* name; /* Name of the atmosphere */ + FILE* octrees_storage; /* File where octrees are serialized. May be NULL */ + /* Spectral range to consider (in wavenumbers). Limits are inclusive */ double spectral_range[2]; double optical_thickness; /* Threshold used during octree building */ @@ -104,6 +106,8 @@ struct rnatm_create_args { 0, /* Number of aerosols */ \ "atmosphere", /* Name */ \ \ + NULL, /* octrees storage */ \ + \ {12820.513, 26315.789}, /* Spectral range */ \ 1, /* Optical thickness */ \ \ diff --git a/src/rnatm_c.h b/src/rnatm_c.h @@ -144,6 +144,7 @@ aerosol_copy_and_release ******************************************************************************/ struct accel_struct { struct svx_tree* octree; + fpos_t fpos; /* Position of the serialized data in the storage file */ size_t iband; /* Index of the spectral band */ size_t iquad_pt; /* Index of the quadrature point */ }; @@ -194,6 +195,7 @@ struct rnatm { struct logger logger__; struct mem_allocator* allocator; struct mem_allocator svx_allocator; + int svx_allocator_is_init; ref_T ref; }; diff --git a/src/rnatm_octree.c b/src/rnatm_octree.c @@ -18,7 +18,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#define _POSIX_C_SOURCE 200112L /* lround and nextafter support */ +/* lround, nextafter */ +#define _POSIX_C_SOURCE 200112L #include "rnatm_c.h" #include "rnatm_log.h" @@ -54,6 +55,13 @@ struct build_sync { #define BUILD_SYNC_NULL__ {NULL, NULL, 0} static const struct build_sync BUILD_SYNC_NULL = BUILD_SYNC_NULL__; +struct storage { + FILE* fp; /* File pointer */ + fpos_t header; /* Position of the header */ +}; +#define STORAGE_NULL__ {NULL} +static const struct storage STORAGE_NULL = STORAGE_NULL__; + struct build_octree_context { struct pool* pool; struct partition* part; /* Current partition */ @@ -517,10 +525,10 @@ setup_tetra_radcoefs_aerosol /* 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) - * - the gas band and aerosol band are the same */ + * - no aerosol band is overlaid by the gas band => FIXME no aerosol + * - the aerosol bands are entirely included in the gas band FIXME general case + * - gas degenerated => FIXME the aerosol bands must include the gas band + * - the gas band and aerosol band are the same => FIXME take the aerosol properties */ /* Aerosol spectral data is not overlaid by the gas band */ if(ars_ibands[0] > ars_ibands[1]) FATAL("Not implemented yet!\n"); @@ -531,6 +539,7 @@ setup_tetra_radcoefs_aerosol if(ars_ibands[0] == ars_ibands[1] && ars_band.lower <= gas_band.lower && ars_band.upper >= gas_band.upper) { + /* FIXME use the aerosole properties */ setup_tetra_radcoefs_gas(atm, tetra, iband, iquad_pt, radcoefs); /* The gas band overlaid N aerosol bands (N >= 1) */ @@ -541,6 +550,8 @@ setup_tetra_radcoefs_aerosol float rcp_gas_band_len; size_t iars_band; + /* TODO If gas.lambda_min == gas.lambda_max use the properties of the + * aerosol band */ FOR_EACH(iars_band, ars_ibands[0], ars_ibands[1]+1) { double lambda_min; double lambda_max; @@ -1166,12 +1177,148 @@ vx_challenge_merge } static res_T +storage_init + (struct rnatm* atm, + const struct rnatm_create_args* args, + struct storage* storage) +{ + size_t noctrees = 0; + size_t header_size = 0; + int err = 0; + res_T res = RES_OK; + + ASSERT(atm && args && storage); + + if(!args->octrees_storage) { /* No octrees storage */ + *storage = STORAGE_NULL; + goto exit; + } + + noctrees = darray_accel_struct_size_get(&atm->accel_structs); + + storage->fp = args->octrees_storage; + + err = fgetpos(storage->fp, &storage->header); + if(err != 0) { res = RES_IO_ERR; goto error; } + + /* Compute the header size */ + header_size = + sizeof(size_t)/*#octrees*/ + + sizeof(fpos_t)*noctrees; /* Table of offsets */ + ASSERT(header_size < LONG_MAX); + + /* Reserve the space for the header */ + err = fseek(storage->fp, (long)header_size, SEEK_CUR); + if(err != 0) { res = RES_IO_ERR; goto error; } + +exit: + return res; +error: + log_err(atm, "error initializing disk storage of octrees -- %s\n", + strerror(errno)); + goto exit; +} + +static res_T +storage_write_octrees + (struct rnatm* atm, + const struct storage* storage, + const size_t ioctrees[2]) /* Octrees to write. Limits are inclusive */ +{ + size_t ioctree = 0; + int err = 0; + res_T res = RES_OK; + ASSERT(atm && storage && ioctrees && ioctrees[0] <= ioctrees[1]); + ASSERT(ioctrees[1] < darray_accel_struct_size_get(&atm->accel_structs)); + + /* No storage: nothing to do */ + if(!storage->fp) goto exit; + + FOR_EACH(ioctree, ioctrees[0], ioctrees[1]+1) { + struct accel_struct* accel_struct = NULL; + accel_struct = darray_accel_struct_data_get(&atm->accel_structs) + ioctree; + + /* Save the current file offset */ + err = fgetpos(storage->fp, &accel_struct->fpos); + if(err != 0) { + log_err(atm, "error retrieving octree storage position -- %s\n", + strerror(errno)); + res = RES_IO_ERR; + goto error; + } + + /* Serialize the octree */ + res = svx_tree_write(accel_struct->octree, storage->fp); + if(res != RES_OK) { + log_err(atm, "error serializing octree %lu -- %s\n", + (unsigned long)ioctree, res_to_cstr(res)); + goto error; + } + + /* Free the octree memory */ + SVX(tree_ref_put(accel_struct->octree)); + accel_struct->octree = NULL; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +storage_finalize(struct rnatm* atm, struct storage* storage) +{ + size_t naccel_structs = 0; + size_t iaccel_struct = 0; + int err = 0; + res_T res = RES_OK; + ASSERT(atm && storage); + + /* No storage: nothing to do */ + if(storage->fp) goto exit; + + err = fsetpos(storage->fp, &storage->header); + if(err != 0) { + log_err(atm, "error positioning on octree storage header -- %s\n", + strerror(errno)); + res = RES_IO_ERR; + goto error; + } + + naccel_structs = darray_accel_struct_size_get(&atm->accel_structs); + + /* Write the number of voxelized octrees and their corresponding offset */ + #define WRITE(Var) { \ + if(fwrite((Var), sizeof(*(Var)), 1, storage->fp) != 1) { \ + log_err(atm, "error serializing octree storage header\n"); \ + res = RES_IO_ERR; \ + goto error; \ + } \ + } (void)0 + + WRITE(&naccel_structs); + FOR_EACH(iaccel_struct, 0, naccel_structs) { + const struct accel_struct* accel_struct = + darray_accel_struct_cdata_get(&atm->accel_structs) + iaccel_struct; + WRITE(&accel_struct->fpos); + } + #undef WRITE + +exit: + return res; +error: + goto exit; +} + +static res_T build_octrees (struct rnatm* atm, const struct rnatm_create_args* args, struct pool* pool, struct build_sync* sync) { + struct storage storage = STORAGE_NULL; struct svx_device* svx = NULL; struct accel_struct* accel_structs = NULL; double low[3], upp[3]; @@ -1200,6 +1347,10 @@ build_octrees naccel_structs = darray_accel_struct_size_get(&atm->accel_structs); voxel_width = pool_get_voxel_width(pool); + /* Setup the disk storage of the octrees */ + res = storage_init(atm, args, &storage); + if(res != RES_OK) goto error; + /* Build the octrees. Each thread consumes an element of the voxels generated * by the voxelization thread, each element corresponding to the voxel of an * octree to be constructed. By fixing the number of threads to the width of @@ -1207,6 +1358,7 @@ build_octrees * single voxelization of the atmospheric meshes */ for(istruct = 0; istruct < naccel_structs; istruct += voxel_width) { const size_t batch_size = MMIN(voxel_width, naccel_structs - istruct); + size_t ioctrees[2]; omp_set_num_threads((int)batch_size); /* Note that we are using a parallel block rather than a parallel loop in @@ -1250,8 +1402,18 @@ build_octrees sync->ibatch += 1; mutex_unlock(sync->mutex); cond_signal(sync->cond); + + /* Offload builded octrees */ + ioctrees[0] = istruct; + ioctrees[1] = istruct + batch_size - 1; + res = storage_write_octrees(atm, &storage, ioctrees); + if(res != RES_OK) goto error; } + /* Finalize the file where octrees are offloaded */ + res = storage_finalize(atm, &storage); + if(res != RES_OK) goto error; + exit: if(svx) SVX(device_ref_put(svx)); return (res_T)res;