star-line

Structure for accelerating line importance sampling
git clone git://git.meso-star.fr/star-line.git
Log | Files | Refs | README | LICENSE

commit a95c0a13fa08100f28f1f6ef15bc01fb83d2f33b
parent 72558293f8c1e20deacaccd22fa56fd5ab0d829b
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 28 Jan 2026 17:36:34 +0100

Check the molecule parameters on tree creation

And correct an API breakage due to the update of the Star-HITRAN
constant name SHTR_MAX_MOLECULE_COUNT.

Diffstat:
Msrc/sln.h | 2+-
Msrc/sln_tree.c | 134++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 134 insertions(+), 2 deletions(-)

diff --git a/src/sln.h b/src/sln.h @@ -90,7 +90,7 @@ struct sln_tree_create_args { enum sln_line_profile line_profile; /* Mixture description */ - struct sln_molecule molecules[SHTR_MAX_MOLECULES_COUNT]; + struct sln_molecule molecules[SHTR_MAX_MOLECULE_COUNT]; /* Thermo dynamic properties */ double pressure; /* [atm] */ diff --git a/src/sln_tree.c b/src/sln_tree.c @@ -25,17 +25,146 @@ #include <rsys/algorithm.h> #include <rsys/cstr.h> +#include <rsys/math.h> /******************************************************************************* * Helper functions ******************************************************************************/ +/* Check that the sum of the molecular concentrations is equal to 1 */ +static res_T +check_molecule_concentration + (struct sln_device* sln, + const char* caller, + const struct sln_tree_create_args* args) +{ + int i = 0; + double sum = 0; + ASSERT(sln && caller && args); + + FOR_EACH(i, 0, SHTR_MAX_MOLECULE_COUNT) { + if(i == SHTR_MOLECULE_ID_NULL) continue; + sum += args->molecules[i].concentration; + } + + if(!eq_eps(sum, 1, 1e-6)) { + ERROR(sln, + "%s: the sum of the concentrations of the molecules does not equal 1: %g.\n", + caller, sum); + return RES_BAD_ARG; + } + + return RES_OK; +} + +/* Verify that the isotope abundance are valids */ +static res_T +check_molecule_isotope_abundances + (struct sln_device* sln, + const char* caller, + const struct sln_molecule* molecule) +{ + int i = 0; + double sum = 0; + ASSERT(sln && caller && molecule); + + /* The isotopic abundances are the default ones. Nothing to do */ + if(!molecule->non_default_isotope_abundances) return RES_OK; + + /* The isotopic abundances are not the default ones. + * Verify that they are valid ... */ + FOR_EACH(i, 0, SLN_MAX_ISOTOPES_COUNT) { + if(molecule->isotope_abundances[i] < 0) { + const int isotope_id = i + 1; /* isotope id in [1, 10] */ + ERROR(sln, "%s: invalid abundance of isotopie %d of %s: %g.\n", + caller, isotope_id, shtr_molecule_cstr(i), + molecule->isotope_abundances[i]); + return RES_BAD_ARG; + } + + sum += molecule->isotope_abundances[i]; + } + + /* ... and that their sum equals 1 */ + if(eq_eps(sum, 1, 1e-6)) { + ERROR(sln, "%s: the %s isotope abundances does not sum to 1: %g.\n", + caller, shtr_molecule_cstr(i), sum); + return RES_BAD_ARG; + } + + return RES_OK; +} + +static res_T +check_molecules + (struct sln_device* sln, + const char* caller, + const struct sln_tree_create_args* args) +{ + char molecule_ok[SHTR_MAX_MOLECULE_COUNT] = {0}; + + size_t iline = 0; + size_t nlines = 0; + res_T res = RES_OK; + ASSERT(args->lines); + + res = check_molecule_concentration(sln, caller, args); + if(res != RES_OK) return res; + + /* Interate over the lines to define which molecules has to be checked, i.e., + * the ones used in the mixture */ + SHTR(line_list_get_size(args->lines, &nlines)); + FOR_EACH(iline, 0, nlines) { + struct shtr_line line = SHTR_LINE_NULL; + const struct sln_molecule* molecule = NULL; + + SHTR(line_list_at(args->lines, iline, &line)); + + /* This molecule was already checked */ + if(molecule_ok[line.molecule_id]) continue; + + molecule = args->molecules + line.molecule_id; + + if(molecule->concentration == 0) { + /* A molecular concentration of zero is allowed, but may be a user error, + * as 0 is the default concentration in the tree creation arguments. + * Therefore, warn the user about this value so that they can determine + * whether or not it is an error on their part. */ + WARN(sln, "%s: the concentration of %s is zero\n.\n", + caller, shtr_molecule_cstr(line.molecule_id)); + + } else if(molecule->concentration < 0) { + /* Concentration cannot be negative... */ + ERROR(sln, "%s: invalid %s concentration: %g.\n", + FUNC_NAME, shtr_molecule_cstr(line.molecule_id), + molecule->concentration); + return RES_BAD_ARG; + } + + if(molecule->cutoff <= 0) { + /* ... cutoff either */ + ERROR(sln, "%s: invalid %s cutoff: %g.\n", + caller, shtr_molecule_cstr(line.molecule_id), molecule->cutoff); + return RES_BAD_ARG; + } + + res = check_molecule_isotope_abundances(sln, caller, molecule); + if(res != RES_OK) return res; + + molecule_ok[line.molecule_id] = 1; + } + + return RES_OK; +} + static res_T check_sln_tree_create_args (struct sln_device* sln, const char* caller, const struct sln_tree_create_args* args) { + res_T res = RES_OK; ASSERT(sln && caller); + if(!args) return RES_BAD_ARG; if(!args->metadata) { @@ -44,7 +173,7 @@ check_sln_tree_create_args } if(!args->lines) { - ERROR(sln, "%s: the list of lines is mssing.\n", caller); + ERROR(sln, "%s: the list of lines is missing.\n", caller); return RES_BAD_ARG; } @@ -71,6 +200,9 @@ check_sln_tree_create_args return RES_BAD_ARG; } + res = check_molecules(sln, caller, args); + if(res != RES_OK) return res; + return RES_OK; }