rnsf

Define and load a phase function data format
git clone git://git.meso-star.fr/rnsf.git
Log | Files | Refs | README | LICENSE

commit a65b8be7dbf522634e8a16563d767e5c940fdca7
parent c15774ccdb473d30b51fdfdfa5ae12706c352286
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue, 21 Jun 2022 16:16:36 +0200

Test the loading of phase functions per band

Diffstat:
Mcmake/CMakeLists.txt | 1+
Asrc/test_rnsf_bands.c | 323+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 324 insertions(+), 0 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -92,6 +92,7 @@ if(NOT NO_TEST) endfunction() new_test(test_rnsf) + new_test(test_rnsf_bands) endif() ################################################################################ diff --git a/src/test_rnsf_bands.c b/src/test_rnsf_bands.c @@ -0,0 +1,323 @@ +/* Copyright (C) 2022 GSMA - Université de Reims Champgne-Ardenne, CNRS + * Copyright (C) 2022 IPGP, Université Paris Cité, CNRS + * Copyright (C) 2022 LAPLACE - Université de Toulouse, CNRS, INPT, UPS + * Copyright (C) 2022 LATMOS/IPSL - UVSQ, Université Paris-Saclay, + * Sorbonne Université, CNRS + * Copyright (C) 2022 LESIA - Observatoire de Paris, Université PSL, + * Sorbonne Université, Université Paris Cité + * Copyright (C) 2022 LMD/IPSL - Sorbonne Université, Université PSL, + * Ecole Polytechnique, Institut Polytechnique de Paris, + * CNRS + * Copyright (C) 2022 |Meso|Star> (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 "rnsf.h" + +#include <rsys/math.h> +#include <rsys/mem_allocator.h> + +static void +test_load1(struct rnsf* rnsf) +{ + FILE* fp = NULL; + const char* filename = "test_file_bands.rnsf"; + const struct rnsf_phase_fn* phase = NULL; + struct rnsf_phase_fn_hg hg = RNSF_PHASE_FN_HG_NULL; + + CHK(fp = fopen(filename, "w+")); + fprintf(fp, "# Comment\n"); + fprintf(fp, "bands 1\n"); + fprintf(fp, "\n"); + fprintf(fp, "200.1 280.3 hg 0\n"); + rewind(fp); + + CHK(rnsf_load_stream(NULL, fp, filename) == RES_BAD_ARG); + CHK(rnsf_load_stream(rnsf, NULL, filename) == RES_BAD_ARG); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_OK); + + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, filename) == RES_OK); + + CHK(rnsf_load(NULL, filename) == RES_BAD_ARG); + CHK(rnsf_load(rnsf, NULL) == RES_BAD_ARG); + CHK(rnsf_load(rnsf, "invalid") == RES_IO_ERR); + CHK(rnsf_load(rnsf, filename) == RES_OK); + + CHK(rnsf_get_phase_fn_count(rnsf) == 1); + CHK(phase = rnsf_get_phase_fn(rnsf, 0)); + CHK(rnsf_phase_fn_get_type(phase) == RNSF_PHASE_FN_HG); + + CHK(rnsf_phase_fn_get_hg(NULL, &hg) == RES_BAD_ARG); + CHK(rnsf_phase_fn_get_hg(phase, NULL) == RES_BAD_ARG); + CHK(rnsf_phase_fn_get_hg(phase, &hg) == RES_OK); + CHK(hg.wavelengths[0] == 200.1); + CHK(hg.wavelengths[1] == 280.3); + CHK(hg.g == 0); + CHK(fclose(fp) == 0); +} + +static void +test_load2(struct rnsf* rnsf) +{ + struct rnsf_phase_fn_discrete discrete = RNSF_PHASE_FN_DISCRETE_NULL; + struct rnsf_phase_fn_hg hg = RNSF_PHASE_FN_HG_NULL; + FILE* fp = NULL; + const struct rnsf_phase_fn* phase = NULL; + + CHK(fp = tmpfile()); + fprintf(fp, "bands 5\n"); + fprintf(fp, "100 200 hg -0.3\n"); + fprintf(fp, "200 300 hg 0.4\n"); + fprintf(fp, "300 400 hg 0.5\n"); + fprintf(fp, "850 875.123 discrete 5\n"); + fprintf(fp, " 0 0.3\n"); + fprintf(fp, " %.9g 0.3\n", PI/4.0); + fprintf(fp, " %.9g 0.3\n", PI/2.0); + fprintf(fp, " %.9g 0.3\n", 3*PI/4.0); + fprintf(fp, " PI 0.3\n"); + fprintf(fp, "900 1000 hg -0.1\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_OK); + + CHK(rnsf_get_phase_fn_count(rnsf) == 5); + + CHK(phase = rnsf_get_phase_fn(rnsf, 0)); + CHK(rnsf_phase_fn_get_type(phase) == RNSF_PHASE_FN_HG); + CHK(rnsf_phase_fn_get_discrete(phase, &discrete) == RES_BAD_ARG); + CHK(rnsf_phase_fn_get_hg(phase, &hg) == RES_OK); + CHK(hg.wavelengths[0] == 100 && hg.wavelengths[1] == 200); + CHK(hg.g == -0.3); + + CHK(phase = rnsf_get_phase_fn(rnsf, 1)); + CHK(rnsf_phase_fn_get_type(phase) == RNSF_PHASE_FN_HG); + CHK(rnsf_phase_fn_get_hg(phase, &hg) == RES_OK); + CHK(hg.wavelengths[0] == 200 && hg.wavelengths[1] == 300); + CHK(hg.g == 0.4); + + CHK(phase = rnsf_get_phase_fn(rnsf, 2)); + CHK(rnsf_phase_fn_get_type(phase) == RNSF_PHASE_FN_HG); + CHK(rnsf_phase_fn_get_hg(phase, &hg) == RES_OK); + CHK(hg.wavelengths[0] == 300 && hg.wavelengths[1] == 400); + CHK(hg.g == 0.5); + + CHK(phase = rnsf_get_phase_fn(rnsf, 3)); + CHK(rnsf_phase_fn_get_type(phase) == RNSF_PHASE_FN_DISCRETE); + CHK(rnsf_phase_fn_get_hg(phase, &hg) == RES_BAD_ARG); + CHK(rnsf_phase_fn_get_discrete(NULL, &discrete) == RES_BAD_ARG); + CHK(rnsf_phase_fn_get_discrete(phase, NULL) == RES_BAD_ARG); + CHK(rnsf_phase_fn_get_discrete(phase, &discrete) == RES_OK); + CHK(discrete.wavelengths[0] == 850); + CHK(discrete.wavelengths[1] == 875.123); + CHK(discrete.nitems == 5); + CHK(discrete.items[0].theta == 0); + CHK(eq_eps(discrete.items[1].theta, PI/4.0, 1.e-6)); + CHK(eq_eps(discrete.items[2].theta, PI/2.0, 1.e-6)); + CHK(eq_eps(discrete.items[3].theta, 3*PI/4.0, 1.e-6)); + CHK(eq_eps(discrete.items[4].theta, PI, 1.e-6)); + /* Check normalization */ + CHK(eq_eps(discrete.items[0].value, 1.0/(4*PI), 1.e-6)); + CHK(eq_eps(discrete.items[1].value, 1.0/(4*PI), 1.e-6)); + CHK(eq_eps(discrete.items[2].value, 1.0/(4*PI), 1.e-6)); + CHK(eq_eps(discrete.items[3].value, 1.0/(4*PI), 1.e-6)); + + CHK(phase = rnsf_get_phase_fn(rnsf, 4)); + CHK(rnsf_phase_fn_get_type(phase) == RNSF_PHASE_FN_HG); + CHK(rnsf_phase_fn_get_hg(phase, &hg) == RES_OK); + CHK(hg.wavelengths[0] == 900 && hg.wavelengths[1] == 1000); + CHK(hg.g == -0.1); + + CHK(fclose(fp) == 0); +} + +static void +test_load_fail(struct rnsf* rnsf) +{ + FILE* fp = NULL; + + /* Invalid keyword */ + CHK(fp = tmpfile()); + fprintf(fp, "bandes 1\n"); + fprintf(fp, "380 780 hg 0.5\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* No bands count */ + CHK(fp = tmpfile()); + fprintf(fp, "bands\n"); + fprintf(fp, "380 780 hg 0.5\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Missing a band definition */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 2\n"); + fprintf(fp, "380 780 hg 0.5\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid wavelengths */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "-380 780 hg 0.5\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Missing a band boundary */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "380 hg 0.5\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid phase function type */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "380 780 Henyey-Greenstein 0.5\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid asymmetric param */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "380 780 hg 1.01\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Additional parameters. Print a warning */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1 additional_text\n"); + fprintf(fp, "380 780 hg 1.0\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_OK); + CHK(fclose(fp) == 0); + + /* Unsorted phase functions */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 2\n"); + fprintf(fp, "380 400 hg 1.0\n"); + fprintf(fp, "280 300 hg 0.0\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Phase functions overlap */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 2\n"); + fprintf(fp, "280 400 hg 1.0\n"); + fprintf(fp, "300 480 hg 0.0\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Phase functions overlap */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 2\n"); + fprintf(fp, "280 280 hg 1.0\n"); + fprintf(fp, "280 280 hg 0.0\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid #angles */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "380 780 discrete 1\n"); + fprintf(fp, " 0 1\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid last angle */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "380 780 discrete 2\n"); + fprintf(fp, " 0 1\n"); + fprintf(fp, " 3.14 1\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Missing an angle */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "380 780 discrete 2\n"); + fprintf(fp, " 0 1\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid angle */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "380 780 discrete 3\n"); + fprintf(fp, " 0 1\n"); + fprintf(fp, " PI 1\n"); + fprintf(fp, " 4 1\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Unsorted angles */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "380 780 discrete 5\n"); + fprintf(fp, " 0 1\n"); + fprintf(fp, " 0.1 1\n"); + fprintf(fp, " 0.2 1\n"); + fprintf(fp, " 0.15 1\n"); + fprintf(fp, " PI 1\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Additional text. Print a warning */ + CHK(fp = tmpfile()); + fprintf(fp, "bands 1\n"); + fprintf(fp, "380 780 discrete 4\n"); + fprintf(fp, " 0 1\n"); + fprintf(fp, " 0.1 1\n"); + fprintf(fp, " 0.15 1 additional_text\n"); + fprintf(fp, " PI 1\n"); + rewind(fp); + CHK(rnsf_load_stream(rnsf, fp, NULL) == RES_OK); + CHK(fclose(fp) == 0); +} + +int +main(int argc, char** argv) +{ + struct rnsf_create_args args = RNSF_CREATE_ARGS_DEFAULT; + struct rnsf* rnsf = NULL; + (void)argc, (void)argv; + + args.verbose = 1; + CHK(rnsf_create(&args, &rnsf) == RES_OK); + CHK(rnsf_get_phase_fn_count(rnsf) == 0); + + test_load1(rnsf); + test_load2(rnsf); + test_load_fail(rnsf); + + CHK(rnsf_ref_put(rnsf) == RES_OK); + CHK(mem_allocated_size() == 0); + return 0; +}