rnatm

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

commit aff0cf67939db10a2cb5261dc1eadf82c0b425a6
parent fd89ed39c48a441f035fedf1754007b38d4c1cd3
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 22 Jul 2022 12:29:54 +0200

Start building the octrees

Diffstat:
MREADME.md | 5+++--
Mcmake/CMakeLists.txt | 6+++++-
Msrc/rnatm.c | 20++++++++++++++++----
Msrc/rnatm.h | 6++++++
Msrc/rnatm_c.h | 9+++++++++
Asrc/rnatm_octree.c | 180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/rnatm_properties.c | 1+
Msrc/rnatm_voxel_partition.h | 5++++-
8 files changed, 224 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md @@ -21,9 +21,10 @@ on the [Rad-Net Scattering Function](https://gitlab.com/meso-star/rnsf), [Star-Aerosol](https://gitlab.com/meso-star/star-aerosol), [Star-Buffer](https://gitlab.com/meso-star/star-buffer), [Star-CorrelatedK](https://gitlab.com/meso-star/star-ck), -[Star-Mesh](https://gitlab.com/meso-star/star-mesh) and +[Star-Mesh](https://gitlab.com/meso-star/star-mesh) [Star-UnstructuredVolumetricMesh](https://gitlab.com/meso-star/star-uvm) -libraries. It optionally depends on [scdoc](https://sr.ht/~sircmpwn/scdoc/) +libraries, and on [OpenMP](https://www.openmp.org) 1.2 the parallelize its +computations. It optionally depends on [scdoc](https://sr.ht/~sircmpwn/scdoc/) which, if available, is used to generate the man pages. First ensure that CMake is installed on your system. Then install the RCMake diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -28,6 +28,7 @@ option(NO_TEST "Do not build tests" OFF) ################################################################################ # Check dependencies ################################################################################ +find_package(OpenMP 1.2 REQUIRED) find_package(RCMake 0.4 REQUIRED) find_package(RNSF REQUIRED) find_package(RSys 0.9 REQUIRED) @@ -62,6 +63,7 @@ set(RNATM_FILES_SRC rnatm.c rnatm_log.c rnatm_mesh.c + rnatm_octree.c rnatm_properties.c rnatm_voxel_partition.c) set(RNATM_FILES_INC @@ -79,9 +81,11 @@ rcmake_prepend_path(RNATM_FILES_INC_API ${RNATM_SOURCE_DIR}) rcmake_prepend_path(RNATM_FILES_DOC ${PROJECT_SOURCE_DIR}/../) add_library(rnatm SHARED ${RNATM_FILES_SRC} ${RNATM_FILES_INC} ${RNATM_FILES_INC_API}) -target_link_libraries(rnatm RNSF RSys StarAerosol StarBuffer StarCK StarMesh StarUVM) +target_link_libraries(rnatm RNSF RSys StarAerosol StarBuffer StarCK StarMesh StarUVM m) set_target_properties(rnatm PROPERTIES + COMPILE_FLAGS "${OpenMP_C_FLAGS}" + LINK_FLAGS "${OpenMP_C_FLAGS}" DEFINE_SYMBOL RNATM_SHARED_BUILD VERSION ${VERSION} SOVERSION ${VERSION_MAJOR}) diff --git a/src/rnatm.c b/src/rnatm.c @@ -32,6 +32,8 @@ #include <rsys/cstr.h> #include <rsys/mem_allocator.h> +#include <omp.h> + /******************************************************************************* * Helper functions ******************************************************************************/ @@ -83,6 +85,12 @@ check_rnatm_create_args(const struct rnatm_create_args* args) if(res != RES_OK) return res; } + /* Check miscalleneous arguments */ + if(!args->name + || !args->grid_definition_hint + || !args->nthreads) + return RES_BAD_ARG; + return RES_OK; } @@ -93,6 +101,7 @@ create_rnatm { struct rnatm* atm = NULL; struct mem_allocator* allocator = NULL; + int nthreads_max = 0; res_T res = RES_OK; if(!out_atm) { res = RES_BAD_ARG; goto error;} @@ -115,7 +124,6 @@ create_rnatm res = RES_MEM_ERR; goto error; } - ref_init(&atm->ref); atm->allocator = allocator; atm->verbose = args->verbose; @@ -123,6 +131,10 @@ create_rnatm gas_init(atm->allocator, &atm->gas); darray_aerosol_init(atm->allocator, &atm->aerosols); + /* Setup the number of threads */ + nthreads_max = MMAX(omp_get_max_threads(), omp_get_num_procs()); + atm->nthreads = MMIN((unsigned)nthreads_max, args->nthreads); + if(args->logger) { atm->logger = args->logger; } else { @@ -131,7 +143,7 @@ create_rnatm if(args->verbose) { fprintf(stderr, MSG_ERROR_PREFIX "Could not setup the default logger of the " - "Rad-Net ATMopshere library.\n"); + "Rad-Net ATMopshere library\n"); } goto error; } @@ -189,8 +201,8 @@ rnatm_create if(res != RES_OK) goto error; res = setup_properties(atm, args); if(res != RES_OK) goto error; - /*res = setup_octrees(atm, args); - if(res != RES_OK) goto error;*/ + res = setup_octrees(atm, args); + if(res != RES_OK) goto error; exit: if(out_atm) *out_atm = atm; diff --git a/src/rnatm.h b/src/rnatm.h @@ -83,10 +83,13 @@ struct rnatm_create_args { size_t naerosols; const char* name; /* Name of the atmosphere */ + unsigned grid_definition_hint; /* Hint on the grid definition */ int precompute_normals; /* Pre-compute the tetrahedra normals */ struct logger* logger; /* NULL <=> use default logger */ struct mem_allocator* allocator; /* NULL <=> use default allocator */ + + unsigned nthreads; /* Hint on the number of threads to use */ int verbose; /* Verbosity level */ }; #define RNATM_CREATE_ARGS_DEFAULT__ { \ @@ -95,10 +98,13 @@ struct rnatm_create_args { 0, /* Number of aerosols */ \ "atmosphere", /* Name */ \ \ + 65536, /* Hint on the grid definition */ \ 0, /* Precompute tetrahedra normals */ \ \ NULL, /* Logger */ \ NULL, /* Allocator */ \ + \ + (unsigned)~0, /* #threads */ \ 0 /* Verbosity level */ \ } static const struct rnatm_create_args RNDGR_CREATE_ARGS_DEFAULT = diff --git a/src/rnatm_c.h b/src/rnatm_c.h @@ -138,7 +138,11 @@ struct rnatm { struct darray_aerosol aerosols; struct str name; + unsigned grid_definition[3]; + + unsigned nthreads; int verbose; + struct logger* logger; struct logger logger__; struct mem_allocator* allocator; @@ -155,4 +159,9 @@ setup_properties (struct rnatm* atm, const struct rnatm_create_args* args); +extern LOCAL_SYM res_T +setup_octrees + (struct rnatm* atm, + const struct rnatm_create_args* args); + #endif /* RNATM_C_H */ diff --git a/src/rnatm_octree.c b/src/rnatm_octree.c @@ -0,0 +1,180 @@ +/* Copyright (C) 2022 Centre National de la Recherche Scientifique + * Copyright (C) 2022 Institut de Physique du Globe de Paris + * Copyright (C) 2022 |Méso|Star> (contact@meso-star.com) + * Copyright (C) 2022 Université de Reims Champagne-Ardenne + * Copyright (C) 2022 Université de Versaille Saint-Quentin + * Copyright (C) 2022 Université Paul Sabatier (contact@laplace.univ-tlse.fr) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 support */ + +#include "rnatm_c.h" +#include "rnatm_log.h" +#include "rnatm_voxel_partition.h" + +#include <star/sck.h> +#include <star/suvm.h> + +#include <rsys/cstr.h> +#include <rsys/math.h> +#include <rsys/rsys.h> + +#include <math.h> /* lround */ +#include <omp.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static size_t +band_get_quad_pt_count(const size_t iband, void* ctx) +{ + struct sck_band band; + struct sck* sck = ctx; + ASSERT(ctx); + + SCK(get_band(sck, iband, &band)); + return band.quad_pts_count; +} + +static FINLINE unsigned +round_pow2(const unsigned val) +{ + const unsigned next_pow2 = (unsigned)round_up_pow2(val); + if(next_pow2 - val <= next_pow2/4) { + return next_pow2; + } else { + return next_pow2/2; + } +} + +static res_T +compute_grid_definition(struct rnatm* atm, const struct rnatm_create_args* args) +{ + double low[3]; + double upp[3]; + double sz[3]; + double sz_max; + double vxsz; + unsigned def[3]; + int iaxis_max; + int iaxis_remain[2]; + int i; + ASSERT(atm && args); + + /* 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 + * AABB of the atmosphere */ + SUVM(volume_get_aabb(atm->gas.volume, low, upp)); + sz[0] = upp[0] - low[0]; + sz[1] = upp[1] - low[1]; + sz[2] = upp[2] - low[2]; + + /* Find the axis along which the atmosphere's AABB is greatest */ + sz_max = -DBL_MAX; + FOR_EACH(i, 0, 3) { + if(sz[i] > sz_max) { iaxis_max = i; sz_max = sz[i]; } + } + + /* Define the other axes */ + iaxis_remain[0] = (iaxis_max + 1) % 3; + iaxis_remain[1] = (iaxis_max + 2) % 3; + + /* Fix the definition along the maximum axis and calculate the size of a + * voxel along this axis */ + def[iaxis_max] = round_pow2(args->grid_definition_hint); + vxsz = sz[iaxis_max] / def[iaxis_max]; + + /* Calculate the definitions along the remaining 2 axes. First calculates + * them assuming the voxels are cubic, then rounds them to their nearest + * power of two */ + def[iaxis_remain[0]] = (unsigned)lround(sz[iaxis_remain[0]]/vxsz); + def[iaxis_remain[1]] = (unsigned)lround(sz[iaxis_remain[1]]/vxsz); + def[iaxis_remain[0]] = round_pow2(def[iaxis_remain[0]]); + def[iaxis_remain[1]] = round_pow2(def[iaxis_remain[1]]); + + /* Setup grid definition */ + atm->grid_definition[0] = def[0]; + atm->grid_definition[1] = def[1]; + atm->grid_definition[2] = def[2]; + + return RES_OK; +} + +static res_T +build_octrees(struct rnatm* atm, const struct rnatm_create_args* args) +{ + /* Empirical constant that defines the number of voxel partitions to + * pre-allocate per thread to avoid contension between the thread building the + * octrees from the partitions and the threads that fill these partitions */ + const size_t NPARTITIONS_PER_THREAD = 16; + + struct pool_create_args pool_args = POOL_CREATE_ARGS_DEFAULT; + struct pool* pool = NULL; + + res_T res = RES_OK; + ASSERT(atm && args); + + /* Create the vortex partition pool */ + pool_args.npartitions = NPARTITIONS_PER_THREAD * atm->nthreads; + pool_args.nbands = sck_get_bands_count(atm->gas.ck); + pool_args.nquad_pts = band_get_quad_pt_count; + pool_args.context = atm->gas.ck; + pool_args.partition_definition = 32; + pool_args.allocator = atm->allocator; + res = pool_create(&pool_args, &pool); + if(res != RES_OK) { + log_err(atm, "Failed to create the voxel partition pool -- %s\n", + res_to_cstr(res)); + goto error; + } + + log_info(atm, "Partitions radiative properties (grid definition: %ux%ux%u)\n", + SPLIT3(atm->grid_definition)); + + /* Enable nested threads to allow multi-threading when calculating radiative + * properties */ + omp_set_nested(1); + + /* TODO build the octrees */ + (void)args; + +exit: + if(pool) pool_ref_put(pool); + return res; +error: + goto exit; +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +setup_octrees(struct rnatm* atm, const struct rnatm_create_args* args) +{ + res_T res = RES_OK; + ASSERT(atm && args); + + res = compute_grid_definition(atm, args); + if(res != RES_OK) goto error; + res = build_octrees(atm, args); + if(res != RES_OK) goto error; + +exit: + return res; +error: + goto exit; +} + diff --git a/src/rnatm_properties.c b/src/rnatm_properties.c @@ -407,6 +407,7 @@ setup_properties(struct rnatm* atm, const struct rnatm_create_args* args) FOR_EACH(i, 0, darray_aerosol_size_get(&atm->aerosols)) { struct aerosol* aerosol = darray_aerosol_data_get(&atm->aerosols)+i; + res = setup_aerosol_properties(atm, aerosol, args->aerosols+i); if(res != RES_OK) goto error; } diff --git a/src/rnatm_voxel_partition.h b/src/rnatm_voxel_partition.h @@ -26,6 +26,8 @@ #include <rsys/list.h> #include <rsys/rsys.h> +/* TODO remove this */ +#if 0 /* Definition of a partition along the 3 axes */ #define PARTITION_LOG2_DEFINITION 5 /* 5 */ #define PARTITION_DEFINITION BIT(PARTITION_LOG2_DEFINITION) /* 2^5 = 32 */ @@ -33,6 +35,7 @@ ( PARTITION_DEFINITION \ * PARTITION_DEFINITION \ * PARTITION_DEFINITION) +#endif struct pool_create_args { size_t npartitions; /* Number of partitions to preallocate */ @@ -44,7 +47,7 @@ struct pool_create_args { struct mem_allocator* allocator; /* NULL <=> default allocator */ }; -#define POOL_CREATE_ARGS_DEFAULT__ {0, 0, NULL, NULL, 0, NULL} +#define POOL_CREATE_ARGS_DEFAULT__ {0, 0, NULL, NULL, 32, NULL} static const struct pool_create_args POOL_CREATE_ARGS_DEFAULT = POOL_CREATE_ARGS_DEFAULT__;