star-hitran

Load line-by-line data from the HITRAN database
git clone git://git.meso-star.fr/star-hitran.git
Log | Files | Refs | README | LICENSE

commit 31809f4f63f8bc681abe7eef910cabf44f6a96f3
parent 701b894144e64bafece998abf9d6c886d99cb8d5
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue,  8 Mar 2022 16:02:15 +0100

Rename 'transition' in 'line'

Diffstat:
Mcmake/CMakeLists.txt | 4++--
Msrc/shtr.h | 43+++++++++++++++++++++----------------------
Asrc/shtr_lines_list.c | 320+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/shtr_transitions_list.c | 325-------------------------------------------------------------------------------
Asrc/test_shtr_lines.c | 265+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/test_shtr_transitions.c | 265-------------------------------------------------------------------------------
6 files changed, 608 insertions(+), 614 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -48,7 +48,7 @@ set(SHTR_FILES_SRC shtr_log.c shtr_isotope_metadata.c shtr_param.c - shtr_transitions_list.c) + shtr_lines_list.c) set(SHTR_FILES_INC shtr_c.h shtr_log.h @@ -91,7 +91,7 @@ if(NOT NO_TEST) new_test(test_shtr) new_test(test_shtr_isotope_metadata) - new_test(test_shtr_transitions) + new_test(test_shtr_lines) endif() ################################################################################ diff --git a/src/shtr.h b/src/shtr.h @@ -30,9 +30,9 @@ #define SHTR_API extern IMPORT_SYM #endif -/* Helper macro that asserts if the invocation of the sth function `Func' - * returns an error. One should use this macro on sth function calls for - * which no explicit error checking is performed */ +/* Helper macro that asserts if the invocation of the shtr function `Func' + * returns an error. One should use this macro on shtr function calls for which + * no explicit error checking is performed */ #ifndef NDEBUG #define SHTR(Func) ASSERT(shtr_ ## Func == RES_OK) #else @@ -76,7 +76,7 @@ static const struct shtr_molecule SHTR_MOLECULE_NULL = #define SHTR_MOLECULE_IS_NULL(Molecule) \ ((Molecule)->id == SHTR_MOLECULE_NULL.id) -struct shtr_transition { +struct shtr_line { double wavenumber; /* Central wavenumber in vacuum [cm^-1] */ double intensity; /* Reference intensity [cm^-1/(molec.cm^2)] */ double gamma_air; /* Air broadening half-width [cm^-1.atm^-1] */ @@ -96,14 +96,13 @@ struct shtr_transition { * data structure loaded from an isotope metadata file */ int32_t isotope_id_local; }; -#define SHTR_TRANSITION_NULL__ {0,0,0,0,0,0,0,-1,-1} -static const struct shtr_transition SHTR_TRANSITION_NULL = - SHTR_TRANSITION_NULL__; +#define SHTR_LINE_NULL__ {0,0,0,0,0,0,0,-1,-1} +static const struct shtr_line SHTR_LINE_NULL = SHTR_LINE_NULL__; /* Forward declarations of opaque data structures */ struct shtr; struct shtr_isotope_metadata; -struct shtr_transitions_list; +struct shtr_lines_list; BEGIN_DECLS @@ -174,35 +173,35 @@ shtr_isotope_metadata_find_molecule * Transitions API ******************************************************************************/ SHTR_API res_T -shtr_transitions_list_load +shtr_lines_list_load (struct shtr* shtr, const char* path, - struct shtr_transitions_list** trlst); + struct shtr_lines_list** trlst); SHTR_API res_T -shtr_transitions_list_load_stream +shtr_lines_list_load_stream (struct shtr* shtr, FILE* stream, const char* stream_name, /* NULL <=> use default stream name */ - struct shtr_transitions_list** trlst); + struct shtr_lines_list** trlst); SHTR_API res_T -shtr_transitions_list_ref_get - (struct shtr_transitions_list* trlst); +shtr_lines_list_ref_get + (struct shtr_lines_list* trlst); SHTR_API res_T -shtr_transitions_list_ref_put - (struct shtr_transitions_list* trlst); +shtr_lines_list_ref_put + (struct shtr_lines_list* trlst); SHTR_API res_T -shtr_transitions_list_get_size - (const struct shtr_transitions_list* trlst, - size_t* ntransitions); +shtr_lines_list_get_size + (const struct shtr_lines_list* trlst, + size_t* nlines); SHTR_API res_T -shtr_transitions_list_get - (const struct shtr_transitions_list* trlst, - const struct shtr_transition* transitions[]); +shtr_lines_list_get + (const struct shtr_lines_list* trlst, + const struct shtr_line* lines[]); END_DECLS diff --git a/src/shtr_lines_list.c b/src/shtr_lines_list.c @@ -0,0 +1,320 @@ +/* Copyright (C) 2022 CNRS - LMD + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * Copyright (C) 2022 Université Paul Sabatier - IRIT + * Copyright (C) 2022 Université Paul Sabatier - Laplace + * + * 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 "shtr.h" +#include "shtr_c.h" +#include "shtr_log.h" +#include "shtr_param.h" + +#include <rsys/cstr.h> +#include <rsys/dynamic_array.h> +#include <rsys/text_reader.h> + +/* Generate the dynamic array of trlst */ +#define DARRAY_NAME line +#define DARRAY_DATA struct shtr_line +#include <rsys/dynamic_array.h> + +struct shtr_lines_list { + /* List of trlst */ + struct darray_line lines; + + struct shtr* shtr; + ref_T ref; +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static res_T +create_lines_list + (struct shtr* shtr, + struct shtr_lines_list** out_lines) +{ + struct shtr_lines_list* trlst = NULL; + res_T res = RES_OK; + ASSERT(shtr && out_lines); + + trlst = MEM_CALLOC(shtr->allocator, 1, sizeof(*trlst)); + if(!trlst) { + log_err(shtr, "Could not allocate the trlst data structure.\n"); + res = RES_MEM_ERR; + goto error; + } + ref_init(&trlst->ref); + SHTR(ref_get(shtr)); + trlst->shtr = shtr; + darray_line_init(shtr->allocator, &trlst->lines); + +exit: + *out_lines = trlst; + return res; +error: + goto exit; +} + +static res_T +parse_line(struct shtr_lines_list* trlst, struct txtrdr* txtrdr) +{ + struct shtr_line tr = SHTR_LINE_NULL; + struct param_desc param = PARAM_DESC_NULL; + struct shtr* shtr = NULL; + char* line = NULL; + char* str = NULL; + char* end = NULL; + char backup; + int molecule_id; + int isotope_id_local; + res_T res = RES_OK; + + ASSERT(trlst && txtrdr); + + line = txtrdr_get_line(txtrdr); + ASSERT(line); + + shtr = trlst->shtr; + param.path = txtrdr_get_name(txtrdr); + param.line = txtrdr_get_line_num(txtrdr); + + str = end = line; + backup = str[0]; + #define NEXT(Size) { \ + *end = backup; \ + str = end; \ + end = str+(Size); \ + backup = *end; \ + *end = '\0'; \ + } (void)0 + #define PARSE(Var, Size, Type, Name, Low, Upp, LowIncl, UppIncl) { \ + NEXT(Size); \ + param.name = (Name); \ + param.low = (Low); \ + param.upp = (Upp); \ + param.is_low_incl = (LowIncl); \ + param.is_upp_incl = (UppIncl); \ + res = parse_param_##Type(shtr, str, &param, Var); \ + if(res != RES_OK) goto error; \ + } (void)0 + + PARSE(&molecule_id, 2, int, "molecule identifier", 0,99,1,1); + tr.molecule_id = (int32_t)molecule_id; + + PARSE(&isotope_id_local, 1, int, "isotope local identifier", 0,9,1,1); + tr.isotope_id_local = (int32_t) + (isotope_id_local == 0 ? 9 : (isotope_id_local - 1)); + + PARSE(&tr.wavenumber, 12, double, "central wavenumber", 0,INF,0,1); + PARSE(&tr.intensity, 10, double, "reference intensity", 0,INF,0,1); + + NEXT(10); /* Skip the Enstein coef */ + + PARSE(&tr.gamma_air, 5, double, "air broadening half-width", 0,INF,1,1); + PARSE(&tr.gamma_self, 5, double, "self broadening half-width", 0,INF,1,1); + + /* Handle unavailable lower state energy */ + PARSE(&tr.lower_state_energy, 10, double, "lower state energy",-INF,INF,1,1); + if(tr.lower_state_energy == -1) { + log_warn(shtr, + "%s:%lu: the lower state energy is unavailable for this line, so it is " + "ignored.\n", param.path, param.line); + goto exit; /* Skip the line */ + } + /* Check the domain validity */ + if(tr.lower_state_energy < 0) { + log_err(shtr, + "%s:%lu: invalid lower state energy %g. It must be in [0, INF].\n", + param.path, param.line, tr.lower_state_energy); + res = RES_BAD_ARG; + goto error; + } + + PARSE(&tr.n_air, 4, double, "temperature-dependent exponent",-INF,INF,1,1); + PARSE(&tr.delta_air, 8, double, "air-pressure wavenumber shift", -INF,INF,1,1); + + /* Skip the remaining values */ + + #undef NEXT + #undef PARSE + + /* Check the size of the remaining data to ensure that there is at least the + * expected number of bytes wrt the HITRAN fileformat */ + *end = backup; + str = end; + if(strlen(str) != 93) { + log_err(trlst->shtr, "%s:%lu: missing data after delta air.\n", + param.path, (unsigned long)param.line); + res = RES_BAD_ARG; + goto error; + } + + res = darray_line_push_back(&trlst->lines, &tr); + if(res != RES_OK) { + log_err(trlst->shtr, + "%s:%lu: error storing the line -- %s.\n", + param.path, (unsigned long)param.line, res_to_cstr(res)); + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +load_stream + (struct shtr* shtr, + FILE* stream, + const char* name, + struct shtr_lines_list** out_lines) +{ + struct shtr_lines_list* trlst = NULL; + struct txtrdr* txtrdr = NULL; + res_T res = RES_OK; + ASSERT(shtr && stream && name && out_lines); + + res = create_lines_list(shtr, &trlst); + if(res != RES_OK) goto error; + + res = txtrdr_stream(trlst->shtr->allocator, stream, name, + 0/*No comment char*/, &txtrdr); + if(res != RES_OK) { + log_err(shtr, "%s: error creating the text reader -- %s.\n", + name, res_to_cstr(res)); + goto error; + } + + for(;;) { + res = txtrdr_read_line(txtrdr); + if(res != RES_OK) { + log_err(shtr, "%s: error reading the line `%lu' -- %s.\n", + name, (unsigned long)txtrdr_get_line_num(txtrdr), res_to_cstr(res)); + goto error; + } + + if(!txtrdr_get_cline(txtrdr)) break; /* No more parsed line */ + res = parse_line(trlst, txtrdr); + if(res != RES_OK) goto error; + } + +exit: + if(txtrdr) txtrdr_ref_put(txtrdr); + *out_lines = trlst; + return res; +error: + if(trlst) { + SHTR(lines_list_ref_put(trlst)); + trlst = NULL; + } + goto exit; +} + +static void +release_lines(ref_T * ref) +{ + struct shtr* shtr = NULL; + struct shtr_lines_list* trlst = CONTAINER_OF + (ref, struct shtr_lines_list, ref); + ASSERT(ref); + shtr = trlst->shtr; + darray_line_release(&trlst->lines); + MEM_RM(shtr->allocator, trlst); + SHTR(ref_put(shtr)); +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +shtr_lines_list_load + (struct shtr* shtr, + const char* path, + struct shtr_lines_list** trlst) +{ + FILE* file = NULL; + res_T res = RES_OK; + + if(!shtr || !path || !trlst) { + res = RES_BAD_ARG; + goto error; + } + + file = fopen(path, "r"); + if(!file) { + log_err(shtr, "%s: error opening file `%s'.\n", FUNC_NAME, path); + res = RES_IO_ERR; + goto error; + } + + res = load_stream(shtr, file, path, trlst); + if(res != RES_OK) goto error; + +exit: + if(file) fclose(file); + return res; +error: + goto exit; +} + +res_T +shtr_lines_list_load_stream + (struct shtr* shtr, + FILE* stream, + const char* stream_name, + struct shtr_lines_list** trlst) +{ + if(!shtr || !stream || !trlst) return RES_BAD_ARG; + return load_stream + (shtr, stream, stream_name ? stream_name : "<stream>", trlst); +} + +res_T +shtr_lines_list_ref_get(struct shtr_lines_list* trlst) +{ + if(!trlst) return RES_BAD_ARG; + ref_get(&trlst->ref); + return RES_OK; +} + +res_T +shtr_lines_list_ref_put(struct shtr_lines_list* trlst) +{ + if(!trlst) return RES_BAD_ARG; + ref_put(&trlst->ref, release_lines); + return RES_OK; +} + +res_T +shtr_lines_list_get_size + (const struct shtr_lines_list* trlst, + size_t* nlines) +{ + if(!trlst || !nlines) return RES_BAD_ARG; + *nlines = darray_line_size_get(&trlst->lines); + return RES_OK; +} + +res_T +shtr_lines_list_get + (const struct shtr_lines_list* trlst, + const struct shtr_line* lines_list[]) +{ + if(!trlst || !lines_list) return RES_BAD_ARG; + *lines_list = darray_line_cdata_get(&trlst->lines); + return RES_OK; +} diff --git a/src/shtr_transitions_list.c b/src/shtr_transitions_list.c @@ -1,325 +0,0 @@ -/* Copyright (C) 2022 CNRS - LMD - * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) - * Copyright (C) 2022 Université Paul Sabatier - IRIT - * Copyright (C) 2022 Université Paul Sabatier - Laplace - * - * 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 SHTR_TRANSITIONS_H -#define SHTR_TRANSITIONS_H - -#include "shtr.h" -#include "shtr_c.h" -#include "shtr_log.h" -#include "shtr_param.h" - -#include <rsys/cstr.h> -#include <rsys/dynamic_array.h> -#include <rsys/text_reader.h> - -/* Generate the dynamic array of trlst */ -#define DARRAY_NAME transition -#define DARRAY_DATA struct shtr_transition -#include <rsys/dynamic_array.h> - -struct shtr_transitions_list { - /* List of trlst */ - struct darray_transition transitions; - - struct shtr* shtr; - ref_T ref; -}; - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static res_T -create_transitions_list - (struct shtr* shtr, - struct shtr_transitions_list** out_transitions) -{ - struct shtr_transitions_list* trlst = NULL; - res_T res = RES_OK; - ASSERT(shtr && out_transitions); - - trlst = MEM_CALLOC(shtr->allocator, 1, sizeof(*trlst)); - if(!trlst) { - log_err(shtr, "Could not allocate the trlst data structure.\n"); - res = RES_MEM_ERR; - goto error; - } - ref_init(&trlst->ref); - SHTR(ref_get(shtr)); - trlst->shtr = shtr; - darray_transition_init(shtr->allocator, &trlst->transitions); - -exit: - *out_transitions = trlst; - return res; -error: - goto exit; -} - -static res_T -parse_transition(struct shtr_transitions_list* trlst, struct txtrdr* txtrdr) -{ - struct shtr_transition tr = SHTR_TRANSITION_NULL; - struct param_desc param = PARAM_DESC_NULL; - struct shtr* shtr = NULL; - char* line = NULL; - char* str = NULL; - char* end = NULL; - char backup; - int molecule_id; - int isotope_id_local; - res_T res = RES_OK; - - ASSERT(trlst && txtrdr); - - line = txtrdr_get_line(txtrdr); - ASSERT(line); - - shtr = trlst->shtr; - param.path = txtrdr_get_name(txtrdr); - param.line = txtrdr_get_line_num(txtrdr); - - str = end = line; - backup = str[0]; - #define NEXT(Size) { \ - *end = backup; \ - str = end; \ - end = str+(Size); \ - backup = *end; \ - *end = '\0'; \ - } (void)0 - #define PARSE(Var, Size, Type, Name, Low, Upp, LowIncl, UppIncl) { \ - NEXT(Size); \ - param.name = (Name); \ - param.low = (Low); \ - param.upp = (Upp); \ - param.is_low_incl = (LowIncl); \ - param.is_upp_incl = (UppIncl); \ - res = parse_param_##Type(shtr, str, &param, Var); \ - if(res != RES_OK) goto error; \ - } (void)0 - - PARSE(&molecule_id, 2, int, "molecule identifier", 0,99,1,1); - tr.molecule_id = (int32_t)molecule_id; - - PARSE(&isotope_id_local, 1, int, "isotope local identifier", 0,9,1,1); - tr.isotope_id_local = (int32_t) - (isotope_id_local == 0 ? 9 : (isotope_id_local - 1)); - - PARSE(&tr.wavenumber, 12, double, "central wavenumber", 0,INF,0,1); - PARSE(&tr.intensity, 10, double, "reference intensity", 0,INF,0,1); - - NEXT(10); /* Skip the Enstein coef */ - - PARSE(&tr.gamma_air, 5, double, "air broadening half-width", 0,INF,1,1); - PARSE(&tr.gamma_self, 5, double, "self broadening half-width", 0,INF,1,1); - - /* Handle unavailable lower state energy */ - PARSE(&tr.lower_state_energy, 10, double, "lower state energy",-INF,INF,1,1); - if(tr.lower_state_energy == -1) { - log_warn(shtr, - "%s:%lu: the lower state energy is unavailable for this line, so it is " - "ignored.\n", param.path, param.line); - goto exit; /* Skip the transition */ - } - /* Check the domain validity */ - if(tr.lower_state_energy < 0) { - log_err(shtr, - "%s:%lu: invalid lower state energy %g. It must be in [0, INF].\n", - param.path, param.line, tr.lower_state_energy); - res = RES_BAD_ARG; - goto error; - } - - PARSE(&tr.n_air, 4, double, "temperature-dependent exponent",-INF,INF,1,1); - PARSE(&tr.delta_air, 8, double, "air-pressure wavenumber shift", -INF,INF,1,1); - - /* Skip the remaining values */ - - #undef NEXT - #undef PARSE - - /* Check the size of the remaining data to ensure that there is at least the - * expected number of bytes wrt the HITRAN fileformat */ - *end = backup; - str = end; - if(strlen(str) != 93) { - log_err(trlst->shtr, "%s:%lu: missing data after delta air.\n", - param.path, (unsigned long)param.line); - res = RES_BAD_ARG; - goto error; - } - - res = darray_transition_push_back(&trlst->transitions, &tr); - if(res != RES_OK) { - log_err(trlst->shtr, - "%s:%lu: error storing the transition -- %s.\n", - param.path, (unsigned long)param.line, res_to_cstr(res)); - goto error; - } - -exit: - return res; -error: - goto exit; -} - -static res_T -load_stream - (struct shtr* shtr, - FILE* stream, - const char* name, - struct shtr_transitions_list** out_transitions) -{ - struct shtr_transitions_list* trlst = NULL; - struct txtrdr* txtrdr = NULL; - res_T res = RES_OK; - ASSERT(shtr && stream && name && out_transitions); - - res = create_transitions_list(shtr, &trlst); - if(res != RES_OK) goto error; - - res = txtrdr_stream(trlst->shtr->allocator, stream, name, - 0/*No comment char*/, &txtrdr); - if(res != RES_OK) { - log_err(shtr, "%s: error creating the text reader -- %s.\n", - name, res_to_cstr(res)); - goto error; - } - - for(;;) { - res = txtrdr_read_line(txtrdr); - if(res != RES_OK) { - log_err(shtr, "%s: error reading the line `%lu' -- %s.\n", - name, (unsigned long)txtrdr_get_line_num(txtrdr), res_to_cstr(res)); - goto error; - } - - if(!txtrdr_get_cline(txtrdr)) break; /* No more parsed line */ - res = parse_transition(trlst, txtrdr); - if(res != RES_OK) goto error; - } - -exit: - if(txtrdr) txtrdr_ref_put(txtrdr); - *out_transitions = trlst; - return res; -error: - if(trlst) { - SHTR(transitions_list_ref_put(trlst)); - trlst = NULL; - } - goto exit; -} - -static void -release_transitions(ref_T * ref) -{ - struct shtr* shtr = NULL; - struct shtr_transitions_list* trlst = CONTAINER_OF - (ref, struct shtr_transitions_list, ref); - ASSERT(ref); - shtr = trlst->shtr; - darray_transition_release(&trlst->transitions); - MEM_RM(shtr->allocator, trlst); - SHTR(ref_put(shtr)); -} - -/******************************************************************************* - * Exported functions - ******************************************************************************/ -res_T -shtr_transitions_list_load - (struct shtr* shtr, - const char* path, - struct shtr_transitions_list** trlst) -{ - FILE* file = NULL; - res_T res = RES_OK; - - if(!shtr || !path || !trlst) { - res = RES_BAD_ARG; - goto error; - } - - file = fopen(path, "r"); - if(!file) { - log_err(shtr, "%s: error opening file `%s'.\n", FUNC_NAME, path); - res = RES_IO_ERR; - goto error; - } - - res = load_stream(shtr, file, path, trlst); - if(res != RES_OK) goto error; - -exit: - if(file) fclose(file); - return res; -error: - goto exit; -} - -res_T -shtr_transitions_list_load_stream - (struct shtr* shtr, - FILE* stream, - const char* stream_name, - struct shtr_transitions_list** trlst) -{ - if(!shtr || !stream || !trlst) return RES_BAD_ARG; - return load_stream - (shtr, stream, stream_name ? stream_name : "<stream>", trlst); -} - -res_T -shtr_transitions_list_ref_get(struct shtr_transitions_list* trlst) -{ - if(!trlst) return RES_BAD_ARG; - ref_get(&trlst->ref); - return RES_OK; -} - -res_T -shtr_transitions_list_ref_put(struct shtr_transitions_list* trlst) -{ - if(!trlst) return RES_BAD_ARG; - ref_put(&trlst->ref, release_transitions); - return RES_OK; -} - -res_T -shtr_transitions_list_get_size - (const struct shtr_transitions_list* trlst, - size_t* ntransitions) -{ - if(!trlst || !ntransitions) return RES_BAD_ARG; - *ntransitions = darray_transition_size_get(&trlst->transitions); - return RES_OK; -} - -res_T -shtr_transitions_list_get - (const struct shtr_transitions_list* trlst, - const struct shtr_transition* transitions_list[]) -{ - if(!trlst || !transitions_list) return RES_BAD_ARG; - *transitions_list = darray_transition_cdata_get(&trlst->transitions); - return RES_OK; -} - -#endif /* SHTR_TRANSITIONS_H */ diff --git a/src/test_shtr_lines.c b/src/test_shtr_lines.c @@ -0,0 +1,265 @@ +/* Copyright (C) 2022 CNRS - LMD + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * Copyright (C) 2022 Université Paul Sabatier - IRIT + * Copyright (C) 2022 Université Paul Sabatier - Laplace + * + * 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 "shtr.h" + +#include <rsys/clock_time.h> +#include <rsys/mem_allocator.h> +#include <rsys/math.h> + +#include <string.h> + +static void +print_lines + (FILE* fp, + const struct shtr_line* lines, + const size_t nlines) +{ + size_t i; + + CHK(fp && (!nlines || lines)); + FOR_EACH(i, 0, nlines) { + fprintf(fp, + "%2d%1d%12.6f%10.3e 0.000E-00.%04d%5.3f%10.4f%4.2f%8.6f" + " 0 0 0" /* Global upper quanta */ + " 0 0 0" /* Global upper quanta */ + " 5 5 0 " /* Local upper quanta */ + " 5 5 1 " /* Local lower quanta */ + "562220" /* Error indices */ + "5041 7833348" /* References */ + " " /* Line mixing flag */ + " 66.0" /* g' */ + " 66.0" /* g'' */ + "\n", + lines[i].molecule_id, + lines[i].isotope_id_local == 9 ? 0 : lines[i].isotope_id_local+1, + lines[i].wavenumber, + lines[i].intensity, + (int)(lines[i].gamma_air*10000+0.5/*round*/), + lines[i].gamma_self, + lines[i].lower_state_energy, + lines[i].n_air, + lines[i].delta_air); + } +} + +static int +line_eq + (const struct shtr_line* tr0, + const struct shtr_line* tr1) +{ + CHK(tr0 && tr1); + return tr0->wavenumber == tr1->wavenumber + && tr0->intensity == tr1->intensity + && tr0->gamma_air == tr1->gamma_air + && tr0->gamma_self == tr1->gamma_self + && tr0->lower_state_energy == tr1->lower_state_energy + && tr0->n_air == tr1->n_air + && tr0->delta_air == tr1->delta_air + && tr0->molecule_id == tr1->molecule_id + && tr0->isotope_id_local == tr1->isotope_id_local; +} + +static void +test_load(struct shtr* shtr) +{ + const struct shtr_line lines[] = { + {0.000134, 2.672E-38, 0.0533, 0.410, 608.4727, 0.79, 0.000060, 1, 4}, + {0.000379, 1.055E-39, 0.0418, 0.329,1747.9686, 0.79, 0.000110, 1, 5}, + {0.000448, 5.560E-38, 0.0490, 0.364,1093.0269, 0.79, 0.000060, 1, 4}, + {0.000686, 1.633E-36, 0.0578, 0.394, 701.1162, 0.79, 0.000180, 1, 4}, + {0.000726, 6.613E-33, 0.0695, 0.428, 402.3295, 0.79, 0.000240, 1, 3} + }; + const size_t nlines = + sizeof(lines) / sizeof(struct shtr_line); + + struct shtr_lines_list* trs = NULL; + const struct shtr_line* trs_list = NULL; + const char* filename = "test_lines.txt"; + FILE* fp = NULL; + size_t i, n; + + CHK(fp = fopen(filename, "w+")); + print_lines(fp, lines, nlines); + rewind(fp); + + CHK(shtr_lines_list_load_stream(NULL, fp, NULL, &trs) == RES_BAD_ARG); + CHK(shtr_lines_list_load_stream(shtr, NULL, NULL, &trs) == RES_BAD_ARG); + CHK(shtr_lines_list_load_stream(shtr, fp, NULL, NULL) == RES_BAD_ARG); + CHK(shtr_lines_list_load_stream(shtr, fp, NULL, &trs) == RES_OK); + + CHK(shtr_lines_list_get_size(NULL, &n) == RES_BAD_ARG); + CHK(shtr_lines_list_get_size(trs, NULL) == RES_BAD_ARG); + CHK(shtr_lines_list_get_size(trs, &n) == RES_OK); + CHK(n == nlines); + + CHK(shtr_lines_list_get(NULL, &trs_list) == RES_BAD_ARG); + CHK(shtr_lines_list_get(trs, NULL) == RES_BAD_ARG); + CHK(shtr_lines_list_get(trs, &trs_list) == RES_OK); + FOR_EACH(i, 0, n) CHK(line_eq(trs_list+i, lines+i)); + + CHK(shtr_lines_list_ref_get(NULL) == RES_BAD_ARG); + CHK(shtr_lines_list_ref_get(trs) == RES_OK); + CHK(shtr_lines_list_ref_put(NULL) == RES_BAD_ARG); + CHK(shtr_lines_list_ref_put(trs) == RES_OK); + CHK(shtr_lines_list_ref_put(trs) == RES_OK); + + CHK(fclose(fp) == 0); + + CHK(shtr_lines_list_load(NULL, filename, &trs) == RES_BAD_ARG); + CHK(shtr_lines_list_load(shtr, NULL, &trs) == RES_BAD_ARG); + CHK(shtr_lines_list_load(shtr, filename, NULL) == RES_BAD_ARG); + CHK(shtr_lines_list_load(shtr, filename, &trs) == RES_OK); + + CHK(shtr_lines_list_get_size(trs, &n) == RES_OK); + CHK(n == nlines); + + CHK(shtr_lines_list_get(trs, &trs_list) == RES_OK); + FOR_EACH(i, 0, n) CHK(line_eq(trs_list+i, lines+i)); + + CHK(shtr_lines_list_ref_put(trs) == RES_OK); +} + +static void +test_line + (struct shtr* shtr, const struct shtr_line* ln, const res_T res) +{ + struct shtr_lines_list* trs = NULL; + FILE* fp = NULL; + + CHK(fp = tmpfile()); + print_lines(fp, ln, 1); + rewind(fp); + CHK(shtr_lines_list_load_stream(shtr, fp, NULL, &trs) == res); + CHK(fclose(fp) == 0); + + if(res == RES_OK) CHK(shtr_lines_list_ref_put(trs) == RES_OK); +} + +static void +test_load_failures(struct shtr* shtr) +{ + const struct shtr_line tr_ref = { + 0.000134, 2.672E-38, 0.0533, 0.410, 608.4727, 0.79, 0.000060, 1, 4, + }; + struct shtr_line ln; + + /* Check that the reference line is valid */ + test_line(shtr, &tr_ref, RES_OK); + + /* Invalid wavenumber */ + ln = tr_ref; ln.wavenumber = 0; + test_line(shtr, &ln, RES_BAD_ARG); + + /* Invalid intensity */ + ln = tr_ref; ln.intensity = 0; + test_line(shtr, &ln, RES_BAD_ARG); + + /* Invalid gamma air */ + ln = tr_ref; ln.gamma_air = -1; + test_line(shtr, &ln, RES_BAD_ARG); + + /* Invalid gamma self */ + ln = tr_ref; ln.gamma_self = -1; + test_line(shtr, &ln, RES_BAD_ARG); + + /* Unavailable lower state energy */ + ln = tr_ref; ln.lower_state_energy = -1; + test_line(shtr, &ln, RES_OK); + + /* Invalid lower state energy */ + ln = tr_ref; ln.lower_state_energy = -2; + test_line(shtr, &ln, RES_BAD_ARG); + + /* Invalid molecule id */ + ln = tr_ref; ln.molecule_id = -1; + test_line(shtr, &ln, RES_BAD_ARG); + + /* Bad file formatting */ + ln = tr_ref; ln.molecule_id = 100; + test_line(shtr, &ln, RES_BAD_ARG); + ln = tr_ref; ln.isotope_id_local = 10; + test_line(shtr, &ln, RES_BAD_ARG); +} + +static void +check_line(const struct shtr_line* ln) +{ + /* Check NaN */ + CHK(ln->wavenumber == ln->wavenumber); + CHK(ln->intensity == ln->intensity); + CHK(ln->gamma_air == ln->gamma_air); + CHK(ln->gamma_self == ln->gamma_self); + CHK(ln->lower_state_energy == ln->lower_state_energy); + CHK(ln->n_air == ln->n_air); + CHK(ln->delta_air == ln->delta_air); + + CHK(ln->wavenumber > 0); + CHK(ln->intensity > 0); + CHK(ln->gamma_air >= 0); + CHK(ln->gamma_self >= 0); + CHK(ln->lower_state_energy >= 0); + CHK(ln->molecule_id >= 0 && ln->molecule_id < 100); + CHK(ln->isotope_id_local >= 0 && ln->isotope_id_local <= 9); +} + +static void +test_load_file(struct shtr* shtr, const char* path) +{ + struct shtr_lines_list* trs = NULL; + const struct shtr_line* trs_list = NULL; + size_t i, n; + CHK(path); + printf("Loading `%s'.\n", path); + CHK(shtr_lines_list_load(shtr, path, &trs) == RES_OK); + CHK(shtr_lines_list_get_size(trs, &n) == RES_OK); + printf(" #lines: %lu\n", n); + + CHK(shtr_lines_list_get(trs, &trs_list) == RES_OK); + FOR_EACH(i, 0, n) check_line(trs_list+i); + CHK(shtr_lines_list_ref_put(trs) == RES_OK); +} + +int +main(int argc, char** argv) +{ + struct shtr_create_args args = SHTR_CREATE_ARGS_DEFAULT; + struct shtr* shtr = NULL; + int i; + (void)argc, (void)argv; + + args.verbose = 1; + CHK(shtr_create(&args, &shtr) == RES_OK); + + test_load(shtr); + test_load_failures(shtr); + FOR_EACH(i, 1, argc) { + char buf[64]; + struct time t0, t1; + + time_current(&t0); + test_load_file(shtr, argv[i]); + time_sub(&t0, time_current(&t1), &t0); + time_dump(&t0, TIME_ALL, NULL, buf, sizeof(buf)); + printf("%s loaded in %s\n", argv[i], buf); + } + + CHK(shtr_ref_put(shtr) == RES_OK); + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_shtr_transitions.c b/src/test_shtr_transitions.c @@ -1,265 +0,0 @@ -/* Copyright (C) 2022 CNRS - LMD - * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) - * Copyright (C) 2022 Université Paul Sabatier - IRIT - * Copyright (C) 2022 Université Paul Sabatier - Laplace - * - * 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 "shtr.h" - -#include <rsys/clock_time.h> -#include <rsys/mem_allocator.h> -#include <rsys/math.h> - -#include <string.h> - -static void -print_transitions - (FILE* fp, - const struct shtr_transition* transitions, - const size_t ntransitions) -{ - size_t i; - - CHK(fp && (!ntransitions || transitions)); - FOR_EACH(i, 0, ntransitions) { - fprintf(fp, - "%2d%1d%12.6f%10.3e 0.000E-00.%04d%5.3f%10.4f%4.2f%8.6f" - " 0 0 0" /* Global upper quanta */ - " 0 0 0" /* Global upper quanta */ - " 5 5 0 " /* Local upper quanta */ - " 5 5 1 " /* Local lower quanta */ - "562220" /* Error indices */ - "5041 7833348" /* References */ - " " /* Line mixing flag */ - " 66.0" /* g' */ - " 66.0" /* g'' */ - "\n", - transitions[i].molecule_id, - transitions[i].isotope_id_local == 9 ? 0 : transitions[i].isotope_id_local+1, - transitions[i].wavenumber, - transitions[i].intensity, - (int)(transitions[i].gamma_air*10000+0.5/*round*/), - transitions[i].gamma_self, - transitions[i].lower_state_energy, - transitions[i].n_air, - transitions[i].delta_air); - } -} - -static int -transition_eq - (const struct shtr_transition* tr0, - const struct shtr_transition* tr1) -{ - CHK(tr0 && tr1); - return tr0->wavenumber == tr1->wavenumber - && tr0->intensity == tr1->intensity - && tr0->gamma_air == tr1->gamma_air - && tr0->gamma_self == tr1->gamma_self - && tr0->lower_state_energy == tr1->lower_state_energy - && tr0->n_air == tr1->n_air - && tr0->delta_air == tr1->delta_air - && tr0->molecule_id == tr1->molecule_id - && tr0->isotope_id_local == tr1->isotope_id_local; -} - -static void -test_load(struct shtr* shtr) -{ - const struct shtr_transition transitions[] = { - {0.000134, 2.672E-38, 0.0533, 0.410, 608.4727, 0.79, 0.000060, 1, 4}, - {0.000379, 1.055E-39, 0.0418, 0.329,1747.9686, 0.79, 0.000110, 1, 5}, - {0.000448, 5.560E-38, 0.0490, 0.364,1093.0269, 0.79, 0.000060, 1, 4}, - {0.000686, 1.633E-36, 0.0578, 0.394, 701.1162, 0.79, 0.000180, 1, 4}, - {0.000726, 6.613E-33, 0.0695, 0.428, 402.3295, 0.79, 0.000240, 1, 3} - }; - const size_t ntransitions = - sizeof(transitions) / sizeof(struct shtr_transition); - - struct shtr_transitions_list* trs = NULL; - const struct shtr_transition* trs_list = NULL; - const char* filename = "test_transitions.txt"; - FILE* fp = NULL; - size_t i, n; - - CHK(fp = fopen(filename, "w+")); - print_transitions(fp, transitions, ntransitions); - rewind(fp); - - CHK(shtr_transitions_list_load_stream(NULL, fp, NULL, &trs) == RES_BAD_ARG); - CHK(shtr_transitions_list_load_stream(shtr, NULL, NULL, &trs) == RES_BAD_ARG); - CHK(shtr_transitions_list_load_stream(shtr, fp, NULL, NULL) == RES_BAD_ARG); - CHK(shtr_transitions_list_load_stream(shtr, fp, NULL, &trs) == RES_OK); - - CHK(shtr_transitions_list_get_size(NULL, &n) == RES_BAD_ARG); - CHK(shtr_transitions_list_get_size(trs, NULL) == RES_BAD_ARG); - CHK(shtr_transitions_list_get_size(trs, &n) == RES_OK); - CHK(n == ntransitions); - - CHK(shtr_transitions_list_get(NULL, &trs_list) == RES_BAD_ARG); - CHK(shtr_transitions_list_get(trs, NULL) == RES_BAD_ARG); - CHK(shtr_transitions_list_get(trs, &trs_list) == RES_OK); - FOR_EACH(i, 0, n) CHK(transition_eq(trs_list+i, transitions+i)); - - CHK(shtr_transitions_list_ref_get(NULL) == RES_BAD_ARG); - CHK(shtr_transitions_list_ref_get(trs) == RES_OK); - CHK(shtr_transitions_list_ref_put(NULL) == RES_BAD_ARG); - CHK(shtr_transitions_list_ref_put(trs) == RES_OK); - CHK(shtr_transitions_list_ref_put(trs) == RES_OK); - - CHK(fclose(fp) == 0); - - CHK(shtr_transitions_list_load(NULL, filename, &trs) == RES_BAD_ARG); - CHK(shtr_transitions_list_load(shtr, NULL, &trs) == RES_BAD_ARG); - CHK(shtr_transitions_list_load(shtr, filename, NULL) == RES_BAD_ARG); - CHK(shtr_transitions_list_load(shtr, filename, &trs) == RES_OK); - - CHK(shtr_transitions_list_get_size(trs, &n) == RES_OK); - CHK(n == ntransitions); - - CHK(shtr_transitions_list_get(trs, &trs_list) == RES_OK); - FOR_EACH(i, 0, n) CHK(transition_eq(trs_list+i, transitions+i)); - - CHK(shtr_transitions_list_ref_put(trs) == RES_OK); -} - -static void -test_transition - (struct shtr* shtr, const struct shtr_transition* tr, const res_T res) -{ - struct shtr_transitions_list* trs = NULL; - FILE* fp = NULL; - - CHK(fp = tmpfile()); - print_transitions(fp, tr, 1); - rewind(fp); - CHK(shtr_transitions_list_load_stream(shtr, fp, NULL, &trs) == res); - CHK(fclose(fp) == 0); - - if(res == RES_OK) CHK(shtr_transitions_list_ref_put(trs) == RES_OK); -} - -static void -test_load_failures(struct shtr* shtr) -{ - const struct shtr_transition tr_ref = { - 0.000134, 2.672E-38, 0.0533, 0.410, 608.4727, 0.79, 0.000060, 1, 4, - }; - struct shtr_transition tr; - - /* Check that the reference transition is valid */ - test_transition(shtr, &tr_ref, RES_OK); - - /* Invalid wavenumber */ - tr = tr_ref; tr.wavenumber = 0; - test_transition(shtr, &tr, RES_BAD_ARG); - - /* Invalid intensity */ - tr = tr_ref; tr.intensity = 0; - test_transition(shtr, &tr, RES_BAD_ARG); - - /* Invalid gamma air */ - tr = tr_ref; tr.gamma_air = -1; - test_transition(shtr, &tr, RES_BAD_ARG); - - /* Invalid gamma self */ - tr = tr_ref; tr.gamma_self = -1; - test_transition(shtr, &tr, RES_BAD_ARG); - - /* Unavailable lower state energy */ - tr = tr_ref; tr.lower_state_energy = -1; - test_transition(shtr, &tr, RES_OK); - - /* Invalid lower state energy */ - tr = tr_ref; tr.lower_state_energy = -2; - test_transition(shtr, &tr, RES_BAD_ARG); - - /* Invalid molecule id */ - tr = tr_ref; tr.molecule_id = -1; - test_transition(shtr, &tr, RES_BAD_ARG); - - /* Bad file formatting */ - tr = tr_ref; tr.molecule_id = 100; - test_transition(shtr, &tr, RES_BAD_ARG); - tr = tr_ref; tr.isotope_id_local = 10; - test_transition(shtr, &tr, RES_BAD_ARG); -} - -static void -check_transition(const struct shtr_transition* tr) -{ - /* Check NaN */ - CHK(tr->wavenumber == tr->wavenumber); - CHK(tr->intensity == tr->intensity); - CHK(tr->gamma_air == tr->gamma_air); - CHK(tr->gamma_self == tr->gamma_self); - CHK(tr->lower_state_energy == tr->lower_state_energy); - CHK(tr->n_air == tr->n_air); - CHK(tr->delta_air == tr->delta_air); - - CHK(tr->wavenumber > 0); - CHK(tr->intensity > 0); - CHK(tr->gamma_air >= 0); - CHK(tr->gamma_self >= 0); - CHK(tr->lower_state_energy >= 0); - CHK(tr->molecule_id >= 0 && tr->molecule_id < 100); - CHK(tr->isotope_id_local >= 0 && tr->isotope_id_local <= 9); -} - -static void -test_load_file(struct shtr* shtr, const char* path) -{ - struct shtr_transitions_list* trs = NULL; - const struct shtr_transition* trs_list = NULL; - size_t i, n; - CHK(path); - printf("Loading `%s'.\n", path); - CHK(shtr_transitions_list_load(shtr, path, &trs) == RES_OK); - CHK(shtr_transitions_list_get_size(trs, &n) == RES_OK); - printf(" #transitions: %lu\n", n); - - CHK(shtr_transitions_list_get(trs, &trs_list) == RES_OK); - FOR_EACH(i, 0, n) check_transition(trs_list+i); - CHK(shtr_transitions_list_ref_put(trs) == RES_OK); -} - -int -main(int argc, char** argv) -{ - struct shtr_create_args args = SHTR_CREATE_ARGS_DEFAULT; - struct shtr* shtr = NULL; - int i; - (void)argc, (void)argv; - - args.verbose = 1; - CHK(shtr_create(&args, &shtr) == RES_OK); - - test_load(shtr); - test_load_failures(shtr); - FOR_EACH(i, 1, argc) { - char buf[64]; - struct time t0, t1; - - time_current(&t0); - test_load_file(shtr, argv[i]); - time_sub(&t0, time_current(&t1), &t0); - time_dump(&t0, TIME_ALL, NULL, buf, sizeof(buf)); - printf("%s loaded in %s\n", argv[i], buf); - } - - CHK(shtr_ref_put(shtr) == RES_OK); - CHK(mem_allocated_size() == 0); - return 0; -}