star-line

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

commit 592c93404c56ad86f05a48b8f1b5b8df81ed2b35
parent bb6e02fe7c1f0a6a36056e9ae41081e588bdac32
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 28 Jan 2026 11:33:09 +0100

Major overhaul of the source code and build system

The build procedure is written in POSIX make, which the user can
configure via the config.mk file. A pkg-config file is provided to link
the library as an external dependency. In addition to the features
already provided in its CMake alternative, this Makefile supports the
construction of static libraries and provides an uninstall target. In
any case, the main motivation behind its writing is to use a good old
well-established standard with simple features, available on all UNIX
systems, thus simplifying its portability and support while being much
lighter.

Fix API breaks introduced by Star-HITRAN updates that remove the
line_view abstraction. The mixture abstraction therefore no longer
works. Thermodynamic and molecular parameters become input arguments to
the tree itself. The same applies to the list of lines to be partitioned
and the isotopological metadata. This not only greatly simplifies the
API, but also reduces the overall memory footprint.

Indeed, the number of lines can be enormous (up to several million).
Given that loading the list of lines is already difficult in terms of
memory, adding an abstraction (namely "mixture") that selected a subset
of these lines was inappropriate: the lines to be used are simply the
lines provided as input. In addition, line parameters relating to
thermodynamic parameters and molecular properties are no longer
precalculated. Storing more parameters per line is not the solution when
memory pressure is already high. They are therefore recalculated on the
fly, trading computing time for memory space.

The internal logging functions have been replaced by helper macros that
directly use the RSys logging API. This simplifies and streamlines the
code. However, the macros provided use variadic arguments, so the
library is now compiled in C99. The tests are still compiled in C89 to
ensure that the library API does not lose its portability. Note that
colors are removed from logging messages, as some terminals do not
support them.

Diffstat:
M.gitignore | 18+++++++++---------
AMakefile | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig.mk | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asln.pc.in | 12++++++++++++
Msrc/sln.h | 126+++++++++++++++++++++----------------------------------------------------------
Msrc/sln_device.c | 7+------
Msrc/sln_device_c.h | 13+++++++++++++
Msrc/sln_line.c | 194++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/sln_line.h | 15+++++++++------
Dsrc/sln_log.c | 127-------------------------------------------------------------------------------
Dsrc/sln_log.h | 71-----------------------------------------------------------------------
Dsrc/sln_mixture.c | 551-------------------------------------------------------------------------------
Dsrc/sln_mixture_c.h | 76----------------------------------------------------------------------------
Msrc/sln_tree.c | 152++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/sln_tree_build.c | 74+++++++++++++++++++++++++-------------------------------------------------
Msrc/sln_tree_c.h | 18+++++++-----------
Msrc/test_sln_tree.c | 164++++++++++++++++++++++++++++++++++++-------------------------------------------
17 files changed, 629 insertions(+), 1259 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,12 +1,12 @@ -.gitignore -CMakeCache.txt -CMakeFiles -Makefile -tmp -[Bb]uild* -*.sw[po] -*.[ao] +*.[daot] *.orig +*.pc +*.so +*.sw[po] *~ +.config +.gitignore +tags tags - +test_* +!test_*.c diff --git a/Makefile b/Makefile @@ -0,0 +1,187 @@ +# 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/>. + +.POSIX: +.SUFFIXES: # Clean up default inference rules + +include config.mk + +LIBNAME_STATIC = libsln.a +LIBNAME_SHARED = libsln.so +LIBNAME = $(LIBNAME_$(LIB_TYPE)) + +default: library +all: library tests utils + +################################################################################ +# Library building +################################################################################ +SRC =\ + src/sln_device.c\ + src/sln_faddeeva.c\ + src/sln_line.c\ + src/sln_polyline.c\ + src/sln_tree_build.c\ + src/sln_tree.c +OBJ = $(SRC:.c=.o) +DEP = $(SRC:.c=.d) + +CFLAGS_LIB = -std=c99 $(CFLAGS_SO) $(INCS) -DSLN_SHARED_BUILD +LDFLAGS_LIB = $(LDFLAGS_SO) $(LIBS) + +library: .config $(DEP) + @$(MAKE) -fMakefile $$(for i in $(DEP); do echo -f $${i}; done) \ + $$(if [ -n "$(LIBNAME)" ]; then\ + echo "$(LIBNAME)";\ + else\ + echo "$(LIBNAME_SHARED)";\ + fi) + +$(DEP) $(OBJ): config.mk + +$(LIBNAME_SHARED): $(OBJ) + $(CC) $(CFLAGS_LIB) -o $@ $(OBJ) $(LDFLAGS_LIB) + +$(LIBNAME_STATIC): libsln.o + $(AR) -rc $@ $? + $(RANLIB) $@ + +libsln.o: $(OBJ) + $(LD) -r $(OBJ) -o $@ + $(OBJCOPY) $(OCPFLAGS) $@ + +.config: config.mk + $(PKG_CONFIG) --atleast-version $(LBLU_VERSION) lblu + $(PKG_CONFIG) --atleast-version $(RSYS_VERSION) rsys + $(PKG_CONFIG) --atleast-version $(SHTR_VERSION) shtr + echo "config done" > $@ + +.SUFFIXES: .c .d .o +.c.d: + @$(CC) $(CFLAGS_LIB) -MM -MT "$(@:.d=.o) $@" $< -MF $@ + +.c.o: + $(CC) $(CFLAGS_LIB) -c $< -o $@ + +################################################################################ +# Installation +################################################################################ +pkg: + sed -e 's#@PREFIX@#$(PREFIX)#g' \ + -e 's#@VERSION@#$(VERSION)#g' \ + -e 's#@LBLU_VERSION@#$(LBLU_VERSION)#g' \ + -e 's#@SHTR_VERSION@#$(SHTR_VERSION)#g' \ + -e 's#@RSYS_VERSION@#$(RSYS_VERSION)#g' \ + sln.pc.in > sln.pc + +sln-local.pc: sln.pc.in + sed -e '1d' \ + -e 's#^includedir=.*#includedir=./src/#' \ + -e 's#^libdir=.*#libdir=./#' \ + -e 's#@VERSION@#$(VERSION)#g' \ + -e 's#@LBLU_VERSION@#$(LBLU_VERSION)#g' \ + -e 's#@SHTR_VERSION@#$(SHTR_VERSION)#g' \ + -e 's#@RSYS_VERSION@#$(RSYS_VERSION)#g' \ + sln.pc.in > $@ + +install: library pkg utils + install() { mode="$$1"; prefix="$$2"; shift 2; \ + mkdir -p "$${prefix}"; \ + cp "$$@" "$${prefix}"; \ + printf '%s\n' "$${@}" | while read -r i; do \ + chmod "$${mode}" "$${prefix}/$${i##*/}"; \ + done; \ + }; \ + if [ "$(LIB_TYPE)" = "STATIC" ]; then mode=644; else mode=755; fi; \ + install "$${mode}" "$(DESTDIR)$(LIBPREFIX)" $(LIBNAME); \ + install 644 "$(DESTDIR)$(LIBPREFIX)/pkgconfig" sln.pc; \ + install 644 "$(DESTDIR)$(INCPREFIX)/star" src/sln.h; \ + install 644 "$(DESTDIR)$(PREFIX)/share/doc/star-line" COPYING README.md + +uninstall: + rm -f "$(DESTDIR)$(LIBPREFIX)/$(LIBNAME)" + rm -f "$(DESTDIR)$(LIBPREFIX)/pkgconfig/sln.pc" + rm -f "$(DESTDIR)$(BINPREFIX)/sln" + rm -f "$(DESTDIR)$(INCPREFIX)/star/sln.h" + rm -f "$(DESTDIR)$(PREFIX)/share/doc/star-line/COPYING" + rm -f "$(DESTDIR)$(PREFIX)/share/doc/star-line/README.md" + +clean: clean_test + rm -f $(OBJ) $(DEP) $(LIBNAME) + rm -f .config libsln.o sln.pc sln-local.pc + +################################################################################ +# Tests +################################################################################ +TEST_SRC =\ + src/test_sln_device.c\ + src/test_sln_mesh.c\ + src/test_sln_tree.c +TEST_OBJ = $(TEST_SRC:.c=.o) +TEST_DEP = $(TEST_SRC:.c=.d) +TEST_TGT = $(TEST_SRC:.c=.t) + +PKG_CONFIG_LOCAL = PKG_CONFIG_PATH="./:$${PKG_CONFIG_PATH}" $(PKG_CONFIG) +INCS_TEST = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --cflags rsys sln-local shtr) +LIBS_TEST = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --libs rsys sln-local shtr) + +CFLAGS_TEST = -std=c89 $(CFLAGS_EXE) $(INCS_TEST) +LDFLAGS_TEST = $(LDFLAGS_EXE) $(LIBS_TEST) + +tests: library $(TEST_DEP) $(TEST_TGT) + @$(MAKE) -fMakefile \ + $$(for i in $(TEST_DEP); do echo -f"$${i}"; done) \ + $$(for i in $(TEST_TGT); do echo -f"$${i}"; done) \ + test_list + +$(TEST_TGT): + @{ \ + exe="$$(basename "$@" ".t")"; \ + printf '%s: %s\n' "$${exe}" $(@:.t=.o); \ + printf 'test_list: %s\n' "$${exe}"; \ + } > $@ + +$(TEST_DEP): config.mk sln-local.pc + @$(CC) $(CFLAGS_TEST) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@ + +$(TEST_OBJ): config.mk sln-local.pc + $(CC) $(CFLAGS_TEST) -c $(@:.o=.c) -o $@ + +test_sln_device \ +test_sln_mesh \ +test_sln_tree \ +: config.mk sln-local.pc $(LIBNAME) + $(CC) $(CFLAGS_TEST) -o $@ src/$@.o $(LDFLAGS_TEST) + +clean_test: + rm -f $(TEST_DEP) $(TEST_OBJ) $(TEST_TGT) + for i in $(TEST_SRC); do rm -f "$$(basename "$${i}" ".c")"; done + +test: tests + @err=0; \ + for i in $(TEST_SRC); do \ + test="$$(basename "$${i}" ".c")"; \ + printf '%s' "$${test}"; \ + if "./$${test}" > /dev/null 2>&1; then \ + printf '\n'; \ + else \ + printf ': error %s\n' "$$?"; \ + err=$$((err+1)); \ + fi \ + done; \ + [ "$${err}" -eq 0 ] diff --git a/config.mk b/config.mk @@ -0,0 +1,83 @@ +VERSION = 0.0 + +PREFIX = /usr/local +BINPREFIX = $(PREFIX)/bin +LIBPREFIX = $(PREFIX)/lib +INCPREFIX = $(PREFIX)/include +MANPREFIX = $(PREFIX)/share/man + +LIB_TYPE = SHARED +#LIB_TYPE = STATIC + +BUILD_TYPE = RELEASE +#BUILD_TYPE = DEBUG + +################################################################################ +# Tools +################################################################################ +AR = ar +CC = cc +LD = ld +OBJCOPY = objcopy +PKG_CONFIG = pkg-config +RANLIB = ranlib + +################################################################################ +# Dependencies +################################################################################ +PCFLAGS_STATIC = --static +PCFLAGS = $(PCFLAGS_$(LIB_TYPE)) + +LBLU_VERSION = 0.0.1 +RSYS_VERSION = 0.14 +SHTR_VERSION = 0 + +INCS = $$($(PKG_CONFIG) $(PCFLAGS) --cflags lblu rsys shtr) +LIBS = $$($(PKG_CONFIG) $(PCFLAGS) --libs lblu rsys shtr) -lm + +################################################################################ +# Compilation options +################################################################################ +WFLAGS =\ + -Wall\ + -Wcast-align\ + -Wconversion\ + -Wextra\ + -Wmissing-declarations\ + -Wmissing-prototypes\ + -Wshadow + +CFLAGS_HARDENED =\ + -D_FORTIFY_SOURCES=2\ + -fcf-protection=full\ + -fstack-clash-protection\ + -fstack-protector-strong + +CFLAGS_COMMON=\ + -pedantic\ + -fvisibility=hidden\ + -fstrict-aliasing\ + $(CFLAGS_HARDENED)\ + $(WFLAGS) + +CFLAGS_DEBUG = -g $(CFLAGS_COMMON) +CFLAGS_RELEASE = -O2 -DNDEBUG $(CFLAGS_COMMON) +CFLAGS = $(CFLAGS_$(BUILD_TYPE)) + +CFLAGS_SO = $(CFLAGS) -fPIC +CFLAGS_EXE = $(CFLAGS) -fPIE + +################################################################################ +# Linker options +################################################################################ +LDFLAGS_HARDENED = -Wl,-z,relro,-z,now +LDFLAGS_DEBUG = $(LDFLAGS_HARDENED) +LDFLAGS_RELEASE = -s $(LDFLAGS_HARDENED) +LDFLAGS = $(LDFLAGS_$(BUILD_TYPE)) + +LDFLAGS_SO = $(LDFLAGS) -shared -Wl,--no-undefined +LDFLAGS_EXE = $(LDFLAGS) -pie + +OCPFLAGS_DEBUG = --localize-hidden +OCPFLAGS_RELEASE = --localize-hidden --strip-unneeded +BOCPFLAGS = $(OCPFLAGS_$(BUILD_TYPE)) diff --git a/sln.pc.in b/sln.pc.in @@ -0,0 +1,12 @@ +prefix=@PREFIX@ +includedir=${prefix}/include +libdir=${prefix}/lib + +Requires: rsys >= @RSYS_VERSION@ +Requires.private: lblu >= @LBLU_VERSION@, shtr >= @SHTR_VERSION@ +Name: Star-Line +Description: Star Line library +Version: @VERSION@ +Libs: -L${libdir} -lsln +Libs.private: -lm +CFlags: -I${includedir} diff --git a/src/sln.h b/src/sln.h @@ -19,6 +19,7 @@ #ifndef SLN_H #define SLN_H +#include <star/shtr.h> #include <rsys/rsys.h> #include <float.h> @@ -42,7 +43,6 @@ #define SLN(Func) sln_ ## Func #endif -#define SLN_MAX_MOLECULES_COUNT 100 #define SLN_MAX_ISOTOPES_COUNT 10 /* Forward declaration of external data structures */ @@ -54,8 +54,8 @@ struct shtr_isotope_metadata; struct shtr_line_list; enum sln_mesh_type { - SLN_MESH_UPPER, /* Mesh that majorize the underlying lines */ - SLN_MESH_USUAL, /* Mesh of the lines */ + SLN_MESH_UPPER, /* Mesh that majorize the spectrum */ + SLN_MESH_USUAL, /* High-definition spectrum mesh */ SLN_MESH_TYPES_COUNT__ }; @@ -69,65 +69,32 @@ struct sln_device_create_args { struct mem_allocator* allocator; /* NULL <=> use default allocator */ int verbose; /* Verbosity level */ }; -#define SLN_DEVICE_CREATE_ARGS_DEFAULT__ {NULL, NULL, 0} +#define SLN_DEVICE_CREATE_ARGS_DEFAULT__ {NULL,NULL,0} static const struct sln_device_create_args SLN_DEVICE_CREATE_ARGS_DEFAULT = SLN_DEVICE_CREATE_ARGS_DEFAULT__; -struct sln_isotope { - double abundance; - int32_t id_local; /* Isotopes identifier _local_ to the molecule */ -}; -#define SLN_ISOTOPE_NULL__ {0, 0} -static const struct sln_isotope SLN_ISOTOPE_NULL = SLN_ISOTOPE_NULL__; struct sln_molecule { - /* List of isotopes to be taken into account */ - struct sln_isotope isotopes[SLN_MAX_ISOTOPES_COUNT]; - /* 0 <=> select all the isotopes of the molecules with reference abundance */ - size_t nisotopes; - + double isotope_abundances[SLN_MAX_ISOTOPES_COUNT]; double concentration; - double cutoff; /* in cm^-1 */ - - int32_t id; /* Identifier of the molecule into the isotope metadata */ + double cutoff; /* [cm^-1] */ + int non_default_isotope_abundances; }; -#define SLN_MOLECULE_NULL__ {{SLN_ISOTOPE_NULL__}, 0, 0, 0, 0} +#define SLN_MOLECULE_NULL__ {{0},0,0,0} static const struct sln_molecule SLN_MOLECULE_NULL = SLN_MOLECULE_NULL__; -struct sln_mixture_create_args { - /* Isotope metadata and overall list of spectral lines */ +struct sln_tree_create_args { + /* Isotope metadata and lise of spectral lines */ struct shtr_isotope_metadata* metadata; struct shtr_line_list* lines; - /* List of molecules to be taken into account with its associated - * concentration and cutoff */ - struct sln_molecule molecules[SLN_MAX_MOLECULES_COUNT]; - size_t nmolecules; - - double wavenumber_range[2]; /* Spectral range */ - - /* Thermodynamic properties */ - double pressure; /* In atm */ - double temperature; /* In K */ -}; -#define SLN_MIXTURE_CREATE_ARGS_DEFAULT__ \ - {NULL, NULL, {SLN_MOLECULE_NULL__}, 0, {0, DBL_MAX}, 0, 0} -static const struct sln_mixture_create_args SLN_MIXTURE_CREATE_ARGS_DEFAULT = - SLN_MIXTURE_CREATE_ARGS_DEFAULT__; - -struct sln_mixture_desc { - double wavenumber_range[2]; /* Spectral range */ - double pressure; /* In atm */ - double temperature; /* In K */ - size_t nlines; /* Number of partitioned lines */ -}; -#define SLN_MIXTURE_DESC_NULL__ {{0,0},0,0,0} -static const struct sln_mixture_desc SLN_MIXTURE_DESC_NULL = - SLN_MIXTURE_DESC_NULL__; + enum sln_line_profile line_profile; + /* Mixture description */ + struct sln_molecule molecules[SHTR_MAX_MOLECULES_COUNT]; -struct sln_tree_create_args { - /* Max number of lines per leaf */ - size_t max_nlines_per_leaf; + /* Thermo dynamic properties */ + double pressure; /* [atm] */ + double temperature; /* [K] */ /* Hint on the number of vertices around the line center */ size_t nvertices_hint; @@ -137,22 +104,31 @@ struct sln_tree_create_args { float mesh_decimation_err; /* > 0 */ enum sln_mesh_type mesh_type; /* Type of mesh to generate */ - enum sln_line_profile line_profile; + double wavenumber_range[2]; /* [cm^-1, cm^-1] */ }; -#define SLN_TREE_CREATE_ARGS_DEFAULT__ { \ - 1, 16, 0.01f, SLN_MESH_UPPER, SLN_LINE_PROFILE_VOIGT \ +#define SLN_TREE_CREATE_ARGS_DEFAULT__ { \ + NULL, /* metadata */ \ + NULL, /* line list */ \ + SLN_LINE_PROFILE_VOIGT, /* Profile */ \ + {SLN_MOLECULE_NULL__}, /* Molecules */ \ + 0, /* Pressure [atm] */ \ + 0, /* Temperature [K] */ \ + 16, /* #vertices hint */ \ + 0.01f, /* Mesh decimation error */ \ + SLN_MESH_UPPER, /* Mesh type */ \ + {-DBL_MAX, DBL_MAX} /* Spectral range */ \ } static const struct sln_tree_create_args SLN_TREE_CREATE_ARGS_DEFAULT = SLN_TREE_CREATE_ARGS_DEFAULT__; struct sln_tree_desc { - size_t max_nlines_per_leaf; /* max #lines per leaf */ + size_t max_nlines_per_leaf; float mesh_decimation_err; enum sln_mesh_type mesh_type; enum sln_line_profile line_profile; }; -#define SLN_TREE_DESC_NULL__ { \ - 0, 0, SLN_MESH_TYPES_COUNT__, SLN_LINE_PROFILES_COUNT__ \ +#define SLN_TREE_DESC_NULL__ { \ + 0, 0, SLN_MESH_TYPES_COUNT__, SLN_LINE_PROFILES_COUNT__ \ } static const struct sln_tree_desc SLN_TREE_DESC_NULL = SLN_TREE_DESC_NULL__; @@ -172,7 +148,6 @@ static const struct sln_mesh SLN_MESH_NULL = SLN_MESH_NULL__; /* Forward declarations of opaque data structures */ struct sln_device; -struct sln_mixture; struct sln_node; struct sln_tree; @@ -193,46 +168,11 @@ sln_device_ref_put (struct sln_device* sln); /******************************************************************************* - * Mixture API - ******************************************************************************/ -SLN_API res_T -sln_mixture_create - (struct sln_device* sln, - const struct sln_mixture_create_args* args, - struct sln_mixture** mixture); - -/* Load a mixture serialized with the "shtr_mixture_write" function */ -SLN_API res_T -sln_mixture_create_from_stream - (struct sln_device* sln, - struct shtr* shtr, - FILE* stream, - struct sln_mixture** mixture); - -SLN_API res_T -sln_mixture_ref_get - (struct sln_mixture* mixture); - -SLN_API res_T -sln_mixture_ref_put - (struct sln_mixture* mixture); - -SLN_API res_T -sln_mixture_get_desc - (const struct sln_mixture* mixture, - struct sln_mixture_desc* desc); - -SLN_API res_T -sln_mixture_write - (const struct sln_mixture* mixture, - FILE* stream); - -/******************************************************************************* * Tree API ******************************************************************************/ SLN_API res_T sln_tree_create - (struct sln_mixture* mixture, + (struct sln_device* dev, const struct sln_tree_create_args* args, struct sln_tree** tree); @@ -280,7 +220,7 @@ sln_node_get_line (const struct sln_tree* tree, const struct sln_node* node, const size_t iline, - const struct shtr_line** line); + struct shtr_line* line); SLN_API res_T sln_node_get_mesh diff --git a/src/sln_device.c b/src/sln_device.c @@ -18,7 +18,6 @@ #include "sln.h" #include "sln_device_c.h" -#include "sln_log.h" /******************************************************************************* * Helper functions @@ -70,11 +69,7 @@ sln_device_create ref_init(&sln->ref); sln->allocator = allocator; sln->verbose = args->verbose; - if(args->logger) { - sln->logger = args->logger; - } else { - setup_log_default(sln); - } + sln->logger = args->logger ? args->logger : LOGGER_DEFAULT; exit: if(out_sln) *out_sln = sln; diff --git a/src/sln_device_c.h b/src/sln_device_c.h @@ -22,6 +22,19 @@ #include <rsys/logger.h> #include <rsys/ref_count.h> +#define MSG_INFO_PREFIX "" +#define MSG_ERROR_PREFIX "error: " +#define MSG_WARNING_PREFIX "warning: " + +/* Helper macros for logging */ +#define LOG__(Dev, Lvl, Type, ...) { \ + if ((Dev)->verbose >= (Lvl)) \ + logger_print((Dev)->logger, Type, __VA_ARGS__); \ +} (void)0 +#define ERROR(Dev, ...) LOG__(Dev, 1, LOG_ERROR, MSG_ERROR_PREFIX __VA_ARGS__) +#define WARN(Dev, ...) LOG__(Dev, 2, LOG_WARNING, MSG_WARNING_PREFIX __VA_ARGS__) +#define INFO(Dev, ...) LOG__(Dev, 3, LOG_OUTPUT, MSG_INFO_PREFIX __VA_ARGS__) + struct mem_allocator; struct sln_device { diff --git a/src/sln_line.c b/src/sln_line.c @@ -20,8 +20,6 @@ #include "sln_device_c.h" #include "sln_line.h" -#include "sln_log.h" -#include "sln_mixture_c.h" #include "sln_tree_c.h" #include <lblu.h> @@ -70,7 +68,7 @@ line_intensity static res_T line_profile_factor - (const struct sln_mixture* mixture, + (const struct sln_tree* tree, const struct shtr_line* shtr_line, double* out_profile_factor) { @@ -79,7 +77,7 @@ line_profile_factor const struct shtr_isotope* isotope = NULL; /* Mixture parameters */ - const struct molecule_params* mol_params = NULL; + const struct sln_molecule* mol_params = NULL; /* Miscellaneous */ double iso_abundance; @@ -95,31 +93,32 @@ line_profile_factor int isoid; /* Isotope id local to its molecule */ res_T res = RES_OK; - ASSERT(mixture && shtr_line && out_profile_factor); + ASSERT(tree && shtr_line && out_profile_factor); /* Fetch the molecule data */ - mol_params = mixture_get_molecule_params(mixture, shtr_line->molecule_id); + mol_params = tree->args.molecules + shtr_line->molecule_id; SHTR(isotope_metadata_find_molecule - (mixture->metadata, shtr_line->molecule_id, &molecule)); + (tree->args.metadata, shtr_line->molecule_id, &molecule)); ASSERT(!SHTR_MOLECULE_IS_NULL(&molecule)); ASSERT(molecule.nisotopes > (size_t)shtr_line->isotope_id_local); isotope = molecule.isotopes + shtr_line->isotope_id_local; - nu_c = line_center(shtr_line, mixture->pressure); + nu_c = line_center(shtr_line, tree->args.pressure); /* Compute the intensity */ - Ps = mixture->pressure * mol_params->concentration; - density = (AVOGADRO_NUMBER * Ps) / (PERFECT_GAZ_CONSTANT * mixture->temperature); + Ps = tree->args.pressure * mol_params->concentration; + density = (AVOGADRO_NUMBER * Ps); + density = density / (PERFECT_GAZ_CONSTANT * tree->args.temperature); density = density * 1e-6; /* Convert in molec.cm^-3 */ /* Compute the partition function. TODO precompute it for molid/isoid */ Q_Tref = isotope->Q296K; molid = shtr_line->molecule_id; isoid = shtr_line->isotope_id_local+1/*Local indices start at 1 in BD_TIPS*/; - T = mixture->temperature; + T = tree->args.temperature; BD_TIPS_2017(&molid, &T, &isoid, &gj, &Q_T); if(Q_T <= 0) { - log_err(mixture->sln, + ERROR(tree->sln, "molecule %d: isotope %d: invalid partition function at T=%g\n", molid, isoid, T); res = RES_BAD_ARG; @@ -129,14 +128,14 @@ line_profile_factor Q = Q_Tref/Q_T; /* Compute the intensity */ - iso_abundance = mol_params->isotopes_abundance[shtr_line->isotope_id_local]; - if(iso_abundance < 0) { /* Use default abundance */ + if(!mol_params->non_default_isotope_abundances) { /* Use default abundance */ intensity_ref = shtr_line->intensity; } else { + iso_abundance = mol_params->isotope_abundances[shtr_line->isotope_id_local]; intensity_ref = shtr_line->intensity/isotope->abundance*iso_abundance; } intensity = line_intensity(intensity_ref, shtr_line->lower_state_energy, Q, - mixture->temperature, T_REF, nu_c); + tree->args.temperature, T_REF, nu_c); profile_factor = 1.e2 * density * intensity; /* In m^-1.cm^-1 */ @@ -184,32 +183,36 @@ error: * only the set of wavenumbers from the line center to its upper bound. */ static res_T regular_mesh_fragmented - (const struct sln_mixture* mixture, + (const struct sln_tree* tree, const struct line* line, - const struct molecule_params* mol_params, - const double fragment_length, const size_t nvertices, struct darray_double* wavenumbers) /* List of issued vertices */ { /* Fragment parameters */ + double fragment_length = 0; double fragment_nu_min = 0; /* Lower bound of the fragment */ size_t fragment_nvtx = 0; /* #vertices into the fragment */ /* Miscellaneous */ + const struct sln_molecule* mol_params = NULL; double line_nu_min = 0; /* In cm^-1 */ double line_nu_max = 0; /* In cm^-1 */ res_T res = RES_OK; - ASSERT(mixture && line && mol_params && wavenumbers); - ASSERT(fragment_length > 0); + ASSERT(tree && line && wavenumbers); ASSERT(IS_POW2(nvertices)); - ASSERT(line->wavenumber + mol_params->cutoff > mixture->wavenumber_range[0]); - ASSERT(line->wavenumber - mol_params->cutoff < mixture->wavenumber_range[1]); + + /* TODO check mol params */ + mol_params = tree->args.molecules + line->molecule_id; /* Compute the spectral range of the line from its center to its cutoff */ line_nu_min = line->wavenumber; line_nu_max = line->wavenumber + mol_params->cutoff; + /* Define the size of a fragment as the width of the line at mid-height for a + * Lorentz profile */ + fragment_length = line->gamma_l; + /* Define the number of vertices for the first interval in [nu, gamma_l] */ fragment_nu_min = line_nu_min; fragment_nvtx = MMAX(nvertices/2, 2); @@ -233,26 +236,25 @@ regular_mesh_fragmented exit: return res; error: - log_err(mixture->sln, "Error meshing the line -- %s.\n", res_to_cstr(res)); + ERROR(tree->sln, "Error meshing the line -- %s.\n", res_to_cstr(res)); goto exit; } +/* Calculate line values for a set of wave numbers */ static res_T eval_mesh - (const struct sln_mixture* mixture, - const size_t iline, + (const struct sln_tree* tree, + const struct line* line, const struct darray_double* wavenumbers, - const enum sln_line_profile line_profile, struct darray_double* values) { const double* nu = NULL; double* ha = NULL; - const struct shtr_line* shtr_line = NULL; size_t ivertex, nvertices; double range[2]; double cutoff; res_T res = RES_OK; - ASSERT(mixture && wavenumbers && values); + ASSERT(tree && line && wavenumbers && values); nvertices = darray_double_size_get(wavenumbers); ASSERT(nvertices); @@ -260,8 +262,6 @@ eval_mesh res = darray_double_resize(values, nvertices); if(res != RES_OK) goto error; - SHTR(line_view_get_line(mixture->line_view, iline, &shtr_line)); - /* Calculate the spectral range in which the vertices should be evaluated. * Recall that a line being symmetrical in its center, we will only evaluate * its upper half. Anyway, note that a line clipped by the spectral range is @@ -269,10 +269,10 @@ eval_mesh * to emit all the vertices needed to mesh the upper half _and_ the lower * half of a possibly clipped line */ cutoff = MMAX - (shtr_line->wavenumber - mixture->wavenumber_range[0], - mixture->wavenumber_range[1] - shtr_line->wavenumber); - range[0] = MMIN(shtr_line->wavenumber, mixture->wavenumber_range[0]); - range[1] = shtr_line->wavenumber + cutoff; + (line->wavenumber - tree->args.wavenumber_range[0], + tree->args.wavenumber_range[1] - line->wavenumber); + range[0] = MMIN(line->wavenumber, tree->args.wavenumber_range[0]); + range[1] = line->wavenumber + cutoff; nu = darray_double_cdata_get(wavenumbers); ha = darray_double_data_get(values); @@ -288,15 +288,14 @@ eval_mesh if(nu_next < range[0] || range[1] < nu_prev) { ha[ivertex] = -1; /* Clip */ } else { - ha[ivertex] = line_value(mixture, iline, line_profile, nu_curr); + ha[ivertex] = line_value(tree, line, nu_curr); } } exit: return res; error: - log_err(mixture->sln, "Error evaluating the line mesh -- %s.\n", - res_to_cstr(res)); + ERROR(tree->sln, "Error evaluating the line mesh -- %s.\n", res_to_cstr(res)); goto exit; } @@ -377,16 +376,15 @@ next_vertex_value static res_T save_line_mesh (struct sln_tree* tree, - const size_t iline, - const struct molecule_params* mol_params, - const double spectral_range[2], + const struct line* line, const struct darray_double* wavenumbers, const struct darray_double* values, size_t vertices_range[2]) /* Range into which the line vertices are saved */ { - const struct line* line = NULL; + const struct sln_molecule* mol_params = NULL; const double* wnums = NULL; const double* vals = NULL; + const double* spectral_range = NULL; size_t nvertices; size_t nwavenumbers; size_t line_nvertices; @@ -394,13 +392,12 @@ save_line_mesh size_t i; res_T res = RES_OK; - ASSERT(tree && mol_params && wavenumbers && values && vertices_range); + ASSERT(tree && line && wavenumbers && values && vertices_range); ASSERT(darray_double_size_get(wavenumbers) == darray_double_size_get(values)); - ASSERT(spectral_range && spectral_range[0] <= spectral_range[1]); - line = darray_line_cdata_get(&tree->mixture->lines) + iline; nvertices = darray_vertex_size_get(&tree->vertices); nwavenumbers = darray_double_size_get(wavenumbers); + spectral_range = tree->args.wavenumber_range; /* Compute the overall number of vertices of the line */ line_nvertices = nwavenumbers @@ -409,16 +406,14 @@ save_line_mesh /* Allocate the list of line vertices */ res = darray_vertex_resize(&tree->vertices, nvertices + line_nvertices); - if(res != RES_OK) { - log_err(tree->mixture->sln, "Error allocating the line vertices -- %s.\n", - res_to_cstr(res)); - goto error; - } + if(res != RES_OK) goto error; wnums = darray_double_cdata_get(wavenumbers); vals = darray_double_cdata_get(values); i = nvertices; + mol_params = tree->args.molecules + line->molecule_id; + #define MIRROR(Nu) (2*line->wavenumber - (Nu)) /* Emit the 1st vertex for the lower bound of the spectral range if the line @@ -428,7 +423,7 @@ save_line_mesh const double nu = spectral_range[0]; double ha = 0; - switch(tree->mesh_type) { + switch(tree->args.mesh_type) { case SLN_MESH_UPPER: ha = nu > line->wavenumber ? next_vertex_value(nu, wavenumbers, values) @@ -436,7 +431,7 @@ save_line_mesh break; case SLN_MESH_USUAL: - ha = line_value(tree->mixture, iline, tree->line_profile, nu); + ha = line_value(tree, line, nu); break; default: FATAL("Unreachable code.\n"); break; @@ -493,7 +488,7 @@ save_line_mesh const double nu = spectral_range[1]; double ha = 0; - switch(tree->mesh_type) { + switch(tree->args.mesh_type) { case SLN_MESH_UPPER: ha = nu > line->wavenumber ? next_vertex_value(nu, wavenumbers, values) @@ -501,7 +496,7 @@ save_line_mesh break; case SLN_MESH_USUAL: - ha = line_value(tree->mixture, iline, tree->line_profile, nu); + ha = line_value(tree, line, nu); break; default: FATAL("Unreachable code.\n"); break; @@ -526,45 +521,49 @@ exit: return res; error: darray_vertex_resize(&tree->vertices, nvertices); + ERROR(tree->sln, "Error while recording line vertices -- %s.\n", + res_to_cstr(res)); goto exit; } - /******************************************************************************* * Local function ******************************************************************************/ res_T -line_setup(struct sln_mixture* mixture, const size_t iline) +line_setup + (const struct sln_tree* tree, + const size_t iline, + struct line* line) { struct shtr_molecule molecule = SHTR_MOLECULE_NULL; - const struct shtr_line* shtr_line = NULL; - struct line* line = NULL; + struct shtr_line shtr_line = SHTR_LINE_NULL; double molar_mass = 0; /* In kg.mol^-1 */ - const struct molecule_params* mol_params = NULL; + const struct sln_molecule* mol_params = NULL; res_T res = RES_OK; - ASSERT(mixture && iline < darray_line_size_get(&mixture->lines)); - line = darray_line_data_get(&mixture->lines) + iline; + ASSERT(tree && line); - SHTR(line_view_get_line(mixture->line_view, iline, &shtr_line)); + SHTR(line_list_at(tree->args.lines, iline, &shtr_line)); SHTR(isotope_metadata_find_molecule - (mixture->metadata, shtr_line->molecule_id, &molecule)); + (tree->args.metadata, shtr_line.molecule_id, &molecule)); ASSERT(!SHTR_MOLECULE_IS_NULL(&molecule)); - ASSERT(molecule.nisotopes > (size_t)shtr_line->isotope_id_local); - mol_params = mixture_get_molecule_params(mixture, shtr_line->molecule_id); + ASSERT(molecule.nisotopes > (size_t)shtr_line.isotope_id_local); + + mol_params = tree->args.molecules + shtr_line.molecule_id; /* Convert the molar mass of the line from g.mol^-1 to kg.mol^-1 */ - molar_mass = molecule.isotopes[shtr_line->isotope_id_local].molar_mass*1e-3; + molar_mass = molecule.isotopes[shtr_line.isotope_id_local].molar_mass*1e-3; /* Setup the line */ - res = line_profile_factor(mixture, shtr_line, &line->profile_factor); + res = line_profile_factor(tree, &shtr_line, &line->profile_factor); if(res != RES_OK) goto error; - line->wavenumber = line_center(shtr_line, mixture->pressure); + line->wavenumber = line_center(&shtr_line, tree->args.pressure); line->gamma_d = sln_compute_line_half_width_doppler - (line->wavenumber, molar_mass, mixture->temperature); - line->gamma_l = sln_compute_line_half_width_lorentz(shtr_line->gamma_air, - shtr_line->gamma_self, mixture->pressure, mol_params->concentration); + (line->wavenumber, molar_mass, tree->args.temperature); + line->gamma_l = sln_compute_line_half_width_lorentz(shtr_line.gamma_air, + shtr_line.gamma_self, tree->args.pressure, mol_params->concentration); + line->molecule_id = shtr_line.molecule_id; exit: return res; @@ -574,29 +573,23 @@ error: double line_value - (const struct sln_mixture* mixture, - const size_t iline, - const enum sln_line_profile line_profile, + (const struct sln_tree* tree, + const struct line* line, const double wavenumber) { - const struct line* line = NULL; - const struct shtr_line* shtr_line = NULL; - const struct molecule_params* mol_params = NULL; + const struct sln_molecule* mol_params = NULL; double profile = 0; - ASSERT(mixture && iline < darray_line_size_get(&mixture->lines)); + ASSERT(tree && line); /* Retrieve the molecular parameters of the line to be mesh */ - SHTR(line_view_get_line(mixture->line_view, iline, &shtr_line)); - mol_params = mixture_get_molecule_params(mixture, shtr_line->molecule_id); - - line = darray_line_cdata_get(&mixture->lines) + iline; + mol_params = tree->args.molecules + line->molecule_id; if(wavenumber < line->wavenumber - mol_params->cutoff || wavenumber > line->wavenumber + mol_params->cutoff) { return 0; } - switch(line_profile) { + switch(tree->args.line_profile) { case SLN_LINE_PROFILE_VOIGT: profile = sln_compute_voigt_profile (wavenumber, line->wavenumber, line->gamma_d, line->gamma_l); @@ -611,23 +604,29 @@ line_mesh (struct sln_tree* tree, const size_t iline, const size_t nvertices_hint, - size_t vertices_range[2]) + size_t vertices_range[2]) /* out */ { + /* The line */ + struct line line = LINE_NULL; + + /* Temporary mesh */ struct darray_double values; /* List of evaluated values */ struct darray_double wavenumbers; /* List of considered wavenumbers */ - const struct shtr_line* shtr_line = NULL; - const struct molecule_params* mol_params = NULL; - const struct line* line = NULL; size_t nvertices_adjusted = 0; /* computed from nvertices_hint */ + + /* Miscellaneous */ res_T res = RES_OK; + + /* Pre-conditions */ ASSERT(tree && nvertices_hint); - ASSERT(iline < darray_line_size_get(&tree->mixture->lines)); - line = darray_line_cdata_get(&tree->mixture->lines) + iline; - SHTR(line_view_get_line(tree->mixture->line_view, iline, &shtr_line)); + darray_double_init(tree->sln->allocator, &values); + darray_double_init(tree->sln->allocator, &wavenumbers); - darray_double_init(tree->mixture->sln->allocator, &values); - darray_double_init(tree->mixture->sln->allocator, &wavenumbers); + /* Setup the line wrt molecule concentration, isotope abundance, temperature + * and pression */ + res = line_setup(tree, iline, &line); + if(res != RES_OK) goto error; /* Adjust the hint on the number of vertices. This is not actually the real * number of vertices but an adjusted hint on it. This new value ensures that @@ -636,19 +635,15 @@ line_mesh (nvertices_hint, MIN_NVERTICES_HINT, MAX_NVERTICES_HINT); nvertices_adjusted = round_up_pow2(nvertices_adjusted); - /* Retrieve the molecular parameters of the line to be mesh */ - mol_params = mixture_get_molecule_params(tree->mixture, shtr_line->molecule_id); - /* Emit the vertex coordinates, i.e. the wavenumbers */ - res = regular_mesh_fragmented(tree->mixture, line, mol_params, line->gamma_l, - nvertices_adjusted, &wavenumbers); + res = regular_mesh_fragmented(tree, &line, nvertices_adjusted, &wavenumbers); if(res != RES_OK) goto error; /* Evaluate the mesh vertices, i.e. define the line value for the list of * wavenumbers */ - eval_mesh(tree->mixture, iline, &wavenumbers, tree->line_profile, &values); + eval_mesh(tree, &line, &wavenumbers, &values); - switch(tree->mesh_type) { + switch(tree->args.mesh_type) { case SLN_MESH_UPPER: snap_mesh_to_upper_bound(&wavenumbers, &values); break; @@ -656,8 +651,7 @@ line_mesh default: FATAL("Unreachable code.\n"); break; } - res = save_line_mesh(tree, iline, mol_params, tree->mixture->wavenumber_range, - &wavenumbers, &values, vertices_range); + res = save_line_mesh(tree, &line, &wavenumbers, &values, vertices_range); if(res != RES_OK) goto error; exit: diff --git a/src/sln_line.h b/src/sln_line.h @@ -30,7 +30,10 @@ struct line { double profile_factor; /* m^-1.cm^-1 (1e2*density*intensity) */ double gamma_d; /* Doppler half width */ double gamma_l; /* Lorentz half width */ + enum shtr_molecule_id molecule_id; }; +#define LINE_NULL__ {0} +static const struct line LINE_NULL = LINE_NULL__; /* Forward declaration */ struct sln_mixture; @@ -48,14 +51,14 @@ line_center extern LOCAL_SYM res_T line_setup - (struct sln_mixture* mixture, - const size_t iline); + (const struct sln_tree* tree, + const size_t iline, + struct line* line); extern LOCAL_SYM double line_value - (const struct sln_mixture* mixture, - const size_t iline, - const enum sln_line_profile profile, + (const struct sln_tree* tree, + const struct line* line, const double wavenumber); extern LOCAL_SYM res_T @@ -64,6 +67,6 @@ line_mesh const size_t iline, const size_t nvertices_hint, /* Range of generated line vertices. Upper bound is inclusive */ - size_t vertices_range[2]); + size_t vertices_range[2]); /* out */ #endif /* SLN_LINE_H */ diff --git a/src/sln_log.c b/src/sln_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 "sln_device_c.h" -#include "sln_log.h" - -#include <rsys/cstr.h> -#include <rsys/logger.h> - -#include <stdarg.h> - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static INLINE void -log_msg - (const struct sln_device* sln, - const enum log_type stream, - const char* msg, - va_list vargs) -{ - ASSERT(sln && msg); - if(sln->verbose) { - res_T res; (void)res; - res = logger_vprint(sln->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 sln_device* sln) -{ - res_T res = RES_OK; - ASSERT(sln); - - res = logger_init(sln->allocator, &sln->logger__); - if(res != RES_OK) { - if(sln->verbose) { - fprintf(stderr, - MSG_ERROR_PREFIX - "Could not setup the default logger for the Star-Line library -- %s.\n", - res_to_cstr(res)); - } - goto error; - } - logger_set_stream(&sln->logger__, LOG_OUTPUT, print_info, NULL); - logger_set_stream(&sln->logger__, LOG_ERROR, print_err, NULL); - logger_set_stream(&sln->logger__, LOG_WARNING, print_warn, NULL); - sln->logger = &sln->logger__; - -exit: - return res; -error: - goto exit; -} - -void -log_info(const struct sln_device* sln, const char* msg, ...) -{ - va_list vargs_list; - ASSERT(sln && msg); - - va_start(vargs_list, msg); - log_msg(sln, LOG_OUTPUT, msg, vargs_list); - va_end(vargs_list); -} - -void -log_err(const struct sln_device* sln, const char* msg, ...) -{ - va_list vargs_list; - ASSERT(sln && msg); - - va_start(vargs_list, msg); - log_msg(sln, LOG_ERROR, msg, vargs_list); - va_end(vargs_list); -} - -void -log_warn(const struct sln_device* sln, const char* msg, ...) -{ - va_list vargs_list; - ASSERT(sln && msg); - - va_start(vargs_list, msg); - log_msg(sln, LOG_WARNING, msg, vargs_list); - va_end(vargs_list); -} diff --git a/src/sln_log.h b/src/sln_log.h @@ -1,71 +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 SLN_LOG_H -#define SLN_LOG_H - -#include <rsys/rsys.h> - -#define MSG_INFO_PREFIX "Star-Line:\x1b[1m\x1b[32minfo\x1b[0m: " -#define MSG_ERROR_PREFIX "Star-Line:\x1b[1m\x1b[31merror\x1b[0m: " -#define MSG_WARNING_PREFIX "Star-Line:\x1b[1m\x1b[33mwarning\x1b[0m: " - -struct sln_device; -struct logger; - -extern LOCAL_SYM res_T -setup_log_default - (struct sln_device* sln); - -/* Conditionally log a message on the LOG_OUTPUT stream of the sln logger, - * with respect to its verbose flag */ -extern LOCAL_SYM void -log_info - (const struct sln_device* sln, - const char* msg, - ...) -#ifdef COMPILER_GCC - __attribute((format(printf, 2, 3))) -#endif -; - -/* Conditionally log a message on the LOG_ERROR stream of the sln logger, - * with respect to its verbose flag */ -extern LOCAL_SYM void -log_err - (const struct sln_device* sln, - const char* msg, - ...) -#ifdef COMPILER_GCC - __attribute((format(printf, 2, 3))) -#endif -; - -/* Conditionally log a message on the LOG_WARNING stream of the sln logger, - * with respect to its verbose flag */ -extern LOCAL_SYM void -log_warn - (const struct sln_device* sln, - const char* msg, - ...) -#ifdef COMPILER_GCC - __attribute((format(printf, 2, 3))) -#endif -; - -#endif /* SLN_LOG_H */ diff --git a/src/sln_mixture.c b/src/sln_mixture.c @@ -1,551 +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 "sln.h" -#include "sln_device_c.h" -#include "sln_log.h" -#include "sln_mixture_c.h" - -#include <star/shtr.h> -#include <rsys/cstr.h> - -STATIC_ASSERT(SLN_MAX_MOLECULES_COUNT <= SHTR_MAX_MOLECULES_COUNT, - Invalid_SLN_MAX_MOLECULES_COUNT); -STATIC_ASSERT(SLN_MAX_ISOTOPES_COUNT <= SHTR_MAX_ISOTOPES_COUNT, - Invalid_SLN_MAX_ISOTOPES_COUNT); - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static res_T -check_sln_isotope - (struct sln_device* sln, - const char* caller, - const int32_t mol_id, - const size_t mol_nisos, - const struct sln_isotope* isotope) -{ - ASSERT(sln && caller && mol_nisos && isotope); - - if(isotope->id_local >= SLN_MAX_ISOTOPES_COUNT) { - log_err(sln, - "%s: molecule %d: isotope %d: invalid isotope local identifier. " - "It must be less than %d.\n", - caller, mol_id, isotope->id_local, SLN_MAX_ISOTOPES_COUNT); - return RES_BAD_ARG; - } - - if((size_t)isotope->id_local >= mol_nisos) { - log_warn(sln, - "%s: molecule %d: the isotope local index %d exceeds " - "the overall number of isotopes %lu.\n", - caller, mol_id, isotope->id_local, mol_nisos); - return RES_OK; /* Do not check the others isotope parameters */ - } - - if(isotope->abundance < 0) { - log_err(sln, - "%s: molecule %d: isotope %d: invalid abundance %g.\n", - caller, mol_id, isotope->id_local, isotope->abundance); - return RES_BAD_ARG; - } - - return RES_OK; -} - -static res_T -check_sln_molecule - (struct sln_device* sln, - const char* caller, - struct shtr_isotope_metadata* metadata, - const struct sln_molecule* molecule) -{ - double abundances_sum = 0; - struct shtr_molecule mol = SHTR_MOLECULE_NULL; - size_t i; - ASSERT(sln && caller && metadata && molecule); - - if(molecule->id >= SLN_MAX_MOLECULES_COUNT) { - log_err(sln, - "%s: molecule %d: invalid molecule indentifier. It must be less than %d.\n", - caller, molecule->id, SLN_MAX_MOLECULES_COUNT); - return RES_BAD_ARG; - } - - SHTR(isotope_metadata_find_molecule(metadata, molecule->id, &mol)); - if(SHTR_MOLECULE_IS_NULL(&mol)) { - log_warn(sln, - "%s: the molecule %d is not found in the isotope metadata.\n", - caller, molecule->id); - return RES_OK; /* Do not check the others molecule parameters */ - } - - if(molecule->nisotopes >= SLN_MAX_ISOTOPES_COUNT) { - log_err(sln, - "%s: too many isotopes %lu regarding the maximum number of per molecule " - "isotopes (SLN_MAX_ISOTOPES_COUNT = %lu).\n", - caller, - (unsigned long)molecule->nisotopes, - (unsigned long)SLN_MAX_ISOTOPES_COUNT); - return RES_BAD_ARG; - } - - abundances_sum = 0; - FOR_EACH(i, 0, molecule->nisotopes) { - const res_T res = check_sln_isotope - (sln, caller, molecule->id, molecule->nisotopes, molecule->isotopes+i); - if(res != RES_OK) return res; - abundances_sum += molecule->isotopes[i].abundance; - } - - if(abundances_sum > 1) { - log_err(sln, - "%s: molecule %d: the sum of the isotope abundances %g is invalid. " - "It must be less than or equal to 1.\n", - caller, molecule->id, abundances_sum); - return RES_BAD_ARG; - } - - if(molecule->concentration < 0) { - log_err(sln, "%s: molecule %d: invalid concentration %g.\n", - caller, molecule->id, molecule->concentration); - return RES_BAD_ARG; - } - - if(molecule->cutoff <= 0) { - log_err(sln, "%s: molecule %d: invalid line cutoff %g.\n", - caller, molecule->id, molecule->concentration); - return RES_BAD_ARG; - } - - return RES_OK; -} - -static res_T -check_sln_mixture_create_args - (struct sln_device* sln, - const char* caller, - const struct sln_mixture_create_args* args) -{ - double concentrations_sum = 0; - size_t i; - ASSERT(sln && caller); - if(!args) return RES_BAD_ARG; - - /* Check lines data base */ - if(!args->metadata || !args->lines) { - return RES_BAD_ARG; - } - - /* Check the list of molecules to be taken into account */ - if(args->nmolecules >= SLN_MAX_MOLECULES_COUNT) { - log_err(sln, - "%s: too many molecules %lu regarding the maximum number of molecules " - "(SLN_MAX_MOLECULES_COUNT = %lu).\n", - caller, - (unsigned long)args->nmolecules, - (unsigned long)SLN_MAX_MOLECULES_COUNT); - return RES_BAD_ARG; - } - - concentrations_sum = 0; - FOR_EACH(i, 0, args->nmolecules) { - const res_T res = check_sln_molecule - (sln, caller, args->metadata, args->molecules+i); - if(res != RES_OK) return res; - concentrations_sum += args->molecules[i].concentration; - } - - if(concentrations_sum > 1) { - log_err(sln, - "%s: the sum of the molecule concentrations %g is invalid. " - "It must be less than or equal to 1.\n", - caller, concentrations_sum); - return RES_BAD_ARG; - } - - if(args->pressure < 0) { - log_err(sln, "%s: invalid pressure %g.\n", caller, args->pressure); - return RES_BAD_ARG; - } - - if(args->temperature < 0) { - log_err(sln, "%s: invalid temperature %g.\n", caller, args->temperature); - return RES_BAD_ARG; - } - - return RES_OK; -} - -static res_T -create_mixture - (struct sln_device* sln, - const char* caller, - struct sln_mixture** out_mixture) -{ - struct sln_mixture* mixture = NULL; - res_T res = RES_OK; - ASSERT(sln && caller && out_mixture); - - mixture = MEM_CALLOC(sln->allocator, 1, sizeof(struct sln_mixture)); - if(!mixture) { - log_err(sln, "%s: could not allocate the mixture data structure.\n", - caller); - res = RES_MEM_ERR; - goto error; - } - ref_init(&mixture->ref); - SLN(device_ref_get(sln)); - mixture->sln = sln; - darray_line_init(sln->allocator, &mixture->lines); - -exit: - *out_mixture = mixture; - return res; -error: - if(mixture) { SLN(mixture_ref_put(mixture)); mixture = NULL; } - goto exit; -} - -static res_T -create_line_view - (struct sln_device* sln, - const struct sln_mixture_create_args* mixture_args, - struct shtr_line_view** out_view) -{ - struct shtr_line_view_create_args view_args = SHTR_LINE_VIEW_CREATE_ARGS_NULL; - struct shtr_line_view* view = NULL; - size_t imol, iiso; - res_T res = RES_OK; - (void)sln; - - ASSERT(sln && mixture_args && out_view); - - view_args.wavenumber_range[0] = mixture_args->wavenumber_range[0]; - view_args.wavenumber_range[1] = mixture_args->wavenumber_range[1]; - view_args.nmolecules = mixture_args->nmolecules; - view_args.pressure = mixture_args->pressure; - - FOR_EACH(imol, 0, mixture_args->nmolecules) { - struct shtr_isotope_selection* view_mol = view_args.molecules + imol; - const struct sln_molecule* mixture_mol = mixture_args->molecules + imol; - - view_mol->id = mixture_mol->id; - view_mol->nisotopes = mixture_mol->nisotopes; - view_mol->cutoff = mixture_mol->cutoff; - FOR_EACH(iiso, 0, mixture_mol->nisotopes) { - view_mol->isotope_ids_local[iiso] = mixture_mol->isotopes[iiso].id_local; - } - } - - res = shtr_line_view_create(mixture_args->lines, &view_args, &view); - if(res != RES_OK) goto error; - -exit: - *out_view = view; - return res; -error: - if(view) { SHTR(line_view_ref_put(view)); view = NULL; } - goto exit; -} - -static void -molecules_params_reset(struct molecule_params params[SLN_MAX_MOLECULES_COUNT]) -{ - size_t imol; - ASSERT(params); - - /* Clean up the params */ - FOR_EACH(imol, 0, SLN_MAX_MOLECULES_COUNT) { - size_t iiso; - params[imol].concentration = -1; - params[imol].cutoff = -1; - FOR_EACH(iiso, 0, SLN_MAX_ISOTOPES_COUNT) { - params[imol].isotopes_abundance[iiso] = -1; - } - } -} - -static res_T -setup_molecule_params - (struct sln_device* sln, - const struct sln_mixture_create_args* args, - struct molecule_params params[SLN_MAX_MOLECULES_COUNT]) -{ - size_t imol; - ASSERT(sln && args && params); - (void)sln; - - molecules_params_reset(params); - - FOR_EACH(imol, 0, args->nmolecules) { - const struct sln_molecule* mol = &args->molecules[imol]; - size_t iiso; - ASSERT(mol->id < SLN_MAX_MOLECULES_COUNT); - - params[mol->id].concentration = mol->concentration; - params[mol->id].cutoff = mol->cutoff; - FOR_EACH(iiso, 0, mol->nisotopes) { - const struct sln_isotope* iso = &mol->isotopes[iiso]; - ASSERT(iso->id_local < SLN_MAX_ISOTOPES_COUNT); - - params[mol->id].isotopes_abundance[iso->id_local] = iso->abundance; - } - } - - return RES_OK; -} - -static INLINE res_T -store_input_args - (struct sln_device* sln, - const struct sln_mixture_create_args* args, - struct sln_mixture* mixture) -{ - ASSERT(sln && args && mixture); - (void)sln; - mixture->wavenumber_range[0] = args->wavenumber_range[0]; - mixture->wavenumber_range[1] = args->wavenumber_range[1]; - mixture->temperature = args->temperature; - mixture->pressure = args->pressure; - SHTR(isotope_metadata_ref_get(args->metadata)); - mixture->metadata = args->metadata; - return RES_OK; -} - -static res_T -setup_lines(struct sln_mixture* mixture, const char* caller) -{ - size_t iline, nlines; - res_T res = RES_OK; - ASSERT(mixture && caller); - - SHTR(line_view_get_size(mixture->line_view, &nlines)); - - res = darray_line_resize(&mixture->lines, nlines); - if(res != RES_OK) { - log_err(mixture->sln, - "%s: error allocating the list of precomputed line data.\n", - caller); - goto error; - } - - FOR_EACH(iline, 0, nlines) { - res = line_setup(mixture, iline); - if(res != RES_OK) goto error; - } - -exit: - return res; -error: - darray_line_clear(&mixture->lines); - goto exit; -} - -static void -release_mixture(ref_T* ref) -{ - struct sln_mixture* mixture = CONTAINER_OF(ref, struct sln_mixture, ref); - struct sln_device* sln = NULL; - ASSERT(ref); - sln = mixture->sln; - if(mixture->metadata) SHTR(isotope_metadata_ref_put(mixture->metadata)); - if(mixture->line_view) SHTR(line_view_ref_put(mixture->line_view)); - darray_line_release(&mixture->lines); - MEM_RM(sln->allocator, mixture); - SLN(device_ref_put(sln)); -} - -/******************************************************************************* - * Exported functions - ******************************************************************************/ -res_T -sln_mixture_create - (struct sln_device* sln, - const struct sln_mixture_create_args* args, - struct sln_mixture** out_mixture) -{ - struct sln_mixture* mixture = NULL; - res_T res = RES_OK; - - if(!sln || !out_mixture) { res = RES_BAD_ARG; goto error; } - res = check_sln_mixture_create_args(sln, FUNC_NAME, args); - if(res != RES_OK) goto error; - res = create_mixture(sln, FUNC_NAME, &mixture); - if(res != RES_OK) goto error; - - #define CALL(Func) { if(RES_OK != (res = Func)) goto error; } (void)0 - CALL(create_line_view(sln, args, &mixture->line_view)); - CALL(setup_molecule_params(sln, args, mixture->molecules_params)); - CALL(store_input_args(sln, args, mixture)); - CALL(setup_lines(mixture, FUNC_NAME)); - #undef CALL - -exit: - if(out_mixture) *out_mixture = mixture; - return res; -error: - if(mixture) { SLN(mixture_ref_put(mixture)); mixture = NULL; } - goto exit; -} - -res_T -sln_mixture_create_from_stream - (struct sln_device* sln, - struct shtr* shtr, - FILE* stream, - struct sln_mixture** out_mixture) -{ - struct sln_mixture* mixture = NULL; - size_t nlines = 0; - int version = 0; - res_T res = RES_OK; - - if(!sln || !shtr || !stream || !out_mixture) { - res = RES_BAD_ARG; - goto error; - } - - res = create_mixture(sln, FUNC_NAME, &mixture); - if(res != RES_OK) goto error; - - #define READ(Var, Nb) { \ - if(fread((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ - if(feof(stream)) { \ - res = RES_BAD_ARG; \ - } else if(ferror(stream)) { \ - res = RES_IO_ERR; \ - } else { \ - res = RES_UNKNOWN_ERR; \ - } \ - log_err(sln, "%s: error reading mixture data -- %s.\n", \ - FUNC_NAME, res_to_cstr(res)); \ - goto error; \ - } \ - } (void)0 - READ(&version, 1); - if(version != SLN_MIXTURE_VERSION) { - log_err(sln, - "%s: unexpected mixture version %d. " - "Expecting a mixture in version %d.\n", - FUNC_NAME, version, SLN_MIXTURE_VERSION); - res = RES_BAD_ARG; - goto error; - } - READ(mixture->molecules_params, SLN_MAX_MOLECULES_COUNT); - - res = shtr_isotope_metadata_create_from_stream(shtr, stream, &mixture->metadata); - if(res != RES_OK) goto error; - res = shtr_line_view_create_from_stream(shtr, stream, &mixture->line_view); - if(res != RES_OK) goto error; - - READ(&nlines, 1); - res = darray_line_resize(&mixture->lines, nlines); - if(res != RES_OK) { - log_err(sln, "%s: error allocating mixture lines -- %s.\n", - FUNC_NAME, res_to_cstr(res)); - goto error; - } - READ(darray_line_data_get(&mixture->lines), nlines); -#ifndef NDEBUG - SHTR(line_view_get_size(mixture->line_view, &nlines)); - ASSERT(darray_line_size_get(&mixture->lines) == nlines); -#endif - - READ(&mixture->temperature, 1); - READ(&mixture->pressure, 1); - READ(&mixture->wavenumber_range, 1); - #undef READ - -exit: - if(out_mixture) *out_mixture = mixture; - return res; -error: - if(mixture) { SLN(mixture_ref_put(mixture)); mixture = NULL; } - goto exit; -} - -res_T -sln_mixture_ref_get(struct sln_mixture* mixture) -{ - if(!mixture) return RES_BAD_ARG; - ref_get(&mixture->ref); - return RES_OK; -} - -res_T -sln_mixture_ref_put(struct sln_mixture* mixture) -{ - if(!mixture) return RES_BAD_ARG; - ref_put(&mixture->ref, release_mixture); - return RES_OK; -} - -res_T -sln_mixture_get_desc - (const struct sln_mixture* mixture, - struct sln_mixture_desc* desc) -{ - if(!mixture || !desc) return RES_BAD_ARG; - desc->wavenumber_range[0] = mixture->wavenumber_range[0]; - desc->wavenumber_range[1] = mixture->wavenumber_range[1]; - desc->temperature = mixture->temperature; - desc->pressure = mixture->pressure; - desc->nlines = darray_line_size_get(&mixture->lines); - return RES_OK; -} - -res_T -sln_mixture_write(const struct sln_mixture* mixture, FILE* stream) -{ - size_t nlines = 0; - res_T res = RES_OK; - - if(!mixture || !stream) { - res = RES_BAD_ARG; - goto error; - } - - #define WRITE(Var, Nb) { \ - if(fwrite((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ - log_err(mixture->sln, "%s: error writing the mixture.\n", FUNC_NAME); \ - res = RES_IO_ERR; \ - goto error; \ - } \ - } (void)0 - WRITE(&SLN_MIXTURE_VERSION, 1); - WRITE(mixture->molecules_params, SLN_MAX_MOLECULES_COUNT); - - res = shtr_isotope_metadata_write(mixture->metadata, stream); - if(res != RES_OK) goto error; - res = shtr_line_view_write(mixture->line_view, stream); - if(res != RES_OK) goto error; - - nlines = darray_line_size_get(&mixture->lines); - WRITE(&nlines, 1); - WRITE(darray_line_cdata_get(&mixture->lines), nlines); - WRITE(&mixture->temperature, 1); - WRITE(&mixture->pressure, 1); - WRITE(mixture->wavenumber_range, 2); - #undef WRITE - -exit: - return res; -error: - goto exit; -} diff --git a/src/sln_mixture_c.h b/src/sln_mixture_c.h @@ -1,76 +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 SLN_MIXTURE_C_H -#define SLN_MIXTURE_C_H - -#include "sln.h" -#include "sln_line.h" - -#include <rsys/dynamic_array.h> -#include <rsys/ref_count.h> - -struct sln_device; -struct shtr_line_view; - -/* Generate the dynamic array of lines */ -#define DARRAY_DATA struct line -#define DARRAY_NAME line -#include <rsys/dynamic_array.h> - -struct molecule_params { - /* Map the isotope local identifier to its abundance */ - double isotopes_abundance[SLN_MAX_ISOTOPES_COUNT]; - - double concentration; - double cutoff; -}; - -/* Current version of the mixture. One should increment it and perform a - * version management onto serialized data when muxture structure is updated. */ -static const int SLN_MIXTURE_VERSION = 0; - -struct sln_mixture { - /* Map the molecule id to its parameters (i.e. concentration, cutoff, - * isotopes abundance) */ - struct molecule_params molecules_params[SLN_MAX_MOLECULES_COUNT]; - - struct shtr_isotope_metadata* metadata; - struct shtr_line_view* line_view; /* Set of lines */ - - /* Store per line precomputed data */ - struct darray_line lines; - - double temperature; /* In Kelvin */ - double pressure; /* In atm */ - double wavenumber_range[2]; /* Spectral range [cm^-1] */ - - struct sln_device* sln; - ref_T ref; -}; - -static INLINE const struct molecule_params* -mixture_get_molecule_params - (const struct sln_mixture* mixture, - const int32_t molecules_id) -{ - ASSERT(mixture && molecules_id >= 0 && molecules_id < SLN_MAX_MOLECULES_COUNT); - return mixture->molecules_params + molecules_id; -} - -#endif /* SLN_MIXTURE_C_H */ diff --git a/src/sln_tree.c b/src/sln_tree.c @@ -19,8 +19,6 @@ #include "sln.h" #include "sln_device_c.h" #include "sln_line.h" -#include "sln_log.h" -#include "sln_mixture_c.h" #include "sln_tree_c.h" #include <star/shtr.h> @@ -40,35 +38,36 @@ check_sln_tree_create_args ASSERT(sln && caller); if(!args) return RES_BAD_ARG; - /* Currently only 1 line per leaf is accepted */ - if(args->max_nlines_per_leaf != 1) { - log_err(sln, - "%s: invalid maximum number of lines per leaf %lu. " - "Currently it must be set to 1.\n", - caller, (unsigned long)args->max_nlines_per_leaf); + if(!args->metadata) { + ERROR(sln, "%s: the metadata is missing.\n", caller); + return RES_BAD_ARG; + } + + if(!args->lines) { + ERROR(sln, "%s: the list of lines is mssing.\n", caller); return RES_BAD_ARG; } if(args->nvertices_hint == 0) { - log_err(sln, + ERROR(sln, "%s: invalid hint on the number of vertices around the line center %lu.\n", caller, (unsigned long)args->nvertices_hint); return RES_BAD_ARG; } if(args->mesh_decimation_err < 0) { - log_err(sln, "%s: invalid decimation error %g.\n", + ERROR(sln, "%s: invalid decimation error %g.\n", caller, args->mesh_decimation_err); return RES_BAD_ARG; } if((unsigned)args->mesh_type >= SLN_MESH_TYPES_COUNT__) { - log_err(sln, "%s: invalid mesh type %d.\n", caller, args->mesh_type); + ERROR(sln, "%s: invalid mesh type %d.\n", caller, args->mesh_type); return RES_BAD_ARG; } if((unsigned)args->line_profile >= SLN_LINE_PROFILES_COUNT__) { - log_err(sln, "%s: invalid line profile %d.\n", caller, args->line_profile); + ERROR(sln, "%s: invalid line profile %d.\n", caller, args->line_profile); return RES_BAD_ARG; } @@ -87,12 +86,14 @@ create_tree tree = MEM_CALLOC(sln->allocator, 1, sizeof(struct sln_tree)); if(!tree) { - log_err(sln, "%s: could not allocate the tree data structure.\n", + ERROR(sln, "%s: could not allocate the tree data structure.\n", caller); res = RES_MEM_ERR; goto error; } ref_init(&tree->ref); + SLN(device_ref_get(sln)); + tree->sln = sln; darray_node_init(sln->allocator, &tree->nodes); darray_vertex_init(sln->allocator, &tree->vertices); @@ -104,19 +105,6 @@ error: goto exit; } -static INLINE res_T -store_input_args - (struct sln_tree* tree, - const struct sln_tree_create_args* args) -{ - ASSERT(args && tree); - tree->max_nlines_per_leaf = args->max_nlines_per_leaf; - tree->mesh_decimation_err = args->mesh_decimation_err; - tree->mesh_type = args->mesh_type; - tree->line_profile = args->line_profile; - return RES_OK; -} - static INLINE int cmp_nu_vtx(const void* key, const void* item) { @@ -131,13 +119,15 @@ static void release_tree(ref_T* ref) { struct sln_tree* tree = CONTAINER_OF(ref, struct sln_tree, ref); - struct sln_mixture* mixture = NULL; + struct sln_device* sln = NULL; ASSERT(ref); - mixture = tree->mixture; + sln = tree->sln; darray_node_release(&tree->nodes); darray_vertex_release(&tree->vertices); - MEM_RM(mixture->sln->allocator, tree); - SLN(mixture_ref_put(mixture)); + if(tree->args.lines) SHTR(line_list_ref_put(tree->args.lines)); + if(tree->args.metadata) SHTR(isotope_metadata_ref_put(tree->args.metadata)); + MEM_RM(sln->allocator, tree); + SLN(device_ref_put(sln)); } /******************************************************************************* @@ -145,25 +135,24 @@ release_tree(ref_T* ref) ******************************************************************************/ res_T sln_tree_create - (struct sln_mixture* mixture, + (struct sln_device* device, const struct sln_tree_create_args* args, struct sln_tree** out_tree) { struct sln_tree* tree = NULL; res_T res = RES_OK; - if(!mixture || !out_tree) { res = RES_BAD_ARG; goto error; } - res = check_sln_tree_create_args(mixture->sln, FUNC_NAME, args); + if(!device || !out_tree) { res = RES_BAD_ARG; goto error; } + res = check_sln_tree_create_args(device, FUNC_NAME, args); if(res != RES_OK) goto error; - res = create_tree(mixture->sln, FUNC_NAME, &tree); + res = create_tree(device, FUNC_NAME, &tree); if(res != RES_OK) goto error; - SLN(mixture_ref_get(mixture)); - tree->mixture = mixture; + SHTR(line_list_ref_get(args->lines)); + SHTR(isotope_metadata_ref_get(args->metadata)); + tree->args = *args; - res = store_input_args(tree, args); - if(res != RES_OK) goto error; - res = tree_build(tree, args); + res = tree_build(tree); if(res != RES_OK) goto error; exit: @@ -203,14 +192,12 @@ sln_tree_create_from_stream } else { \ res = RES_UNKNOWN_ERR; \ } \ - log_err(sln, "%s: error reading tree data -- %s.\n", \ - FUNC_NAME, res_to_cstr(res)); \ goto error; \ } \ } (void)0 READ(&version, 1); if(version != SLN_TREE_VERSION) { - log_err(sln, + ERROR(sln, "%s: unexpected tree version %d. Expecting a tree in version %d.\n", FUNC_NAME, version, SLN_TREE_VERSION); res = RES_BAD_ARG; @@ -218,29 +205,27 @@ sln_tree_create_from_stream } READ(&n, 1); - res = darray_node_resize(&tree->nodes, n); - if(res != RES_OK) { - log_err(sln, "%s: error allocating the tree nodes -- %s.\n", - FUNC_NAME, res_to_cstr(res)); - goto error; - } + if((res = darray_node_resize(&tree->nodes, n)) != RES_OK) goto error; READ(darray_node_data_get(&tree->nodes), n); READ(&n, 1); - res = darray_vertex_resize(&tree->vertices, n); - if(res != RES_OK) { - log_err(sln, "%s: error allocatiing the tree vertices -- %s.\n", - FUNC_NAME, res_to_cstr(res)); - goto error; - } + if((res = darray_vertex_resize(&tree->vertices, n)) != RES_OK) goto error; READ(darray_vertex_data_get(&tree->vertices), n); - READ(&tree->max_nlines_per_leaf, 1); - READ(&tree->mesh_decimation_err, 1); - READ(&tree->line_profile, 1); + READ(&tree->args.line_profile, 1); + READ(&tree->args.molecules, 1); + READ(&tree->args.pressure, 1); + READ(&tree->args.temperature, 1); + READ(&tree->args.nvertices_hint, 1); + READ(&tree->args.mesh_decimation_err, 1); + READ(&tree->args.mesh_type, 1); + READ(&tree->args.wavenumber_range, 1); #undef READ - res = sln_mixture_create_from_stream(sln, shtr, stream, &tree->mixture); + res = shtr_isotope_metadata_create_from_stream(shtr, stream, &tree->args.metadata); + if(res != RES_OK) goto error; + + res = shtr_line_list_create_from_stream(shtr, stream, &tree->args.lines); if(res != RES_OK) goto error; exit: @@ -248,6 +233,10 @@ exit: return res; error: if(tree) { SLN(tree_ref_put(tree)); tree = NULL; } + if(sln) { + ERROR(sln, "%s: error loading the tree structure -- %s.\n", + FUNC_NAME, res_to_cstr(res)); + } goto exit; } @@ -271,10 +260,10 @@ res_T sln_tree_get_desc(const struct sln_tree* tree, struct sln_tree_desc* desc) { if(!tree || !desc) return RES_BAD_ARG; - desc->max_nlines_per_leaf = tree->max_nlines_per_leaf; - desc->mesh_decimation_err = tree->mesh_decimation_err; - desc->mesh_type = tree->mesh_type; - desc->line_profile = tree->line_profile; + desc->max_nlines_per_leaf = 1; + desc->mesh_decimation_err = tree->args.mesh_decimation_err; + desc->mesh_type = tree->args.mesh_type; + desc->line_profile = tree->args.line_profile; return RES_OK; } @@ -315,13 +304,13 @@ sln_node_get_line (const struct sln_tree* tree, const struct sln_node* node, const size_t iline, - const struct shtr_line** line) + struct shtr_line* line) { if(!tree || !node || iline > sln_node_get_lines_count(node)) return RES_BAD_ARG; - return shtr_line_view_get_line - (tree->mixture->line_view, node->range[0] + iline, line); + return shtr_line_list_at + (tree->args.lines, node->range[0] + iline, line); } res_T @@ -345,8 +334,18 @@ sln_node_eval double ka = 0; size_t iline; ASSERT(tree && node && nu >= 0); + FOR_EACH(iline, node->range[0], node->range[1]+1) { - ka += line_value(tree->mixture, iline, tree->line_profile, nu); + struct line line = LINE_NULL; + res_T res = RES_OK; + + res = line_setup(tree, iline, &line); + if(res != RES_OK) { + WARN(tree->sln, "%s: could not setup the line %lu-- %s\n", + FUNC_NAME, iline, res_to_cstr(res)); + } + + ka += line_value(tree, &line, nu); } return ka; } @@ -395,7 +394,6 @@ sln_tree_write(const struct sln_tree* tree, FILE* stream) #define WRITE(Var, Nb) { \ if(fwrite((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ - log_err(tree->mixture->sln, "%s: error writing the tree.\n", FUNC_NAME); \ res = RES_IO_ERR; \ goto error; \ } \ @@ -410,16 +408,28 @@ sln_tree_write(const struct sln_tree* tree, FILE* stream) WRITE(&n, 1); WRITE(darray_vertex_cdata_get(&tree->vertices), n); - WRITE(&tree->max_nlines_per_leaf, 1); - WRITE(&tree->mesh_decimation_err, 1); - WRITE(&tree->line_profile, 1); + WRITE(&tree->args.line_profile, 1); + WRITE(&tree->args.molecules, 1); + WRITE(&tree->args.pressure, 1); + WRITE(&tree->args.temperature, 1); + WRITE(&tree->args.nvertices_hint, 1); + WRITE(&tree->args.mesh_decimation_err, 1); + WRITE(&tree->args.mesh_type, 1); + WRITE(&tree->args.wavenumber_range, 1); #undef WRITE - res = sln_mixture_write(tree->mixture, stream); + res = shtr_isotope_metadata_write(tree->args.metadata, stream); + if(res != RES_OK) goto error; + + res = shtr_line_list_write(tree->args.lines, stream); if(res != RES_OK) goto error; exit: return res; error: + if(tree) { + ERROR(tree->sln, "%s: error writing the tree -- %s\n", + FUNC_NAME, res_to_cstr(res)); + } goto exit; } diff --git a/src/sln_tree_build.c b/src/sln_tree_build.c @@ -17,15 +17,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "sln.h" -#include "sln_log.h" +#include "sln_device_c.h" #include "sln_polyline.h" -#include "sln_mixture_c.h" #include "sln_tree_c.h" #include <star/shtr.h> #include <rsys/cstr.h> +/* Maximum number of lines per leaf */ +#define MAX_NLINES_PER_LEAF 1 + /* STACK_SIZE is set to the maximum depth of the partitioning tree generated by * the tree_build function. This is actually the maximum stack size where tree * nodes are pushed by the recursive build process */ @@ -43,10 +45,7 @@ ui64_to_ui32(const uint64_t ui64) } static INLINE res_T -build_leaf_polyline - (struct sln_tree* tree, - const struct sln_tree_create_args* args, - struct sln_node* leaf) +build_leaf_polyline(struct sln_tree* tree, struct sln_node* leaf) { size_t vertices_range[2]; res_T res = RES_OK; @@ -55,18 +54,13 @@ build_leaf_polyline ASSERT(leaf->range[0] == leaf->range[1]); /* Line meshing */ - res = line_mesh(tree, leaf->range[0], args->nvertices_hint, vertices_range); + res = line_mesh(tree, leaf->range[0], tree->args.nvertices_hint, vertices_range); if(res != RES_OK) goto error; /* Decimate the line mesh */ - res = polyline_decimate - (tree->mixture->sln, darray_vertex_data_get(&tree->vertices), - vertices_range, args->mesh_decimation_err, tree->mesh_type); - if(res != RES_OK) { - log_err(tree->mixture->sln, "Error while decimating the line mesh -- %s.\n", - res_to_cstr(res)); - goto error; - } + res = polyline_decimate(tree->sln, darray_vertex_data_get(&tree->vertices), + vertices_range, tree->args.mesh_decimation_err, tree->args.mesh_type); + if(res != RES_OK) goto error; /* Shrink the size of the vertices */ darray_vertex_resize(&tree->vertices, vertices_range[1] + 1); @@ -91,7 +85,7 @@ eval_ka double ka = 0; ASSERT(tree && node && wavenumber >= 0); - switch(tree->mesh_type) { + switch(tree->args.mesh_type) { case SLN_MESH_UPPER: SLN(node_get_mesh(tree, node, &mesh)); ka = sln_mesh_eval(&mesh, wavenumber); @@ -110,7 +104,6 @@ eval_ka static res_T merge_node_polylines (struct sln_tree* tree, - const struct sln_tree_create_args* args, const struct sln_node* node0, const struct sln_node* node1, struct sln_node* merged_node) @@ -130,8 +123,7 @@ merge_node_polylines /* Allocate the memory space to store the new polyline */ res = darray_vertex_resize(&tree->vertices, vertices_range[1] + 1); if(res != RES_OK) { - log_err(tree->mixture->sln, "Error in merging polylines -- %s.\n", - res_to_cstr(res)); + ERROR(tree->sln, "Error in merging polylines -- %s.\n", res_to_cstr(res)); goto error; } vertices = darray_vertex_data_get(&tree->vertices); @@ -168,17 +160,9 @@ merge_node_polylines } /* Decimate the resulting polyline */ - res = polyline_decimate - (tree->mixture->sln, - darray_vertex_data_get(&tree->vertices), - vertices_range, - args->mesh_decimation_err, - tree->mesh_type); - if(res != RES_OK) { - log_err(tree->mixture->sln, "Error while decimating the line mesh -- %s.\n", - res_to_cstr(res)); - goto error; - } + res = polyline_decimate(tree->sln, darray_vertex_data_get(&tree->vertices), + vertices_range, tree->args.mesh_decimation_err, tree->args.mesh_type); + if(res != RES_OK) goto error; /* Shrink the size of the vertices */ darray_vertex_resize(&tree->vertices, vertices_range[1] + 1); @@ -194,15 +178,13 @@ error: } static res_T -build_polylines - (struct sln_tree* tree, - const struct sln_tree_create_args* args) +build_polylines(struct sln_tree* tree) { size_t stack[STACK_SIZE*2]; size_t istack = 0; size_t inode = 0; res_T res = RES_OK; - ASSERT(tree && args); + ASSERT(tree); #define NODE(Id) (darray_node_data_get(&tree->nodes) + (Id)) #define IS_LEAF(Id) (NODE(Id)->offset == 0) @@ -214,7 +196,7 @@ build_polylines while(inode != SIZE_MAX) { if(IS_LEAF(inode)) { - res = build_leaf_polyline(tree, args, NODE(inode)); + res = build_leaf_polyline(tree, NODE(inode)); if(res != RES_OK) goto error; inode = stack[--istack]; /* Pop the next node */ @@ -230,7 +212,7 @@ build_polylines /* Build the polyline of the current node by merging the polylines of * its children */ res = merge_node_polylines - (tree, args, NODE(ichild0), NODE(ichild1), NODE(inode)); + (tree, NODE(ichild0), NODE(ichild1), NODE(inode)); if(res != RES_OK) goto error; inode = stack[--istack]; @@ -256,9 +238,7 @@ error: } static res_T -partition_lines - (struct sln_tree* tree, - const struct sln_tree_create_args* args) +partition_lines(struct sln_tree* tree) { size_t stack[STACK_SIZE]; size_t istack = 0; @@ -266,8 +246,8 @@ partition_lines size_t nlines; res_T res = RES_OK; - ASSERT(tree && args); - SHTR(line_view_get_size(tree->mixture->line_view, &nlines)); + ASSERT(tree); + SHTR(line_list_get_size(tree->args.lines, &nlines)); #define NODE(Id) (darray_node_data_get(&tree->nodes) + (Id)) #define CREATE_NODE { \ @@ -290,7 +270,7 @@ partition_lines nlines = NODE(inode)->range[1] - NODE(inode)->range[0] + 1; /* Make a leaf */ - if(nlines <= args->max_nlines_per_leaf) { + if(nlines <= MAX_NLINES_PER_LEAF) { NODE(inode)->offset = 0; inode = stack[--istack]; /* Pop the next node */ @@ -340,16 +320,12 @@ error: * Local functions ******************************************************************************/ res_T -tree_build - (struct sln_tree* tree, - const struct sln_tree_create_args* args) +tree_build(struct sln_tree* tree) { res_T res = RES_OK; - res = partition_lines(tree, args); - if(res != RES_OK) goto error; - res = build_polylines(tree, args); - if(res != RES_OK) goto error; + if((res = partition_lines(tree)) != RES_OK) goto error; + if((res = build_polylines(tree)) != RES_OK) goto error; exit: return res; diff --git a/src/sln_tree_c.h b/src/sln_tree_c.h @@ -28,12 +28,13 @@ /* Current version of the serialized tree data. One should increment it and * perform a version management onto serialized tree when these data are * updated. */ -static const int SLN_TREE_VERSION = 0; +static const int SLN_TREE_VERSION = 1; /* Forward declaration */ -struct sln_mixture; +struct shtr_isotope_metadata; +struct shtr_line_list; +struct sln_device; struct sln_tree_create_args; -struct shtr_line_view; struct sln_node { /* 32 Bytes */ /* Range of the line indices corresponding to the node */ @@ -59,18 +60,13 @@ struct sln_tree { struct darray_node nodes; /* Nodes used to partition the lines */ struct darray_vertex vertices; /* List of vertices */ - size_t max_nlines_per_leaf; - float mesh_decimation_err; - enum sln_mesh_type mesh_type; - enum sln_line_profile line_profile; - - struct sln_mixture* mixture; + struct sln_tree_create_args args; + struct sln_device* sln; ref_T ref; }; extern LOCAL_SYM res_T tree_build - (struct sln_tree* tree, - const struct sln_tree_create_args* args); + (struct sln_tree* tree); #endif /* SLN_TREE_C_H */ diff --git a/src/test_sln_tree.c b/src/test_sln_tree.c @@ -28,51 +28,48 @@ /******************************************************************************* * Helper function ******************************************************************************/ -static int -cmp_line(const void* key, const void* item) -{ - const struct shtr_line* line0 = key; - const struct shtr_line* line1 = item; - CHK(key && item); - if(line0->wavenumber < line1->wavenumber) return -1; - else if(line0->wavenumber > line1->wavenumber) return +1; - else return 0; -} - /* Return the index of the line in the line_list or SIZE_MAX if the line does * not exist */ static INLINE size_t find_line - (const struct shtr_line_list* line_list, + (struct shtr_line_list* line_list, const struct shtr_line* line) { - const struct shtr_line* list = NULL; - const struct shtr_line* found = NULL; - size_t iline, nlines; + struct shtr_line ln = SHTR_LINE_NULL; + size_t lo, hi, mid; + size_t iline; + size_t nlines; - CHK(shtr_line_list_get(line_list, &list) == RES_OK); CHK(shtr_line_list_get_size(line_list, &nlines) == RES_OK); - /* Dichotomous search wrt the wavenumber of lines */ - found = search_lower_bound - (line, list, nlines, sizeof(struct shtr_line), cmp_line); - if(!found) return SIZE_MAX; + /* Dichotomic search */ + lo = 0; hi = nlines -1; + while(lo < hi) { + mid = (lo+hi)/2; + + CHK(shtr_line_list_at(line_list, mid, &ln) == RES_OK); + if(line->wavenumber > ln.wavenumber) { + lo = mid + 1; + } else { + hi = mid; + } + } + iline = lo; + + CHK(shtr_line_list_at(line_list, iline, &ln) == RES_OK); + if(ln.wavenumber != line->wavenumber) return SIZE_MAX; + /* Find a line with the same wavenumber as the one searched for and whose * other member variables are also equal to those of the line searched for */ - CHK(found >= list); - iline = (size_t)(found - list); - while(list[iline].wavenumber == line->wavenumber - && !shtr_line_eq(&list[iline], line) - && iline < nlines) { - ++iline; + while(ln.wavenumber == line->wavenumber + && !shtr_line_eq(&ln, line) + && iline < nlines) { + iline += 1; + CHK(shtr_line_list_at(line_list, iline, &ln) == RES_OK); } - if(shtr_line_eq(&list[iline], line)) { - return iline; - } else { - return SIZE_MAX; - } + return shtr_line_eq(&ln, line) ? iline : SIZE_MAX; } /* This test assumes that all the lines contained into the list are @@ -80,10 +77,9 @@ find_line static void check_tree (const struct sln_tree* tree, - const struct shtr_line_list* line_list) + struct shtr_line_list* line_list) { #define STACK_SIZE 64 - const struct shtr_line* list = NULL; const struct sln_node* stack[STACK_SIZE] = {NULL}; struct sln_tree_desc desc = SLN_TREE_DESC_NULL; size_t istack = 0; @@ -94,12 +90,10 @@ check_tree size_t line_list_sz; CHK(shtr_line_list_get_size(line_list, &line_list_sz) == RES_OK); - CHK(shtr_line_list_get(line_list, &list) == RES_OK); + CHK(sln_tree_get_desc(tree, &desc) == RES_OK); CHK(found_lines = mem_calloc(line_list_sz, sizeof(char))); - CHK(sln_tree_get_desc(tree, &desc) == RES_OK); - node = sln_tree_get_root(tree); while(node) { if(!sln_node_is_leaf(node)) { @@ -115,10 +109,10 @@ check_tree nlines = sln_node_get_lines_count(node); CHK(nlines <= desc.max_nlines_per_leaf); FOR_EACH(iline, 0, nlines) { - const struct shtr_line* line = NULL; + struct shtr_line line = SHTR_LINE_NULL; size_t found_iline = 0; CHK(sln_node_get_line(tree, node, iline, &line) == RES_OK); - found_iline = find_line(line_list, line); + found_iline = find_line(line_list, &line); CHK(found_iline != SIZE_MAX); /* Line is found */ if(!found_lines[found_iline]) { @@ -151,22 +145,26 @@ dump_line(FILE* stream, const struct sln_mesh* mesh) } static void -test_tree(struct sln_mixture* mixture, const struct shtr_line_list* line_list) +test_tree + (struct sln_device* sln, + const struct sln_tree_create_args* tree_args_in, + struct shtr_line_list* line_list) { struct sln_tree_create_args tree_args = SLN_TREE_CREATE_ARGS_DEFAULT; struct sln_tree_desc desc = SLN_TREE_DESC_NULL; struct sln_mesh mesh = SLN_MESH_NULL; struct sln_tree* tree = NULL; const struct sln_node* node = NULL; - const struct shtr_line* line = NULL; + struct shtr_line line = SHTR_LINE_NULL; size_t nlines = 0; - CHK(mixture && line_list); + CHK(sln && tree_args_in && line_list); + tree_args = *tree_args_in; CHK(sln_tree_create(NULL, &tree_args, &tree) == RES_BAD_ARG); - CHK(sln_tree_create(mixture, NULL, &tree) == RES_BAD_ARG); - CHK(sln_tree_create(mixture, &tree_args, NULL) == RES_BAD_ARG); - CHK(sln_tree_create(mixture, &tree_args, &tree) == RES_OK); + CHK(sln_tree_create(sln, NULL, &tree) == RES_BAD_ARG); + CHK(sln_tree_create(sln, &tree_args, NULL) == RES_BAD_ARG); + CHK(sln_tree_create(sln, &tree_args, &tree) == RES_OK); CHK(shtr_line_list_get_size(line_list, &nlines) == RES_OK); @@ -174,7 +172,6 @@ test_tree(struct sln_mixture* mixture, const struct shtr_line_list* line_list) CHK(sln_tree_get_desc(tree, NULL) == RES_BAD_ARG); CHK(sln_tree_get_desc(tree, &desc) == RES_OK); - CHK(desc.max_nlines_per_leaf == tree_args.max_nlines_per_leaf); CHK(desc.mesh_decimation_err == tree_args.mesh_decimation_err); CHK(desc.mesh_type == tree_args.mesh_type); CHK(desc.line_profile == tree_args.line_profile); @@ -183,10 +180,10 @@ test_tree(struct sln_mixture* mixture, const struct shtr_line_list* line_list) while(!sln_node_is_leaf(node)) { node = sln_node_get_child(node, 0); } - CHK(sln_node_get_lines_count(node) <= tree_args.max_nlines_per_leaf); + CHK(sln_node_get_lines_count(node) <= desc.max_nlines_per_leaf); CHK(sln_node_get_line(NULL, node, 0, &line) == RES_BAD_ARG); CHK(sln_node_get_line(tree, NULL, 0, &line) == RES_BAD_ARG); - CHK(sln_node_get_line(tree, node, tree_args.max_nlines_per_leaf+1, &line) + CHK(sln_node_get_line(tree, node, desc.max_nlines_per_leaf+1, &line) == RES_BAD_ARG); CHK(sln_node_get_line(tree, node, 0, NULL) == RES_BAD_ARG); CHK(sln_node_get_line(tree, node, 0, &line) == RES_OK); @@ -209,23 +206,19 @@ test_tree(struct sln_mixture* mixture, const struct shtr_line_list* line_list) CHK(sln_tree_ref_put(tree) == RES_OK); CHK(sln_tree_ref_put(tree) == RES_OK); - tree_args.max_nlines_per_leaf = 0; - CHK(sln_tree_create(mixture, &tree_args, &tree) == RES_BAD_ARG); - - tree_args.max_nlines_per_leaf = 1; tree_args.mesh_decimation_err = -1; - CHK(sln_tree_create(mixture, &tree_args, &tree) == RES_BAD_ARG); + CHK(sln_tree_create(sln, &tree_args, &tree) == RES_BAD_ARG); tree_args.mesh_decimation_err = 1e-1f; tree_args.mesh_type = SLN_MESH_TYPES_COUNT__; - CHK(sln_tree_create(mixture, &tree_args, &tree) == RES_BAD_ARG); + CHK(sln_tree_create(sln, &tree_args, &tree) == RES_BAD_ARG); tree_args.mesh_type = SLN_MESH_USUAL; tree_args.line_profile = SLN_LINE_PROFILES_COUNT__; - CHK(sln_tree_create(mixture, &tree_args, &tree) == RES_BAD_ARG); + CHK(sln_tree_create(sln, &tree_args, &tree) == RES_BAD_ARG); tree_args.line_profile = SLN_LINE_PROFILE_VOIGT; - CHK(sln_tree_create(mixture, &tree_args, &tree) == RES_OK); + CHK(sln_tree_create(sln, &tree_args, &tree) == RES_OK); CHK(sln_tree_ref_put(tree) == RES_OK); } @@ -259,11 +252,11 @@ check_node_equality nlines = sln_node_get_lines_count(node1); FOR_EACH(iline, 0, nlines) { - const struct shtr_line* line1 = NULL; - const struct shtr_line* line2 = NULL; + struct shtr_line line1 = SHTR_LINE_NULL; + struct shtr_line line2 = SHTR_LINE_NULL; CHK(sln_node_get_line(tree1, node1, iline, &line1) == RES_OK); CHK(sln_node_get_line(tree2, node2, iline, &line2) == RES_OK); - CHK(shtr_line_eq(line1, line2)); + CHK(shtr_line_eq(&line1, &line2)); } CHK(sln_node_get_mesh(tree1, node1, &mesh1) == RES_OK); @@ -315,15 +308,14 @@ check_tree_equality static void test_tree_serialization (struct sln_device* sln, - struct shtr* shtr, - struct sln_mixture* mixture) + const struct sln_tree_create_args* tree_args, + struct shtr* shtr) { - struct sln_tree_create_args tree_args = SLN_TREE_CREATE_ARGS_DEFAULT; struct sln_tree* tree1 = NULL; struct sln_tree* tree2 = NULL; FILE* fp = NULL; - CHK(sln_tree_create(mixture, &tree_args, &tree1) == RES_OK); + CHK(sln_tree_create(sln, tree_args, &tree1) == RES_OK); CHK(fp = tmpfile()); CHK(sln_tree_write(NULL, fp) == RES_BAD_ARG); @@ -351,12 +343,12 @@ int main(int argc, char** argv) { struct sln_device_create_args dev_args = SLN_DEVICE_CREATE_ARGS_DEFAULT; - struct sln_mixture_create_args mixture_args = SLN_MIXTURE_CREATE_ARGS_DEFAULT; + struct sln_tree_create_args tree_args = SLN_TREE_CREATE_ARGS_DEFAULT; struct sln_device* sln = NULL; - struct sln_mixture* mixture = NULL; struct shtr_create_args shtr_args = SHTR_CREATE_ARGS_DEFAULT; struct shtr* shtr = NULL; + struct shtr_line_list_load_args line_load_args = SHTR_LINE_LIST_LOAD_ARGS_NULL; struct shtr_line_list* line_list = NULL; struct shtr_isotope_metadata* metadata = NULL; @@ -381,7 +373,10 @@ main(int argc, char** argv) shtr_args.verbose = 1; CHK(shtr_create(&shtr_args, &shtr) == RES_OK); CHK(shtr_isotope_metadata_load_stream(shtr, fp_mdata, NULL, &metadata) == RES_OK); - CHK(shtr_line_list_load_stream(shtr, fp_lines, NULL, &line_list) == RES_OK); + + line_load_args.filename = "stream"; + line_load_args.file = fp_lines; + CHK(shtr_line_list_load(shtr, &line_load_args, &line_list) == RES_OK); CHK(fclose(fp_lines) == 0); CHK(fclose(fp_mdata) == 0); @@ -390,32 +385,23 @@ main(int argc, char** argv) CHK(sln_device_create(&dev_args, &sln) == RES_OK); /* Create the mixture */ - mixture_args.metadata = metadata; - mixture_args.lines = line_list; - mixture_args.molecules[0].nisotopes = 0; /* Handle all isotopes */ - mixture_args.molecules[0].concentration = 1.0/3.0; - mixture_args.molecules[0].cutoff = 25; - mixture_args.molecules[0].id = 1; /* H2O */ - mixture_args.molecules[1].nisotopes = 0; /* Handle all isotopes */ - mixture_args.molecules[1].concentration = 1.0/3.0; - mixture_args.molecules[1].cutoff = 50; - mixture_args.molecules[1].id = 2; /* CO2 */ - mixture_args.molecules[2].nisotopes = 0; /* Handle all isotopes */ - mixture_args.molecules[2].concentration = 1.0/3.0; - mixture_args.molecules[2].cutoff = 25; - mixture_args.molecules[2].id = 3; /* O3 */ - mixture_args.nmolecules = 3; - mixture_args.wavenumber_range[0] = 0; - mixture_args.wavenumber_range[1] = INF; - mixture_args.pressure = 1; - mixture_args.temperature = 296; - CHK(sln_mixture_create(sln, &mixture_args, &mixture) == RES_OK); - - test_tree(mixture, line_list); - test_tree_serialization(sln, shtr, mixture); + tree_args.metadata = metadata; + tree_args.lines = line_list; + tree_args.molecules[SHTR_H2O].concentration = 1.0/3.0; + tree_args.molecules[SHTR_H2O].cutoff = 25; + tree_args.molecules[SHTR_CO2].concentration = 1.0/3.0; + tree_args.molecules[SHTR_CO2].cutoff = 50; + tree_args.molecules[SHTR_O3 ].concentration = 1.0/3.0; + tree_args.molecules[SHTR_O3 ].cutoff = 25; + tree_args.wavenumber_range[0] = 0; + tree_args.wavenumber_range[1] = INF; + tree_args.pressure = 1; + tree_args.temperature = 296; + + test_tree(sln, &tree_args, line_list); + test_tree_serialization(sln, &tree_args, shtr); CHK(sln_device_ref_put(sln) == RES_OK); - CHK(sln_mixture_ref_put(mixture) == RES_OK); CHK(shtr_ref_put(shtr) == RES_OK); CHK(shtr_line_list_ref_put(line_list) == RES_OK); CHK(shtr_isotope_metadata_ref_put(metadata) == RES_OK);