star-phor-input

File format for describing photoreactor configurations
git clone https://www.edstar.cnrs.fr/git/star-phor-input.git
Log | Files | Refs | README | LICENSE

commit 9fc78e68382849e6f70149d783bf770c4b3c03d9
parent 613e91a73513277160ca4f6ed74b6b0200e54c6e
Author: Eduardo Fontana Lazzari <edufonlaz@gmail.com>
Date:   Thu, 13 Nov 2025 16:56:27 +0100

Add refractive index to star-phor-input

Refractive indices can now be declared as part of volumes in
star-phor-input.

The new structure `sphin_refractive_index` is composed of two spectral
properties as member variables: one for the real part and one for the
imaginary part of the refractive index. Thus, each one of these two
variables benefit from the full `sphin_spectral_property` API
(descriptor, interpolation, etc.).

Each part of the refractive index (real and imaginary) is also
independent in the input file. This approach was chosen as it simplifies
parsing, ensures decoupling between the two parts of the refractive
index, and minimizes the amount of new code.

Diffstat:
MMakefile | 7++++---
Mdoc/star-phor-input.scd | 5++++-
Msrc/sphin.h | 27+++++++++++++++++++++++++++
Asrc/sphin_refractive_index.c | 202+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sphin_refractive_index.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/sphin_volume.c | 46+++++++++++++++++++++++++++++++++++++++-------
Msrc/sphin_volume.h | 7++++---
Msrc/test_sphin_load_volume.c | 28++++++++++++++++++++++++----
8 files changed, 352 insertions(+), 18 deletions(-)

diff --git a/Makefile b/Makefile @@ -42,6 +42,7 @@ SRC =\ src/sphin_config.c\ src/sphin_geometry.c\ src/sphin_prop_rad.c\ + src/sphin_refractive_index.c\ src/sphin_scatterer.c\ src/sphin_sensor.c\ src/sphin_sensor_surface.c\ @@ -232,7 +233,7 @@ test_sphin_load_volume \ clean_test: rm -f $(TEST_DEP) $(TEST_OBJ) $(TEST_TGT) rm -f file.txt test_0.stl test_1.stl test_2.stl test_3.stl\ - source_spec.txt abs_cross_sec.txt abs_cross_sec_0.txt\ - abs_cross_sec_1.txt abs_cross_sec_2.txt abs_cross_sec_3.txt\ - abs_cross_sec_4.txt + source_spec.txt abs_cross_sec.txt spectral_property.txt\ + abs_cross_sec_0.txt abs_cross_sec_1.txt abs_cross_sec_2.txt\ + abs_cross_sec_3.txt abs_cross_sec_4.txt for i in $(TEST_SRC); do rm -f "$$(basename "$${i}" ".c")"; done diff --git a/doc/star-phor-input.scd b/doc/star-phor-input.scd @@ -137,7 +137,6 @@ The file format describing a photoreactive system is as follows: <cross-section> ::= 'cross_sections:' <abs-cross-sections> <abs-cross-sections> ::= 'abs_cross_sec:' <prop-file> <spec-unit> <cross-sec-unit> -<prop-file> ::= path % no spaces allowed <spec-unit> ::= %TODO <cross-sec-unit> ::= % should be compatible with concentration-unit | 'm^2/kg' @@ -147,6 +146,9 @@ The file format describing a photoreactive system is as follows: | 'm^2/part' | 'm^2.part^-1' +<refractive_index> ::= 'refractive_index:' + ['n_real:' <prop-file>] + ['n_imag:' <prop-file>] <brdf> ::= 'brdf:' <brdf-type> <reflectivity> <brdf-type> ::= 'LAMBERT' | 'SPECULAR' @@ -175,6 +177,7 @@ The file format describing a photoreactive system is as follows: <collimation-degree> ::= real % Collimation degree > 0 <direction> ::= '['real',' real',' real']' +<prop-file> ::= path % no spaces allowed <comment> ::= '#' string <name> ::= '"'string'"' ``` diff --git a/src/sphin.h b/src/sphin.h @@ -222,6 +222,7 @@ struct sphin_config; /* Physical configuration */ struct sphin_brdf; struct sphin_geometry; struct sphin_prop_rad; +struct sphin_refractive_index; struct sphin_scatterer; struct sphin_sensor_surface; struct sphin_sensor_volume; @@ -342,6 +343,11 @@ sphin_volume_get_prop_rad size_t iprop_rad, struct sphin_prop_rad** prop_rad); +SPHIN_API res_T +sphin_volume_get_refractive_index + (struct sphin_volume* volume, + struct sphin_refractive_index** refr_ind); /* May be NULL <=> no refr_ind */ + /******************************************************************************* * API of the radiative properties ******************************************************************************/ @@ -385,6 +391,27 @@ sphin_scatterer_get_abs_cross_sec struct sphin_spectral_property** abs_cross_sec); /******************************************************************************* + * API of the refractive index + ******************************************************************************/ +SPHIN_API res_T +sphin_refractive_index_ref_get + (struct sphin_refractive_index* refr_ind); + +SPHIN_API res_T +sphin_refractive_index_ref_put + (struct sphin_refractive_index* refr_ind); + +SPHIN_API res_T +sphin_refractive_index_get_n_real + (struct sphin_refractive_index* refr_ind, + struct sphin_spectral_property** n_real); /* May be NULL <=> no n_real */ + +SPHIN_API res_T +sphin_refractive_index_get_n_imag + (struct sphin_refractive_index* refr_ind, + struct sphin_spectral_property** n_imag); /* May be NULL <=> no n_imag */ + +/******************************************************************************* * API of the surface ******************************************************************************/ SPHIN_API res_T diff --git a/src/sphin_refractive_index.c b/src/sphin_refractive_index.c @@ -0,0 +1,202 @@ +/* Copyright (C) 2024-2025 Centre National de la Recherche Scientifique + * Copyright (C) 2024-2025 Clermont Auvergne INP + * Copyright (C) 2024-2025 INSA Lyon + * Copyright (C) 2024-2025 Institut Mines Télécom Albi-Carmaux + * Copyright (C) 2024-2025 Institut National Polytechnique de Toulouse + * Copyright (C) 2024-2025 |Méso|Star> (contact@meso-star.com) + * Copyright (C) 2024-2025 PhotonLyX (info@photonlyx.com) + * Copyright (C) 2024-2025 Université de Lorraine + * Copyright (C) 2024-2025 Université Paul Sabatier + * Copyright (C) 2024-2025 Université Toulouse - Jean Jaurès + * + * 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 200112L /* for strtok_r support */ + +#include "sphin_c.h" +#include "sphin_config.h" +#include "sphin_refractive_index.h" +#include "sphin_spectral_property.h" + +#include <rsys/text_reader.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static res_T +refractive_index_create + (struct sphin* sphin, + struct sphin_refractive_index** out_refractive_index) +{ + struct sphin_refractive_index* refr_ind = NULL; + res_T res = RES_OK; + + ASSERT(NULL != out_refractive_index); + ASSERT(NULL != sphin); + + refr_ind = MEM_CALLOC(sphin->allocator, 1, sizeof(struct sphin_refractive_index)); + if (NULL == refr_ind) { res = RES_MEM_ERR; goto error; } + ref_init(&refr_ind->ref); + SPHIN(ref_get(sphin)); + refr_ind->sphin = sphin; + refr_ind->n_real = NULL; + refr_ind->n_imag = NULL; + +exit: + *out_refractive_index = refr_ind; + return res; +error: + if (NULL != refr_ind) { + SPHIN(refractive_index_ref_put(refr_ind)); + refr_ind = NULL; + } + goto exit; +} + +static void +release_refractive_index + (ref_T* address) +{ + struct sphin_refractive_index* refr_ind = NULL; + struct sphin* sphin = NULL; + + ASSERT(NULL != address); + + refr_ind = CONTAINER_OF(address, struct sphin_refractive_index, ref); + sphin = refr_ind->sphin; + if (NULL != refr_ind->n_real) { + SPHIN(spectral_property_ref_put(refr_ind->n_real)); + } + if (NULL != refr_ind->n_imag) { + SPHIN(spectral_property_ref_put(refr_ind->n_imag)); + } + sphin = refr_ind->sphin; + MEM_RM(sphin->allocator, refr_ind); + SPHIN(ref_put(sphin)); +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +parse_refractive_index + (struct sphin* sphin, + struct txtrdr* txtrdr, + struct sphin_refractive_index** out_refractive_index) +{ + char* token = NULL; + char* token_ptr = NULL; + char* keyword = NULL; + char* filename = NULL; + struct sphin_refractive_index* refr_ind = NULL; + struct str line; + res_T res = RES_OK; + + ASSERT(NULL != sphin); + ASSERT(NULL != txtrdr); + ASSERT(NULL != out_refractive_index); + + str_init(sphin->allocator, &line); + + res = refractive_index_create(sphin, &refr_ind); + if (RES_OK != res) { goto error; } + + res = txtrdr_read_line(txtrdr); + if (RES_OK != res) { goto error; } + + while (NULL != txtrdr_get_line(txtrdr)) { + res = str_set(&line, txtrdr_get_cline(txtrdr)); + if (RES_OK != res) { goto error; } + + token = strtok_r(str_get(&line), ":", &token_ptr); + if (NULL == token){ res = RES_BAD_ARG; goto error; } + keyword = trim_keyword(token); + filename = trim_keyword(token_ptr); + + if (0 == strcmp(keyword, "n_real")) { + res = parse_spectral_property(sphin, filename, &refr_ind->n_real); + if (RES_OK != res) { goto error; } + res = txtrdr_read_line(txtrdr); + if (RES_OK != res) { goto error; } + } + else if (0 == strcmp(keyword, "n_imag")) { + res = parse_spectral_property(sphin, filename, &refr_ind->n_imag); + if (RES_OK != res) { goto error; } + res = txtrdr_read_line(txtrdr); + if (RES_OK != res) { goto error; } + } + else { + break; + } + } + +exit: + str_release(&line); + *out_refractive_index = refr_ind; + return res; +error: + if (NULL != refr_ind) { + SPHIN(refractive_index_ref_put(refr_ind)); + } + refr_ind = NULL; + goto exit; +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +sphin_refractive_index_ref_get + (struct sphin_refractive_index* refr_ind) +{ + if (NULL == refr_ind) { + return RES_BAD_ARG; + } + ref_get(&refr_ind->ref); + return RES_OK; +} + +res_T +sphin_refractive_index_ref_put + (struct sphin_refractive_index* refr_ind) +{ + if (NULL == refr_ind) { + return RES_BAD_ARG; + } + ref_put(&refr_ind->ref, release_refractive_index); + return RES_OK; +} + +res_T +sphin_refractive_index_get_n_real + (struct sphin_refractive_index* refr_ind, + struct sphin_spectral_property** n_real) +{ + if (NULL == refr_ind || NULL == n_real) { + return RES_BAD_ARG; + } + *n_real = refr_ind->n_real; + return RES_OK; +} + +res_T +sphin_refractive_index_get_n_imag + (struct sphin_refractive_index* refr_ind, + struct sphin_spectral_property** n_imag) +{ + if (NULL == refr_ind || NULL == n_imag) { + return RES_BAD_ARG; + } + *n_imag = refr_ind->n_imag; + return RES_OK; +} diff --git a/src/sphin_refractive_index.h b/src/sphin_refractive_index.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2024-2025 Centre National de la Recherche Scientifique + * Copyright (C) 2024-2025 Clermont Auvergne INP + * Copyright (C) 2024-2025 INSA Lyon + * Copyright (C) 2024-2025 Institut Mines Télécom Albi-Carmaux + * Copyright (C) 2024-2025 Institut National Polytechnique de Toulouse + * Copyright (C) 2024-2025 |Méso|Star> (contact@meso-star.com) + * Copyright (C) 2024-2025 PhotonLyX (info@photonlyx.com) + * Copyright (C) 2024-2025 Université de Lorraine + * Copyright (C) 2024-2025 Université Paul Sabatier + * Copyright (C) 2024-2025 Université Toulouse - Jean Jaurès + * + * 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 SPHIN_REFRACTIVE_INDEX_H +#define SPHIN_REFRACTIVE_INDEX_H + +#include "sphin.h" +#include "sphin_prop_rad.h" + +#include <rsys/ref_count.h> + +struct sphin_refractive_index { + struct sphin_spectral_property* n_real; + struct sphin_spectral_property* n_imag; + + struct sphin* sphin; + ref_T ref; +}; + +extern LOCAL_SYM res_T +parse_refractive_index + (struct sphin* sphin, + struct txtrdr* txtrdr, + struct sphin_refractive_index** out_refractive_index); + + +#endif /* SPHIN_REFRACTIVE_INDEX_H */ diff --git a/src/sphin_volume.c b/src/sphin_volume.c @@ -28,6 +28,7 @@ #include "sphin_config.h" #include "sphin_geometry.h" #include "sphin_prop_rad.h" +#include "sphin_refractive_index.h" #include "sphin_sensor_volume.h" #include "sphin_volume.h" @@ -36,7 +37,6 @@ #include <rsys/str.h> #include <rsys/text_reader.h> - /******************************************************************************* * Helper functions ******************************************************************************/ @@ -62,6 +62,7 @@ volume_create SPHIN(ref_get(sphin)); volume->sphin = sphin; volume->sensor_volume = NULL; + volume->refractive_index = NULL; str_init(sphin->allocator, &volume->name); darray_sphin_geometry_ptr_init(sphin->allocator, &volume->geometries); @@ -89,6 +90,7 @@ release_volume struct sphin_prop_rad** prop_rads = NULL; struct sphin* sphin = NULL; struct sphin_sensor_volume* sensor_volume = NULL; + struct sphin_refractive_index* refr_ind = NULL; struct sphin_volume* volume = NULL; ASSERT(NULL != address); @@ -117,12 +119,16 @@ release_volume if (NULL != prop_rads) { darray_sphin_prop_rad_ptr_release(&volume->prop_rads); } - sphin = volume->sphin; sensor_volume = volume->sensor_volume; - MEM_RM(sphin->allocator, volume); if (NULL != sensor_volume) { SPHIN(sensor_volume_ref_put(sensor_volume)); } + refr_ind = volume->refractive_index; + if (NULL != refr_ind) { + SPHIN(refractive_index_ref_put(refr_ind)); + } + sphin = volume->sphin; + MEM_RM(sphin->allocator, volume); SPHIN(ref_put(sphin)); } @@ -263,12 +269,25 @@ parse_volume } else if (0 == strcmp(keyword, "sensor")) { /* for the sensor_volume, - * strings are not allowed in the input file after the : - * check if there is only tabs and spaces after : */ + * strings are not allowed in the input file after the ":" + * check if there is only tabs and spaces after ":" and return an error if + * not */ + token = strtok_r(NULL, "\t ", &token_ptr); + if (NULL != token) { res = RES_BAD_ARG; goto error; } + /* continue parsing otherwise */ + res = parse_sensor_volume + (volume->sphin, txtrdr, name, &volume->sensor_volume); + } + else if (0 == strcmp(keyword, "refractive_index")) { + /* for the sensor_volume, + * strings are not allowed in the input file after the ":" + * check if there is only tabs and spaces after ":" and return an error if + * not */ token = strtok_r(NULL, "\t ", &token_ptr); if (NULL != token) { res = RES_BAD_ARG; goto error; } - res = parse_sensor_volume(volume->sphin, txtrdr, - name, &volume->sensor_volume); + /* continue parsing otherwise */ + res = parse_refractive_index + (volume->sphin, txtrdr, &volume->refractive_index); } else { break; @@ -422,3 +441,16 @@ sphin_volume_get_prop_rad return RES_OK; } + +res_T +sphin_volume_get_refractive_index + (struct sphin_volume* volume, + struct sphin_refractive_index** refr_ind) +{ + if (NULL == volume + || NULL == refr_ind) { + return RES_BAD_ARG; + } + *refr_ind = volume->refractive_index; + return RES_OK; +} diff --git a/src/sphin_volume.h b/src/sphin_volume.h @@ -38,11 +38,12 @@ struct txtrdr; struct sphin_volume { struct str name; - double ka; + double ka; /* DEPRECATED */ + struct sphin_refractive_index* refractive_index; + struct sphin_sensor_volume* sensor_volume; + struct darray_sphin_prop_rad_ptr prop_rads; struct darray_sphin_geometry_ptr geometries; /* dynamic array of struct geometry. see rsys/dynamic_array.h */ - struct darray_sphin_prop_rad_ptr prop_rads; - struct sphin_sensor_volume* sensor_volume; struct sphin* sphin; ref_T ref; }; diff --git a/src/test_sphin_load_volume.c b/src/test_sphin_load_volume.c @@ -91,12 +91,11 @@ write_prop_rad_test_files { FILE* file; static const char* test0 = - "#wv,abs_cross_sec\n" "100 1\n" "200 2\n" "300 3\n" "400 4\n"; - file = fopen("abs_cross_sec_0.txt", "w"); + file = fopen("spectral_property.txt", "w"); CHK(file != NULL); fwrite(test0, sizeof(char), strlen(test0), file); fclose(file); @@ -110,8 +109,10 @@ test_volume_api const char* path = "file.txt"; char* name = NULL; struct sphin_volume* volume = NULL; - struct sphin_sensor_volume* sensor_volume = NULL; struct sphin_prop_rad* prop_rad = NULL; + struct sphin_refractive_index* refr_ind = NULL; + struct sphin_sensor_volume* sensor_volume = NULL; + struct sphin_spectral_property* spec_prop = NULL; size_t nvolumes; size_t nprop_rad; double ka, response_function; @@ -123,7 +124,10 @@ test_volume_api fprintf(fp, "\tprop_rad: \"name\" SCATTERER\n"); fprintf(fp, "\t\tconcentration: 1.935 mol/m^3\n"); fprintf(fp, "\t\tcross_sections:\n"); - fprintf(fp, "\t\t\tabs_cross_sec: abs_cross_sec_0.txt nm m^2/part\n"); + fprintf(fp, "\t\t\tabs_cross_sec: spectral_property.txt nm m^2/part\n"); + fprintf(fp, "\trefractive_index:\n"); + fprintf(fp, "\t\tn_real: spectral_property.txt\n"); + fprintf(fp, "\t\tn_imag: spectral_property.txt\n"); fprintf(fp, "\tsensor:\n"); fprintf(fp, "\t\tresponse_function: 1\n"); fprintf(fp, "\tgeometry: FRONT test_0.stl\n"); @@ -180,6 +184,20 @@ test_volume_api CHK(sphin_sensor_volume_get_response_function(sensor_volume, NULL) == RES_BAD_ARG); CHK(sphin_sensor_volume_get_response_function(sensor_volume, &response_function) == RES_OK); CHK(eq_eps(response_function, 1, 1e-15)); + CHK(sphin_volume_get_refractive_index(NULL, NULL) == RES_BAD_ARG); + CHK(sphin_volume_get_refractive_index(NULL, &refr_ind) == RES_BAD_ARG); + CHK(sphin_volume_get_refractive_index(volume, NULL) == RES_BAD_ARG); + CHK(sphin_volume_get_refractive_index(volume, &refr_ind) == RES_OK); + CHK(sphin_refractive_index_ref_get(refr_ind) == RES_OK); + CHK(sphin_refractive_index_ref_put(refr_ind) == RES_OK); + CHK(sphin_refractive_index_get_n_real(NULL, NULL) == RES_BAD_ARG); + CHK(sphin_refractive_index_get_n_real(refr_ind, NULL) == RES_BAD_ARG); + CHK(sphin_refractive_index_get_n_real(NULL, &spec_prop) == RES_BAD_ARG); + CHK(sphin_refractive_index_get_n_real(refr_ind, &spec_prop) == RES_OK); + CHK(sphin_refractive_index_get_n_imag(NULL, NULL) == RES_BAD_ARG); + CHK(sphin_refractive_index_get_n_imag(refr_ind, NULL) == RES_BAD_ARG); + CHK(sphin_refractive_index_get_n_imag(NULL, &spec_prop) == RES_BAD_ARG); + CHK(sphin_refractive_index_get_n_imag(refr_ind, &spec_prop) == RES_OK); CHK(sphin_volume_ref_get(volume) == RES_OK); CHK(sphin_volume_ref_put(volume) == RES_OK); @@ -188,6 +206,8 @@ test_volume_api CHK(sphin_volume_get_ka(volume, &ka) == RES_OK); CHK(eq_eps(ka, 10, 1e-15)); CHK(sphin_volume_get_sensor(volume, &sensor_volume) == RES_OK); + CHK(sphin_volume_get_refractive_index(volume, &refr_ind) == RES_OK); + CHK(refr_ind == NULL); /* Test volume 2 */ CHK(sphin_config_get_volume(config, 2, &volume) == RES_OK);