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:
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;
+}