rnatm

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

commit cafbee574f57ca35bcf6b9168e5087e89c5f8280
parent dee1860da5064bf52167534832c3903feb30fbfe
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 20 Jul 2022 11:13:04 +0200

Load gas and aerosol properties

Diffstat:
Mcmake/CMakeLists.txt | 5+++--
Msrc/rnatm.c | 57+++++++++++++++++++++++++++++++++++++++++++++++++--------
Msrc/rnatm.h | 4++--
Msrc/rnatm_c.h | 47+++++++++++++++++++++++++++++++++++++++++++++--
Msrc/rnatm_mesh.c | 15++++++++++-----
Asrc/rnatm_properties.c | 420+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 529 insertions(+), 19 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -61,7 +61,8 @@ set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(RNATM_FILES_SRC rnatm.c rnatm_log.c - rnatm_mesh.c) + rnatm_mesh.c + rnatm_properties.c) set(RNATM_FILES_INC rnatm_c.h rnatm_log.h) @@ -75,7 +76,7 @@ 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 RSys StarAerosol StarBuffer StarCK StarMesh StarUVM) +target_link_libraries(rnatm RNSF RSys StarAerosol StarBuffer StarCK StarMesh StarUVM) set_target_properties(rnatm PROPERTIES DEFINE_SYMBOL RNATM_SHARED_BUILD diff --git a/src/rnatm.c b/src/rnatm.c @@ -22,6 +22,8 @@ #include "rnatm_c.h" #include "rnatm_log.h" +#include <rad-net/rnsf.h> + #include <star/sars.h> #include <star/sbuf.h> #include <star/sck.h> @@ -41,7 +43,7 @@ check_rnatm_gas_args(const struct rnatm_gas_args* args) /* Filenames cannot be NULL */ if(!args->smsh_filename || !args->sck_filename - || !args->props_filename) + || !args->temperatures_filename) return RES_BAD_ARG; return RES_OK; @@ -55,7 +57,7 @@ check_rnatm_aerosol_args(const struct rnatm_aerosol_args* args) /* Filenames cannot be NULL */ if(!args->smsh_filename || !args->sars_filename - || !args->props_filename + || !args->phase_fn_ids_filename || !args->phase_fn_lst_filename) return RES_BAD_ARG; @@ -169,7 +171,6 @@ release_rnatm(ref_T* ref) MEM_RM(atm->allocator, atm); } - /******************************************************************************* * Exported symbols ******************************************************************************/ @@ -186,10 +187,10 @@ rnatm_create res = setup_meshes(atm, args); if(res != RES_OK) goto error; - /*res = setup_octrees(atm, args); - if(res != RES_OK) goto error; res = setup_properties(atm, args); - if(res != RES_OK) goto error; */ + if(res != RES_OK) goto error; + /*res = setup_octrees(atm, args); + if(res != RES_OK) goto error;*/ exit: if(out_atm) *out_atm = atm; @@ -219,6 +220,40 @@ rnatm_ref_put(struct rnatm* atm) * Local functions ******************************************************************************/ res_T +phase_fn_init(struct mem_allocator* allocator, struct rnsf** phase_fn) +{ + (void)allocator; + *phase_fn = NULL; + return RES_OK; +} + +void +phase_fn_release(struct rnsf** phase_fn) +{ + if(*phase_fn) RNSF(ref_put(*phase_fn)); +} + +res_T +phase_fn_copy(struct rnsf** dst, struct rnsf* const* src) +{ + ASSERT(dst && src); + if(*dst) RNSF(ref_put(*dst)); + *dst = *src; + if(*dst) RNSF(ref_get(*dst)); + return RES_OK; +} + +res_T +phase_fn_copy_and_release(struct rnsf** dst, struct rnsf** src) +{ + ASSERT(dst && src); + if(*dst) RNSF(ref_put(*dst)); + *dst = *src; + *src = NULL; + return RES_OK; +} + +res_T gas_init(struct mem_allocator* allocator, struct gas* gas) { (void)allocator; @@ -226,6 +261,8 @@ gas_init(struct mem_allocator* allocator, struct gas* gas) gas->volume = NULL; gas->temperatures = NULL; gas->ck = NULL; + gas->ntetrahedra = 0; + gas->nvertices = 0; return RES_OK; } @@ -275,9 +312,12 @@ aerosol_init(struct mem_allocator* allocator, struct aerosol* aerosol) { (void)allocator; ASSERT(aerosol); + darray_phase_fn_init(allocator, &aerosol->phase_fn_lst); aerosol->volume = NULL; aerosol->phase_fn_ids = NULL; aerosol->sars = NULL; + aerosol->ntetrahedra = 0; + aerosol->nvertices = 0; return RES_OK; } @@ -285,6 +325,7 @@ void aerosol_release(struct aerosol* aerosol) { ASSERT(aerosol); + darray_phase_fn_release(&aerosol->phase_fn_lst); if(aerosol->volume) SUVM(volume_ref_put(aerosol->volume)); if(aerosol->phase_fn_ids) SBUF(ref_put(aerosol->phase_fn_ids)); if(aerosol->sars) SARS(ref_put(aerosol->sars)); @@ -303,7 +344,7 @@ aerosol_copy(struct aerosol* dst, const struct aerosol* src) if(dst->volume) SUVM(volume_ref_get(dst->volume)); if(dst->phase_fn_ids) SBUF(ref_get(dst->phase_fn_ids)); if(dst->sars) SARS(ref_get(dst->sars)); - return RES_OK; + return darray_phase_fn_copy(&dst->phase_fn_lst, &src->phase_fn_lst); } res_T @@ -319,5 +360,5 @@ aerosol_copy_and_release(struct aerosol* dst, struct aerosol* src) src->volume = NULL; src->phase_fn_ids = NULL; src->sars = NULL; - return RES_OK; + return darray_phase_fn_copy_and_release(&dst->phase_fn_lst, &src->phase_fn_lst); } diff --git a/src/rnatm.h b/src/rnatm.h @@ -50,7 +50,7 @@ struct mem_allocator; struct rnatm_gas_args { const char* smsh_filename; /* Geometry */ const char* sck_filename; /* Radiative properties */ - const char* props_filename; /* Temperature */ + const char* temperatures_filename; /* Temperature */ }; #define RNATM_GAS_ARGS_NULL__ {NULL, NULL, NULL} static const struct rnatm_gas_args RNATM_GAS_ARGS_NULL = RNATM_GAS_ARGS_NULL__; @@ -58,7 +58,7 @@ static const struct rnatm_gas_args RNATM_GAS_ARGS_NULL = RNATM_GAS_ARGS_NULL__; struct rnatm_aerosol_args { const char* smsh_filename; /* Geometry */ const char* sars_filename; /* Radiative properties */ - const char* props_filename; /* Indice de la fonction de phase */ + const char* phase_fn_ids_filename; /* Per node phase function id */ const char* phase_fn_lst_filename; /* List of phase functions */ }; #define RNATM_AEROSOL_ARGS_NULL__ {NULL, NULL, NULL, NULL} diff --git a/src/rnatm_c.h b/src/rnatm_c.h @@ -28,6 +28,39 @@ #include <rsys/ref_count.h> #include <rsys/str.h> +struct rnsf; + +/******************************************************************************* + * Phase function + ******************************************************************************/ +extern LOCAL_SYM res_T +phase_fn_init + (struct mem_allocator* allocator, + struct rnsf** phase_fn); + +extern LOCAL_SYM void +phase_fn_release + (struct rnsf** phase_fn); + +extern LOCAL_SYM res_T +phase_fn_copy + (struct rnsf** dst, + struct rnsf* const* src); + +extern LOCAL_SYM res_T +phase_fn_copy_and_release + (struct rnsf** dst, + struct rnsf** src); + +/* Generate the dynamic array of phase functions */ +#define DARRAY_NAME phase_fn +#define DARRAY_DATA struct rnsf* +#define DARRAY_FUNCTOR_INIT phase_fn_init +#define DARRAY_FUNCTOR_RELEASE phase_fn_release +#define DARRAY_FUNCTOR_COPY phase_fn_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE phase_fn_copy_and_release +#include <rsys/dynamic_array.h> + /******************************************************************************* * Gas ******************************************************************************/ @@ -35,6 +68,8 @@ struct gas { struct suvm_volume* volume; struct sbuf* temperatures; struct sck* ck; + size_t ntetrahedra; + size_t nvertices; }; extern LOCAL_SYM res_T @@ -57,12 +92,15 @@ gas_copy_and_release struct gas* src); /******************************************************************************* - * Aerosol + * Aerosol ******************************************************************************/ struct aerosol { + struct darray_phase_fn phase_fn_lst; struct suvm_volume* volume; struct sbuf* phase_fn_ids; struct sars* sars; + size_t ntetrahedra; + size_t nvertices; }; extern LOCAL_SYM res_T @@ -81,7 +119,7 @@ aerosol_copy extern LOCAL_SYM res_T aerosol_copy_and_release - (struct aerosol* dst, + (struct aerosol* dst, struct aerosol* src); /* Define the dynamic array of aerosols */ @@ -113,4 +151,9 @@ setup_meshes (struct rnatm* atm, const struct rnatm_create_args* args); +extern LOCAL_SYM res_T +setup_properties + (struct rnatm* atm, + const struct rnatm_create_args* args); + #endif /* RNATM_C_H */ diff --git a/src/rnatm_mesh.c b/src/rnatm_mesh.c @@ -80,7 +80,9 @@ setup_uvm const char* filename, struct suvm_device* suvm, struct smsh* smsh, - struct suvm_volume** out_volume) + struct suvm_volume** out_volume, + size_t* ntetrahedra, + size_t* nvertices) { struct suvm_tetrahedral_mesh_args mesh_args = SUVM_TETRAHEDRAL_MESH_ARGS_NULL; struct smsh_desc smsh_desc = SMSH_DESC_NULL; @@ -110,9 +112,11 @@ setup_uvm exit: *out_volume = volume; + *ntetrahedra = smsh_desc.ncells; + *nvertices = smsh_desc.nnodes; return res; error: - if(volume) SUVM(volume_ref_put(volume)); + if(volume) { SUVM(volume_ref_put(volume)); volume = NULL; } goto exit; } @@ -141,15 +145,16 @@ setup_meshes(struct rnatm* atm, const struct rnatm_create_args* args) if(res != RES_OK) goto error; /* Load and structure gas volumetric mesh */ - res = setup_uvm - (atm, args, args->gas.smsh_filename, suvm, smsh, &atm->gas.volume); + res = setup_uvm(atm, args, args->gas.smsh_filename, suvm, smsh, + &atm->gas.volume, &atm->gas.ntetrahedra, &atm->gas.nvertices); if(res != RES_OK) goto error; /* Load and structure aerosol volumetric meshes */ FOR_EACH(i, 0, args->naerosols) { struct aerosol* aerosol = darray_aerosol_data_get(&atm->aerosols)+i; const char* filename = args->aerosols[i].smsh_filename; - res = setup_uvm(atm, args, filename, suvm, smsh, &aerosol->volume); + res = setup_uvm(atm, args, filename, suvm, smsh, &aerosol->volume, + &aerosol->ntetrahedra, &aerosol->nvertices); if(res != RES_OK) goto error; } diff --git a/src/rnatm_properties.c b/src/rnatm_properties.c @@ -0,0 +1,420 @@ +/* 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 /* strtok_r and wordexp */ + +#include "rnatm_c.h" +#include "rnatm_log.h" + +#include <rad-net/rnsf.h> + +#include <star/sars.h> +#include <star/sbuf.h> +#include <star/sck.h> + +#include <rsys/cstr.h> +#include <rsys/text_reader.h> + +#include <string.h> +#include <wordexp.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static INLINE void +reset_gas_properties(struct gas* gas) +{ + if(gas->temperatures) SBUF(ref_put(gas->temperatures)); + if(gas->ck) SCK(ref_put(gas->ck)); + gas->temperatures = NULL; + gas->ck = NULL; +} + +static INLINE void +reset_aerosol_properties(struct aerosol* aerosol) +{ + if(aerosol->phase_fn_ids) SBUF(ref_put(aerosol->phase_fn_ids)); + if(aerosol->sars) SARS(ref_put(aerosol->sars)); + aerosol->phase_fn_ids = NULL; + aerosol->sars = NULL; + darray_phase_fn_clear(&aerosol->phase_fn_lst); +} + +static INLINE res_T +check_gas_temperatures_desc + (const struct rnatm* atm, + const struct sbuf_desc* desc, + const struct rnatm_gas_args* gas_args) +{ + ASSERT(atm && desc && gas_args); + + if(desc->size != atm->gas.nvertices) { + log_err(atm, + "%s: no sufficient temperatures regarding the mesh %s\n", + gas_args->temperatures_filename, gas_args->smsh_filename); + return RES_BAD_ARG; + } + + if(desc->szitem != 4 || desc->alitem != 4 || desc->pitch != 4) { + log_err(atm, "%s: unexpected layout of temperatures\n", + gas_args->temperatures_filename); + return RES_BAD_ARG; + } + + return RES_OK; +} + +static INLINE res_T +check_gas_ck_desc + (const struct rnatm* atm, + const struct rnatm_gas_args* gas_args) +{ + ASSERT(atm && gas_args); + + if(sck_get_nodes_count(atm->gas.ck) != atm->gas.nvertices) { + log_err(atm, + "%s: no sufficient correlated-K regarding the mesh %s\n", + gas_args->sck_filename, gas_args->smsh_filename); + return RES_BAD_ARG; + } + return RES_OK; +} + +static INLINE res_T +check_aerosol_phase_fn_ids_desc + (const struct rnatm* atm, + const struct aerosol* aerosol, + const struct sbuf_desc* desc, + const struct rnatm_aerosol_args* aerosol_args) +{ + ASSERT(atm && aerosol && desc && aerosol_args); + + if(desc->size != aerosol->nvertices) { + log_err(atm, + "%s: no sufficient phase function ids regarding the mesh %s\n", + aerosol_args->phase_fn_ids_filename, aerosol_args->smsh_filename); + return RES_BAD_ARG; + } + + if(desc->szitem != 4 || desc->alitem != 4 || desc->pitch != 4) { + log_err(atm, "%s: unexpected layout of phase function ids\n", + aerosol_args->phase_fn_ids_filename); + return RES_BAD_ARG; + } + + return RES_OK; +} + +static INLINE res_T +check_aerosol_sars_desc + (const struct rnatm* atm, + const struct aerosol* aerosol, + const struct rnatm_aerosol_args* aerosol_args) +{ + ASSERT(atm && aerosol && aerosol_args); + + if(sars_get_nodes_count(aerosol->sars) != aerosol->nvertices) { + log_err(atm, + "%s: no sufficient radiative properties regarding the mesh %s\n", + aerosol_args->sars_filename, aerosol_args->smsh_filename); + return RES_BAD_ARG; + } + return RES_OK; +} + +static res_T +parse_phase_fn + (struct rnatm* atm, + struct aerosol* aerosol, + struct txtrdr* txtrdr, + struct rnsf** out_phase_fn) +{ + wordexp_t wexp; + char* tk = NULL; + char* tk_ctx = NULL; + struct rnsf_create_args args = RNSF_CREATE_ARGS_DEFAULT; + struct rnsf* phase_fn = NULL; + int wexp_is_allocated = 1; + res_T res = RES_OK; + int err = 0; + ASSERT(atm && aerosol && txtrdr && out_phase_fn); + + res = txtrdr_read_line(txtrdr); + if(res != RES_OK) { + log_err(atm, "%s: can't read the line `%lu' -- %s\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + res_to_cstr(res)); + goto error; + } + + if(!txtrdr_get_cline(txtrdr)) { + const size_t nexpect = darray_phase_fn_size_get(&aerosol->phase_fn_lst); + const size_t nparsed = + (size_t)(out_phase_fn - darray_phase_fn_cdata_get(&aerosol->phase_fn_lst)); + log_err(atm, + "%s:%lu: missing a phase function filename. " + "Expecting %lu phase function%s while %lu %s parsed.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + (unsigned long)nexpect, nexpect == 1 ? " " : "s ", + (unsigned long)nparsed, nparsed > 1 ? "were" : "was"); + res = RES_BAD_ARG; + goto error; + } + + tk = strtok_r(txtrdr_get_line(txtrdr), "", &tk_ctx); + ASSERT(tk); + + err = wordexp(tk, &wexp, 0/*flags*/); + if(err) { + log_err(atm, "%s:%lu: unable to expand phase function filename\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + wexp_is_allocated = 1; + ASSERT(wexp.we_wordc != 0); + + args.verbose = atm->verbose; + args.logger = atm->logger; + args.allocator = atm->allocator; + res = rnsf_create(&args, &phase_fn); + if(res != RES_OK) { + log_err(atm, + "%s:%lu: could not create the Rad-Net Scattering Function data structure\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + goto error; + } + + res = rnsf_load(phase_fn, wexp.we_wordv[0]); + if(res != RES_OK) goto error; + + if(wexp.we_wordc > 1) { + log_warn(atm, "%s:%lu: unexpected text `%s'\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + wexp.we_wordv[1]); + } + +exit: + if(wexp_is_allocated) wordfree(&wexp); + *out_phase_fn = phase_fn; + return res; +error: + goto exit; +} + +static res_T +parse_phase_fn_list + (struct rnatm* atm, + struct aerosol* aerosol, + const struct rnatm_aerosol_args* args) +{ + struct txtrdr* txtrdr = NULL; + char* tk = NULL; + char* tk_ctx = NULL; + size_t iphase_fn = 0; + unsigned long nphase_fn = 0; + res_T res = RES_OK; + ASSERT(atm && aerosol && args); + + res = txtrdr_file(atm->allocator, args->phase_fn_lst_filename, '#', &txtrdr); + if(res != RES_OK) { + log_err(atm, "Could not create text reader to parse file `%s' -- %s\n", + args->phase_fn_lst_filename, res_to_cstr(res)); + goto error; + } + + res = txtrdr_read_line(txtrdr); + if(res != RES_OK) { + log_err(atm, "%s: can't read the line %lu --%s\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + res_to_cstr(res)); + goto error; + } + + if(!txtrdr_get_cline(txtrdr)) { + log_err(atm, "%s: file cannot be empty\n", txtrdr_get_name(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + + tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); + ASSERT(tk); + + res = cstr_to_ulong(tk, &nphase_fn); + if(res == RES_OK && nphase_fn == 0) res = RES_BAD_ARG; + if(res != RES_OK) { + log_err(atm, "%s:%lu: invalid number of phase functions %lu\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + nphase_fn); + goto error; + } + + res = darray_phase_fn_resize(&aerosol->phase_fn_lst, nphase_fn); + if(res != RES_OK) { + log_err(atm, "%s: could not allocate the list of %lu phase functions -- %s\n", + txtrdr_get_name(txtrdr), nphase_fn, res_to_cstr(res)); + goto error; + } + + tk = strtok_r(NULL, " \t", &tk_ctx); + if(tk) { + log_warn(atm, "%s:%lu: unexpected text `%s'\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + } + + FOR_EACH(iphase_fn, 0, nphase_fn) { + struct rnsf** phase_fn = + darray_phase_fn_data_get(&aerosol->phase_fn_lst)+iphase_fn; + res = parse_phase_fn(atm, aerosol, txtrdr, phase_fn); + if(res != RES_OK) goto error; + } + +exit: + if(txtrdr) txtrdr_ref_put(txtrdr); + return res; +error: + goto exit; +} + +static res_T +setup_gas_properties(struct rnatm* atm, const struct rnatm_gas_args* gas_args) +{ + struct sck_create_args sck_args = SCK_CREATE_ARGS_DEFAULT; + struct sbuf_create_args sbuf_args = SBUF_CREATE_ARGS_DEFAULT; + struct sbuf_desc sbuf_desc = SBUF_DESC_NULL; + + res_T res = RES_OK; + ASSERT(atm && gas_args); + + /* Create the Star-Buffer loader */ + sbuf_args.logger = atm->logger; + sbuf_args.allocator = atm->allocator; + sbuf_args.verbose = atm->verbose; + res = sbuf_create(&sbuf_args, &atm->gas.temperatures); + if(res != RES_OK) goto error; + + /* Load gas temperatures */ + res = sbuf_load(atm->gas.temperatures, gas_args->temperatures_filename); + if(res != RES_OK) goto error; + res = sbuf_get_desc(atm->gas.temperatures, &sbuf_desc); + if(res != RES_OK) goto error; + res = check_gas_temperatures_desc(atm, &sbuf_desc, gas_args); + if(res != RES_OK) goto error; + + /* Create the Star-CK loader */ + sck_args.logger = atm->logger; + sck_args.allocator = atm->allocator; + sck_args.verbose = atm->verbose; + res = sck_create(&sck_args, &atm->gas.ck); + if(res != RES_OK) goto error; + + /* Load correlated-K */ + res = sck_load(atm->gas.ck, gas_args->sck_filename); + if(res != RES_OK) goto error; + res = check_gas_ck_desc(atm, gas_args); + if(res != RES_OK) goto error; + +exit: + return res; +error: + reset_gas_properties(&atm->gas); + goto exit; +} + +static res_T +setup_aerosol_properties + (struct rnatm* atm, + struct aerosol* aerosol, + const struct rnatm_aerosol_args* aerosol_args) +{ + struct sars_create_args sars_args = SARS_CREATE_ARGS_DEFAULT; + struct sbuf_create_args sbuf_args = SBUF_CREATE_ARGS_DEFAULT; + struct sbuf_desc sbuf_desc = SBUF_DESC_NULL; + + res_T res = RES_OK; + ASSERT(atm && aerosol_args); + + res = parse_phase_fn_list(atm, aerosol, aerosol_args); + if(res != RES_OK) goto error; + + /* Create the Star-Buffer loader */ + sbuf_args.logger = atm->logger; + sbuf_args.allocator = atm->allocator; + sbuf_args.verbose = atm->verbose; + res = sbuf_create(&sbuf_args, &aerosol->phase_fn_ids); + if(res != RES_OK) goto error; + + /* Load phase function ids */ + res = sbuf_load(aerosol->phase_fn_ids, aerosol_args->phase_fn_ids_filename); + if(res != RES_OK) goto error; + res = sbuf_get_desc(aerosol->phase_fn_ids, &sbuf_desc); + if(res != RES_OK) goto error; + res = check_aerosol_phase_fn_ids_desc(atm, aerosol, &sbuf_desc, aerosol_args); + if(res != RES_OK) goto error; + + /* Create the Star-Aerosol loader */ + sars_args.logger = atm->logger; + sars_args.allocator = atm->allocator; + sars_args.verbose = atm->verbose; + res = sars_create(&sars_args, &aerosol->sars); + if(res != RES_OK) goto error; + + /* Load the aerosol radiativ properties */ + res = sars_load(aerosol->sars, aerosol_args->sars_filename); + if(res != RES_OK) goto error; + res = check_aerosol_sars_desc(atm, aerosol, aerosol_args); + if(res != RES_OK) goto error; + +exit: + return res; +error: + reset_aerosol_properties(aerosol); + goto exit; +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +setup_properties(struct rnatm* atm, const struct rnatm_create_args* args) +{ + size_t i = 0; + res_T res = RES_OK; + ASSERT(atm && args); + + res = setup_gas_properties(atm, &args->gas); + if(res != RES_OK) goto error; + + 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; + } + +exit: + return res; +error: + reset_gas_properties(&atm->gas); + FOR_EACH(i, 0, darray_aerosol_size_get(&atm->aerosols)) { + struct aerosol* aerosol = darray_aerosol_data_get(&atm->aerosols)+i; + reset_aerosol_properties(aerosol); + } + goto exit; +}