star-aerosol

Describe the radiative properties of aerosols
git clone git://git.meso-star.fr/star-aerosol.git
Log | Files | Refs | README | LICENSE

commit f8214a066414d837d75c793845c67ef885abe456
parent 7b8417a8634615edc387834ec7a71c47cf7e318d
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 15 Jun 2022 09:33:58 +0200

Implement sars_load and sars_load_stream

Diffstat:
Msrc/sars.c | 215+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 215 insertions(+), 0 deletions(-)

diff --git a/src/sars.c b/src/sars.c @@ -13,12 +13,19 @@ * 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 200809L /* mmap support */ +#define _DEFAULT_SOURCE 1 /* MAP_POPULATE support */ +#define _BSD_SOURCE 1 /* MAP_POPULATE for glibc < 2.19 */ + #include "sars.h" #include "sars_c.h" #include "sars_log.h" #include <unistd.h> /* sysconf support */ +#include <errno.h> +#include <sys/mman.h> /* mmap */ + /******************************************************************************* * Helper functions ******************************************************************************/ @@ -30,6 +37,176 @@ check_sars_create_args(const struct sars_create_args* args) } static void +reset_sars(struct sars* sars) +{ + ASSERT(sars); + sars->pagesize = 0; + sars->nnodes = 0; + darray_band_purge(&sars->bands); +} + +static res_T +read_band + (struct sars* sars, + struct band* band, + FILE* stream, + const char* stream_name) +{ + size_t iband; + res_T res = RES_OK; + ASSERT(sars && band && stream_name); + + iband = (size_t)(band - darray_band_cdata_get(&sars->bands)); + + /* Read band definition */ + #define READ(Var, Name) { \ + if(fread((Var), sizeof(*(Var)), 1, stream) != 1) { \ + log_err(sars, "%s: band %lu: could not read the %s.\n", \ + stream_name, (unsigned long)iband, (Name)); \ + res = RES_IO_ERR; \ + goto error; \ + } \ + } (void)0 + READ(&band->low, "band lower bound"); + READ(&band->upp, "band upper bound"); + #undef READ + + /* Check band description */ + if(band->low < 0 || band->low > band->upp) { + log_err(sars, + "%s: band %lu: invalid band range [%g, %g].\n", + stream_name, (unsigned long)iband, band->low, band->upp); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + + +static res_T +load_stream(struct sars* sars, FILE* stream, const char* stream_name) +{ + size_t map_len; + size_t iband; + uint64_t nbands; + off_t offset = 0; + res_T res = RES_OK; + ASSERT(sars && stream && stream_name); + + reset_sars(sars); + + /* Read file header */ + #define READ(Var, Name) { \ + if(fread((Var), sizeof(*(Var)), 1, stream) != 1) { \ + log_err(sars, "%s: could not read the %s.\n", stream_name, (Name)); \ + res = RES_IO_ERR; \ + goto error; \ + } \ + } (void)0 + READ(&sars->pagesize, "page size"); + READ(&nbands, "number of bands"); + READ(&sars->nnodes, "number of nodes"); + #undef READ + + /* Check band description */ + if(!IS_ALIGNED(sars->pagesize, sars->pagesize_os)) { + log_err(sars, + "%s: invalid page size %lu. The page size attribute must be aligned on " + "the page size of the operating system (%lu).\n", + stream_name, + (unsigned long)sars->pagesize, + (unsigned long)sars->pagesize_os); + res = RES_BAD_ARG; + goto error; + } + if(!nbands) { + log_err(sars, "%s: invalid number of bands %lu.\n", + stream_name, (unsigned long)nbands); + res = RES_BAD_ARG; + goto error; + } + if(!sars->nnodes) { + log_err(sars, "%s: invalid number of nodes %lu.\n", + stream_name, (unsigned long)sars->nnodes); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate the bands */ + res = darray_band_resize(&sars->bands, nbands); + if(res != RES_OK) { + log_err(sars, "%s: could not allocate the list of bands (#bands=%lu).\n", + stream_name, (unsigned long)nbands); + goto error; + } + + /* Read the band description */ + FOR_EACH(iband, 0, nbands) { + struct band* band = darray_band_data_get(&sars->bands) + iband; + res = read_band(sars, band, stream, stream_name); + if(res != RES_OK) goto error; + if(iband > 0 && band[0].low < band[-1].upp) { + log_err(sars, + "%s: bands must be sorted in ascending order and must not " + "overlap (band %lu in [%g, %g] nm; band %lu in [%g, %g] nm).\n", + stream_name, + (unsigned long)(iband-1), band[-1].low, band[-1].upp, + (unsigned long)(iband), band[ 0].low, band[ 0].upp); + res = RES_BAD_ARG; + goto error; + } + } + + /* Compute the length in bytes of the k to map for each band/quadrature point */ + map_len = ALIGN_SIZE(sars->nnodes * sizeof(float), sars->pagesize); + + /* Compute the offset toward the 1st list of radiative coefficients */ + offset = ftell(stream); + offset = (off_t)ALIGN_SIZE((uint64_t)offset, sars->pagesize); + + FOR_EACH(iband, 0, nbands) { + struct band* band = NULL; + + band = darray_band_data_get(&sars->bands) + iband; + band->map_len = map_len; + + /* Map the per band scattering coefficient */ + band->ks_list = mmap(NULL, band->map_len, PROT_READ, + MAP_PRIVATE|MAP_POPULATE, fileno(stream), offset); + if(band->ks_list == MAP_FAILED) { + log_err(sars, + "%s: band %lu: could not map the scattering coefficients -- %s\n", + stream_name, (unsigned long)iband, strerror(errno)); + res = RES_IO_ERR; + goto error; + } + offset = (off_t)((size_t)offset + map_len); + + /* Map the per band absorption coefficient */ + band->ka_list = mmap(NULL, band->map_len, PROT_READ, + MAP_PRIVATE|MAP_POPULATE, fileno(stream), offset); + if(band->ks_list == MAP_FAILED) { + log_err(sars, + "%s: band %lu: could not map the absorption coefficients -- %s\n", + stream_name, (unsigned long)iband, strerror(errno)); + res = RES_IO_ERR; + goto error; + } + offset = (off_t)((size_t)offset + map_len); + } + +exit: + return res; +error: + reset_sars(sars); + goto exit; +} + +static void release_sars(ref_T* ref) { struct sars* sars = NULL; @@ -106,3 +283,41 @@ sars_ref_put(struct sars* sars) ref_put(&sars->ref, release_sars); return RES_OK; } + +res_T +sars_load(struct sars* sars, const char* path) +{ + FILE* file = NULL; + res_T res = RES_OK; + + if(!sars || !path) { + res = RES_BAD_ARG; + goto error; + } + + file = fopen(path, "r"); + if(!file) { + log_err(sars, "%s: error opening file `%s'.\n", FUNC_NAME, path); + res = RES_IO_ERR; + goto error; + } + + res = load_stream(sars, file, path); + if(res != RES_OK) goto error; + +exit: + if(file) fclose(file); + return res; +error: + goto exit; +} + +res_T +sars_load_stream + (struct sars* sars, + FILE* stream, + const char* stream_name) +{ + if(!sars || !stream) return RES_BAD_ARG; + return load_stream(sars, stream, stream_name ? stream_name : "<stream>"); +}