star-mesh

Define and load a binary data format for meshes
git clone git://git.meso-star.fr/star-mesh.git
Log | Files | Refs | README | LICENSE

test_smsh_load.c (9922B)


      1 /* Copyright (C) 2020-2023, 2025 |Méso|Star> (contact@meso-star.com)
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #include "smsh.h"
     17 
     18 #include <rsys/double3.h>
     19 #include <rsys/math.h>
     20 #include <rsys/mem_allocator.h>
     21 #include <rsys/rsys.h>
     22 
     23 #include <stdio.h>
     24 #include <string.h>
     25 #include <unistd.h>
     26 
     27 /*******************************************************************************
     28  * Helper functions
     29  ******************************************************************************/
     30 static void
     31 check_smsh_desc
     32   (const struct smsh_desc* desc,
     33    const uint64_t nnodes,
     34    const uint64_t ncells,
     35    const uint64_t dnode,
     36    const uint64_t dcell)
     37 {
     38   size_t i, j;
     39   CHK(desc);
     40   CHK(nnodes);
     41   CHK(ncells);
     42   CHK(dnode);
     43   CHK(dcell);
     44 
     45   CHK(desc->nnodes == nnodes);
     46   CHK(desc->ncells == ncells);
     47   CHK(desc->dnode == dnode);
     48   CHK(desc->dcell == dcell);
     49 
     50   FOR_EACH(i, 0, nnodes) {
     51     const double* node0 = desc->nodes + i*dnode;
     52     const double* node1 = smsh_desc_get_node(desc, i);
     53     FOR_EACH(j, 0, dnode) {
     54       CHK(node0[j] == node1[j]);
     55       CHK(node0[j] == (double)i + (double)j*0.1);
     56     }
     57   }
     58 
     59   FOR_EACH(i, 0, ncells) {
     60     const uint64_t* cell0 = desc->cells + i*dcell;
     61     const uint64_t* cell1 = smsh_desc_get_cell(desc, i);
     62     FOR_EACH(j, 0, dcell) {
     63       CHK(cell0[j] == cell1[j]);
     64       CHK(cell0[j] == (i*dcell+j)%nnodes);
     65     }
     66   }
     67 }
     68 
     69 static void
     70 test_load_mesh(struct smsh* smsh, const uint32_t dnode, const uint32_t dcell)
     71 {
     72   hash256_T hash0;
     73   hash256_T hash1;
     74   struct smsh_desc desc = SMSH_DESC_NULL;
     75   struct smsh_load_args args = SMSH_LOAD_ARGS_NULL;
     76   struct smsh_load_stream_args stream_args = SMSH_LOAD_STREAM_ARGS_NULL;
     77   FILE* fp = NULL;
     78   const char* filename = "test_file.smsh";
     79   const uint64_t pagesize = 16384;
     80   const uint64_t nnodes = 287;
     81   const uint64_t ncells = 192;
     82   size_t i, j;
     83   char byte = 0;
     84   ASSERT(smsh);
     85 
     86   fp = fopen(filename, "w+");
     87   CHK(fp);
     88 
     89   /* Write file header */
     90   CHK(fwrite(&pagesize, sizeof(pagesize), 1, fp) == 1);
     91   CHK(fwrite(&nnodes, sizeof(nnodes), 1, fp) == 1);
     92   CHK(fwrite(&ncells, sizeof(ncells), 1, fp) == 1);
     93   CHK(fwrite(&dnode, sizeof(dnode), 1, fp) == 1);
     94   CHK(fwrite(&dcell, sizeof(dcell), 1, fp) == 1);
     95 
     96   /* Padding */
     97   CHK(fseek(fp, (long)ALIGN_SIZE((size_t)ftell(fp), pagesize), SEEK_SET) == 0);
     98 
     99   /* Write vertex nodes */
    100   FOR_EACH(i, 0, nnodes) {
    101     FOR_EACH(j, 0, dnode) {
    102       const double dbl = (double)i + (double)j * 0.1;
    103       CHK(fwrite(&dbl, sizeof(dbl), 1, fp) == 1);
    104     }
    105   }
    106 
    107   /* Padding */
    108   CHK(fseek(fp, (long)ALIGN_SIZE((size_t)ftell(fp), pagesize), SEEK_SET) == 0);
    109 
    110   /* Write tetrahedra */
    111   FOR_EACH(i, 0, ncells) {
    112     FOR_EACH(j, 0, dcell) {
    113       const uint64_t ui64 = (i*dcell + j) % nnodes;
    114       CHK(fwrite(&ui64, sizeof(ui64), 1, fp) == 1);
    115     }
    116   }
    117 
    118   /* Padding. Write one char to position the EOF indicator */
    119   CHK(fseek(fp, (long)ALIGN_SIZE((size_t)ftell(fp), pagesize)-1, SEEK_SET) == 0);
    120   CHK(fwrite(&byte, sizeof(byte), 1, fp) == 1);
    121 
    122   rewind(fp);
    123 
    124   stream_args.stream = fp;
    125   stream_args.name = filename;
    126   CHK(smsh_load_stream(NULL, &stream_args) == RES_BAD_ARG);
    127   CHK(smsh_load_stream(smsh, NULL) == RES_BAD_ARG);
    128   stream_args.stream = NULL;
    129   CHK(smsh_load_stream(smsh, &stream_args) == RES_BAD_ARG);
    130   stream_args.stream = fp;
    131   stream_args.name = NULL;
    132   CHK(smsh_load_stream(smsh, &stream_args) == RES_BAD_ARG);
    133   stream_args.name = filename;
    134   CHK(smsh_load_stream(smsh, &stream_args) == RES_OK);
    135   CHK(smsh_get_desc(NULL, &desc) == RES_BAD_ARG);
    136   CHK(smsh_get_desc(smsh, NULL) == RES_BAD_ARG);
    137   CHK(smsh_get_desc(smsh, &desc) == RES_OK);
    138   check_smsh_desc(&desc, nnodes, ncells, dnode, dcell);
    139 
    140   CHK(smsh_desc_compute_hash(NULL, hash0) == RES_BAD_ARG);
    141   CHK(smsh_desc_compute_hash(&desc, NULL) == RES_BAD_ARG);
    142   CHK(smsh_desc_compute_hash(&desc, hash0) == RES_OK);
    143 
    144   rewind(fp);
    145   stream_args.name = SMSH_LOAD_STREAM_ARGS_NULL.name;
    146   stream_args.memory_mapping = 1;
    147   CHK(smsh_load_stream(smsh, &stream_args) == RES_OK);
    148   CHK(smsh_get_desc(smsh, &desc) == RES_OK);
    149   check_smsh_desc(&desc, nnodes, ncells, dnode, dcell);
    150 
    151   CHK(smsh_desc_compute_hash(&desc, hash1) == RES_OK);
    152   CHK(hash256_eq(hash0, hash1));
    153   CHK(fclose(fp) == 0);
    154 
    155   args.path = filename;
    156   CHK(smsh_load(NULL, &args) == RES_BAD_ARG);
    157   CHK(smsh_load(smsh, NULL) == RES_BAD_ARG);
    158   args.path = NULL;
    159   CHK(smsh_load(smsh, &args) == RES_BAD_ARG);
    160   args.path = "nop";
    161   CHK(smsh_load(smsh, &args) == RES_IO_ERR);
    162   args.path = filename;
    163   CHK(smsh_load(smsh, &args) == RES_OK);
    164   CHK(smsh_get_desc(smsh, &desc) == RES_OK);
    165   check_smsh_desc(&desc, nnodes, ncells, dnode, dcell);
    166   CHK(smsh_desc_compute_hash(&desc, hash1) == RES_OK);
    167   CHK(hash256_eq(hash0, hash1));
    168 
    169   args.memory_mapping = 1;
    170   CHK(smsh_load(smsh, &args) == RES_OK);
    171   CHK(smsh_get_desc(smsh, &desc) == RES_OK);
    172   check_smsh_desc(&desc, nnodes, ncells, dnode, dcell);
    173   CHK(smsh_desc_compute_hash(&desc, hash1) == RES_OK);
    174   CHK(hash256_eq(hash0, hash1));
    175 }
    176 
    177 static void
    178 test_load_fail(struct smsh* smsh)
    179 {
    180   struct smsh_load_stream_args args = SMSH_LOAD_STREAM_ARGS_NULL;
    181   const char byte = 0;
    182   FILE* fp = NULL;
    183   uint64_t pagesize;
    184   uint64_t nnodes;
    185   uint64_t ncells;
    186   unsigned dnode;
    187   unsigned dcell;
    188 
    189   /* Wrong pagesize */
    190   fp = tmpfile();
    191   CHK(fp);
    192   pagesize = 1023;
    193   nnodes = 10;
    194   ncells = 10;
    195   dnode = 3;
    196   dcell = 4;
    197   CHK(fwrite(&pagesize, sizeof(pagesize), 1, fp) == 1);
    198   CHK(fwrite(&nnodes, sizeof(nnodes), 1, fp) == 1);
    199   CHK(fwrite(&ncells, sizeof(ncells), 1, fp) == 1);
    200   CHK(fwrite(&dnode, sizeof(dnode), 1, fp) == 1);
    201   CHK(fwrite(&dcell, sizeof(dcell), 1, fp) == 1);
    202   CHK(fseek(fp, (long)ALIGN_SIZE((size_t)ftell(fp), pagesize), SEEK_SET) == 0);
    203   CHK(fseek(fp, (long)(sizeof(double[3])*nnodes), SEEK_CUR) == 0);
    204   CHK(fseek(fp, (long)ALIGN_SIZE((size_t)ftell(fp), pagesize), SEEK_SET) == 0);
    205   CHK(fseek(fp, (long)(sizeof(uint64_t[4])*ncells), SEEK_CUR) == 0);
    206   CHK(fseek(fp, (long)ALIGN_SIZE((size_t)ftell(fp), pagesize)-1, SEEK_SET) == 0);
    207   CHK(fwrite(&byte, sizeof(byte), 1, fp) == 1);
    208   rewind(fp);
    209   args.stream = fp;
    210   CHK(smsh_load_stream(smsh, &args) == RES_BAD_ARG);
    211   CHK(fclose(fp) == 0);
    212 
    213   /* Wrong size */
    214   fp = tmpfile();
    215   CHK(fp);
    216   pagesize = (uint64_t)sysconf(_SC_PAGESIZE);
    217   nnodes = 10;
    218   ncells = 10;
    219   dnode = 3;
    220   dcell = 4;
    221   CHK(fwrite(&pagesize, sizeof(pagesize), 1, fp) == 1);
    222   CHK(fwrite(&nnodes, sizeof(nnodes), 1, fp) == 1);
    223   CHK(fwrite(&ncells, sizeof(ncells), 1, fp) == 1);
    224   CHK(fwrite(&dnode, sizeof(dnode), 1, fp) == 1);
    225   CHK(fwrite(&dcell, sizeof(dcell), 1, fp) == 1);
    226   CHK(fseek(fp, (long)ALIGN_SIZE((size_t)ftell(fp), pagesize), SEEK_SET) == 0);
    227   CHK(fseek(fp, (long)(sizeof(double[3])*nnodes), SEEK_CUR) == 0);
    228   CHK(fseek(fp, (long)ALIGN_SIZE((size_t)ftell(fp), pagesize), SEEK_SET) == 0);
    229   CHK(fseek(fp, (long)(sizeof(uint64_t[4])*ncells), SEEK_CUR) == 0);
    230   CHK(fseek(fp, (long)ALIGN_SIZE((size_t)ftell(fp), pagesize)-2, SEEK_SET) == 0);
    231   CHK(fwrite(&byte, sizeof(byte), 1, fp) == 1);
    232   rewind(fp);
    233   args.stream = fp;
    234   CHK(smsh_load_stream(smsh, &args) == RES_IO_ERR);
    235   CHK(fclose(fp) == 0);
    236 }
    237 
    238 static void
    239 test_load_files(struct smsh* smsh, int argc, char** argv)
    240 {
    241   hash256_T hash;
    242   int i;
    243   CHK(smsh);
    244   FOR_EACH(i, 1, argc) {
    245     struct smsh_desc desc = SMSH_DESC_NULL;
    246     size_t j;
    247     size_t inode;
    248     size_t icell;
    249 
    250     /* Load from file */
    251     if(strcmp(argv[i], "-") != 0) {
    252       struct smsh_load_args args = SMSH_LOAD_ARGS_NULL;
    253       printf("Load %s\n", argv[i]);
    254       args.path = argv[i];
    255       args.memory_mapping = 1;
    256       CHK(smsh_load(smsh, &args) == RES_OK);
    257 
    258     /* Load from stdin */
    259     } else {
    260       struct smsh_load_stream_args args = SMSH_LOAD_STREAM_ARGS_NULL;
    261       printf("Load from stdin\n");
    262       args.stream = stdin;
    263       args.name = "stdin";
    264       args.memory_mapping = 1;
    265       CHK(smsh_load_stream(smsh, &args) == RES_BAD_ARG);
    266       args.memory_mapping = 0;
    267       CHK(smsh_load_stream(smsh, &args) == RES_OK);
    268     }
    269     CHK(smsh_get_desc(smsh, &desc) == RES_OK);
    270     CHK(smsh_desc_compute_hash(&desc, hash) == RES_OK);
    271 
    272     FOR_EACH(inode, 0, desc.nnodes) {
    273       const double* node = smsh_desc_get_node(&desc, inode);
    274       FOR_EACH(j, 0, desc.dnode) {
    275         CHK(node[j] == node[j]); /* !NaN */
    276         CHK(!IS_INF(node[j]));
    277       }
    278     }
    279     FOR_EACH(icell, 0, desc.ncells) {
    280       const uint64_t* ids = smsh_desc_get_cell(&desc, icell);
    281       FOR_EACH(j, 0, desc.dcell) {
    282         size_t k;
    283         FOR_EACH(k, 0, desc.dcell) {
    284           if(k == j) continue;
    285           CHK(ids[j] != ids[k]); /* Check non degenerated cell */
    286         }
    287       }
    288     }
    289   }
    290 }
    291 
    292 /*******************************************************************************
    293  * Main function
    294  ******************************************************************************/
    295 int
    296 main(int argc, char** argv)
    297 {
    298   struct smsh_create_args args = SMSH_CREATE_ARGS_DEFAULT;
    299   struct smsh* smsh = NULL;
    300   (void)argc, (void)argv;
    301 
    302   args.verbose = 1;
    303   CHK(smsh_create(&args, &smsh) == RES_OK);
    304 
    305   if(argc > 1) {
    306     test_load_files(smsh, argc, argv);
    307   } else {
    308     test_load_mesh(smsh, 3, 4); /* Tetrahedra */
    309     test_load_mesh(smsh, 3, 3); /* Triangles 3D */
    310     test_load_mesh(smsh, 2, 3); /* Triangles 2D */
    311     test_load_fail(smsh);
    312   }
    313 
    314   CHK(smsh_ref_put(smsh) == RES_OK);
    315   CHK(mem_allocated_size() == 0);
    316   return 0;
    317 }