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:
| M | cmake/CMakeLists.txt | | | 74 | +++++++++++++++++++++++++++++++++++++------------------------------------- |
| D | src/shitran.c | | | 101 | ------------------------------------------------------------------------------- |
| D | src/shitran.h | | | 209 | ------------------------------------------------------------------------------- |
| D | src/shitran_c.h | | | 35 | ----------------------------------- |
| D | src/shitran_isotope_metadata.c | | | 632 | ------------------------------------------------------------------------------- |
| D | src/shitran_log.c | | | 127 | ------------------------------------------------------------------------------- |
| D | src/shitran_log.h | | | 73 | ------------------------------------------------------------------------- |
| D | src/shitran_param.c | | | 81 | ------------------------------------------------------------------------------- |
| D | src/shitran_param.h | | | 54 | ------------------------------------------------------ |
| D | src/shitran_transitions.c | | | 308 | ------------------------------------------------------------------------------- |
| A | src/shtr.c | | | 101 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/shtr.h | | | 209 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/shtr_c.h | | | 35 | +++++++++++++++++++++++++++++++++++ |
| A | src/shtr_isotope_metadata.c | | | 632 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/shtr_log.c | | | 127 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/shtr_log.h | | | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/shtr_param.c | | | 81 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/shtr_param.h | | | 54 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/shtr_transitions.c | | | 308 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | src/test_shitran.c | | | 74 | -------------------------------------------------------------------------- |
| D | src/test_shitran_isotope_metadata.c | | | 394 | ------------------------------------------------------------------------------- |
| D | src/test_shitran_transitions.c | | | 258 | ------------------------------------------------------------------------------- |
| A | src/test_shtr.c | | | 74 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/test_shtr_isotope_metadata.c | | | 394 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/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, ¶m_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, ¶m_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, ¶m_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, ¶m_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, ¶m_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, ¶m); \
- 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, ¶m, 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, ¶m_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, ¶m_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, ¶m_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, ¶m_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, ¶m_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, ¶m); \
+ 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, ¶m, 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;
+}