commit 940e2f9a8fbbacdadacc178a5961070b17082e32
parent 8e88632e8fdbdb9772b954cfd9c722123a244c11
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 29 Jan 2018 10:04:43 +0100
Implement the load function
Diffstat:
7 files changed, 811 insertions(+), 6 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -43,7 +43,10 @@ set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(HTGOP_FILES_SRC
htgop.c)
set(SSOL_FILES_INC
- htgop_c.h)
+ htgop_c.h
+ htgop_layer.h
+ htgop_parse_layers_spectral_intervals_data.h
+ htgop_spectral_intervals.h)
set(SSOL_FILES_INC_API
htgop.h)
diff --git a/src/htgop.c b/src/htgop.c
@@ -16,24 +16,300 @@
#include "htgop.h"
#include "htgop_c.h"
+#include <rsys/cstr.h>
#include <rsys/logger.h>
#include <rsys/mem_allocator.h>
+#include <rsys/stretchy_array.h>
+
+#include <string.h>
+
+/*******************************************************************************
+ * Reader
+ ******************************************************************************/
+struct reader {
+ FILE* stream;
+ const char* name;
+ size_t iline;
+ char* line;
+};
+
+static void
+reader_init(struct reader* rdr, FILE* stream, const char* name)
+{
+ ASSERT(rdr && stream && name);
+ memset(rdr, 0, sizeof(struct reader));
+ rdr->stream = stream;
+ rdr->name = name;
+ rdr->iline = 0;
+ rdr->line = sa_add(rdr->line, 128);
+ ASSERT(rdr->line);
+}
+
+static void
+reader_release(struct reader* rdr)
+{
+ ASSERT(rdr);
+ sa_release(rdr->line);
+}
+
+/* Read a non empty line */
+static char*
+read_line(struct reader* rdr)
+{
+ const int chunk = 32;
+
+ do {
+ if(!fgets(rdr->line, (int)sa_size(rdr->line), rdr->stream)) return NULL;
+ ++rdr->iline;
+
+ /* Ensure that the whole line is read */
+ while(!strrchr(rdr->line, '\n') && !feof(rdr->stream)) {
+ CHK(fgets(sa_add(rdr->line, (size_t)chunk), chunk, rdr->stream));
+ }
+
+ rdr->line[strcspn(rdr->line, "#\n\r")] = '\0'; /* Rm new line & comments */
+ } while(strspn(rdr->line, " \t") == strlen(rdr->line)); /* Empty line */
+ return rdr->line;
+}
/*******************************************************************************
* Helper functions
- ******************************************************************************/
+ ******************************************************************************/
+static void
+log_msg
+ (const struct htgop* htgop,
+ const enum log_type stream,
+ const char* msg,
+ va_list vargs)
+{
+ ASSERT(htgop && msg);
+ if(htgop->verbose) {
+ res_T res; (void)res;
+ res = logger_vprint(htgop->logger, stream, msg, vargs);
+ ASSERT(res == RES_OK);
+ }
+}
+
+static res_T
+parse_spectral_intervals
+ (struct htgop* htgop,
+ struct reader* rdr,
+ const unsigned long nspecints,
+ struct spectral_intervals* specints)
+{
+ unsigned long ispecint;
+ double* wave_numbers = NULL;
+ struct darray_double* quadratures = NULL;
+ res_T res = RES_OK;
+ (void)htgop;
+ ASSERT(htgop && rdr && nspecints && specints);
+
+ #define CALL(Func) { if((res = Func) != RES_OK) goto error; } (void)0
+
+ /* Allocate the memory space for the wave numbers and the quadratures */
+ CALL(darray_double_resize(&specints->wave_numbers, nspecints + 1));
+ CALL(darray_dbllst_resize(&specints->quadratures, nspecints));
+ wave_numbers = darray_double_data_get(&specints->wave_numbers);
+ quadratures = darray_dbllst_data_get(&specints->quadratures);
+
+ FOR_EACH(ispecint, 0, nspecints) {
+ double* quadrature = NULL;
+ double wave_number_low;
+ double wave_number_upp;
+ unsigned long quad_len;
+ unsigned long iquad;
+
+ /* Parse the interval bounds */
+ CALL(cstr_to_double(read_line(rdr), &wave_number_low));
+ CALL(cstr_to_double(read_line(rdr), &wave_number_upp));
+
+ /* Check and register the interval bounds */
+ if(wave_number_low >= wave_number_upp) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(ispecint == 0) {
+ wave_numbers[ispecint] = wave_number_low;
+ } else if(wave_number_low != wave_numbers[ispecint]) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ wave_numbers[ispecint + 1] = wave_number_upp;
+
+ /* Parse and allocate the quadrature length */
+ CALL(cstr_to_ulong(read_line(rdr), &quad_len));
+
+ /* Allocate the points of the quadrature */
+ CALL(darray_double_resize(&quadratures[ispecint], quad_len));
+ quadrature = darray_double_data_get(&quadratures[ispecint]);
+
+ /* Read the weight of the quadrature points */
+ FOR_EACH(iquad, 0, quad_len) {
+ CALL(cstr_to_double(read_line(rdr), &quadrature[iquad]));
+ }
+ }
+
+ #undef CALL
+
+exit:
+ return res;
+error:
+ darray_double_clear(&specints->wave_numbers);
+ darray_dbllst_clear(&specints->quadratures);
+ goto exit;
+}
+
+/* Generate the parse_layers_spectral_intervals_ka_lw function */
+#define LAYER_SPECINT_DATA ka
+#define LAYER_SPECINT_DOMAIN lw
+#include "htgop_parse_layers_spectral_intervals_data.h"
+/* Generate the parse_layers_spectral_intervals_ka_sw function */
+#define LAYER_SPECINT_DATA ka
+#define LAYER_SPECINT_DOMAIN sw
+#include "htgop_parse_layers_spectral_intervals_data.h"
+/* Generate the parse_layers_spectral_intervals_ks_sw function */
+#define LAYER_SPECINT_DATA ks
+#define LAYER_SPECINT_DOMAIN sw
+#include "htgop_parse_layers_spectral_intervals_data.h"
+
+static res_T
+parse_layers_spectral_intervals(struct htgop* htgop, struct reader* rdr)
+{
+ struct layer* layers = NULL;
+ size_t lw_nspecints, sw_nspecints, nlays;
+ size_t ilay;
+ res_T res = RES_OK;
+ ASSERT(htgop && rdr);
+
+ nlays = darray_layer_size_get(&htgop->layers);
+ ASSERT(nlays > 0);
+ lw_nspecints = darray_double_size_get(&htgop->lw_specints.wave_numbers) - 1;
+ sw_nspecints = darray_double_size_get(&htgop->sw_specints.wave_numbers) - 1;
+ ASSERT(lw_nspecints > 0 && sw_nspecints);
+
+ #define CALL(Func) { if((res = Func) != RES_OK) goto error; } (void)0
+ /* Allocate the per layer spectral intervals */
+ FOR_EACH(ilay, 0, nlays) {
+ CALL(darray_lay_lw_specint_resize(&layers[ilay].lw_specints, lw_nspecints));
+ CALL(darray_lay_sw_specint_resize(&layers[ilay].sw_specints, sw_nspecints));
+ }
+ /* Parse the spectral data of the layers */
+ CALL(parse_layers_spectral_intervals_ka_lw(htgop, rdr));
+ CALL(parse_layers_spectral_intervals_ka_sw(htgop, rdr));
+ CALL(parse_layers_spectral_intervals_ks_sw(htgop, rdr));
+ #undef CALL
+
+exit:
+ return res;
+error:
+ FOR_EACH(ilay, 0, nlays) {
+ darray_lay_lw_specint_clear(&layers[ilay].lw_specints);
+ darray_lay_sw_specint_clear(&layers[ilay].sw_specints);
+ }
+ goto exit;
+}
+
+static res_T
+load_stream(struct htgop* htgop, FILE* stream, const char* stream_name)
+{
+ struct reader rdr;
+ struct level* levels = NULL;
+ struct layer* layers = NULL;
+ unsigned long nlvls, nlays, tab_len, nspecints_lw, nspecints_sw;
+ unsigned long ilvl, ilay, itab;
+ res_T res = RES_OK;
+ ASSERT(htgop && stream && stream_name);
+ reader_init(&rdr, stream, stream_name);
+
+ #define CALL(Func) { if((res = Func) != RES_OK) goto error; }
+
+ /* Parse the number of levels/layers */
+ CALL(cstr_to_ulong(read_line(&rdr), &nlvls));
+ CALL(cstr_to_ulong(read_line(&rdr), &nlays));
+ if(nlvls != nlays + 1) { res = RES_BAD_ARG; goto error; }
+
+ /* Parse the ground temperature */
+ CALL(cstr_to_double(read_line(&rdr), &htgop->ground.temperature));
+
+ /* Allocate the per level data */
+ CALL(darray_level_resize(&htgop->levels, nlvls));
+ CALL(darray_layer_resize(&htgop->layers, nlays));
+ levels = darray_level_data_get(&htgop->levels);
+ layers = darray_layer_data_get(&htgop->layers);
+
+ /* Per level data */
+ FOR_EACH(ilvl, 0, nlvls) { /* Pressure */
+ CALL(cstr_to_double(read_line(&rdr), &levels[ilvl].pressure));
+ }
+ FOR_EACH(ilvl, 0, nlvls) { /* Temperature */
+ CALL(cstr_to_double(read_line(&rdr), &levels[ilvl].temperature));
+ }
+ FOR_EACH(ilvl, 0, nlvls) { /* Height */
+ CALL(cstr_to_double(read_line(&rdr), &levels[ilvl].height));
+ }
+
+ /* Per layer x H2O nominal */
+ FOR_EACH(ilay, 0, nlays) {
+ CALL(cstr_to_double(read_line(&rdr), &layers[ilay].x_h2o_nominal));
+ }
+
+ /* Parse the length of the tabulation */
+ CALL(cstr_to_ulong(read_line(&rdr), &tab_len));
+
+ /* Allocate the tabulated xH2O of each layer */
+ FOR_EACH(ilay, 0, nlays) {
+ CALL(darray_double_resize(&layers[ilay].x_h2o_tab, tab_len));
+ }
+
+ /* Parse the tabulated xH2O of each layer */
+ FOR_EACH(itab, 0, tab_len) {
+ FOR_EACH(ilay, 0, nlays) {
+ double* x_h2o_tab = darray_double_data_get(&layers[ilay].x_h2o_tab);
+ CALL(cstr_to_double(read_line(&rdr), &x_h2o_tab[itab]));
+ }
+ }
+
+ /* Parse the long/short wave emissivity of the hround */
+ CALL(cstr_to_double(read_line(&rdr), &htgop->ground.lw_emissivity));
+ CALL(cstr_to_double(read_line(&rdr), &htgop->ground.sw_emissivity));
+
+ /* Parse the numver of long/short wave spectral intervals */
+ CALL(cstr_to_ulong(read_line(&rdr), &nspecints_lw));
+ CALL(cstr_to_ulong(read_line(&rdr), &nspecints_sw));
+
+ /* Parse the data of the long/short wave spectral intervals */
+ CALL(parse_spectral_intervals(htgop, &rdr, nspecints_lw, &htgop->lw_specints));
+ CALL(parse_spectral_intervals(htgop, &rdr, nspecints_sw, &htgop->sw_specints));
+
+ /* Parse the spectral data of the layers */
+ CALL(parse_layers_spectral_intervals(htgop, &rdr));
+
+ #undef CALL
+
+exit:
+ reader_release(&rdr);
+ return res;
+error:
+ log_err(htgop, "%s:%lu: Parsing error.\n", rdr.name, rdr.iline);
+ goto exit;
+}
+
static void
release_htgop(ref_T* ref)
{
struct htgop* htgop;
ASSERT(ref);
htgop = CONTAINER_OF(ref, struct htgop, ref);
+ spectral_intervals_release(&htgop->lw_specints);
+ spectral_intervals_release(&htgop->sw_specints);
+ darray_level_release(&htgop->levels);
+ darray_layer_release(&htgop->layers);
MEM_RM(htgop->allocator, htgop);
}
/*******************************************************************************
* Exported functions
- ******************************************************************************/
+ ******************************************************************************/
res_T
htgop_create
(struct logger* log,
@@ -68,6 +344,10 @@ htgop_create
htgop->allocator = allocator;
htgop->logger = logger;
htgop->verbose = verbose;
+ spectral_intervals_init(allocator, &htgop->lw_specints);
+ spectral_intervals_init(allocator, &htgop->sw_specints);
+ darray_level_init(allocator, &htgop->levels);
+ darray_layer_init(allocator, &htgop->layers);
exit:
if(out_htgop) *out_htgop = htgop;
@@ -96,3 +376,52 @@ htgop_ref_put(struct htgop* htgop)
return RES_OK;
}
+res_T
+htgop_load(struct htgop* htgop, const char* filename)
+{
+ FILE* file = NULL;
+ res_T res = RES_OK;
+
+ if(!htgop || !filename) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ file = fopen(filename, "r");
+ if(!file) {
+ log_err(htgop, "%s: error opening file `%s'.\n", FUNC_NAME, filename);
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+ res = load_stream(htgop, file, filename);
+ if(res != RES_OK) goto error;
+
+exit:
+ if(file) fclose(file);
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+htgop_load_stream(struct htgop* htgop, FILE* stream)
+{
+ if(!htgop || !stream) return RES_BAD_ARG;
+ return load_stream(htgop, stream, "<stream>");
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+void
+log_err(const struct htgop* htgop, const char* msg, ...)
+{
+ va_list vargs_list;
+ ASSERT(htgop && msg);
+
+ va_start(vargs_list, msg);
+ log_msg(htgop, LOG_ERROR, msg, vargs_list);
+ va_end(vargs_list);
+}
+
diff --git a/src/htgop_c.h b/src/htgop_c.h
@@ -16,18 +16,54 @@
#ifndef HTGOP_C_H
#define HTGOP_C_H
+#include "htgop_layer.h"
+#include "htgop_spectral_intervals.h"
+
+#include <rsys/dynamic_array.h>
#include <rsys/ref_count.h>
-struct logger;
-struct mem_allocator;
+struct ground {
+ double temperature; /* In Kelvin */
+ double lw_emissivity; /* Long wave emissivity */
+ double sw_emissivity; /* Short wave emissivity */
+};
+
+struct level {
+ double pressure; /* In Pascal */
+ double temperature; /* In Kelvin */
+ double height; /* In meter */
+};
+
+/* Generate the dynamic array of level */
+#define DARRAY_NAME level
+#define DARRAY_DATA struct level
+#include <rsys/dynamic_array.h>
struct htgop {
- int verbose;
+ struct ground ground;
+
+ /* Description of the spectral intervals for the short/long wave domain */
+ struct spectral_intervals lw_specints;
+ struct spectral_intervals sw_specints;
+ struct darray_layer layers; /* Par layer data */
+ struct darray_level levels; /* Per level data (#level = #layer + 1 ) */
+
+ int verbose; /* Verbosity level */
struct logger* logger;
struct mem_allocator* allocator;
ref_T ref;
};
+extern LOCAL_SYM void
+log_err
+ (const struct htgop* htgop,
+ const char* fmt,
+ ...)
+#ifdef COMPILER_GCC
+ __attribute((format(printf, 2, 3)))
+#endif
+ ;
+
#endif /* HTGOP_C_H */
diff --git a/src/htgop_dbllst.h b/src/htgop_dbllst.h
@@ -0,0 +1,31 @@
+/* Copyright (C) |Meso|Star> 2018 (contact@meso-star.com)
+ *
+ * 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/>. */
+
+#ifndef HTGOP_DBLLST_H
+#define HTGOP_DBLLST_H
+
+#include <rsys/dynamic_array_double.h>
+
+/* Generate the darray_dbllst dynamic array */
+#define DARRAY_NAME dbllst
+#define DARRAY_DATA struct darray_double
+#define DARRAY_FUNCTOR_INIT darray_double_init
+#define DARRAY_FUNCTOR_RELEASE darray_double_release
+#define DARRAY_FUNCTOR_COPY darray_double_copy
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE darray_double_copy_and_release
+#include <rsys/dynamic_array.h>
+
+#endif /* HTGOP_DBLLST_H */
+
diff --git a/src/htgop_layer.h b/src/htgop_layer.h
@@ -0,0 +1,229 @@
+/* Copyright (C) |Meso|Star> 2018 (contact@meso-star.com)
+ *
+ * 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/>. */
+
+#ifndef HTGOP_LAYER_H
+#define HTGOP_LAYER_H
+
+#include "htgop_dbllst.h"
+#include <rsys/dynamic_array.h>
+
+/*******************************************************************************
+ * Long wave spectral interval of a layer. Each data are defined per quadrature
+ * point.
+ ******************************************************************************/
+struct layer_lw_spectral_interval {
+ struct darray_double ka_nominal; /* Nominal absorption coef */
+ struct darray_dbllst ka_tab; /* Tabulated absorption coef */
+};
+
+static INLINE void
+layer_lw_spectral_interval_init
+ (struct mem_allocator* allocator, struct layer_lw_spectral_interval* inter)
+{
+ ASSERT(inter);
+ darray_double_init(allocator, &inter->ka_nominal);
+ darray_dbllst_init(allocator, &inter->ka_tab);
+}
+
+static INLINE void
+layer_lw_spectral_interval_release(struct layer_lw_spectral_interval* inter)
+{
+ ASSERT(inter);
+ darray_double_release(&inter->ka_nominal);
+ darray_dbllst_release(&inter->ka_tab);
+}
+
+static INLINE res_T
+layer_lw_spectral_interval_copy
+ (struct layer_lw_spectral_interval* dst,
+ const struct layer_lw_spectral_interval* src)
+{
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+ #define CALL(Func) { if(RES_OK != (res = Func)) return res; } (void)0
+ CALL(darray_double_copy(&dst->ka_nominal, &src->ka_nominal));
+ CALL(darray_dbllst_copy(&dst->ka_tab, &src->ka_tab));
+ #undef CALL
+ return RES_OK;
+}
+
+static INLINE res_T
+layer_lw_spectral_interval_copy_and_release
+ (struct layer_lw_spectral_interval* dst,
+ struct layer_lw_spectral_interval* src)
+{
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+ #define CALL(Func) { if(RES_OK != (res = Func)) return res; } (void)0
+ CALL(darray_double_copy_and_release(&dst->ka_nominal, &src->ka_nominal));
+ CALL(darray_dbllst_copy_and_release(&dst->ka_tab, &src->ka_tab));
+ #undef CALL
+ layer_lw_spectral_interval_release(src);
+ return RES_OK;
+}
+
+/* Generate the darray_lay_lw_specint dynamic array */
+#define DARRAY_NAME lay_lw_specint
+#define DARRAY_DATA struct layer_lw_spectral_interval
+#define DARRAY_FUNCTOR_INIT layer_lw_spectral_interval_init
+#define DARRAY_FUNCTOR_RELEASE layer_lw_spectral_interval_release
+#define DARRAY_FUNCTOR_COPY layer_lw_spectral_interval_copy
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE \
+ layer_lw_spectral_interval_copy_and_release
+#include <rsys/dynamic_array.h>
+
+/*******************************************************************************
+ * Short wave spectral interval of a layer. Each data are defined per
+ * quadrature point.
+ ******************************************************************************/
+struct layer_sw_spectral_interval {
+ struct darray_double ka_nominal; /* Nominal absorption coef */
+ struct darray_double ks_nominal; /* Nominal diffusion coef */
+ struct darray_dbllst ka_tab; /* Tabulated absorption coef */
+ struct darray_dbllst ks_tab; /* Tabulated diffusion coef */
+};
+
+static INLINE void
+layer_sw_spectral_interval_init
+ (struct mem_allocator* allocator, struct layer_sw_spectral_interval* inter)
+{
+ ASSERT(inter);
+ darray_double_init(allocator, &inter->ka_nominal);
+ darray_double_init(allocator, &inter->ks_nominal);
+ darray_dbllst_init(allocator, &inter->ka_tab);
+ darray_dbllst_init(allocator, &inter->ks_tab);
+}
+
+static INLINE void
+layer_sw_spectral_interval_release(struct layer_sw_spectral_interval* inter)
+{
+ ASSERT(inter);
+ darray_double_release(&inter->ka_nominal);
+ darray_double_release(&inter->ks_nominal);
+ darray_dbllst_release(&inter->ka_tab);
+ darray_dbllst_release(&inter->ks_tab);
+}
+
+static INLINE res_T
+layer_sw_spectral_interval_copy
+ (struct layer_sw_spectral_interval* dst,
+ const struct layer_sw_spectral_interval* src)
+{
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+ #define CALL(Func) { if(RES_OK != (res = Func)) return res; } (void)0
+ CALL(darray_double_copy(&dst->ka_nominal, &src->ka_nominal));
+ CALL(darray_double_copy(&dst->ks_nominal, &src->ks_nominal));
+ CALL(darray_dbllst_copy(&dst->ka_tab, &src->ka_tab));
+ CALL(darray_dbllst_copy(&dst->ks_tab, &src->ks_tab));
+ #undef CALL
+ return RES_OK;
+}
+
+static INLINE res_T
+layer_sw_spectral_interval_copy_and_release
+ (struct layer_sw_spectral_interval* dst,
+ struct layer_sw_spectral_interval* src)
+{
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+ #define CALL(Func) { if(RES_OK != (res = Func)) return res; } (void)0
+ CALL(darray_double_copy_and_release(&dst->ka_nominal, &src->ka_nominal));
+ CALL(darray_double_copy_and_release(&dst->ks_nominal, &src->ks_nominal));
+ CALL(darray_dbllst_copy_and_release(&dst->ka_tab, &src->ka_tab));
+ CALL(darray_dbllst_copy_and_release(&dst->ks_tab, &src->ks_tab));
+ #undef CALL
+ layer_sw_spectral_interval_release(src);
+ return RES_OK;
+}
+
+/* Generate the darray_lay_sw_specint dynamic array */
+#define DARRAY_NAME lay_sw_specint
+#define DARRAY_DATA struct layer_sw_spectral_interval
+#define DARRAY_FUNCTOR_INIT layer_sw_spectral_interval_init
+#define DARRAY_FUNCTOR_RELEASE layer_sw_spectral_interval_release
+#define DARRAY_FUNCTOR_COPY layer_sw_spectral_interval_copy
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE \
+ layer_sw_spectral_interval_copy_and_release
+#include <rsys/dynamic_array.h>
+
+/*******************************************************************************
+ * Per layer data
+ ******************************************************************************/
+struct layer {
+ double x_h2o_nominal; /* Nominal molar fraction of water vapor */
+ struct darray_double x_h2o_tab; /* Tabulated xH2O */
+ struct darray_lay_lw_specint lw_specints; /* Long wave spectral interval data */
+ struct darray_lay_sw_specint sw_specints; /* Short wave spectral interval data */
+};
+
+static INLINE void
+layer_init(struct mem_allocator* allocator, struct layer* layer)
+{
+ ASSERT(layer);
+ darray_double_init(allocator, &layer->x_h2o_tab);
+ darray_lay_lw_specint_init(allocator, &layer->lw_specints);
+ darray_lay_sw_specint_init(allocator, &layer->sw_specints);
+}
+
+static INLINE void
+layer_release(struct layer* layer)
+{
+ ASSERT(layer);
+ darray_double_release(&layer->x_h2o_tab);
+ darray_lay_lw_specint_release(&layer->lw_specints);
+ darray_lay_sw_specint_release(&layer->sw_specints);
+}
+
+static INLINE res_T
+layer_copy(struct layer* dst, const struct layer* src)
+{
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+ dst->x_h2o_nominal = src->x_h2o_nominal;
+ #define CALL(Func) { if(RES_OK != (res = Func)) return res; } (void)0
+ CALL(darray_double_copy(&dst->x_h2o_tab, &src->x_h2o_tab));
+ CALL(darray_lay_lw_specint_copy(&dst->lw_specints, &src->lw_specints));
+ CALL(darray_lay_sw_specint_copy(&dst->sw_specints, &src->sw_specints));
+ #undef CALL
+ return RES_OK;
+}
+
+static INLINE res_T
+layer_copy_and_release(struct layer* dst, struct layer* src)
+{
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+ dst->x_h2o_nominal = src->x_h2o_nominal;
+ #define CALL(Func) { if(RES_OK != (res = Func)) return res; } (void)0
+ CALL(darray_double_copy_and_release(&dst->x_h2o_tab, &src->x_h2o_tab));
+ CALL(darray_lay_lw_specint_copy_and_release(&dst->lw_specints, &src->lw_specints));
+ CALL(darray_lay_sw_specint_copy_and_release(&dst->sw_specints, &src->sw_specints));
+ #undef CALL
+ layer_release(src);
+ return RES_OK;
+}
+
+/* Generate the darray_layer dynamic array */
+#define DARRAY_NAME layer
+#define DARRAY_DATA struct layer
+#define DARRAY_FUNCTOR_INIT layer_init
+#define DARRAY_FUNCTOR_RELEASE layer_release
+#define DARRAY_FUNCTOR_COPY layer_copy
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE layer_copy_and_release
+#include <rsys/dynamic_array.h>
+
+#endif /* HTGOP_LAYER_H */
+
diff --git a/src/htgop_parse_layers_spectral_intervals_data.h b/src/htgop_parse_layers_spectral_intervals_data.h
@@ -0,0 +1,104 @@
+/* Copyright (C) |Meso|Star> 2018 (contact@meso-star.com)
+ *
+ * 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/>. */
+
+/*
+ * Generate the function parsing a per layer and per spectral interval data for
+ * a given domain long/short wave.
+ */
+
+#if !defined(LAYER_SPECINT_DATA) || !defined(LAYER_SPECINT_DOMAIN)
+ #error "Missing the LAYER_SPECINT_<DATA|XDOMAIN> macro."
+#endif
+
+#define DATA CONCAT(CONCAT(LAYER_SPECINT_DATA, _), LAYER_SPECINT_DOMAIN)
+#define XDOMAIN(Name) CONCAT(CONCAT(LAYER_SPECINT_DOMAIN, _), Name)
+#define XDATA(Name) CONCAT(CONCAT(LAYER_SPECINT_DATA, _), Name)
+
+static res_T
+CONCAT(parse_layers_spectral_intervals_, DATA)
+ (struct htgop* htgop, struct reader* rdr)
+{
+ struct layer* layers = NULL;
+ size_t nspecints, nlays, tab_len, quad_len;
+ size_t ispecint, ilay, itab, iquad;
+ res_T res = RES_OK;
+ ASSERT(htgop && rdr);
+
+ layers = darray_layer_data_get(&htgop->layers);
+ nlays = darray_layer_size_get(&htgop->layers);
+ ASSERT(nlays > 0);
+
+ tab_len = darray_double_size_get(&layers[0].x_h2o_tab);
+ ASSERT(tab_len > 0);
+
+ nspecints = darray_double_size_get(&htgop->XDOMAIN(specints).wave_numbers)-1;
+ ASSERT(nspecints > 0);
+
+ #define CALL(Func) { if((res = Func) != RES_OK) goto error; } (void)0
+ FOR_EACH(ispecint, 0, nspecints) {
+ struct CONCAT(layer_, XDOMAIN(spectral_interval))* layspecint;
+ struct darray_double* quad; /* Quadrature of the current interval */
+ double* XDATA(nominal);
+ struct darray_double* XDATA(tab);
+
+ quad = darray_dbllst_data_get
+ (&htgop->XDOMAIN(specints).quadratures) + ispecint;
+ quad_len = darray_double_size_get(quad);
+
+ /* Allocate the per layer data */
+ FOR_EACH(ilay, 0, nlays) {
+ layspecint = CONCAT(CONCAT(darray_lay_, XDOMAIN(specint)), _data_get)
+ (&layers[ilay].XDOMAIN(specints)) + ispecint;
+ CALL(darray_double_resize(&layspecint->XDATA(nominal), quad_len));
+ CALL(darray_dbllst_resize(&layspecint->XDATA(tab), quad_len));
+ FOR_EACH(iquad, 0, quad_len) { /* Tabulated data */
+ XDATA(tab) = darray_dbllst_data_get(&layspecint->XDATA(tab)) + iquad;
+ CALL(darray_double_resize(XDATA(tab), tab_len));
+ }
+ }
+
+ FOR_EACH(iquad, 0, quad_len) {
+ /* Read per layer nominal data */
+ FOR_EACH(ilay, 0, nlays) {
+ layspecint = CONCAT(CONCAT(darray_lay_, XDOMAIN(specint)), _data_get)
+ (&layers[ilay].XDOMAIN(specints)) + ispecint;
+ XDATA(nominal) = darray_double_data_get(&layspecint->XDATA(nominal));
+ CALL(cstr_to_double(read_line(rdr), &XDATA(nominal)[iquad]));
+ }
+
+ /* Read per layer tabulated data */
+ FOR_EACH(itab, 0, tab_len) {
+ FOR_EACH(ilay, 0, nlays) {
+ layspecint = CONCAT(CONCAT(darray_lay_, XDOMAIN(specint)), _data_get)
+ (&layers[ilay].XDOMAIN(specints)) + ispecint;
+ XDATA(tab) = darray_dbllst_data_get(&layspecint->XDATA(tab)) + iquad;
+ CALL(cstr_to_double(read_line(rdr), &darray_double_data_get(XDATA(tab))[itab]));
+ }
+ }
+ }
+ }
+ #undef CALL
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+#undef DATA
+#undef XDOMAIN
+#undef XDATA
+#undef LAYER_SPECINT_DATA
+#undef LAYER_SPECINT_DOMAIN
diff --git a/src/htgop_spectral_intervals.h b/src/htgop_spectral_intervals.h
@@ -0,0 +1,73 @@
+/* Copyright (C) |Meso|Star> 2018 (contact@meso-star.com)
+ *
+ * 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/>. */
+
+#ifndef HTGOP_SPECTRAL_INTERVALS_H
+#define HTGOP_SPECTRAL_INTERVALS_H
+
+#include "htgop_dbllst.h"
+
+struct spectral_intervals {
+ /* List of wave numbers, in cm^-1, sorted in ascending order.
+ * #wave numbers == #intervals + 1 */
+ struct darray_double wave_numbers;
+ struct darray_dbllst quadratures; /* Per spectral interval quadrature weight */
+};
+
+static INLINE void
+spectral_intervals_init
+ (struct mem_allocator* allocator, struct spectral_intervals* sinters)
+{
+ ASSERT(sinters);
+ darray_double_init(allocator, &sinters->wave_numbers);
+ darray_dbllst_init(allocator, &sinters->quadratures);
+}
+
+static INLINE void
+spectral_intervals_release(struct spectral_intervals* sinters)
+{
+ ASSERT(sinters);
+ darray_double_release(&sinters->wave_numbers);
+ darray_dbllst_release(&sinters->quadratures);
+}
+
+static INLINE res_T
+spectral_intervals_copy
+ (struct spectral_intervals* dst, const struct spectral_intervals* src)
+{
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+ #define CALL(Func) { if(RES_OK != (res = Func)) return res; } (void)0
+ CALL(darray_double_copy(&dst->wave_numbers, &src->wave_numbers));
+ CALL(darray_dbllst_copy(&dst->quadratures, &src->quadratures));
+ #undef CALL
+ return RES_OK;
+}
+
+static INLINE res_T
+spectral_intervals_copy_and_release
+ (struct spectral_intervals* dst, struct spectral_intervals* src)
+{
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+ #define CALL(Func) { if(RES_OK != (res = Func)) return res; } (void)0
+ CALL(darray_double_copy_and_release(&dst->wave_numbers, &src->wave_numbers));
+ CALL(darray_dbllst_copy_and_release(&dst->quadratures, &src->quadratures));
+ #undef CALL
+ spectral_intervals_release(src);
+ return RES_OK;
+}
+
+#endif /* HTGOP_SPECTRAL_INTERVALS_H */
+