shtr_isotope_metadata.c (26461B)
1 /* Copyright (C) 2022, 2025, 2026 |Méso|Star> (contact@meso-star.com) 2 * Copyright (C) 2025, 2026 Université de Lorraine 3 * Copyright (C) 2022 Centre National de la Recherche Scientifique 4 * Copyright (C) 2022 Université Paul Sabatier 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19 #define _POSIX_C_SOURCE 200112L /* strtok_r support */ 20 21 #include "shtr.h" 22 #include "shtr_c.h" 23 #include "shtr_param.h" 24 25 #include <rsys/cstr.h> 26 #include <rsys/dynamic_array_char.h> 27 #include <rsys/ref_count.h> 28 #include <rsys/str.h> 29 #include <rsys/text_reader.h> 30 31 #include <ctype.h> 32 #include <string.h> 33 34 /* Version of the isotope metadata. One should increment it and perform a 35 * version management onto serialized data when the isotope metadata structure 36 * is updated. */ 37 static const int SHTR_ISOTOPE_METADATA_VERSION = 0; 38 39 /* Generate the dynamic array of isotopes */ 40 #define DARRAY_NAME isotope 41 #define DARRAY_DATA struct shtr_isotope 42 #include <rsys/dynamic_array.h> 43 44 struct molecule { 45 struct str name; 46 size_t isotopes_range[2]; /* Range of the [1st and last[ isotopes */ 47 int id; /* Unique identifier of the molecule */ 48 }; 49 #define MOLECULE_IS_VALID(Molecule) ((Molecule)->id >= 0) 50 51 static INLINE void 52 molecule_clear(struct molecule* molecule) 53 { 54 ASSERT(molecule); 55 molecule->isotopes_range[0] = SIZE_MAX; 56 molecule->isotopes_range[1] = 0; 57 molecule->id = -1; 58 } 59 60 static INLINE void 61 molecule_init(struct mem_allocator* allocator, struct molecule* molecule) 62 { 63 str_init(allocator, &molecule->name); 64 molecule_clear(molecule); 65 } 66 67 static INLINE void 68 molecule_release(struct molecule* molecule) 69 { 70 str_release(&molecule->name); 71 } 72 73 static INLINE res_T 74 molecule_copy(struct molecule* dst, const struct molecule* src) 75 { 76 dst->isotopes_range[0] = src->isotopes_range[0]; 77 dst->isotopes_range[1] = src->isotopes_range[1]; 78 dst->id = src->id; 79 return str_copy(&dst->name, &src->name); 80 } 81 82 static INLINE res_T 83 molecule_copy_and_release(struct molecule* dst, struct molecule* src) 84 { 85 dst->isotopes_range[0] = src->isotopes_range[0]; 86 dst->isotopes_range[1] = src->isotopes_range[1]; 87 dst->id = src->id; 88 return str_copy_and_release(&dst->name, &src->name); 89 } 90 91 /* Generate the dynamic array of molecules */ 92 #define DARRAY_NAME molecule 93 #define DARRAY_DATA struct molecule 94 #define DARRAY_FUNCTOR_INIT molecule_init 95 #define DARRAY_FUNCTOR_RELEASE molecule_release 96 #define DARRAY_FUNCTOR_COPY molecule_copy 97 #define DARRAY_FUNCTOR_COPY_AND_RELEASE molecule_copy_and_release 98 #include <rsys/dynamic_array.h> 99 100 struct shtr_isotope_metadata { 101 /* List of molecules and isotopes */ 102 struct darray_molecule molecules; 103 struct darray_isotope isotopes; 104 105 /* Map the global identifier of a molecule to its correspond local index into 106 * the dynamic array into which it is registered */ 107 int molid2idx[SHTR_MAX_MOLECULES_COUNT]; 108 109 struct shtr* shtr; 110 ref_T ref; 111 }; 112 113 /******************************************************************************* 114 * Helper functions 115 ******************************************************************************/ 116 static res_T 117 create_isotope_metadata 118 (struct shtr* shtr, 119 struct shtr_isotope_metadata** out_isotopes) 120 { 121 struct shtr_isotope_metadata* metadata = NULL; 122 res_T res = RES_OK; 123 ASSERT(shtr && out_isotopes); 124 125 metadata = MEM_CALLOC(shtr->allocator, 1, sizeof(*metadata)); 126 if(!metadata) { 127 ERROR(shtr, 128 "Could not allocate the isotope metadata data structure.\n"); 129 res = RES_MEM_ERR; 130 goto error; 131 } 132 ref_init(&metadata->ref); 133 SHTR(ref_get(shtr)); 134 metadata->shtr = shtr; 135 darray_molecule_init(shtr->allocator, &metadata->molecules); 136 darray_isotope_init(shtr->allocator, &metadata->isotopes); 137 memset(metadata->molid2idx, 0xFF, sizeof(metadata->molid2idx)); 138 139 exit: 140 *out_isotopes = metadata; 141 return res; 142 error: 143 if(metadata) { 144 SHTR(isotope_metadata_ref_put(metadata)); 145 metadata = NULL; 146 } 147 goto exit; 148 } 149 150 static res_T 151 flush_molecule 152 (struct shtr_isotope_metadata* metadata, 153 struct molecule* molecule, /* Currently parsed molecule */ 154 struct txtrdr* txtrdr) 155 { 156 size_t ientry = SIZE_MAX; 157 size_t* pimolecule = NULL; 158 res_T res = RES_OK; 159 ASSERT(metadata && molecule && MOLECULE_IS_VALID(molecule)); 160 161 /* Fetch _exclusive_ upper bound */ 162 molecule->isotopes_range[1] = 163 darray_isotope_size_get(&metadata->isotopes); 164 if(molecule->isotopes_range[0] >= molecule->isotopes_range[1]) { 165 WARN(metadata->shtr, 166 "%s:%lu: the %s molecule does not have any isotope.\n", 167 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 168 str_cget(&molecule->name)); 169 } 170 171 /* Fetch the index where the molecule is going to be store */ 172 ientry = darray_molecule_size_get(&metadata->molecules); 173 CHK(ientry < SHTR_MAX_MOLECULES_COUNT); 174 175 /* Store the molecule */ 176 res = darray_molecule_push_back(&metadata->molecules, molecule); 177 if(res != RES_OK) { 178 ERROR(metadata->shtr, 179 "%s: error storing the %s molecule -- %s.\n", 180 txtrdr_get_name(txtrdr), str_cget(&molecule->name), res_to_cstr(res)); 181 goto error; 182 } 183 184 /* Register the molecule */ 185 if(metadata->molid2idx[molecule->id] >= 0) { 186 const struct molecule* molecule2 = NULL; 187 molecule2 = darray_molecule_cdata_get(&metadata->molecules) + *pimolecule; 188 ERROR(metadata->shtr, 189 "%s: cannot register the %s molecule. " 190 "The %s molecule has the same identifier %i.\n", 191 txtrdr_get_name(txtrdr), 192 str_cget(&molecule->name), 193 str_cget(&molecule2->name), 194 molecule->id); 195 res = RES_OK; 196 goto error; 197 } 198 ASSERT((size_t)((int)ientry) == ientry); 199 metadata->molid2idx[molecule->id] = (int)ientry; 200 molecule_clear(molecule); 201 202 exit: 203 return res; 204 error: 205 if(ientry != SIZE_MAX) darray_molecule_resize(&metadata->molecules, ientry); 206 metadata->molid2idx[molecule->id] = -1; 207 goto exit; 208 } 209 210 static res_T 211 parse_molecule 212 (struct shtr_isotope_metadata* metadata, 213 struct molecule* molecule, 214 struct txtrdr* txtrdr) 215 { 216 char* name = NULL; 217 char* id = NULL; 218 char* tk = NULL; 219 char* tk_ctx = NULL; 220 size_t len; 221 res_T res = RES_OK; 222 ASSERT(molecule && txtrdr); 223 224 name = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); 225 id = strtok_r(NULL, " \t", &tk_ctx); 226 227 if(!name) { 228 ERROR(metadata->shtr, "%s:%lu: molecule name is missing.\n", 229 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); 230 res = RES_BAD_ARG; 231 goto error; 232 } 233 234 res = str_set(&molecule->name, name); 235 if(res != RES_OK) { 236 ERROR(metadata->shtr, 237 "%s:%lu: error seting the molecule name `%s' -- %s.\n", 238 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 239 name, res_to_cstr(res)); 240 goto error; 241 } 242 243 len = strlen(id); 244 if(!id || !len || id[0] != '(' || id[len-1] != ')') { 245 ERROR(metadata->shtr, 246 "%s:%lu: invalid definition of the molecule identifier.\n", 247 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); 248 res = RES_BAD_ARG; 249 goto error; 250 } 251 252 id[len-1] = '\0'; /* Rm trailing parenthesis */ 253 res = cstr_to_int(id+1/*Rm leading parenthesis*/, &molecule->id); 254 if(res != RES_OK || !MOLECULE_IS_VALID(molecule)) { 255 id[len-1] = ')'; /* Re-add the trailing parenthesis */ 256 ERROR(metadata->shtr, "%s:%lu: invalid molecule identifier `%s'.\n", 257 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), id); 258 res = RES_BAD_ARG; 259 goto error; 260 } 261 262 tk = strtok_r(NULL, " \t", &tk_ctx); 263 if(tk) { 264 WARN(metadata->shtr, "%s:%lu: unexpected text `%s'.\n", 265 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 266 } 267 268 molecule->isotopes_range[0] = darray_isotope_size_get(&metadata->isotopes); 269 270 exit: 271 return res; 272 error: 273 goto exit; 274 } 275 276 static res_T 277 parse_isotope 278 (struct shtr_isotope_metadata* metadata, 279 struct txtrdr* txtrdr) 280 { 281 struct shtr_isotope isotope = SHTR_ISOTOPE_NULL; 282 struct param_desc param_desc = PARAM_DESC_NULL; 283 struct shtr* shtr = NULL; 284 char* tk = NULL; 285 char* tk_ctx = NULL; 286 size_t local_id = SIZE_MAX; 287 res_T res = RES_OK; 288 ASSERT(metadata && txtrdr); 289 290 shtr = metadata->shtr; 291 param_desc.path = txtrdr_get_name(txtrdr); 292 param_desc.line = txtrdr_get_line_num(txtrdr); 293 294 /* Fetch the index of the molecule to which the isotope belongs */ 295 isotope.molecule_id_local = darray_molecule_size_get(&metadata->molecules); 296 297 tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); 298 param_desc.name = "isotope id"; 299 param_desc.low = 0; 300 param_desc.upp = INT_MAX; 301 param_desc.is_low_incl = 1; 302 param_desc.is_upp_incl = 1; 303 res = parse_param_int(shtr, tk, ¶m_desc, &isotope.id); 304 if(res != RES_OK) goto error; 305 306 tk = strtok_r(NULL, " \t", &tk_ctx); 307 param_desc.name = "isotope abundance"; 308 param_desc.low = 0; 309 param_desc.upp = 1; 310 param_desc.is_low_incl = 0; 311 param_desc.is_upp_incl = 1; 312 res = parse_param_double(shtr, tk, ¶m_desc, &isotope.abundance); 313 if(res != RES_OK) goto error; 314 315 tk = strtok_r(NULL, " \t", &tk_ctx); 316 param_desc.name = "isotope Q(296K)"; 317 param_desc.low = 0; 318 param_desc.upp = INF; 319 param_desc.is_low_incl = 0; 320 param_desc.is_upp_incl = 1; 321 res = parse_param_double(shtr, tk, ¶m_desc, &isotope.Q296K); 322 if(res != RES_OK) goto error; 323 324 tk = strtok_r(NULL, " \t", &tk_ctx); 325 param_desc.name = "isotope state independant degeneracy factor"; 326 param_desc.low = -INT_MAX; 327 param_desc.upp = INT_MAX; 328 param_desc.is_low_incl = 1; 329 param_desc.is_upp_incl = 1; 330 res = parse_param_int(shtr, tk, ¶m_desc, &isotope.gj); 331 if(res != RES_OK) goto error; 332 333 tk = strtok_r(NULL, " \t", &tk_ctx), 334 param_desc.name = "isotope molar mass"; 335 param_desc.low = 0; 336 param_desc.upp = INF; 337 param_desc.is_low_incl = 0; 338 param_desc.is_upp_incl = 1; 339 res = parse_param_double(shtr, tk, ¶m_desc, &isotope.molar_mass); 340 if(res != RES_OK) goto error; 341 342 local_id = darray_isotope_size_get(&metadata->isotopes); 343 344 /* Store the isotope */ 345 res = darray_isotope_push_back(&metadata->isotopes, &isotope); 346 if(res != RES_OK) { 347 ERROR(shtr, "%s:%lu: error storing the isotope %d -- %s.\n", 348 param_desc.path, param_desc.line, isotope.id, res_to_cstr(res)); 349 res = RES_OK; 350 goto error; 351 } 352 353 exit: 354 return res; 355 error: 356 if(local_id != SIZE_MAX) darray_isotope_resize(&metadata->isotopes, local_id); 357 goto exit; 358 } 359 360 static res_T 361 parse_line 362 (struct shtr_isotope_metadata* metadata, 363 struct molecule* molecule, /* Currently parsed molecule */ 364 struct txtrdr* txtrdr) 365 { 366 const char* line = NULL; 367 size_t i; 368 res_T res = RES_OK; 369 ASSERT(metadata && molecule && txtrdr); 370 371 line = txtrdr_get_cline(txtrdr); 372 ASSERT(line); 373 i = strspn(line, " \t"); 374 ASSERT(i < strlen(line)); 375 376 if(isalpha(line[i])) { 377 if(MOLECULE_IS_VALID(molecule)) { 378 res = flush_molecule(metadata, molecule, txtrdr); 379 if(res != RES_OK) goto error; 380 } 381 res = parse_molecule(metadata, molecule, txtrdr); 382 if(res != RES_OK) goto error; 383 } else { 384 if(!MOLECULE_IS_VALID(molecule)) { 385 ERROR(metadata->shtr, "%s:%lu: missing a molecule definition.\n", 386 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); 387 res = RES_BAD_ARG; 388 goto error; 389 } 390 res = parse_isotope(metadata, txtrdr); 391 if(res != RES_OK) goto error; 392 } 393 394 exit: 395 return res; 396 error: 397 goto exit; 398 } 399 400 static res_T 401 load_stream 402 (struct shtr* shtr, 403 FILE* stream, 404 const char* name, 405 struct shtr_isotope_metadata** out_isotopes) 406 { 407 struct molecule molecule; /* Current molecule */ 408 struct shtr_isotope_metadata* metadata = NULL; 409 struct txtrdr* txtrdr = NULL; 410 res_T res = RES_OK; 411 ASSERT(shtr && stream && name && out_isotopes); 412 413 molecule_init(shtr->allocator, &molecule); 414 415 res = create_isotope_metadata(shtr, &metadata); 416 if(res != RES_OK) goto error; 417 418 res = txtrdr_stream(metadata->shtr->allocator, stream, name, 419 0/*No comment char*/, &txtrdr); 420 if(res != RES_OK) { 421 ERROR(shtr, "%s: error creating the text reader -- %s.\n", 422 name, res_to_cstr(res)); 423 goto error; 424 } 425 426 #define READ_LINE { \ 427 res = txtrdr_read_line(txtrdr); \ 428 if(res != RES_OK) { \ 429 ERROR(shtr, "%s: error reading the line `%lu' -- %s.\n", \ 430 name, (unsigned long)txtrdr_get_line_num(txtrdr), res_to_cstr(res)); \ 431 goto error; \ 432 } \ 433 } (void)0 434 435 /* Skip the 1st line that is a comment line */ 436 READ_LINE; 437 if(!txtrdr_get_cline(txtrdr)) goto exit; 438 439 for(;;) { 440 READ_LINE; 441 442 if(!txtrdr_get_cline(txtrdr)) break; /* No more parsed line */ 443 res = parse_line(metadata, &molecule, txtrdr); 444 if(res != RES_OK) goto error; 445 } 446 #undef READ_LINE 447 448 if(MOLECULE_IS_VALID(&molecule)) { 449 res = flush_molecule(metadata, &molecule, txtrdr); 450 if(res != RES_OK) goto error; 451 } 452 453 exit: 454 if(txtrdr) txtrdr_ref_put(txtrdr); 455 *out_isotopes = metadata; 456 molecule_release(&molecule); 457 return res; 458 error: 459 if(metadata) { 460 SHTR(isotope_metadata_ref_put(metadata)); 461 metadata = NULL; 462 } 463 goto exit; 464 } 465 466 static res_T 467 write_molecules 468 (const struct shtr_isotope_metadata* metadata, 469 const char* caller, 470 FILE* stream) 471 { 472 const struct molecule* molecules = NULL; 473 size_t i, nmolecules; 474 res_T res = RES_OK; 475 ASSERT(metadata && caller && stream); 476 477 molecules = darray_molecule_cdata_get(&metadata->molecules); 478 nmolecules = darray_molecule_size_get(&metadata->molecules); 479 480 #define WRITE(Var, Nb) { \ 481 if(fwrite((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ 482 res = RES_IO_ERR; \ 483 goto error; \ 484 } \ 485 } (void)0 486 WRITE(&nmolecules, 1); 487 488 FOR_EACH(i, 0, nmolecules) { 489 const struct molecule* molecule = molecules + i; 490 const size_t len = str_len(&molecule->name); 491 WRITE(&len, 1); 492 WRITE(str_cget(&molecule->name), len); 493 WRITE(molecule->isotopes_range, 2); 494 WRITE(&molecule->id, 1); 495 } 496 #undef WRITE 497 498 exit: 499 return res; 500 error: 501 ERROR(metadata->shtr, "%s: error writing molecules\n", caller); 502 goto exit; 503 } 504 505 static res_T 506 read_molecules 507 (struct shtr_isotope_metadata* metadata, 508 const char* caller, 509 FILE* stream) 510 { 511 struct darray_char name; 512 struct molecule* molecules = NULL; 513 size_t i, nmolecules; 514 res_T res = RES_OK; 515 ASSERT(metadata && caller && stream); 516 517 darray_char_init(metadata->shtr->allocator, &name); 518 519 #define READ(Var, Nb) { \ 520 if(fread((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ 521 if(feof(stream)) { \ 522 res = RES_BAD_ARG; \ 523 } else if(ferror(stream)) { \ 524 res = RES_IO_ERR; \ 525 } else { \ 526 res = RES_UNKNOWN_ERR; \ 527 } \ 528 goto error; \ 529 } \ 530 } (void)0 531 532 READ(&nmolecules, 1); 533 534 res = darray_molecule_resize(&metadata->molecules, nmolecules); 535 if(res != RES_OK) goto error; 536 537 molecules = darray_molecule_data_get(&metadata->molecules); 538 FOR_EACH(i, 0, nmolecules) { 539 struct molecule* molecule = molecules + i; 540 size_t len = 0; 541 542 READ(&len, 1); 543 res = darray_char_resize(&name, len+1); 544 if(res != RES_OK) goto error; 545 546 READ(darray_char_data_get(&name), len); 547 darray_char_data_get(&name)[len] = '\0'; 548 res = str_set(&molecule->name, darray_char_data_get(&name)); 549 if(res != RES_OK) goto error; 550 551 READ(molecule->isotopes_range, 2); 552 READ(&molecule->id, 1); 553 } 554 #undef READ 555 556 exit: 557 darray_char_release(&name); 558 return res; 559 error: 560 ERROR(metadata->shtr, "%s: error reading molecules -- %s.\n", 561 caller, res_to_cstr(res)); 562 goto exit; 563 } 564 565 static res_T 566 write_isotopes 567 (const struct shtr_isotope_metadata* metadata, 568 const char* caller, 569 FILE* stream) 570 { 571 const struct shtr_isotope* isotopes = NULL; 572 size_t nisotopes = 0; 573 res_T res = RES_OK; 574 ASSERT(metadata && caller && stream); 575 576 isotopes = darray_isotope_cdata_get(&metadata->isotopes); 577 nisotopes = darray_isotope_size_get(&metadata->isotopes); 578 579 #define WRITE(Var, Nb) { \ 580 if(fwrite((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ 581 ERROR(metadata->shtr, "%s: error writing isotopes\n", caller); \ 582 res = RES_IO_ERR; \ 583 goto error; \ 584 } \ 585 } (void)0 586 WRITE(&nisotopes, 1); 587 WRITE(isotopes, nisotopes); 588 #undef WRITE 589 590 exit: 591 return res; 592 error: 593 goto exit; 594 } 595 596 static res_T 597 read_isotopes 598 (struct shtr_isotope_metadata* metadata, 599 const char* caller, 600 FILE* stream) 601 { 602 size_t nisotopes = 0; 603 res_T res = RES_OK; 604 ASSERT(metadata && caller && stream); 605 606 #define READ(Var, Nb) { \ 607 if(fread((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ 608 if(feof(stream)) { \ 609 res = RES_BAD_ARG; \ 610 } else if(ferror(stream)) { \ 611 res = RES_IO_ERR; \ 612 } else { \ 613 res = RES_UNKNOWN_ERR; \ 614 } \ 615 goto error; \ 616 } \ 617 } (void)0 618 READ(&nisotopes, 1); 619 res = darray_isotope_resize(&metadata->isotopes, nisotopes); 620 if(res != RES_OK) goto error; 621 READ(darray_isotope_data_get(&metadata->isotopes), nisotopes); 622 #undef READ 623 624 exit: 625 return res; 626 error: 627 ERROR(metadata->shtr, "%s: error reading isotopes -- %s.\n", 628 caller, res_to_cstr(res)); 629 goto exit; 630 } 631 632 static void 633 release_isotope_metadata(ref_T* ref) 634 { 635 struct shtr* shtr = NULL; 636 struct shtr_isotope_metadata* metadata = CONTAINER_OF 637 (ref, struct shtr_isotope_metadata, ref); 638 ASSERT(ref); 639 shtr = metadata->shtr; 640 darray_molecule_release(&metadata->molecules); 641 darray_isotope_release(&metadata->isotopes); 642 MEM_RM(shtr->allocator, metadata); 643 SHTR(ref_put(shtr)); 644 } 645 646 /******************************************************************************* 647 * Exported functions 648 ******************************************************************************/ 649 res_T 650 shtr_isotope_metadata_load 651 (struct shtr* shtr, 652 const char* path, 653 struct shtr_isotope_metadata** metadata) 654 { 655 FILE* file = NULL; 656 res_T res = RES_OK; 657 658 if(!shtr || !path || !metadata) { 659 res = RES_BAD_ARG; 660 goto error; 661 } 662 663 file = fopen(path, "r"); 664 if(!file) { 665 ERROR(shtr, "%s: error opening file `%s'.\n", FUNC_NAME, path); 666 res = RES_IO_ERR; 667 goto error; 668 } 669 670 res = load_stream(shtr, file, path, metadata); 671 if(res != RES_OK) goto error; 672 673 exit: 674 if(file) fclose(file); 675 return res; 676 error: 677 goto exit; 678 } 679 680 res_T 681 shtr_isotope_metadata_load_stream 682 (struct shtr* shtr, 683 FILE* stream, 684 const char* stream_name, 685 struct shtr_isotope_metadata** metadata) 686 { 687 if(!shtr || !stream || !metadata) return RES_BAD_ARG; 688 return load_stream 689 (shtr, stream, stream_name ? stream_name : "<stream>", metadata); 690 } 691 692 res_T 693 shtr_isotope_metadata_create_from_stream 694 (struct shtr* shtr, 695 FILE* stream, 696 struct shtr_isotope_metadata** out_metadata) 697 { 698 struct shtr_isotope_metadata* metadata = NULL; 699 int version = 0; 700 res_T res = RES_OK; 701 702 if(!shtr || !out_metadata || !stream) { 703 res = RES_BAD_ARG; 704 goto error; 705 } 706 707 res = create_isotope_metadata(shtr, &metadata); 708 if(res != RES_OK) goto error; 709 710 #define READ(Var, Nb) { \ 711 if(fread((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ 712 if(feof(stream)) { \ 713 res = RES_BAD_ARG; \ 714 } else if(ferror(stream)) { \ 715 res = RES_IO_ERR; \ 716 } else { \ 717 res = RES_UNKNOWN_ERR; \ 718 } \ 719 ERROR(shtr, "%s: error reading isotope metadata -- %s.\n", \ 720 FUNC_NAME, res_to_cstr(res)); \ 721 goto error; \ 722 } \ 723 } (void)0 724 READ(&version, 1); 725 if(version != SHTR_ISOTOPE_METADATA_VERSION) { 726 ERROR(shtr, 727 "%s: unexpected isotope metadata version %d. " 728 "Expecting a isotope metadata in version %d.\n", 729 FUNC_NAME, version, SHTR_ISOTOPE_METADATA_VERSION); 730 res = RES_BAD_ARG; 731 goto error; 732 } 733 734 res = read_molecules(metadata, FUNC_NAME, stream); 735 if(res != RES_OK) goto error; 736 res = read_isotopes(metadata, FUNC_NAME, stream); 737 if(res != RES_OK) goto error; 738 739 READ(metadata->molid2idx, SHTR_MAX_MOLECULES_COUNT); 740 #undef READ 741 742 exit: 743 if(out_metadata) *out_metadata = metadata; 744 return res; 745 error: 746 if(metadata) { 747 SHTR(isotope_metadata_ref_put(metadata)); 748 metadata = NULL; 749 } 750 goto exit; 751 } 752 753 res_T 754 shtr_isotope_metadata_ref_get 755 (struct shtr_isotope_metadata* metadata) 756 { 757 if(!metadata) return RES_BAD_ARG; 758 ref_get(&metadata->ref); 759 return RES_OK; 760 } 761 762 res_T 763 shtr_isotope_metadata_ref_put 764 (struct shtr_isotope_metadata* metadata) 765 { 766 if(!metadata) return RES_BAD_ARG; 767 ref_put(&metadata->ref, release_isotope_metadata); 768 return RES_OK; 769 } 770 771 res_T 772 shtr_isotope_metadata_get_molecules_count 773 (const struct shtr_isotope_metadata* metadata, 774 size_t* nmolecules) 775 { 776 if(!metadata || !nmolecules) return RES_BAD_ARG; 777 *nmolecules = darray_molecule_size_get(&metadata->molecules); 778 return RES_OK; 779 } 780 781 res_T 782 shtr_isotope_metadata_get_isotopes_count 783 (const struct shtr_isotope_metadata* metadata, 784 size_t* nisotopes) 785 { 786 if(!metadata || !nisotopes) return RES_BAD_ARG; 787 *nisotopes = darray_isotope_size_get(&metadata->isotopes); 788 return RES_OK; 789 } 790 791 res_T 792 shtr_isotope_metadata_get_molecule 793 (const struct shtr_isotope_metadata* metadata, 794 const size_t imolecule, 795 struct shtr_molecule* out_molecule) 796 { 797 const struct molecule* molecule = NULL; 798 res_T res = RES_OK; 799 800 if(!metadata || !out_molecule) { 801 res = RES_BAD_ARG; 802 goto error; 803 } 804 if(imolecule >= darray_molecule_size_get(&metadata->molecules)) { 805 ERROR(metadata->shtr, "%s: invalid molecule index %lu.\n", 806 FUNC_NAME, (unsigned long)imolecule); 807 res = RES_BAD_ARG; 808 goto error; 809 } 810 811 molecule = darray_molecule_cdata_get(&metadata->molecules) + imolecule; 812 out_molecule->name = str_cget(&molecule->name); 813 out_molecule->id = molecule->id; 814 out_molecule->nisotopes = 815 molecule->isotopes_range[1] - molecule->isotopes_range[0]; 816 out_molecule->isotopes = 817 darray_isotope_cdata_get(&metadata->isotopes) + molecule->isotopes_range[0]; 818 819 exit: 820 return res; 821 error: 822 goto exit; 823 } 824 825 res_T 826 shtr_isotope_metadata_find_molecule 827 (struct shtr_isotope_metadata* metadata, 828 const int molecule_id, 829 struct shtr_molecule* out_molecule) 830 { 831 int imolecule = 0; 832 res_T res = RES_OK; 833 834 if(!metadata || !out_molecule) { 835 res = RES_BAD_ARG; 836 goto error; 837 } 838 839 imolecule = metadata->molid2idx[molecule_id]; 840 if(imolecule < 0) { 841 *out_molecule = SHTR_MOLECULE_NULL; 842 } else { 843 res = shtr_isotope_metadata_get_molecule 844 (metadata, (size_t)imolecule, out_molecule); 845 if(res != RES_OK) goto error; 846 } 847 848 exit: 849 return res; 850 error: 851 goto exit; 852 } 853 854 res_T 855 shtr_isotope_metadata_write 856 (const struct shtr_isotope_metadata* metadata, 857 FILE* stream) 858 { 859 res_T res = RES_OK; 860 861 if(!metadata || !stream) { 862 res = RES_BAD_ARG; 863 goto error; 864 } 865 866 #define WRITE(Var, Nb) { \ 867 if(fwrite((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ 868 ERROR(metadata->shtr, "%s: error writing metadata\n", FUNC_NAME); \ 869 res = RES_IO_ERR; \ 870 goto error; \ 871 } \ 872 } (void)0 873 WRITE(&SHTR_ISOTOPE_METADATA_VERSION, 1); 874 875 res = write_molecules(metadata, FUNC_NAME, stream); 876 if(res != RES_OK) goto error; 877 res = write_isotopes(metadata, FUNC_NAME, stream); 878 if(res != RES_OK) goto error; 879 880 WRITE(metadata->molid2idx, SHTR_MAX_MOLECULES_COUNT); 881 #undef WRITE 882 883 exit: 884 return res; 885 error: 886 goto exit; 887 }