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

sphin_scatterer.c (10776B)


      1 /* Copyright (C) 2024-2026 Centre National de la Recherche Scientifique
      2  * Copyright (C) 2024-2026 Clermont Auvergne INP
      3  * Copyright (C) 2024-2026 INSA Lyon
      4  * Copyright (C) 2024-2026 Institut Mines Télécom Albi-Carmaux
      5  * Copyright (C) 2024-2026 Institut National Polytechnique de Toulouse
      6  * Copyright (C) 2024-2026 |Méso|Star> (contact@meso-star.com)
      7  * Copyright (C) 2024-2026 PhotonLyX (info@photonlyx.com)
      8  * Copyright (C) 2024-2026 Université de Lorraine
      9  * Copyright (C) 2024-2026 Université Paul Sabatier
     10  * Copyright (C) 2024-2026 Université Toulouse - Jean Jaurès
     11  *
     12  * This program is free software: you can redistribute it and/or modify
     13  * it under the terms of the GNU General Public License as published by
     14  * the Free Software Foundation, either version 3 of the License, or
     15  * (at your option) any later version.
     16  *
     17  * This program is distributed in the hope that it will be useful,
     18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     20  * GNU General Public License for more details.
     21  *
     22  * You should have received a copy of the GNU General Public License
     23  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     24 #define _POSIX_C_SOURCE 200112L /* for strtok_r support */
     25 
     26 #include "sphin.h"
     27 #include "sphin_c.h"
     28 #include "sphin_config.h"
     29 #include "sphin_prop_rad.h"
     30 #include "sphin_scatterer.h"
     31 #include "sphin_spectral_property.h"
     32 
     33 #include <rsys/cstr.h> /* str_to_double */
     34 #include <rsys/mem_allocator.h>
     35 #include <rsys/ref_count.h>
     36 #include <rsys/rsys.h>
     37 #include <rsys/str.h>
     38 #include <rsys/text_reader.h>
     39 
     40 struct sphin_scatterer{
     41   double concentration;
     42   struct sphin_spectral_property* abs_cross_sec;
     43 
     44   /* TODO struct sphin_spectral_property* sca_cross_sec;
     45    * struct phase_fn* phase_fn;
     46    * struct mie* mie; */
     47 
     48   struct sphin* sphin;
     49   ref_T ref;
     50 };
     51 
     52 /*******************************************************************************
     53  * Helper functions
     54  ******************************************************************************/
     55 static res_T
     56 scatterer_create
     57   (struct sphin* sphin,
     58    struct sphin_scatterer** out_scatterer)
     59 {
     60   struct sphin_scatterer* scatterer = NULL;
     61   res_T res = RES_OK;
     62 
     63   ASSERT(NULL != out_scatterer);
     64   ASSERT(NULL != sphin);
     65 
     66   scatterer = MEM_CALLOC(sphin->allocator, 1, sizeof(struct sphin_scatterer));
     67   if (NULL == scatterer) { res = RES_MEM_ERR; goto error; }
     68   ref_init(&scatterer->ref);
     69   SPHIN(ref_get(sphin));
     70   scatterer->sphin = sphin;
     71   scatterer->abs_cross_sec = NULL;
     72 
     73 exit:
     74   *out_scatterer = scatterer;
     75   return res;
     76 error:
     77   if (NULL != scatterer) {
     78     SPHIN(scatterer_ref_put(scatterer));
     79     scatterer = NULL;
     80   }
     81   goto exit;
     82 }
     83 
     84 static void
     85 release_scatterer
     86   (ref_T* address)
     87 {
     88   struct sphin_scatterer* scatterer = NULL;
     89   struct sphin* sphin = NULL;
     90 
     91   ASSERT(NULL != address);
     92 
     93   scatterer = CONTAINER_OF(address, struct sphin_scatterer, ref);
     94   sphin = scatterer->sphin;
     95   if (NULL != scatterer->abs_cross_sec) {
     96     SPHIN(spectral_property_ref_put(scatterer->abs_cross_sec));
     97   }
     98   MEM_RM(sphin->allocator, scatterer);
     99   SPHIN(ref_put(sphin));
    100 }
    101 
    102 static res_T
    103 parse_concentration
    104   (struct sphin_scatterer* scatterer,
    105    struct txtrdr* txtrdr,
    106    char* value)
    107 {
    108   char* concentration_val = NULL;
    109   char* concentration_unit = NULL;
    110   char* token = NULL;
    111   char* token_ptr = NULL;
    112   res_T res = RES_OK;
    113   double concentration;
    114 
    115   ASSERT(NULL != scatterer);
    116   ASSERT(NULL != txtrdr);
    117 
    118   if (NULL == value){ res = RES_BAD_ARG; goto error; }
    119 
    120   /* Parse concentration value */
    121   concentration_val = strtok_r(value, " \t", &token_ptr);
    122   res = cstr_to_double(concentration_val, &concentration);
    123   if (RES_OK != res) { goto error; }
    124   if (concentration < 0) { res = RES_BAD_ARG; goto error; }
    125 
    126   /* Parse concentration unit and convert its value to unit/m^-3 accordingly,
    127    * where unit is kg, mol or part */
    128   concentration_unit = strtok_r(NULL, " \t", &token_ptr);
    129 
    130   if (0 == strcmp(concentration_unit, "kg/m^3")
    131   ||  0 == strcmp(concentration_unit, "kg.m^-3")
    132   ||  0 == strcmp(concentration_unit, "mol/m^3")
    133   ||  0 == strcmp(concentration_unit, "mol.m^-3")
    134   ||  0 == strcmp(concentration_unit, "part/m^3")
    135   ||  0 == strcmp(concentration_unit, "part.m^-3")
    136   ) {
    137     scatterer->concentration = concentration * 1;
    138   } else
    139   if (0 == strcmp(concentration_unit, "kg/L")
    140   ||  0 == strcmp(concentration_unit, "kg.L^-1")
    141   ||  0 == strcmp(concentration_unit, "mol/L")
    142   ||  0 == strcmp(concentration_unit, "mol.L^-1")
    143   ||  0 == strcmp(concentration_unit, "part/L")
    144   ||  0 == strcmp(concentration_unit, "part.L^-1")
    145   ) {
    146     scatterer->concentration = concentration * 1000;
    147   }
    148   else { res = RES_BAD_ARG; goto error; }
    149 
    150   /* Assert that there isnt anything but the concentration value and its unit
    151    * in the line */
    152   token = strtok_r(NULL, " \t", &token_ptr);
    153   if (NULL != token) { res = RES_BAD_ARG; goto error; }
    154 
    155   res = txtrdr_read_line(txtrdr);
    156   if (RES_OK != res) { goto error; }
    157 
    158 exit:
    159   return res;
    160 error:
    161   goto exit;
    162 }
    163 
    164 static res_T
    165 parse_abs_cross_sec
    166   (struct sphin_scatterer* scatterer,
    167    struct txtrdr* txtrdr,
    168    char* value)
    169 {
    170   char* tokens[3] = {NULL}; /* filename, spectral_unit, property_unit */
    171   char* filename = NULL;
    172   char* spectral_unit = NULL;
    173   char* property_unit = NULL;
    174   char* token = NULL;
    175   char* token_ptr = NULL;
    176   size_t token_count = 0;
    177   res_T res = RES_OK;
    178 
    179   ASSERT(NULL != scatterer);
    180   ASSERT(NULL != txtrdr);
    181 
    182   if (NULL == value) { res = RES_BAD_ARG; goto error; }
    183 
    184   token = strtok_r(value, " \t", &token_ptr);
    185   while (token != NULL && token_count < 3) {
    186     tokens[token_count++] = trim_keyword(token);
    187     token = strtok_r(NULL, " \t", &token_ptr);
    188   }
    189 
    190   /* The number of tokens must be 3 (filename and each one of the units) */
    191   if (token_count != 3) { res = RES_BAD_ARG; goto error; }
    192 
    193   filename = tokens[0];
    194   if (NULL == filename) { res = RES_BAD_ARG; goto error; }
    195   spectral_unit = tokens[1];
    196   if (NULL == spectral_unit) { res = RES_BAD_ARG; goto error; }
    197   property_unit = tokens[2];
    198   if (NULL == property_unit) { res = RES_BAD_ARG; goto error; }
    199 
    200   res = parse_spectral_property
    201     (scatterer->sphin, filename, &scatterer->abs_cross_sec);
    202   if (RES_OK != res) { goto error; }
    203 
    204   res = convert_wavelengths
    205     (&scatterer->abs_cross_sec->wavelengths, spectral_unit);
    206   if (RES_OK != res) { goto error; }
    207 
    208   res = txtrdr_read_line(txtrdr);
    209   if (RES_OK != res) { goto error; }
    210 
    211 exit:
    212   return res;
    213 error:
    214   goto exit;
    215 }
    216 
    217 static res_T
    218 parse_tabulated_cross_sections
    219   (struct sphin_scatterer* scatterer,
    220    struct txtrdr* txtrdr)
    221 {
    222   char* keyword = NULL;
    223   char* token = NULL;
    224   char* token_ptr = NULL;
    225   struct str line;
    226   res_T res = RES_OK;
    227 
    228   ASSERT(NULL != scatterer);
    229   ASSERT(NULL != txtrdr);
    230 
    231   str_init(scatterer->sphin->allocator, &line);
    232 
    233   res = txtrdr_read_line(txtrdr);
    234   if (RES_OK != res) { goto error; }
    235 
    236   while (NULL != txtrdr_get_line(txtrdr)) {
    237     res = str_set(&line, txtrdr_get_cline(txtrdr));
    238     if (RES_OK != res) { goto error; }
    239     /* parse keyword */
    240     token = strtok_r(str_get(&line), ":", &token_ptr);
    241     if (NULL == token){ res = RES_BAD_ARG; goto error; }
    242     keyword = trim_keyword(token);
    243     if (NULL == keyword){ res = RES_BAD_ARG; goto error; }
    244     if (0 == strcmp(keyword, "abs_cross_sec")){
    245       res = parse_abs_cross_sec(scatterer, txtrdr, token_ptr);
    246     }
    247     else {
    248       break;
    249     }
    250     if (RES_OK != res) { goto error; }
    251   }
    252 
    253 exit:
    254   str_release(&line);
    255   return res;
    256 error:
    257   goto exit;
    258 }
    259 
    260 static res_T
    261 parse_cross_sections
    262   (struct sphin_scatterer* scatterer,
    263    struct txtrdr* txtrdr,
    264    char* value)
    265 {
    266   char* type = NULL;
    267   char* token_ptr = NULL;
    268   res_T res = RES_OK;
    269 
    270   type = strtok_r(value, "\t ", &token_ptr);
    271 
    272   if (NULL == type) {
    273     /* Parse the cross sections as imposed in the input file */
    274     res = parse_tabulated_cross_sections(scatterer, txtrdr);
    275     if (RES_OK != res) { goto error; }
    276   } else if (0 == strcmp(type, "MIE")) {
    277     /* TODO Scatterer type is mie */
    278   } else {
    279     res = RES_BAD_ARG; goto error;
    280   }
    281 
    282 exit:
    283   return res;
    284 error:
    285   goto exit;
    286 }
    287 
    288 /*******************************************************************************
    289  * Local functions
    290  ******************************************************************************/
    291 res_T
    292 parse_scatterer
    293   (struct sphin_prop_rad* prop_rad,
    294   struct txtrdr* txtrdr)
    295 {
    296   struct sphin_scatterer* scatterer = NULL;
    297   struct str line;
    298   char* keyword = NULL;
    299   char* token = NULL;
    300   char* token_ptr = NULL;
    301   res_T res = RES_OK;
    302 
    303   ASSERT(NULL != prop_rad);
    304   ASSERT(NULL != txtrdr);
    305 
    306   str_init(prop_rad->sphin->allocator, &line);
    307 
    308   res = scatterer_create(prop_rad->sphin, &scatterer);
    309   if (RES_OK != res) { goto error; }
    310 
    311   res = txtrdr_read_line(txtrdr);
    312   if (RES_OK != res) { goto error; }
    313 
    314   while (NULL != txtrdr_get_line(txtrdr)) {
    315     res = str_set(&line, txtrdr_get_cline(txtrdr));
    316     if (RES_OK != res) { goto error; }
    317     /* parse keyword */
    318     token = strtok_r(str_get(&line), ":", &token_ptr);
    319     if (NULL == token){ res = RES_BAD_ARG; goto error; }
    320     keyword = trim_keyword(token);
    321     if (NULL == keyword){ res = RES_BAD_ARG; goto error; }
    322 
    323     /* parse value */
    324     token = token_ptr;
    325     if (0 == strcmp(keyword, "concentration")){
    326       res = parse_concentration(scatterer, txtrdr, token);
    327     }
    328     else if (0 == strcmp(keyword, "cross_sections")){
    329       res = parse_cross_sections(scatterer, txtrdr, token);
    330     }
    331     else {
    332       break;
    333     }
    334     if (RES_OK != res) { goto error; }
    335   }
    336 
    337 exit:
    338   prop_rad->scatterer = scatterer;
    339   str_release(&line);
    340   return res;
    341 error:
    342   if (NULL != scatterer) {
    343     SPHIN(scatterer_ref_put(scatterer));
    344     scatterer = NULL;
    345   }
    346   goto exit;
    347 }
    348 
    349 /*******************************************************************************
    350  * Exported functions
    351  ******************************************************************************/
    352 res_T
    353 sphin_scatterer_ref_get
    354   (struct sphin_scatterer* scatterer)
    355 {
    356   if (NULL == scatterer) {
    357     return RES_BAD_ARG;
    358   }
    359   ref_get(&scatterer->ref);
    360   return RES_OK;
    361 }
    362 
    363 res_T
    364 sphin_scatterer_ref_put
    365   (struct sphin_scatterer* scatterer)
    366 {
    367   if (NULL == scatterer) {
    368     return RES_BAD_ARG;
    369   }
    370   ref_put(&scatterer->ref, release_scatterer);
    371   return RES_OK;
    372 }
    373 
    374 res_T
    375 sphin_scatterer_get_concentration
    376   (struct sphin_scatterer* scatterer,
    377    double* concentration)
    378 {
    379   if (NULL == scatterer || NULL == concentration) {
    380     return RES_BAD_ARG;
    381   }
    382   *concentration = scatterer->concentration;
    383   return RES_OK;
    384 }
    385 
    386 res_T
    387 sphin_scatterer_get_abs_cross_sec
    388   (struct sphin_scatterer* scatterer,
    389    struct sphin_spectral_property** abs_cross_sec)
    390 {
    391   if (NULL == scatterer || NULL == abs_cross_sec) {
    392     return RES_BAD_ARG;
    393   }
    394   *abs_cross_sec = scatterer->abs_cross_sec;
    395   return RES_OK;
    396 }