star-hitran

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

commit bd06ecca27908f0e4c2c0d97e571c3a33d617ecb
parent 0137c8983b0702bc42a1274518917f870f0c6d0a
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 14 Feb 2022 12:10:57 +0100

Start implementing transitions parsing

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/shitran.h | 47++++++++++++++++++++++++++++++++++++++++++++---
Asrc/shitran_transitions.c | 277+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 322 insertions(+), 3 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -47,6 +47,7 @@ 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 diff --git a/src/shitran.h b/src/shitran.h @@ -76,9 +76,26 @@ static const struct shitran_molecule SHITRAN_MOLECULE_NULL = #define SHITRAN_MOLECULE_IS_NULL(Molecule) \ ((Molecule)->id == SHITRAN_MOLECULE_NULL.id) -/* Forward declarations */ +struct shitran_transition { + float wavenumber; /* Central wavenumber in vacuum [cm^-1] */ + float intensity; /* Reference intensity [cm^-1/(molec.cm^2)] */ + float gamma_air; /* Air broadening half-width [cm^-1.atm^-1] */ + float gamma_self; /* Self broadening half-width [cm^-1.atm^-1] */ + float lower_state_energy; /* [cm^-1] */ + float n_air; /* Temperature-dependant exponent */ + float delta_air; /* Air-pressure wavenumber shift [cm^-1.atm^-1] */ + + int16_t molecule_id; + int16_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 @@ -135,16 +152,40 @@ shitran_isotope_metadata_get_isotopes_count SHITRAN_API res_T shitran_isotope_metadata_get_molecule (const struct shitran_isotope_metadata* metadata, - const size_t imolecule, /* Index of the molecule in [0, molecules_count[ */ + 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 */ + 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); + END_DECLS #endif /* SHITRAN_H */ diff --git a/src/shitran_transitions.c b/src/shitran_transitions.c @@ -0,0 +1,277 @@ +/* Copyright (C) 2022 CNRS - LMD + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * Copyright (C) 2022 Université Paul Sabatier - IRIT + * Copyright (C) 2022 Université Paul Sabatier - Laplace + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef SHITRAN_TRANSITIONS_H +#define SHITRAN_TRANSITIONS_H + +#include "shitran.h" +#include "shitran_c.h" +#include "shitran_log.h" +#include "shitran_param.h" + +#include <rsys/cstr.h> +#include <rsys/dynamic_array.h> +#include <rsys/text_reader.h> + +/* Generate the dynamic array of transitions */ +#define DARRAY_NAME transition +#define DARRAY_DATA struct shitran_transition +#include <rsys/dynamic_array.h> + +struct shitran_transitions { + /* List of transitions */ + struct darray_transition transitions; + + struct shitran* shitran; + ref_T ref; +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static res_T +create_transitions + (struct shitran* shitran, + struct shitran_transitions** out_transitions) +{ + struct shitran_transitions* transitions = NULL; + res_T res = RES_OK; + ASSERT(shitran && out_transitions); + + transitions = MEM_CALLOC(shitran->allocator, 1, sizeof(*transitions)); + if(!transitions) { + log_err(shitran, "Could not allocate the transitions data structure.\n"); + res = RES_MEM_ERR; + goto error; + } + ref_init(&transitions->ref); + SHITRAN(ref_get(shitran)); + transitions->shitran = shitran; + darray_transition_init(shitran->allocator, &transitions->transitions); + +exit: + *out_transitions = transitions; + return res; +error: + goto exit; +} + +static res_T +parse_transition(struct shitran_transitions* transitions, struct txtrdr* txtrdr) +{ + struct shitran_transition tr = SHITRAN_TRANSITION_NULL; + struct param_desc param = PARAM_DESC_NULL; + struct shitran* shitran = NULL; + char* line = NULL; + char* str = NULL; + char* end = NULL; + char backup; + int molecule_id; + int isotope_id_local; + res_T res = RES_OK; + + ASSERT(transitions && txtrdr); + + line = txtrdr_get_line(txtrdr); + ASSERT(line); + + shitran = transitions->shitran; + param.path = txtrdr_get_name(txtrdr); + param.line = txtrdr_get_line_num(txtrdr); + + str = end = line; + backup = str[0]; + #define NEXT(Size) { \ + *end = backup; \ + str = end; \ + end = str+(Size); \ + backup = *end; \ + *end = '\0'; \ + } (void)0 + #define PARSE(Var, Size, Type, Name, Low, Upp, LowIncl, UppIncl) { \ + NEXT(Size); \ + param.name = (Name); \ + param.low = (Low); \ + param.upp = (Upp); \ + param.is_low_incl = (LowIncl); \ + param.is_upp_incl = (UppIncl); \ + res = parse_param_##Type(shitran, str, &param, Var); \ + if(res != RES_OK) goto error; \ + } (void)0 + + PARSE(&molecule_id, 2, int, "molecule identifier", 0,99,1,1); + tr.molecule_id = (int16_t)molecule_id; + + PARSE(&isotope_id_local, 1, int, "isotope local identifier", 0,9,1,1); + tr.isotope_id_local = (int16_t) + (isotope_id_local == 0 ? 9 : (isotope_id_local - 1)); + + PARSE(&tr.wavenumber, 12, float, "central wavenumber", 0,INF,0,1); + PARSE(&tr.intensity, 10, float, "reference intensity", 0,INF,0,1); + + NEXT(10); /* Skip the Enstein coef */ + + PARSE(&tr.gamma_air, 5, float, "air broadening half-width", 0,INF,0,1); + PARSE(&tr.gamma_self, 5, float, "self broadening half-width", 0,INF,0,1); + PARSE(&tr.lower_state_energy, 10, float, "lower state energy", 0,INF,0,1); + PARSE(&tr.n_air, 4, float, "temperature-dependent exponent", 0,INF,0,1); + PARSE(&tr.delta_air, 8, float, "air-pressure wavenumber shift", -INF,INF,1,1); + + /* Skip the remaining values */ + + #undef NEXT + #undef PARSE + + 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(transitions->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; +} + +#endif /* SHITRAN_TRANSITIONS_H */