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:
| M | src/sln.h | | | 2 | +- |
| M | src/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;
}