htgop

Optical properties of a gas mixture
git clone git://git.meso-star.fr/htgop.git
Log | Files | Refs | README | LICENSE

commit 22df719f66edfa9baba1fb2d8906b4b8d01c79bb
parent fb44c28d0176fa571d5c96bd754e4c27903c45a0
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue, 31 Jul 2018 16:07:06 +0200

Test the interpolation of the radiative properties

Diffstat:
Mcmake/CMakeLists.txt | 3+++
Msrc/htgop.c | 19++++++++++++++++---
Msrc/htgop.h | 2+-
Msrc/htgop_fetch_radiative_properties.h | 2+-
Msrc/htgop_parse_layers_spectral_intervals_data.h | 7+++++++
Asrc/test_htgop_fetch_radiative_properties.c | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_htgop_fetch_radiative_properties.h | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_htgop_load.c | 4++++
8 files changed, 229 insertions(+), 5 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -100,11 +100,14 @@ if(NOT NO_TEST) endif() new_test(test_htgop) + build_test(test_htgop_fetch_radiative_properties) build_test(test_htgop_load) build_test(test_htgop_sample) add_test(test_htgop_load test_htgop_load ${_etc_dst}/ecrad_opt_prop.txt) add_test(test_htgop_sample test_htgop_sample ${_etc_dst}/ecrad_opt_prop.txt) + add_test(test_htgop_fetch_radiative_properties + test_htgop_fetch_radiative_properties ${_etc_dst}/ecrad_opt_prop.txt) endif() ################################################################################ diff --git a/src/htgop.c b/src/htgop.c @@ -275,11 +275,24 @@ load_stream(struct htgop* htgop, FILE* stream, const char* stream_name) 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])); - + if(x_h2o_tab[itab] < 0) { + log_err(htgop, + "%s:%lu: the tabulated water vapor molar fractions must be in [0, 1].\n", + rdr.name, rdr.iline); + res = RES_BAD_ARG; + goto error; + } if(itab && x_h2o_tab[itab] < x_h2o_tab[itab-1]) { log_err(htgop, - "%s:%lu: The tabulated x H2O must be sorted in strict ascending " - "order.\n", rdr.name, rdr.iline); + "%s:%lu: the tabulated water vapor molar fractions must be sorted in " + "strict ascending order.\n", rdr.name, rdr.iline); + res = RES_BAD_ARG; + goto error; + } + if(itab == tab_len-1 && x_h2o_tab[itab] != 1) { + log_err(htgop, + "%s:%lu: the tabulated water vapor molar fractions is not normalized.\n", + rdr.name, rdr.iline); res = RES_BAD_ARG; goto error; } diff --git a/src/htgop.h b/src/htgop.h @@ -216,7 +216,7 @@ htgop_layer_sw_spectral_interval_get_tab struct htgop_layer_sw_spectral_interval_tab* tab); /******************************************************************************* - * The following functions Retrieve the absorption/scattering coefficient in a + * The following functions retrieve the absorption/scattering coefficient in a * layer, in short/long wave, at a given spectral interval for a specific * quadrature point with respect to a submitted water vapor molar fraction * x_h2o. x_h2o is compared to the values of tabulated water vapor molar diff --git a/src/htgop_fetch_radiative_properties.h b/src/htgop_fetch_radiative_properties.h @@ -83,7 +83,7 @@ CONCAT(CONCAT(CONCAT(htgop_layer_fetch_,LAYER_SPECINT_DOMAIN),_),LAYER_SPECINT_D if(!k1 || !k2) { /* Linear interpolation */ k = k1 + (k2-k1)/(x2-x1) * (x_h2o-x1); } else { - const double alpha = (log(k2) - log(k1))/(log(x1) - log(x2)); + const double alpha = (log(k2) - log(k1))/(log(x2) - log(x1)); const double beta = log(k1) - alpha * log(x1); k = exp(alpha * log(x_h2o) + beta); } diff --git a/src/htgop_parse_layers_spectral_intervals_data.h b/src/htgop_parse_layers_spectral_intervals_data.h @@ -85,6 +85,13 @@ CONCAT(parse_layers_spectral_intervals_, DATA) (&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])); +#if 0 + if(darray_double_data_get(XDATA(tab))[itab] < 0) { + log_err(htgop, "The radiative properties cannot be negative.\n"); + res = RES_BAD_ARG; + goto error; + } +#endif } } } diff --git a/src/test_htgop_fetch_radiative_properties.c b/src/test_htgop_fetch_radiative_properties.c @@ -0,0 +1,69 @@ +/* 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/>. */ + +#include "htgop.h" + +#include "htgop.h" +#include "test_htgop_utils.h" + +#include <rsys/math.h> + +/* Generate the check_layer_fetch_lw_ka function */ +#define DOMAIN lw +#define DATA ka +#include "test_htgop_fetch_radiative_properties.h" +/* Generate the check_layer_fetch_sw_ka function */ +#define DOMAIN sw +#define DATA ka +#include "test_htgop_fetch_radiative_properties.h" +/* Generate the check_layer_fetch_sw_ks function */ +#define DOMAIN sw +#define DATA ks +#include "test_htgop_fetch_radiative_properties.h" + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct htgop* htgop; + size_t i, n; + + if(argc < 2) { + fprintf(stderr, "Usage: %s FILENAME\n", argv[0]); + return 1; + } + + CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); + CHK(htgop_create(NULL, &allocator, 1, &htgop) == RES_OK); + CHK(htgop_load(htgop, argv[1]) == RES_OK); + + CHK(htgop_get_layers_count(htgop, &n) == RES_OK); + CHK(n > 0); + + FOR_EACH(i, 0, n) { + struct htgop_layer layer; + CHK(htgop_get_layer(htgop, i, &layer) == RES_OK); + check_layer_fetch_lw_ka(htgop, &layer); + check_layer_fetch_sw_ka(htgop, &layer); + check_layer_fetch_sw_ks(htgop, &layer); + } + + CHK(htgop_ref_put(htgop) == RES_OK); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_htgop_fetch_radiative_properties.h b/src/test_htgop_fetch_radiative_properties.h @@ -0,0 +1,128 @@ +/* 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/>. */ + +#include "htgop.h" +#include <math.h> + +#if !defined(DOMAIN) || !defined(DATA) + #error "Missing the <DATA|DOMAIN> macro." +#endif + +/* Helper macros */ +#define GET_NSPECINTS \ + CONCAT(CONCAT(htgop_get_, DOMAIN), _spectral_intervals_count) +#define GET_SPECINT \ + CONCAT(CONCAT(htgop_get_, DOMAIN), _spectral_interval) +#define LAY_SPECINT \ + CONCAT(CONCAT(htgop_layer_, DOMAIN),_spectral_interval) +#define LAY_SPECINT_TAB \ + CONCAT(CONCAT(htgop_layer_, DOMAIN),_spectral_interval_tab) +#define GET_LAY_SPECINT \ + CONCAT(CONCAT(htgop_layer_get_, DOMAIN), _spectral_interval) +#define GET_LAY_SPECINT_TAB \ + CONCAT(CONCAT(htgop_layer_, DOMAIN), _spectral_interval_get_tab) +#define FETCH_K \ + CONCAT(CONCAT(CONCAT(htgop_layer_fetch_, DOMAIN),_), DATA) +#define K_TAB CONCAT(DATA, _tab) + +static void +CONCAT(CONCAT(CONCAT(check_layer_fetch_, DOMAIN),_), DATA) + (const struct htgop* htgop, + const struct htgop_layer* layer) +{ + struct htgop_spectral_interval specint; + size_t ispecint; + size_t nspecints; + size_t quad_len; + double x_h2o; + double k; + + CHK(htgop && layer); + CHK(GET_NSPECINTS(htgop, &nspecints) == RES_OK); + CHK(nspecints); + + CHK(GET_SPECINT(htgop, 0, &specint) == RES_OK); + CHK(specint.quadrature_length); + CHK(layer->tab_length); + + quad_len = specint.quadrature_length; + + x_h2o = layer->x_h2o_tab[0]; + CHK(FETCH_K(NULL, 0, 0, x_h2o, &k) == RES_BAD_ARG); + CHK(FETCH_K(layer, nspecints, 0, x_h2o, &k) == RES_BAD_ARG); + CHK(FETCH_K(layer, 0, quad_len, x_h2o, &k) == RES_BAD_ARG); + CHK(FETCH_K(layer, 0, 0, 1.0000001, &k) == RES_BAD_ARG); + CHK(FETCH_K(layer, 0, 0, x_h2o, NULL) == RES_BAD_ARG); + + FOR_EACH(ispecint, 0, nspecints) { + struct LAY_SPECINT lay_specint; + struct LAY_SPECINT_TAB lay_tab; + size_t iquad; + + CHK(GET_SPECINT(htgop, ispecint, &specint) == RES_OK); + CHK(specint.quadrature_length); + + FOR_EACH(iquad, 0, specint.quadrature_length) { + size_t itab; + + CHK(GET_LAY_SPECINT(layer, ispecint, &lay_specint) == RES_OK); + CHK(GET_LAY_SPECINT_TAB(&lay_specint, iquad, &lay_tab) == RES_OK); + CHK(lay_tab.tab_length == layer->tab_length); + + /* Check boundaries */ + FOR_EACH(itab, 0, layer->tab_length) { + const size_t N = 10; + size_t i; + + x_h2o = layer->x_h2o_tab[itab]; + CHK(FETCH_K(layer, ispecint, iquad, x_h2o, &k) == RES_OK); + CHK(eq_eps(k, lay_tab.K_TAB[itab], 1.e-6)); + + FOR_EACH(i, 0, N) { + const double r = rand_canonic(); + const double x1 = itab ? layer->x_h2o_tab[itab-1] : 0; + const double k1 = itab ? lay_tab.K_TAB[itab-1] : 0; + const double x2 = layer->x_h2o_tab[itab]; + const double k2 = lay_tab.K_TAB[itab]; + double ref; + + x_h2o = x1 + (x2 - x1) * r; + if(!itab || !k1 || !k2) { + ref = k1 + (k2-k1) / (x2 - x1) * x_h2o; + } else { + const double alpha = (log(k2) - log(k1)) / (log(x2) - log(x1)); + const double beta = log(k1) - alpha*log(x1); + ref = exp(alpha*log(x_h2o) + beta); + } + + CHK(FETCH_K(layer, ispecint, iquad, x_h2o, &k) == RES_OK); + CHK(eq_eps(k, ref, 1.e-6)); + } + } + } + } +} + +#undef GET_NSPECINTS +#undef GET_SPECINT +#undef LAY_SPECINT +#undef LAY_SPECINT_TAB +#undef GET_LAY_SPECINT +#undef GET_LAY_SPECINT_TAB +#undef FETCH_K +#undef K_TAB +#undef DOMAIN +#undef DATA + diff --git a/src/test_htgop_load.c b/src/test_htgop_load.c @@ -288,6 +288,8 @@ main(int argc, char** argv) FOR_EACH(iquad, 0, specint.quadrature_length) { FOR_EACH(ilay, 0, nlays) { CHK(htgop_get_layer(htgop, ilay, &lay) == RES_OK); + CHK(lay.lw_spectral_intervals_count == nspecints_lw); + CHK(lay.sw_spectral_intervals_count == nspecints_sw); CHK(htgop_layer_get_lw_spectral_interval(&lay, ispecint, &lw_specint) == RES_OK); CHK(lw_specint.quadrature_length == specint.quadrature_length); CHK(cstr_to_double(read_line(&rdr), &dbl) == RES_OK); @@ -296,6 +298,8 @@ main(int argc, char** argv) FOR_EACH(itab, 0, tab_len) { FOR_EACH(ilay, 0, nlays) { CHK(htgop_get_layer(htgop, ilay, &lay) == RES_OK); + CHK(lay.lw_spectral_intervals_count == nspecints_lw); + CHK(lay.sw_spectral_intervals_count == nspecints_sw); CHK(htgop_layer_get_lw_spectral_interval(&lay, ispecint, &lw_specint) == RES_OK); CHK(htgop_layer_lw_spectral_interval_get_tab(&lw_specint, iquad, &lw_tab) == RES_OK); CHK(lw_tab.tab_length == tab_len);