htgop.c (30706B)
1 /* Copyright (C) 2018-2021, 2023 |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 #define _POSIX_C_SOURCE 200112L /* nextafter support */ 17 18 #include "htgop.h" 19 #include "htgop_c.h" 20 #include "htgop_reader.h" 21 22 #include <rsys/algorithm.h> 23 #include <rsys/cstr.h> 24 #include <rsys/logger.h> 25 #include <rsys/mem_allocator.h> 26 27 #include <math.h> 28 29 /******************************************************************************* 30 * Helper functions 31 ******************************************************************************/ 32 static void 33 log_msg 34 (const struct htgop* htgop, 35 const enum log_type stream, 36 const char* msg, 37 va_list vargs) 38 { 39 ASSERT(htgop && msg); 40 if(htgop->verbose) { 41 res_T res; (void)res; 42 res = logger_vprint(htgop->logger, stream, msg, vargs); 43 ASSERT(res == RES_OK); 44 } 45 } 46 47 static INLINE int 48 cmp_lvl(const void* key, const void* data) 49 { 50 const double height = *((const double*)key); 51 const struct htgop_level* lvl = (const struct htgop_level*)data; 52 return height < lvl->height ? -1 : (height > lvl->height ? 1 : 0); 53 } 54 55 static res_T 56 parse_spectral_intervals 57 (struct htgop* htgop, 58 struct reader* rdr, 59 const unsigned long nspecints, 60 struct spectral_intervals* specints) 61 { 62 unsigned long ispecint; 63 double* wave_numbers = NULL; 64 struct darray_double* pdfs = NULL; 65 struct darray_double* cdfs = NULL; 66 res_T res = RES_OK; 67 (void)htgop; 68 ASSERT(htgop && rdr && nspecints && specints); 69 70 #define CALL(Func) { if((res = Func) != RES_OK) goto error; } (void)0 71 72 /* Allocate the memory space for the wave numbers and the quadratures */ 73 CALL(darray_double_resize(&specints->wave_numbers, nspecints + 1)); 74 CALL(darray_dbllst_resize(&specints->quadrature_pdfs, nspecints)); 75 CALL(darray_dbllst_resize(&specints->quadrature_cdfs, nspecints)); 76 wave_numbers = darray_double_data_get(&specints->wave_numbers); 77 pdfs = darray_dbllst_data_get(&specints->quadrature_pdfs); 78 cdfs = darray_dbllst_data_get(&specints->quadrature_cdfs); 79 80 FOR_EACH(ispecint, 0, nspecints) { 81 double* pdf = NULL; 82 double* cdf = NULL; 83 double wave_number_low; 84 double wave_number_upp; 85 double sum = 0; 86 unsigned long quad_len; 87 unsigned long iquad; 88 89 /* Parse the interval bounds */ 90 CALL(cstr_to_double(read_line(rdr), &wave_number_low)); 91 CALL(cstr_to_double(read_line(rdr), &wave_number_upp)); 92 93 /* Check and register the interval bounds */ 94 if(wave_number_low >= wave_number_upp) { 95 res = RES_BAD_ARG; 96 goto error; 97 } 98 if(ispecint == 0) { 99 wave_numbers[ispecint] = wave_number_low; 100 } else if(wave_number_low != wave_numbers[ispecint]) { 101 res = RES_BAD_ARG; 102 goto error; 103 } 104 wave_numbers[ispecint + 1] = wave_number_upp; 105 106 /* Parse and allocate the quadrature length */ 107 CALL(cstr_to_ulong(read_line(rdr), &quad_len)); 108 109 /* Allocate the points of the quadrature */ 110 CALL(darray_double_resize(&pdfs[ispecint], quad_len)); 111 CALL(darray_double_resize(&cdfs[ispecint], quad_len)); 112 pdf = darray_double_data_get(&pdfs[ispecint]); 113 cdf = darray_double_data_get(&cdfs[ispecint]); 114 115 /* Read the weight of the quadrature points */ 116 sum = 0; 117 FOR_EACH(iquad, 0, quad_len) { 118 CALL(cstr_to_double(read_line(rdr), &pdf[iquad])); 119 cdf[iquad] = iquad == 0 ? pdf[iquad] : pdf[iquad]+cdf[iquad-1]; 120 sum += pdf[iquad]; 121 } 122 ASSERT(eq_eps(sum, 1.0, 1.e6)); 123 ASSERT(eq_eps(cdf[quad_len-1], 1.0, 1.e6)); 124 cdf[quad_len-1] = 1.0; /* Handle numerical imprecision */ 125 } 126 127 #undef CALL 128 129 exit: 130 return res; 131 error: 132 darray_double_clear(&specints->wave_numbers); 133 darray_dbllst_clear(&specints->quadrature_pdfs); 134 darray_dbllst_clear(&specints->quadrature_cdfs); 135 goto exit; 136 } 137 138 /* Generate the parse_layers_spectral_intervals_ka_lw function */ 139 #define DOMAIN lw 140 #define DATA ka 141 #include "htgop_parse_layers_spectral_intervals_data.h" 142 /* Generate the parse_layers_spectral_intervals_ka_sw function */ 143 #define DOMAIN sw 144 #define DATA ka 145 #include "htgop_parse_layers_spectral_intervals_data.h" 146 /* Generate the parse_layers_spectral_intervals_ks_sw function */ 147 #define DOMAIN sw 148 #define DATA ks 149 #include "htgop_parse_layers_spectral_intervals_data.h" 150 151 static res_T 152 parse_layers_spectral_intervals(struct htgop* htgop, struct reader* rdr) 153 { 154 struct layer* layers = NULL; 155 size_t lw_nspecints, sw_nspecints, nlays; 156 size_t ilay; 157 res_T res = RES_OK; 158 ASSERT(htgop && rdr); 159 160 layers = darray_layer_data_get(&htgop->layers); 161 nlays = darray_layer_size_get(&htgop->layers); 162 ASSERT(nlays > 0); 163 lw_nspecints = darray_double_size_get(&htgop->lw_specints.wave_numbers) - 1; 164 sw_nspecints = darray_double_size_get(&htgop->sw_specints.wave_numbers) - 1; 165 ASSERT(lw_nspecints > 0 && sw_nspecints); 166 167 #define CALL(Func) { if((res = Func) != RES_OK) goto error; } (void)0 168 /* Allocate the per layer spectral intervals */ 169 FOR_EACH(ilay, 0, nlays) { 170 CALL(darray_lay_lw_specint_resize(&layers[ilay].lw_specints, lw_nspecints)); 171 CALL(darray_lay_sw_specint_resize(&layers[ilay].sw_specints, sw_nspecints)); 172 } 173 /* Parse the spectral data of the layers */ 174 CALL(parse_layers_spectral_intervals_ka_lw(htgop, rdr)); 175 CALL(parse_layers_spectral_intervals_ka_sw(htgop, rdr)); 176 CALL(parse_layers_spectral_intervals_ks_sw(htgop, rdr)); 177 #undef CALL 178 179 exit: 180 return res; 181 error: 182 FOR_EACH(ilay, 0, nlays) { 183 darray_lay_lw_specint_clear(&layers[ilay].lw_specints); 184 darray_lay_sw_specint_clear(&layers[ilay].sw_specints); 185 } 186 goto exit; 187 } 188 189 static res_T 190 load_stream(struct htgop* htgop, FILE* stream, const char* stream_name) 191 { 192 struct reader rdr; 193 struct htgop_level* levels = NULL; 194 struct layer* layers = NULL; 195 unsigned long nlvls, nlays, tab_len, nspecints_lw, nspecints_sw; 196 unsigned long ilvl, ilay, itab; 197 unsigned long iline_saved; 198 res_T res = RES_OK; 199 ASSERT(htgop && stream && stream_name); 200 reader_init(&rdr, stream, stream_name); 201 202 #define CALL(Func) { \ 203 if((res = Func) != RES_OK) { \ 204 log_err(htgop, "%s:%lu: Parsing error.\n", rdr.name, rdr.iline); \ 205 goto error; \ 206 } \ 207 } (void)0 208 209 /* Parse the number of levels/layers */ 210 CALL(cstr_to_ulong(read_line(&rdr), &nlvls)); 211 iline_saved = rdr.iline; 212 CALL(cstr_to_ulong(read_line(&rdr), &nlays)); 213 if(!nlays) { 214 log_err(htgop, "%s:%lu: The number of layers cannot be null.\n", 215 rdr.name, rdr.iline); 216 res = RES_BAD_ARG; 217 goto error; 218 } 219 if(nlvls != nlays + 1) { 220 log_err(htgop, 221 "%s:%lu: Invalid number of levels `%lu' (#layers = `%lu').\n", 222 rdr.name, iline_saved, nlvls, nlays); 223 res = RES_BAD_ARG; 224 goto error; 225 } 226 227 /* Parse the ground temperature */ 228 CALL(cstr_to_double(read_line(&rdr), &htgop->ground.temperature)); 229 230 /* Allocate the per level data */ 231 CALL(darray_level_resize(&htgop->levels, nlvls)); 232 CALL(darray_layer_resize(&htgop->layers, nlays)); 233 levels = darray_level_data_get(&htgop->levels); 234 layers = darray_layer_data_get(&htgop->layers); 235 236 /* Per level data */ 237 FOR_EACH(ilvl, 0, nlvls) { /* Pressure */ 238 CALL(cstr_to_double(read_line(&rdr), &levels[ilvl].pressure)); 239 } 240 FOR_EACH(ilvl, 0, nlvls) { /* Temperature */ 241 CALL(cstr_to_double(read_line(&rdr), &levels[ilvl].temperature)); 242 } 243 FOR_EACH(ilvl, 0, nlvls) { /* Height */ 244 CALL(cstr_to_double(read_line(&rdr), &levels[ilvl].height)); 245 if(ilvl && levels[ilvl].height <= levels[ilvl-1].height) { 246 log_err(htgop, 247 "%s:%lu: The levels must be sorted in strict ascending order " 248 "wrt their height.\n", rdr.name, rdr.iline); 249 res = RES_BAD_ARG; 250 goto error; 251 } 252 } 253 254 /* Per layer x H2O nominal */ 255 FOR_EACH(ilay, 0, nlays) { 256 CALL(cstr_to_double(read_line(&rdr), &layers[ilay].x_h2o_nominal)); 257 } 258 259 /* Parse the length of the tabulation */ 260 CALL(cstr_to_ulong(read_line(&rdr), &tab_len)); 261 if(!tab_len) { 262 log_err(htgop, 263 "%s:%lu: The tabulation length cannot be null.\n", rdr.name, rdr.iline); 264 res = RES_BAD_ARG; 265 goto error; 266 } 267 268 /* Allocate the tabulated xH2O of each layer */ 269 FOR_EACH(ilay, 0, nlays) { 270 CALL(darray_double_resize(&layers[ilay].x_h2o_tab, tab_len)); 271 } 272 273 /* Parse the tabulated xH2O of each layer */ 274 FOR_EACH(itab, 0, tab_len) { 275 FOR_EACH(ilay, 0, nlays) { 276 double* x_h2o_tab = darray_double_data_get(&layers[ilay].x_h2o_tab); 277 CALL(cstr_to_double(read_line(&rdr), &x_h2o_tab[itab])); 278 if(x_h2o_tab[itab] < 0) { 279 log_err(htgop, 280 "%s:%lu: the tabulated water vapor molar fractions must be in [0, 1].\n", 281 rdr.name, rdr.iline); 282 res = RES_BAD_ARG; 283 goto error; 284 } 285 if(itab && x_h2o_tab[itab] < x_h2o_tab[itab-1]) { 286 log_err(htgop, 287 "%s:%lu: the tabulated water vapor molar fractions must be sorted in " 288 "strict ascending order.\n", rdr.name, rdr.iline); 289 res = RES_BAD_ARG; 290 goto error; 291 } 292 if(itab == tab_len-1 && x_h2o_tab[itab] != 1) { 293 log_err(htgop, 294 "%s:%lu: the tabulated water vapor molar fractions is not normalized.\n", 295 rdr.name, rdr.iline); 296 res = RES_BAD_ARG; 297 goto error; 298 } 299 } 300 } 301 302 /* Parse the long/short wave emissivity of the hround */ 303 CALL(cstr_to_double(read_line(&rdr), &htgop->ground.lw_emissivity)); 304 CALL(cstr_to_double(read_line(&rdr), &htgop->ground.sw_emissivity)); 305 306 /* Parse the number of long/short wave spectral intervals */ 307 CALL(cstr_to_ulong(read_line(&rdr), &nspecints_lw)); 308 CALL(cstr_to_ulong(read_line(&rdr), &nspecints_sw)); 309 310 /* Parse the data of the long/short wave spectral intervals */ 311 CALL(parse_spectral_intervals(htgop, &rdr, nspecints_lw, &htgop->lw_specints)); 312 CALL(parse_spectral_intervals(htgop, &rdr, nspecints_sw, &htgop->sw_specints)); 313 314 /* Parse the spectral data of the layers */ 315 CALL(parse_layers_spectral_intervals(htgop, &rdr)); 316 317 #undef CALL 318 319 exit: 320 reader_release(&rdr); 321 return res; 322 error: 323 goto exit; 324 } 325 326 static void 327 release_htgop(ref_T* ref) 328 { 329 struct htgop* htgop; 330 ASSERT(ref); 331 htgop = CONTAINER_OF(ref, struct htgop, ref); 332 spectral_intervals_release(&htgop->lw_specints); 333 spectral_intervals_release(&htgop->sw_specints); 334 darray_double_release(&htgop->sw_X_cdf); 335 darray_double_release(&htgop->sw_Y_cdf); 336 darray_double_release(&htgop->sw_Z_cdf); 337 darray_level_release(&htgop->levels); 338 darray_layer_release(&htgop->layers); 339 MEM_RM(htgop->allocator, htgop); 340 } 341 342 /******************************************************************************* 343 * Exported functions 344 ******************************************************************************/ 345 res_T 346 htgop_create 347 (struct logger* log, 348 struct mem_allocator* mem_allocator, 349 const int verbose, 350 struct htgop** out_htgop) 351 { 352 struct mem_allocator* allocator = NULL; 353 struct logger* logger = NULL; 354 struct htgop* htgop = NULL; 355 res_T res = RES_OK; 356 357 if(!out_htgop) { 358 res = RES_BAD_ARG; 359 goto error; 360 } 361 362 allocator = mem_allocator ? mem_allocator : &mem_default_allocator; 363 logger = log ? log : LOGGER_DEFAULT; 364 365 htgop = MEM_CALLOC(allocator, 1, sizeof(struct htgop)); 366 if(!htgop) { 367 if(verbose) { 368 logger_print(logger, LOG_ERROR, 369 "Could not allocate the HTGOP handler.\n"); 370 } 371 res = RES_MEM_ERR; 372 goto error; 373 } 374 375 ref_init(&htgop->ref); 376 htgop->allocator = allocator; 377 htgop->logger = logger; 378 htgop->verbose = verbose; 379 spectral_intervals_init(allocator, &htgop->lw_specints); 380 spectral_intervals_init(allocator, &htgop->sw_specints); 381 darray_double_init(allocator, &htgop->sw_X_cdf); 382 darray_double_init(allocator, &htgop->sw_Y_cdf); 383 darray_double_init(allocator, &htgop->sw_Z_cdf); 384 darray_level_init(allocator, &htgop->levels); 385 darray_layer_init(allocator, &htgop->layers); 386 387 exit: 388 if(out_htgop) *out_htgop = htgop; 389 return res; 390 error: 391 if(htgop) { 392 HTGOP(ref_put(htgop)); 393 htgop = NULL; 394 } 395 goto exit; 396 } 397 398 res_T 399 htgop_ref_get(struct htgop* htgop) 400 { 401 if(!htgop) return RES_BAD_ARG; 402 ref_get(&htgop->ref); 403 return RES_OK; 404 } 405 406 res_T 407 htgop_ref_put(struct htgop* htgop) 408 { 409 if(!htgop) return RES_BAD_ARG; 410 ref_put(&htgop->ref, release_htgop); 411 return RES_OK; 412 } 413 414 res_T 415 htgop_load(struct htgop* htgop, const char* filename) 416 { 417 FILE* file = NULL; 418 res_T res = RES_OK; 419 420 if(!htgop || !filename) { 421 res = RES_BAD_ARG; 422 goto error; 423 } 424 425 file = fopen(filename, "r"); 426 if(!file) { 427 log_err(htgop, "%s: error opening file `%s'.\n", FUNC_NAME, filename); 428 res = RES_IO_ERR; 429 goto error; 430 } 431 432 res = load_stream(htgop, file, filename); 433 if(res != RES_OK) goto error; 434 435 exit: 436 if(file) fclose(file); 437 return res; 438 error: 439 goto exit; 440 } 441 442 res_T 443 htgop_load_stream(struct htgop* htgop, FILE* stream) 444 { 445 if(!htgop || !stream) return RES_BAD_ARG; 446 return load_stream(htgop, stream, "<stream>"); 447 } 448 449 res_T 450 htgop_get_ground(const struct htgop* htgop, struct htgop_ground* ground) 451 { 452 if(!htgop || !ground) return RES_BAD_ARG; 453 *ground = htgop->ground; 454 return RES_OK; 455 } 456 457 res_T 458 htgop_get_layers_count(const struct htgop* htgop, size_t* nlayers) 459 { 460 if(!htgop || !nlayers) return RES_BAD_ARG; 461 *nlayers = darray_layer_size_get(&htgop->layers); 462 return RES_OK; 463 } 464 465 res_T 466 htgop_get_levels_count(const struct htgop* htgop, size_t* nlevels) 467 { 468 if(!htgop || !nlevels) return RES_BAD_ARG; 469 *nlevels = darray_level_size_get(&htgop->levels); 470 return RES_OK; 471 } 472 473 res_T 474 htgop_get_level 475 (const struct htgop* htgop, const size_t ilvl, struct htgop_level* lvl) 476 { 477 size_t n; 478 if(!htgop || !lvl) return RES_BAD_ARG; 479 HTGOP(get_levels_count(htgop, &n)); 480 if(ilvl >= n) { 481 log_err(htgop, "%s: invalid level `%lu'.\n", FUNC_NAME, ilvl); 482 return RES_BAD_ARG; 483 } 484 *lvl = darray_level_cdata_get(&htgop->levels)[ilvl]; 485 return RES_OK; 486 } 487 488 res_T 489 htgop_get_layer 490 (const struct htgop* htgop, 491 const size_t ilayer, 492 struct htgop_layer* layer) 493 { 494 const struct layer* l; 495 size_t n; 496 if(!htgop || !layer) return RES_BAD_ARG; 497 HTGOP(get_layers_count(htgop, &n)); 498 if(ilayer >= n) { 499 log_err(htgop, "%s: invalid layer `%lu'.\n", 500 FUNC_NAME, (unsigned long)ilayer); 501 return RES_BAD_ARG; 502 } 503 l = darray_layer_cdata_get(&htgop->layers) + ilayer; 504 layer->x_h2o_nominal = l->x_h2o_nominal; 505 layer->x_h2o_tab = darray_double_cdata_get(&l->x_h2o_tab); 506 layer->tab_length = darray_double_size_get(&l->x_h2o_tab); 507 layer->lw_spectral_intervals_count = 508 darray_lay_lw_specint_size_get(&l->lw_specints); 509 layer->sw_spectral_intervals_count = 510 darray_lay_sw_specint_size_get(&l->sw_specints); 511 layer->data__ = l; 512 layer->htgop = htgop; 513 return RES_OK; 514 } 515 516 res_T 517 htgop_layer_get_lw_spectral_interval 518 (const struct htgop_layer* layer, 519 const size_t ispecint, 520 struct htgop_layer_lw_spectral_interval* specint) 521 { 522 const struct layer* l; 523 const struct layer_lw_spectral_interval* lspecint; 524 if(!layer || !specint) return RES_BAD_ARG; 525 if(ispecint >= layer->lw_spectral_intervals_count) { 526 log_err(layer->htgop, "%s: invalid spectral interval `%lu'.\n", 527 FUNC_NAME, (unsigned long)ispecint); 528 return RES_BAD_ARG; 529 } 530 l = layer->data__; 531 lspecint = darray_lay_lw_specint_cdata_get(&l->lw_specints) + ispecint; 532 specint->ka_nominal = darray_double_cdata_get(&lspecint->ka_nominal); 533 specint->quadrature_length = darray_double_size_get(&lspecint->ka_nominal); 534 specint->htgop = layer->htgop; 535 specint->data__ = lspecint; 536 specint->layer__ = l; 537 return RES_OK; 538 } 539 540 res_T 541 htgop_layer_get_sw_spectral_interval 542 (const struct htgop_layer* layer, 543 const size_t ispecint, 544 struct htgop_layer_sw_spectral_interval* specint) 545 { 546 const struct layer* l; 547 const struct layer_sw_spectral_interval* lspecint; 548 if(!layer || !specint) return RES_BAD_ARG; 549 if(ispecint >= layer->sw_spectral_intervals_count) { 550 log_err(layer->htgop, "%s: invalid spectral interval `%lu'.\n", 551 FUNC_NAME, (unsigned long)ispecint); 552 return RES_BAD_ARG; 553 } 554 l = layer->data__; 555 lspecint = darray_lay_sw_specint_cdata_get(&l->sw_specints) + ispecint; 556 specint->ka_nominal = darray_double_cdata_get(&lspecint->ka_nominal); 557 specint->ks_nominal = darray_double_cdata_get(&lspecint->ks_nominal); 558 specint->quadrature_length = darray_double_size_get(&lspecint->ka_nominal); 559 specint->htgop = layer->htgop; 560 specint->data__ = lspecint; 561 specint->layer__ = l; 562 return RES_OK; 563 } 564 565 res_T 566 htgop_layer_lw_spectral_interval_get_tab 567 (const struct htgop_layer_lw_spectral_interval* specint, 568 const size_t iquad, 569 struct htgop_layer_lw_spectral_interval_tab* tab) 570 { 571 const struct layer_lw_spectral_interval* lspecint; 572 const struct layer* l; 573 const struct darray_double* t; 574 if(!specint || !tab) return RES_BAD_ARG; 575 if(iquad >= specint->quadrature_length) { 576 log_err(specint->htgop, "%s: invalid quadrature point `%lu'.\n", 577 FUNC_NAME, (unsigned long)iquad); 578 return RES_BAD_ARG; 579 } 580 lspecint = specint->data__; 581 l = specint->layer__; 582 t = darray_dbllst_cdata_get(&lspecint->ka_tab) + iquad; 583 tab->x_h2o_tab = darray_double_cdata_get(&l->x_h2o_tab); 584 tab->ka_tab = darray_double_cdata_get(t); 585 tab->tab_length = darray_double_size_get(t); 586 tab->htgop = specint->htgop; 587 return RES_OK; 588 } 589 590 res_T 591 htgop_layer_sw_spectral_interval_get_tab 592 (const struct htgop_layer_sw_spectral_interval* specint, 593 const size_t iquad, 594 struct htgop_layer_sw_spectral_interval_tab* tab) 595 { 596 const struct layer_sw_spectral_interval* lspecint; 597 const struct layer* l; 598 const struct darray_double* ka_tab; 599 const struct darray_double* ks_tab; 600 if(!specint || !tab) return RES_BAD_ARG; 601 if(iquad >= specint->quadrature_length) { 602 log_err(specint->htgop, "%s: invalid quadrature point `%lu'.\n", 603 FUNC_NAME, (unsigned long)iquad); 604 return RES_BAD_ARG; 605 } 606 lspecint = specint->data__; 607 l = specint->layer__; 608 609 ka_tab = darray_dbllst_cdata_get(&lspecint->ka_tab) + iquad; 610 ks_tab = darray_dbllst_cdata_get(&lspecint->ks_tab) + iquad; 611 tab->x_h2o_tab = darray_double_cdata_get(&l->x_h2o_tab); 612 tab->ka_tab = darray_double_cdata_get(ka_tab); 613 tab->ks_tab = darray_double_cdata_get(ks_tab); 614 tab->tab_length = darray_double_size_get(ka_tab); 615 tab->htgop = specint->htgop; 616 return RES_OK; 617 } 618 619 res_T 620 htgop_get_lw_spectral_intervals_count(const struct htgop* htgop, size_t* nspecints) 621 { 622 if(!htgop || !nspecints) return RES_BAD_ARG; 623 *nspecints = darray_dbllst_size_get(&htgop->lw_specints.quadrature_pdfs); 624 return RES_OK; 625 } 626 627 res_T 628 htgop_get_sw_spectral_intervals_count(const struct htgop* htgop, size_t* nspecints) 629 { 630 if(!htgop || !nspecints) return RES_BAD_ARG; 631 *nspecints = darray_dbllst_size_get(&htgop->sw_specints.quadrature_pdfs); 632 return RES_OK; 633 } 634 635 res_T 636 htgop_get_lw_spectral_intervals_wave_numbers 637 (const struct htgop* htgop, const double* wave_numbers[]) 638 { 639 if(!htgop || !wave_numbers) return RES_BAD_ARG; 640 *wave_numbers = darray_double_cdata_get(&htgop->lw_specints.wave_numbers); 641 return RES_OK; 642 } 643 644 res_T 645 htgop_get_sw_spectral_intervals_wave_numbers 646 (const struct htgop* htgop, const double* wave_numbers[]) 647 { 648 if(!htgop || !wave_numbers) return RES_BAD_ARG; 649 *wave_numbers = darray_double_cdata_get(&htgop->sw_specints.wave_numbers); 650 return RES_OK; 651 } 652 653 res_T 654 htgop_get_lw_spectral_interval 655 (const struct htgop* htgop, 656 const size_t ispecint, 657 struct htgop_spectral_interval* interval) 658 { 659 const double* wave_numbers; 660 const struct darray_double* quad_cdfs; 661 const struct darray_double* quad_pdfs; 662 size_t n; 663 if(!htgop || !interval) return RES_BAD_ARG; 664 HTGOP(get_lw_spectral_intervals_count(htgop, &n)); 665 if(ispecint >= n) { 666 log_err(htgop, "%s: invalid long wave spectral interval `%lu'.\n", 667 FUNC_NAME, (unsigned long)ispecint); 668 return RES_BAD_ARG; 669 } 670 wave_numbers = darray_double_cdata_get(&htgop->lw_specints.wave_numbers); 671 quad_pdfs = darray_dbllst_cdata_get(&htgop->lw_specints.quadrature_pdfs); 672 quad_cdfs = darray_dbllst_cdata_get(&htgop->lw_specints.quadrature_cdfs); 673 interval->wave_numbers[0] = wave_numbers[ispecint+0]; 674 interval->wave_numbers[1] = wave_numbers[ispecint+1]; 675 interval->quadrature_pdf = darray_double_cdata_get(&quad_pdfs[ispecint]); 676 interval->quadrature_cdf = darray_double_cdata_get(&quad_cdfs[ispecint]); 677 interval->quadrature_length = darray_double_size_get(&quad_pdfs[ispecint]); 678 interval->htgop = htgop; 679 return RES_OK; 680 } 681 682 res_T 683 htgop_get_sw_spectral_interval 684 (const struct htgop* htgop, 685 const size_t ispecint, 686 struct htgop_spectral_interval* interval) 687 { 688 const double* wave_numbers; 689 const struct darray_double* quad_pdfs; 690 const struct darray_double* quad_cdfs; 691 size_t n; 692 if(!htgop || !interval) return RES_BAD_ARG; 693 HTGOP(get_sw_spectral_intervals_count(htgop, &n)); 694 if(ispecint >= n) { 695 log_err(htgop, "%s: invalid short wave spectral interval `%lu'.\n", 696 FUNC_NAME, (unsigned long)ispecint); 697 return RES_BAD_ARG; 698 } 699 wave_numbers = darray_double_cdata_get(&htgop->sw_specints.wave_numbers); 700 quad_pdfs = darray_dbllst_cdata_get(&htgop->sw_specints.quadrature_pdfs); 701 quad_cdfs = darray_dbllst_cdata_get(&htgop->sw_specints.quadrature_cdfs); 702 interval->wave_numbers[0] = wave_numbers[ispecint+0]; 703 interval->wave_numbers[1] = wave_numbers[ispecint+1]; 704 interval->quadrature_pdf = darray_double_cdata_get(&quad_pdfs[ispecint]); 705 interval->quadrature_cdf = darray_double_cdata_get(&quad_cdfs[ispecint]); 706 interval->quadrature_length = darray_double_size_get(&quad_pdfs[ispecint]); 707 interval->htgop = htgop; 708 return RES_OK; 709 } 710 711 res_T 712 htgop_find_lw_spectral_interval_id 713 (const struct htgop* htgop, 714 const double wnum, 715 size_t* ispecint) 716 { 717 const double* find = NULL; 718 const double* wnums = NULL; 719 size_t nwnums = 0; 720 if(!htgop || !ispecint) return RES_BAD_ARG; 721 722 wnums = darray_double_cdata_get(&htgop->lw_specints.wave_numbers); 723 nwnums = darray_double_size_get(&htgop->lw_specints.wave_numbers); 724 725 find = search_lower_bound(&wnum, wnums, nwnums, sizeof(*wnums), cmp_dbl); 726 if(!find || find == wnums) { 727 log_warn(htgop, "%s: the wavenumber `%g' is not included in any band.\n", 728 FUNC_NAME, wnum); 729 *ispecint = SIZE_MAX; 730 } else { 731 *ispecint = (size_t)(find - wnums - 1); 732 #ifndef NDEBUG 733 { 734 size_t n; 735 HTGOP(get_lw_spectral_intervals_count(htgop, &n)); 736 ASSERT(*ispecint < n); 737 } 738 #endif 739 } 740 return RES_OK; 741 } 742 743 res_T 744 htgop_find_sw_spectral_interval_id 745 (const struct htgop* htgop, 746 const double wnum, 747 size_t* ispecint) 748 { 749 const double* find = NULL; 750 const double* wnums = NULL; 751 size_t nwnums = 0; 752 if(!htgop || !ispecint) return RES_BAD_ARG; 753 754 wnums = darray_double_cdata_get(&htgop->sw_specints.wave_numbers); 755 nwnums = darray_double_size_get(&htgop->sw_specints.wave_numbers); 756 757 find = search_lower_bound(&wnum, wnums, nwnums, sizeof(*wnums), cmp_dbl); 758 if(!find || find == wnums) { 759 log_warn(htgop, "%s: the wavenumber `%g' is not included in any band.\n", 760 FUNC_NAME, wnum); 761 *ispecint = SIZE_MAX; 762 } else { 763 *ispecint = (size_t)(find - wnums - 1); 764 #ifndef NDEBUG 765 { 766 size_t n; 767 HTGOP(get_sw_spectral_intervals_count(htgop, &n)); 768 ASSERT(*ispecint < n); 769 } 770 #endif 771 772 } 773 return RES_OK; 774 } 775 776 res_T 777 htgop_spectral_interval_sample_quadrature 778 (const struct htgop_spectral_interval* specint, 779 const double r, /* Canonical number in [0, 1[ */ 780 size_t* iquad_point) /* Id of the sample quadrature point */ 781 { 782 double r_next = nextafter(r, DBL_MAX); 783 double* find; 784 size_t i; 785 786 if(!specint || !iquad_point) return RES_BAD_ARG; 787 788 if(r < 0 || r >= 1) { 789 log_err(specint->htgop, 790 "%s: invalid canonical random number `%g'.\n", FUNC_NAME, r); 791 return RES_BAD_ARG; 792 } 793 794 /* Use r_next rather than r in order to find the first entry that is not less 795 * than *or equal* to r */ 796 find = search_lower_bound(&r_next, specint->quadrature_cdf, 797 specint->quadrature_length, sizeof(double), cmp_dbl); 798 ASSERT(find); 799 i = (size_t)(find - specint->quadrature_cdf); 800 ASSERT(i < specint->quadrature_length); 801 ASSERT(specint->quadrature_cdf[i] > r); 802 ASSERT(!i || specint->quadrature_cdf[i-1] <= r); 803 *iquad_point = i; 804 return RES_OK; 805 } 806 807 res_T 808 htgop_position_to_layer_id 809 (const struct htgop* htgop, const double pos, size_t* ilayer) 810 { 811 const struct htgop_level* lvls; 812 size_t nlvls; 813 814 if(!htgop || !ilayer) return RES_BAD_ARG; 815 816 lvls = darray_level_cdata_get(&htgop->levels); 817 nlvls = darray_level_size_get(&htgop->levels); 818 ASSERT(nlvls); 819 820 if(pos == lvls[0].height) { 821 *ilayer = 0; 822 } else if(pos == lvls[nlvls-1].height) { 823 *ilayer = nlvls - 2; 824 } else { 825 const struct htgop_level* find; 826 size_t i; 827 828 find = search_lower_bound(&pos, lvls, nlvls, sizeof(*lvls), cmp_lvl); 829 if(!find || find == lvls) { 830 log_err(htgop, "%s: the position `%g' is outside the atmospheric slices.\n", 831 FUNC_NAME, pos); 832 return RES_BAD_ARG; 833 } 834 835 i = (size_t)(find - lvls); 836 ASSERT(i < nlvls && i > 0); 837 ASSERT(lvls[i].height > pos && (!i || lvls[i-1].height <= pos)); 838 *ilayer = i - 1; 839 } 840 return RES_OK; 841 } 842 843 res_T 844 htgop_get_sw_spectral_intervals 845 (const struct htgop* htgop, 846 const double wnum_range[2], 847 size_t specint_range[2]) 848 { 849 const double* wnums = NULL; 850 size_t nwnums = 0; 851 res_T res = RES_OK; 852 853 if(!htgop || !wnum_range || wnum_range[0]>wnum_range[1] || !specint_range) { 854 res = RES_BAD_ARG; 855 goto error; 856 } 857 858 wnums = darray_double_cdata_get(&htgop->sw_specints.wave_numbers); 859 nwnums = darray_double_size_get(&htgop->sw_specints.wave_numbers); 860 861 res = get_spectral_intervals 862 (htgop, FUNC_NAME, wnum_range, wnums, nwnums, specint_range); 863 if(res != RES_OK) goto error; 864 865 exit: 866 return res; 867 error: 868 goto exit; 869 } 870 871 res_T 872 htgop_get_lw_spectral_intervals 873 (const struct htgop* htgop, 874 const double wnum_range[2], 875 size_t specint_range[2]) 876 { 877 const double* wnums = NULL; 878 size_t nwnums = 0; 879 res_T res = RES_OK; 880 881 if(!htgop || !wnum_range || wnum_range[0]>wnum_range[1] || !specint_range) { 882 res = RES_BAD_ARG; 883 goto error; 884 } 885 886 wnums = darray_double_cdata_get(&htgop->lw_specints.wave_numbers); 887 nwnums = darray_double_size_get(&htgop->lw_specints.wave_numbers); 888 889 res = get_spectral_intervals 890 (htgop, FUNC_NAME, wnum_range, wnums, nwnums, specint_range); 891 if(res != RES_OK) goto error; 892 893 exit: 894 return res; 895 error: 896 goto exit; 897 } 898 899 /* Generate the htgop_layer_fetch_lw_ka function */ 900 #define DOMAIN lw 901 #define DATA ka 902 #include "htgop_fetch_radiative_properties.h" 903 904 /* Generate the htgop_layer_fetch_sw_ka function */ 905 #define DOMAIN sw 906 #define DATA ka 907 #include "htgop_fetch_radiative_properties.h" 908 909 /* Generate the htgop_layer_fetch_sw_ks function */ 910 #define DOMAIN sw 911 #define DATA ks 912 #include "htgop_fetch_radiative_properties.h" 913 914 /* Generate the htgop_layer_get_sw_kext function */ 915 #define GET_DATA(Tab, Id) ((Tab)->ka_tab[Id] + (Tab)->ks_tab[Id]) 916 #define DOMAIN sw 917 #define DATA kext 918 #include "htgop_fetch_radiative_properties.h" 919 920 /* Generate the functions that get the boundaries of ka in LW */ 921 #define DOMAIN lw 922 #define DATA ka 923 #include "htgop_get_radiative_properties_bounds.h" 924 925 /* Generate the functions that get the boundaries of ka in SW */ 926 #define DOMAIN sw 927 #define DATA ka 928 #include "htgop_get_radiative_properties_bounds.h" 929 930 /* Generate the functions that get the boundaries of ks in SW */ 931 #define DOMAIN sw 932 #define DATA ks 933 #include "htgop_get_radiative_properties_bounds.h" 934 935 /* Generate the functions that get the boundaries of kext in SW */ 936 #define GET_DATA(Tab, Id) ((Tab)->ka_tab[Id] + (Tab)->ks_tab[Id]) 937 #define DOMAIN sw 938 #define DATA kext 939 #include "htgop_get_radiative_properties_bounds.h" 940 941 /******************************************************************************* 942 * Local functions 943 ******************************************************************************/ 944 void 945 log_err(const struct htgop* htgop, const char* msg, ...) 946 { 947 va_list vargs_list; 948 ASSERT(htgop && msg); 949 950 va_start(vargs_list, msg); 951 log_msg(htgop, LOG_ERROR, msg, vargs_list); 952 va_end(vargs_list); 953 } 954 955 void 956 log_warn(const struct htgop* htgop, const char* msg, ...) 957 { 958 va_list vargs_list; 959 ASSERT(htgop && msg); 960 961 va_start(vargs_list, msg); 962 log_msg(htgop, LOG_WARNING, msg, vargs_list); 963 va_end(vargs_list); 964 } 965 966 res_T 967 get_spectral_intervals 968 (const struct htgop* htgop, 969 const char* func_name, 970 const double wnum_range[2], 971 const double* wnums, 972 const size_t nwnums, 973 size_t specint_range[2]) 974 { 975 double wnum_min = 0; 976 double wnum_max = 0; 977 double* low = NULL; 978 double* upp = NULL; 979 res_T res = RES_OK; 980 ASSERT(htgop && wnum_range && wnums && nwnums && specint_range); 981 ASSERT(wnum_range[0] <= wnum_range[1]); 982 983 wnum_min = nextafter(wnum_range[0], DBL_MAX); 984 wnum_max = wnum_range[1]; 985 low = search_lower_bound(&wnum_min, wnums, nwnums, sizeof(double), cmp_dbl); 986 upp = search_lower_bound(&wnum_max, wnums, nwnums, sizeof(double), cmp_dbl); 987 988 if(!low || upp == wnums) { 989 log_err(htgop, 990 "%s: the loaded data do not overlap the wave numbers in [%g, %g].\n", 991 func_name, wnum_range[0], wnum_range[1]); 992 res = RES_BAD_OP; 993 goto error; 994 } 995 ASSERT(low[0] >= wnum_min && (low == wnums || low[-1] < wnum_min)); 996 ASSERT(!upp || (upp[0] >= wnum_max && upp[-1] < wnum_max)); 997 998 specint_range[0] = low == wnums ? 0 : (size_t)(low - wnums) - 1; 999 specint_range[1] = !upp ? nwnums - 1 : (size_t)(upp - wnums); 1000 /* Transform the upper wnum bound in spectral interval id */ 1001 specint_range[1] = specint_range[1] - 1; 1002 1003 1004 ASSERT(specint_range[0] <= specint_range[1]); 1005 ASSERT(wnums[specint_range[0]+1] > wnum_range[0]); 1006 ASSERT(wnums[specint_range[1]+0] < wnum_range[1]); 1007 1008 ASSERT(wnums[specint_range[0]+0] <= wnum_range[0] 1009 || specint_range[0]==0); /* The data do not include `wnum_range' */ 1010 ASSERT(wnums[specint_range[1]+1] >= wnum_range[1] 1011 || specint_range[1] + 1 == nwnums-1);/* The data do not include `wnum_range' */ 1012 1013 exit: 1014 return res; 1015 error: 1016 if(specint_range) { 1017 specint_range[0] = SIZE_MAX; 1018 specint_range[1] = 0; 1019 } 1020 goto exit; 1021 }