star-line

Structure for accelerating line importance sampling
git clone git://git.meso-star.com/star-line.git
Log | Files | Refs | README | LICENSE

test_sln_tree.c (19650B)


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