test_sln_tree.c (19651B)
1 /* Copyright (C) 2022, 2026 |Méso|Star> (contact@meso-star.com) 2 * Copyright (C) 2026 Université de Lorraine 3 * Copyright (C) 2022 Centre National de la Recherche Scientifique 4 * Copyright (C) 2022 Université Paul Sabatier 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19 #include "test_sln_lines.h" 20 #include "sln.h" 21 22 #include <star/shtr.h> 23 24 #include <rsys/algorithm.h> 25 #include <rsys/math.h> 26 #include <rsys/mem_allocator.h> 27 28 /******************************************************************************* 29 * Helper function 30 ******************************************************************************/ 31 /* Return the index of the line in the line_list or SIZE_MAX if the line does 32 * not exist */ 33 static INLINE size_t 34 find_line 35 (struct shtr_line_list* line_list, 36 const struct shtr_line* line) 37 { 38 struct shtr_line ln = SHTR_LINE_NULL; 39 size_t lo, hi, mid; 40 size_t iline; 41 size_t nlines; 42 43 CHK(shtr_line_list_get_size(line_list, &nlines) == RES_OK); 44 45 /* Dichotomic search */ 46 lo = 0; hi = nlines -1; 47 while(lo < hi) { 48 mid = (lo+hi)/2; 49 50 CHK(shtr_line_list_at(line_list, mid, &ln) == RES_OK); 51 if(line->wavenumber > ln.wavenumber) { 52 lo = mid + 1; 53 } else { 54 hi = mid; 55 } 56 } 57 iline = lo; 58 59 CHK(shtr_line_list_at(line_list, iline, &ln) == RES_OK); 60 if(ln.wavenumber != line->wavenumber) return SIZE_MAX; 61 62 63 /* Find a line with the same wavenumber as the one searched for and whose 64 * other member variables are also equal to those of the line searched for */ 65 while(ln.wavenumber == line->wavenumber 66 && !shtr_line_eq(&ln, line) 67 && iline < nlines) { 68 iline += 1; 69 CHK(shtr_line_list_at(line_list, iline, &ln) == RES_OK); 70 } 71 72 return shtr_line_eq(&ln, line) ? iline : SIZE_MAX; 73 } 74 75 /* This test assumes that all the lines contained into the list are 76 * partitionned in the tree */ 77 static void 78 check_tree_lines 79 (const struct sln_tree* tree, 80 struct shtr_line_list* line_list) 81 { 82 #define STACK_SIZE \ 83 ( SLN_TREE_DEPTH_MAX \ 84 * SLN_TREE_ARITY_MAX - 1/*1st child*/ \ 85 + 1/*Dummy node*/) 86 const struct sln_node* stack[STACK_SIZE] = {NULL}; 87 struct sln_tree_desc desc = SLN_TREE_DESC_NULL; 88 size_t istack = 0; 89 const struct sln_node* node = NULL; 90 91 char* found_lines = NULL; 92 size_t found_nlines = 0; 93 size_t line_list_sz; 94 95 CHK(shtr_line_list_get_size(line_list, &line_list_sz) == RES_OK); 96 CHK(sln_tree_get_desc(tree, &desc) == RES_OK); 97 98 CHK(found_lines = mem_calloc(line_list_sz, sizeof(char))); 99 100 stack[istack++] = NULL; /* Dummy node to stop the recursion */ 101 102 node = sln_tree_get_root(tree); 103 while(node) { 104 struct sln_node_desc node_desc = SLN_NODE_DESC_NULL; 105 size_t node_nlines = 0; 106 107 CHK(sln_node_get_desc(tree, node, &node_desc) == RES_OK); 108 node_nlines = node_desc.ilines[1] - node_desc.ilines[0] + 1; 109 110 if(!sln_node_is_leaf(node)) { 111 unsigned i = 0; 112 unsigned n = sln_node_get_child_count(tree, node); 113 114 CHK(node_nlines > desc.leaf_nlines); 115 116 FOR_EACH(i, 1, n) { 117 stack[istack++] = sln_node_get_child(tree, node, i); 118 } 119 node = sln_node_get_child(tree, node, 0); /* Handle the child 0 */ 120 121 } else { 122 size_t iline; 123 124 CHK(node_nlines <= desc.leaf_nlines); 125 FOR_EACH(iline, node_desc.ilines[0], node_desc.ilines[1]+1) { 126 if(!found_lines[iline]) { 127 found_nlines += 1; 128 found_lines[iline] = 1; 129 } 130 } 131 132 node = stack[--istack]; /* Pop the next node */ 133 } 134 } 135 136 /* Check that all lines are found */ 137 CHK(found_nlines == line_list_sz); 138 139 mem_rm(found_lines); 140 #undef STACK_SIZE 141 } 142 143 static void 144 check_mesh_equality(const struct sln_mesh* mesh1, const struct sln_mesh* mesh2) 145 { 146 size_t i; 147 CHK(mesh1 && mesh2); 148 CHK(mesh1->nvertices == mesh2->nvertices); 149 150 FOR_EACH(i, 0, mesh1->nvertices) { 151 CHK(mesh1->vertices[i].wavenumber == mesh2->vertices[i].wavenumber); 152 CHK(mesh1->vertices[i].ka == mesh2->vertices[i].ka); 153 } 154 } 155 156 static void 157 check_node_equality 158 (const struct sln_tree* tree1, 159 const struct sln_tree* tree2, 160 const struct sln_node* node1, 161 const struct sln_node* node2) 162 { 163 struct sln_mesh mesh1 = SLN_MESH_NULL; 164 struct sln_mesh mesh2 = SLN_MESH_NULL; 165 struct sln_node_desc desc1 = SLN_NODE_DESC_NULL; 166 struct sln_node_desc desc2 = SLN_NODE_DESC_NULL; 167 size_t iline = 0; 168 169 CHK(node1 && node2); 170 CHK(sln_node_is_leaf(node1) == sln_node_is_leaf(node2)); 171 CHK(sln_node_get_desc(tree1, node1, &desc1) == RES_OK); 172 CHK(sln_node_get_desc(tree2, node2, &desc2) == RES_OK); 173 174 CHK(desc1.ilines[0] == desc2.ilines[0]); 175 CHK(desc1.ilines[1] == desc2.ilines[1]); 176 CHK(desc1.nvertices == desc2.nvertices); 177 CHK(desc1.nchildren == desc2.nchildren); 178 179 FOR_EACH(iline, desc1.ilines[0], desc1.ilines[1]+1) { 180 struct sln_line line1 = SLN_LINE_NULL; 181 struct sln_line line2 = SLN_LINE_NULL; 182 CHK(sln_tree_get_line(tree1, iline, &line1) == RES_OK); 183 CHK(sln_tree_get_line(tree2, iline, &line2) == RES_OK); 184 185 CHK(line1.wavenumber == line2.wavenumber); 186 CHK(line1.profile_factor == line2.profile_factor); 187 CHK(line1.gamma_d == line2.gamma_d); 188 CHK(line1.gamma_l == line2.gamma_l); 189 CHK(line1.molecule_id == line2.molecule_id); 190 } 191 192 CHK(sln_node_get_mesh(tree1, node1, &mesh1) == RES_OK); 193 CHK(sln_node_get_mesh(tree2, node2, &mesh2) == RES_OK); 194 check_mesh_equality(&mesh1, &mesh2); 195 } 196 197 static void 198 check_tree_equality 199 (const struct sln_tree* tree1, 200 const struct sln_tree* tree2) 201 { 202 #define STACK_SIZE \ 203 ( SLN_TREE_DEPTH_MAX \ 204 * (SLN_TREE_ARITY_MAX-1/*1st child*/) * 2/*#trees*/ \ 205 + 1/*Dummy node*/) 206 207 const struct sln_node* stack[STACK_SIZE] = {NULL}; 208 int istack = 0; 209 210 struct sln_tree_desc desc1 = SLN_TREE_DESC_NULL; 211 struct sln_tree_desc desc2 = SLN_TREE_DESC_NULL; 212 const struct sln_node* node1 = NULL; 213 const struct sln_node* node2 = NULL; 214 215 CHK(sln_tree_get_desc(tree1, &desc1) == RES_OK); 216 CHK(sln_tree_get_desc(tree2, &desc2) == RES_OK); 217 CHK(desc1.leaf_nlines == desc2.leaf_nlines); 218 CHK(desc1.mesh_decimation_err == desc2.mesh_decimation_err); 219 CHK(desc1.mesh_type == desc2.mesh_type); 220 CHK(desc1.line_profile == desc2.line_profile); 221 CHK(desc1.pressure == desc2.pressure); 222 CHK(desc1.temperature == desc2.temperature); 223 CHK(desc1.depth == desc2.depth); 224 CHK(desc1.nlines == desc2.nlines); 225 CHK(desc1.nvertices == desc2.nvertices); 226 CHK(desc1.nnodes == desc2.nnodes); 227 CHK(desc1.arity == desc2.arity); 228 229 stack[istack++] = NULL; 230 stack[istack++] = NULL; 231 232 node1 = sln_tree_get_root(tree1); 233 node2 = sln_tree_get_root(tree2); 234 235 while(node1 || node2) { 236 CHK((!node1 && !node2) || (node1 && node2)); 237 check_node_equality(tree1, tree2, node1, node2); 238 239 if(sln_node_is_leaf(node1)) { 240 node2 = stack[--istack]; 241 node1 = stack[--istack]; 242 } else { 243 unsigned i = 0; 244 unsigned n = sln_node_get_child_count(tree1, node1); 245 246 FOR_EACH(i, 1, n) { 247 stack[istack++] = sln_node_get_child(tree1, node1, i); 248 stack[istack++] = sln_node_get_child(tree2, node2, i); 249 } 250 node1 = sln_node_get_child(tree1, node1, 0); 251 node2 = sln_node_get_child(tree2, node2, 0); 252 } 253 } 254 255 #undef STACK_SIZE 256 } 257 258 static void 259 check_node_value(const struct sln_tree* tree, const struct sln_node* node) 260 { 261 struct sln_node_desc desc = SLN_NODE_DESC_NULL; 262 struct sln_line line = SLN_LINE_NULL; 263 size_t iline = 0; 264 double ka_ref = 0; 265 double ka_node = 0; 266 double nu = 0; 267 268 CHK(sln_node_get_desc(tree, node, &desc) == RES_OK); 269 270 CHK(sln_tree_get_line(tree, desc.ilines[0], &line) == RES_OK); 271 nu = line.wavenumber + 10; 272 CHK(sln_tree_get_line(tree, desc.ilines[1], &line) == RES_OK); 273 nu += line.wavenumber - 10; 274 nu *= 0.5; 275 276 ka_node = sln_node_eval(tree, node, nu); 277 FOR_EACH(iline, desc.ilines[0], desc.ilines[1]+1/*inclusive*/) { 278 CHK(sln_tree_get_line(tree, iline, &line) == RES_OK); 279 ka_ref += sln_line_eval(tree, &line, nu); 280 } 281 282 CHK(eq_eps(ka_node, ka_ref, ka_ref*1e-6)); 283 } 284 285 static void 286 test_tree 287 (struct sln_device* sln, 288 const struct sln_tree_create_args* tree_args_in, 289 struct shtr_line_list* line_list) 290 { 291 struct sln_tree_create_args tree_args = SLN_TREE_CREATE_ARGS_DEFAULT; 292 struct sln_tree_desc desc = SLN_TREE_DESC_NULL; 293 struct sln_node_desc node_desc = SLN_NODE_DESC_NULL; 294 struct sln_mesh mesh = SLN_MESH_NULL; 295 struct sln_tree* tree = NULL; 296 const struct sln_node* node = NULL; 297 struct sln_line line = SLN_LINE_NULL; 298 size_t nlines = 0; 299 size_t nleaf = 0; 300 unsigned depth = 0; 301 302 CHK(sln && tree_args_in && line_list); 303 tree_args = *tree_args_in; 304 305 CHK(sln_tree_create(NULL, &tree_args, &tree) == RES_BAD_ARG); 306 CHK(sln_tree_create(sln, NULL, &tree) == RES_BAD_ARG); 307 CHK(sln_tree_create(sln, &tree_args, NULL) == RES_BAD_ARG); 308 CHK(sln_tree_create(sln, &tree_args, &tree) == RES_OK); 309 310 CHK(shtr_line_list_get_size(line_list, &nlines) == RES_OK); 311 312 CHK(sln_tree_get_desc(NULL, &desc) == RES_BAD_ARG); 313 CHK(sln_tree_get_desc(tree, NULL) == RES_BAD_ARG); 314 CHK(sln_tree_get_desc(tree, &desc) == RES_OK); 315 316 CHK(desc.leaf_nlines >= 1); 317 CHK(desc.mesh_decimation_err == tree_args.mesh_decimation_err); 318 CHK(desc.mesh_type == tree_args.mesh_type); 319 CHK(desc.line_profile == tree_args.line_profile); 320 CHK(desc.nlines == nlines); 321 CHK(desc.nvertices >= 1); 322 CHK(desc.nnodes >= 1); 323 324 nleaf = (desc.nlines + desc.leaf_nlines-1/*ceil*/)/ desc.leaf_nlines; 325 depth = (unsigned)ceil(log((double)nleaf)/log((double)desc.arity)); 326 CHK(desc.depth == depth); 327 328 CHK(desc.pressure == tree_args.pressure); 329 CHK(desc.temperature == tree_args.temperature); 330 CHK(desc.arity == tree_args.arity); 331 332 CHK(sln_tree_get_line(NULL, 0, &line) == RES_BAD_ARG); 333 CHK(sln_tree_get_line(tree, nlines, &line) == RES_BAD_ARG); 334 CHK(sln_tree_get_line(tree, 0, NULL) == RES_BAD_ARG); 335 CHK(sln_tree_get_line(tree, 0, &line) == RES_OK); 336 CHK(sln_tree_get_line(tree, nlines-1, &line) == RES_OK); 337 338 CHK(node = sln_tree_get_root(tree)); 339 CHK(node != NULL); 340 341 CHK(sln_node_get_desc(NULL, node, &node_desc) == RES_BAD_ARG); 342 CHK(sln_node_get_desc(tree, NULL, &node_desc) == RES_BAD_ARG); 343 CHK(sln_node_get_desc(tree, node, NULL) == RES_BAD_ARG); 344 CHK(sln_node_get_desc(tree, node, &node_desc) == RES_OK); 345 CHK(node_desc.ilines[0] == 0); 346 CHK(node_desc.ilines[1] == desc.nlines - 1); 347 CHK(node_desc.nvertices >= 1 && node_desc.nvertices < desc.nvertices); 348 CHK(node_desc.nchildren <= desc.arity); 349 350 while(!sln_node_is_leaf(node)) { 351 struct sln_node_desc node_desc_next = SLN_NODE_DESC_NULL; 352 353 CHK(sln_node_get_child_count(tree, node) != 0); 354 CHK(sln_node_get_child_count(tree, node) <= desc.arity); 355 356 node = sln_node_get_child(tree, node, 0); 357 358 CHK(sln_node_get_desc(tree, node, &node_desc_next) == RES_OK); 359 360 #define NLINES(Desc) ((Desc).ilines[1] - (Desc).ilines[0] + 1) 361 CHK(NLINES(node_desc_next) >= 1); 362 CHK(NLINES(node_desc_next) < NLINES(node_desc)); 363 #undef NLINES 364 365 CHK(node_desc_next.nvertices >= 1); 366 if(sln_node_is_leaf(node)) { 367 CHK(node_desc_next.nchildren == 0); 368 } else { 369 CHK(node_desc_next.nchildren != 0); 370 CHK(node_desc_next.nchildren <= desc.arity); 371 } 372 373 node_desc = node_desc_next; 374 } 375 CHK(sln_node_get_child_count(tree, node) == 0); 376 377 CHK(node_desc.ilines[1] - node_desc.ilines[0] + 1 <= desc.leaf_nlines); 378 379 CHK(sln_node_get_mesh(NULL, node, &mesh) == RES_BAD_ARG); 380 CHK(sln_node_get_mesh(tree, NULL, &mesh) == RES_BAD_ARG); 381 CHK(sln_node_get_mesh(tree, node, NULL) == RES_BAD_ARG); 382 CHK(sln_node_get_mesh(tree, node, &mesh) == RES_OK); 383 check_node_value(tree, node); 384 385 CHK(node = sln_tree_get_root(tree)); 386 check_tree_lines(tree, line_list); 387 388 CHK(sln_tree_ref_get(NULL) == RES_BAD_ARG); 389 CHK(sln_tree_ref_get(tree) == RES_OK); 390 CHK(sln_tree_ref_put(NULL) == RES_BAD_ARG); 391 CHK(sln_tree_ref_put(tree) == RES_OK); 392 CHK(sln_tree_ref_put(tree) == RES_OK); 393 394 tree_args.mesh_decimation_err = -1; 395 CHK(sln_tree_create(sln, &tree_args, &tree) == RES_BAD_ARG); 396 tree_args.mesh_decimation_err = SLN_TREE_CREATE_ARGS_DEFAULT.mesh_decimation_err; 397 398 tree_args.mesh_type = SLN_MESH_TYPES_COUNT__; 399 CHK(sln_tree_create(sln, &tree_args, &tree) == RES_BAD_ARG); 400 tree_args.mesh_type = SLN_TREE_CREATE_ARGS_DEFAULT.mesh_type; 401 402 tree_args.line_profile = SLN_LINE_PROFILES_COUNT__; 403 CHK(sln_tree_create(sln, &tree_args, &tree) == RES_BAD_ARG); 404 tree_args.line_profile = SLN_TREE_CREATE_ARGS_DEFAULT.line_profile; 405 406 tree_args.arity = 1; 407 CHK(sln_tree_create(sln, &tree_args, &tree) == RES_BAD_ARG); 408 tree_args.arity = SLN_TREE_ARITY_MAX + 1; 409 CHK(sln_tree_create(sln, &tree_args, &tree) == RES_BAD_ARG); 410 tree_args.arity = SLN_TREE_CREATE_ARGS_DEFAULT.arity; 411 412 tree_args.leaf_nlines = 0; 413 CHK(sln_tree_create(sln, &tree_args, &tree) == RES_BAD_ARG); 414 tree_args.leaf_nlines = SLN_LEAF_NLINES_MAX + 1; 415 CHK(sln_tree_create(sln, &tree_args, &tree) == RES_BAD_ARG); 416 tree_args.leaf_nlines = SLN_TREE_CREATE_ARGS_DEFAULT.leaf_nlines; 417 418 CHK(sln_tree_create(sln, &tree_args, &tree) == RES_OK); 419 420 if(tree_args.arity == 2 && tree_args.collapse_polylines == 0) { 421 struct sln_tree* tree2 = NULL; 422 423 /* Verify that, when constructing a binary tree, creating polylines for 424 * internal nodes by reducing the polylines of their children results in 425 * exactly the same tree as when the polyline of an internal node is 426 * constructed by merging the polylines of its children */ 427 tree_args.collapse_polylines = 1; 428 CHK(sln_tree_create(sln, &tree_args, &tree2) == RES_OK); 429 check_tree_equality(tree, tree2); 430 431 CHK(sln_tree_ref_put(tree2) == RES_OK); 432 } 433 434 CHK(sln_tree_ref_put(tree) == RES_OK); 435 } 436 437 438 static void 439 test_tree_serialization 440 (struct sln_device* sln, 441 const struct sln_tree_create_args* tree_args) 442 { 443 struct sln_tree_write_args wargs = SLN_TREE_WRITE_ARGS_NULL; 444 struct sln_tree_read_args rargs = SLN_TREE_READ_ARGS_NULL; 445 struct sln_tree* tree1 = NULL; 446 struct sln_tree* tree2 = NULL; 447 448 const char* filename = "tree.sln"; 449 FILE* fp = NULL; 450 451 CHK(sln_tree_create(sln, tree_args, &tree1) == RES_OK); 452 453 CHK(fp = fopen(filename, "w+")); 454 455 wargs.file = fp; 456 CHK(sln_tree_write(NULL, &wargs) == RES_BAD_ARG); 457 CHK(sln_tree_write(tree1, NULL) == RES_BAD_ARG); 458 wargs.file = NULL; 459 CHK(sln_tree_write(tree1, &wargs) == RES_BAD_ARG); 460 wargs.file = fp; 461 CHK(sln_tree_write(tree1, &wargs) == RES_OK); 462 rewind(fp); 463 464 rargs.metadata = tree_args->metadata; 465 rargs.lines = tree_args->lines; 466 rargs.file = fp; 467 CHK(sln_tree_read(NULL, &rargs, &tree2) == RES_BAD_ARG); 468 CHK(sln_tree_read(sln, NULL, &tree2) == RES_BAD_ARG); 469 rargs.metadata = NULL; 470 CHK(sln_tree_read(sln, &rargs, &tree2) == RES_BAD_ARG); 471 rargs.metadata = tree_args->metadata; 472 rargs.lines = NULL; 473 CHK(sln_tree_read(sln, &rargs, &tree2) == RES_BAD_ARG); 474 rargs.lines = tree_args->lines; 475 rargs.file = NULL; 476 CHK(sln_tree_read(sln, &rargs, &tree2) == RES_BAD_ARG); 477 rargs.file = fp; 478 CHK(sln_tree_read(sln, &rargs, NULL) == RES_BAD_ARG); 479 CHK(sln_tree_read(sln, &rargs, &tree2) == RES_OK); 480 fclose(fp); 481 482 check_tree_equality(tree1, tree2); 483 CHK(sln_tree_ref_put(tree2) == RES_OK); 484 485 wargs.file = NULL; 486 wargs.filename = filename; 487 CHK(sln_tree_write(tree1, &wargs) == RES_OK); 488 489 rargs.file = NULL; 490 rargs.filename = "nop"; 491 CHK(sln_tree_read(sln, &rargs, &tree2) == RES_IO_ERR); 492 rargs.filename = filename; 493 CHK(sln_tree_read(sln, &rargs, &tree2) == RES_OK); 494 495 check_tree_equality(tree1, tree2); 496 497 CHK(sln_tree_ref_put(tree2) == RES_OK); 498 CHK(sln_tree_ref_put(tree1) == RES_OK); 499 } 500 501 /******************************************************************************* 502 * Test function 503 ******************************************************************************/ 504 int 505 main(int argc, char** argv) 506 { 507 struct sln_device_create_args dev_args = SLN_DEVICE_CREATE_ARGS_DEFAULT; 508 struct sln_tree_create_args tree_args = SLN_TREE_CREATE_ARGS_DEFAULT; 509 struct sln_device* sln = NULL; 510 511 struct shtr_create_args shtr_args = SHTR_CREATE_ARGS_DEFAULT; 512 struct shtr* shtr = NULL; 513 struct shtr_line_list_load_args line_load_args = SHTR_LINE_LIST_LOAD_ARGS_NULL; 514 struct shtr_line_list* line_list = NULL; 515 struct shtr_isotope_metadata* metadata = NULL; 516 517 FILE* fp_lines = NULL; 518 FILE* fp_mdata = NULL; 519 (void)argc, (void)argv; 520 521 /* Generate the file of the isotope metadata */ 522 CHK(fp_mdata = tmpfile()); 523 fprintf(fp_mdata, "Molecule # Iso Abundance Q(296K) gj Molar Mass(g)\n"); 524 write_shtr_molecule(fp_mdata, &g_H2O); 525 write_shtr_molecule(fp_mdata, &g_CO2); 526 write_shtr_molecule(fp_mdata, &g_O3); 527 rewind(fp_mdata); 528 529 /* Generate the file of lines */ 530 CHK(fp_lines = tmpfile()); 531 write_shtr_lines(fp_lines, g_lines, g_nlines); 532 rewind(fp_lines); 533 534 /* Load the isotope metadata and the lines */ 535 shtr_args.verbose = 1; 536 CHK(shtr_create(&shtr_args, &shtr) == RES_OK); 537 CHK(shtr_isotope_metadata_load_stream(shtr, fp_mdata, NULL, &metadata) == RES_OK); 538 539 line_load_args.filename = "stream"; 540 line_load_args.file = fp_lines; 541 CHK(shtr_line_list_load(shtr, &line_load_args, &line_list) == RES_OK); 542 543 CHK(fclose(fp_lines) == 0); 544 CHK(fclose(fp_mdata) == 0); 545 546 dev_args.verbose = 1; 547 CHK(sln_device_create(&dev_args, &sln) == RES_OK); 548 549 /* Create the mixture */ 550 tree_args.metadata = metadata; 551 tree_args.lines = line_list; 552 tree_args.molecules[SHTR_H2O].concentration = 1.0/3.0; 553 tree_args.molecules[SHTR_H2O].cutoff = 25; 554 tree_args.molecules[SHTR_CO2].concentration = 1.0/3.0; 555 tree_args.molecules[SHTR_CO2].cutoff = 50; 556 tree_args.molecules[SHTR_O3 ].concentration = 1.0/3.0; 557 tree_args.molecules[SHTR_O3 ].cutoff = 25; 558 tree_args.pressure = 1; 559 tree_args.temperature = 296; 560 561 test_tree(sln, &tree_args, line_list); 562 test_tree_serialization(sln, &tree_args); 563 564 /* Test a tree with a non default arity */ 565 tree_args.arity = 13; 566 test_tree(sln, &tree_args, line_list); 567 test_tree_serialization(sln, &tree_args); 568 569 /* Test a tree with a non-standard arity, where the polylines of the internal 570 * nodes are created by collapsing the polylines of their child nodes */ 571 tree_args.arity = 5; 572 tree_args.collapse_polylines = 1; 573 test_tree(sln, &tree_args, line_list); 574 test_tree_serialization(sln, &tree_args); 575 576 /* Test a tree where the number of rows per leaf is greater than 1 */ 577 tree_args.arity = 4; 578 tree_args.leaf_nlines = 3; 579 tree_args.collapse_polylines = 0; 580 test_tree(sln, &tree_args, line_list); 581 test_tree_serialization(sln, &tree_args); 582 583 /* Test a tree in which the number of lines per leaf is greater than 1. The 584 * polylines for the leaves and internal nodes are created by reducing, 585 * respectively, the polyline of the leaf lines or those of the internal 586 * nodes' children */ 587 tree_args.arity = 3; 588 tree_args.leaf_nlines = 6; 589 tree_args.collapse_polylines = 1; 590 test_tree(sln, &tree_args, line_list); 591 test_tree_serialization(sln, &tree_args); 592 593 CHK(sln_device_ref_put(sln) == RES_OK); 594 CHK(shtr_ref_put(shtr) == RES_OK); 595 CHK(shtr_line_list_ref_put(line_list) == RES_OK); 596 CHK(shtr_isotope_metadata_ref_put(metadata) == RES_OK); 597 CHK(mem_allocated_size() == 0); 598 return 0; 599 }