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 6007c4608df05992724886d74e24091e4ef7af00
parent 13fe40ce8bff5113cb072a3cb60322644413edea
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue, 15 Feb 2022 12:19:45 +0100

Change shitran prefix in shtr

Diffstat:
Mcmake/CMakeLists.txt | 74+++++++++++++++++++++++++++++++++++++-------------------------------------
Dsrc/shitran.c | 101-------------------------------------------------------------------------------
Dsrc/shitran.h | 209-------------------------------------------------------------------------------
Dsrc/shitran_c.h | 35-----------------------------------
Dsrc/shitran_isotope_metadata.c | 632-------------------------------------------------------------------------------
Dsrc/shitran_log.c | 127-------------------------------------------------------------------------------
Dsrc/shitran_log.h | 73-------------------------------------------------------------------------
Dsrc/shitran_param.c | 81-------------------------------------------------------------------------------
Dsrc/shitran_param.h | 54------------------------------------------------------
Dsrc/shitran_transitions.c | 308-------------------------------------------------------------------------------
Asrc/shtr.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shtr.h | 209+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shtr_c.h | 35+++++++++++++++++++++++++++++++++++
Asrc/shtr_isotope_metadata.c | 632+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shtr_log.c | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shtr_log.h | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shtr_param.c | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shtr_param.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shtr_transitions.c | 308+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/test_shitran.c | 74--------------------------------------------------------------------------
Dsrc/test_shitran_isotope_metadata.c | 394-------------------------------------------------------------------------------
Dsrc/test_shitran_transitions.c | 258-------------------------------------------------------------------------------
Asrc/test_shtr.c | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_shtr_isotope_metadata.c | 394+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_shtr_transitions.c | 258+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
25 files changed, 2383 insertions(+), 2383 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -17,10 +17,10 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. cmake_minimum_required(VERSION 3.1) -project(shitran C) +project(shtr C) enable_testing() -set(SHITRAN_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) +set(SHTR_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) option(NO_TEST "Do not build tests" OFF) ################################################################################ @@ -43,44 +43,44 @@ set(VERSION_MINOR 0) set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) -set(SHITRAN_FILES_SRC - shitran.c - shitran_log.c - shitran_isotope_metadata.c - shitran_transitions.c - shitran_param.c) -set(SHITRAN_FILES_INC - shitran_c.h - shitran_log.h) -set(SHITRAN_FILES_INC_API - shitran.h) - -set(SHITRAN_FILES_DOC COPYING README.md) - -# Prepend each file in the `SHITRAN_FILES_<SRC|INC>' list by `SHITRAN_SOURCE_DIR' -rcmake_prepend_path(SHITRAN_FILES_SRC ${SHITRAN_SOURCE_DIR}) -rcmake_prepend_path(SHITRAN_FILES_INC ${SHITRAN_SOURCE_DIR}) -rcmake_prepend_path(SHITRAN_FILES_INC_API ${SHITRAN_SOURCE_DIR}) -rcmake_prepend_path(SHITRAN_FILES_DOC ${PROJECT_SOURCE_DIR}/../) - -add_library(shitran SHARED - ${SHITRAN_FILES_SRC} ${SHITRAN_FILES_INC} ${SHITRAN_FILES_INC_API}) -target_link_libraries(shitran RSys) - -set_target_properties(shitran PROPERTIES - DEFINE_SYMBOL SHITRAN_SHARED_BUILD +set(SHTR_FILES_SRC + shtr.c + shtr_log.c + shtr_isotope_metadata.c + shtr_transitions.c + shtr_param.c) +set(SHTR_FILES_INC + shtr_c.h + shtr_log.h) +set(SHTR_FILES_INC_API + shtr.h) + +set(SHTR_FILES_DOC COPYING README.md) + +# Prepend each file in the `SHTR_FILES_<SRC|INC>' list by `SHTR_SOURCE_DIR' +rcmake_prepend_path(SHTR_FILES_SRC ${SHTR_SOURCE_DIR}) +rcmake_prepend_path(SHTR_FILES_INC ${SHTR_SOURCE_DIR}) +rcmake_prepend_path(SHTR_FILES_INC_API ${SHTR_SOURCE_DIR}) +rcmake_prepend_path(SHTR_FILES_DOC ${PROJECT_SOURCE_DIR}/../) + +add_library(shtr SHARED + ${SHTR_FILES_SRC} ${SHTR_FILES_INC} ${SHTR_FILES_INC_API}) +target_link_libraries(shtr RSys) + +set_target_properties(shtr PROPERTIES + DEFINE_SYMBOL SHTR_SHARED_BUILD VERSION ${VERSION} SOVERSION ${VERSION_MAJOR}) -rcmake_setup_devel(shitran StarHITRAN ${VERSION} star/shitran_version.h) +rcmake_setup_devel(shtr StarHITRAN ${VERSION} star/shtr_version.h) ################################################################################ # Add tests ################################################################################ if(NOT NO_TEST) function(build_test _name) - add_executable(${_name} ${SHITRAN_SOURCE_DIR}/${_name}.c) - target_link_libraries(${_name} shitran RSys ${ARGN}) + add_executable(${_name} ${SHTR_SOURCE_DIR}/${_name}.c) + target_link_libraries(${_name} shtr RSys ${ARGN}) endfunction() function(new_test _name) @@ -88,18 +88,18 @@ if(NOT NO_TEST) add_test(${_name} ${_name}) endfunction() - new_test(test_shitran) - new_test(test_shitran_isotope_metadata) - new_test(test_shitran_transitions) + new_test(test_shtr) + new_test(test_shtr_isotope_metadata) + new_test(test_shtr_transitions) endif() ################################################################################ # Define output & install directories ################################################################################ -install(TARGETS shitran +install(TARGETS shtr ARCHIVE DESTINATION bin LIBRARY DESTINATION lib RUNTIME DESTINATION bin) -install(FILES ${SHITRAN_FILES_INC_API} DESTINATION include/star) -install(FILES ${SHITRAN_FILES_DOC} DESTINATION share/doc/star-hitran) +install(FILES ${SHTR_FILES_INC_API} DESTINATION include/star) +install(FILES ${SHTR_FILES_DOC} DESTINATION share/doc/star-hitran) diff --git a/src/shitran.c b/src/shitran.c @@ -1,101 +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 "shitran.h" -#include "shitran_c.h" -#include "shitran_log.h" - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static INLINE res_T -check_shitran_create_args(const struct shitran_create_args* args) -{ - return args ? RES_OK : RES_BAD_ARG; -} - -static void -release_shitran(ref_T* ref) -{ - struct shitran* shitran = CONTAINER_OF(ref, struct shitran, ref); - ASSERT(ref); - if(shitran->logger == &shitran->logger__) logger_release(&shitran->logger__); - MEM_RM(shitran->allocator, shitran); -} - -/******************************************************************************* - * Exported functions - ******************************************************************************/ -res_T -shitran_create - (const struct shitran_create_args* args, - struct shitran** out_shitran) -{ - struct mem_allocator* allocator = NULL; - struct shitran* shitran = NULL; - res_T res = RES_OK; - - if(!out_shitran) { res = RES_BAD_ARG; goto error; } - res = check_shitran_create_args(args); - if(res != RES_OK) goto error; - - allocator = args->allocator ? args->allocator : &mem_default_allocator; - shitran = MEM_CALLOC(allocator, 1, sizeof(*shitran)); - if(!shitran) { - #define ERR_STR "Could not allocate the Star-HITRAN data structure.\n" - if(args->logger) { - logger_print(args->logger, LOG_ERROR, ERR_STR); - } else { - fprintf(stderr, MSG_ERROR_PREFIX ERR_STR); - } - #undef ERR_STR - res = RES_MEM_ERR; - goto error; - } - ref_init(&shitran->ref); - shitran->allocator = allocator; - shitran->verbose = args->verbose; - if(args->logger) { - shitran->logger = args->logger; - } else { - setup_log_default(shitran); - } - -exit: - if(out_shitran) *out_shitran = shitran; - return res; -error: - if(shitran) { SHITRAN(ref_put(shitran)); shitran = NULL; } - goto exit; -} - -res_T -shitran_ref_get(struct shitran* shitran) -{ - if(!shitran) return RES_BAD_ARG; - ref_get(&shitran->ref); - return RES_OK; -} - -res_T -shitran_ref_put(struct shitran* shitran) -{ - if(!shitran) return RES_BAD_ARG; - ref_put(&shitran->ref, release_shitran); - return RES_OK; -} diff --git a/src/shitran.h b/src/shitran.h @@ -1,209 +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 SHITRAN_H -#define SHITRAN_H - -#include <rsys/rsys.h> - -/* Library symbol management */ -#if defined(SHITRAN_SHARED_BUILD) /* Build shared library */ - #define SHITRAN_API extern EXPORT_SYM -#elif defined(SHITRAN_STATIC) /* Use/build static library */ - #define SHITRAN_API extern LOCAL_SYM -#else - #define SHITRAN_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 */ -#ifndef NDEBUG - #define SHITRAN(Func) ASSERT(shitran_ ## Func == RES_OK) -#else - #define SHITRAN(Func) shitran_ ## Func -#endif - -struct shitran_create_args { - struct logger* logger; /* May be NULL <=> default logger */ - struct mem_allocator* allocator; /* NULL <=> use default allocator */ - int verbose; /* Verbosity level */ -}; -#define SHITRAN_CREATE_ARGS_DEFAULT__ {NULL, NULL, 0} -static const struct shitran_create_args SHITRAN_CREATE_ARGS_DEFAULT = - SHITRAN_CREATE_ARGS_DEFAULT__; - -struct shitran_isotope { - double abundance; /* in ]0, 1] */ - double Q296K; /* Partition function at Tref = 296K */ - double molar_mass; /* In g */ - - /* Local idx of the molecule to which the isotope belongs */ - size_t molecule_id_local; - - int gj; /* State independent degeneracy factor */ - int id; /* Identifier of the isotope <=> Global index */ -}; -#define SHITRAN_ISOTOPE_NULL__ {0,0,0,0,0,-1} -static const struct shitran_isotope SHITRAN_ISOTOPE_NULL = - SHITRAN_ISOTOPE_NULL__; - -struct shitran_molecule { - const char* name; - size_t nisotopes; /* Number of isotopes */ - const struct shitran_isotope* isotopes; - int id; /* Unique identifier */ -}; -#define SHITRAN_MOLECULE_NULL__ {NULL, 0, NULL, -1} -static const struct shitran_molecule SHITRAN_MOLECULE_NULL = - SHITRAN_MOLECULE_NULL__; - -#define SHITRAN_MOLECULE_IS_NULL(Molecule) \ - ((Molecule)->id == SHITRAN_MOLECULE_NULL.id) - -struct shitran_transition { - 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] */ - double gamma_self; /* Self broadening half-width [cm^-1.atm^-1] */ - double lower_state_energy; /* [cm^-1] */ - double n_air; /* Temperature-dependant exponent */ - double delta_air; /* Air-pressure wavenumber shift [cm^-1.atm^-1] */ - - int32_t molecule_id; - - /* The value of the following isotopic index is _not_ the value of the - * isotopic index read from the HITRAN file. The original value is in [0, 9] - * with 0 actually meaning 10. Thus, once decoded, the index is located in - * [1, 10]. The next member variable simply stores this index but decremented - * by one in order to make it compatible with C indexeing. As a result, it - * can be used directly to index the 'isotopes' array of a 'shitran_molecule' - * data structure loaded from an isotope metadata file */ - int32_t isotope_id_local; -}; -#define SHITRAN_TRANSITION_NULL__ {0,0,0,0,0,0,0,-1,-1} -static const struct shitran_transition SHITRAN_TRANSITION_NULL = - SHITRAN_TRANSITION_NULL__; - -/* Forward declarations of opaque data structures */ -struct shitran; -struct shitran_isotope_metadata; -struct shitran_transitions; - -BEGIN_DECLS - -/******************************************************************************* - * Device API - ******************************************************************************/ -SHITRAN_API res_T -shitran_create - (const struct shitran_create_args* args, - struct shitran** shitran); - -SHITRAN_API res_T -shitran_ref_get - (struct shitran* shitran); - -SHITRAN_API res_T -shitran_ref_put - (struct shitran* shitran); - -/******************************************************************************* - * Isotope metadata API - ******************************************************************************/ -SHITRAN_API res_T -shitran_isotope_metadata_load - (struct shitran* shitran, - const char* path, - struct shitran_isotope_metadata** metadata); - -SHITRAN_API res_T -shitran_isotope_metadata_load_stream - (struct shitran* shitran, - FILE* stream, - const char* stream_name, /* NULL <=> use default stream name */ - struct shitran_isotope_metadata** metadata); - -SHITRAN_API res_T -shitran_isotope_metadata_ref_get - (struct shitran_isotope_metadata* metadata); - -SHITRAN_API res_T -shitran_isotope_metadata_ref_put - (struct shitran_isotope_metadata* metadata); - -SHITRAN_API res_T -shitran_isotope_metadata_get_molecules_count - (const struct shitran_isotope_metadata* metadata, - size_t* nmolecules); - -SHITRAN_API res_T -shitran_isotope_metadata_get_isotopes_count - (const struct shitran_isotope_metadata* metadata, - size_t* nisotopes); - -SHITRAN_API res_T -shitran_isotope_metadata_get_molecule - (const struct shitran_isotope_metadata* metadata, - const size_t imolecule, /* Local index of the molecule in [0, molecules_count[ */ - struct shitran_molecule* molecule); - -/* `molecule' is set to SHITRAN_MOLECULE_NULL if `molecule_id' is not found */ -SHITRAN_API res_T -shitran_isotope_metadata_find_molecule - (struct shitran_isotope_metadata* metadata, - const int molecule_id, /* Unique identifier of the molecule <=> Global index */ - struct shitran_molecule* molecule); - -/******************************************************************************* - * Transitions API - ******************************************************************************/ -SHITRAN_API res_T -shitran_transitions_load - (struct shitran* shitran, - const char* path, - struct shitran_transitions** transitions); - -SHITRAN_API res_T -shitran_transitions_load_stream - (struct shitran* shitran, - FILE* stream, - const char* stream_name, /* NULL <=> use default stream name */ - struct shitran_transitions** transitions); - -SHITRAN_API res_T -shitran_transitions_ref_get - (struct shitran_transitions* transitions); - -SHITRAN_API res_T -shitran_transitions_ref_put - (struct shitran_transitions* transitions); - -SHITRAN_API res_T -shitran_transitions_get_count - (const struct shitran_transitions* transitions, - size_t* ntransitions); - -SHITRAN_API res_T -shitran_transitions_get - (const struct shitran_transitions* transitions, - const struct shitran_transition* transitions_list[]); - -END_DECLS - -#endif /* SHITRAN_H */ diff --git a/src/shitran_c.h b/src/shitran_c.h @@ -1,35 +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 SHITRAN_C_H -#define SHITRAN_C_H - -#include <rsys/logger.h> -#include <rsys/ref_count.h> - -struct mem_allocator; - -struct shitran { - struct mem_allocator* allocator; - struct logger* logger; - struct logger logger__; /* Default logger */ - int verbose; - ref_T ref; -}; - -#endif /* SHITRAN_C_H */ diff --git a/src/shitran_isotope_metadata.c b/src/shitran_isotope_metadata.c @@ -1,632 +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/>. */ - -#define _POSIX_C_SOURCE 200112L /* strtok_r support */ - -#include "shitran.h" -#include "shitran_c.h" -#include "shitran_log.h" -#include "shitran_param.h" - -#include <rsys/cstr.h> -#include <rsys/dynamic_array.h> -#include <rsys/hash_table.h> -#include <rsys/ref_count.h> -#include <rsys/str.h> -#include <rsys/text_reader.h> - -#include <ctype.h> -#include <string.h> - -/* Generate the dynamic array of isotopes */ -#define DARRAY_NAME isotope -#define DARRAY_DATA struct shitran_isotope -#include <rsys/dynamic_array.h> - -struct molecule { - struct str name; - size_t isotopes_range[2]; /* Range of the [1st and last[ isotopes */ - int id; /* Unique identifier of the molecule */ -}; -#define MOLECULE_IS_VALID(Molecule) ((Molecule)->id >= 0) - -static INLINE void -molecule_clear(struct molecule* molecule) -{ - ASSERT(molecule); - molecule->isotopes_range[0] = SIZE_MAX; - molecule->isotopes_range[1] = 0; - molecule->id = -1; -} - -static INLINE void -molecule_init(struct mem_allocator* allocator, struct molecule* molecule) -{ - str_init(allocator, &molecule->name); - molecule_clear(molecule); -} - -static INLINE void -molecule_release(struct molecule* molecule) -{ - str_release(&molecule->name); -} - -static INLINE res_T -molecule_copy(struct molecule* dst, const struct molecule* src) -{ - dst->isotopes_range[0] = src->isotopes_range[0]; - dst->isotopes_range[1] = src->isotopes_range[1]; - dst->id = src->id; - return str_copy(&dst->name, &src->name); -} - -static INLINE res_T -molecule_copy_and_release(struct molecule* dst, struct molecule* src) -{ - dst->isotopes_range[0] = src->isotopes_range[0]; - dst->isotopes_range[1] = src->isotopes_range[1]; - dst->id = src->id; - return str_copy_and_release(&dst->name, &src->name); -} - -/* Generate the dynamic array of molecules */ -#define DARRAY_NAME molecule -#define DARRAY_DATA struct molecule -#define DARRAY_FUNCTOR_INIT molecule_init -#define DARRAY_FUNCTOR_RELEASE molecule_release -#define DARRAY_FUNCTOR_COPY molecule_copy -#define DARRAY_FUNCTOR_COPY_AND_RELEASE molecule_copy_and_release -#include <rsys/dynamic_array.h> - -/* Generate the hash table that map a global identifier to its local index */ -#define HTABLE_NAME molid2idx -#define HTABLE_KEY int /* Unique identifier */ -#define HTABLE_DATA size_t /* Index of the corresponding registered data */ -#include <rsys/hash_table.h> - -struct shitran_isotope_metadata { - /* List of molecules and isotopes */ - struct darray_molecule molecules; - struct darray_isotope isotopes; - - /* Map the global identifier of a molecule to its correspond local index into - * the dynamic aray into which it is registered */ - struct htable_molid2idx molid2idx; - - struct shitran* shitran; - ref_T ref; -}; - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static res_T -create_isotope_metadata - (struct shitran* shitran, - struct shitran_isotope_metadata** out_isotopes) -{ - struct shitran_isotope_metadata* metadata = NULL; - res_T res = RES_OK; - ASSERT(shitran && out_isotopes); - - metadata = MEM_CALLOC(shitran->allocator, 1, sizeof(*metadata)); - if(!metadata) { - log_err(shitran, - "Could not allocate the isotope metadata data structure.\n"); - res = RES_MEM_ERR; - goto error; - } - ref_init(&metadata->ref); - SHITRAN(ref_get(shitran)); - metadata->shitran = shitran; - darray_molecule_init(shitran->allocator, &metadata->molecules); - darray_isotope_init(shitran->allocator, &metadata->isotopes); - htable_molid2idx_init(shitran->allocator, &metadata->molid2idx); - -exit: - *out_isotopes = metadata; - return res; -error: - goto exit; -} - -static res_T -flush_molecule - (struct shitran_isotope_metadata* metadata, - struct molecule* molecule, /* Currently parsed molecule */ - struct txtrdr* txtrdr) -{ - size_t ientry = SIZE_MAX; - size_t* pimolecule = NULL; - res_T res = RES_OK; - ASSERT(metadata && molecule && MOLECULE_IS_VALID(molecule)); - - /* Fetch _exclusive_ upper bound */ - molecule->isotopes_range[1] = - darray_isotope_size_get(&metadata->isotopes); - if(molecule->isotopes_range[0] >= molecule->isotopes_range[1]) { - log_warn(metadata->shitran, - "%s:%lu: the %s molecule does not have any isotope.\n", - txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), - str_cget(&molecule->name)); - } - - /* Fetch the index where the molecule is going to be store */ - ientry = darray_molecule_size_get(&metadata->molecules); - - /* Store the molecule */ - res = darray_molecule_push_back(&metadata->molecules, molecule); - if(res != RES_OK) { - log_err(metadata->shitran, - "%s: error storing the %s molecule -- %s.\n", - txtrdr_get_name(txtrdr), str_cget(&molecule->name), res_to_cstr(res)); - goto error; - } - - /* Register the molecule */ - pimolecule = htable_molid2idx_find(&metadata->molid2idx, &molecule->id); - if(pimolecule) { - const struct molecule* molecule2 = NULL; - molecule2 = darray_molecule_cdata_get(&metadata->molecules) + *pimolecule; - log_err(metadata->shitran, - "%s: cannot register the %s molecule. " - "The %s molecule has the same identifier %i.\n", - txtrdr_get_name(txtrdr), - str_cget(&molecule->name), - str_cget(&molecule2->name), - molecule->id); - res = RES_OK; - goto error; - } - res = htable_molid2idx_set(&metadata->molid2idx, &molecule->id, &ientry); - if(res != RES_OK) { - log_err(metadata->shitran, - "%s: error registering the %s molecule -- %s.\n", - txtrdr_get_name(txtrdr), str_cget(&molecule->name), res_to_cstr(res)); - goto error; - } - - molecule_clear(molecule); - -exit: - return res; -error: - if(ientry != SIZE_MAX) darray_molecule_resize(&metadata->molecules, ientry); - htable_molid2idx_erase(&metadata->molid2idx, &molecule->id); - goto exit; -} - -static res_T -parse_molecule - (struct shitran_isotope_metadata* metadata, - struct molecule* molecule, - struct txtrdr* txtrdr) -{ - char* name = NULL; - char* id = NULL; - char* tk = NULL; - char* tk_ctx = NULL; - size_t len; - res_T res = RES_OK; - ASSERT(molecule && txtrdr); - - name = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); - id = strtok_r(NULL, " \t", &tk_ctx); - - if(!name) { - log_err(metadata->shitran, "%s:%lu: molecule name is missing.\n", - txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); - res = RES_BAD_ARG; - goto error; - } - - res = str_set(&molecule->name, name); - if(res != RES_OK) { - log_err(metadata->shitran, - "%s:%lu: error seting the molecule name `%s' -- %s.\n", - txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), - name, res_to_cstr(res)); - goto error; - } - - len = strlen(id); - if(!id || !len || id[0] != '(' || id[len-1] != ')') { - log_err(metadata->shitran, - "%s:%lu: invalid definition of the molecule identifier.\n", - txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); - res = RES_BAD_ARG; - goto error; - } - - id[len-1] = '\0'; /* Rm trailing parenthesis */ - res = cstr_to_int(id+1/*Rm leading parenthesis*/, &molecule->id); - if(res != RES_OK || !MOLECULE_IS_VALID(molecule)) { - id[len-1] = ')'; /* Re-add the trailing parenthesis */ - log_err(metadata->shitran, "%s:%lu: invalid molecule identifier `%s'.\n", - txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), id); - res = RES_BAD_ARG; - goto error; - } - - tk = strtok_r(NULL, " \t", &tk_ctx); - if(tk) { - log_warn(metadata->shitran, "%s:%lu: unexpected text `%s'.\n", - txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); - } - - molecule->isotopes_range[0] = darray_isotope_size_get(&metadata->isotopes); - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_isotope - (struct shitran_isotope_metadata* metadata, - struct txtrdr* txtrdr) -{ - struct shitran_isotope isotope = SHITRAN_ISOTOPE_NULL; - struct param_desc param_desc = PARAM_DESC_NULL; - struct shitran* shitran = NULL; - char* tk = NULL; - char* tk_ctx = NULL; - size_t local_id = SIZE_MAX; - res_T res = RES_OK; - ASSERT(metadata && txtrdr); - - shitran = metadata->shitran; - param_desc.path = txtrdr_get_name(txtrdr); - param_desc.line = txtrdr_get_line_num(txtrdr); - - /* Fetch the index of the molecule to which the isotope belongs */ - isotope.molecule_id_local = darray_molecule_size_get(&metadata->molecules); - - tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); - param_desc.name = "isotope id"; - param_desc.low = 0; - param_desc.upp = INT_MAX; - param_desc.is_low_incl = 1; - param_desc.is_upp_incl = 1; - res = parse_param_int(shitran, tk, &param_desc, &isotope.id); - if(res != RES_OK) goto error; - - tk = strtok_r(NULL, " \t", &tk_ctx); - param_desc.name = "isotope abundance"; - param_desc.low = 0; - param_desc.upp = 1; - param_desc.is_low_incl = 0; - param_desc.is_upp_incl = 1; - res = parse_param_double(shitran, tk, &param_desc, &isotope.abundance); - if(res != RES_OK) goto error; - - tk = strtok_r(NULL, " \t", &tk_ctx); - param_desc.name = "isotope Q(296K)"; - param_desc.low = 0; - param_desc.upp = INF; - param_desc.is_low_incl = 0; - param_desc.is_upp_incl = 1; - res = parse_param_double(shitran, tk, &param_desc, &isotope.Q296K); - if(res != RES_OK) goto error; - - tk = strtok_r(NULL, " \t", &tk_ctx); - param_desc.name = "isotope state independant degeneracy factor"; - param_desc.low = -INT_MAX; - param_desc.upp = INT_MAX; - param_desc.is_low_incl = 1; - param_desc.is_upp_incl = 1; - res = parse_param_int(shitran, tk, &param_desc, &isotope.gj); - if(res != RES_OK) goto error; - - tk = strtok_r(NULL, " \t", &tk_ctx), - param_desc.name = "isotope molar mass"; - param_desc.low = 0; - param_desc.upp = INF; - param_desc.is_low_incl = 0; - param_desc.is_upp_incl = 1; - res = parse_param_double(shitran, tk, &param_desc, &isotope.molar_mass); - if(res != RES_OK) goto error; - - local_id = darray_isotope_size_get(&metadata->isotopes); - - /* Store the isotope */ - res = darray_isotope_push_back(&metadata->isotopes, &isotope); - if(res != RES_OK) { - log_err(shitran, "%s:%lu: error storing the isotope %d -- %s.\n", - param_desc.path, param_desc.line, isotope.id, res_to_cstr(res)); - res = RES_OK; - goto error; - } - -exit: - return res; -error: - if(local_id != SIZE_MAX) darray_isotope_resize(&metadata->isotopes, local_id); - goto exit; -} - -static res_T -parse_line - (struct shitran_isotope_metadata* metadata, - struct molecule* molecule, /* Currently parsed molecule */ - struct txtrdr* txtrdr) -{ - const char* line = NULL; - size_t i; - res_T res = RES_OK; - ASSERT(metadata && molecule && txtrdr); - - line = txtrdr_get_cline(txtrdr); - ASSERT(line); - i = strspn(line, " \t"); - ASSERT(i < strlen(line)); - - if(isalpha(line[i])) { - if(MOLECULE_IS_VALID(molecule)) { - res = flush_molecule(metadata, molecule, txtrdr); - if(res != RES_OK) goto error; - } - res = parse_molecule(metadata, molecule, txtrdr); - if(res != RES_OK) goto error; - } else { - if(!MOLECULE_IS_VALID(molecule)) { - log_err(metadata->shitran, "%s:%lu: missing a molecule definition.\n", - txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); - res = RES_BAD_ARG; - goto error; - } - res = parse_isotope(metadata, txtrdr); - if(res != RES_OK) goto error; - } - -exit: - return res; -error: - goto exit; -} - -static res_T -load_stream - (struct shitran* shitran, - FILE* stream, - const char* name, - struct shitran_isotope_metadata** out_isotopes) -{ - struct molecule molecule; /* Current molecule */ - struct shitran_isotope_metadata* metadata = NULL; - struct txtrdr* txtrdr = NULL; - res_T res = RES_OK; - ASSERT(shitran && stream && name && out_isotopes); - - molecule_init(shitran->allocator, &molecule); - - res = create_isotope_metadata(shitran, &metadata); - if(res != RES_OK) goto error; - - res = txtrdr_stream(metadata->shitran->allocator, stream, name, - 0/*No comment char*/, &txtrdr); - if(res != RES_OK) { - log_err(shitran, "%s: error creating the text reader -- %s.\n", - name, res_to_cstr(res)); - goto error; - } - - #define READ_LINE { \ - res = txtrdr_read_line(txtrdr); \ - if(res != RES_OK) { \ - log_err(shitran, "%s: error reading the line `%lu' -- %s.\n", \ - name, (unsigned long)txtrdr_get_line_num(txtrdr), res_to_cstr(res)); \ - goto error; \ - } \ - } (void)0 - - /* Skip the 1st line that is a comment line*/ - READ_LINE; - if(!txtrdr_get_cline(txtrdr)) goto exit; - - for(;;) { - READ_LINE; - - if(!txtrdr_get_cline(txtrdr)) break; /* No more parsed line */ - res = parse_line(metadata, &molecule, txtrdr); - if(res != RES_OK) goto error; - } - #undef READ_LINE - - if(MOLECULE_IS_VALID(&molecule)) { - res = flush_molecule(metadata, &molecule, txtrdr); - if(res != RES_OK) goto error; - } - -exit: - if(txtrdr) txtrdr_ref_put(txtrdr); - *out_isotopes = metadata; - molecule_release(&molecule); - return res; -error: - if(metadata) { - SHITRAN(isotope_metadata_ref_put(metadata)); - metadata = NULL; - } - goto exit; -} - -static void -release_isotope_metadata(ref_T* ref) -{ - struct shitran* shitran = NULL; - struct shitran_isotope_metadata* metadata = CONTAINER_OF - (ref, struct shitran_isotope_metadata, ref); - ASSERT(ref); - shitran = metadata->shitran; - darray_molecule_release(&metadata->molecules); - darray_isotope_release(&metadata->isotopes); - htable_molid2idx_release(&metadata->molid2idx); - MEM_RM(shitran->allocator, metadata); - SHITRAN(ref_put(shitran)); -} - -/******************************************************************************* - * Exported functions - ******************************************************************************/ -res_T -shitran_isotope_metadata_load - (struct shitran* shitran, - const char* path, - struct shitran_isotope_metadata** metadata) -{ - FILE* file = NULL; - res_T res = RES_OK; - - if(!shitran || !path || !metadata) { - res = RES_BAD_ARG; - goto error; - } - - file = fopen(path, "r"); - if(!file) { - log_err(shitran, "%s: error opening file `%s'.\n", FUNC_NAME, path); - res = RES_IO_ERR; - goto error; - } - - res = load_stream(shitran, file, path, metadata); - if(res != RES_OK) goto error; - -exit: - if(file) fclose(file); - return res; -error: - goto exit; -} - -res_T -shitran_isotope_metadata_load_stream - (struct shitran* shitran, - FILE* stream, - const char* stream_name, - struct shitran_isotope_metadata** metadata) -{ - if(!shitran || !stream || !metadata) return RES_BAD_ARG; - return load_stream - (shitran, stream, stream_name ? stream_name : "<stream>", metadata); -} - -res_T -shitran_isotope_metadata_ref_get - (struct shitran_isotope_metadata* metadata) -{ - if(!metadata) return RES_BAD_ARG; - ref_get(&metadata->ref); - return RES_OK; -} - -res_T -shitran_isotope_metadata_ref_put - (struct shitran_isotope_metadata* metadata) -{ - if(!metadata) return RES_BAD_ARG; - ref_put(&metadata->ref, release_isotope_metadata); - return RES_OK; -} - -res_T -shitran_isotope_metadata_get_molecules_count - (const struct shitran_isotope_metadata* metadata, - size_t* nmolecules) -{ - if(!metadata || !nmolecules) return RES_BAD_ARG; - *nmolecules = darray_molecule_size_get(&metadata->molecules); - return RES_OK; -} - -res_T -shitran_isotope_metadata_get_isotopes_count - (const struct shitran_isotope_metadata* metadata, - size_t* nisotopes) -{ - if(!metadata || !nisotopes) return RES_BAD_ARG; - *nisotopes = darray_isotope_size_get(&metadata->isotopes); - return RES_OK; -} - -res_T -shitran_isotope_metadata_get_molecule - (const struct shitran_isotope_metadata* metadata, - const size_t imolecule, - struct shitran_molecule* out_molecule) -{ - const struct molecule* molecule = NULL; - res_T res = RES_OK; - - if(!metadata || !out_molecule) { - res = RES_BAD_ARG; - goto error; - } - if(imolecule >= darray_molecule_size_get(&metadata->molecules)) { - log_err(metadata->shitran, "%s: invalid molecule index %lu.\n", - FUNC_NAME, (unsigned long)imolecule); - res = RES_BAD_ARG; - goto error; - } - - molecule = darray_molecule_cdata_get(&metadata->molecules) + imolecule; - out_molecule->name = str_cget(&molecule->name); - out_molecule->id = molecule->id; - out_molecule->nisotopes = - molecule->isotopes_range[1] - molecule->isotopes_range[0]; - out_molecule->isotopes = - darray_isotope_cdata_get(&metadata->isotopes) + molecule->isotopes_range[0]; - -exit: - return res; -error: - goto exit; -} - -res_T -shitran_isotope_metadata_find_molecule - (struct shitran_isotope_metadata* metadata, - const int molecule_id, - struct shitran_molecule* out_molecule) -{ - size_t* pimolecule = NULL; - res_T res = RES_OK; - - if(!metadata || !out_molecule) { - res = RES_BAD_ARG; - goto error; - } - - pimolecule = htable_molid2idx_find(&metadata->molid2idx, &molecule_id); - if(!pimolecule) { - *out_molecule = SHITRAN_MOLECULE_NULL; - } else { - res = shitran_isotope_metadata_get_molecule - (metadata, *pimolecule, out_molecule); - if(res != RES_OK) goto error; - } - -exit: - return res; -error: - goto exit; -} - diff --git a/src/shitran_log.c b/src/shitran_log.c @@ -1,127 +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 "shitran_c.h" -#include "shitran_log.h" - -#include <rsys/cstr.h> -#include <rsys/logger.h> - -#include <stdarg.h> - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static INLINE void -log_msg - (const struct shitran* shitran, - const enum log_type stream, - const char* msg, - va_list vargs) -{ - ASSERT(shitran && msg); - if(shitran->verbose) { - res_T res; (void)res; - res = logger_vprint(shitran->logger, stream, msg, vargs); - ASSERT(res == RES_OK); - } -} - -static void -print_info(const char* msg, void* ctx) -{ - (void)ctx; - fprintf(stderr, MSG_INFO_PREFIX"%s", msg); -} - -static void -print_err(const char* msg, void* ctx) -{ - (void)ctx; - fprintf(stderr, MSG_ERROR_PREFIX"%s", msg); -} - -static void -print_warn(const char* msg, void* ctx) -{ - (void)ctx; - fprintf(stderr, MSG_WARNING_PREFIX"%s", msg); -} - -/******************************************************************************* - * Local functions - ******************************************************************************/ -res_T -setup_log_default(struct shitran* shitran) -{ - res_T res = RES_OK; - ASSERT(shitran); - - res = logger_init(shitran->allocator, &shitran->logger__); - if(res != RES_OK) { - if(shitran->verbose) { - fprintf(stderr, - MSG_ERROR_PREFIX - "Could not setup the default logger for the Star-HITRAN library -- %s.\n", - res_to_cstr(res)); - } - goto error; - } - logger_set_stream(&shitran->logger__, LOG_OUTPUT, print_info, NULL); - logger_set_stream(&shitran->logger__, LOG_ERROR, print_err, NULL); - logger_set_stream(&shitran->logger__, LOG_WARNING, print_warn, NULL); - shitran->logger = &shitran->logger__; - -exit: - return res; -error: - goto exit; -} - -void -log_info(const struct shitran* shitran, const char* msg, ...) -{ - va_list vargs_list; - ASSERT(shitran && msg); - - va_start(vargs_list, msg); - log_msg(shitran, LOG_OUTPUT, msg, vargs_list); - va_end(vargs_list); -} - -void -log_err(const struct shitran* shitran, const char* msg, ...) -{ - va_list vargs_list; - ASSERT(shitran && msg); - - va_start(vargs_list, msg); - log_msg(shitran, LOG_ERROR, msg, vargs_list); - va_end(vargs_list); -} - -void -log_warn(const struct shitran* shitran, const char* msg, ...) -{ - va_list vargs_list; - ASSERT(shitran && msg); - - va_start(vargs_list, msg); - log_msg(shitran, LOG_WARNING, msg, vargs_list); - va_end(vargs_list); -} diff --git a/src/shitran_log.h b/src/shitran_log.h @@ -1,73 +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 SHITRAN_LOG_H -#define SHITRAN_LOG_H - -#include <rsys/rsys.h> - -#define MSG_INFO_PREFIX "Star-HITRAN:\x1b[1m\x1b[32minfo\x1b[0m: " -#define MSG_ERROR_PREFIX "Star-HITRAN:\x1b[1m\x1b[31merror\x1b[0m: " -#define MSG_WARNING_PREFIX "Star-HITRAN:\x1b[1m\x1b[33mwarning\x1b[0m: " - -struct shitran; -struct logger; - -extern LOCAL_SYM res_T -setup_log_default - (struct shitran* shitran); - -/* Conditionally log a message on the LOG_OUTPUT stream of the shitran logger, - * with respect to its verbose flag */ -extern LOCAL_SYM void -log_info - (const struct shitran* shitran, - const char* msg, - ...) -#ifdef COMPILER_GCC - __attribute((format(printf, 2, 3))) -#endif -; - -/* Conditionally log a message on the LOG_ERROR stream of the shitran logger, - * with respect to its verbose flag */ -extern LOCAL_SYM void -log_err - (const struct shitran* shitran, - const char* msg, - ...) -#ifdef COMPILER_GCC - __attribute((format(printf, 2, 3))) -#endif -; - -/* Conditionally log a message on the LOG_WARNING stream of the shitran logger, - * with respect to its verbose flag */ -extern LOCAL_SYM void -log_warn - (const struct shitran* shitran, - const char* msg, - ...) -#ifdef COMPILER_GCC - __attribute((format(printf, 2, 3))) -#endif -; - - -#endif /* SHITRAN_LOG_H */ - diff --git a/src/shitran_param.c b/src/shitran_param.c @@ -1,81 +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 "shitran_c.h" -#include "shitran_log.h" -#include "shitran_param.h" - -#include <rsys/cstr.h> - -#define C_FORMAT_double "%g" -#define C_FORMAT_float "%g" -#define C_FORMAT_int "%d" - -/******************************************************************************* - * Local functions - ******************************************************************************/ -#define DEFINE_PARSE_PARAM_FUNCTION(Type) \ - res_T \ - parse_param_##Type \ - (struct shitran* shitran, \ - const char* str, \ - const struct param_desc* desc, \ - Type* out_param) \ - { \ - Type param = 0; \ - res_T res = RES_OK; \ - ASSERT(shitran && desc && out_param); \ - ASSERT(desc->low < desc->upp \ - || (desc->low == desc->upp && desc->is_low_incl && desc->is_upp_incl));\ - \ - if(!str) { \ - log_err(shitran, "%s:%lu: %s is missing.\n", \ - desc->path, (unsigned long)desc->line, desc->name); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - \ - res = cstr_to_##Type(str, &param); \ - if(res != RES_OK) { \ - log_err(shitran, "%s:%lu: invalid %s `%s'.\n", \ - desc->path, (unsigned long)desc->line, desc->name, str); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - \ - if(param < desc->low || (param == desc->low && !desc->is_low_incl) \ - || param > desc->upp || (param == desc->upp && !desc->is_upp_incl)) { \ - log_err(shitran, \ - "%s:%lu: invalid %s `%s'. It must be in " \ - "%c"CONCAT(C_FORMAT_, Type)", "CONCAT(C_FORMAT_, Type)"%c.\n", \ - desc->path, (unsigned long)desc->line, desc->name, str, \ - desc->is_low_incl ? '[' : ']', (Type)desc->low, \ - (Type)desc->upp, desc->is_upp_incl ? ']' : '['); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - \ - exit: \ - *out_param = param; \ - return res; \ - error: \ - goto exit; \ - } -DEFINE_PARSE_PARAM_FUNCTION(int) -DEFINE_PARSE_PARAM_FUNCTION(double) -#undef DEFINE_PARSE_PARAM_FUNCTION diff --git a/src/shitran_param.h b/src/shitran_param.h @@ -1,54 +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 SHITRAN_PARAM_H -#define SHITRAN_PARAM_H - -#include <rsys/rsys.h> - -struct param_desc { - const char* path; /* Path where the param lies */ - const char* name; /* Name of the param */ - size_t line; /* Line number of the param */ - - /* Domain of the param */ - double low, upp; - int is_low_incl; /* Define if the lower bound is inclusive */ - int is_upp_incl; /* Define if the upper bound is inclusive */ -}; -#define PARAM_DESC_NULL__ {NULL, NULL, 0, 0, 0, 0, 0} -static const struct param_desc PARAM_DESC_NULL = PARAM_DESC_NULL__; - -/* Forware declaration */ -struct shitran; - -extern LOCAL_SYM res_T -parse_param_int - (struct shitran* shitran, - const char* str, - const struct param_desc* desc, - int* param); - -extern LOCAL_SYM res_T -parse_param_double - (struct shitran* shitran, - const char* str, - const struct param_desc* desc, - double* param); - -#endif /* SHITRAN_PARAM_H */ diff --git a/src/shitran_transitions.c b/src/shitran_transitions.c @@ -1,308 +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 SHITRAN_TRANSITIONS_H -#define SHITRAN_TRANSITIONS_H - -#include "shitran.h" -#include "shitran_c.h" -#include "shitran_log.h" -#include "shitran_param.h" - -#include <rsys/cstr.h> -#include <rsys/dynamic_array.h> -#include <rsys/text_reader.h> - -/* Generate the dynamic array of transitions */ -#define DARRAY_NAME transition -#define DARRAY_DATA struct shitran_transition -#include <rsys/dynamic_array.h> - -struct shitran_transitions { - /* List of transitions */ - struct darray_transition transitions; - - struct shitran* shitran; - ref_T ref; -}; - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static res_T -create_transitions - (struct shitran* shitran, - struct shitran_transitions** out_transitions) -{ - struct shitran_transitions* transitions = NULL; - res_T res = RES_OK; - ASSERT(shitran && out_transitions); - - transitions = MEM_CALLOC(shitran->allocator, 1, sizeof(*transitions)); - if(!transitions) { - log_err(shitran, "Could not allocate the transitions data structure.\n"); - res = RES_MEM_ERR; - goto error; - } - ref_init(&transitions->ref); - SHITRAN(ref_get(shitran)); - transitions->shitran = shitran; - darray_transition_init(shitran->allocator, &transitions->transitions); - -exit: - *out_transitions = transitions; - return res; -error: - goto exit; -} - -static res_T -parse_transition(struct shitran_transitions* transitions, struct txtrdr* txtrdr) -{ - struct shitran_transition tr = SHITRAN_TRANSITION_NULL; - struct param_desc param = PARAM_DESC_NULL; - struct shitran* shitran = 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(transitions && txtrdr); - - line = txtrdr_get_line(txtrdr); - ASSERT(line); - - shitran = transitions->shitran; - 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(shitran, 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,0,1); - PARSE(&tr.gamma_self, 5, double, "self broadening half-width", 0,INF,0,1); - PARSE(&tr.lower_state_energy, 10, double, "lower state energy", 0,INF,1,1); - PARSE(&tr.n_air, 4, double, "temperature-dependent exponent", 0,INF,0,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(transitions->shitran, "%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(&transitions->transitions, &tr); - if(res != RES_OK) { - log_err(transitions->shitran, - "%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 shitran* shitran, - FILE* stream, - const char* name, - struct shitran_transitions** out_transitions) -{ - struct shitran_transitions* transitions = NULL; - struct txtrdr* txtrdr = NULL; - res_T res = RES_OK; - ASSERT(shitran && stream && name && out_transitions); - - res = create_transitions(shitran, &transitions); - if(res != RES_OK) goto error; - - res = txtrdr_stream(transitions->shitran->allocator, stream, name, - 0/*No comment char*/, &txtrdr); - if(res != RES_OK) { - log_err(shitran, "%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(shitran, "%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(transitions, txtrdr); - if(res != RES_OK) goto error; - } - -exit: - if(txtrdr) txtrdr_ref_put(txtrdr); - *out_transitions = transitions; - return res; -error: - if(transitions) { - SHITRAN(transitions_ref_put(transitions)); - transitions = NULL; - } - goto exit; -} - -static void -release_transitions(ref_T * ref) -{ - struct shitran* shitran = NULL; - struct shitran_transitions* transitions = CONTAINER_OF - (ref, struct shitran_transitions, ref); - ASSERT(ref); - shitran = transitions->shitran; - darray_transition_release(&transitions->transitions); - MEM_RM(shitran->allocator, transitions); - SHITRAN(ref_put(shitran)); -} - -/******************************************************************************* - * Exported functions - ******************************************************************************/ -res_T -shitran_transitions_load - (struct shitran* shitran, - const char* path, - struct shitran_transitions** transitions) -{ - FILE* file = NULL; - res_T res = RES_OK; - - if(!shitran || !path || !transitions) { - res = RES_BAD_ARG; - goto error; - } - - file = fopen(path, "r"); - if(!file) { - log_err(shitran, "%s: error opening file `%s'.\n", FUNC_NAME, path); - res = RES_IO_ERR; - goto error; - } - - res = load_stream(shitran, file, path, transitions); - if(res != RES_OK) goto error; - -exit: - if(file) fclose(file); - return res; -error: - goto exit; -} - -res_T -shitran_transitions_load_stream - (struct shitran* shitran, - FILE* stream, - const char* stream_name, - struct shitran_transitions** transitions) -{ - if(!shitran || !stream || !transitions) return RES_BAD_ARG; - return load_stream - (shitran, stream, stream_name ? stream_name : "<stream>", transitions); -} - -res_T -shitran_transitions_ref_get(struct shitran_transitions* transitions) -{ - if(!transitions) return RES_BAD_ARG; - ref_get(&transitions->ref); - return RES_OK; -} - -res_T -shitran_transitions_ref_put(struct shitran_transitions* transitions) -{ - if(!transitions) return RES_BAD_ARG; - ref_put(&transitions->ref, release_transitions); - return RES_OK; -} - -res_T -shitran_transitions_get_count - (const struct shitran_transitions* transitions, - size_t* ntransitions) -{ - if(!transitions || !ntransitions) return RES_BAD_ARG; - *ntransitions = darray_transition_size_get(&transitions->transitions); - return RES_OK; -} - -res_T -shitran_transitions_get - (const struct shitran_transitions* transitions, - const struct shitran_transition* transitions_list[]) -{ - if(!transitions || !transitions_list) return RES_BAD_ARG; - *transitions_list = darray_transition_cdata_get(&transitions->transitions); - return RES_OK; -} - -#endif /* SHITRAN_TRANSITIONS_H */ diff --git a/src/shtr.c b/src/shtr.c @@ -0,0 +1,101 @@ +/* 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" + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static INLINE res_T +check_shtr_create_args(const struct shtr_create_args* args) +{ + return args ? RES_OK : RES_BAD_ARG; +} + +static void +release_shtr(ref_T* ref) +{ + struct shtr* shtr = CONTAINER_OF(ref, struct shtr, ref); + ASSERT(ref); + if(shtr->logger == &shtr->logger__) logger_release(&shtr->logger__); + MEM_RM(shtr->allocator, shtr); +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +shtr_create + (const struct shtr_create_args* args, + struct shtr** out_shtr) +{ + struct mem_allocator* allocator = NULL; + struct shtr* shtr = NULL; + res_T res = RES_OK; + + if(!out_shtr) { res = RES_BAD_ARG; goto error; } + res = check_shtr_create_args(args); + if(res != RES_OK) goto error; + + allocator = args->allocator ? args->allocator : &mem_default_allocator; + shtr = MEM_CALLOC(allocator, 1, sizeof(*shtr)); + if(!shtr) { + #define ERR_STR "Could not allocate the Star-HITRAN data structure.\n" + if(args->logger) { + logger_print(args->logger, LOG_ERROR, ERR_STR); + } else { + fprintf(stderr, MSG_ERROR_PREFIX ERR_STR); + } + #undef ERR_STR + res = RES_MEM_ERR; + goto error; + } + ref_init(&shtr->ref); + shtr->allocator = allocator; + shtr->verbose = args->verbose; + if(args->logger) { + shtr->logger = args->logger; + } else { + setup_log_default(shtr); + } + +exit: + if(out_shtr) *out_shtr = shtr; + return res; +error: + if(shtr) { SHTR(ref_put(shtr)); shtr = NULL; } + goto exit; +} + +res_T +shtr_ref_get(struct shtr* shtr) +{ + if(!shtr) return RES_BAD_ARG; + ref_get(&shtr->ref); + return RES_OK; +} + +res_T +shtr_ref_put(struct shtr* shtr) +{ + if(!shtr) return RES_BAD_ARG; + ref_put(&shtr->ref, release_shtr); + return RES_OK; +} diff --git a/src/shtr.h b/src/shtr.h @@ -0,0 +1,209 @@ +/* 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_H +#define SHTR_H + +#include <rsys/rsys.h> + +/* Library symbol management */ +#if defined(SHTR_SHARED_BUILD) /* Build shared library */ + #define SHTR_API extern EXPORT_SYM +#elif defined(SHTR_STATIC) /* Use/build static library */ + #define SHTR_API extern LOCAL_SYM +#else + #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 */ +#ifndef NDEBUG + #define SHTR(Func) ASSERT(shtr_ ## Func == RES_OK) +#else + #define SHTR(Func) shtr_ ## Func +#endif + +struct shtr_create_args { + struct logger* logger; /* May be NULL <=> default logger */ + struct mem_allocator* allocator; /* NULL <=> use default allocator */ + int verbose; /* Verbosity level */ +}; +#define SHTR_CREATE_ARGS_DEFAULT__ {NULL, NULL, 0} +static const struct shtr_create_args SHTR_CREATE_ARGS_DEFAULT = + SHTR_CREATE_ARGS_DEFAULT__; + +struct shtr_isotope { + double abundance; /* in ]0, 1] */ + double Q296K; /* Partition function at Tref = 296K */ + double molar_mass; /* In g */ + + /* Local idx of the molecule to which the isotope belongs */ + size_t molecule_id_local; + + int gj; /* State independent degeneracy factor */ + int id; /* Identifier of the isotope <=> Global index */ +}; +#define SHTR_ISOTOPE_NULL__ {0,0,0,0,0,-1} +static const struct shtr_isotope SHTR_ISOTOPE_NULL = + SHTR_ISOTOPE_NULL__; + +struct shtr_molecule { + const char* name; + size_t nisotopes; /* Number of isotopes */ + const struct shtr_isotope* isotopes; + int id; /* Unique identifier */ +}; +#define SHTR_MOLECULE_NULL__ {NULL, 0, NULL, -1} +static const struct shtr_molecule SHTR_MOLECULE_NULL = + SHTR_MOLECULE_NULL__; + +#define SHTR_MOLECULE_IS_NULL(Molecule) \ + ((Molecule)->id == SHTR_MOLECULE_NULL.id) + +struct shtr_transition { + 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] */ + double gamma_self; /* Self broadening half-width [cm^-1.atm^-1] */ + double lower_state_energy; /* [cm^-1] */ + double n_air; /* Temperature-dependant exponent */ + double delta_air; /* Air-pressure wavenumber shift [cm^-1.atm^-1] */ + + int32_t molecule_id; + + /* The value of the following isotopic index is _not_ the value of the + * isotopic index read from the HITRAN file. The original value is in [0, 9] + * with 0 actually meaning 10. Thus, once decoded, the index is located in + * [1, 10]. The next member variable simply stores this index but decremented + * by one in order to make it compatible with C indexeing. As a result, it + * can be used directly to index the 'isotopes' array of a 'shtr_molecule' + * 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__; + +/* Forward declarations of opaque data structures */ +struct shtr; +struct shtr_isotope_metadata; +struct shtr_transitions; + +BEGIN_DECLS + +/******************************************************************************* + * Device API + ******************************************************************************/ +SHTR_API res_T +shtr_create + (const struct shtr_create_args* args, + struct shtr** shtr); + +SHTR_API res_T +shtr_ref_get + (struct shtr* shtr); + +SHTR_API res_T +shtr_ref_put + (struct shtr* shtr); + +/******************************************************************************* + * Isotope metadata API + ******************************************************************************/ +SHTR_API res_T +shtr_isotope_metadata_load + (struct shtr* shtr, + const char* path, + struct shtr_isotope_metadata** metadata); + +SHTR_API res_T +shtr_isotope_metadata_load_stream + (struct shtr* shtr, + FILE* stream, + const char* stream_name, /* NULL <=> use default stream name */ + struct shtr_isotope_metadata** metadata); + +SHTR_API res_T +shtr_isotope_metadata_ref_get + (struct shtr_isotope_metadata* metadata); + +SHTR_API res_T +shtr_isotope_metadata_ref_put + (struct shtr_isotope_metadata* metadata); + +SHTR_API res_T +shtr_isotope_metadata_get_molecules_count + (const struct shtr_isotope_metadata* metadata, + size_t* nmolecules); + +SHTR_API res_T +shtr_isotope_metadata_get_isotopes_count + (const struct shtr_isotope_metadata* metadata, + size_t* nisotopes); + +SHTR_API res_T +shtr_isotope_metadata_get_molecule + (const struct shtr_isotope_metadata* metadata, + const size_t imolecule, /* Local index of the molecule in [0, molecules_count[ */ + struct shtr_molecule* molecule); + +/* `molecule' is set to SHTR_MOLECULE_NULL if `molecule_id' is not found */ +SHTR_API res_T +shtr_isotope_metadata_find_molecule + (struct shtr_isotope_metadata* metadata, + const int molecule_id, /* Unique identifier of the molecule <=> Global index */ + struct shtr_molecule* molecule); + +/******************************************************************************* + * Transitions API + ******************************************************************************/ +SHTR_API res_T +shtr_transitions_load + (struct shtr* shtr, + const char* path, + struct shtr_transitions** transitions); + +SHTR_API res_T +shtr_transitions_load_stream + (struct shtr* shtr, + FILE* stream, + const char* stream_name, /* NULL <=> use default stream name */ + struct shtr_transitions** transitions); + +SHTR_API res_T +shtr_transitions_ref_get + (struct shtr_transitions* transitions); + +SHTR_API res_T +shtr_transitions_ref_put + (struct shtr_transitions* transitions); + +SHTR_API res_T +shtr_transitions_get_count + (const struct shtr_transitions* transitions, + size_t* ntransitions); + +SHTR_API res_T +shtr_transitions_get + (const struct shtr_transitions* transitions, + const struct shtr_transition* transitions_list[]); + +END_DECLS + +#endif /* SHTR_H */ diff --git a/src/shtr_c.h b/src/shtr_c.h @@ -0,0 +1,35 @@ +/* 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_C_H +#define SHTR_C_H + +#include <rsys/logger.h> +#include <rsys/ref_count.h> + +struct mem_allocator; + +struct shtr { + struct mem_allocator* allocator; + struct logger* logger; + struct logger logger__; /* Default logger */ + int verbose; + ref_T ref; +}; + +#endif /* SHTR_C_H */ diff --git a/src/shtr_isotope_metadata.c b/src/shtr_isotope_metadata.c @@ -0,0 +1,632 @@ +/* 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/>. */ + +#define _POSIX_C_SOURCE 200112L /* strtok_r support */ + +#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/hash_table.h> +#include <rsys/ref_count.h> +#include <rsys/str.h> +#include <rsys/text_reader.h> + +#include <ctype.h> +#include <string.h> + +/* Generate the dynamic array of isotopes */ +#define DARRAY_NAME isotope +#define DARRAY_DATA struct shtr_isotope +#include <rsys/dynamic_array.h> + +struct molecule { + struct str name; + size_t isotopes_range[2]; /* Range of the [1st and last[ isotopes */ + int id; /* Unique identifier of the molecule */ +}; +#define MOLECULE_IS_VALID(Molecule) ((Molecule)->id >= 0) + +static INLINE void +molecule_clear(struct molecule* molecule) +{ + ASSERT(molecule); + molecule->isotopes_range[0] = SIZE_MAX; + molecule->isotopes_range[1] = 0; + molecule->id = -1; +} + +static INLINE void +molecule_init(struct mem_allocator* allocator, struct molecule* molecule) +{ + str_init(allocator, &molecule->name); + molecule_clear(molecule); +} + +static INLINE void +molecule_release(struct molecule* molecule) +{ + str_release(&molecule->name); +} + +static INLINE res_T +molecule_copy(struct molecule* dst, const struct molecule* src) +{ + dst->isotopes_range[0] = src->isotopes_range[0]; + dst->isotopes_range[1] = src->isotopes_range[1]; + dst->id = src->id; + return str_copy(&dst->name, &src->name); +} + +static INLINE res_T +molecule_copy_and_release(struct molecule* dst, struct molecule* src) +{ + dst->isotopes_range[0] = src->isotopes_range[0]; + dst->isotopes_range[1] = src->isotopes_range[1]; + dst->id = src->id; + return str_copy_and_release(&dst->name, &src->name); +} + +/* Generate the dynamic array of molecules */ +#define DARRAY_NAME molecule +#define DARRAY_DATA struct molecule +#define DARRAY_FUNCTOR_INIT molecule_init +#define DARRAY_FUNCTOR_RELEASE molecule_release +#define DARRAY_FUNCTOR_COPY molecule_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE molecule_copy_and_release +#include <rsys/dynamic_array.h> + +/* Generate the hash table that map a global identifier to its local index */ +#define HTABLE_NAME molid2idx +#define HTABLE_KEY int /* Unique identifier */ +#define HTABLE_DATA size_t /* Index of the corresponding registered data */ +#include <rsys/hash_table.h> + +struct shtr_isotope_metadata { + /* List of molecules and isotopes */ + struct darray_molecule molecules; + struct darray_isotope isotopes; + + /* Map the global identifier of a molecule to its correspond local index into + * the dynamic aray into which it is registered */ + struct htable_molid2idx molid2idx; + + struct shtr* shtr; + ref_T ref; +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static res_T +create_isotope_metadata + (struct shtr* shtr, + struct shtr_isotope_metadata** out_isotopes) +{ + struct shtr_isotope_metadata* metadata = NULL; + res_T res = RES_OK; + ASSERT(shtr && out_isotopes); + + metadata = MEM_CALLOC(shtr->allocator, 1, sizeof(*metadata)); + if(!metadata) { + log_err(shtr, + "Could not allocate the isotope metadata data structure.\n"); + res = RES_MEM_ERR; + goto error; + } + ref_init(&metadata->ref); + SHTR(ref_get(shtr)); + metadata->shtr = shtr; + darray_molecule_init(shtr->allocator, &metadata->molecules); + darray_isotope_init(shtr->allocator, &metadata->isotopes); + htable_molid2idx_init(shtr->allocator, &metadata->molid2idx); + +exit: + *out_isotopes = metadata; + return res; +error: + goto exit; +} + +static res_T +flush_molecule + (struct shtr_isotope_metadata* metadata, + struct molecule* molecule, /* Currently parsed molecule */ + struct txtrdr* txtrdr) +{ + size_t ientry = SIZE_MAX; + size_t* pimolecule = NULL; + res_T res = RES_OK; + ASSERT(metadata && molecule && MOLECULE_IS_VALID(molecule)); + + /* Fetch _exclusive_ upper bound */ + molecule->isotopes_range[1] = + darray_isotope_size_get(&metadata->isotopes); + if(molecule->isotopes_range[0] >= molecule->isotopes_range[1]) { + log_warn(metadata->shtr, + "%s:%lu: the %s molecule does not have any isotope.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + str_cget(&molecule->name)); + } + + /* Fetch the index where the molecule is going to be store */ + ientry = darray_molecule_size_get(&metadata->molecules); + + /* Store the molecule */ + res = darray_molecule_push_back(&metadata->molecules, molecule); + if(res != RES_OK) { + log_err(metadata->shtr, + "%s: error storing the %s molecule -- %s.\n", + txtrdr_get_name(txtrdr), str_cget(&molecule->name), res_to_cstr(res)); + goto error; + } + + /* Register the molecule */ + pimolecule = htable_molid2idx_find(&metadata->molid2idx, &molecule->id); + if(pimolecule) { + const struct molecule* molecule2 = NULL; + molecule2 = darray_molecule_cdata_get(&metadata->molecules) + *pimolecule; + log_err(metadata->shtr, + "%s: cannot register the %s molecule. " + "The %s molecule has the same identifier %i.\n", + txtrdr_get_name(txtrdr), + str_cget(&molecule->name), + str_cget(&molecule2->name), + molecule->id); + res = RES_OK; + goto error; + } + res = htable_molid2idx_set(&metadata->molid2idx, &molecule->id, &ientry); + if(res != RES_OK) { + log_err(metadata->shtr, + "%s: error registering the %s molecule -- %s.\n", + txtrdr_get_name(txtrdr), str_cget(&molecule->name), res_to_cstr(res)); + goto error; + } + + molecule_clear(molecule); + +exit: + return res; +error: + if(ientry != SIZE_MAX) darray_molecule_resize(&metadata->molecules, ientry); + htable_molid2idx_erase(&metadata->molid2idx, &molecule->id); + goto exit; +} + +static res_T +parse_molecule + (struct shtr_isotope_metadata* metadata, + struct molecule* molecule, + struct txtrdr* txtrdr) +{ + char* name = NULL; + char* id = NULL; + char* tk = NULL; + char* tk_ctx = NULL; + size_t len; + res_T res = RES_OK; + ASSERT(molecule && txtrdr); + + name = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); + id = strtok_r(NULL, " \t", &tk_ctx); + + if(!name) { + log_err(metadata->shtr, "%s:%lu: molecule name is missing.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + + res = str_set(&molecule->name, name); + if(res != RES_OK) { + log_err(metadata->shtr, + "%s:%lu: error seting the molecule name `%s' -- %s.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + name, res_to_cstr(res)); + goto error; + } + + len = strlen(id); + if(!id || !len || id[0] != '(' || id[len-1] != ')') { + log_err(metadata->shtr, + "%s:%lu: invalid definition of the molecule identifier.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + + id[len-1] = '\0'; /* Rm trailing parenthesis */ + res = cstr_to_int(id+1/*Rm leading parenthesis*/, &molecule->id); + if(res != RES_OK || !MOLECULE_IS_VALID(molecule)) { + id[len-1] = ')'; /* Re-add the trailing parenthesis */ + log_err(metadata->shtr, "%s:%lu: invalid molecule identifier `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), id); + res = RES_BAD_ARG; + goto error; + } + + tk = strtok_r(NULL, " \t", &tk_ctx); + if(tk) { + log_warn(metadata->shtr, "%s:%lu: unexpected text `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + } + + molecule->isotopes_range[0] = darray_isotope_size_get(&metadata->isotopes); + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_isotope + (struct shtr_isotope_metadata* metadata, + struct txtrdr* txtrdr) +{ + struct shtr_isotope isotope = SHTR_ISOTOPE_NULL; + struct param_desc param_desc = PARAM_DESC_NULL; + struct shtr* shtr = NULL; + char* tk = NULL; + char* tk_ctx = NULL; + size_t local_id = SIZE_MAX; + res_T res = RES_OK; + ASSERT(metadata && txtrdr); + + shtr = metadata->shtr; + param_desc.path = txtrdr_get_name(txtrdr); + param_desc.line = txtrdr_get_line_num(txtrdr); + + /* Fetch the index of the molecule to which the isotope belongs */ + isotope.molecule_id_local = darray_molecule_size_get(&metadata->molecules); + + tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); + param_desc.name = "isotope id"; + param_desc.low = 0; + param_desc.upp = INT_MAX; + param_desc.is_low_incl = 1; + param_desc.is_upp_incl = 1; + res = parse_param_int(shtr, tk, &param_desc, &isotope.id); + if(res != RES_OK) goto error; + + tk = strtok_r(NULL, " \t", &tk_ctx); + param_desc.name = "isotope abundance"; + param_desc.low = 0; + param_desc.upp = 1; + param_desc.is_low_incl = 0; + param_desc.is_upp_incl = 1; + res = parse_param_double(shtr, tk, &param_desc, &isotope.abundance); + if(res != RES_OK) goto error; + + tk = strtok_r(NULL, " \t", &tk_ctx); + param_desc.name = "isotope Q(296K)"; + param_desc.low = 0; + param_desc.upp = INF; + param_desc.is_low_incl = 0; + param_desc.is_upp_incl = 1; + res = parse_param_double(shtr, tk, &param_desc, &isotope.Q296K); + if(res != RES_OK) goto error; + + tk = strtok_r(NULL, " \t", &tk_ctx); + param_desc.name = "isotope state independant degeneracy factor"; + param_desc.low = -INT_MAX; + param_desc.upp = INT_MAX; + param_desc.is_low_incl = 1; + param_desc.is_upp_incl = 1; + res = parse_param_int(shtr, tk, &param_desc, &isotope.gj); + if(res != RES_OK) goto error; + + tk = strtok_r(NULL, " \t", &tk_ctx), + param_desc.name = "isotope molar mass"; + param_desc.low = 0; + param_desc.upp = INF; + param_desc.is_low_incl = 0; + param_desc.is_upp_incl = 1; + res = parse_param_double(shtr, tk, &param_desc, &isotope.molar_mass); + if(res != RES_OK) goto error; + + local_id = darray_isotope_size_get(&metadata->isotopes); + + /* Store the isotope */ + res = darray_isotope_push_back(&metadata->isotopes, &isotope); + if(res != RES_OK) { + log_err(shtr, "%s:%lu: error storing the isotope %d -- %s.\n", + param_desc.path, param_desc.line, isotope.id, res_to_cstr(res)); + res = RES_OK; + goto error; + } + +exit: + return res; +error: + if(local_id != SIZE_MAX) darray_isotope_resize(&metadata->isotopes, local_id); + goto exit; +} + +static res_T +parse_line + (struct shtr_isotope_metadata* metadata, + struct molecule* molecule, /* Currently parsed molecule */ + struct txtrdr* txtrdr) +{ + const char* line = NULL; + size_t i; + res_T res = RES_OK; + ASSERT(metadata && molecule && txtrdr); + + line = txtrdr_get_cline(txtrdr); + ASSERT(line); + i = strspn(line, " \t"); + ASSERT(i < strlen(line)); + + if(isalpha(line[i])) { + if(MOLECULE_IS_VALID(molecule)) { + res = flush_molecule(metadata, molecule, txtrdr); + if(res != RES_OK) goto error; + } + res = parse_molecule(metadata, molecule, txtrdr); + if(res != RES_OK) goto error; + } else { + if(!MOLECULE_IS_VALID(molecule)) { + log_err(metadata->shtr, "%s:%lu: missing a molecule definition.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + res = parse_isotope(metadata, txtrdr); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +load_stream + (struct shtr* shtr, + FILE* stream, + const char* name, + struct shtr_isotope_metadata** out_isotopes) +{ + struct molecule molecule; /* Current molecule */ + struct shtr_isotope_metadata* metadata = NULL; + struct txtrdr* txtrdr = NULL; + res_T res = RES_OK; + ASSERT(shtr && stream && name && out_isotopes); + + molecule_init(shtr->allocator, &molecule); + + res = create_isotope_metadata(shtr, &metadata); + if(res != RES_OK) goto error; + + res = txtrdr_stream(metadata->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; + } + + #define READ_LINE { \ + 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; \ + } \ + } (void)0 + + /* Skip the 1st line that is a comment line*/ + READ_LINE; + if(!txtrdr_get_cline(txtrdr)) goto exit; + + for(;;) { + READ_LINE; + + if(!txtrdr_get_cline(txtrdr)) break; /* No more parsed line */ + res = parse_line(metadata, &molecule, txtrdr); + if(res != RES_OK) goto error; + } + #undef READ_LINE + + if(MOLECULE_IS_VALID(&molecule)) { + res = flush_molecule(metadata, &molecule, txtrdr); + if(res != RES_OK) goto error; + } + +exit: + if(txtrdr) txtrdr_ref_put(txtrdr); + *out_isotopes = metadata; + molecule_release(&molecule); + return res; +error: + if(metadata) { + SHTR(isotope_metadata_ref_put(metadata)); + metadata = NULL; + } + goto exit; +} + +static void +release_isotope_metadata(ref_T* ref) +{ + struct shtr* shtr = NULL; + struct shtr_isotope_metadata* metadata = CONTAINER_OF + (ref, struct shtr_isotope_metadata, ref); + ASSERT(ref); + shtr = metadata->shtr; + darray_molecule_release(&metadata->molecules); + darray_isotope_release(&metadata->isotopes); + htable_molid2idx_release(&metadata->molid2idx); + MEM_RM(shtr->allocator, metadata); + SHTR(ref_put(shtr)); +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +shtr_isotope_metadata_load + (struct shtr* shtr, + const char* path, + struct shtr_isotope_metadata** metadata) +{ + FILE* file = NULL; + res_T res = RES_OK; + + if(!shtr || !path || !metadata) { + 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, metadata); + if(res != RES_OK) goto error; + +exit: + if(file) fclose(file); + return res; +error: + goto exit; +} + +res_T +shtr_isotope_metadata_load_stream + (struct shtr* shtr, + FILE* stream, + const char* stream_name, + struct shtr_isotope_metadata** metadata) +{ + if(!shtr || !stream || !metadata) return RES_BAD_ARG; + return load_stream + (shtr, stream, stream_name ? stream_name : "<stream>", metadata); +} + +res_T +shtr_isotope_metadata_ref_get + (struct shtr_isotope_metadata* metadata) +{ + if(!metadata) return RES_BAD_ARG; + ref_get(&metadata->ref); + return RES_OK; +} + +res_T +shtr_isotope_metadata_ref_put + (struct shtr_isotope_metadata* metadata) +{ + if(!metadata) return RES_BAD_ARG; + ref_put(&metadata->ref, release_isotope_metadata); + return RES_OK; +} + +res_T +shtr_isotope_metadata_get_molecules_count + (const struct shtr_isotope_metadata* metadata, + size_t* nmolecules) +{ + if(!metadata || !nmolecules) return RES_BAD_ARG; + *nmolecules = darray_molecule_size_get(&metadata->molecules); + return RES_OK; +} + +res_T +shtr_isotope_metadata_get_isotopes_count + (const struct shtr_isotope_metadata* metadata, + size_t* nisotopes) +{ + if(!metadata || !nisotopes) return RES_BAD_ARG; + *nisotopes = darray_isotope_size_get(&metadata->isotopes); + return RES_OK; +} + +res_T +shtr_isotope_metadata_get_molecule + (const struct shtr_isotope_metadata* metadata, + const size_t imolecule, + struct shtr_molecule* out_molecule) +{ + const struct molecule* molecule = NULL; + res_T res = RES_OK; + + if(!metadata || !out_molecule) { + res = RES_BAD_ARG; + goto error; + } + if(imolecule >= darray_molecule_size_get(&metadata->molecules)) { + log_err(metadata->shtr, "%s: invalid molecule index %lu.\n", + FUNC_NAME, (unsigned long)imolecule); + res = RES_BAD_ARG; + goto error; + } + + molecule = darray_molecule_cdata_get(&metadata->molecules) + imolecule; + out_molecule->name = str_cget(&molecule->name); + out_molecule->id = molecule->id; + out_molecule->nisotopes = + molecule->isotopes_range[1] - molecule->isotopes_range[0]; + out_molecule->isotopes = + darray_isotope_cdata_get(&metadata->isotopes) + molecule->isotopes_range[0]; + +exit: + return res; +error: + goto exit; +} + +res_T +shtr_isotope_metadata_find_molecule + (struct shtr_isotope_metadata* metadata, + const int molecule_id, + struct shtr_molecule* out_molecule) +{ + size_t* pimolecule = NULL; + res_T res = RES_OK; + + if(!metadata || !out_molecule) { + res = RES_BAD_ARG; + goto error; + } + + pimolecule = htable_molid2idx_find(&metadata->molid2idx, &molecule_id); + if(!pimolecule) { + *out_molecule = SHTR_MOLECULE_NULL; + } else { + res = shtr_isotope_metadata_get_molecule + (metadata, *pimolecule, out_molecule); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + goto exit; +} + diff --git a/src/shtr_log.c b/src/shtr_log.c @@ -0,0 +1,127 @@ +/* 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_c.h" +#include "shtr_log.h" + +#include <rsys/cstr.h> +#include <rsys/logger.h> + +#include <stdarg.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static INLINE void +log_msg + (const struct shtr* shtr, + const enum log_type stream, + const char* msg, + va_list vargs) +{ + ASSERT(shtr && msg); + if(shtr->verbose) { + res_T res; (void)res; + res = logger_vprint(shtr->logger, stream, msg, vargs); + ASSERT(res == RES_OK); + } +} + +static void +print_info(const char* msg, void* ctx) +{ + (void)ctx; + fprintf(stderr, MSG_INFO_PREFIX"%s", msg); +} + +static void +print_err(const char* msg, void* ctx) +{ + (void)ctx; + fprintf(stderr, MSG_ERROR_PREFIX"%s", msg); +} + +static void +print_warn(const char* msg, void* ctx) +{ + (void)ctx; + fprintf(stderr, MSG_WARNING_PREFIX"%s", msg); +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +setup_log_default(struct shtr* shtr) +{ + res_T res = RES_OK; + ASSERT(shtr); + + res = logger_init(shtr->allocator, &shtr->logger__); + if(res != RES_OK) { + if(shtr->verbose) { + fprintf(stderr, + MSG_ERROR_PREFIX + "Could not setup the default logger for the Star-HITRAN library -- %s.\n", + res_to_cstr(res)); + } + goto error; + } + logger_set_stream(&shtr->logger__, LOG_OUTPUT, print_info, NULL); + logger_set_stream(&shtr->logger__, LOG_ERROR, print_err, NULL); + logger_set_stream(&shtr->logger__, LOG_WARNING, print_warn, NULL); + shtr->logger = &shtr->logger__; + +exit: + return res; +error: + goto exit; +} + +void +log_info(const struct shtr* shtr, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(shtr && msg); + + va_start(vargs_list, msg); + log_msg(shtr, LOG_OUTPUT, msg, vargs_list); + va_end(vargs_list); +} + +void +log_err(const struct shtr* shtr, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(shtr && msg); + + va_start(vargs_list, msg); + log_msg(shtr, LOG_ERROR, msg, vargs_list); + va_end(vargs_list); +} + +void +log_warn(const struct shtr* shtr, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(shtr && msg); + + va_start(vargs_list, msg); + log_msg(shtr, LOG_WARNING, msg, vargs_list); + va_end(vargs_list); +} diff --git a/src/shtr_log.h b/src/shtr_log.h @@ -0,0 +1,73 @@ +/* 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_LOG_H +#define SHTR_LOG_H + +#include <rsys/rsys.h> + +#define MSG_INFO_PREFIX "Star-HITRAN:\x1b[1m\x1b[32minfo\x1b[0m: " +#define MSG_ERROR_PREFIX "Star-HITRAN:\x1b[1m\x1b[31merror\x1b[0m: " +#define MSG_WARNING_PREFIX "Star-HITRAN:\x1b[1m\x1b[33mwarning\x1b[0m: " + +struct shtr; +struct logger; + +extern LOCAL_SYM res_T +setup_log_default + (struct shtr* shtr); + +/* Conditionally log a message on the LOG_OUTPUT stream of the shtr logger, + * with respect to its verbose flag */ +extern LOCAL_SYM void +log_info + (const struct shtr* shtr, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif +; + +/* Conditionally log a message on the LOG_ERROR stream of the shtr logger, + * with respect to its verbose flag */ +extern LOCAL_SYM void +log_err + (const struct shtr* shtr, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif +; + +/* Conditionally log a message on the LOG_WARNING stream of the shtr logger, + * with respect to its verbose flag */ +extern LOCAL_SYM void +log_warn + (const struct shtr* shtr, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif +; + + +#endif /* SHTR_LOG_H */ + diff --git a/src/shtr_param.c b/src/shtr_param.c @@ -0,0 +1,81 @@ +/* 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_c.h" +#include "shtr_log.h" +#include "shtr_param.h" + +#include <rsys/cstr.h> + +#define C_FORMAT_double "%g" +#define C_FORMAT_float "%g" +#define C_FORMAT_int "%d" + +/******************************************************************************* + * Local functions + ******************************************************************************/ +#define DEFINE_PARSE_PARAM_FUNCTION(Type) \ + res_T \ + parse_param_##Type \ + (struct shtr* shtr, \ + const char* str, \ + const struct param_desc* desc, \ + Type* out_param) \ + { \ + Type param = 0; \ + res_T res = RES_OK; \ + ASSERT(shtr && desc && out_param); \ + ASSERT(desc->low < desc->upp \ + || (desc->low == desc->upp && desc->is_low_incl && desc->is_upp_incl));\ + \ + if(!str) { \ + log_err(shtr, "%s:%lu: %s is missing.\n", \ + desc->path, (unsigned long)desc->line, desc->name); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + \ + res = cstr_to_##Type(str, &param); \ + if(res != RES_OK) { \ + log_err(shtr, "%s:%lu: invalid %s `%s'.\n", \ + desc->path, (unsigned long)desc->line, desc->name, str); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + \ + if(param < desc->low || (param == desc->low && !desc->is_low_incl) \ + || param > desc->upp || (param == desc->upp && !desc->is_upp_incl)) { \ + log_err(shtr, \ + "%s:%lu: invalid %s `%s'. It must be in " \ + "%c"CONCAT(C_FORMAT_, Type)", "CONCAT(C_FORMAT_, Type)"%c.\n", \ + desc->path, (unsigned long)desc->line, desc->name, str, \ + desc->is_low_incl ? '[' : ']', (Type)desc->low, \ + (Type)desc->upp, desc->is_upp_incl ? ']' : '['); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + \ + exit: \ + *out_param = param; \ + return res; \ + error: \ + goto exit; \ + } +DEFINE_PARSE_PARAM_FUNCTION(int) +DEFINE_PARSE_PARAM_FUNCTION(double) +#undef DEFINE_PARSE_PARAM_FUNCTION diff --git a/src/shtr_param.h b/src/shtr_param.h @@ -0,0 +1,54 @@ +/* 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_PARAM_H +#define SHTR_PARAM_H + +#include <rsys/rsys.h> + +struct param_desc { + const char* path; /* Path where the param lies */ + const char* name; /* Name of the param */ + size_t line; /* Line number of the param */ + + /* Domain of the param */ + double low, upp; + int is_low_incl; /* Define if the lower bound is inclusive */ + int is_upp_incl; /* Define if the upper bound is inclusive */ +}; +#define PARAM_DESC_NULL__ {NULL, NULL, 0, 0, 0, 0, 0} +static const struct param_desc PARAM_DESC_NULL = PARAM_DESC_NULL__; + +/* Forware declaration */ +struct shtr; + +extern LOCAL_SYM res_T +parse_param_int + (struct shtr* shtr, + const char* str, + const struct param_desc* desc, + int* param); + +extern LOCAL_SYM res_T +parse_param_double + (struct shtr* shtr, + const char* str, + const struct param_desc* desc, + double* param); + +#endif /* SHTR_PARAM_H */ diff --git a/src/shtr_transitions.c b/src/shtr_transitions.c @@ -0,0 +1,308 @@ +/* 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 transitions */ +#define DARRAY_NAME transition +#define DARRAY_DATA struct shtr_transition +#include <rsys/dynamic_array.h> + +struct shtr_transitions { + /* List of transitions */ + struct darray_transition transitions; + + struct shtr* shtr; + ref_T ref; +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static res_T +create_transitions + (struct shtr* shtr, + struct shtr_transitions** out_transitions) +{ + struct shtr_transitions* transitions = NULL; + res_T res = RES_OK; + ASSERT(shtr && out_transitions); + + transitions = MEM_CALLOC(shtr->allocator, 1, sizeof(*transitions)); + if(!transitions) { + log_err(shtr, "Could not allocate the transitions data structure.\n"); + res = RES_MEM_ERR; + goto error; + } + ref_init(&transitions->ref); + SHTR(ref_get(shtr)); + transitions->shtr = shtr; + darray_transition_init(shtr->allocator, &transitions->transitions); + +exit: + *out_transitions = transitions; + return res; +error: + goto exit; +} + +static res_T +parse_transition(struct shtr_transitions* transitions, 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(transitions && txtrdr); + + line = txtrdr_get_line(txtrdr); + ASSERT(line); + + shtr = transitions->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,0,1); + PARSE(&tr.gamma_self, 5, double, "self broadening half-width", 0,INF,0,1); + PARSE(&tr.lower_state_energy, 10, double, "lower state energy", 0,INF,1,1); + PARSE(&tr.n_air, 4, double, "temperature-dependent exponent", 0,INF,0,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(transitions->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(&transitions->transitions, &tr); + if(res != RES_OK) { + log_err(transitions->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** out_transitions) +{ + struct shtr_transitions* transitions = NULL; + struct txtrdr* txtrdr = NULL; + res_T res = RES_OK; + ASSERT(shtr && stream && name && out_transitions); + + res = create_transitions(shtr, &transitions); + if(res != RES_OK) goto error; + + res = txtrdr_stream(transitions->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(transitions, txtrdr); + if(res != RES_OK) goto error; + } + +exit: + if(txtrdr) txtrdr_ref_put(txtrdr); + *out_transitions = transitions; + return res; +error: + if(transitions) { + SHTR(transitions_ref_put(transitions)); + transitions = NULL; + } + goto exit; +} + +static void +release_transitions(ref_T * ref) +{ + struct shtr* shtr = NULL; + struct shtr_transitions* transitions = CONTAINER_OF + (ref, struct shtr_transitions, ref); + ASSERT(ref); + shtr = transitions->shtr; + darray_transition_release(&transitions->transitions); + MEM_RM(shtr->allocator, transitions); + SHTR(ref_put(shtr)); +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +shtr_transitions_load + (struct shtr* shtr, + const char* path, + struct shtr_transitions** transitions) +{ + FILE* file = NULL; + res_T res = RES_OK; + + if(!shtr || !path || !transitions) { + 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, transitions); + if(res != RES_OK) goto error; + +exit: + if(file) fclose(file); + return res; +error: + goto exit; +} + +res_T +shtr_transitions_load_stream + (struct shtr* shtr, + FILE* stream, + const char* stream_name, + struct shtr_transitions** transitions) +{ + if(!shtr || !stream || !transitions) return RES_BAD_ARG; + return load_stream + (shtr, stream, stream_name ? stream_name : "<stream>", transitions); +} + +res_T +shtr_transitions_ref_get(struct shtr_transitions* transitions) +{ + if(!transitions) return RES_BAD_ARG; + ref_get(&transitions->ref); + return RES_OK; +} + +res_T +shtr_transitions_ref_put(struct shtr_transitions* transitions) +{ + if(!transitions) return RES_BAD_ARG; + ref_put(&transitions->ref, release_transitions); + return RES_OK; +} + +res_T +shtr_transitions_get_count + (const struct shtr_transitions* transitions, + size_t* ntransitions) +{ + if(!transitions || !ntransitions) return RES_BAD_ARG; + *ntransitions = darray_transition_size_get(&transitions->transitions); + return RES_OK; +} + +res_T +shtr_transitions_get + (const struct shtr_transitions* transitions, + const struct shtr_transition* transitions_list[]) +{ + if(!transitions || !transitions_list) return RES_BAD_ARG; + *transitions_list = darray_transition_cdata_get(&transitions->transitions); + return RES_OK; +} + +#endif /* SHTR_TRANSITIONS_H */ diff --git a/src/test_shitran.c b/src/test_shitran.c @@ -1,74 +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 "shitran.h" - -#include <rsys/logger.h> - -static void -log_stream(const char* msg, void* ctx) -{ - ASSERT(msg); - (void)msg, (void)ctx; - printf("%s\n", msg); -} - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct logger logger; - struct shitran* shitran; - struct shitran_create_args args = SHITRAN_CREATE_ARGS_DEFAULT; - (void)argc, (void)argv; - - CHK(shitran_create(NULL, &shitran) == RES_BAD_ARG); - CHK(shitran_create(&args, NULL) == RES_BAD_ARG); - CHK(shitran_create(&args, &shitran) == RES_OK); - - CHK(shitran_ref_get(NULL) == RES_BAD_ARG); - CHK(shitran_ref_get(shitran) == RES_OK); - CHK(shitran_ref_put(NULL) == RES_BAD_ARG); - CHK(shitran_ref_put(shitran) == RES_OK); - CHK(shitran_ref_put(shitran) == RES_OK); - - CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); - args.allocator = &allocator; - args.verbose = 1; - CHK(shitran_create(&args, &shitran) == RES_OK); - CHK(MEM_ALLOCATED_SIZE(&allocator) != 0); - CHK(shitran_ref_put(shitran) == RES_OK); - - CHK(logger_init(&allocator, &logger) == RES_OK); - logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL); - logger_set_stream(&logger, LOG_ERROR, log_stream, NULL); - logger_set_stream(&logger, LOG_WARNING, log_stream, NULL); - - args.logger = &logger; - CHK(shitran_create(&args, &shitran) == RES_OK); - CHK(shitran_ref_put(shitran) == RES_OK); - args.allocator = NULL; - CHK(shitran_create(&args, &shitran) == RES_OK); - CHK(shitran_ref_put(shitran) == RES_OK); - - logger_release(&logger); - CHK(MEM_ALLOCATED_SIZE(&allocator) == 0); - mem_shutdown_proxy_allocator(&allocator); - CHK(mem_allocated_size() == 0); - return 0; -} diff --git a/src/test_shitran_isotope_metadata.c b/src/test_shitran_isotope_metadata.c @@ -1,394 +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 "shitran.h" - -#include <rsys/mem_allocator.h> -#include <rsys/math.h> - -#include <string.h> - -static const struct shitran_isotope H2O_isotopes[] = { - {9.97317E-01, 1.7458E+02, 18.010565, 0, 1, 161}, - {1.99983E-03, 1.7605E+02, 20.014811, 0, 1, 181}, - {3.71884E-04, 1.0521E+03, 19.014780, 0, 6, 171}, - {3.10693E-04, 8.6474E+02, 19.016740, 0, 6, 162}, - {6.23003E-07, 8.7557E+02, 21.020985, 0, 6, 182}, - {1.15853E-07, 5.2268E+03, 20.020956, 0, 36, 172}, - {2.41974E-08, 1.0278E+03, 20.022915, 0, 1, 262} -}; - - -static const struct shitran_molecule H2O = { - "H2O", sizeof(H2O_isotopes)/sizeof(struct shitran_isotope), H2O_isotopes, 1, -}; - -static const struct shitran_isotope CO2_isotopes[] = { - {9.84204E-01, 2.8609E+02, 43.989830, 1, 1, 626}, - {1.10574E-02, 5.7664E+02, 44.993185, 1, 2, 636}, - {3.94707E-03, 6.0781E+02, 45.994076, 1, 1, 628}, - {7.33989E-04, 3.5426E+03, 44.994045, 1, 6, 627}, - {4.43446E-05, 1.2255E+03, 46.997431, 1, 2, 638}, - {8.24623E-06, 7.1413E+03, 45.997400, 1, 12, 637}, - {3.95734E-06, 3.2342E+02, 47.998320, 1, 1, 828}, - {1.47180E-06, 3.7666E+03, 46.998291, 1, 6, 827}, - {1.36847E-07, 1.0972E+04, 45.998262, 1, 1, 727}, - {4.44600E-08, 6.5224E+02, 49.001675, 1, 2, 838}, - {1.65354E-08, 7.5950E+03, 48.001646, 1, 12, 837}, - {1.53745E-09, 2.2120E+04, 47.001618, 1, 2, 737} -}; - -static const struct shitran_molecule CO2 = { - "CO2", sizeof(CO2_isotopes)/sizeof(struct shitran_isotope), CO2_isotopes, 2, -}; - -static void -isotope_print(FILE* fp, const struct shitran_isotope* isotope) -{ - CHK(fp && isotope); - fprintf(fp, " %d %.5E %.4E %d %.6f\n", - isotope->id, - isotope->abundance, - isotope->Q296K, - isotope->gj, - isotope->molar_mass); -} - -static void -molecule_print(FILE* fp, const struct shitran_molecule* molecule) -{ - size_t i; - CHK(fp && molecule); - - fprintf(fp, " %s (%d)\n", molecule->name, molecule->id); - FOR_EACH(i, 0, molecule->nisotopes) { - isotope_print(fp, molecule->isotopes+i); - } -} - -static int -isotope_eq(const struct shitran_isotope* i0, const struct shitran_isotope* i1) -{ - CHK(i0 && i1); - return i0->abundance == i1->abundance - && i0->Q296K == i1->Q296K - && i0->molar_mass == i1->molar_mass - && i0->molecule_id_local == i1->molecule_id_local - && i0->gj == i1->gj - && i0->id == i1->id; -} - -static int -molecule_eq(const struct shitran_molecule* m0, const struct shitran_molecule* m1) -{ - size_t i; - - CHK(m0 && m1); - if(strcmp(m0->name, m1->name) - || m0->id != m1->id - || m0->nisotopes != m1->nisotopes) - return 0; - - FOR_EACH(i, 0, m0->nisotopes) { - if(!isotope_eq(m0->isotopes+i, m1->isotopes+i)) - return 0; - } - return 1; -} - -static void -check_isotope - (struct shitran_isotope_metadata* mdata, - const struct shitran_molecule* molecule, - const struct shitran_isotope* isotope) -{ - struct shitran_molecule molecule2 = SHITRAN_MOLECULE_NULL; - - /* Check NaN */ - CHK(isotope->abundance == isotope->abundance); - CHK(isotope->Q296K == isotope->Q296K); - CHK(isotope->molar_mass == isotope->molar_mass); - - CHK(isotope->abundance > 0 && isotope->abundance <= 1); - CHK(isotope->Q296K > 0); - CHK(isotope->molar_mass > 0); - CHK(isotope->id >= 0); - - CHK(shitran_isotope_metadata_get_molecule - (mdata, isotope->molecule_id_local, &molecule2) == RES_OK); - CHK(molecule_eq(molecule, &molecule2)); -} - -static void -check_molecule - (struct shitran_isotope_metadata* mdata, - struct shitran_molecule* molecule) -{ - size_t i = 0; - - CHK(mdata && molecule); - CHK(molecule->name); - CHK(molecule->id >= 0); - - FOR_EACH(i, 0, molecule->nisotopes) { - check_isotope(mdata, molecule, molecule->isotopes+i); - } -} - -static void -test_load(struct shitran* shitran) -{ - struct shitran_molecule molecule = SHITRAN_MOLECULE_NULL; - const char* filename = "test_isotope_metadata.txt"; - struct shitran_isotope_metadata* mdata = NULL; - FILE* fp = NULL; - size_t nmolecules = 0; - size_t nisotopes = 0; - - CHK(fp = fopen(filename, "w+")); - - fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); - molecule_print(fp, &H2O); - molecule_print(fp, &CO2); - rewind(fp); - - CHK(shitran_isotope_metadata_load_stream(NULL, fp, NULL, &mdata) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_load_stream(shitran, NULL, NULL, &mdata) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, NULL) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, &mdata) == RES_OK); - - CHK(shitran_isotope_metadata_get_molecules_count(NULL, &nmolecules) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_get_molecules_count(mdata, NULL) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); - CHK(nmolecules == 2); - - CHK(shitran_isotope_metadata_get_isotopes_count(NULL, &nisotopes) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_get_isotopes_count(mdata, NULL) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_get_isotopes_count(mdata, &nisotopes) == RES_OK); - CHK(nisotopes == H2O.nisotopes + CO2.nisotopes); - - CHK(shitran_isotope_metadata_get_molecule(NULL, 0, &molecule) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_get_molecule(mdata, 2, &molecule) == RES_BAD_ARG); - - CHK(shitran_isotope_metadata_get_molecule(mdata, 0, &molecule) == RES_OK); - CHK(molecule_eq(&molecule, &H2O)); - check_molecule(mdata, &molecule); - - CHK(shitran_isotope_metadata_get_molecule(mdata, 1, &molecule) == RES_OK); - CHK(molecule_eq(&molecule, &CO2)); - check_molecule(mdata, &molecule); - - CHK(shitran_isotope_metadata_find_molecule(NULL, 1, &molecule) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_find_molecule(mdata, 1, NULL) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_find_molecule(mdata, 1, &molecule) == RES_OK); - CHK(!SHITRAN_MOLECULE_IS_NULL(&molecule)); - CHK(molecule_eq(&molecule, &H2O)); - - CHK(shitran_isotope_metadata_find_molecule(mdata, 2, &molecule) == RES_OK); - CHK(!SHITRAN_MOLECULE_IS_NULL(&molecule)); - CHK(molecule_eq(&molecule, &CO2)); - - CHK(shitran_isotope_metadata_find_molecule(mdata, 0, &molecule) == RES_OK); - CHK(SHITRAN_MOLECULE_IS_NULL(&molecule)); - - CHK(shitran_isotope_metadata_ref_get(NULL) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_ref_get(mdata) == RES_OK); - CHK(shitran_isotope_metadata_ref_put(NULL) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_ref_put(mdata) == RES_OK); - CHK(shitran_isotope_metadata_ref_put(mdata) == RES_OK); - - CHK(fclose(fp) == 0); - - CHK(shitran_isotope_metadata_load(NULL, filename, &mdata) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_load(shitran, NULL, &mdata) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_load(shitran, filename, NULL) == RES_BAD_ARG); - CHK(shitran_isotope_metadata_load(shitran, "no_file", &mdata) == RES_IO_ERR); - - CHK(shitran_isotope_metadata_load(shitran, filename, &mdata) == RES_OK); - CHK(shitran_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); - CHK(nmolecules == 2); - CHK(shitran_isotope_metadata_get_molecule(mdata, 0, &molecule) == RES_OK); - CHK(molecule_eq(&molecule, &H2O)); - CHK(shitran_isotope_metadata_get_molecule(mdata, 1, &molecule) == RES_OK); - CHK(molecule_eq(&molecule, &CO2)); - CHK(shitran_isotope_metadata_ref_put(mdata) == RES_OK); - - /* Empty file */ - CHK(fp = tmpfile()); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, &mdata) == RES_OK); - CHK(shitran_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); - CHK(nmolecules == 0); - CHK(shitran_isotope_metadata_ref_put(mdata) == RES_OK); - fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); - rewind(fp); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, &mdata) == RES_OK); - CHK(shitran_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); - CHK(nmolecules == 0); - CHK(shitran_isotope_metadata_ref_put(mdata) == RES_OK); - CHK(fclose(fp) == 0); - - /* Molecule without isotope */ - CHK(fp = tmpfile()); - fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); - fprintf(fp, "%s (%d)\n", H2O.name, H2O.id); - fprintf(fp, "%s (%d)\n", CO2.name, CO2.id); - rewind(fp); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, &mdata) == RES_OK); - CHK(shitran_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); - CHK(nmolecules == 2); - - CHK(shitran_isotope_metadata_get_molecule(mdata, 0, &molecule) == RES_OK); - CHK(!strcmp(molecule.name, H2O.name)); - CHK(molecule.id == H2O.id); - CHK(molecule.nisotopes == 0); - CHK(molecule.isotopes == NULL); - - CHK(shitran_isotope_metadata_get_molecule(mdata, 1, &molecule) == RES_OK); - CHK(!strcmp(molecule.name, CO2.name)); - CHK(molecule.id == CO2.id); - CHK(molecule.nisotopes == 0); - CHK(molecule.isotopes == NULL); - - CHK(shitran_isotope_metadata_ref_put(mdata) == RES_OK); - CHK(fclose(fp) == 0); -} - -static void -test_load_failures(struct shitran* shitran) -{ - struct shitran_isotope isotope = SHITRAN_ISOTOPE_NULL; - struct shitran_isotope_metadata* mdata = NULL; - FILE* fp = NULL; - - CHK(shitran); - - /* 1st line is missing */ - CHK(fp = tmpfile()); - molecule_print(fp, &H2O); - rewind(fp); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, &mdata) == RES_BAD_ARG); - CHK(fclose(fp) == 0); - - /* Invalid molecule id */ - CHK(fp = tmpfile()); - fprintf(fp, "Comment line\n"); - fprintf(fp, "H2O 1\n"); - isotope_print(fp, &H2O_isotopes[0]); - rewind(fp); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, &mdata) == RES_BAD_ARG); - rewind(fp); - fprintf(fp, "Comment line\n"); - fprintf(fp, "H2O (-1)\n"); - isotope_print(fp, &H2O_isotopes[0]); - rewind(fp); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, &mdata) == RES_BAD_ARG); - CHK(fclose(fp) == 0); - - /* Invalid isotope id */ - CHK(fp = tmpfile()); - fprintf(fp, "Comment line\n"); - fprintf(fp, "H2O (1)\n"); - isotope = H2O_isotopes[0]; - isotope.id = -1; - isotope_print(fp, &isotope); - rewind(fp); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, &mdata) == RES_BAD_ARG); - CHK(fclose(fp) == 0); - - /* Invalid abundance */ - CHK(fp = tmpfile()); - fprintf(fp, "Comment line\n"); - fprintf(fp, "H2O (1)\n"); - isotope = H2O_isotopes[0]; - isotope.abundance = 0; - isotope_print(fp, &isotope); - rewind(fp); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, &mdata) == RES_BAD_ARG); - CHK(fclose(fp) == 0); - CHK(fp = tmpfile()); - fprintf(fp, "Comment line\n"); - fprintf(fp, "H2O (1)\n"); - isotope.abundance = 1.00001; - isotope_print(fp, &isotope); - rewind(fp); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, &mdata) == RES_BAD_ARG); - CHK(fclose(fp) == 0); - - /* Invalid Q(296K) */ - CHK(fp = tmpfile()); - fprintf(fp, "Comment line\n"); - fprintf(fp, "H2O (1)\n"); - isotope = H2O_isotopes[0]; - isotope.Q296K = 0; - isotope_print(fp, &isotope); - rewind(fp); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, &mdata) == RES_BAD_ARG); - CHK(fclose(fp) == 0); - - /* Invalid molar mass */ - CHK(fp = tmpfile()); - fprintf(fp, "Comment line\n"); - fprintf(fp, "H2O (1)\n"); - isotope = H2O_isotopes[0]; - isotope.molar_mass = 0; - isotope_print(fp, &isotope); - rewind(fp); - CHK(shitran_isotope_metadata_load_stream(shitran, fp, NULL, &mdata) == RES_BAD_ARG); - CHK(fclose(fp) == 0); -} - -static void -test_load_file(struct shitran* shitran, const char* path) -{ - struct shitran_isotope_metadata* mdata = NULL; - size_t i, n; - CHK(path); - printf("Loading `%s'.\n", path); - CHK(shitran_isotope_metadata_load(shitran, path, &mdata) == RES_OK); - CHK(shitran_isotope_metadata_get_molecules_count(mdata, &n) == RES_OK); - printf(" #molecules: %lu\n", n); - FOR_EACH(i, 0, n) { - struct shitran_molecule molecule = SHITRAN_MOLECULE_NULL; - CHK(shitran_isotope_metadata_get_molecule(mdata, i, &molecule) == RES_OK); - printf(" Checking %s\n", molecule.name); - check_molecule(mdata, &molecule); - } - CHK(shitran_isotope_metadata_ref_put(mdata) == RES_OK); -} - -int -main(int argc, char** argv) -{ - struct shitran_create_args args = SHITRAN_CREATE_ARGS_DEFAULT; - struct shitran* shitran = NULL; - int i; - (void)argc, (void)argv; - - args.verbose = 1; - CHK(shitran_create(&args, &shitran) == RES_OK); - - test_load(shitran); - test_load_failures(shitran); - FOR_EACH(i, 1, argc) { - test_load_file(shitran, argv[i]); - } - - CHK(shitran_ref_put(shitran) == RES_OK); - CHK(mem_allocated_size() == 0); - return 0; -} diff --git a/src/test_shitran_transitions.c b/src/test_shitran_transitions.c @@ -1,258 +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 "shitran.h" - -#include <rsys/mem_allocator.h> -#include <rsys/math.h> - -#include <string.h> - -static void -print_transitions - (FILE* fp, - const struct shitran_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 shitran_transition* tr0, - const struct shitran_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 shitran* shitran) -{ - const struct shitran_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 shitran_transition); - - struct shitran_transitions* trs = NULL; - const struct shitran_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(shitran_transitions_load_stream(NULL, fp, NULL, &trs) == RES_BAD_ARG); - CHK(shitran_transitions_load_stream(shitran, NULL, NULL, &trs) == RES_BAD_ARG); - CHK(shitran_transitions_load_stream(shitran, fp, NULL, NULL) == RES_BAD_ARG); - CHK(shitran_transitions_load_stream(shitran, fp, NULL, &trs) == RES_OK); - - CHK(shitran_transitions_get_count(NULL, &n) == RES_BAD_ARG); - CHK(shitran_transitions_get_count(trs, NULL) == RES_BAD_ARG); - CHK(shitran_transitions_get_count(trs, &n) == RES_OK); - CHK(n == ntransitions); - - CHK(shitran_transitions_get(NULL, &trs_list) == RES_BAD_ARG); - CHK(shitran_transitions_get(trs, NULL) == RES_BAD_ARG); - CHK(shitran_transitions_get(trs, &trs_list) == RES_OK); - FOR_EACH(i, 0, n) CHK(transition_eq(trs_list+i, transitions+i)); - - CHK(shitran_transitions_ref_get(NULL) == RES_BAD_ARG); - CHK(shitran_transitions_ref_get(trs) == RES_OK); - CHK(shitran_transitions_ref_put(NULL) == RES_BAD_ARG); - CHK(shitran_transitions_ref_put(trs) == RES_OK); - CHK(shitran_transitions_ref_put(trs) == RES_OK); - - CHK(fclose(fp) == 0); - - CHK(shitran_transitions_load(NULL, filename, &trs) == RES_BAD_ARG); - CHK(shitran_transitions_load(shitran, NULL, &trs) == RES_BAD_ARG); - CHK(shitran_transitions_load(shitran, filename, NULL) == RES_BAD_ARG); - CHK(shitran_transitions_load(shitran, filename, &trs) == RES_OK); - - CHK(shitran_transitions_get_count(trs, &n) == RES_OK); - CHK(n == ntransitions); - - CHK(shitran_transitions_get(trs, &trs_list) == RES_OK); - FOR_EACH(i, 0, n) CHK(transition_eq(trs_list+i, transitions+i)); - - CHK(shitran_transitions_ref_put(trs) == RES_OK); -} - -static void -test_transition - (struct shitran* shitran, const struct shitran_transition* tr, const res_T res) -{ - struct shitran_transitions* trs = NULL; - FILE* fp = NULL; - - CHK(fp = tmpfile()); - print_transitions(fp, tr, 1); - rewind(fp); - CHK(shitran_transitions_load_stream(shitran, fp, NULL, &trs) == res); - CHK(fclose(fp) == 0); - - if(res == RES_OK) CHK(shitran_transitions_ref_put(trs) == RES_OK); -} - -static void -test_load_failures(struct shitran* shitran) -{ - const struct shitran_transition tr_ref = { - 0.000134, 2.672E-38, 0.0533, 0.410, 608.4727, 0.79, 0.000060, 1, 4, - }; - struct shitran_transition tr; - - /* Check that the reference transition is valid */ - test_transition(shitran, &tr_ref, RES_OK); - - /* Invalid wavenumber */ - tr = tr_ref; tr.wavenumber = 0; - test_transition(shitran, &tr, RES_BAD_ARG); - - /* Invalid intensity */ - tr = tr_ref; tr.intensity = 0; - test_transition(shitran, &tr, RES_BAD_ARG); - - /* Invalid gamma air */ - tr = tr_ref; tr.gamma_air = 0; - test_transition(shitran, &tr, RES_BAD_ARG); - - /* Invalid gamma self */ - tr = tr_ref; tr.gamma_self = 0; - test_transition(shitran, &tr, RES_BAD_ARG); - - /* Invalid lower state energy */ - tr = tr_ref; tr.lower_state_energy = -1; - test_transition(shitran, &tr, RES_BAD_ARG); - - /* Invalid n_air */ - tr = tr_ref; tr.n_air = 0; - test_transition(shitran, &tr, RES_BAD_ARG); - - /* Invalid molecule id */ - tr = tr_ref; tr.molecule_id = -1; - test_transition(shitran, &tr, RES_BAD_ARG); - - /* Bad file formatting */ - tr = tr_ref; tr.molecule_id = 100; - test_transition(shitran, &tr, RES_BAD_ARG); - tr = tr_ref; tr.isotope_id_local = 10; - test_transition(shitran, &tr, RES_BAD_ARG); -} - -static void -check_transition(const struct shitran_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->n_air > 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 shitran* shitran, const char* path) -{ - struct shitran_transitions* trs = NULL; - const struct shitran_transition* trs_list = NULL; - size_t i, n; - CHK(path); - printf("Loading `%s'.\n", path); - CHK(shitran_transitions_load(shitran, path, &trs) == RES_OK); - CHK(shitran_transitions_get_count(trs, &n) == RES_OK); - printf(" #transitions: %lu\n", n); - - CHK(shitran_transitions_get(trs, &trs_list) == RES_OK); - FOR_EACH(i, 0, n) check_transition(trs_list+i); - CHK(shitran_transitions_ref_put(trs) == RES_OK); -} - -int -main(int argc, char** argv) -{ - struct shitran_create_args args = SHITRAN_CREATE_ARGS_DEFAULT; - struct shitran* shitran = NULL; - int i; - (void)argc, (void)argv; - - args.verbose = 1; - CHK(shitran_create(&args, &shitran) == RES_OK); - - test_load(shitran); - test_load_failures(shitran); - FOR_EACH(i, 1, argc) { - test_load_file(shitran, argv[i]); - } - - CHK(shitran_ref_put(shitran) == RES_OK); - CHK(mem_allocated_size() == 0); - return 0; -} diff --git a/src/test_shtr.c b/src/test_shtr.c @@ -0,0 +1,74 @@ +/* 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/logger.h> + +static void +log_stream(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)msg, (void)ctx; + printf("%s\n", msg); +} + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct logger logger; + struct shtr* shtr; + struct shtr_create_args args = SHTR_CREATE_ARGS_DEFAULT; + (void)argc, (void)argv; + + CHK(shtr_create(NULL, &shtr) == RES_BAD_ARG); + CHK(shtr_create(&args, NULL) == RES_BAD_ARG); + CHK(shtr_create(&args, &shtr) == RES_OK); + + CHK(shtr_ref_get(NULL) == RES_BAD_ARG); + CHK(shtr_ref_get(shtr) == RES_OK); + CHK(shtr_ref_put(NULL) == RES_BAD_ARG); + CHK(shtr_ref_put(shtr) == RES_OK); + CHK(shtr_ref_put(shtr) == RES_OK); + + CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); + args.allocator = &allocator; + args.verbose = 1; + CHK(shtr_create(&args, &shtr) == RES_OK); + CHK(MEM_ALLOCATED_SIZE(&allocator) != 0); + CHK(shtr_ref_put(shtr) == RES_OK); + + CHK(logger_init(&allocator, &logger) == RES_OK); + logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL); + logger_set_stream(&logger, LOG_ERROR, log_stream, NULL); + logger_set_stream(&logger, LOG_WARNING, log_stream, NULL); + + args.logger = &logger; + CHK(shtr_create(&args, &shtr) == RES_OK); + CHK(shtr_ref_put(shtr) == RES_OK); + args.allocator = NULL; + CHK(shtr_create(&args, &shtr) == RES_OK); + CHK(shtr_ref_put(shtr) == RES_OK); + + logger_release(&logger); + CHK(MEM_ALLOCATED_SIZE(&allocator) == 0); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_shtr_isotope_metadata.c b/src/test_shtr_isotope_metadata.c @@ -0,0 +1,394 @@ +/* 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/mem_allocator.h> +#include <rsys/math.h> + +#include <string.h> + +static const struct shtr_isotope H2O_isotopes[] = { + {9.97317E-01, 1.7458E+02, 18.010565, 0, 1, 161}, + {1.99983E-03, 1.7605E+02, 20.014811, 0, 1, 181}, + {3.71884E-04, 1.0521E+03, 19.014780, 0, 6, 171}, + {3.10693E-04, 8.6474E+02, 19.016740, 0, 6, 162}, + {6.23003E-07, 8.7557E+02, 21.020985, 0, 6, 182}, + {1.15853E-07, 5.2268E+03, 20.020956, 0, 36, 172}, + {2.41974E-08, 1.0278E+03, 20.022915, 0, 1, 262} +}; + + +static const struct shtr_molecule H2O = { + "H2O", sizeof(H2O_isotopes)/sizeof(struct shtr_isotope), H2O_isotopes, 1, +}; + +static const struct shtr_isotope CO2_isotopes[] = { + {9.84204E-01, 2.8609E+02, 43.989830, 1, 1, 626}, + {1.10574E-02, 5.7664E+02, 44.993185, 1, 2, 636}, + {3.94707E-03, 6.0781E+02, 45.994076, 1, 1, 628}, + {7.33989E-04, 3.5426E+03, 44.994045, 1, 6, 627}, + {4.43446E-05, 1.2255E+03, 46.997431, 1, 2, 638}, + {8.24623E-06, 7.1413E+03, 45.997400, 1, 12, 637}, + {3.95734E-06, 3.2342E+02, 47.998320, 1, 1, 828}, + {1.47180E-06, 3.7666E+03, 46.998291, 1, 6, 827}, + {1.36847E-07, 1.0972E+04, 45.998262, 1, 1, 727}, + {4.44600E-08, 6.5224E+02, 49.001675, 1, 2, 838}, + {1.65354E-08, 7.5950E+03, 48.001646, 1, 12, 837}, + {1.53745E-09, 2.2120E+04, 47.001618, 1, 2, 737} +}; + +static const struct shtr_molecule CO2 = { + "CO2", sizeof(CO2_isotopes)/sizeof(struct shtr_isotope), CO2_isotopes, 2, +}; + +static void +isotope_print(FILE* fp, const struct shtr_isotope* isotope) +{ + CHK(fp && isotope); + fprintf(fp, " %d %.5E %.4E %d %.6f\n", + isotope->id, + isotope->abundance, + isotope->Q296K, + isotope->gj, + isotope->molar_mass); +} + +static void +molecule_print(FILE* fp, const struct shtr_molecule* molecule) +{ + size_t i; + CHK(fp && molecule); + + fprintf(fp, " %s (%d)\n", molecule->name, molecule->id); + FOR_EACH(i, 0, molecule->nisotopes) { + isotope_print(fp, molecule->isotopes+i); + } +} + +static int +isotope_eq(const struct shtr_isotope* i0, const struct shtr_isotope* i1) +{ + CHK(i0 && i1); + return i0->abundance == i1->abundance + && i0->Q296K == i1->Q296K + && i0->molar_mass == i1->molar_mass + && i0->molecule_id_local == i1->molecule_id_local + && i0->gj == i1->gj + && i0->id == i1->id; +} + +static int +molecule_eq(const struct shtr_molecule* m0, const struct shtr_molecule* m1) +{ + size_t i; + + CHK(m0 && m1); + if(strcmp(m0->name, m1->name) + || m0->id != m1->id + || m0->nisotopes != m1->nisotopes) + return 0; + + FOR_EACH(i, 0, m0->nisotopes) { + if(!isotope_eq(m0->isotopes+i, m1->isotopes+i)) + return 0; + } + return 1; +} + +static void +check_isotope + (struct shtr_isotope_metadata* mdata, + const struct shtr_molecule* molecule, + const struct shtr_isotope* isotope) +{ + struct shtr_molecule molecule2 = SHTR_MOLECULE_NULL; + + /* Check NaN */ + CHK(isotope->abundance == isotope->abundance); + CHK(isotope->Q296K == isotope->Q296K); + CHK(isotope->molar_mass == isotope->molar_mass); + + CHK(isotope->abundance > 0 && isotope->abundance <= 1); + CHK(isotope->Q296K > 0); + CHK(isotope->molar_mass > 0); + CHK(isotope->id >= 0); + + CHK(shtr_isotope_metadata_get_molecule + (mdata, isotope->molecule_id_local, &molecule2) == RES_OK); + CHK(molecule_eq(molecule, &molecule2)); +} + +static void +check_molecule + (struct shtr_isotope_metadata* mdata, + struct shtr_molecule* molecule) +{ + size_t i = 0; + + CHK(mdata && molecule); + CHK(molecule->name); + CHK(molecule->id >= 0); + + FOR_EACH(i, 0, molecule->nisotopes) { + check_isotope(mdata, molecule, molecule->isotopes+i); + } +} + +static void +test_load(struct shtr* shtr) +{ + struct shtr_molecule molecule = SHTR_MOLECULE_NULL; + const char* filename = "test_isotope_metadata.txt"; + struct shtr_isotope_metadata* mdata = NULL; + FILE* fp = NULL; + size_t nmolecules = 0; + size_t nisotopes = 0; + + CHK(fp = fopen(filename, "w+")); + + fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); + molecule_print(fp, &H2O); + molecule_print(fp, &CO2); + rewind(fp); + + CHK(shtr_isotope_metadata_load_stream(NULL, fp, NULL, &mdata) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_load_stream(shtr, NULL, NULL, &mdata) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, NULL) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_OK); + + CHK(shtr_isotope_metadata_get_molecules_count(NULL, &nmolecules) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_get_molecules_count(mdata, NULL) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); + CHK(nmolecules == 2); + + CHK(shtr_isotope_metadata_get_isotopes_count(NULL, &nisotopes) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_get_isotopes_count(mdata, NULL) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_get_isotopes_count(mdata, &nisotopes) == RES_OK); + CHK(nisotopes == H2O.nisotopes + CO2.nisotopes); + + CHK(shtr_isotope_metadata_get_molecule(NULL, 0, &molecule) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_get_molecule(mdata, 2, &molecule) == RES_BAD_ARG); + + CHK(shtr_isotope_metadata_get_molecule(mdata, 0, &molecule) == RES_OK); + CHK(molecule_eq(&molecule, &H2O)); + check_molecule(mdata, &molecule); + + CHK(shtr_isotope_metadata_get_molecule(mdata, 1, &molecule) == RES_OK); + CHK(molecule_eq(&molecule, &CO2)); + check_molecule(mdata, &molecule); + + CHK(shtr_isotope_metadata_find_molecule(NULL, 1, &molecule) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_find_molecule(mdata, 1, NULL) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_find_molecule(mdata, 1, &molecule) == RES_OK); + CHK(!SHTR_MOLECULE_IS_NULL(&molecule)); + CHK(molecule_eq(&molecule, &H2O)); + + CHK(shtr_isotope_metadata_find_molecule(mdata, 2, &molecule) == RES_OK); + CHK(!SHTR_MOLECULE_IS_NULL(&molecule)); + CHK(molecule_eq(&molecule, &CO2)); + + CHK(shtr_isotope_metadata_find_molecule(mdata, 0, &molecule) == RES_OK); + CHK(SHTR_MOLECULE_IS_NULL(&molecule)); + + CHK(shtr_isotope_metadata_ref_get(NULL) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_ref_get(mdata) == RES_OK); + CHK(shtr_isotope_metadata_ref_put(NULL) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); + CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); + + CHK(fclose(fp) == 0); + + CHK(shtr_isotope_metadata_load(NULL, filename, &mdata) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_load(shtr, NULL, &mdata) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_load(shtr, filename, NULL) == RES_BAD_ARG); + CHK(shtr_isotope_metadata_load(shtr, "no_file", &mdata) == RES_IO_ERR); + + CHK(shtr_isotope_metadata_load(shtr, filename, &mdata) == RES_OK); + CHK(shtr_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); + CHK(nmolecules == 2); + CHK(shtr_isotope_metadata_get_molecule(mdata, 0, &molecule) == RES_OK); + CHK(molecule_eq(&molecule, &H2O)); + CHK(shtr_isotope_metadata_get_molecule(mdata, 1, &molecule) == RES_OK); + CHK(molecule_eq(&molecule, &CO2)); + CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); + + /* Empty file */ + CHK(fp = tmpfile()); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_OK); + CHK(shtr_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); + CHK(nmolecules == 0); + CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); + fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); + rewind(fp); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_OK); + CHK(shtr_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); + CHK(nmolecules == 0); + CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); + CHK(fclose(fp) == 0); + + /* Molecule without isotope */ + CHK(fp = tmpfile()); + fprintf(fp, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); + fprintf(fp, "%s (%d)\n", H2O.name, H2O.id); + fprintf(fp, "%s (%d)\n", CO2.name, CO2.id); + rewind(fp); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_OK); + CHK(shtr_isotope_metadata_get_molecules_count(mdata, &nmolecules) == RES_OK); + CHK(nmolecules == 2); + + CHK(shtr_isotope_metadata_get_molecule(mdata, 0, &molecule) == RES_OK); + CHK(!strcmp(molecule.name, H2O.name)); + CHK(molecule.id == H2O.id); + CHK(molecule.nisotopes == 0); + CHK(molecule.isotopes == NULL); + + CHK(shtr_isotope_metadata_get_molecule(mdata, 1, &molecule) == RES_OK); + CHK(!strcmp(molecule.name, CO2.name)); + CHK(molecule.id == CO2.id); + CHK(molecule.nisotopes == 0); + CHK(molecule.isotopes == NULL); + + CHK(shtr_isotope_metadata_ref_put(mdata) == RES_OK); + CHK(fclose(fp) == 0); +} + +static void +test_load_failures(struct shtr* shtr) +{ + struct shtr_isotope isotope = SHTR_ISOTOPE_NULL; + struct shtr_isotope_metadata* mdata = NULL; + FILE* fp = NULL; + + CHK(shtr); + + /* 1st line is missing */ + CHK(fp = tmpfile()); + molecule_print(fp, &H2O); + rewind(fp); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid molecule id */ + CHK(fp = tmpfile()); + fprintf(fp, "Comment line\n"); + fprintf(fp, "H2O 1\n"); + isotope_print(fp, &H2O_isotopes[0]); + rewind(fp); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); + rewind(fp); + fprintf(fp, "Comment line\n"); + fprintf(fp, "H2O (-1)\n"); + isotope_print(fp, &H2O_isotopes[0]); + rewind(fp); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid isotope id */ + CHK(fp = tmpfile()); + fprintf(fp, "Comment line\n"); + fprintf(fp, "H2O (1)\n"); + isotope = H2O_isotopes[0]; + isotope.id = -1; + isotope_print(fp, &isotope); + rewind(fp); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid abundance */ + CHK(fp = tmpfile()); + fprintf(fp, "Comment line\n"); + fprintf(fp, "H2O (1)\n"); + isotope = H2O_isotopes[0]; + isotope.abundance = 0; + isotope_print(fp, &isotope); + rewind(fp); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + CHK(fp = tmpfile()); + fprintf(fp, "Comment line\n"); + fprintf(fp, "H2O (1)\n"); + isotope.abundance = 1.00001; + isotope_print(fp, &isotope); + rewind(fp); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid Q(296K) */ + CHK(fp = tmpfile()); + fprintf(fp, "Comment line\n"); + fprintf(fp, "H2O (1)\n"); + isotope = H2O_isotopes[0]; + isotope.Q296K = 0; + isotope_print(fp, &isotope); + rewind(fp); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); + CHK(fclose(fp) == 0); + + /* Invalid molar mass */ + CHK(fp = tmpfile()); + fprintf(fp, "Comment line\n"); + fprintf(fp, "H2O (1)\n"); + isotope = H2O_isotopes[0]; + isotope.molar_mass = 0; + isotope_print(fp, &isotope); + rewind(fp); + CHK(shtr_isotope_metadata_load_stream(shtr, fp, NULL, &mdata) == RES_BAD_ARG); + CHK(fclose(fp) == 0); +} + +static void +test_load_file(struct shtr* shtr, const char* path) +{ + struct shtr_isotope_metadata* mdata = NULL; + size_t i, n; + CHK(path); + printf("Loading `%s'.\n", path); + CHK(shtr_isotope_metadata_load(shtr, path, &mdata) == RES_OK); + CHK(shtr_isotope_metadata_get_molecules_count(mdata, &n) == RES_OK); + printf(" #molecules: %lu\n", n); + FOR_EACH(i, 0, n) { + struct shtr_molecule molecule = SHTR_MOLECULE_NULL; + CHK(shtr_isotope_metadata_get_molecule(mdata, i, &molecule) == RES_OK); + printf(" Checking %s\n", molecule.name); + check_molecule(mdata, &molecule); + } + CHK(shtr_isotope_metadata_ref_put(mdata) == 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) { + test_load_file(shtr, argv[i]); + } + + 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 @@ -0,0 +1,258 @@ +/* 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/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* 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_load_stream(NULL, fp, NULL, &trs) == RES_BAD_ARG); + CHK(shtr_transitions_load_stream(shtr, NULL, NULL, &trs) == RES_BAD_ARG); + CHK(shtr_transitions_load_stream(shtr, fp, NULL, NULL) == RES_BAD_ARG); + CHK(shtr_transitions_load_stream(shtr, fp, NULL, &trs) == RES_OK); + + CHK(shtr_transitions_get_count(NULL, &n) == RES_BAD_ARG); + CHK(shtr_transitions_get_count(trs, NULL) == RES_BAD_ARG); + CHK(shtr_transitions_get_count(trs, &n) == RES_OK); + CHK(n == ntransitions); + + CHK(shtr_transitions_get(NULL, &trs_list) == RES_BAD_ARG); + CHK(shtr_transitions_get(trs, NULL) == RES_BAD_ARG); + CHK(shtr_transitions_get(trs, &trs_list) == RES_OK); + FOR_EACH(i, 0, n) CHK(transition_eq(trs_list+i, transitions+i)); + + CHK(shtr_transitions_ref_get(NULL) == RES_BAD_ARG); + CHK(shtr_transitions_ref_get(trs) == RES_OK); + CHK(shtr_transitions_ref_put(NULL) == RES_BAD_ARG); + CHK(shtr_transitions_ref_put(trs) == RES_OK); + CHK(shtr_transitions_ref_put(trs) == RES_OK); + + CHK(fclose(fp) == 0); + + CHK(shtr_transitions_load(NULL, filename, &trs) == RES_BAD_ARG); + CHK(shtr_transitions_load(shtr, NULL, &trs) == RES_BAD_ARG); + CHK(shtr_transitions_load(shtr, filename, NULL) == RES_BAD_ARG); + CHK(shtr_transitions_load(shtr, filename, &trs) == RES_OK); + + CHK(shtr_transitions_get_count(trs, &n) == RES_OK); + CHK(n == ntransitions); + + CHK(shtr_transitions_get(trs, &trs_list) == RES_OK); + FOR_EACH(i, 0, n) CHK(transition_eq(trs_list+i, transitions+i)); + + CHK(shtr_transitions_ref_put(trs) == RES_OK); +} + +static void +test_transition + (struct shtr* shtr, const struct shtr_transition* tr, const res_T res) +{ + struct shtr_transitions* trs = NULL; + FILE* fp = NULL; + + CHK(fp = tmpfile()); + print_transitions(fp, tr, 1); + rewind(fp); + CHK(shtr_transitions_load_stream(shtr, fp, NULL, &trs) == res); + CHK(fclose(fp) == 0); + + if(res == RES_OK) CHK(shtr_transitions_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 = 0; + test_transition(shtr, &tr, RES_BAD_ARG); + + /* Invalid gamma self */ + tr = tr_ref; tr.gamma_self = 0; + test_transition(shtr, &tr, RES_BAD_ARG); + + /* Invalid lower state energy */ + tr = tr_ref; tr.lower_state_energy = -1; + test_transition(shtr, &tr, RES_BAD_ARG); + + /* Invalid n_air */ + tr = tr_ref; tr.n_air = 0; + 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->n_air > 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* trs = NULL; + const struct shtr_transition* trs_list = NULL; + size_t i, n; + CHK(path); + printf("Loading `%s'.\n", path); + CHK(shtr_transitions_load(shtr, path, &trs) == RES_OK); + CHK(shtr_transitions_get_count(trs, &n) == RES_OK); + printf(" #transitions: %lu\n", n); + + CHK(shtr_transitions_get(trs, &trs_list) == RES_OK); + FOR_EACH(i, 0, n) check_transition(trs_list+i); + CHK(shtr_transitions_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) { + test_load_file(shtr, argv[i]); + } + + CHK(shtr_ref_put(shtr) == RES_OK); + CHK(mem_allocated_size() == 0); + return 0; +}