star-line

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

commit 2a95e02dd8faf31a06a5042279dc1634b769f188
parent e32936df9a3d7dd53706fa9fdc7dc61ac65b400a
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 29 Jan 2026 16:39:25 +0100

Start implementation of the sln-build tool

Implement argument analysis

Diffstat:
M.gitignore | 1+
MMakefile | 37++++++++++++++++++++++++++++++++++---
Asrc/sln_build.c | 288+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 323 insertions(+), 3 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -6,6 +6,7 @@ *~ .config .gitignore +sln-build tags tags test_* diff --git a/Makefile b/Makefile @@ -26,7 +26,7 @@ LIBNAME_SHARED = libsln.so LIBNAME = $(LIBNAME_$(LIB_TYPE)) default: library -all: library tests +all: library tests utils ################################################################################ # Library building @@ -79,6 +79,38 @@ libsln.o: $(OBJ) $(CC) $(CFLAGS_LIB) -c $< -o $@ ################################################################################ +# Utils +################################################################################ +UTIL_SRC = src/sln_build.c +UTIL_OBJ = $(UTIL_SRC:.c=.o) +UTIL_DEP = $(UTIL_SRC:.c=.d) + +PKG_CONFIG_LOCAL = PKG_CONFIG_PATH="./:$${PKG_CONFIG_PATH}" $(PKG_CONFIG) + +INCS_UTIL = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --cflags rsys sln-local) +LIBS_UTIL = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --libs rsys sln-local) + +CFLAGS_UTIL = -std=c89 $(CFLAGS_EXE) $(INCS_UTIL) +LDFLAGS_UTIL = $(LDFLAGS_EXE) $(LIBS_UTIL) + +utils: library $(UTIL_DEP) + @$(MAKE) -fMakefile \ + $$(for i in $(UTIL_DEP); do printf -- '-f%s\n' "$${i}"; done) \ + sln-build + +sln-build: config.mk sln-local.pc src/sln_build.o $(LIBNAME) + $(CC) $(CFLAGS_UTIL) -o $@ src/sln_build.o $(LDFLAGS_UTIL) + +$(UTIL_DEP): config.mk sln-local.pc + $(CC) $(CFLAGS_UTIL) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@ + +$(UTIL_OBJ): config.mk sln-local.pc + $(CC) $(CFLAGS_UTIL) -c $(@:.o=.c) -o $@ + +clean_utils: + rm -f $(UTIL_OBJ) $(UTIL_DEP) sln-build + +################################################################################ # Installation ################################################################################ pkg: @@ -121,7 +153,7 @@ uninstall: rm -f "$(DESTDIR)$(PREFIX)/share/doc/star-line/COPYING" rm -f "$(DESTDIR)$(PREFIX)/share/doc/star-line/README.md" -clean: clean_test +clean: clean_test clean_utils rm -f $(OBJ) $(DEP) $(LIBNAME) rm -f .config libsln.o sln.pc sln-local.pc @@ -139,7 +171,6 @@ 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) diff --git a/src/sln_build.c b/src/sln_build.c @@ -0,0 +1,288 @@ +/* Copyright (C) 2022, 2026 |Méso|Star> (contact@meso-star.com) + * Copyright (C) 2026 Université de Lorraine + * Copyright (C) 2022 Centre National de la Recherche Scientifique + * Copyright (C) 2022 Université Paul Sabatier + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#define _POSIX_C_SOURCE 200809L /* strtok_r */ + +#include "sln.h" + +#include <rsys/cstr.h> +#include <rsys/mem_allocator.h> +#include <rsys/rsys.h> + +#include <stdio.h> +#include <string.h> +#include <unistd.h> /* getopt */ + +enum line_list_format { + LINE_LIST_HITRAN, + LINE_LIST_SHTR, + LINE_LIST_FORMAT_COUNT__ +}; + +struct args { + /* Spectroscopic parameters */ + const char* lines; + const char* molparams; + enum sln_line_profile line_profile; + + const char* output; + + /* Thermodynamic properties */ + const char* mixture; + double pressure; /* [atm] */ + double temperature; /* [K] */ + + /* Polyline */ + double mesh_decimation_err; + unsigned nvertices_hint; + enum sln_mesh_type mesh_type; + + /* Miscellaneous */ + int quit; + int verbose; + enum line_list_format line_format; +}; +#define ARGS_DEFAULT__ { \ + /* Spectroscopic parameters */ \ + NULL, /* line list */ \ + NULL, /* Isotopologue metadata */ \ + SLN_LINE_PROFILE_VOIGT, /* Line profile */ \ + \ + NULL, /* Output */ \ + \ + /* Thermodynamic properties */ \ + NULL, \ + -1, /* Pressure [atm] */ \ + -1, /* Temperature [K] */ \ + \ + /* Polyline */ \ + 0.01, \ + 16, \ + SLN_MESH_UPPER, \ + \ + /* Miscellaneous */ \ + 0, /* Quit */ \ + 0, /* Verbose */ \ + LINE_LIST_HITRAN /* lines_format */ \ +} +static const struct args ARGS_DEFAULT = ARGS_DEFAULT__; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +usage(FILE* stream) +{ + fprintf(stream, +"usage: sln-build [-hsv] [-e polyline_opt[:polyline_opt ...]] [-l line_profile]\n" +" [-o accel_struct] -P pressure -T temperature -m molparams\n" +" -x mixture [lines]\n"); +} + +static res_T +parse_line_profile(const char* str, enum sln_line_profile* profile) +{ + res_T res = RES_OK; + ASSERT(str && profile); + + if(!strcmp(str, "voigt")) { + *profile = SLN_LINE_PROFILE_VOIGT; + + } else { + fprintf(stderr, "invalid line profile '%s'\n", str); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_mesh_type(const char* str, enum sln_mesh_type* type) +{ + res_T res = RES_OK; + ASSERT(str && type); + + if(!strcmp(str, "fit")) { + *type = SLN_MESH_FIT; + } else if(!strcmp(str, "upper")) { + *type = SLN_MESH_UPPER; + } else { + fprintf(stderr, "invalid mesh type `%s'\n", str); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_polyline_opt(const char* str, void* ptr) +{ + enum { ERR, MESH, VCOUNT } opt; + char buf[BUFSIZ]; + + struct args* args = ptr; + + char* key = NULL; + char* val = NULL; + char* tk_ctx = NULL; + res_T res = RES_OK; + + ASSERT(str && ptr); + + if(strlen(str) >= sizeof(buf) -1/*NULL char*/) { + fprintf(stderr, "could not duplicate polyline option `%s'\n", str); + res = RES_MEM_ERR; + goto error; + } + + strncpy(buf, str, sizeof(buf)); + + key = strtok_r(buf, "=", &tk_ctx); + val = strtok_r(NULL, "", &tk_ctx); + + if(!strcmp(key, "err")) opt = ERR; + else if(!strcmp(key, "mesh")) opt = MESH; + else if(!strcmp(key, "vcount")) opt = MESH; + else { + fprintf(stderr, "invalid polyline option `%s'\n", key); + res = RES_BAD_ARG; + goto error; + } + + switch(opt) { + case ERR: + res = cstr_to_double(val, &args->mesh_decimation_err); + if(res == RES_OK && args->mesh_decimation_err < 0) res = RES_BAD_ARG; + break; + case MESH: + res = parse_mesh_type(val, &args->mesh_type); + break; + case VCOUNT: + res = cstr_to_uint(val, &args->nvertices_hint); + break; + default: FATAL("Unreachable code\n"); break; + } + + if(res != RES_OK) { + fprintf(stderr, + "error while parsing the polyline option `%s' -- %s\n", + str, res_to_cstr(res)); + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +args_init(struct args* args, int argc, char** argv) +{ + int opt = 0; + res_T res = RES_OK; + + ASSERT(args); + + *args = ARGS_DEFAULT; + + while((opt = getopt(argc, argv, "e:hl:o:P:sT:m:vx:")) != -1) { + switch(opt) { + case 'e': + res = cstr_parse_list(optarg, ':', parse_polyline_opt, args); + break; + case 'h': + usage(stdout); + args->quit = 1; + goto exit; + case 'l': + res = parse_line_profile(optarg, &args->line_profile); + break; + case 'o': args->output = optarg; break; + case 'P': + res = cstr_to_double(optarg, &args->pressure); + if(res == RES_OK && args->pressure < 0) res = RES_BAD_ARG; + break; + case 's': args->line_format = LINE_LIST_SHTR; break; + case 'T': + res = cstr_to_double(optarg, &args->temperature); + if(res == RES_OK && args->temperature < 0) res = RES_BAD_ARG; + break; + case 'm': args->molparams = optarg; break; + case 'v': args->verbose += (args->verbose < 3); break; + case 'x': args->mixture = optarg; break; + default: res = RES_BAD_ARG; break; + } + + if(res != RES_OK) { + if(optarg) { + fprintf(stderr, "%s: invalid option argument '%s' -- '%c'\n", + argv[0], optarg, opt); + } + goto error; + } + } + + #define MANDATORY(Cond, Name, Opt) { \ + if(!(Cond)) { \ + fprintf(stderr, "%s: %s missing -- option '-%c'\n", argv[0], (Name), (Opt)); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + } (void)0 + MANDATORY(args->pressure >= 0, "pressure", 'P'); + MANDATORY(args->temperature >= 0, "temperature", 'T'); + MANDATORY(args->molparams, "molparams", 'm'); + MANDATORY(args->mixture, "mixture", 'x'); + #undef MANDATORY + +exit: + return res; +error: + usage(stderr); + goto exit; +} + +/******************************************************************************* + * The program + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct args args = ARGS_DEFAULT; + int err = 0; + res_T res = RES_OK; + + if((res = args_init(&args, argc, argv)) != RES_OK) goto error; + if(args.quit) goto exit; + +exit: + CHK(mem_allocated_size() == 0); + return err; +error: + err = 1; + goto exit; +}