stardis-parsing.c (84391B)
1 /* Copyright (C) 2018-2025 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "stardis-parsing.h" 17 #include "stardis-app.h" 18 #include "stardis-args.h" 19 #include "stardis-description.h" 20 #include "stardis-hbound.h" 21 #include "stardis-hbound-prog.h" 22 #include "stardis-hfbound.h" 23 #include "stardis-hfbound-prog.h" 24 #include "stardis-tbound.h" 25 #include "stardis-tbound-prog.h" 26 #include "stardis-fbound.h" 27 #include "stardis-fbound-prog.h" 28 #include "stardis-sfconnect.h" 29 #include "stardis-sfconnect-prog.h" 30 #include "stardis-ssconnect.h" 31 #include "stardis-ssconnect-prog.h" 32 #include "stardis-fluid-prog.h" 33 #include "stardis-fluid.h" 34 #include "stardis-solid-prog.h" 35 #include "stardis-solid.h" 36 #include "stardis-program.h" 37 #include "stardis-default.h" 38 #include "stardis-green-types.h" 39 40 #include <rsys/rsys.h> 41 #include <rsys/cstr.h> 42 #include <rsys/double2.h> 43 #include <rsys/double3.h> 44 #include <rsys/logger.h> 45 #include <rsys/text_reader.h> 46 #include <rsys/library.h> 47 48 #include <star/sg3d.h> 49 #include <wordexp.h> 50 #include <stdlib.h> 51 #include <stdio.h> 52 #include <string.h> 53 #ifdef COMPILER_GCC 54 #include <strings.h> /* strcasecmp */ 55 #else 56 #define strcasecmp(s1, s2) _stricmp((s1), (s2)) 57 #endif 58 59 /******************************************************************************* 60 * Local Functions 61 ******************************************************************************/ 62 static void 63 add_geom_ctx_properties 64 (const unsigned itri, 65 unsigned prop[3], 66 void* context) 67 { 68 const struct add_geom_ctx* ctx = context; 69 int i; 70 ASSERT(prop && ctx); (void)itri; 71 ASSERT(itri < ctx->stl_desc.triangles_count); 72 /* Same media for the whole add_geometry set of triangles */ 73 for(i = 0; i < SG3D_PROP_TYPES_COUNT__; i++) prop[i] = ctx->properties[i]; 74 } 75 76 static res_T 77 add_geom_keep_degenerated 78 (const unsigned itri, 79 void* context, 80 int* abort) 81 { 82 const struct add_geom_ctx* ctx = context; 83 struct darray_uint* degenerated; 84 ASSERT(abort && ctx && ctx->custom); (void)abort; 85 ASSERT(itri < ctx->stl_desc.triangles_count); 86 degenerated = ctx->custom; 87 return darray_uint_push_back(degenerated, &itri); 88 } 89 90 static res_T 91 read_sides_and_files 92 (struct stardis* stardis, 93 const int descr_is_intface, /* if 1, don't read side */ 94 const unsigned description_id, 95 wordexp_t* pwordexp, 96 size_t* idx) 97 { 98 char* arg = NULL; 99 int file_count = 0; 100 struct sstl* sstl = NULL; 101 struct add_geom_ctx add_geom_ctx; 102 unsigned current_merge_errors; 103 struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__; 104 struct darray_uint degenerated; 105 struct str str, name; 106 FILE* f = NULL; 107 res_T res = RES_OK; 108 109 ASSERT(stardis && pwordexp && idx); 110 111 darray_uint_init(stardis->allocator, °enerated); 112 str_init(stardis->allocator, &name); 113 str_init(stardis->allocator, &str); 114 callbacks.get_indices = add_geom_ctx_indices; 115 callbacks.get_properties = add_geom_ctx_properties; 116 callbacks.get_position = add_geom_ctx_position; 117 callbacks.degenerated_triangle = add_geom_keep_degenerated; 118 add_geom_ctx.custom = °enerated; 119 120 ERR(sg3d_geometry_get_unique_triangles_with_merge_conflict_count( 121 stardis->geometry.sg3d, ¤t_merge_errors)); 122 123 /* At least one side+name, no side without name */ 124 ERR(sstl_create(stardis->logger, stardis->allocator, 1, &sstl)); 125 for(;;) { 126 unsigned merge_errors; 127 if(descr_is_intface) { 128 add_geom_ctx.properties[SG3D_FRONT] = SG3D_UNSPECIFIED_PROPERTY; 129 add_geom_ctx.properties[SG3D_BACK] = SG3D_UNSPECIFIED_PROPERTY; 130 add_geom_ctx.properties[SG3D_INTFACE] = description_id; 131 } else { 132 if(pwordexp->we_wordc <= *idx 133 || 0 == strcasecmp((arg = pwordexp->we_wordv[(*idx)++]), "PROG_PARAMS")) 134 { 135 if(file_count == 0) { 136 /* At least 1 side */ 137 logger_print(stardis->logger, LOG_ERROR, 138 "Invalid data (missing token 'side')\n"); 139 res = RES_BAD_ARG; 140 goto error; 141 } 142 else break; 143 } 144 add_geom_ctx.properties[SG3D_INTFACE] = SG3D_UNSPECIFIED_PROPERTY; 145 if(0 == strcasecmp(arg, "FRONT")) { 146 add_geom_ctx.properties[SG3D_FRONT] = description_id; 147 add_geom_ctx.properties[SG3D_BACK] = SG3D_UNSPECIFIED_PROPERTY; 148 } 149 else if(0 == strcasecmp(arg, "BACK")) { 150 add_geom_ctx.properties[SG3D_FRONT] = SG3D_UNSPECIFIED_PROPERTY; 151 add_geom_ctx.properties[SG3D_BACK] = description_id; 152 } 153 else if(0 == strcasecmp(arg, "BOTH")) { 154 add_geom_ctx.properties[SG3D_FRONT] = description_id; 155 add_geom_ctx.properties[SG3D_BACK] = description_id; 156 } 157 else { 158 logger_print(stardis->logger, LOG_ERROR, 159 "Invalid side specifier: %s\n", arg); 160 res = RES_BAD_ARG; 161 goto error; 162 } 163 } 164 if(pwordexp->we_wordc <= *idx 165 || 0 == strcasecmp((arg = pwordexp->we_wordv[(*idx)++]), "PROG_PARAMS")) 166 { 167 if(!descr_is_intface /* Has read a side specifier */ 168 || !file_count) /* Need at least 1 file name */ 169 { 170 logger_print(stardis->logger, LOG_ERROR, 171 "Invalid data (missing token 'file name')\n"); 172 res = RES_BAD_ARG; 173 goto error; 174 } 175 else break; 176 } 177 file_count++; 178 res = sstl_load(sstl, arg); 179 if(res == RES_OK) { 180 ERR(sstl_get_desc(sstl, &add_geom_ctx.stl_desc)); 181 ASSERT(add_geom_ctx.stl_desc.vertices_count <= UINT_MAX 182 && add_geom_ctx.stl_desc.triangles_count <= UINT_MAX); 183 logger_print(stardis->logger, LOG_OUTPUT, 184 "Read file '%s': %u triangles found.\n", 185 arg, (unsigned)add_geom_ctx.stl_desc.triangles_count); 186 } else { 187 logger_print(stardis->logger, LOG_ERROR, 188 "Cannot read STL file: '%s'\n", arg); 189 goto error; 190 } 191 192 res = sg3d_geometry_add( 193 stardis->geometry.sg3d, 194 (unsigned)add_geom_ctx.stl_desc.vertices_count, 195 (unsigned)add_geom_ctx.stl_desc.triangles_count, 196 &callbacks, 197 &add_geom_ctx); 198 if(darray_uint_size_get(°enerated)) { 199 size_t c, n; 200 const unsigned* ids = darray_uint_cdata_get(°enerated); 201 c = darray_uint_size_get(°enerated); 202 ASSERT(c <= ULONG_MAX); 203 logger_print(stardis->logger, LOG_WARNING, 204 "File '%s' included %lu degenerated triangles (removed)\n", 205 arg, (unsigned long)c); 206 ERR(str_printf(&str, "Degenerated triangles IDs: %u", ids[0])); 207 FOR_EACH(n, 1, c) { ERR(str_append_printf(&str, ", %u", ids[n])); } 208 logger_print(stardis->logger, LOG_OUTPUT, "%s\n", str_cget(&str)); 209 darray_uint_clear(°enerated); 210 } 211 212 if(res != RES_OK) { 213 logger_print(stardis->logger, LOG_ERROR, 214 "Cannot add file content: '%s'\n", arg); 215 goto error; 216 } 217 /* Check conflicts */ 218 ERR(sg3d_geometry_get_unique_triangles_with_merge_conflict_count( 219 stardis->geometry.sg3d, &merge_errors)); 220 if(current_merge_errors != merge_errors) { 221 int is_for_compute = 222 (stardis->mode & COMPUTE_MODES) && !(stardis->mode & MODE_DUMP_MODEL); 223 if(!str_is_empty(&stardis->dump_model_filename)) { 224 ERR(str_copy(&name, &stardis->dump_model_filename)); 225 ERR(str_append(&name, "_merge_conflits.obj")); 226 f = fopen(str_cget(&name), "w"); 227 if(!f) { 228 logger_print(stardis->logger, LOG_ERROR, 229 "cannot open file '%s' for writing.\n", str_cget(&name)); 230 res = RES_IO_ERR; 231 goto error; 232 } 233 ERR(sg3d_geometry_dump_as_obj(stardis->geometry.sg3d, f, 234 SG3D_OBJ_DUMP_MERGE_CONFLICTS)); 235 fclose(f); f = NULL; 236 } 237 logger_print(stardis->logger, (is_for_compute ? LOG_ERROR : LOG_WARNING), 238 "Merge conflicts found reading file '%s' (%u triangles).\n", 239 arg, merge_errors - current_merge_errors); 240 if(is_for_compute) { 241 res = RES_BAD_ARG; 242 goto error; 243 } 244 } 245 current_merge_errors = merge_errors; 246 } 247 248 end: 249 if(f) fclose(f); 250 str_release(&name); 251 darray_uint_release(°enerated); 252 str_release(&str); 253 if(sstl) SSTL(ref_put(sstl)); 254 return res; 255 error: 256 goto end; 257 } 258 259 /******************************************************************************* 260 * Public Functions 261 ******************************************************************************/ 262 void 263 add_geom_ctx_position 264 (const unsigned ivert, 265 double pos[3], 266 void* context) 267 { 268 const struct add_geom_ctx* ctx = context; 269 const float* v; 270 ASSERT(pos && ctx); 271 ASSERT(ivert < ctx->stl_desc.vertices_count); 272 v = ctx->stl_desc.vertices + 3 * ivert; 273 d3_set_f3(pos, v); 274 } 275 276 void 277 add_geom_ctx_indices 278 (const unsigned itri, 279 unsigned ids[3], 280 void* context) 281 { 282 const struct add_geom_ctx* ctx = context; 283 const unsigned* trg; 284 int i; 285 ASSERT(ids && ctx); 286 ASSERT(itri < ctx->stl_desc.triangles_count); 287 trg = ctx->stl_desc.indices + 3 * itri; 288 for(i = 0; i < 3; i++) ids[i] = trg[i]; 289 } 290 291 static res_T 292 description_set_name 293 (struct stardis* stardis, 294 struct str* name, 295 const char* arg) 296 { 297 res_T res = RES_OK; 298 double foo; 299 const char* keywords[] = { 300 "AUTO", "BACK", "BOTH", "FLUID", "FLUID_PROG", "FRONT", "F_BOUNDARY_FOR_SOLID", 301 "F_BOUNDARY_FOR_SOLID_PROG", "H_BOUNDARY_FOR_FLUID", "H_BOUNDARY_FOR_FLUID_PROG", 302 "HF_BOUNDARY_FOR_SOLID", "HF_BOUNDARY_FOR_SOLID_PROG", 303 "H_BOUNDARY_FOR_SOLID", "H_BOUNDARY_FOR_SOLID_PROG", "PROGRAM", "PROG_PARAMS", 304 "SCALE", "SOLID", "SOLID_PROG", "SOLID_FLUID_CONNECTION", 305 "SOLID_FLUID_CONNECTION_PROG", "SOLID_SOLID_CONNECTION", 306 "SOLID_SOLID_CONNECTION_PROG", "SPHERICAL_SOURCE", "SPHERICAL_SOURCE_PROG", 307 "TRAD", "T_BOUNDARY_FOR_SOLID", "T_BOUNDARY_FOR_SOLID_PROG", "UNKNOWN" }; 308 const char* reason = NULL; 309 size_t i; 310 ASSERT(name && arg); 311 312 /* Use name before uppercasing it */ 313 ERR(str_set(name, arg)); 314 315 if(RES_OK == cstr_to_double(arg, &foo)) { 316 /* A number is not a sensible choice for a name! */ 317 res = RES_BAD_ARG; 318 reason = "number"; 319 goto error; 320 } 321 FOR_EACH(i, 0, sizeof(keywords) / sizeof(*keywords)) { 322 if(0 == strcasecmp(arg, keywords[i])) { 323 /* A keyword is not a sensible choice for a name! */ 324 res = RES_BAD_ARG; 325 reason = "reserved keyword"; 326 goto error; 327 } 328 } 329 if(str_len(name) > DESC_NAME_MAX_LEN) { 330 /* Due to Green export limitations, names are limited in length */ 331 res = RES_BAD_ARG; 332 reason = "too long"; 333 goto error; 334 } 335 /* Name is OK */ 336 337 end: 338 return res; 339 error: 340 ASSERT(reason != NULL); 341 logger_print(stardis->logger, LOG_ERROR, "Invalid name (%s): %s\n", 342 reason, arg); 343 goto end; 344 } 345 346 static struct description* 347 find_description_by_name 348 (struct stardis* stardis, 349 const struct str* name, 350 const struct description* self) 351 { 352 size_t i; 353 ASSERT(stardis && name); 354 355 FOR_EACH(i, 0, darray_descriptions_size_get(&stardis->descriptions)) { 356 struct description* desc 357 = darray_descriptions_data_get(&stardis->descriptions) + i; 358 if(self == desc) continue; 359 if(str_eq(name, get_description_name(desc))) { 360 return desc; 361 } 362 } 363 return NULL; 364 } 365 366 /* H_BOUNDARY_FOR_SOLID Name ref_temperature emissivity specular_fraction hc T_env STL_filenames 367 * H_BOUNDARY_FOR_FLUID Name ref_temperature emissivity specular_fraction hc T_env STL_filenames */ 368 static res_T 369 process_h 370 (struct stardis* stardis, 371 const enum description_type type, 372 wordexp_t* pwordexp) 373 { 374 char* arg = NULL; 375 struct description* desc; 376 size_t sz; 377 struct h_boundary* h_boundary; 378 size_t idx = 1; 379 res_T res = RES_OK; 380 381 ASSERT(stardis && pwordexp); 382 383 stardis->counts.hbound_count++; 384 385 sz = darray_descriptions_size_get(&stardis->descriptions); 386 ERR(darray_descriptions_resize(&stardis->descriptions, sz+1)); 387 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 388 ERR(init_h_boundary(stardis->allocator, &desc->d.h_boundary)); 389 h_boundary = desc->d.h_boundary; 390 desc->type = type; 391 392 CHK_ARG(idx, "h boundary name"); 393 ERR(description_set_name(stardis, &h_boundary->name, arg)); 394 if(find_description_by_name(stardis, &h_boundary->name, desc)) { 395 logger_print(stardis->logger, LOG_ERROR, 396 "Name already used: %s\n", arg); 397 if(res == RES_OK) res = RES_BAD_ARG; 398 goto error; 399 } 400 401 CHK_ARG(idx, "ref_temperature"); 402 res = cstr_to_double(arg, &h_boundary->ref_temperature); 403 if(res != RES_OK || h_boundary->ref_temperature < 0) { 404 logger_print(stardis->logger, LOG_ERROR, 405 "Invalid reference temperature: %s\n", arg); 406 if(res == RES_OK) res = RES_BAD_ARG; 407 goto error; 408 } 409 stardis->t_range[0] = MMIN(stardis->t_range[0], h_boundary->ref_temperature); 410 stardis->t_range[1] = MMAX(stardis->t_range[1], h_boundary->ref_temperature); 411 CHK_ARG(idx, "emissivity"); 412 res = cstr_to_double(arg, &h_boundary->emissivity); 413 if(res != RES_OK 414 || h_boundary->emissivity < 0 415 || h_boundary->emissivity > 1) { 416 logger_print(stardis->logger, LOG_ERROR, "Invalid emissivity: %s\n", arg); 417 if(res == RES_OK) res = RES_BAD_ARG; 418 goto error; 419 } 420 CHK_ARG(idx, "specular fraction"); 421 res = cstr_to_double(arg, &h_boundary->specular_fraction); 422 if(res != RES_OK 423 || h_boundary->specular_fraction < 0 424 || h_boundary->specular_fraction > 1) { 425 logger_print(stardis->logger, LOG_ERROR, 426 "Invalid specular fraction: %s\n", arg); 427 if(res == RES_OK) res = RES_BAD_ARG; 428 goto error; 429 } 430 CHK_ARG(idx, "Convection coefficient"); 431 res = cstr_to_double(arg, &h_boundary->hc); 432 if(res != RES_OK || h_boundary->hc < 0) { 433 logger_print(stardis->logger, LOG_ERROR, 434 "Invalid Convection coefficient: %s\n", arg); 435 if(res == RES_OK) res = RES_BAD_ARG; 436 goto error; 437 } 438 CHK_ARG(idx, "temperature"); 439 res = cstr_to_double(arg, &h_boundary->imposed_temperature); 440 if(res != RES_OK 441 || SDIS_TEMPERATURE_IS_UNKNOWN(h_boundary->imposed_temperature)) { 442 logger_print(stardis->logger, LOG_ERROR, "Invalid temperature: %s\n", arg); 443 if(res == RES_OK) res = RES_BAD_ARG; 444 goto error; 445 } 446 447 if(type == DESC_BOUND_H_FOR_FLUID) 448 ERR(get_dummy_solid_id(stardis, &h_boundary->mat_id)); 449 else { 450 struct fluid* fluid = NULL; 451 ASSERT(type == DESC_BOUND_H_FOR_SOLID); 452 ERR(init_fluid(stardis->allocator, &fluid)); 453 fluid->fluid_id = allocate_stardis_medium_id(stardis); 454 h_boundary->mat_id = fluid->fluid_id; 455 h_boundary->possible_external_fluid = fluid; 456 ASSERT(sz <= UINT_MAX); 457 fluid->desc_id = (unsigned)sz; 458 fluid->imposed_temperature = h_boundary->imposed_temperature; 459 fluid->t0 = stardis->initial_time; 460 fluid->is_outside = 1; 461 fluid->is_green = stardis->mode & (MODE_GREEN_BIN | MODE_GREEN_ASCII); 462 ERR(create_solver_fluid(stardis, fluid)); 463 logger_print(stardis->logger, LOG_OUTPUT, 464 "External fluid created: T=%g (it is medium %u)\n", 465 fluid->imposed_temperature, 466 fluid->fluid_id); 467 } 468 469 ASSERT(sz <= UINT_MAX); 470 ERR(read_sides_and_files(stardis, 1, (unsigned)sz, pwordexp, &idx)); 471 472 end: 473 return res; 474 error: 475 goto end; 476 } 477 478 /* HF_BOUNDARY_FOR_SOLID Name ref_temperature emissivity specular_fraction hc 479 * T_env flux STL_filenames */ 480 static res_T 481 process_hf 482 (struct stardis* stardis, 483 const enum description_type type, 484 wordexp_t* pwordexp) 485 { 486 char* arg = NULL; 487 struct description* desc; 488 size_t sz; 489 struct hf_boundary* hf_boundary; 490 size_t idx = 1; 491 struct fluid* fluid = NULL; 492 res_T res = RES_OK; 493 494 ASSERT(stardis && pwordexp); 495 496 stardis->counts.hbound_count++; 497 498 sz = darray_descriptions_size_get(&stardis->descriptions); 499 ERR(darray_descriptions_resize(&stardis->descriptions, sz+1)); 500 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 501 ERR(init_hf_boundary(stardis->allocator, &desc->d.hf_boundary)); 502 hf_boundary = desc->d.hf_boundary; 503 desc->type = type; 504 505 CHK_ARG(idx, "hf boundary name"); 506 ERR(description_set_name(stardis, &hf_boundary->name, arg)); 507 if(find_description_by_name(stardis, &hf_boundary->name, desc)) { 508 logger_print(stardis->logger, LOG_ERROR, 509 "Name already used: %s\n", arg); 510 if(res == RES_OK) res = RES_BAD_ARG; 511 goto error; 512 } 513 514 CHK_ARG(idx, "ref_temperature"); 515 res = cstr_to_double(arg, &hf_boundary->ref_temperature); 516 if(res != RES_OK || hf_boundary->ref_temperature < 0) { 517 logger_print(stardis->logger, LOG_ERROR, 518 "Invalid reference temperature: %s\n", arg); 519 if(res == RES_OK) res = RES_BAD_ARG; 520 goto error; 521 } 522 stardis->t_range[0] = MMIN(stardis->t_range[0], hf_boundary->ref_temperature); 523 stardis->t_range[1] = MMAX(stardis->t_range[1], hf_boundary->ref_temperature); 524 CHK_ARG(idx, "emissivity"); 525 res = cstr_to_double(arg, &hf_boundary->emissivity); 526 if(res != RES_OK 527 || hf_boundary->emissivity < 0 528 || hf_boundary->emissivity > 1) { 529 logger_print(stardis->logger, LOG_ERROR, "Invalid emissivity: %s\n", arg); 530 if(res == RES_OK) res = RES_BAD_ARG; 531 goto error; 532 } 533 CHK_ARG(idx, "specular fraction"); 534 res = cstr_to_double(arg, &hf_boundary->specular_fraction); 535 if(res != RES_OK 536 || hf_boundary->specular_fraction < 0 537 || hf_boundary->specular_fraction > 1) { 538 logger_print(stardis->logger, LOG_ERROR, 539 "Invalid specular fraction: %s\n", arg); 540 if(res == RES_OK) res = RES_BAD_ARG; 541 goto error; 542 } 543 CHK_ARG(idx, "convection coefficient"); 544 res = cstr_to_double(arg, &hf_boundary->hc); 545 if(res != RES_OK || hf_boundary->hc < 0) { 546 logger_print(stardis->logger, LOG_ERROR, 547 "Invalid convection coefficient: %s\n", arg); 548 if(res == RES_OK) res = RES_BAD_ARG; 549 goto error; 550 } 551 CHK_ARG(idx, "temperature"); 552 res = cstr_to_double(arg, &hf_boundary->imposed_temperature); 553 if(res != RES_OK 554 || SDIS_TEMPERATURE_IS_UNKNOWN(hf_boundary->imposed_temperature)) { 555 logger_print(stardis->logger, LOG_ERROR, "Invalid temperature: %s\n", arg); 556 if(res == RES_OK) res = RES_BAD_ARG; 557 goto error; 558 } 559 CHK_ARG(idx, "flux"); 560 res = cstr_to_double(arg, &hf_boundary->imposed_flux); 561 if(res != RES_OK 562 || hf_boundary->imposed_flux == SDIS_FLUX_NONE) { 563 /* Flux can be < 0 but not undefined */ 564 logger_print(stardis->logger, LOG_ERROR, 565 "Invalid flux: %s\n", arg); 566 if(res == RES_OK) res = RES_BAD_ARG; 567 goto error; 568 } 569 570 ASSERT(type == DESC_BOUND_HF_FOR_SOLID); 571 ERR(init_fluid(stardis->allocator, &fluid)); 572 fluid->fluid_id = allocate_stardis_medium_id(stardis); 573 hf_boundary->mat_id = fluid->fluid_id; 574 hf_boundary->possible_external_fluid = fluid; 575 ASSERT(sz <= UINT_MAX); 576 fluid->desc_id = (unsigned)sz; 577 fluid->imposed_temperature = hf_boundary->imposed_temperature; 578 fluid->t0 = stardis->initial_time; 579 fluid->is_outside = 1; 580 fluid->is_green = stardis->mode & (MODE_GREEN_BIN | MODE_GREEN_ASCII); 581 ERR(create_solver_fluid(stardis, fluid)); 582 logger_print(stardis->logger, LOG_OUTPUT, 583 "External fluid created: T=%g (it is medium %u)\n", 584 fluid->imposed_temperature, 585 fluid->fluid_id); 586 587 ASSERT(sz <= UINT_MAX); 588 ERR(read_sides_and_files(stardis, 1, (unsigned)sz, pwordexp, &idx)); 589 590 end: 591 return res; 592 error: 593 goto end; 594 } 595 596 static res_T 597 set_argc_argv 598 (struct mem_allocator* allocator, 599 const char* prog_name, /* First argument to copy in argv[0] */ 600 size_t* out_argc, 601 char** out_argv[], 602 const wordexp_t* pwordexp, 603 size_t idx) 604 { 605 char** argv = NULL; 606 size_t argc; 607 size_t i, n; 608 res_T res = RES_OK; 609 610 ASSERT(prog_name && out_argc && out_argv && pwordexp); 611 612 if(pwordexp->we_wordc < idx) { 613 res = RES_BAD_ARG; 614 goto error; 615 } 616 617 /* Allocate an additional argument to store the program name as the first 618 * argument. This is not only useful information, but also respects the C 619 * convention for declaring a list of arguments. So anyone can use the 620 * standard getopt function to parse input arguments*/ 621 argc = pwordexp->we_wordc - idx + 1/*program name*/; 622 argv = MEM_CALLOC(allocator, argc, sizeof(char*)); 623 if(argv == NULL) { res = RES_MEM_ERR; goto error; } 624 625 #define STRDUP(Dst, Src) { \ 626 (Dst) = MEM_CALLOC(allocator, 1, 1 + strlen(Src)); \ 627 if((Dst) == NULL) { res = RES_MEM_ERR; goto error; } \ 628 strcpy((Dst), (Src)); /* size is adequate */ \ 629 } (void)0 630 STRDUP(argv[0], prog_name); 631 for(i = idx, n = 1; i < pwordexp->we_wordc; i++, n++) { 632 STRDUP(argv[n], pwordexp->we_wordv[i]); 633 } 634 #undef STRDUP 635 636 end: 637 *out_argc = argc; 638 *out_argv = argv; 639 return res; 640 error: 641 if(argv) { 642 FOR_EACH(i, 0, argc) if(argv[i]) MEM_RM(allocator, argv[i]); 643 MEM_RM(allocator, argv); 644 } 645 argc = 0; 646 argv = NULL; 647 goto end; 648 } 649 650 /* utility macros */ 651 #define GET_LIB_SYMBOL_BASE(DestField, LibHandle, FunName, Optional) \ 652 *(void**)DestField = library_get_symbol((LibHandle), #FunName ); \ 653 if(!*DestField && !(Optional)) { \ 654 logger_print(stardis->logger, LOG_ERROR, \ 655 "Cannot find function '" #FunName "()' in lib %s\n", lib_name); \ 656 res = RES_BAD_ARG; \ 657 goto error; \ 658 } 659 660 #define GET_LIB_SYMBOL(Dest, Field, FunName) \ 661 GET_LIB_SYMBOL_BASE(&((Dest)->Field), (Dest)->program->lib_handle, FunName, 0) 662 663 #define CREATE_DESC_DATA_BASE(Desc, CreateArgs) \ 664 (Desc)->prog_data = (Desc)->create(&ctx, CreateArgs); \ 665 if(!(Desc)->prog_data) { \ 666 logger_print(stardis->logger, LOG_ERROR, \ 667 "Cannot create data for description %s\n", str_cget(&(Desc)->name)); \ 668 res = RES_BAD_ARG; \ 669 goto error; \ 670 } 671 672 #define CREATE_DESC_DATA(Desc) \ 673 CREATE_DESC_DATA_BASE(Desc, \ 674 LIST_ARG3((Desc)->program->prog_data, (Desc)->argc, (Desc)->argv)) 675 676 /* The returned program is NULL if no stardis_create_program function is 677 * defined in the library. */ 678 static res_T 679 get_prog_common 680 (const char* lib_name, 681 struct stardis* stardis, 682 struct program** program, 683 void* (**create) 684 (const struct stardis_description_create_context*, void*, size_t, char**), 685 void (**release)(void*)) 686 { 687 res_T res = RES_OK; 688 struct description* desc; 689 struct str tmp; 690 691 ASSERT(lib_name && program && create && release && stardis); 692 693 /* get the library handler */ 694 str_init(stardis->allocator, &tmp); 695 ERR(str_set(&tmp, lib_name)); 696 desc = find_description_by_name(stardis, &tmp, NULL); 697 if(!desc) { 698 logger_print(stardis->logger, LOG_ERROR, 699 "Undefined PROGRAM: %s\n", lib_name); 700 if(res == RES_OK) res = RES_BAD_ARG; 701 goto error; 702 } 703 else if(desc->type != DESC_PROGRAM) { 704 logger_print(stardis->logger, LOG_ERROR, 705 "Is not a PROGRAM: %s\n", lib_name); 706 if(res == RES_OK) res = RES_BAD_ARG; 707 goto error; 708 } 709 *program = desc->d.program; 710 /* get the mandatory user-defined functions from the library */ 711 GET_LIB_SYMBOL_BASE(create, (*program)->lib_handle, stardis_create_data, 0); 712 GET_LIB_SYMBOL_BASE(release, (*program)->lib_handle, stardis_release_data, 0); 713 714 end: 715 str_release(&tmp); 716 return res; 717 error: 718 goto end; 719 } 720 721 /* PROGRAM Name library_path [...] */ 722 static res_T 723 process_program 724 (struct stardis* stardis, 725 wordexp_t* pwordexp) 726 { 727 char* arg = NULL; 728 struct description* desc; 729 size_t sz; 730 struct program* program; 731 const char* lib_name; 732 const char* lic; 733 const char* _c_; 734 size_t idx = 1; 735 res_T res = RES_OK; 736 737 ASSERT(stardis && pwordexp); 738 739 sz = darray_descriptions_size_get(&stardis->descriptions); 740 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 741 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 742 ERR(init_program(stardis->allocator, &desc->d.program)); 743 program = desc->d.program; 744 desc->type = DESC_PROGRAM; 745 746 CHK_ARG(idx, "program name"); 747 ERR(description_set_name(stardis, &program->name, arg)); 748 if(find_description_by_name(stardis, &program->name, desc)) { 749 logger_print(stardis->logger, LOG_ERROR, 750 "Name already used: %s\n", arg); 751 if(res == RES_OK) res = RES_BAD_ARG; 752 goto error; 753 } 754 lib_name = arg; 755 756 CHK_ARG(idx, "library path"); 757 ERR(str_set(&program->lib_path, arg)); 758 759 /* get the library handler */ 760 program->lib_handle = library_open(arg); 761 if(!program->lib_handle) { 762 logger_print(stardis->logger, LOG_ERROR, 763 "Cannot open library: %s (%s)\n", lib_name, arg); 764 res = RES_BAD_ARG; 765 goto error; 766 } 767 768 /* get the mandatory user-defined functions from the library */ 769 GET_LIB_SYMBOL_BASE(&program->get_copyright_notice, program->lib_handle, 770 get_copyright_notice, 0); 771 GET_LIB_SYMBOL_BASE(&program->get_license_short, program->lib_handle, 772 get_license_short, 0); 773 GET_LIB_SYMBOL_BASE(&program->get_license_text, program->lib_handle, 774 get_license_text, 0); 775 /* get the optional user-defined functions from the library */ 776 GET_LIB_SYMBOL_BASE(&program->create, 777 program->lib_handle, stardis_create_library_data, 1); 778 GET_LIB_SYMBOL_BASE(&program->release, 779 program->lib_handle, stardis_release_library_data, 1); 780 GET_LIB_SYMBOL_BASE(&program->finalize, 781 program->lib_handle, stardis_finalize_library_data, 1); 782 if(!(program->create && program->release && program->finalize) 783 && !(!program->create && !program->release && !program->finalize)) 784 { 785 logger_print(stardis->logger, LOG_ERROR, 786 "Inconsistent library data management for library '%s'.\n", 787 lib_name); 788 logger_print(stardis->logger, LOG_ERROR, 789 "Please define all or none of stardis_create_library_data, " 790 "stardis_finalize_library_data and stardis_release_library_data funcions.\n"); 791 res = RES_BAD_ARG; 792 goto error; 793 } 794 795 /* store the end of line as args for custom init */ 796 ERR(set_argc_argv(stardis->allocator, str_cget(&program->name), 797 &program->argc, &program->argv, pwordexp, idx)); 798 if(program->create) { 799 /* create and init custom data */ 800 struct stardis_program_context ctx; 801 ctx.name = lib_name; 802 switch(stardis->verbose) { 803 case 0: ctx.verbosity_level = STARDIS_VERBOSE_NONE; break; 804 case 1: ctx.verbosity_level = STARDIS_VERBOSE_ERROR; break; 805 case 2: ctx.verbosity_level = STARDIS_VERBOSE_WARNING; break; 806 case 3: ctx.verbosity_level = STARDIS_VERBOSE_INFO; break; 807 default: 808 FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); 809 } 810 CREATE_DESC_DATA_BASE(program, LIST_ARG2(program->argc, program->argv)); 811 } else if(program->argc != 1) { 812 logger_print(stardis->logger, LOG_ERROR, 813 "Library '%s' has no custom data management functions but has arguments:\n", 814 lib_name); 815 for( ; idx < pwordexp->we_wordc; idx++) { 816 logger_print(stardis->logger, LOG_ERROR, "%s\n", pwordexp->we_wordv[idx]); 817 } 818 res = RES_BAD_ARG; 819 goto error; 820 } 821 822 lic = program->get_license_short(program->prog_data); 823 _c_ = program->get_copyright_notice(program->prog_data); 824 if(!lic) { 825 res = RES_BAD_ARG; 826 goto error; 827 } 828 if(!_c_) { 829 res = RES_BAD_ARG; 830 goto error; 831 } 832 logger_print(stardis->logger, LOG_OUTPUT, 833 "Loading external library '%s': \"%s\"\n", 834 str_cget(&program->name), str_cget(&program->lib_path)); 835 logger_print(stardis->logger, LOG_OUTPUT, " %s\n", _c_); 836 logger_print(stardis->logger, LOG_OUTPUT, " %s\n", lic); 837 838 end: 839 return res; 840 error: 841 goto end; 842 } 843 844 /* H_BOUNDARY_FOR_SOLID_PROG Name ProgName STL_filenames [PROG_PARAMS ...] 845 * H_BOUNDARY_FOR_FLUID_PROG Name ProgName STL_filenames [PROG_PARAMS ...] */ 846 static res_T 847 process_h_prog 848 (struct stardis* stardis, 849 const enum description_type type, 850 wordexp_t* pwordexp) 851 { 852 char* arg = NULL; 853 struct description* desc; 854 const char *lib_name, *desc_name; 855 double h_bound_t_range[2] = {DBL_MAX, -DBL_MAX}; 856 size_t sz; 857 struct h_boundary_prog* h_boundary_prog; 858 struct stardis_description_create_context ctx; 859 size_t idx = 1; 860 res_T res = RES_OK; 861 862 ASSERT(stardis && pwordexp); 863 864 stardis->counts.fmed_count++; 865 866 sz = darray_descriptions_size_get(&stardis->descriptions); 867 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 868 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 869 ERR(init_h_boundary_prog(stardis->allocator, &desc->d.h_boundary_prog)); 870 h_boundary_prog = desc->d.h_boundary_prog; 871 desc->type = type; 872 873 CHK_ARG(idx, "programmed h boundary name"); 874 ERR(description_set_name(stardis, &h_boundary_prog->name, arg)); 875 if(find_description_by_name(stardis, &h_boundary_prog->name, desc)) { 876 logger_print(stardis->logger, LOG_ERROR, 877 "Name already used: %s\n", arg); 878 if(res == RES_OK) res = RES_BAD_ARG; 879 goto error; 880 } 881 desc_name = arg; 882 883 CHK_ARG(idx, "program name"); 884 ERR(str_set(&h_boundary_prog->prog_name, arg)); 885 lib_name = arg; 886 887 ASSERT(sz <= UINT_MAX); 888 ERR(read_sides_and_files(stardis, 1, (unsigned)sz, pwordexp, &idx)); 889 890 /* store the end of line as args for custom init */ 891 ERR(set_argc_argv(stardis->allocator, str_cget(&h_boundary_prog->name), 892 &h_boundary_prog->argc, &h_boundary_prog->argv, pwordexp, idx)); 893 /* get the user-defined functions from the library */ 894 ERR(get_prog_common(lib_name, stardis, &h_boundary_prog->program, 895 &h_boundary_prog->create, &h_boundary_prog->release)); 896 GET_LIB_SYMBOL(h_boundary_prog, ref_temp, stardis_reference_temperature); 897 GET_LIB_SYMBOL(h_boundary_prog, emissivity, stardis_emissivity); 898 GET_LIB_SYMBOL(h_boundary_prog, alpha, stardis_specular_fraction); 899 GET_LIB_SYMBOL(h_boundary_prog, hc, stardis_convection_coefficient); 900 GET_LIB_SYMBOL(h_boundary_prog, hmax, stardis_max_convection_coefficient); 901 GET_LIB_SYMBOL(h_boundary_prog, t_range, stardis_t_range); 902 if(type == DESC_BOUND_H_FOR_FLUID_PROG) { 903 GET_LIB_SYMBOL(h_boundary_prog, boundary_temp, stardis_boundary_temperature); 904 } else { 905 GET_LIB_SYMBOL(h_boundary_prog, fluid_temp, stardis_medium_temperature); 906 } 907 /* create and init custom data */ 908 ctx.name = desc_name; 909 CREATE_DESC_DATA(h_boundary_prog); 910 911 h_boundary_prog->t_range(h_boundary_prog->prog_data, h_bound_t_range); 912 if(STARDIS_TEMPERATURE_IS_KNOWN(h_bound_t_range[0])) 913 stardis->t_range[0] = MMIN(stardis->t_range[0], h_bound_t_range[0]); 914 if(STARDIS_TEMPERATURE_IS_KNOWN(h_bound_t_range[1])) 915 stardis->t_range[1] = MMAX(stardis->t_range[1], h_bound_t_range[1]); 916 917 /* create the media behind the interface */ 918 if(type == DESC_BOUND_H_FOR_FLUID_PROG) { 919 ERR(get_dummy_solid_id(stardis, &h_boundary_prog->mat_id)); 920 } else { 921 struct fluid_prog* fluid_prog = NULL; 922 ASSERT(type == DESC_BOUND_H_FOR_SOLID_PROG); 923 ERR(init_fluid_prog(stardis->allocator, &fluid_prog)); 924 fluid_prog->fluid_id = allocate_stardis_medium_id(stardis); 925 h_boundary_prog->mat_id = fluid_prog->fluid_id; 926 h_boundary_prog->possible_external_fluid = fluid_prog; 927 fluid_prog->desc_id = (unsigned)sz; 928 fluid_prog->temp = h_boundary_prog->fluid_temp; 929 fluid_prog->is_outside = 1; 930 fluid_prog->prog_data = h_boundary_prog->prog_data; 931 /* fluid_prog->release is NULL to avoid deleting shared prog_data */ 932 ERR(create_solver_external_fluid_prog(stardis, fluid_prog)); 933 logger_print(stardis->logger, LOG_OUTPUT, 934 "External programmed fluid created (it is medium %u)\n", 935 fluid_prog->fluid_id); 936 } 937 938 end: 939 return res; 940 error: 941 goto end; 942 } 943 944 /* HF_BOUNDARY_FOR_SOLID_PROG Name ProgName STL_filenames [PROG_PARAMS ...] */ 945 static res_T 946 process_hf_prog 947 (struct stardis* stardis, 948 const enum description_type type, 949 wordexp_t* pwordexp) 950 { 951 char* arg = NULL; 952 struct description* desc; 953 const char *lib_name, *desc_name; 954 double hf_bound_t_range[2] = {DBL_MAX, -DBL_MAX}; 955 size_t sz; 956 struct hf_boundary_prog* hf_boundary_prog; 957 struct stardis_description_create_context ctx; 958 struct fluid_prog* fluid_prog = NULL; 959 size_t idx = 1; 960 res_T res = RES_OK; 961 962 ASSERT(stardis && pwordexp); 963 ASSERT(type == DESC_BOUND_HF_FOR_SOLID_PROG); /* No HF prog for fluids */ 964 965 stardis->counts.fmed_count++; 966 967 sz = darray_descriptions_size_get(&stardis->descriptions); 968 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 969 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 970 ERR(init_hf_boundary_prog(stardis->allocator, &desc->d.hf_boundary_prog)); 971 hf_boundary_prog = desc->d.hf_boundary_prog; 972 desc->type = type; 973 974 CHK_ARG(idx, "programmed hf boundary name"); 975 ERR(description_set_name(stardis, &hf_boundary_prog->name, arg)); 976 if(find_description_by_name(stardis, &hf_boundary_prog->name, desc)) { 977 logger_print(stardis->logger, LOG_ERROR, 978 "Name already used: %s\n", arg); 979 if(res == RES_OK) res = RES_BAD_ARG; 980 goto error; 981 } 982 desc_name = arg; 983 984 CHK_ARG(idx, "program name"); 985 ERR(str_set(&hf_boundary_prog->prog_name, arg)); 986 lib_name = arg; 987 988 ASSERT(sz <= UINT_MAX); 989 ERR(read_sides_and_files(stardis, 1, (unsigned)sz, pwordexp, &idx)); 990 991 /* store the end of line as args for custom init */ 992 ERR(set_argc_argv(stardis->allocator, str_cget(&hf_boundary_prog->name), 993 &hf_boundary_prog->argc, &hf_boundary_prog->argv, pwordexp, idx)); 994 /* get the user-defined functions from the library */ 995 ERR(get_prog_common(lib_name, stardis, &hf_boundary_prog->program, 996 &hf_boundary_prog->create, &hf_boundary_prog->release)); 997 GET_LIB_SYMBOL(hf_boundary_prog, ref_temp, stardis_reference_temperature); 998 GET_LIB_SYMBOL(hf_boundary_prog, emissivity, stardis_emissivity); 999 GET_LIB_SYMBOL(hf_boundary_prog, alpha, stardis_specular_fraction); 1000 GET_LIB_SYMBOL(hf_boundary_prog, hc, stardis_convection_coefficient); 1001 GET_LIB_SYMBOL(hf_boundary_prog, hmax, stardis_max_convection_coefficient); 1002 GET_LIB_SYMBOL(hf_boundary_prog, flux, stardis_boundary_flux); 1003 GET_LIB_SYMBOL(hf_boundary_prog, t_range, stardis_t_range); 1004 GET_LIB_SYMBOL(hf_boundary_prog, fluid_temp, stardis_medium_temperature); 1005 /* create and init custom data */ 1006 ctx.name = desc_name; 1007 CREATE_DESC_DATA(hf_boundary_prog); 1008 1009 hf_boundary_prog->t_range(hf_boundary_prog->prog_data, hf_bound_t_range); 1010 if(STARDIS_TEMPERATURE_IS_KNOWN(hf_bound_t_range[0])) 1011 stardis->t_range[0] = MMIN(stardis->t_range[0], hf_bound_t_range[0]); 1012 if(STARDIS_TEMPERATURE_IS_KNOWN(hf_bound_t_range[1])) 1013 stardis->t_range[1] = MMAX(stardis->t_range[1], hf_bound_t_range[1]); 1014 1015 /* create the media behind the interface */ 1016 ERR(init_fluid_prog(stardis->allocator, &fluid_prog)); 1017 fluid_prog->fluid_id = allocate_stardis_medium_id(stardis); 1018 hf_boundary_prog->mat_id = fluid_prog->fluid_id; 1019 hf_boundary_prog->possible_external_fluid = fluid_prog; 1020 fluid_prog->desc_id = (unsigned)sz; 1021 fluid_prog->temp = hf_boundary_prog->fluid_temp; 1022 fluid_prog->is_outside = 1; 1023 fluid_prog->prog_data = hf_boundary_prog->prog_data; 1024 /* fluid_prog->release is NULL to avoid deleting shared prog_data */ 1025 ERR(create_solver_external_fluid_prog(stardis, fluid_prog)); 1026 logger_print(stardis->logger, LOG_OUTPUT, 1027 "External programmed fluid created (it is medium %u)\n", 1028 fluid_prog->fluid_id); 1029 1030 end: 1031 return res; 1032 error: 1033 goto end; 1034 } 1035 1036 /* T_BOUNDARY_FOR_SOLID Name T STL_filenames */ 1037 static res_T 1038 process_t 1039 (struct stardis* stardis, 1040 wordexp_t* pwordexp) 1041 { 1042 char* arg = NULL; 1043 struct description* desc; 1044 size_t sz; 1045 struct t_boundary* t_boundary; 1046 size_t idx = 1; 1047 res_T res = RES_OK; 1048 1049 ASSERT(stardis && pwordexp); 1050 1051 stardis->counts.tbound_count++; 1052 1053 sz = darray_descriptions_size_get(&stardis->descriptions); 1054 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 1055 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 1056 ERR(init_t_boundary(stardis->allocator, &desc->d.t_boundary)); 1057 t_boundary = desc->d.t_boundary; 1058 desc->type = DESC_BOUND_T_FOR_SOLID; 1059 1060 ERR(get_dummy_fluid_id(stardis, &t_boundary->mat_id)); 1061 1062 1063 CHK_ARG(idx, "temperature boundary name"); 1064 ERR(description_set_name(stardis, &t_boundary->name, arg)); 1065 if(find_description_by_name(stardis, &t_boundary->name, desc)) { 1066 logger_print(stardis->logger, LOG_ERROR, 1067 "Name already used: %s\n", arg); 1068 if(res == RES_OK) res = RES_BAD_ARG; 1069 goto error; 1070 } 1071 1072 CHK_ARG(idx, "temperature"); 1073 res = cstr_to_double(arg, &t_boundary->imposed_temperature); 1074 if(res != RES_OK 1075 || SDIS_TEMPERATURE_IS_UNKNOWN(t_boundary->imposed_temperature)) { 1076 logger_print(stardis->logger, LOG_ERROR, "Invalid temperature: %s\n", arg); 1077 if(res == RES_OK) res = RES_BAD_ARG; 1078 goto error; 1079 } 1080 1081 /* Temporarily use the set temperature as a reference temperature. 1082 * TODO use a different reference temperature when the file format is updated 1083 * to allow explicit definition by the user. */ 1084 stardis->t_range[0] = MMIN(stardis->t_range[0], t_boundary->imposed_temperature); 1085 stardis->t_range[1] = MMAX(stardis->t_range[1], t_boundary->imposed_temperature); 1086 1087 ASSERT(sz <= UINT_MAX); 1088 ERR(read_sides_and_files(stardis, 1, (unsigned)sz, pwordexp, &idx)); 1089 1090 end: 1091 return res; 1092 error: 1093 goto end; 1094 } 1095 1096 /* T_BOUNDARY_FOR_SOLID_PROG Name ProgName STL_filenames [PROG_PARAMS ...] */ 1097 static res_T 1098 process_t_prog 1099 (struct stardis* stardis, 1100 wordexp_t* pwordexp) 1101 { 1102 char* arg = NULL; 1103 struct description* desc; 1104 const char *lib_name, *desc_name; 1105 double t_bound_t_range[2] = {DBL_MAX, -DBL_MAX}; 1106 size_t sz; 1107 struct t_boundary_prog* t_boundary_prog; 1108 struct stardis_description_create_context ctx; 1109 size_t idx = 1; 1110 res_T res = RES_OK; 1111 1112 ASSERT(stardis && pwordexp); 1113 1114 stardis->counts.fmed_count++; 1115 1116 sz = darray_descriptions_size_get(&stardis->descriptions); 1117 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 1118 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 1119 ERR(init_t_boundary_prog(stardis->allocator, &desc->d.t_boundary_prog)); 1120 t_boundary_prog = desc->d.t_boundary_prog; 1121 desc->type = DESC_BOUND_T_FOR_SOLID_PROG; 1122 1123 ERR(get_dummy_fluid_id(stardis, &t_boundary_prog->mat_id)); 1124 1125 CHK_ARG(idx, "programmed t boundary name"); 1126 ERR(description_set_name(stardis, &t_boundary_prog->name, arg)); 1127 if(find_description_by_name(stardis, &t_boundary_prog->name, desc)) { 1128 logger_print(stardis->logger, LOG_ERROR, 1129 "Name already used: %s\n", arg); 1130 if(res == RES_OK) res = RES_BAD_ARG; 1131 goto error; 1132 } 1133 desc_name = arg; 1134 1135 CHK_ARG(idx, "program name"); 1136 ERR(str_set(&t_boundary_prog->prog_name, arg)); 1137 lib_name = arg; 1138 1139 ASSERT(sz <= UINT_MAX); 1140 ERR(read_sides_and_files(stardis, 1, (unsigned)sz, pwordexp, &idx)); 1141 1142 /* store the end of line as args for custom init */ 1143 ERR(set_argc_argv(stardis->allocator, str_cget(&t_boundary_prog->name), 1144 &t_boundary_prog->argc, &t_boundary_prog->argv, pwordexp, idx)); 1145 /* get the user-defined functions from the library */ 1146 ERR(get_prog_common(lib_name, stardis, &t_boundary_prog->program, 1147 &t_boundary_prog->create, &t_boundary_prog->release)); 1148 GET_LIB_SYMBOL(t_boundary_prog, temperature, stardis_boundary_temperature); 1149 GET_LIB_SYMBOL(t_boundary_prog, t_range, stardis_t_range); 1150 /* create and init custom data */ 1151 ctx.name = desc_name; 1152 CREATE_DESC_DATA(t_boundary_prog); 1153 1154 t_boundary_prog->t_range(t_boundary_prog->prog_data, t_bound_t_range); 1155 if(STARDIS_TEMPERATURE_IS_KNOWN(t_bound_t_range[0])) 1156 stardis->t_range[0] = MMIN(stardis->t_range[0], t_bound_t_range[0]); 1157 if(STARDIS_TEMPERATURE_IS_KNOWN(t_bound_t_range[1])) 1158 stardis->t_range[1] = MMAX(stardis->t_range[1], t_bound_t_range[1]); 1159 1160 end: 1161 return res; 1162 error: 1163 goto end; 1164 } 1165 1166 /* F_BOUNDARY_FOR_SOLID Name F STL_filenames */ 1167 static res_T 1168 process_flx 1169 (struct stardis* stardis, 1170 wordexp_t* pwordexp) 1171 { 1172 char* arg = NULL; 1173 struct description* desc; 1174 size_t sz; 1175 struct f_boundary* f_boundary; 1176 size_t idx = 1; 1177 res_T res = RES_OK; 1178 1179 ASSERT(stardis && pwordexp); 1180 1181 stardis->counts.fbound_count++; 1182 1183 sz = darray_descriptions_size_get(&stardis->descriptions); 1184 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 1185 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 1186 ERR(init_f_boundary(stardis->allocator, &desc->d.f_boundary)); 1187 f_boundary = desc->d.f_boundary; 1188 desc->type = DESC_BOUND_F_FOR_SOLID; 1189 1190 ERR(get_dummy_fluid_id(stardis, &f_boundary->mat_id)); 1191 1192 CHK_ARG(idx, "flux boundary name"); 1193 ERR(description_set_name(stardis, &f_boundary->name, arg)); 1194 if(find_description_by_name(stardis, &f_boundary->name, desc)) { 1195 logger_print(stardis->logger, LOG_ERROR, 1196 "Name already used: %s\n", arg); 1197 if(res == RES_OK) res = RES_BAD_ARG; 1198 goto error; 1199 } 1200 1201 CHK_ARG(idx, "flux"); 1202 res = cstr_to_double(arg, &f_boundary->imposed_flux); 1203 if(res != RES_OK 1204 || f_boundary->imposed_flux == SDIS_FLUX_NONE) { 1205 /* Flux can be < 0 but not undefined */ 1206 if(res == RES_OK) res = RES_BAD_ARG; 1207 logger_print(stardis->logger, LOG_ERROR, "Invalid flux: %s\n", arg); 1208 goto error; 1209 } 1210 if(f_boundary->imposed_flux != 0 && stardis->picard_order > 1) { 1211 logger_print(stardis->logger, LOG_ERROR, 1212 "Cannot have a flux defined at a boundary (here %f) if Picard order " 1213 "is not 1 (here order is %u)\n", 1214 f_boundary->imposed_flux, stardis->picard_order); 1215 res = RES_BAD_ARG; 1216 goto error; 1217 } 1218 1219 ASSERT(sz <= UINT_MAX); 1220 ERR(read_sides_and_files(stardis, 1, (unsigned)sz, pwordexp, &idx)); 1221 1222 end: 1223 return res; 1224 error: 1225 goto end; 1226 } 1227 1228 /* F_BOUNDARY_FOR_SOLID_PROG Name ProgName STL_filenames [PROG_PARAMS ...] */ 1229 static res_T 1230 process_flx_prog 1231 (struct stardis* stardis, 1232 wordexp_t* pwordexp) 1233 { 1234 char* arg = NULL; 1235 struct description* desc; 1236 const char *lib_name, *desc_name; 1237 size_t sz; 1238 struct f_boundary_prog* f_boundary_prog; 1239 struct stardis_description_create_context ctx; 1240 size_t idx = 1; 1241 res_T res = RES_OK; 1242 1243 ASSERT(stardis && pwordexp); 1244 1245 stardis->counts.fmed_count++; 1246 1247 sz = darray_descriptions_size_get(&stardis->descriptions); 1248 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 1249 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 1250 ERR(init_f_boundary_prog(stardis->allocator, &desc->d.f_boundary_prog)); 1251 f_boundary_prog = desc->d.f_boundary_prog; 1252 desc->type = DESC_BOUND_F_FOR_SOLID_PROG; 1253 1254 ERR(get_dummy_fluid_id(stardis, &f_boundary_prog->mat_id)); 1255 1256 CHK_ARG(idx, "programmed t boundary name"); 1257 ERR(description_set_name(stardis, &f_boundary_prog->name, arg)); 1258 if(find_description_by_name(stardis, &f_boundary_prog->name, desc)) { 1259 logger_print(stardis->logger, LOG_ERROR, 1260 "Name already used: %s\n", arg); 1261 if(res == RES_OK) res = RES_BAD_ARG; 1262 goto error; 1263 } 1264 1265 CHK_ARG(idx, "program name"); 1266 ERR(str_set(&f_boundary_prog->prog_name, arg)); 1267 desc_name = arg; 1268 desc_name = arg; 1269 lib_name = arg; 1270 1271 ASSERT(sz <= UINT_MAX); 1272 ERR(read_sides_and_files(stardis, 1, (unsigned)sz, pwordexp, &idx)); 1273 1274 /* store the end of line as args for custom init */ 1275 ERR(set_argc_argv(stardis->allocator, str_cget(&f_boundary_prog->name), 1276 &f_boundary_prog->argc, &f_boundary_prog->argv, pwordexp, idx)); 1277 /* get the user-defined functions from the library */ 1278 ERR(get_prog_common(lib_name, stardis, &f_boundary_prog->program, 1279 &f_boundary_prog->create, &f_boundary_prog->release)); 1280 GET_LIB_SYMBOL(f_boundary_prog, flux, stardis_boundary_flux); 1281 /* create and init custom data */ 1282 ctx.name = desc_name; 1283 CREATE_DESC_DATA(f_boundary_prog); 1284 1285 end: 1286 return res; 1287 error: 1288 goto end; 1289 } 1290 1291 /* SOLID_FLUID_CONNECTION Name ref_temperature emissivity specular_fraction hc STL_filenames */ 1292 static res_T 1293 process_sfc 1294 (struct stardis* stardis, 1295 const int with_flux, 1296 wordexp_t* pwordexp) 1297 { 1298 char* arg = NULL; 1299 struct description* desc; 1300 size_t sz; 1301 struct solid_fluid_connect* sf_connect; 1302 size_t idx = 1; 1303 res_T res = RES_OK; 1304 1305 ASSERT(stardis && pwordexp); 1306 1307 stardis->counts.sfconnect_count++; 1308 1309 sz = darray_descriptions_size_get(&stardis->descriptions); 1310 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 1311 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 1312 ERR(init_sf_connect(stardis->allocator, &desc->d.sf_connect)); 1313 sf_connect = desc->d.sf_connect; 1314 desc->type = DESC_SOLID_FLUID_CONNECT; 1315 1316 /* Use a medium ID even if there is no medium here 1317 * As other cases use media IDs as unique IDs for read_sides_and_files calls 1318 * we continue the trend to ensure connection ID is OK */ 1319 sf_connect->connection_id = allocate_stardis_medium_id(stardis); 1320 1321 CHK_ARG(idx, "solid-fluid connection name"); 1322 ERR(description_set_name(stardis, &sf_connect->name, arg)); 1323 if(find_description_by_name(stardis, &sf_connect->name, desc)) { 1324 logger_print(stardis->logger, LOG_ERROR, 1325 "Name already used: %s\n", arg); 1326 if(res == RES_OK) res = RES_BAD_ARG; 1327 goto error; 1328 } 1329 1330 CHK_ARG(idx, "ref_temperature"); 1331 res = cstr_to_double(arg, &sf_connect->ref_temperature); 1332 if(res != RES_OK || sf_connect->ref_temperature < 0) { 1333 logger_print(stardis->logger, LOG_ERROR, 1334 "Invalid reference temperature: %s\n", arg); 1335 if(res == RES_OK) res = RES_BAD_ARG; 1336 goto error; 1337 } 1338 stardis->t_range[0] = MMIN(stardis->t_range[0], sf_connect->ref_temperature); 1339 stardis->t_range[1] = MMAX(stardis->t_range[1], sf_connect->ref_temperature); 1340 CHK_ARG(idx, "emissivity"); 1341 res = cstr_to_double(arg, &sf_connect->emissivity); 1342 if(res != RES_OK 1343 || sf_connect->emissivity < 0 1344 || sf_connect->emissivity > 1) { 1345 logger_print(stardis->logger, LOG_ERROR, "Invalid emissivity: %s\n", arg); 1346 if(res == RES_OK) res = RES_BAD_ARG; 1347 goto error; 1348 } 1349 CHK_ARG(idx, "specular fraction"); 1350 res = cstr_to_double(arg, &sf_connect->specular_fraction); 1351 if(res != RES_OK 1352 || sf_connect->specular_fraction < 0 1353 || sf_connect->specular_fraction > 1) { 1354 logger_print(stardis->logger, LOG_ERROR, 1355 "Invalid specular fraction: %s\n", arg); 1356 if(res == RES_OK) res = RES_BAD_ARG; 1357 goto error; 1358 } 1359 CHK_ARG(idx, "convection coefficient"); 1360 res = cstr_to_double(arg, &sf_connect->hc); 1361 if(res != RES_OK || sf_connect->hc < 0) { 1362 logger_print(stardis->logger, LOG_ERROR, 1363 "Invalid convection coefficient: %s\n", arg); 1364 if(res == RES_OK) res = RES_BAD_ARG; 1365 goto error; 1366 } 1367 1368 if(with_flux) { 1369 CHK_ARG(idx, "flux"); 1370 res = cstr_to_double(arg, &sf_connect->flux); 1371 if(res != RES_OK) { 1372 logger_print(stardis->logger, LOG_ERROR, 1373 "Invalid flux: %s\n", arg); 1374 goto error; 1375 } 1376 } 1377 1378 ASSERT(sz <= UINT_MAX); 1379 ERR(read_sides_and_files(stardis, 1, (unsigned)sz, pwordexp, &idx)); 1380 1381 end: 1382 return res; 1383 error: 1384 goto end; 1385 } 1386 1387 /* SOLID_FLUID_CONNECTION_PROG Name ProgName STL_filenames [PROG_PARAMS ...] */ 1388 static res_T 1389 process_sfc_prog 1390 (struct stardis* stardis, 1391 const int with_flux, 1392 wordexp_t* pwordexp) 1393 { 1394 char* arg = NULL; 1395 struct description* desc; 1396 const char *lib_name, *desc_name; 1397 double sf_t_range[2] = {DBL_MAX, -DBL_MAX}; 1398 size_t sz; 1399 struct solid_fluid_connect_prog* sf_connect_prog; 1400 struct stardis_description_create_context ctx; 1401 size_t idx = 1; 1402 res_T res = RES_OK; 1403 1404 ASSERT(stardis && pwordexp); 1405 1406 stardis->counts.sfconnect_count++; 1407 1408 sz = darray_descriptions_size_get(&stardis->descriptions); 1409 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 1410 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 1411 ERR(init_sf_connect_prog(stardis->allocator, &desc->d.sf_connect_prog)); 1412 sf_connect_prog = desc->d.sf_connect_prog; 1413 desc->type = DESC_SOLID_FLUID_CONNECT_PROG; 1414 1415 CHK_ARG(idx, "programmed solid-fluid connection name"); 1416 ERR(description_set_name(stardis, &sf_connect_prog->name, arg)); 1417 if(find_description_by_name(stardis, &sf_connect_prog->name, desc)) { 1418 logger_print(stardis->logger, LOG_ERROR, 1419 "Name already used: %s\n", arg); 1420 if(res == RES_OK) res = RES_BAD_ARG; 1421 goto error; 1422 } 1423 desc_name = arg; 1424 1425 CHK_ARG(idx, "program name"); 1426 ERR(str_set(&sf_connect_prog->prog_name, arg)); 1427 lib_name = arg; 1428 1429 ASSERT(sz <= UINT_MAX); 1430 ERR(read_sides_and_files(stardis, 1, (unsigned)sz, pwordexp, &idx)); 1431 1432 /* store the end of line as args for custom init */ 1433 ERR(set_argc_argv(stardis->allocator, str_cget(&sf_connect_prog->name), 1434 &sf_connect_prog->argc, &sf_connect_prog->argv, pwordexp, idx)); 1435 /* get the user-defined functions from the library */ 1436 ERR(get_prog_common(lib_name, stardis, &sf_connect_prog->program, 1437 &sf_connect_prog->create, &sf_connect_prog->release)); 1438 GET_LIB_SYMBOL(sf_connect_prog, ref_temp, stardis_reference_temperature); 1439 GET_LIB_SYMBOL(sf_connect_prog, emissivity, stardis_emissivity); 1440 GET_LIB_SYMBOL(sf_connect_prog, alpha, stardis_specular_fraction); 1441 GET_LIB_SYMBOL(sf_connect_prog, hc, stardis_convection_coefficient); 1442 GET_LIB_SYMBOL(sf_connect_prog, hmax, stardis_max_convection_coefficient); 1443 GET_LIB_SYMBOL(sf_connect_prog, t_range, stardis_t_range); 1444 if(with_flux) { 1445 GET_LIB_SYMBOL(sf_connect_prog, flux, stardis_boundary_flux); 1446 } 1447 /* create and init custom data */ 1448 ctx.name = desc_name; 1449 CREATE_DESC_DATA(sf_connect_prog); 1450 1451 sf_connect_prog->t_range(sf_connect_prog->prog_data, sf_t_range); 1452 if(STARDIS_TEMPERATURE_IS_KNOWN(sf_t_range[0])) 1453 stardis->t_range[0] = MMIN(stardis->t_range[0], sf_t_range[0]); 1454 if(STARDIS_TEMPERATURE_IS_KNOWN(sf_t_range[1])) 1455 stardis->t_range[1] = MMAX(stardis->t_range[1], sf_t_range[1]); 1456 1457 end: 1458 return res; 1459 error: 1460 goto end; 1461 } 1462 1463 /* SOLID_SOLID_CONNECTION Name contact-resitance STL_filenames */ 1464 static res_T 1465 process_ssc 1466 (struct stardis* stardis, 1467 wordexp_t* pwordexp) 1468 { 1469 char* arg = NULL; 1470 struct description* desc; 1471 size_t sz; 1472 struct solid_solid_connect* ss_connect; 1473 size_t idx = 1; 1474 res_T res = RES_OK; 1475 1476 ASSERT(stardis && pwordexp); 1477 1478 stardis->counts.ssconnect_count++; 1479 1480 sz = darray_descriptions_size_get(&stardis->descriptions); 1481 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 1482 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 1483 ERR(init_ss_connect(stardis->allocator, &desc->d.ss_connect)); 1484 ss_connect = desc->d.ss_connect; 1485 desc->type = DESC_SOLID_SOLID_CONNECT; 1486 1487 /* Use a medium ID even if there is no medium here 1488 * As other cases use media IDs as unique IDs for read_sides_and_files calls 1489 * we continue the trend to ensure connection ID is OK */ 1490 ss_connect->connection_id = allocate_stardis_medium_id(stardis); 1491 1492 CHK_ARG(idx, "solid-solid connection name"); 1493 ERR(description_set_name(stardis, &ss_connect->name, arg)); 1494 if(find_description_by_name(stardis, &ss_connect->name, desc)) { 1495 logger_print(stardis->logger, LOG_ERROR, 1496 "Name already used: %s\n", arg); 1497 if(res == RES_OK) res = RES_BAD_ARG; 1498 goto error; 1499 } 1500 1501 CHK_ARG(idx, "contact resistance"); 1502 res = cstr_to_double(arg, &ss_connect->tcr); 1503 if(res != RES_OK || ss_connect->tcr < 0) { 1504 logger_print(stardis->logger, LOG_ERROR, 1505 "Invalid contact resistance: %s\n", arg); 1506 if(res == RES_OK) res = RES_BAD_ARG; 1507 goto error; 1508 } 1509 else if(ss_connect->tcr == 0) { 1510 logger_print(stardis->logger, LOG_WARNING, 1511 "Solid-solid connection %s: defining a contact resistance to 0 has " 1512 "no effect\n", str_cget(&ss_connect->name)); 1513 } 1514 1515 ASSERT(sz <= UINT_MAX); 1516 ERR(read_sides_and_files(stardis, 1, (unsigned)sz, pwordexp, &idx)); 1517 1518 end: 1519 return res; 1520 error: 1521 goto end; 1522 } 1523 1524 /* SOLID_SOLID_CONNECTION_PROG Name ProgName STL_filenames [PROG_PARAMS ...] */ 1525 static res_T 1526 process_ssc_prog 1527 (struct stardis* stardis, 1528 wordexp_t* pwordexp) 1529 { 1530 char* arg = NULL; 1531 struct description* desc; 1532 const char *lib_name, *desc_name; 1533 size_t sz; 1534 struct solid_solid_connect_prog* ss_connect_prog; 1535 struct stardis_description_create_context ctx; 1536 size_t idx = 1; 1537 res_T res = RES_OK; 1538 1539 ASSERT(stardis && pwordexp); 1540 1541 stardis->counts.sfconnect_count++; 1542 1543 sz = darray_descriptions_size_get(&stardis->descriptions); 1544 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 1545 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 1546 ERR(init_ss_connect_prog(stardis->allocator, &desc->d.ss_connect_prog)); 1547 ss_connect_prog = desc->d.ss_connect_prog; 1548 desc->type = DESC_SOLID_SOLID_CONNECT_PROG; 1549 1550 CHK_ARG(idx, "programmed solid-solid connection name"); 1551 ERR(description_set_name(stardis, &ss_connect_prog->name, arg)); 1552 if(find_description_by_name(stardis, &ss_connect_prog->name, desc)) { 1553 logger_print(stardis->logger, LOG_ERROR, 1554 "Name already used: %s\n", arg); 1555 if(res == RES_OK) res = RES_BAD_ARG; 1556 goto error; 1557 } 1558 desc_name = arg; 1559 1560 CHK_ARG(idx, "program name"); 1561 ERR(str_set(&ss_connect_prog->prog_name, arg)); 1562 lib_name = arg; 1563 1564 ASSERT(sz <= UINT_MAX); 1565 ERR(read_sides_and_files(stardis, 1, (unsigned)sz, pwordexp, &idx)); 1566 1567 /* store the end of line as args for custom init */ 1568 ERR(set_argc_argv(stardis->allocator, str_cget(&ss_connect_prog->name), 1569 &ss_connect_prog->argc, &ss_connect_prog->argv, pwordexp, idx)); 1570 /* get the user-defined functions from the library */ 1571 ERR(get_prog_common(lib_name, stardis, &ss_connect_prog->program, 1572 &ss_connect_prog->create, &ss_connect_prog->release)); 1573 GET_LIB_SYMBOL(ss_connect_prog, tcr, stardis_thermal_contact_resistance); 1574 if(!ss_connect_prog->tcr) { 1575 logger_print(stardis->logger, LOG_ERROR, 1576 "Cannot find function 'stardis_thermal_contact_resistance()' in lib %s\n", 1577 lib_name); 1578 res = RES_BAD_ARG; 1579 goto error; 1580 } 1581 /* create and init custom data */ 1582 ctx.name = desc_name; 1583 CREATE_DESC_DATA(ss_connect_prog); 1584 1585 end: 1586 return res; 1587 error: 1588 goto end; 1589 } 1590 1591 static res_T 1592 read_imposed_temperature 1593 (struct stardis* stardis, 1594 double* imposed_temperature, 1595 wordexp_t* pwordexp, 1596 size_t* idx) 1597 { 1598 char* arg = NULL; 1599 struct str keep; 1600 res_T res = RES_OK; 1601 ASSERT(stardis && imposed_temperature && pwordexp); 1602 1603 str_init(stardis->allocator, &keep); 1604 CHK_ARG((*idx), "imposed temperature"); 1605 ERR(str_set(&keep, arg)); 1606 if(0 == strcasecmp(arg, "UNKNOWN")) { 1607 *imposed_temperature = UNKNOWN_MEDIUM_TEMPERATURE; 1608 } else if((res = cstr_to_double(arg, imposed_temperature)) != RES_OK) { 1609 goto error; 1610 } 1611 1612 end: 1613 str_release(&keep); 1614 return res; 1615 error: 1616 logger_print(stardis->logger, LOG_ERROR, "Invalid imposed temperature: %s\n", 1617 str_cget(&keep)); 1618 goto end; 1619 } 1620 1621 static res_T 1622 read_delta 1623 (struct stardis* stardis, 1624 double* delta, 1625 wordexp_t* pwordexp, 1626 size_t* idx) 1627 { 1628 char* arg = NULL; 1629 res_T res = RES_OK; 1630 ASSERT(stardis && delta && pwordexp && idx); 1631 1632 CHK_ARG((*idx), "delta"); 1633 if(RES_OK == cstr_to_double(arg, delta)) { 1634 /* Was a number */ 1635 if(*delta <= 0) { 1636 res = RES_BAD_ARG; 1637 goto error; 1638 } 1639 } else { 1640 /* Could be 'auto' */ 1641 if(0 == strcasecmp(arg, "AUTO")) { 1642 /* Set to DELTA_AUTO until actual value is substituted */ 1643 *delta = DELTA_AUTO; 1644 } else { 1645 res = RES_BAD_ARG; 1646 goto error; 1647 } 1648 } 1649 end: 1650 return res; 1651 error: 1652 logger_print(stardis->logger, LOG_ERROR, "Invalid delta: %s\n", arg); 1653 goto end; 1654 } 1655 1656 /* SOLID Name lambda rho cp delta Tinit Timposed volumic_power STL_filenames */ 1657 static res_T 1658 process_solid 1659 (struct stardis* stardis, 1660 wordexp_t* pwordexp) 1661 { 1662 char* arg = NULL; 1663 struct description* desc; 1664 size_t sz; 1665 struct solid* solid; 1666 size_t idx = 1; 1667 res_T res = RES_OK; 1668 1669 ASSERT(stardis && pwordexp); 1670 1671 stardis->counts.smed_count++; 1672 1673 sz = darray_descriptions_size_get(&stardis->descriptions); 1674 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 1675 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 1676 ERR(init_solid(stardis->allocator, &desc->d.solid)); 1677 solid = desc->d.solid; 1678 desc->type = DESC_MAT_SOLID; 1679 solid->solid_id = allocate_stardis_medium_id(stardis); 1680 solid->is_green = stardis->mode & (MODE_GREEN_BIN | MODE_GREEN_ASCII); 1681 solid->t0 = stardis->initial_time; 1682 solid->is_outside = 0; 1683 ASSERT(sz <= UINT_MAX); 1684 solid->desc_id = (unsigned)sz; 1685 1686 CHK_ARG(idx, "solid name"); 1687 ERR(description_set_name(stardis, &solid->name, arg)); 1688 if(find_description_by_name(stardis, &solid->name, desc)) { 1689 logger_print(stardis->logger, LOG_ERROR, 1690 "Name already used: %s\n", arg); 1691 if(res == RES_OK) res = RES_BAD_ARG; 1692 goto error; 1693 } 1694 1695 CHK_ARG(idx, "lambda"); 1696 res = cstr_to_double(arg, &solid->lambda); 1697 if(res != RES_OK || solid->lambda <= 0) { 1698 logger_print(stardis->logger, LOG_ERROR, "Invalid lambda: %s\n", arg); 1699 if(res == RES_OK) res = RES_BAD_ARG; 1700 goto error; 1701 } 1702 CHK_ARG(idx, "rho"); 1703 res = cstr_to_double(arg, &solid->rho); 1704 if(res != RES_OK || solid->rho <= 0) { 1705 logger_print(stardis->logger, LOG_ERROR, "Invalid rho: %s\n", arg); 1706 if(res == RES_OK) res = RES_BAD_ARG; 1707 goto error; 1708 } 1709 CHK_ARG(idx, "cp"); 1710 res = cstr_to_double(arg, &solid->cp); 1711 if(res != RES_OK || solid->cp <= 0) { 1712 logger_print(stardis->logger, LOG_ERROR, "Invalid cp: %s\n", arg); 1713 if(res == RES_OK) res = RES_BAD_ARG; 1714 goto error; 1715 } 1716 ERR(read_delta(stardis, &solid->delta, pwordexp, &idx)); 1717 CHK_ARG(idx, "Tinit"); 1718 res = cstr_to_double(arg, &solid->tinit); 1719 if(res != RES_OK || SDIS_TEMPERATURE_IS_UNKNOWN(solid->tinit)) { 1720 logger_print(stardis->logger, LOG_ERROR, "Invalid Tinit: %s\n", arg); 1721 if(res == RES_OK) res = RES_BAD_ARG; 1722 goto error; 1723 } 1724 ERR(read_imposed_temperature(stardis, &solid->imposed_temperature, 1725 pwordexp, &idx)); 1726 if(SDIS_TEMPERATURE_IS_KNOWN(solid->imposed_temperature) 1727 && solid->imposed_temperature != solid->tinit) { 1728 logger_print(stardis->logger, LOG_ERROR, 1729 "Imposed temperature, if defined, must match initial temperature " 1730 "(initial: %g; imposed: %g)\n", 1731 solid->tinit, solid->imposed_temperature); 1732 res = RES_BAD_ARG; 1733 goto error; 1734 } 1735 1736 CHK_ARG(idx, "volumic power"); 1737 res = cstr_to_double(arg, &solid->vpower); 1738 if(res != RES_OK) { 1739 /* VPower can be < 0 */ 1740 logger_print(stardis->logger, LOG_ERROR, "Invalid volumic power: %s\n", arg); 1741 goto error; 1742 } 1743 if(solid->vpower != 0 && stardis->picard_order > 1) { 1744 logger_print(stardis->logger, LOG_ERROR, 1745 "Cannot have volumic power (here %f) if Picard order is not 1 " 1746 "(here order is %u)\n", 1747 solid->vpower, stardis->picard_order); 1748 res = RES_BAD_ARG; 1749 goto error; 1750 } 1751 1752 /* Actual solid creation is defered until geometry is read to allow 1753 * enclosure shape VS delta analysis (and auto delta computation) */ 1754 1755 ERR(read_sides_and_files(stardis, 0, (unsigned)sz, pwordexp, &idx)); 1756 1757 end: 1758 return res; 1759 error: 1760 goto end; 1761 } 1762 1763 /* SOLID_PROG Name ProgName STL_filenames [PROG_PARAMS ...] */ 1764 static res_T 1765 process_solid_prog 1766 (struct stardis* stardis, 1767 wordexp_t* pwordexp) 1768 { 1769 char* arg = NULL; 1770 struct description* desc; 1771 const char *lib_name, *desc_name; 1772 size_t sz; 1773 struct solid_prog* solid_prog; 1774 struct stardis_description_create_context ctx; 1775 size_t idx = 1; 1776 res_T res = RES_OK; 1777 1778 ASSERT(stardis && pwordexp); 1779 1780 stardis->counts.fmed_count++; 1781 1782 sz = darray_descriptions_size_get(&stardis->descriptions); 1783 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 1784 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 1785 ERR(init_solid_prog(stardis->allocator, &desc->d.solid_prog)); 1786 solid_prog = desc->d.solid_prog; 1787 desc->type = DESC_MAT_SOLID_PROG; 1788 solid_prog->solid_id = allocate_stardis_medium_id(stardis); 1789 ASSERT(sz <= UINT_MAX); 1790 solid_prog->desc_id = (unsigned)sz; 1791 1792 CHK_ARG(idx, "programmed solid name"); 1793 ERR(description_set_name(stardis, &solid_prog->name, arg)); 1794 if(find_description_by_name(stardis, &solid_prog->name, desc)) { 1795 logger_print(stardis->logger, LOG_ERROR, 1796 "Name already used: %s\n", arg); 1797 if(res == RES_OK) res = RES_BAD_ARG; 1798 goto error; 1799 } 1800 desc_name = arg; 1801 1802 CHK_ARG(idx, "program name"); 1803 ERR(str_set(&solid_prog->prog_name, arg)); 1804 lib_name = arg; 1805 1806 ERR(read_sides_and_files(stardis, 0, (unsigned)sz, pwordexp, &idx)); 1807 1808 /* store the end of line as args for custom init */ 1809 ERR(set_argc_argv(stardis->allocator, str_cget(&solid_prog->name), 1810 &solid_prog->argc, &solid_prog->argv, pwordexp, idx)); 1811 /* get the user-defined functions from the library */ 1812 ERR(get_prog_common(lib_name, stardis, &solid_prog->program, 1813 &solid_prog->create, &solid_prog->release)); 1814 GET_LIB_SYMBOL(solid_prog, lambda, stardis_conductivity); 1815 GET_LIB_SYMBOL(solid_prog, rho, stardis_volumic_mass); 1816 GET_LIB_SYMBOL(solid_prog, cp, stardis_calorific_capacity); 1817 GET_LIB_SYMBOL(solid_prog, delta, stardis_delta_solid); 1818 GET_LIB_SYMBOL(solid_prog, temp, stardis_medium_temperature); 1819 GET_LIB_SYMBOL(solid_prog, vpower, stardis_volumic_power); 1820 1821 GET_LIB_SYMBOL_BASE(&solid_prog->sample_path, solid_prog->program->lib_handle, 1822 stardis_sample_conductive_path, 1); 1823 GET_LIB_SYMBOL_BASE(&solid_prog->t_range, solid_prog->program->lib_handle, 1824 stardis_t_range, 1); 1825 1826 /* create and init custom data */ 1827 ctx.name = desc_name; 1828 CREATE_DESC_DATA(solid_prog); 1829 1830 if(solid_prog->t_range) { 1831 double t_range[2]; 1832 solid_prog->t_range(solid_prog->prog_data, t_range); 1833 if(STARDIS_TEMPERATURE_IS_KNOWN(t_range[0])) 1834 stardis->t_range[0] = MMIN(stardis->t_range[0], t_range[0]); 1835 if(STARDIS_TEMPERATURE_IS_KNOWN(t_range[1])) 1836 stardis->t_range[1] = MMAX(stardis->t_range[1], t_range[1]); 1837 } 1838 1839 ERR(create_solver_solid_prog(stardis, solid_prog)); 1840 1841 end: 1842 return res; 1843 error: 1844 goto end; 1845 } 1846 1847 /* FLUID Name rho cp Tinit Timposed STL_filenames */ 1848 static res_T 1849 process_fluid 1850 (struct stardis* stardis, 1851 wordexp_t* pwordexp) 1852 { 1853 char* arg = NULL; 1854 struct description* desc; 1855 size_t sz; 1856 struct fluid* fluid; 1857 size_t idx = 1; 1858 res_T res = RES_OK; 1859 1860 ASSERT(stardis && pwordexp); 1861 1862 stardis->counts.fmed_count++; 1863 1864 sz = darray_descriptions_size_get(&stardis->descriptions); 1865 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 1866 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 1867 ERR(init_fluid(stardis->allocator, &desc->d.fluid)); 1868 fluid = desc->d.fluid; 1869 desc->type = DESC_MAT_FLUID; 1870 fluid->t0 = stardis->initial_time; 1871 fluid->fluid_id = allocate_stardis_medium_id(stardis); 1872 fluid->is_green = stardis->mode & (MODE_GREEN_BIN | MODE_GREEN_ASCII); 1873 ASSERT(sz <= UINT_MAX); 1874 fluid->desc_id = (unsigned)sz; 1875 1876 CHK_ARG(idx, "fluid name"); 1877 ERR(description_set_name(stardis, &fluid->name, arg)); 1878 if(find_description_by_name(stardis, &fluid->name, desc)) { 1879 logger_print(stardis->logger, LOG_ERROR, 1880 "Name already used: %s\n", arg); 1881 if(res == RES_OK) res = RES_BAD_ARG; 1882 goto error; 1883 } 1884 1885 CHK_ARG(idx, "rho"); 1886 res = cstr_to_double(arg, &fluid->rho); 1887 if(res != RES_OK || fluid->rho <= 0) { 1888 logger_print(stardis->logger, LOG_ERROR, "Invalid rho: %s\n", arg); 1889 if(res == RES_OK) res = RES_BAD_ARG; 1890 goto error; 1891 } 1892 CHK_ARG(idx, "cp"); 1893 res = cstr_to_double(arg, &fluid->cp); 1894 if(res != RES_OK || fluid->cp <= 0) { 1895 logger_print(stardis->logger, LOG_ERROR, "Invalid cp: %s\n", arg); 1896 if(res == RES_OK) res = RES_BAD_ARG; 1897 goto error; 1898 } 1899 CHK_ARG(idx, "Tinit"); 1900 res = cstr_to_double(arg, &fluid->tinit); 1901 if(res != RES_OK || SDIS_TEMPERATURE_IS_UNKNOWN(fluid->tinit)) { 1902 logger_print(stardis->logger, LOG_ERROR, "Invalid Tinit: %s\n", arg); 1903 if(res == RES_OK) res = RES_BAD_ARG; 1904 goto error; 1905 } 1906 ERR(read_imposed_temperature(stardis, &fluid->imposed_temperature, 1907 pwordexp, &idx)); 1908 if(SDIS_TEMPERATURE_IS_KNOWN(fluid->imposed_temperature) 1909 && fluid->imposed_temperature != fluid->tinit) { 1910 logger_print(stardis->logger, LOG_ERROR, 1911 "Imposed temperature, if defined, must match initial temperature " 1912 "(initial: %g; imposed: %g)\n", 1913 fluid->tinit, fluid->imposed_temperature); 1914 res = RES_BAD_ARG; 1915 goto error; 1916 } 1917 1918 ERR(create_solver_fluid(stardis, fluid)); 1919 1920 ERR(read_sides_and_files(stardis, 0, (unsigned)sz, pwordexp, &idx)); 1921 1922 end: 1923 return res; 1924 error: 1925 goto end; 1926 } 1927 1928 /* FLUID_PROG Name ProgName STL_filenames [PROG_PARAMS ...] */ 1929 static res_T 1930 process_fluid_prog 1931 (struct stardis* stardis, 1932 wordexp_t* pwordexp) 1933 { 1934 char* arg = NULL; 1935 struct description* desc; 1936 const char *lib_name, *desc_name; 1937 size_t sz; 1938 struct fluid_prog* fluid_prog; 1939 struct stardis_description_create_context ctx; 1940 size_t idx = 1; 1941 res_T res = RES_OK; 1942 1943 ASSERT(stardis && pwordexp); 1944 1945 stardis->counts.fmed_count++; 1946 1947 sz = darray_descriptions_size_get(&stardis->descriptions); 1948 ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); 1949 desc = darray_descriptions_data_get(&stardis->descriptions) + sz; 1950 ERR(init_fluid_prog(stardis->allocator, &desc->d.fluid_prog)); 1951 fluid_prog = desc->d.fluid_prog; 1952 desc->type = DESC_MAT_FLUID_PROG; 1953 fluid_prog->fluid_id = allocate_stardis_medium_id(stardis); 1954 ASSERT(sz <= UINT_MAX); 1955 fluid_prog->desc_id = (unsigned)sz; 1956 1957 CHK_ARG(idx, "programmed fluid name"); 1958 ERR(description_set_name(stardis, &fluid_prog->name, arg)); 1959 if(find_description_by_name(stardis, &fluid_prog->name, desc)) { 1960 logger_print(stardis->logger, LOG_ERROR, 1961 "Name already used: %s\n", arg); 1962 if(res == RES_OK) res = RES_BAD_ARG; 1963 goto error; 1964 } 1965 desc_name = arg; 1966 1967 CHK_ARG(idx, "program name"); 1968 ERR(str_set(&fluid_prog->prog_name, arg)); 1969 lib_name = arg; 1970 1971 ERR(read_sides_and_files(stardis, 0, (unsigned)sz, pwordexp, &idx)); 1972 1973 /* store the end of line as args for custom init */ 1974 ERR(set_argc_argv(stardis->allocator, str_cget(&fluid_prog->name), 1975 &fluid_prog->argc, &fluid_prog->argv, pwordexp, idx)); 1976 /* get the user-defined functions from the library */ 1977 ERR(get_prog_common(lib_name, stardis, &fluid_prog->program, 1978 &fluid_prog->create, &fluid_prog->release)); 1979 GET_LIB_SYMBOL(fluid_prog, rho, stardis_volumic_mass); 1980 GET_LIB_SYMBOL(fluid_prog, cp, stardis_calorific_capacity); 1981 GET_LIB_SYMBOL(fluid_prog, temp, stardis_medium_temperature); 1982 /* create and init custom data */ 1983 ctx.name = desc_name; 1984 CREATE_DESC_DATA(fluid_prog); 1985 1986 ERR(create_solver_fluid_prog(stardis, fluid_prog)); 1987 1988 end: 1989 return res; 1990 error: 1991 goto end; 1992 } 1993 1994 /* SCALE scale_factor */ 1995 static res_T 1996 process_scale 1997 (struct stardis* stardis, 1998 wordexp_t* pwordexp) 1999 { 2000 char* arg = NULL; 2001 size_t idx = 1; 2002 res_T res = RES_OK; 2003 2004 ASSERT(stardis && pwordexp); 2005 2006 if(stardis->scale_factor > 0) { 2007 logger_print(stardis->logger, LOG_ERROR, 2008 "SCALE cannot be specified twice\n"); 2009 res = RES_BAD_ARG; 2010 goto error; 2011 } 2012 CHK_ARG(idx, "scale factor"); 2013 res = cstr_to_double(arg, &stardis->scale_factor); 2014 if(res != RES_OK || stardis->scale_factor <= 0) { 2015 logger_print(stardis->logger, LOG_ERROR, 2016 "Invalid scale factor: %s\n", arg); 2017 if(res == RES_OK) res = RES_BAD_ARG; 2018 goto error; 2019 } 2020 2021 end: 2022 return res; 2023 error: 2024 goto end; 2025 } 2026 2027 /* TRAD Trad Trad_ref */ 2028 static res_T 2029 process_radiative 2030 (struct stardis* stardis, 2031 wordexp_t* pwordexp) 2032 { 2033 double trad = 0; 2034 double tref = 0; 2035 char* arg = NULL; 2036 size_t idx = 1; 2037 res_T res = RES_OK; 2038 2039 ASSERT(stardis && pwordexp); 2040 2041 if(stardis->radenv_def) { 2042 logger_print(stardis->logger, LOG_ERROR, 2043 "Radiative environment cannot be specified twice\n"); 2044 res = RES_BAD_ARG; 2045 goto error; 2046 } 2047 2048 res = radiative_env_init_const(stardis->allocator, &stardis->radenv); 2049 if(res != RES_OK) goto error; 2050 2051 CHK_ARG(idx, "Trad"); 2052 res = cstr_to_double(arg, &trad); 2053 if(res != RES_OK || SDIS_TEMPERATURE_IS_UNKNOWN(trad)) { 2054 logger_print(stardis->logger, LOG_ERROR, 2055 "Invalid Trad: %s\n", arg); 2056 if(res == RES_OK) res = RES_BAD_ARG; 2057 goto error; 2058 } 2059 CHK_ARG(idx, "Trad reference"); 2060 res = cstr_to_double(arg, &tref); 2061 if(res != RES_OK || tref < 0) { 2062 logger_print(stardis->logger, LOG_ERROR, 2063 "Invalid Trad reference: %s\n", arg); 2064 if(res == RES_OK) res = RES_BAD_ARG; 2065 goto error; 2066 } 2067 2068 stardis->radenv.data.cst.temperature = trad; 2069 stardis->radenv.data.cst.reference_temperature = tref; 2070 stardis->radenv_def = 1; 2071 2072 end: 2073 return res; 2074 error: 2075 radiative_env_release(&stardis->radenv); 2076 stardis->radenv = RADIATIVE_ENV_DEFAULT; 2077 goto end; 2078 } 2079 2080 static res_T 2081 process_radiative_prog(struct stardis* stardis, wordexp_t* pwordexp) 2082 { 2083 struct stardis_description_create_context ctx; 2084 struct radiative_env_prog* radenv = NULL; 2085 double radenv_t_range[2] = {DBL_MAX, -DBL_MAX}; 2086 char* lib_name = NULL; 2087 char* arg = NULL; 2088 size_t idx = 1; 2089 res_T res = RES_OK; 2090 2091 ASSERT(stardis && pwordexp); 2092 2093 radenv = &stardis->radenv.data.prg; 2094 2095 if(stardis->radenv_def) { 2096 logger_print(stardis->logger, LOG_ERROR, 2097 "Radiative environment cannot be specified twice\n"); 2098 res = RES_BAD_ARG; 2099 goto error; 2100 } 2101 2102 res = radiative_env_init_prog(stardis->allocator, &stardis->radenv); 2103 2104 CHK_ARG(idx, "program name"); 2105 ERR(str_set(&radenv->prog_name, arg)); 2106 lib_name = arg; 2107 2108 if(idx < pwordexp->we_wordc 2109 && strcasecmp(pwordexp->we_wordv[idx++], "PROG_PARAMS")) { 2110 logger_print(stardis->logger, LOG_ERROR, 2111 "Expecting PROG_PARAMS keyword while parsing `%s'.\n", 2112 pwordexp->we_wordv[idx]); 2113 res = RES_BAD_ARG; 2114 goto error; 2115 } 2116 2117 ERR(set_argc_argv(stardis->allocator, str_cget(&radenv->prog_name), 2118 &radenv->argc, &radenv->argv, pwordexp, idx)); 2119 ERR(get_prog_common 2120 (lib_name, stardis, &radenv->program, &radenv->create, &radenv->release)); 2121 GET_LIB_SYMBOL(radenv, temperature, 2122 stardis_radiative_env_temperature); 2123 GET_LIB_SYMBOL(radenv, reference_temperature, 2124 stardis_radiative_env_reference_temperature); 2125 GET_LIB_SYMBOL(radenv, t_range, 2126 stardis_t_range); 2127 2128 ctx.name = "Radiative environment"; 2129 radenv->data = radenv->create 2130 (&ctx, radenv->program->prog_data, radenv->argc, radenv->argv); 2131 if(!radenv->data) { 2132 logger_print(stardis->logger, LOG_ERROR, 2133 "Cannot create data for the radiative environment\n"); 2134 res = RES_UNKNOWN_ERR; 2135 goto error; 2136 } 2137 2138 radenv->t_range(radenv->data, radenv_t_range); 2139 if(STARDIS_TEMPERATURE_IS_KNOWN(radenv_t_range[0])) 2140 stardis->t_range[0] = MMIN(stardis->t_range[0], radenv_t_range[0]); 2141 if(STARDIS_TEMPERATURE_IS_KNOWN(radenv_t_range[1])) 2142 stardis->t_range[1] = MMAX(stardis->t_range[1], radenv_t_range[1]); 2143 2144 exit: 2145 return res; 2146 error: 2147 radiative_env_release(&stardis->radenv); 2148 stardis->radenv = RADIATIVE_ENV_DEFAULT; 2149 goto exit; 2150 } 2151 2152 static res_T 2153 process_spherical_source 2154 (struct stardis* stardis, 2155 wordexp_t* pwordexp) 2156 { 2157 struct spherical_source* src = NULL; 2158 char* arg = NULL; 2159 size_t idx = 1; 2160 res_T res = RES_OK; 2161 ASSERT(stardis && pwordexp); 2162 2163 src = &stardis->extsrc.data.sphere; 2164 2165 if(stardis->extsrc.type != EXTERN_SOURCE_NONE__) { 2166 logger_print(stardis->logger, LOG_ERROR, 2167 "Only one external source can be defined\n"); 2168 res = RES_BAD_ARG; 2169 goto error; 2170 } 2171 2172 res = extern_source_init_sphere(stardis->allocator, &stardis->extsrc); 2173 if(res != RES_OK) goto error; 2174 2175 CHK_ARG(idx, "radius"); 2176 res = cstr_to_double(arg, &src->radius); 2177 if(res == RES_OK && src->radius < 0) res = RES_BAD_ARG; 2178 if(res != RES_OK) { 2179 logger_print(stardis->logger, LOG_ERROR, 2180 "Invalid spherical source radius: %s\n", arg); 2181 goto error; 2182 } 2183 2184 #define PARSE_POS(Name, Id) { \ 2185 CHK_ARG(idx, "position "Name); \ 2186 res = cstr_to_double(arg, &src->position[Id]); \ 2187 if(res != RES_OK) { \ 2188 logger_print(stardis->logger, LOG_ERROR, \ 2189 "Invalid spherical source "Name" coordinate: %s\n", arg); \ 2190 goto error; \ 2191 } \ 2192 } (void)0 2193 PARSE_POS("X", 0); 2194 PARSE_POS("Y", 1); 2195 PARSE_POS("Z", 2); 2196 #undef PARSE_POS 2197 2198 CHK_ARG(idx, "power"); 2199 res = cstr_to_double(arg, &src->power); 2200 if(res == RES_OK && src->power < 0) res = RES_BAD_ARG; 2201 if(res != RES_OK) { 2202 logger_print(stardis->logger, LOG_ERROR, 2203 "Invalid spherical source power: %s\n", arg); 2204 goto error; 2205 } 2206 2207 CHK_ARG(idx, "diffuse radiance"); 2208 res = cstr_to_double(arg, &src->diffuse_radiance); 2209 if(res == RES_OK && src->diffuse_radiance < 0) res = RES_BAD_ARG; 2210 if(res != RES_OK) { 2211 logger_print(stardis->logger, LOG_ERROR, 2212 "Invalid diffuse radiance for the spherical source: %s\n", arg); 2213 goto error; 2214 } 2215 2216 res = extern_source_create_solver_source(&stardis->extsrc, stardis); 2217 if(res != RES_OK) goto error; 2218 2219 exit: 2220 return res; 2221 error: 2222 extern_source_release(&stardis->extsrc); 2223 stardis->extsrc = EXTERN_SOURCE_NULL; 2224 goto exit; 2225 } 2226 2227 static res_T 2228 process_spherical_source_prog(struct stardis* stardis, wordexp_t* pwordexp) 2229 { 2230 struct stardis_description_create_context ctx; 2231 struct spherical_source_prog* src = NULL; 2232 char* lib_name = NULL; 2233 char* arg = NULL; 2234 size_t idx = 1; 2235 res_T res = RES_OK; 2236 ASSERT(stardis && pwordexp); 2237 2238 src = &stardis->extsrc.data.sphere_prog; 2239 2240 if(stardis->extsrc.type != EXTERN_SOURCE_NONE__) { 2241 logger_print(stardis->logger, LOG_ERROR, 2242 "Only one external source can be defined\n"); 2243 res = RES_BAD_ARG; 2244 goto error; 2245 } 2246 2247 res = extern_source_init_sphere_prog(stardis->allocator, &stardis->extsrc); 2248 if(res != RES_OK) goto error; 2249 2250 CHK_ARG(idx, "radius"); 2251 res = cstr_to_double(arg, &src->radius); 2252 if(res == RES_OK && src->radius < 0) res = RES_BAD_ARG; 2253 if(res != RES_OK) { 2254 logger_print(stardis->logger, LOG_ERROR, 2255 "Invalid spherical source radius: %s\n", arg); 2256 goto error; 2257 } 2258 2259 CHK_ARG(idx, "program name"); 2260 ERR(str_set(&src->prog_name, arg)); 2261 lib_name = arg; 2262 2263 if(idx < pwordexp->we_wordc 2264 && strcasecmp(pwordexp->we_wordv[idx++], "PROG_PARAMS")) { 2265 logger_print(stardis->logger, LOG_ERROR, 2266 "Expecting PROG_PARAMS keyword while parsing `%s'.\n", 2267 pwordexp->we_wordv[idx]); 2268 res = RES_BAD_ARG; 2269 goto error; 2270 } 2271 2272 ERR(set_argc_argv(stardis->allocator, str_cget(&src->prog_name), &src->argc, 2273 &src->argv, pwordexp, idx)); 2274 ERR(get_prog_common(lib_name, stardis, &src->program, &src->create, &src->release)); 2275 GET_LIB_SYMBOL(src, position, stardis_spherical_source_position); 2276 GET_LIB_SYMBOL(src, power, stardis_spherical_source_power); 2277 GET_LIB_SYMBOL(src, diffuse_radiance, stardis_spherical_source_diffuse_radiance); 2278 2279 ctx.name = "External spherical source"; 2280 src->data = src->create(&ctx, src->program->prog_data, src->argc, src->argv); 2281 if(!src->data) { 2282 logger_print(stardis->logger, LOG_ERROR, 2283 "Cannot create data for the external spherical source\n"); 2284 res = RES_UNKNOWN_ERR; 2285 goto error; 2286 } 2287 2288 res = extern_source_create_solver_source(&stardis->extsrc, stardis); 2289 if(res != RES_OK) goto error; 2290 2291 exit: 2292 return res; 2293 error: 2294 extern_source_release(&stardis->extsrc); 2295 stardis->extsrc = EXTERN_SOURCE_NULL; 2296 goto exit; 2297 } 2298 2299 /* Read medium or boundary line; should be one of: 2300 * SOLID Name lambda rho cp delta Tinit Timposed volumic_power STL_sides_filenames 2301 * FLUID Name rho cp Tinit Timposed STL_filenames 2302 * H_BOUNDARY_FOR_SOLID Name ref_temperature emissivity specular_fraction hc T_env STL_sides_filenames 2303 * H_BOUNDARY_FOR_FLUID Name ref_temperature emissivity specular_fraction hc T_env STL_filenames 2304 * T_BOUNDARY_FOR_SOLID Name T STL_filenames 2305 * F_BOUNDARY_FOR_SOLID Name F STL_filenames 2306 * SOLID_FLUID_CONNECTION Name ref_temperature emissivity specular_fraction hc STL_filenames 2307 * 2308 * SOLID_PROG Name Libray STL_sides_filenames [ PROG_PARAMS ... ] 2309 * SOLID_PROG Name Libray STL_sides_filenames [ PROG_PARAMS ... ] 2310 * H_BOUNDARY_FOR_SOLID_PROG Name Libray STL_filenames [ PROG_PARAMS ... ] 2311 * H_BOUNDARY_FOR_FLUID_PROG Name Libray STL_filenames [ PROG_PARAMS ... ] 2312 * T_BOUNDARY_FOR_SOLID_PROG Name Libray STL_filenames [ PROG_PARAMS ... ] 2313 * F_BOUNDARY_FOR_SOLID_PROG Name Libray STL_filenames [ PROG_PARAMS ... ] 2314 * SOLID_FLUID_CONNECTION_PROG Name Libray STL_filenames [ PROG_PARAMS ... ] 2315 * SOLID_SOLID_CONNECTION_PROG Name Libray STL_filenames [ PROG_PARAMS ... ] 2316 * 2317 * SCALE scale_factor 2318 * TRAD Trad Trad_ref 2319 * 2320 * STL_sides_filenames = { { FRONT | BACK | BOTH } STL_filename }+ 2321 * STL_filenames = { STL_filename }+ 2322 */ 2323 static res_T 2324 process_model_line 2325 (const char* file_name, 2326 const char* line, 2327 wordexp_t *pwordexp, 2328 struct stardis* stardis) 2329 { 2330 res_T res = RES_OK; 2331 char* arg = NULL; 2332 size_t idx = 0; 2333 2334 ASSERT(file_name && line && pwordexp && stardis); 2335 2336 CHK_ARG(idx, "model line type"); 2337 2338 if(0 == strcasecmp(arg, "H_BOUNDARY_FOR_SOLID")) 2339 ERR(process_h(stardis, DESC_BOUND_H_FOR_SOLID, pwordexp)); 2340 else if(0 == strcasecmp(arg, "H_BOUNDARY_FOR_SOLID_PROG")) 2341 ERR(process_h_prog(stardis, DESC_BOUND_H_FOR_SOLID_PROG, pwordexp)); 2342 else if(0 == strcasecmp(arg, "HF_BOUNDARY_FOR_SOLID")) 2343 ERR(process_hf(stardis, DESC_BOUND_HF_FOR_SOLID, pwordexp)); 2344 else if(0 == strcasecmp(arg, "HF_BOUNDARY_FOR_SOLID_PROG")) 2345 ERR(process_hf_prog(stardis, DESC_BOUND_HF_FOR_SOLID_PROG, pwordexp)); 2346 else if(0 == strcasecmp(arg, "H_BOUNDARY_FOR_FLUID")) 2347 ERR(process_h(stardis, DESC_BOUND_H_FOR_FLUID, pwordexp)); 2348 else if(0 == strcasecmp(arg, "H_BOUNDARY_FOR_FLUID_PROG")) 2349 ERR(process_h_prog(stardis, DESC_BOUND_H_FOR_FLUID_PROG, pwordexp)); 2350 else if(0 == strcasecmp(arg, "T_BOUNDARY_FOR_SOLID")) 2351 ERR(process_t(stardis, pwordexp)); 2352 else if(0 == strcasecmp(arg, "T_BOUNDARY_FOR_SOLID_PROG")) 2353 ERR(process_t_prog(stardis, pwordexp)); 2354 else if(0 == strcasecmp(arg, "F_BOUNDARY_FOR_SOLID")) 2355 ERR(process_flx(stardis, pwordexp)); 2356 else if(0 == strcasecmp(arg, "F_BOUNDARY_FOR_SOLID_PROG")) 2357 ERR(process_flx_prog(stardis, pwordexp)); 2358 else if(0 == strcasecmp(arg, "SOLID_FLUID_CONNECTION")) 2359 ERR(process_sfc(stardis, 0/* No flux*/, pwordexp)); 2360 else if(0 == strcasecmp(arg, "F_SOLID_FLUID_CONNECTION")) 2361 ERR(process_sfc(stardis, 1/* Flux */, pwordexp)); 2362 else if(0 == strcasecmp(arg, "SOLID_FLUID_CONNECTION_PROG")) 2363 ERR(process_sfc_prog(stardis, 0/* No flux*/, pwordexp)); 2364 else if(0 == strcasecmp(arg, "F_SOLID_FLUID_CONNECTION_PROG")) 2365 ERR(process_sfc_prog(stardis, 1/* Flux */, pwordexp)); 2366 else if(0 == strcasecmp(arg, "SOLID_SOLID_CONNECTION")) 2367 ERR(process_ssc(stardis, pwordexp)); 2368 else if(0 == strcasecmp(arg, "SOLID_SOLID_CONNECTION_PROG")) 2369 ERR(process_ssc_prog(stardis, pwordexp)); 2370 else if(0 == strcasecmp(arg, "SOLID")) 2371 ERR(process_solid(stardis, pwordexp)); 2372 else if(0 == strcasecmp(arg, "SOLID_PROG")) 2373 ERR(process_solid_prog(stardis, pwordexp)); 2374 else if(0 == strcasecmp(arg, "FLUID")) 2375 ERR(process_fluid(stardis, pwordexp)); 2376 else if(0 == strcasecmp(arg, "FLUID_PROG")) 2377 ERR(process_fluid_prog(stardis, pwordexp)); 2378 else if(0 == strcasecmp(arg, "PROGRAM")) 2379 ERR(process_program(stardis, pwordexp)); 2380 else if(0 == strcasecmp(arg, "SCALE")) 2381 ERR(process_scale(stardis, pwordexp)); 2382 else if(0 == strcasecmp(arg, "TRAD")) 2383 ERR(process_radiative(stardis, pwordexp)); 2384 else if(0 == strcasecmp(arg, "TRAD_PROG")) 2385 ERR(process_radiative_prog(stardis, pwordexp)); 2386 else if(0 == strcasecmp(arg, "SPHERICAL_SOURCE")) 2387 ERR(process_spherical_source(stardis, pwordexp)); 2388 else if(0 == strcasecmp(arg, "SPHERICAL_SOURCE_PROG")) 2389 ERR(process_spherical_source_prog(stardis, pwordexp)); 2390 else { 2391 logger_print(stardis->logger, LOG_ERROR, 2392 "Unknown description type: %s\n", arg); 2393 res = RES_BAD_ARG; 2394 goto error; 2395 } 2396 2397 end: 2398 return res; 2399 error: 2400 logger_print(stardis->logger, LOG_ERROR, 2401 "Invalid description line in model file '%s':\n", file_name); 2402 logger_print(stardis->logger, LOG_ERROR, "%s\n", line); 2403 goto end; 2404 } 2405 2406 /******************************************************************************* 2407 * Public Functions 2408 ******************************************************************************/ 2409 2410 res_T 2411 get_dummy_solid_id 2412 (struct stardis* stardis, 2413 unsigned* id) 2414 { 2415 res_T res = RES_OK; 2416 struct solid* dummy = NULL; 2417 struct dummies* dummies; 2418 ASSERT(stardis && id); 2419 dummies = &stardis->dummies; 2420 if(dummies->dummy_solid) { 2421 *id = dummies->dummy_solid_id; 2422 goto end; 2423 } 2424 ERR(init_solid(stardis->allocator, &dummy)); 2425 dummies->stardis_solid = dummy; 2426 dummies->dummy_solid_id = allocate_stardis_medium_id(stardis); 2427 dummy->solid_id = dummies->dummy_solid_id; 2428 dummy->t0 = stardis->initial_time; 2429 dummy->is_outside = 1; 2430 dummy->is_green = stardis->mode & (MODE_GREEN_BIN | MODE_GREEN_ASCII); 2431 create_solver_solid(stardis, dummy); 2432 dummies->dummy_solid 2433 = darray_media_ptr_data_get(&stardis->media)[dummies->dummy_solid_id]; 2434 logger_print(stardis->logger, LOG_OUTPUT, 2435 "Dummy solid created: (it is medium %u)\n", 2436 dummies->dummy_solid_id); 2437 *id = dummies->dummy_solid_id; 2438 end: 2439 return res; 2440 error: 2441 goto end; 2442 } 2443 2444 res_T 2445 get_dummy_fluid_id 2446 (struct stardis* stardis, 2447 unsigned* id) 2448 { 2449 res_T res = RES_OK; 2450 struct fluid* dummy = NULL; 2451 struct dummies* dummies; 2452 ASSERT(stardis && id); 2453 dummies = &stardis->dummies; 2454 if(dummies->dummy_fluid) { 2455 *id = dummies->dummy_fluid_id; 2456 goto end; 2457 } 2458 ERR(init_fluid(stardis->allocator, &dummy)); 2459 dummies->stardis_fluid = dummy; 2460 dummies->dummy_fluid_id = allocate_stardis_medium_id(stardis); 2461 dummy->fluid_id = dummies->dummy_fluid_id; 2462 dummy->t0 = stardis->initial_time; 2463 dummy->is_outside = 1; 2464 dummy->is_green = stardis->mode & (MODE_GREEN_BIN | MODE_GREEN_ASCII); 2465 create_solver_fluid(stardis, dummy); 2466 dummies->dummy_fluid 2467 = darray_media_ptr_data_get(&stardis->media)[dummies->dummy_fluid_id]; 2468 logger_print(stardis->logger, LOG_OUTPUT, 2469 "Dummy fluid created: (it is medium %u)\n", 2470 dummies->dummy_fluid_id); 2471 *id = dummies->dummy_fluid_id; 2472 end: 2473 return res; 2474 error: 2475 goto end; 2476 } 2477 2478 res_T 2479 read_model 2480 (const struct darray_str* model_files, 2481 struct stardis* stardis) 2482 { 2483 res_T res = RES_OK; 2484 const struct str* files = NULL; 2485 size_t i; 2486 FILE* f = NULL; 2487 struct txtrdr* txtrdr = NULL; 2488 wordexp_t pwordexp; 2489 int word_initialized = 0; 2490 2491 ASSERT(model_files && stardis); 2492 files = darray_str_cdata_get(model_files); 2493 FOR_EACH(i, 0, darray_str_size_get(model_files)) { 2494 const char* name = str_cget(files + i); 2495 int fst = 1; 2496 f = fopen(name, "r"); 2497 if(!f) { 2498 logger_print(stardis->logger, LOG_ERROR, 2499 "Cannot open model file '%s'\n", name); 2500 res = RES_IO_ERR; 2501 goto error; 2502 } 2503 txtrdr_stream(stardis->allocator, f, name, '#', &txtrdr); 2504 for(;;) { 2505 char* line; 2506 int flags = WRDE_NOCMD | WRDE_UNDEF; 2507 if(!fst) flags |= WRDE_REUSE; 2508 ERR(txtrdr_read_line(txtrdr)); 2509 line = txtrdr_get_line(txtrdr); 2510 if(!line) break; 2511 switch(wordexp(line, &pwordexp, flags)) { 2512 case 0: /* No error */ 2513 word_initialized = 1; 2514 break; 2515 case WRDE_NOSPACE: /* Ran out of memory. */ 2516 res = RES_MEM_ERR; 2517 goto error; 2518 case WRDE_BADCHAR: /* A metachar appears in the wrong place. */ 2519 logger_print(stardis->logger, LOG_ERROR, 2520 "%s: word expansion error: invalid character.\n", name); 2521 goto exp_error; 2522 case WRDE_BADVAL: /* Undefined var reference with WRDE_UNDEF. */ 2523 logger_print(stardis->logger, LOG_ERROR, 2524 "%s: word expansion error: undefined environment variable.\n", name); 2525 goto exp_error; 2526 case WRDE_CMDSUB: /* Command substitution with WRDE_NOCMD. */ 2527 logger_print(stardis->logger, LOG_ERROR, 2528 "%s: word expansion error: command substitution is not enabled.\n", 2529 name); 2530 goto exp_error; 2531 case WRDE_SYNTAX: /* Shell syntax error. */ 2532 logger_print(stardis->logger, LOG_ERROR, 2533 "%s: word expansion error: syntax error.\n", name); 2534 goto exp_error; 2535 default: 2536 FATAL("Unexpected return code.\n"); 2537 } 2538 ERR(process_model_line(name, line, &pwordexp, stardis)); 2539 fst = 0; 2540 continue; 2541 exp_error: 2542 logger_print(stardis->logger, LOG_ERROR, "%s\n", line); 2543 res = RES_BAD_ARG; 2544 goto error; 2545 } 2546 txtrdr_ref_put(txtrdr); 2547 txtrdr = NULL; 2548 fclose(f); 2549 f = NULL; 2550 } 2551 if(stardis->scale_factor <= 0) 2552 stardis->scale_factor = STARDIS_DEFAULT_SCALE_FACTOR; 2553 logger_print(stardis->logger, LOG_OUTPUT, 2554 "Scaling factor is %g\n", stardis->scale_factor); 2555 if(stardis->radenv.type == RADIATIVE_ENV_CONST) { 2556 const double trad = stardis->radenv.data.cst.temperature; 2557 const double trad_ref = stardis->radenv.data.cst.reference_temperature; 2558 logger_print(stardis->logger, LOG_OUTPUT, 2559 "Trad is %g, Trad reference is %g\n", trad, trad_ref); 2560 stardis->t_range[0] = MMIN(stardis->t_range[0], trad_ref); 2561 stardis->t_range[1] = MMAX(stardis->t_range[1], trad_ref); 2562 } 2563 logger_print(stardis->logger, LOG_OUTPUT, 2564 "System Tref range is [%g %g]\n", SPLIT2(stardis->t_range)); 2565 logger_print(stardis->logger, LOG_OUTPUT, 2566 "Picard order is %u\n", stardis->picard_order); 2567 2568 ASSERT(!f && !txtrdr); 2569 exit: 2570 if(word_initialized) wordfree(&pwordexp); 2571 return res; 2572 error: 2573 if(f) fclose(f); 2574 if(txtrdr) txtrdr_ref_put(txtrdr); 2575 goto exit; 2576 } 2577