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 }