stardis-app.c (32294B)
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 #ifdef STARDIS_ENABLE_MPI 17 #define _POSIX_C_SOURCE 200112L 18 #endif 19 20 #include <star/sg3d.h> 21 22 #include "stardis-app.h" 23 #include "stardis-args.h" 24 #include "stardis-description.h" 25 #include "stardis-default.h" 26 #include "stardis-parsing.h" 27 #include "stardis-compute.h" 28 #include "stardis-intface.h" 29 #include "stardis-solid.h" 30 #include "stardis-fluid.h" 31 #include "stardis-program.h" 32 33 #include <star/senc3d.h> 34 #include <star/sg3d_sencXd_helper.h> 35 #include <star/sg3d_sdisXd_helper.h> 36 37 #include <rsys/str.h> 38 #include <rsys/library.h> 39 #include <rsys/logger.h> 40 #include <rsys/double2.h> 41 #include <rsys/double3.h> 42 #include <rsys/dynamic_array_double.h> 43 44 #include <string.h> 45 46 #ifdef STARDIS_ENABLE_MPI 47 #include <stdio.h> 48 #include <mpi.h> 49 #endif 50 51 static const struct dummies DUMMIES_NULL = DUMMIES_NULL__; 52 static const struct counts COUNTS_NULL = COUNTS_NULL__; 53 54 /******************************************************************************* 55 * Local Functions 56 ******************************************************************************/ 57 static struct sdis_interface* 58 geometry_get_interface 59 (const size_t itri, void* ctx) 60 { 61 struct darray_interface_ptrs* app_interface_data = ctx; 62 ASSERT(app_interface_data 63 && itri < darray_interface_ptrs_size_get(app_interface_data)); 64 return darray_interface_ptrs_cdata_get(app_interface_data)[itri]; 65 } 66 67 static res_T 68 check_delta_and_create_solid 69 (struct stardis* stardis, 70 struct description* description) 71 { 72 res_T res = RES_OK; 73 struct senc3d_enclosure* enc = NULL; 74 double ratio, delta_range[2] = { DBL_MAX, -DBL_MAX }; 75 const double acceptance_ratio = 3; 76 struct senc3d_enclosure_header header; 77 struct solid* solid = description->d.solid; 78 79 ASSERT(stardis && description && description->type == DESC_MAT_SOLID); 80 81 /* Create solid to have ID informed */ 82 /* Check if delta can fit possible multiple enclosures */ 83 if(stardis->senc3d_scn) { 84 /* Due to previous errors, senc3d_scn can be unavailable */ 85 unsigned e, ecount = 0; 86 const unsigned desc_id = solid->desc_id; 87 double solid_volume = 0; 88 89 /* The enclosures where created using description ids */ 90 ERR(senc3d_scene_get_enclosure_count_by_medium(stardis->senc3d_scn, 91 desc_id, &ecount)); 92 if(ecount == 0) { 93 unsigned ccount; 94 ERR(sg3d_geometry_get_unique_triangles_with_properties_conflict_count( 95 stardis->geometry.sg3d, &ccount)); 96 CHK(ccount == 0); /* This solid can only be unused if in conflict*/ 97 } else { 98 int external = 0; 99 FOR_EACH(e, 0, ecount) { 100 ERR(senc3d_scene_get_enclosure_by_medium(stardis->senc3d_scn, desc_id, 101 e, &enc)); 102 ERR(senc3d_enclosure_get_header(enc, &header)); 103 solid_volume += header.volume; 104 if(header.is_infinite) { 105 /* External solid, volume is negative and no delta walk expected */ 106 external = 1; 107 } else { 108 double d = header.volume / (header.area * 6); 109 if(d <= 0) { 110 /* Should not */ 111 res = RES_BAD_OP; 112 goto error; 113 } 114 delta_range[0] = MMIN(delta_range[0], d); 115 delta_range[1] = MMAX(delta_range[1], d); 116 } 117 ERR(senc3d_enclosure_ref_put(enc)); 118 enc = NULL; 119 } 120 if(ecount > 1 || !external) { 121 ASSERT(0 < delta_range[0] && delta_range[0] <= delta_range[1]); 122 ratio = delta_range[1] / delta_range[0]; 123 if(ratio > acceptance_ratio) 124 logger_print(stardis->logger, LOG_WARNING, 125 "Solid '%s' is used in %u different enclosures that have different " 126 "delta requirements.\n", 127 str_cget(&solid->name), ecount); 128 /* Delta needs to be substituted with actual value */ 129 if(solid->delta == DELTA_AUTO) { 130 solid->delta = delta_range[0]; 131 logger_print(stardis->logger, LOG_OUTPUT, 132 "Auto delta for solid '%s' set to %g\n", 133 str_cget(&solid->name), solid->delta); 134 } else { 135 int too_small 136 = (delta_range[0] > solid->delta * acceptance_ratio); 137 int too_big 138 = (delta_range[0] * acceptance_ratio < solid->delta); 139 /* Check if user delta is OK */ 140 if(too_small || too_big) { 141 logger_print(stardis->logger, LOG_WARNING, 142 "User delta for solid '%s' seems too %s: %g; " 143 "auto delta would have set it to %g.\n", 144 str_cget(&solid->name), (too_big ? "big" : "small"), 145 solid->delta, delta_range[0]); 146 } 147 } 148 /* Print power */ 149 if(solid->vpower != SDIS_VOLUMIC_POWER_NONE && solid->vpower != 0) { 150 logger_print(stardis->logger, LOG_OUTPUT, 151 "Power of the Solid '%s': %g W\n", 152 str_cget(&solid->name), solid_volume * solid->vpower); 153 } 154 } 155 } 156 } 157 ERR(create_solver_solid(stardis, solid)); 158 159 end: 160 if(enc) SENC3D(enclosure_ref_put(enc)); 161 return res; 162 error: 163 goto end; 164 } 165 166 /******************************************************************************* 167 * Public Functions 168 ******************************************************************************/ 169 170 #ifdef STARDIS_ENABLE_MPI 171 /* To be called after logger has been initialized 172 * and before stardis is initialized */ 173 res_T 174 init_mpi 175 (int* pargc, 176 char** pargv[], 177 void (*prt_err_fn)(const char* msg, void* ctx), 178 void (*prt_warn_fn)(const char* msg, void* ctx)) 179 { 180 res_T res = RES_OK; 181 char buf[64]; 182 int mpi_provided; 183 184 ASSERT(pargc && pargv && prt_err_fn && prt_warn_fn); 185 186 if(MPI_Init_thread(pargc, pargv, MPI_THREAD_MULTIPLE, &mpi_provided) 187 != MPI_SUCCESS) 188 { 189 prt_err_fn("Cannot init MPI\n", NULL); 190 res = RES_BAD_ARG; 191 goto error; 192 } 193 else if(mpi_provided != MPI_THREAD_MULTIPLE) { 194 const char* lvl; 195 switch(mpi_provided) { 196 case MPI_THREAD_SINGLE: lvl = "MPI_THREAD_SINGLE"; break; 197 case MPI_THREAD_FUNNELED: lvl = "MPI_THREAD_FUNNELED"; break; 198 case MPI_THREAD_SERIALIZED: lvl = "MPI_THREAD_SERIALIZED"; break; 199 default: FATAL("Unreachable code.\n"); break; 200 } 201 snprintf(buf, sizeof(buf)-1, "MPI support restricted to %s\n", lvl); 202 prt_warn_fn(buf, NULL); 203 } 204 205 end: 206 return res; 207 error: 208 goto end; 209 } 210 211 void 212 finalize_mpi(void) 213 { 214 int initialized; 215 216 CHK(MPI_Initialized(&initialized) == MPI_SUCCESS); 217 if(initialized) 218 CHK(MPI_Finalize() == MPI_SUCCESS); 219 } 220 #endif 221 222 res_T 223 stardis_init 224 (const struct args* args, 225 struct logger* logger, 226 struct mem_allocator* allocator, 227 struct stardis* stardis) 228 { 229 res_T tmp_res, res = RES_OK; 230 struct sg3d_sdisXd_scene_create_context create_context; 231 struct htable_intface htable_interfaces; 232 struct str str, name; 233 FILE* f = NULL; 234 unsigned i, vcount, tcount, ocount, count; 235 int is_for_compute; 236 struct sdis_device_create_args dev_args = SDIS_DEVICE_CREATE_ARGS_DEFAULT; 237 238 ASSERT(args && logger && allocator && stardis); 239 240 str_init(allocator, &str); 241 str_init(allocator, &name); 242 /* Init everything that cannot fail */ 243 stardis->dummies = DUMMIES_NULL; 244 stardis->logger = logger; 245 stardis->allocator = allocator; 246 htable_intface_init(stardis->allocator, &htable_interfaces); 247 darray_descriptions_init(stardis->allocator, &stardis->descriptions); 248 d3_set(stardis->probe, args->pos_and_time); 249 d2_set(stardis->time_range, args->pos_and_time + 3); 250 stardis->dev = NULL; 251 stardis->sdis_scn = NULL; 252 stardis->senc3d_scn = NULL; 253 stardis->mode = args->mode; 254 stardis->counts = COUNTS_NULL; 255 init_camera(stardis->allocator, &stardis->camera); 256 str_init(stardis->allocator, &stardis->solve_name); 257 str_init(stardis->allocator, &stardis->dump_model_filename); 258 str_init(stardis->allocator, &stardis->paths_filename); 259 str_init(stardis->allocator, &stardis->bin_green_filename); 260 str_init(stardis->allocator, &stardis->end_paths_filename); 261 str_init(stardis->allocator, &stardis->rndgen_state_in_filename); 262 str_init(stardis->allocator, &stardis->rndgen_state_out_filename); 263 str_init(stardis->allocator, &stardis->chunks_prefix); 264 darray_size_t_init(stardis->allocator, &stardis->compute_surface.primitives); 265 darray_sides_init(stardis->allocator, &stardis->compute_surface.sides); 266 darray_uint_init(stardis->allocator, &stardis->compute_surface.err_triangles); 267 darray_probe_boundary_init(stardis->allocator, &stardis->probe_boundary_list); 268 stardis->compute_surface.area = 0; 269 stardis->samples = args->samples; 270 stardis->nthreads = args->nthreads; 271 stardis->picard_order = args->picard_order; 272 stardis->scale_factor = -1; /* invalid value */ 273 stardis->radenv = RADIATIVE_ENV_DEFAULT; 274 stardis->radenv_def = 0; 275 stardis->initial_time = args->initial_time; 276 stardis->geometry_initialized = 0; 277 d2(stardis->t_range, INF, -INF); 278 stardis->dump_paths = SDIS_HEAT_PATH_NONE; 279 if(args->dump_paths & DUMP_ERROR) 280 stardis->dump_paths |= SDIS_HEAT_PATH_FAILURE; 281 if(args->dump_paths & DUMP_SUCCESS) 282 stardis->dump_paths |= SDIS_HEAT_PATH_SUCCESS; 283 stardis->diff_algo = args->diff_algo; 284 stardis->next_medium_id = 0; 285 stardis->undefined_medium_behind_boundary_id = SENC3D_UNSPECIFIED_MEDIUM; 286 stardis->verbose = args->verbose; 287 stardis->extsrc = EXTERN_SOURCE_NULL; 288 stardis->disable_intrad = args->disable_intrad; 289 darray_media_ptr_init(stardis->allocator, &stardis->media); 290 291 /* If a dump is expected, we won't process any computation */ 292 is_for_compute = 293 (stardis->mode & COMPUTE_MODES) && !(stardis->mode & MODE_DUMP_MODEL); 294 295 dev_args.logger = stardis->logger; 296 dev_args.allocator = stardis->allocator; 297 dev_args.nthreads_hint = stardis->nthreads; 298 dev_args.verbosity = stardis->verbose; 299 300 #ifdef STARDIS_ENABLE_MPI 301 logger_print(stardis->logger, LOG_OUTPUT, "MPI is enabled.\n"); 302 /* Open MPI accepts the C/C++ argc and argv arguments to main, 303 * but neither modifies, interprets, nor distributes them: use NULL */ 304 CHK(MPI_Initialized(&stardis->mpi_initialized) == MPI_SUCCESS); 305 if(stardis->mpi_initialized) 306 CHK(MPI_Comm_rank(MPI_COMM_WORLD, &stardis->mpi_rank) == MPI_SUCCESS); 307 #else 308 logger_print(stardis->logger, LOG_OUTPUT, "MPI is disabled.\n"); 309 stardis->mpi_initialized = 0; 310 #endif 311 312 dev_args.use_mpi = stardis->mpi_initialized; 313 314 ERR(sdis_device_create(&dev_args, &stardis->dev)); 315 316 ERR(init_geometry(stardis->logger, stardis->allocator, stardis->verbose, 317 &stardis->geometry)); 318 stardis->geometry_initialized = 1; 319 320 if(args->dump_model_filename) { 321 ERR(str_set(&stardis->dump_model_filename, args->dump_model_filename)); 322 } 323 324 if(args->mode & MODE_COMPUTE_IMAGE_IR) { 325 ERR(parse_camera(stardis->logger, args->camera, stardis)); 326 } 327 else if(args->mode & MODE_COMPUTE_TEMP_MEAN_IN_MEDIUM) { 328 ERR(str_set(&stardis->solve_name, args->medium_name)); 329 } 330 else if((args->mode & MODE_COMPUTE_PROBE_TEMP_ON_SURF) 331 || (args->mode & MODE_COMPUTE_PROBE_FLUX_DNSTY_ON_SURF) 332 || (args->mode & MODE_COMPUTE_LIST_PROBE_TEMP_ON_SURF) 333 || (args->mode & MODE_COMPUTE_LIST_PROBE_FLUX_DNSTY_ON_SURF)) { 334 ERR(darray_probe_boundary_copy 335 (&stardis->probe_boundary_list, &args->probe_boundary_list)); 336 } 337 else if(args->mode & SURFACE_COMPUTE_MODES) { 338 ERR(str_set(&stardis->solve_name, args->solve_filename)); 339 } 340 else if(args->mode & MODE_DUMP_C_CHUNKS) { 341 ERR(str_set(&stardis->chunks_prefix, args->chunks_prefix)); 342 } 343 ERR(read_model(&args->model_files, stardis)); 344 345 create_context.geometry = stardis->geometry.sg3d; 346 create_context.app_interface_getter = geometry_get_interface; 347 create_context.app_interface_data = &stardis->geometry.interf_bytrg; 348 ERR(sg3d_geometry_get_unique_vertices_count(stardis->geometry.sg3d, &vcount)); 349 ERR(sg3d_geometry_get_unique_triangles_count(stardis->geometry.sg3d, &tcount)); 350 351 logger_print(stardis->logger, LOG_OUTPUT, 352 "Read %u unique triangles.\n", tcount); 353 354 ERR(sg3d_geometry_validate_properties(stardis->geometry.sg3d, 355 validate_properties, stardis)); 356 ERR(sg3d_geometry_get_unique_triangles_with_properties_conflict_count( 357 stardis->geometry.sg3d, &count)); 358 if(count) { 359 if(!str_is_empty(&stardis->dump_model_filename)) { 360 ERR(str_copy(&name, &stardis->dump_model_filename)); 361 ERR(str_append(&name, "_property_conflits.obj")); 362 f = fopen(str_cget(&name), "w"); 363 if(!f) { 364 logger_print(stardis->logger, LOG_ERROR, 365 "cannot open file '%s' for writing.\n", str_cget(&name)); 366 res = RES_IO_ERR; 367 goto error; 368 } 369 ERR(sg3d_geometry_dump_as_obj(stardis->geometry.sg3d, f, 370 SG3D_OBJ_DUMP_PROPERTY_CONFLICTS)); 371 fclose(f); f = NULL; 372 } 373 logger_print(stardis->logger, (is_for_compute ? LOG_ERROR : LOG_WARNING), 374 "Property conflicts found in the model (%u triangles).\n", count); 375 if(is_for_compute) { 376 res = RES_BAD_ARG; 377 goto error; 378 } 379 } 380 381 /* If computation is on a compute surface, read it */ 382 if(args->mode & SURFACE_COMPUTE_MODES) { 383 unsigned save_count = count; 384 ASSERT(!str_is_empty(&stardis->solve_name)); 385 ERR(read_compute_surface(stardis)); 386 /* Check compute surface */ 387 ERR(sg3d_geometry_validate_properties(stardis->geometry.sg3d, 388 validate_properties, stardis)); 389 ERR(sg3d_geometry_get_unique_triangles_with_properties_conflict_count( 390 stardis->geometry.sg3d, &count)); 391 ASSERT(count >= save_count); 392 if(save_count != count) { 393 logger_print(stardis->logger, (is_for_compute ? LOG_ERROR : LOG_WARNING), 394 "Invalid compute region defined by file '%s'.\n", 395 str_cget(&stardis->solve_name)); 396 logger_print(stardis->logger, (is_for_compute ? LOG_ERROR : LOG_WARNING), 397 "The file contains %u triangles not in the model.\n", count - save_count); 398 if(is_for_compute) { 399 res = RES_BAD_ARG; 400 goto error; 401 } 402 } 403 logger_print(stardis->logger, LOG_OUTPUT, "Compute surface area is %g m2\n", 404 stardis->compute_surface.area); 405 } 406 407 /* Create enclosures */ 408 tmp_res = init_enclosures(stardis); 409 if(tmp_res != RES_OK && is_for_compute) { 410 res = tmp_res; 411 goto error; 412 } 413 ERR(senc3d_scene_get_overlapping_triangles_count(stardis->senc3d_scn, &ocount)); 414 if(ocount) { 415 if(!str_is_empty(&stardis->dump_model_filename)) { 416 ERR(str_copy(&name, &stardis->dump_model_filename)); 417 ERR(str_append(&name, "_overlapping_triangles.obj")); 418 f = fopen(str_cget(&name), "w"); 419 if(!f) { 420 logger_print(stardis->logger, LOG_ERROR, 421 "cannot open file '%s' for writing.\n", str_cget(&name)); 422 res = RES_IO_ERR; 423 goto error; 424 } 425 /* Dump vertices */ 426 for(i = 0; i < vcount; i++) { 427 double coord[3]; 428 ERR(senc3d_scene_get_vertex(stardis->senc3d_scn, i, coord)); 429 fprintf(f, "v %.16g %.16g %.16g\n", SPLIT3(coord)); 430 } 431 /* Dump triangles */ 432 for(i = 0; i < ocount; i++) { 433 unsigned id, trg[3]; 434 ERR(senc3d_scene_get_overlapping_triangle(stardis->senc3d_scn, i, &id)); 435 ERR(senc3d_scene_get_triangle(stardis->senc3d_scn, id, trg)); 436 fprintf(f, "f %u %u %u\n", 437 1 + trg[0], 1 + trg[1], 1 + trg[2]); /* OBJ indexing starts at 1 */ 438 } 439 fclose(f); f = NULL; 440 } 441 logger_print(stardis->logger, (is_for_compute ? LOG_ERROR : LOG_WARNING), 442 "Scene contains %u overlapping triangles.\n", 443 ocount); 444 if(is_for_compute) { 445 res = RES_BAD_ARG; 446 goto error; 447 } 448 } 449 450 /* Create solids, finalize program data, and log model information */ 451 for(i = 0; i < darray_descriptions_size_get(&stardis->descriptions); i++) { 452 struct description* desc = 453 darray_descriptions_data_get(&stardis->descriptions) + i; 454 if(desc->type == DESC_MAT_SOLID) { 455 tmp_res = check_delta_and_create_solid(stardis, desc); 456 } else if(desc->type == DESC_PROGRAM && desc->d.program->finalize) { 457 enum stardis_return_status rs; 458 rs = desc->d.program->finalize(desc->d.program->prog_data); 459 switch(rs) { 460 case STARDIS_SUCCESS: tmp_res = RES_OK; break; 461 case STARDIS_FAILURE: tmp_res = RES_BAD_ARG; break; 462 default: 463 FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); 464 } 465 } 466 if(tmp_res != RES_OK && is_for_compute) { 467 res = tmp_res; 468 goto error; 469 } 470 ERR(str_print_description(&str, i, desc)); 471 logger_print(stardis->logger, LOG_OUTPUT, "%s\n", str_cget(&str)); 472 } 473 474 if(is_for_compute) { 475 for(i = 0; i < tcount; ++i) { 476 ERR(create_intface(stardis, i, &htable_interfaces)); 477 } 478 if(args->paths_filename) { 479 ERR(str_set(&stardis->paths_filename, args->paths_filename)); 480 } 481 if(args->bin_green_filename) { 482 ERR(str_set(&stardis->bin_green_filename, args->bin_green_filename)); 483 } 484 if(args->end_paths_filename) { 485 ERR(str_set(&stardis->end_paths_filename, args->end_paths_filename)); 486 } 487 if(args->rndgen_state_in_filename) { 488 ERR(str_set(&stardis->rndgen_state_in_filename, 489 args->rndgen_state_in_filename)); 490 } 491 if(args->rndgen_state_out_filename) { 492 ERR(str_set(&stardis->rndgen_state_out_filename, 493 args->rndgen_state_out_filename)); 494 } 495 } 496 497 /* If computation is on a volume, check medium is known */ 498 if(args->mode & MODE_COMPUTE_TEMP_MEAN_IN_MEDIUM) { 499 if(!find_medium_by_name(stardis, str_cget(&stardis->solve_name), NULL)) { 500 logger_print(stardis->logger, (is_for_compute ? LOG_ERROR : LOG_WARNING), 501 "Cannot find medium '%s'\n", str_cget(&stardis->solve_name)); 502 res = RES_BAD_ARG; 503 goto error; 504 } 505 } 506 507 if(is_for_compute) { 508 struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT; 509 ASSERT(darray_interface_ptrs_size_get(&stardis->geometry.interf_bytrg) 510 == tcount); 511 512 res = radiative_env_create_solver_radiative_env(&stardis->radenv, stardis); 513 if(res != RES_OK) goto error; 514 515 scn_args.get_indices = sg3d_sdisXd_geometry_get_indices; 516 scn_args.get_interface = sg3d_sdisXd_geometry_get_interface; 517 scn_args.get_position = sg3d_sdisXd_geometry_get_position; 518 scn_args.nprimitives = tcount; 519 scn_args.nvertices = vcount; 520 scn_args.fp_to_meter = stardis->scale_factor; 521 scn_args.t_range[0] = stardis->t_range[0]; 522 scn_args.t_range[1] = stardis->t_range[1]; 523 scn_args.source = stardis->extsrc.sdis_src; 524 scn_args.radenv = stardis->radenv.sdis_radenv; 525 scn_args.context = &create_context; 526 527 /* Setting Tmax to 0 is a way of setting the radiative coefficient to 0, and 528 * thus setting the probability of evolving in a radiative random walk to 529 * zero. */ 530 if(stardis->disable_intrad) { 531 scn_args.t_range[0] = 0; 532 scn_args.t_range[1] = 0; 533 } 534 535 res = sdis_scene_create(stardis->dev, &scn_args, &stardis->sdis_scn); 536 if(res != RES_OK) { 537 logger_print(stardis->logger, LOG_ERROR, 538 "Cannot create the stardis solver scene.\n"); 539 goto error; 540 } 541 } 542 543 exit: 544 if(f) fclose(f); 545 str_release(&str); 546 str_release(&name); 547 htable_intface_release(&htable_interfaces); 548 return res; 549 error: 550 stardis_release(stardis); 551 goto exit; 552 } 553 554 void 555 stardis_release 556 (struct stardis* stardis) 557 { 558 size_t i; 559 560 ASSERT(stardis); 561 562 if(stardis->dev) SDIS(device_ref_put(stardis->dev)); 563 if(stardis->sdis_scn) SDIS(scene_ref_put(stardis->sdis_scn)); 564 if(stardis->senc3d_scn) SENC3D(scene_ref_put(stardis->senc3d_scn)); 565 str_release(&stardis->solve_name); 566 str_release(&stardis->dump_model_filename); 567 str_release(&stardis->paths_filename); 568 str_release(&stardis->bin_green_filename); 569 str_release(&stardis->end_paths_filename); 570 str_release(&stardis->chunks_prefix); 571 572 extern_source_release(&stardis->extsrc); 573 radiative_env_release(&stardis->radenv); 574 575 /* release non-PROGRAM descritions first */ 576 FOR_EACH(i, 0, darray_descriptions_size_get(&stardis->descriptions)) { 577 struct description* d = darray_descriptions_data_get(&stardis->descriptions) +i; 578 if(d->type == DESC_PROGRAM) continue; 579 release_description(d, stardis->allocator); 580 } 581 /* release PROGRAM descritions */ 582 FOR_EACH(i, 0, darray_descriptions_size_get(&stardis->descriptions)) { 583 struct description* d = darray_descriptions_data_get(&stardis->descriptions) +i; 584 if(d->type != DESC_PROGRAM) continue; 585 release_description(d, stardis->allocator); 586 } 587 darray_descriptions_release(&stardis->descriptions); 588 if(stardis->geometry_initialized) 589 release_geometry(&stardis->geometry); 590 darray_size_t_release(&stardis->compute_surface.primitives); 591 darray_sides_release(&stardis->compute_surface.sides); 592 darray_uint_release(&stardis->compute_surface.err_triangles); 593 FOR_EACH(i, 0, darray_media_ptr_size_get(&stardis->media)) { 594 if(darray_media_ptr_data_get(&stardis->media)[i]) 595 SDIS(medium_ref_put(darray_media_ptr_data_get(&stardis->media)[i])); 596 } 597 darray_media_ptr_release(&stardis->media); 598 release_camera(&stardis->camera); 599 if(stardis->dummies.stardis_fluid) { 600 release_fluid(stardis->dummies.stardis_fluid, stardis->allocator); 601 } 602 if(stardis->dummies.stardis_solid) { 603 release_solid(stardis->dummies.stardis_solid, stardis->allocator); 604 } 605 darray_probe_boundary_release(&stardis->probe_boundary_list); 606 } 607 608 unsigned 609 allocate_stardis_medium_id 610 (struct stardis* stardis) 611 { 612 ASSERT(stardis); 613 return stardis->next_medium_id++; 614 } 615 616 res_T 617 init_enclosures 618 (struct stardis* stardis) 619 { 620 res_T res = RES_OK; 621 unsigned tsz, vsz; 622 struct senc3d_device* senc_dev = NULL; 623 624 ERR(sg3d_geometry_get_unique_triangles_count(stardis->geometry.sg3d, &tsz)); 625 626 ERR(sg3d_geometry_get_unique_vertices_count(stardis->geometry.sg3d, &vsz)); 627 ERR(senc3d_device_create(stardis->logger, stardis->allocator, 628 stardis->nthreads, stardis->verbose, &senc_dev)); 629 stardis->undefined_medium_behind_boundary_id 630 = allocate_stardis_medium_id(stardis); 631 ERR(senc3d_scene_create(senc_dev, 632 SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_OUTSIDE, 633 tsz, sg3d_sencXd_geometry_get_indices, sg3d_sencXd_geometry_get_media, 634 vsz, sg3d_sencXd_geometry_get_position, stardis->geometry.sg3d, 635 &stardis->senc3d_scn)); 636 exit: 637 if(senc_dev) senc3d_device_ref_put(senc_dev); 638 return res; 639 error: 640 goto exit; 641 } 642 643 #define COUNT_SIDE(Rank) {\ 644 if(properties[(Rank)] == SG3D_UNSPECIFIED_PROPERTY) undef_count++;\ 645 else {\ 646 ASSERT(properties[(Rank)] < darray_descriptions_size_get(&stardis->descriptions));\ 647 ASSERT(DESC_IS_MEDIUM(descs+properties[(Rank)]));\ 648 if(DESC_IS_SOLID(descs+properties[(Rank)])) { solid_count++; }\ 649 else { ASSERT(DESC_IS_FLUID(descs+properties[(Rank)])); fluid_count++; }\ 650 }\ 651 } 652 653 res_T 654 validate_properties 655 (const unsigned itri, 656 const unsigned properties[SG3D_PROP_TYPES_COUNT__], 657 void* context, 658 int* properties_conflict_status) 659 { 660 res_T res = RES_OK; 661 struct stardis* stardis = context; 662 unsigned undef_count, solid_count, fluid_count, intface_count; 663 const struct description* descs; 664 const struct description* intface = NULL; 665 666 (void)itri; 667 ASSERT(stardis && properties_conflict_status); 668 descs = darray_descriptions_cdata_get(&stardis->descriptions); 669 *properties_conflict_status = NO_PROPERTY_CONFLICT; 670 undef_count = solid_count = fluid_count = intface_count = 0; 671 672 COUNT_SIDE(SG3D_FRONT); 673 COUNT_SIDE(SG3D_BACK); 674 if(properties[SG3D_INTFACE] == SG3D_UNSPECIFIED_PROPERTY) 675 undef_count++; 676 else intface_count++; 677 678 ASSERT(solid_count <= 2 && fluid_count <= 2 && intface_count <= 1); 679 ASSERT(undef_count + solid_count + fluid_count + intface_count == 3); 680 if(intface_count) { 681 ASSERT(properties[SG3D_INTFACE] 682 < darray_descriptions_size_get(&stardis->descriptions)); 683 intface = descs + properties[SG3D_INTFACE]; 684 switch (intface->type) { 685 case DESC_BOUND_H_FOR_FLUID: 686 case DESC_BOUND_H_FOR_FLUID_PROG: 687 if(!(solid_count == 0 && fluid_count == 1)) { 688 if(solid_count + fluid_count == 2) 689 *properties_conflict_status = BOUND_H_FOR_FLUID_BETWEEN_2_DEFS; 690 else if(solid_count + fluid_count == 0) 691 *properties_conflict_status = BOUND_H_FOR_FLUID_BETWEEN_2_UNDEFS; 692 else if(solid_count == 1) 693 *properties_conflict_status = BOUND_H_FOR_FLUID_ENCLOSING_SOLID; 694 else FATAL("error:" STR(__FILE__) ":" STR(__LINE__)"\n"); 695 goto end; 696 } 697 break; 698 case DESC_BOUND_H_FOR_SOLID: 699 case DESC_BOUND_H_FOR_SOLID_PROG: 700 if(!(solid_count == 1 && fluid_count == 0)) { 701 if(solid_count + fluid_count == 2) 702 *properties_conflict_status = BOUND_H_FOR_SOLID_BETWEEN_2_DEFS; 703 else if(solid_count + fluid_count == 0) 704 *properties_conflict_status = BOUND_H_FOR_SOLID_BETWEEN_2_UNDEFS; 705 else if(fluid_count == 1) 706 *properties_conflict_status = BOUND_H_FOR_SOLID_ENCLOSING_FLUID; 707 else FATAL("error:" STR(__FILE__) ":" STR(__LINE__)"\n"); 708 goto end; 709 } 710 break; 711 case DESC_BOUND_HF_FOR_SOLID: 712 case DESC_BOUND_HF_FOR_SOLID_PROG: 713 if(!(solid_count == 1 && fluid_count == 0)) { 714 if(solid_count + fluid_count == 2) 715 *properties_conflict_status = BOUND_HF_FOR_SOLID_BETWEEN_2_DEFS; 716 else if(solid_count + fluid_count == 0) 717 *properties_conflict_status = BOUND_HF_FOR_SOLID_BETWEEN_2_UNDEFS; 718 else if(fluid_count == 1) 719 *properties_conflict_status = BOUND_HF_FOR_SOLID_ENCLOSING_FLUID; 720 else FATAL("error:" STR(__FILE__) ":" STR(__LINE__)"\n"); 721 goto end; 722 } 723 break; 724 case DESC_BOUND_T_FOR_SOLID: 725 case DESC_BOUND_T_FOR_SOLID_PROG: 726 if(!(solid_count == 1 && fluid_count == 0)) { 727 if(solid_count + fluid_count == 2) 728 *properties_conflict_status = BOUND_T_FOR_SOLID_BETWEEN_2_DEFS; 729 else if(solid_count + fluid_count == 0) 730 *properties_conflict_status = BOUND_T_FOR_SOLID_BETWEEN_2_UNDEFS; 731 else if(fluid_count == 1) 732 *properties_conflict_status = BOUND_T_FOR_SOLID_ENCLOSING_FLUID; 733 else FATAL("error:" STR(__FILE__) ":" STR(__LINE__)"\n"); 734 goto end; 735 } 736 break; 737 case DESC_BOUND_F_FOR_SOLID: 738 case DESC_BOUND_F_FOR_SOLID_PROG: 739 if(!(solid_count == 1 && fluid_count == 0)) { 740 if(solid_count + fluid_count == 2) 741 *properties_conflict_status = BOUND_F_FOR_SOLID_BETWEEN_2_DEFS; 742 else if(solid_count + fluid_count == 0) 743 *properties_conflict_status = BOUND_F_FOR_SOLID_BETWEEN_2_UNDEFS; 744 else if(fluid_count == 1) 745 *properties_conflict_status = BOUND_F_FOR_SOLID_ENCLOSING_FLUID; 746 else FATAL("error:" STR(__FILE__) ":" STR(__LINE__)"\n"); 747 goto end; 748 } 749 break; 750 case DESC_SOLID_FLUID_CONNECT: 751 case DESC_SOLID_FLUID_CONNECT_PROG: 752 if(solid_count != 1 || fluid_count != 1) { 753 if(solid_count == 2) 754 *properties_conflict_status = SFCONNECT_BETWEEN_2_SOLIDS; 755 else if(fluid_count == 2) 756 *properties_conflict_status = SFCONNECT_BETWEEN_2_FLUIDS; 757 else if(solid_count + fluid_count == 1) 758 *properties_conflict_status = SFCONNECT_USED_AS_BOUNDARY; 759 else if(solid_count + fluid_count == 0) 760 *properties_conflict_status = SFCONNECT_BETWEEN_2_UNDEFS; 761 else FATAL("error:" STR(__FILE__) ":" STR(__LINE__)"\n"); 762 goto end; 763 } 764 break; 765 case DESC_SOLID_SOLID_CONNECT: 766 case DESC_SOLID_SOLID_CONNECT_PROG: 767 if(solid_count != 2) { 768 /*if(soli_count == 1 && fluid_count == 1)*/ 769 /**properties_conflict_status = SSCONNECT_BETWEEN_SOLID_AND_FLUID;*/ 770 goto end; 771 } 772 break; 773 default: 774 FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); 775 } 776 } else { 777 /* No interface defined */ 778 ASSERT(intface_count == 0 && undef_count >= 1); 779 if(undef_count == 3) { 780 *properties_conflict_status = TRG_WITH_NO_PROPERTY; 781 goto end; 782 } 783 if(fluid_count == 2) { 784 *properties_conflict_status = NO_CONNECTION_BETWEEN_2_FLUIDS; 785 goto end; 786 } 787 if(undef_count == 2) { 788 ASSERT(fluid_count + solid_count == 1); 789 if(fluid_count) 790 *properties_conflict_status = NO_BOUND_BETWEEN_FLUID_AND_UNDEF; 791 else *properties_conflict_status = NO_BOUND_BETWEEN_SOLID_AND_UNDEF; 792 goto end; 793 } 794 if(undef_count == 1 && solid_count == 1 && fluid_count == 1) { 795 *properties_conflict_status = NO_CONNECTION_BETWEEN_SOLID_AND_FLUID; 796 goto end; 797 } 798 /* Undef interface between solids is OK */ 799 CHK(solid_count == 2); 800 } 801 802 end: 803 return res; 804 } 805 806 #undef COUNT_SIDE 807 808 res_T 809 init_geometry 810 (struct logger* logger, 811 struct mem_allocator* allocator, 812 const int verbose, 813 struct geometry* geom) 814 { 815 res_T res = RES_OK; 816 struct sg3d_device* sg3d_dev = NULL; 817 818 ASSERT(allocator && geom); 819 820 geom->sg3d = NULL; 821 darray_interface_ptrs_init(allocator, &geom->interfaces); 822 darray_interface_ptrs_init(allocator, &geom->interf_bytrg); 823 ERR(sg3d_device_create(logger, allocator, verbose, &sg3d_dev)); 824 ERR(sg3d_geometry_create(sg3d_dev, &geom->sg3d)); 825 826 exit: 827 if(sg3d_dev) SG3D(device_ref_put(sg3d_dev)); 828 return res; 829 error: 830 release_geometry(geom); 831 goto exit; 832 } 833 834 void 835 release_geometry 836 (struct geometry* geom) 837 { 838 size_t i; 839 struct sdis_interface 840 ** intf = darray_interface_ptrs_data_get(&geom->interfaces); 841 if(geom->sg3d) SG3D(geometry_ref_put(geom->sg3d)); 842 for(i = 0; i < darray_interface_ptrs_size_get(&geom->interfaces); ++i) 843 SDIS(interface_ref_put(intf[i])); 844 darray_interface_ptrs_release(&geom->interfaces); 845 darray_interface_ptrs_release(&geom->interf_bytrg); 846 } 847 848 void 849 init_camera 850 (struct mem_allocator* alloc, struct camera* cam) 851 { 852 ASSERT(alloc && cam); 853 d3(cam->pos, STARDIS_DEFAULT_RENDERING_POS); 854 d3(cam->tgt, STARDIS_DEFAULT_RENDERING_TGT); 855 d3(cam->up, STARDIS_DEFAULT_RENDERING_UP); 856 cam->fmt = STARDIS_DEFAULT_RENDERING_OUTPUT_FILE_FMT; 857 cam->fov = STARDIS_DEFAULT_RENDERING_FOV; 858 cam->spp = STARDIS_DEFAULT_RENDERING_SPP; 859 cam->img_width = STARDIS_DEFAULT_RENDERING_IMG_WIDTH; 860 cam->img_height = STARDIS_DEFAULT_RENDERING_IMG_HEIGHT; 861 d2(cam->time_range, STARDIS_DEFAULT_RENDERING_TIME); 862 cam->auto_look_at = 1; 863 str_init(alloc, &cam->file_name); 864 } 865 866 void 867 release_camera 868 (struct camera* cam) 869 { 870 ASSERT(cam); 871 str_release(&cam->file_name); 872 } 873 874 void 875 log_err_fn 876 (const char* msg, void* ctx) 877 { 878 #ifdef STARDIS_ENABLE_MPI 879 int initialized, rank = 0; 880 #endif 881 882 ASSERT(msg); 883 (void)ctx; 884 885 #ifdef STARDIS_ENABLE_MPI 886 CHK(MPI_Initialized(&initialized) == MPI_SUCCESS); 887 if(initialized) CHK(MPI_Comm_rank(MPI_COMM_WORLD, &rank) == MPI_SUCCESS); 888 /* Only master prints */ 889 if(rank != 0) return; 890 #endif 891 892 #ifdef OS_WINDOWS 893 fprintf(stderr, "error: %s", msg); 894 #else 895 fprintf(stderr, "\x1b[31merror:\x1b[0m %s", msg); 896 #endif 897 } 898 899 void 900 log_warn_fn 901 (const char* msg, void* ctx) 902 { 903 #ifdef STARDIS_ENABLE_MPI 904 int initialized, rank = 0; 905 #endif 906 907 ASSERT(msg); 908 (void)ctx; 909 910 #ifdef STARDIS_ENABLE_MPI 911 CHK(MPI_Initialized(&initialized) == MPI_SUCCESS); 912 if(initialized) CHK(MPI_Comm_rank(MPI_COMM_WORLD, &rank) == MPI_SUCCESS); 913 /* Only master prints */ 914 if(rank != 0) return; 915 #endif 916 917 #ifdef OS_WINDOWS 918 fprintf(stderr, "warning: %s", msg); 919 #else 920 fprintf(stderr, "\x1b[33mwarning:\x1b[0m %s", msg); 921 #endif 922 } 923 924 void 925 log_prt_fn 926 (const char* msg, void* ctx) 927 { 928 #ifdef STARDIS_ENABLE_MPI 929 int initialized, rank = 0; 930 #endif 931 932 ASSERT(msg); 933 (void)ctx; 934 935 #ifdef STARDIS_ENABLE_MPI 936 CHK(MPI_Initialized(&initialized) == MPI_SUCCESS); 937 if(initialized) CHK(MPI_Comm_rank(MPI_COMM_WORLD, &rank) == MPI_SUCCESS); 938 /* only master prints */ 939 if(rank != 0) return; 940 #endif 941 942 #ifdef OS_WINDOWS 943 fprintf(stderr, "message: %s", msg); 944 #else 945 fprintf(stderr, "\x1b[32moutput:\x1b[0m %s", msg); 946 #endif 947 } 948