htrdr_planets_args.c (27055B)
1 /* Copyright (C) 2018-2019, 2022-2025 Centre National de la Recherche Scientifique 2 * Copyright (C) 2020-2022 Institut Mines Télécom Albi-Carmaux 3 * Copyright (C) 2022-2025 Institut Pierre-Simon Laplace 4 * Copyright (C) 2022-2025 Institut de Physique du Globe de Paris 5 * Copyright (C) 2018-2025 |Méso|Star> (contact@meso-star.com) 6 * Copyright (C) 2022-2025 Observatoire de Paris 7 * Copyright (C) 2022-2025 Université de Reims Champagne-Ardenne 8 * Copyright (C) 2022-2025 Université de Versaille Saint-Quentin 9 * Copyright (C) 2018-2019, 2022-2025 Université Paul Sabatier 10 * 11 * This program is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation, either version 3 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 23 24 #define _POSIX_C_SOURCE 200112L /* strtok_r support */ 25 26 #include "planets/htrdr_planets_args.h" 27 28 #include <rsys/cstr.h> 29 #include <rsys/stretchy_array.h> 30 #include <rsys/mem_allocator.h> 31 32 #include <getopt.h> 33 #include <string.h> 34 35 /******************************************************************************* 36 * Helper functions 37 ******************************************************************************/ 38 static INLINE res_T 39 check_gas_args(const struct rnatm_gas_args* args) 40 { 41 if(!args) return RES_BAD_ARG; 42 43 /* Filenames cannot be NULL */ 44 if(!args->smsh_filename 45 || !args->sck_filename 46 || !args->temperatures_filename) 47 return RES_BAD_ARG; 48 49 return RES_OK; 50 } 51 52 static INLINE res_T 53 check_aerosol_args(const struct rnatm_aerosol_args* args) 54 { 55 if(!args) return RES_BAD_ARG; 56 57 /* Filenames cannot be NULL */ 58 if(!args->smsh_filename 59 || !args->sars_filename 60 || !args->phase_fn_ids_filename 61 || !args->phase_fn_lst_filename) 62 return RES_BAD_ARG; 63 64 return RES_OK; 65 } 66 67 static INLINE res_T 68 check_ground_args(const struct htrdr_planets_ground_args* args) 69 { 70 if(!args) return RES_BAD_ARG; 71 72 /* Filenames cannot be NULL */ 73 if(!args->smsh_filename 74 || !args->props_filename 75 || !args->mtllst_filename) 76 return RES_BAD_ARG; 77 78 return RES_OK; 79 } 80 81 static INLINE res_T 82 check_spectral_args(const struct htrdr_planets_spectral_args* args) 83 { 84 if(!args) return RES_BAD_ARG; 85 86 /* Invalid type */ 87 switch(args->type) { 88 case HTRDR_SPECTRAL_LW: 89 case HTRDR_SPECTRAL_SW: 90 case HTRDR_SPECTRAL_SW_CIE_XYZ: 91 /* Nothing to be done */ 92 break; 93 default: 94 return RES_BAD_ARG; 95 } 96 97 /* Invalid spectral range */ 98 if(args->wlen_range[0] < 0 99 || args->wlen_range[1] < 0 100 || args->wlen_range[0] > args->wlen_range[1]) 101 return RES_BAD_ARG; 102 103 return RES_OK; 104 } 105 106 static INLINE res_T 107 check_volrad_budget_args(const struct htrdr_planets_volrad_budget_args* args) 108 { 109 if(!args) return RES_BAD_ARG; 110 111 /* Filename could not be NULL */ 112 if(!args->smsh_filename) return RES_BAD_ARG; 113 114 /* Samples per tetrahedron could not be zero */ 115 if(!args->spt) return RES_BAD_ARG; 116 117 return RES_OK; 118 } 119 120 static INLINE res_T 121 check_accel_struct_build_args 122 (const struct htrdr_planets_accel_struct_build_args* args) 123 { 124 if(!args) return RES_BAD_ARG; 125 126 /* Definition and number of threads cannot be null */ 127 if(!args->definition_hint || !args->nthreads) return RES_BAD_ARG; 128 129 /* Invalid threshold */ 130 if(args->optical_thickness < 0) return RES_BAD_ARG; 131 132 return RES_OK; 133 } 134 135 static void 136 usage(void) 137 { 138 printf("usage: htrdr-planets [-dfhNv] [-a aerosol_opt[:aerosol_opt ...]]\n"); 139 printf(" [-b accel_struct_build_opt[:accel_struct_build_opt ...]]\n"); 140 printf(" [-C persp_camera_opt[:persp_camera_opt ...]]\n"); 141 printf(" [-G ground_opt[:ground_opt ...]]\n"); 142 printf(" [-i image_opt[:image_opt ...]] [-o output]\n"); 143 printf(" [-P ortho_camera_opt[:ortho_camera_opt ...]]\n"); 144 printf(" [-r volrad_budget_opt[:volrad_budget_opt ...]]\n"); 145 printf(" [-S source_opt[:source_opt ...]]\n"); 146 printf(" [-s spectral_opt[:spectral_opt ...]] [-t threads_count]\n"); 147 printf(" -g gas_opt[:gas_opt ...]\n"); 148 } 149 150 static INLINE char* 151 str_dup(const char* str) 152 { 153 size_t len = 0; 154 char* dup = NULL; 155 ASSERT(str); 156 len = strlen(str) + 1/*NULL char*/; 157 dup = mem_alloc(len); 158 if(!dup) { 159 return NULL; 160 } else { 161 return memcpy(dup, str, len); 162 } 163 } 164 165 static res_T 166 parse_aerosol_parameters(const char* str, void* ptr) 167 { 168 enum { MESH, NAME, RADPROP, PHASEFN, PHASEIDS } iparam; 169 struct rnatm_aerosol_args* aerosol = NULL; 170 char buf[BUFSIZ]; 171 struct htrdr_planets_args* args = ptr; 172 char* key; 173 char* val; 174 char* tk_ctx; 175 res_T res = RES_OK; 176 ASSERT(args && str); 177 178 if(strlen(str) >= sizeof(buf) -1/*NULL char*/) { 179 fprintf(stderr, "Could not duplicate the aerosol parameter `%s'\n", str); 180 res = RES_MEM_ERR; 181 goto error; 182 } 183 strncpy(buf, str, sizeof(buf)); 184 185 key = strtok_r(buf, "=", &tk_ctx); 186 val = strtok_r(NULL, "", &tk_ctx); 187 188 if(!strcmp(key, "mesh")) iparam = MESH; 189 else if(!strcmp(key, "name")) iparam = NAME; 190 else if(!strcmp(key, "radprop")) iparam = RADPROP; 191 else if(!strcmp(key, "phasefn")) iparam = PHASEFN; 192 else if(!strcmp(key, "phaseids")) iparam = PHASEIDS; 193 else { 194 fprintf(stderr, "Invalid aerosol parameter `%s'\n", key); 195 res = RES_BAD_ARG; 196 goto error; 197 } 198 199 if(!val) { 200 fprintf(stderr, "Invalid null value for aerosol parameter `%s'\n", key); 201 res = RES_BAD_ARG; 202 goto error; 203 } 204 205 ASSERT(args->naerosols); 206 aerosol = args->aerosols + (args->naerosols - 1); 207 208 #define SET_STR(Dst) { \ 209 if(Dst) mem_rm(Dst); \ 210 if(!((Dst) = str_dup(val))) res = RES_MEM_ERR; \ 211 } (void)0 212 switch(iparam) { 213 case MESH: SET_STR(aerosol->smsh_filename); break; 214 case NAME: SET_STR(aerosol->name); break; 215 case RADPROP: SET_STR(aerosol->sars_filename); break; 216 case PHASEFN: SET_STR(aerosol->phase_fn_lst_filename); break; 217 case PHASEIDS: SET_STR(aerosol->phase_fn_ids_filename); break; 218 default: FATAL("Unreachable code\n"); break; 219 } 220 #undef SET_STR 221 if(res != RES_OK) { 222 fprintf(stderr, "Unable to parse the aerosol parameter `%s' -- %s\n", 223 str, res_to_cstr(res)); 224 goto error; 225 } 226 227 exit: 228 return res; 229 error: 230 goto exit; 231 } 232 233 static res_T 234 parse_ground_parameters(const char* str, void* ptr) 235 { 236 enum { BRDF, MESH, NAME, PROP } iparam; 237 char buf[BUFSIZ]; 238 struct htrdr_planets_args* args = ptr; 239 char* key; 240 char* val; 241 char* tk_ctx; 242 res_T res = RES_OK; 243 ASSERT(args && str); 244 245 if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { 246 fprintf(stderr, "Could not duplicate the ground parameter `%s'\n", str); 247 res = RES_MEM_ERR; 248 goto error; 249 } 250 strncpy(buf, str, sizeof(buf)); 251 252 key = strtok_r(buf, "=", &tk_ctx); 253 val = strtok_r(NULL, "", &tk_ctx); 254 255 if(!strcmp(key, "brdf")) iparam = BRDF; 256 else if(!strcmp(key, "mesh")) iparam = MESH; 257 else if(!strcmp(key, "name")) iparam = NAME; 258 else if(!strcmp(key, "prop")) iparam = PROP; 259 else { 260 fprintf(stderr, "Invalid ground parameter `%s'\n", key); 261 res = RES_BAD_ARG; 262 goto error; 263 } 264 265 if(!val) { 266 fprintf(stderr, "Invalid null value for ground parameter `%s'\n", key); 267 res = RES_BAD_ARG; 268 goto error; 269 } 270 271 #define SET_STR(Dst) { \ 272 if(Dst) mem_rm(Dst); \ 273 if(!((Dst) = str_dup(val))) res = RES_MEM_ERR; \ 274 } (void)0 275 switch(iparam) { 276 case BRDF: SET_STR(args->ground.mtllst_filename); break; 277 case MESH: SET_STR(args->ground.smsh_filename); break; 278 case NAME: SET_STR(args->ground.name); break; 279 case PROP: SET_STR(args->ground.props_filename); break; 280 default: FATAL("Unreachable code\n"); break; 281 } 282 #undef SET_STR 283 if(res != RES_OK) { 284 fprintf(stderr, "Unable to parse the ground parameter `%s' -- %s\n", 285 str, res_to_cstr(res)); 286 goto error; 287 } 288 289 exit: 290 return res; 291 error: 292 goto exit; 293 } 294 295 static res_T 296 parse_gas_parameters(const char* str, void* ptr) 297 { 298 enum { MESH, CK, TEMP } iparam; 299 char buf[BUFSIZ]; 300 struct htrdr_planets_args* args = ptr; 301 char* key; 302 char* val; 303 char* tk_ctx; 304 res_T res = RES_OK; 305 ASSERT(args && str); 306 307 if(strlen(str) >= sizeof(buf) -1/*NULL char*/) { 308 fprintf(stderr, "Could not duplicate the gas parameter `%s'\n", str); 309 res = RES_MEM_ERR; 310 goto error; 311 } 312 strncpy(buf, str, sizeof(buf)); 313 314 key = strtok_r(buf, "=", &tk_ctx); 315 val = strtok_r(NULL, "", &tk_ctx); 316 317 if(!strcmp(key, "mesh")) iparam = MESH; 318 else if(!strcmp(key, "ck")) iparam = CK; 319 else if(!strcmp(key, "temp")) iparam = TEMP; 320 else { 321 fprintf(stderr, "Invalid gas parameter `%s'\n", key); 322 res = RES_BAD_ARG; 323 goto error; 324 } 325 326 if(!val) { 327 fprintf(stderr, "Invalid null value for gas parameter `%s'\n", key); 328 res = RES_BAD_ARG; 329 goto error; 330 } 331 332 #define SET_STR(Dst) { \ 333 if(Dst) mem_rm(Dst); \ 334 if(!((Dst) = str_dup(val))) res = RES_MEM_ERR; \ 335 } (void)0 336 switch(iparam) { 337 case MESH: SET_STR(args->gas.smsh_filename); break; 338 case CK: SET_STR(args->gas.sck_filename); break; 339 case TEMP: SET_STR(args->gas.temperatures_filename); break; 340 default: FATAL("Unreachable code\n"); break; 341 } 342 #undef SET_STR 343 if(res != RES_OK) { 344 fprintf(stderr, "Unable to parse the gas parameter `%s' -- %s\n", 345 str, res_to_cstr(res)); 346 goto error; 347 } 348 349 exit: 350 return res; 351 error: 352 goto exit; 353 } 354 355 static res_T 356 parse_source_parameters(const char* str, void* ptr) 357 { 358 enum {LAT, LON, DST, RADIUS, TEMP, RAD} iparam; 359 char buf[BUFSIZ]; 360 struct htrdr_planets_args* args = ptr; 361 struct htrdr_planets_source_args* src = NULL; 362 char* key; 363 char* val; 364 char* tk_ctx; 365 res_T res = RES_OK; 366 ASSERT(str && ptr); 367 368 src = &args->source; 369 370 if(strlen(str) >= sizeof(buf) -1/*NULL char*/) { 371 fprintf(stderr, "Could not duplicate the source parameter `%s'\n", str); 372 res = RES_MEM_ERR; 373 goto error; 374 } 375 strncpy(buf, str, sizeof(buf)); 376 377 key = strtok_r(buf, "=", &tk_ctx); 378 val = strtok_r(NULL, "", &tk_ctx); 379 380 if(!strcmp(key, "lat")) iparam = LAT; 381 else if(!strcmp(key, "lon")) iparam = LON; 382 else if(!strcmp(key, "dst")) iparam = DST; 383 else if(!strcmp(key, "rad")) iparam = RAD; 384 else if(!strcmp(key, "radius")) iparam = RADIUS; 385 else if(!strcmp(key, "temp")) iparam = TEMP; 386 else { 387 fprintf(stderr, "Invalid source parameter `%s'\n", key); 388 res = RES_BAD_ARG; 389 goto error; 390 } 391 392 if(!val) { 393 fprintf(stderr, "Invalid null value for the source parameter`%s'\n", key); 394 res = RES_BAD_ARG; 395 goto error; 396 } 397 398 switch(iparam) { 399 case LAT: 400 res = cstr_to_double(val, &src->latitude); 401 if(res == RES_OK && (src->latitude < -90 || src->latitude > 90)) { 402 res = RES_BAD_ARG; 403 } 404 break; 405 case LON: 406 res = cstr_to_double(val, &src->longitude); 407 if(res == RES_OK && (src->longitude < -180 || src->longitude > 180)) { 408 res = RES_BAD_ARG; 409 } 410 break; 411 case DST: 412 res = cstr_to_double(val, &src->distance); 413 if(res == RES_OK && src->distance < 0) res = RES_BAD_ARG; 414 break; 415 case RAD: 416 /* Use a per wavelength radiance rather than a constant temperature */ 417 src->temperature = -1; 418 if(src->rnrl_filename) mem_rm(src->rnrl_filename); 419 src->rnrl_filename = str_dup(val); 420 if(!src->rnrl_filename) res = RES_MEM_ERR; 421 break; 422 case RADIUS: 423 res = cstr_to_double(val, &src->radius); 424 if(res == RES_OK && src->radius < 0) res = RES_BAD_ARG; 425 break; 426 case TEMP: 427 /* Use a constant temperature rather than a per wavelength radiance */ 428 if(src->rnrl_filename) { 429 mem_rm(src->rnrl_filename); 430 src->rnrl_filename = NULL; 431 } 432 res = cstr_to_double(val, &src->temperature); 433 if(res == RES_OK && src->temperature < 0) res = RES_BAD_ARG; 434 break; 435 default: FATAL("Unreachable code\n"); break; 436 } 437 if(res != RES_OK) { 438 fprintf(stderr, "Unable to parse the source parameter `%s' -- %s\n", 439 str, res_to_cstr(res)); 440 goto error; 441 } 442 443 exit: 444 return res; 445 error: 446 goto exit; 447 } 448 449 static INLINE res_T 450 parse_spectral_range(const char* str, double wlen_range[2]) 451 { 452 double range[2]; 453 size_t len; 454 res_T res = RES_OK; 455 ASSERT(wlen_range && str); 456 457 res = cstr_to_list_double(str, ',', range, &len, 2); 458 if(res == RES_OK && len != 2) res = RES_BAD_ARG; 459 if(res == RES_OK && range[0] > range[1]) res = RES_BAD_ARG; 460 if(res == RES_OK && (range[0] < 0 || range[1] < 0)) res = RES_BAD_ARG; 461 if(res != RES_OK) goto error; 462 463 wlen_range[0] = range[0]; 464 wlen_range[1] = range[1]; 465 466 exit: 467 return res; 468 error: 469 goto exit; 470 } 471 472 static res_T 473 parse_spectral_parameters(const char* str, void* ptr) 474 { 475 enum {CIE_XYZ, LW, SW} iparam; 476 char buf[BUFSIZ]; 477 struct htrdr_planets_args* args = ptr; 478 struct htrdr_planets_spectral_args* spectral = NULL; 479 char* key; 480 char* val; 481 char* tk_ctx; 482 res_T res = RES_OK; 483 ASSERT(str && ptr); 484 485 spectral = &args->spectral_domain; 486 487 if(strlen(str) >= sizeof(buf) -1/*NULL char*/) { 488 fprintf(stderr, "Could not duplicate the spectral parameter `%s'\n", str); 489 res = RES_MEM_ERR; 490 goto error; 491 } 492 strncpy(buf, str, sizeof(buf)); 493 494 key = strtok_r(buf, "=", &tk_ctx); 495 val = strtok_r(NULL, "", &tk_ctx); 496 497 if(!strcmp(key, "cie_xyz")) iparam = CIE_XYZ; 498 else if(!strcmp(key, "lw")) iparam = LW; 499 else if(!strcmp(key, "sw")) iparam = SW; 500 else { 501 fprintf(stderr, "Invalid spectral parameter `%s'\n", key); 502 res = RES_BAD_ARG; 503 goto error; 504 } 505 506 if((iparam == LW || iparam == SW) && !val) { 507 fprintf(stderr, 508 "Invalid null value for the spectral parameter `%s'\n", key); 509 res = RES_BAD_ARG; 510 goto error; 511 } 512 513 switch(iparam) { 514 case CIE_XYZ: 515 spectral->type = HTRDR_SPECTRAL_SW_CIE_XYZ; 516 spectral->wlen_range[0] = HTRDR_RAN_WLEN_CIE_XYZ_RANGE_DEFAULT[0]; 517 spectral->wlen_range[1] = HTRDR_RAN_WLEN_CIE_XYZ_RANGE_DEFAULT[1]; 518 break; 519 case LW: 520 spectral->type = HTRDR_SPECTRAL_LW; 521 res = parse_spectral_range(val, spectral->wlen_range); 522 break; 523 case SW: 524 spectral->type = HTRDR_SPECTRAL_SW; 525 res = parse_spectral_range(val, spectral->wlen_range); 526 break; 527 default: FATAL("Unreachable code\n"); break; 528 } 529 if(res != RES_OK) { 530 fprintf(stderr, "Unable to parse the spectral parameter `%s' -- %s\n", 531 str, res_to_cstr(res)); 532 goto error; 533 } 534 535 exit: 536 return res; 537 error: 538 goto exit; 539 } 540 541 static res_T 542 parse_volrad_budget_parameters(const char* str, void* ptr) 543 { 544 enum { MESH, SPT } iparam; 545 char buf[BUFSIZ]; 546 struct htrdr_planets_args* args = ptr; 547 char* key; 548 char* val; 549 char* tk_ctx; 550 res_T res = RES_OK; 551 ASSERT(str && ptr); 552 553 if(strlen(str) >= sizeof(buf) -1/*NULL char*/) { 554 fprintf(stderr, 555 "Could not duplicate the parameters " 556 "of the volumic radiative budget calculation `%s'\n", 557 str); 558 res = RES_MEM_ERR; 559 goto error; 560 } 561 strncpy(buf, str, sizeof(buf)); 562 563 key = strtok_r(buf, "=", &tk_ctx); 564 val = strtok_r(NULL, "", &tk_ctx); 565 566 if(!strcmp(key, "mesh")) iparam = MESH; 567 else if(!strcmp(key, "spt")) iparam = SPT; 568 else { 569 fprintf(stderr, "Invalid volumic radiative budget parameter `%s'\n", key); 570 res = RES_BAD_ARG; 571 goto error; 572 } 573 574 if(!val) { 575 fprintf(stderr, 576 "Invalid null value for the volumic radiative budget parameter `%s'.\n", 577 key); 578 res = RES_BAD_ARG; 579 goto error; 580 } 581 582 switch(iparam) { 583 case MESH: 584 if(args->volrad_budget.smsh_filename) { 585 mem_rm(args->volrad_budget.smsh_filename); 586 } 587 if(!(args->volrad_budget.smsh_filename = str_dup(val))) { 588 res = RES_MEM_ERR; 589 } 590 break; 591 case SPT: /* Sample Per Tetrahedron */ 592 res = cstr_to_uint(val, &args->volrad_budget.spt); 593 break; 594 default: FATAL("Unreachable code\n"); break; 595 } 596 if(res != RES_OK) { 597 fprintf(stderr, 598 "Unable to parse the volumic radiative budget parameter `%s' -- %s\n", 599 str, res_to_cstr(res)); 600 goto error; 601 } 602 603 exit: 604 return res; 605 error: 606 goto exit; 607 } 608 609 static res_T 610 parse_accel_struct_build_parameters(const char* str, void* ptr) 611 { 612 enum { DEF, NTHREADS, PROC, STORAGE, OPTIC_THICKNESS} iparam; 613 char buf[BUFSIZ]; 614 struct htrdr_planets_args* args = ptr; 615 char* key; 616 char* val; 617 char* tk_ctx; 618 res_T res = RES_OK; 619 620 ASSERT(str && ptr); 621 622 if(strlen(str) >= sizeof(buf) -1/*NULL char*/) { 623 fprintf(stderr, 624 "Could not duplicate the parameters of the acceleration structures `%s'", 625 str); 626 res = RES_MEM_ERR; 627 goto error; 628 } 629 strncpy(buf, str, sizeof(buf)); 630 631 key = strtok_r(buf, "=", &tk_ctx); 632 val = strtok_r(NULL, "", &tk_ctx); 633 634 if(!strcmp(key, "def")) iparam = DEF; 635 else if(!strcmp(key, "nthreads")) iparam = NTHREADS; 636 else if(!strcmp(key, "proc")) iparam = PROC; 637 else if(!strcmp(key, "storage")) iparam = STORAGE; 638 else if(!strcmp(key, "tau")) iparam = OPTIC_THICKNESS; 639 else { 640 fprintf(stderr, "Invalid acceleration structure parameter `%s'\n", key); 641 res = RES_BAD_ARG; 642 goto error; 643 } 644 645 switch(iparam) { 646 case DEF: 647 res = cstr_to_uint(val, &args->accel_struct.definition_hint); 648 if(res == RES_OK && args->accel_struct.definition_hint == 0) 649 res = RES_BAD_ARG; 650 break; 651 case NTHREADS: 652 res = cstr_to_uint(val, &args->accel_struct.nthreads); 653 if(res == RES_OK && args->accel_struct.nthreads == 0) res = RES_BAD_ARG; 654 break; 655 case PROC: 656 if(!strcmp(val, "all")) { 657 args->accel_struct.master_only = 0; 658 } else if(!strcmp(val, "master")) { 659 args->accel_struct.master_only = 1; 660 } else { 661 res = RES_BAD_ARG; 662 } 663 break; 664 case STORAGE: 665 if(args->accel_struct.storage) mem_rm(args->accel_struct.storage); 666 if(!(args->accel_struct.storage = str_dup(val))) res = RES_MEM_ERR; 667 break; 668 case OPTIC_THICKNESS: 669 res = cstr_to_double(val, &args->accel_struct.optical_thickness); 670 if(res == RES_OK && args->accel_struct.optical_thickness < 0) 671 res = RES_BAD_ARG; 672 break; 673 default: FATAL("Unreachable code\n"); break; 674 } 675 if(res != RES_OK) { 676 fprintf(stderr, 677 "Unable to parse the acceleration structure parameter `%s' -- %s\n", 678 str, res_to_cstr(res)); 679 goto error; 680 } 681 682 exit: 683 return res; 684 error: 685 goto exit; 686 } 687 688 /******************************************************************************* 689 * Local functions 690 ******************************************************************************/ 691 res_T 692 htrdr_planets_args_init(struct htrdr_planets_args* args, int argc, char** argv) 693 { 694 int opt; 695 res_T res = RES_OK; 696 ASSERT(args && argc && argv); 697 698 *args = HTRDR_PLANETS_ARGS_DEFAULT; 699 700 while((opt = getopt(argc, argv, "a:b:C:dfG:g:hi:No:P:r:S:s:t:v")) != -1) { 701 switch(opt) { 702 case 'a': 703 (void)sa_add(args->aerosols, 1); 704 args->aerosols[args->naerosols] = RNATM_AEROSOL_ARGS_NULL; 705 args->naerosols += 1; 706 res = cstr_parse_list(optarg, ':', parse_aerosol_parameters, args); 707 if(res == RES_OK) { 708 res = check_aerosol_args(args->aerosols+args->naerosols-1); 709 } 710 break; 711 case 'b': 712 res = cstr_parse_list(optarg, ':', parse_accel_struct_build_parameters, args); 713 break; 714 case 'C': 715 args->output_type = HTRDR_PLANETS_ARGS_OUTPUT_IMAGE; 716 args->cam_type = HTRDR_ARGS_CAMERA_PERSPECTIVE; 717 res = htrdr_args_camera_perspective_parse(&args->cam_persp, optarg); 718 break; 719 case 'd': 720 args->output_type = HTRDR_PLANETS_ARGS_OUTPUT_OCTREES; 721 break; 722 case 'f': 723 args->force_output_overwrite = 1; 724 break; 725 case 'G': 726 res = cstr_parse_list(optarg, ':', parse_ground_parameters, args); 727 if(res == RES_OK) { 728 res = check_ground_args(&args->ground); 729 } 730 break; 731 case 'g': 732 res = cstr_parse_list(optarg, ':', parse_gas_parameters, args); 733 if(res == RES_OK) { 734 res = check_gas_args(&args->gas); 735 } 736 break; 737 case 'h': 738 usage(); 739 htrdr_planets_args_release(args); 740 args->quit = 1; 741 goto exit; 742 case 'i': 743 res = htrdr_args_image_parse(&args->image, optarg); 744 break; 745 case 'N': args->precompute_normals = 1; break; 746 case 'o': args->output = optarg; break; 747 case 'P': 748 args->output_type = HTRDR_PLANETS_ARGS_OUTPUT_IMAGE; 749 args->cam_type = HTRDR_ARGS_CAMERA_ORTHOGRAPHIC; 750 res = htrdr_args_camera_orthographic_parse(&args->cam_ortho, optarg); 751 break; 752 case 'r': 753 res = cstr_parse_list(optarg, ':', parse_volrad_budget_parameters, args); 754 args->output_type = HTRDR_PLANETS_ARGS_OUTPUT_VOLUMIC_RADIATIVE_BUDGET; 755 break; 756 case 'S': 757 res = cstr_parse_list(optarg, ':', parse_source_parameters, args); 758 break; 759 case 's': 760 res = cstr_parse_list(optarg, ':', parse_spectral_parameters, args); 761 break; 762 case 't': 763 res = cstr_to_uint(optarg, &args->nthreads); 764 if(res == RES_OK && !args->nthreads) res = RES_BAD_ARG; 765 break; 766 case 'v': args->verbose = 1; break; 767 default: res = RES_BAD_ARG; break; 768 } 769 if(res != RES_OK) { 770 if(optarg) { 771 fprintf(stderr, "%s: invalid option argument '%s' -- '%c'\n", 772 argv[0], optarg, opt); 773 } 774 goto error; 775 } 776 } 777 778 res = check_gas_args(&args->gas); 779 if(res != RES_OK) { 780 fprintf(stderr, "missing gas definition -- option '-g'\n"); 781 goto error; 782 } 783 784 if(args->output_type != HTRDR_PLANETS_ARGS_OUTPUT_OCTREES) { 785 res = check_ground_args(&args->ground); 786 if(res != RES_OK) { 787 fprintf(stderr, "missing ground definition -- option '-G'\n"); 788 goto error; 789 } 790 791 /* Check the source */ 792 if(args->spectral_domain.type == HTRDR_SPECTRAL_SW 793 || args->spectral_domain.type == HTRDR_SPECTRAL_SW_CIE_XYZ) { 794 res = htrdr_planets_source_args_check(&args->source); 795 if(res != RES_OK) { 796 fprintf(stderr, "missing source definition -- option '-S'\n"); 797 goto error; 798 } 799 } 800 } 801 802 if(args->output_type == HTRDR_PLANETS_ARGS_OUTPUT_VOLUMIC_RADIATIVE_BUDGET 803 && args->spectral_domain.type != HTRDR_SPECTRAL_LW 804 && args->spectral_domain.type != HTRDR_SPECTRAL_SW) { 805 fprintf(stderr, 806 "volumic radiative budget can be evaluated in " 807 "longwave or shortwave only -- option '-s'\n"); 808 res = RES_BAD_ARG; 809 goto error; 810 } 811 812 exit: 813 return res; 814 error: 815 usage(); 816 htrdr_planets_args_release(args); 817 goto exit; 818 } 819 820 void 821 htrdr_planets_args_release(struct htrdr_planets_args* args) 822 { 823 size_t i; 824 ASSERT(args); 825 826 if(args->gas.smsh_filename) mem_rm(args->gas.smsh_filename); 827 if(args->gas.sck_filename) mem_rm(args->gas.sck_filename); 828 if(args->gas.temperatures_filename) mem_rm(args->gas.temperatures_filename); 829 if(args->ground.smsh_filename) mem_rm(args->ground.smsh_filename); 830 if(args->ground.props_filename) mem_rm(args->ground.props_filename); 831 if(args->ground.mtllst_filename) mem_rm(args->ground.mtllst_filename); 832 if(args->ground.name) mem_rm(args->ground.name); 833 if(args->source.rnrl_filename) mem_rm(args->source.rnrl_filename); 834 if(args->volrad_budget.smsh_filename) mem_rm(args->volrad_budget.smsh_filename); 835 if(args->accel_struct.storage) mem_rm(args->accel_struct.storage); 836 837 FOR_EACH(i, 0, args->naerosols) { 838 struct rnatm_aerosol_args* aerosol = args->aerosols + i; 839 if(aerosol->name) mem_rm(aerosol->name); 840 if(aerosol->smsh_filename) mem_rm(aerosol->smsh_filename); 841 if(aerosol->sars_filename) mem_rm(aerosol->sars_filename); 842 if(aerosol->phase_fn_ids_filename) mem_rm(aerosol->phase_fn_ids_filename); 843 if(aerosol->phase_fn_lst_filename) mem_rm(aerosol->phase_fn_lst_filename); 844 } 845 sa_release(args->aerosols); 846 847 *args = HTRDR_PLANETS_ARGS_DEFAULT; 848 } 849 850 res_T 851 htrdr_planets_args_check(const struct htrdr_planets_args* args) 852 { 853 size_t i; 854 res_T res = RES_OK; 855 856 if(!args) return RES_BAD_ARG; 857 858 /* Check the gas */ 859 res = check_gas_args(&args->gas); 860 if(res != RES_OK) return res; 861 862 /* Check the aerosols */ 863 FOR_EACH(i, 0, args->naerosols) { 864 res = check_aerosol_args(args->aerosols+i); 865 if(res != RES_OK) return res; 866 } 867 868 /* Check the octree parameters */ 869 res = check_accel_struct_build_args(&args->accel_struct); 870 if(res != RES_OK) return res; 871 872 /* Check the spectral domain */ 873 res = check_spectral_args(&args->spectral_domain); 874 if(res != RES_OK) return res; 875 876 if(args->output_type != HTRDR_PLANETS_ARGS_OUTPUT_OCTREES) { 877 /* Check the ground */ 878 res = check_ground_args(&args->ground); 879 if(res != RES_OK) return res; 880 881 /* Check the source */ 882 if(args->spectral_domain.type == HTRDR_SPECTRAL_SW 883 || args->spectral_domain.type == HTRDR_SPECTRAL_SW_CIE_XYZ) { 884 res = htrdr_planets_source_args_check(&args->source); 885 if(res != RES_OK) return res; 886 } 887 } 888 889 if(args->output_type == HTRDR_PLANETS_ARGS_OUTPUT_IMAGE) { 890 res = htrdr_args_camera_perspective_check(&args->cam_persp); 891 if(res != RES_OK) return res; 892 893 res = htrdr_args_image_check(&args->image); 894 if(res != RES_OK) return res; 895 } 896 897 if(args->output_type == HTRDR_PLANETS_ARGS_OUTPUT_VOLUMIC_RADIATIVE_BUDGET) { 898 res = check_volrad_budget_args(&args->volrad_budget); 899 if(res != RES_OK) return res; 900 901 /* The volumic radiative budget can be evaluated 902 * in longwave or shortwave only */ 903 if(args->spectral_domain.type != HTRDR_SPECTRAL_LW 904 && args->spectral_domain.type != HTRDR_SPECTRAL_SW) { 905 return RES_BAD_ARG; 906 } 907 } 908 909 /* Check miscalleneous parameters */ 910 if(args->nthreads == 0 911 || (unsigned)args->output_type >= HTRDR_PLANETS_ARGS_OUTPUT_TYPES_COUNT__) 912 return RES_BAD_ARG; 913 914 return RES_OK; 915 } 916 917 res_T 918 htrdr_planets_source_args_check(const struct htrdr_planets_source_args* args) 919 { 920 if(!args) return RES_BAD_ARG; 921 922 /* Invalid position */ 923 if(args->latitude <-90 924 || args->latitude > 90 925 || args->longitude <-180 926 || args->longitude > 180 927 || args->distance < 0) 928 return RES_BAD_ARG; 929 930 /* Invalid radius */ 931 if(args->radius < 0) 932 return RES_BAD_ARG; 933 934 /* Invalid radiance */ 935 if((args->temperature < 0 && !args->rnrl_filename) /* Both are invalids */ 936 || (args->temperature >=0 && args->rnrl_filename)) /* Both are valids */ 937 return RES_BAD_ARG; 938 939 return RES_OK; 940 }