Path: blob/main/src/t8_cmesh/t8_cmesh_internal/t8_cmesh_trees.h
921 views
/*1This file is part of t8code.2t8code is a C library to manage a collection (a forest) of multiple3connected adaptive space-trees of general element classes in parallel.45Copyright (C) 2015 the developers67t8code is free software; you can redistribute it and/or modify8it under the terms of the GNU General Public License as published by9the Free Software Foundation; either version 2 of the License, or10(at your option) any later version.1112t8code is distributed in the hope that it will be useful,13but WITHOUT ANY WARRANTY; without even the implied warranty of14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15GNU General Public License for more details.1617You should have received a copy of the GNU General Public License18along with t8code; if not, write to the Free Software Foundation, Inc.,1951 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.20*/2122/** \file t8_cmesh_trees.h23* Interface for the data layout of the coarse trees.24*/2526#ifndef T8_CMESH_PART_TREE_H27#define T8_CMESH_PART_TREE_H2829#include <t8.h>30#include <t8_cmesh/t8_cmesh.h>31#include <t8_cmesh/t8_cmesh_internal/t8_cmesh_types.h>3233T8_EXTERN_C_BEGIN ();3435/* Interface for the data layout of the coarse trees.36*37* The layout is the same for replicated and partitioned meshes.38* Each process stores a meta array of data arrays. In the replicated case this meta39* array has only one entry whereas in the partitioned case there is one data array for40* each processor from which local trees were received in the last partition step41* (and only one meta array if the cmesh arose from a partitioned commit).42*43* Each dara arrays stores the local trees, the ghosts, face neighbor information44* of the ghosts, face neihbor information of the trees and the attributes of the trees.45* Furthermore we store for each tree and for each ghost to which data array they belong to.46* So the data looks like:47*48* TODO: would be more logical to switch Ghost and Tree faces49*50* M_0: | Trees | Ghosts | Ghost faces | Tree faces | Tree attributes | Ghost attributes51* M_1: | Trees | Ghosts | Ghost faces | Tree faces | Tree attributes | Ghost attributes52* . . . . . .53* M_n: | Trees | Ghosts | Ghost faces | Tree faces | Tree attributes | Ghost attributes54*55* tree_to_proc: | 0 | 0 | 1 | ... | n | these are just random examples here56* ghost_to_proc: | 0 | 1 | 2 | ... | n |57*58*59* Each tree T stores an offset to its Tree faces, such that (char*)&T + offset is60* a pointer to the faces array.61* The same holds for the ghost.62* Also each tree stores the number of attributes and an offset relative to itself63* to the first attribute entry of that tree.64*65* Tree faces:66*67* For each tree the data of the tree faces (where F is the number of faces of the tree) looks like this:68*69* | Treeid1 Treeid2 ... TreeidF | ttf1 ttf2 ... ttfN | padding |70*71* Where padding is a number of unused bytes that makes the whole block a multiple72* of 4 Bytes.73* Treeid is a t8_locidx_t storing the local tree id for local tree neighbors and74* the local ghost id + num_local_trees for ghost neighbors.75* For the encoding of ttf (tree to face) see \ref t8_ctree_struct_t, ttf entries are int8_t76* and the offset of ttf1 can be calculated from the Tree faces offset and the77* class of the tree.78*79* Ghost faces:80*81* | Treeid1 Treeid2 ... TreeidF | ttf1 ttf2 ... ttfF | padding |82*83* Where padding is a number of unused bytes that makes the whole block a multiple84* of sizeof (void*) Bytes.85* Treeidj is a t8_gloidx_t storing the global tree id for all neighbors.86* For the encoding of ttf (tree to face) see \ref t8_ctree_struct_t, ttf entries are int8_t87* and the offset of ttf1 can be calculated from the Tree faces offset and the88* class of the tree.89* Tree attributes:90*91* The data of Tree attributes looks like, where N is the total number of attributes:92* The Attributes do not necessarily need to be sorted in a particular way, as they are93* accessed by offsets in the Att_descr.94*95* | Att00_descr | Att01_descr | ... Att0 A_0_descr| Att10_descr | ... | AttrT A_T | Att0_data | Att2_data | ... AttN_data|96* TODO: maybe insert padding here ||97* Where Attij_descr is a descriptor of the j-th attribute data of tree i storing98* - an offset to Attk_data starting from Attij_descr, where k is the index in the dataarray.99* The actual data is put there in the order of the attribute descriptors, but this is not necessitated by the layout.100* - package id of the attribute (int)101* - key of the attribute (int)102* The data type is t8_attribute_info_struct_t103*104* Attrend_descr only stores the offset of the end of this attributes block105* (like an imaginary very last attribute);106* using this info the size of each attribute can be computed as the difference107* of the sizes of two consecutive attributes.108*109* padding is a number of nonused bytes to make the size of the descr block110* a multiple of four.111*112* TODO: maybe padding after the last Att_data is useful too113* TODO: We may also need padding between the attributes.114*115*/116117/* allocate a t8_cmesh_tree struct and allocate memory for its entries.118* No memory for ctrees or ghosts is allocated here */119/* TODO: document */120121/** Given a tree return the beginning of its attributes block */122#define T8_TREE_FIRST_ATT_INFO(t) ((char *) (t) + (t)->att_offset)123124/** Given a tree and an index i return the i-th attribute index of that tree */125#define T8_TREE_ATTR_INFO(t, i) \126((t8_attribute_info_struct_t *) ((char *) (t) + (t)->att_offset + (i) * sizeof (t8_attribute_info_struct_t)))127128/** Given a tree and an attribute info return the attribute */129#define T8_TREE_ATTR(t, ai) (T8_TREE_FIRST_ATT_INFO (t) + (ai)->attribute_offset)130131/** Given a tree return its face_neighbor array */132#define T8_TREE_FACE(t) ((char *) (t) + (t)->neigh_offset)133134/** Given a tree return irs tree_to_face array */135#define T8_TREE_TTF(t) (T8_TREE_FACE (t) + t8_eclass_num_faces[(t)->eclass] * sizeof (t8_locidx_t))136137/** Given a ghost return the beginning of its attribute block */138#define T8_GHOST_FIRST_ATT_INFO(g) T8_TREE_FIRST_ATT_INFO (g)139140/** Given a ghost and an index i return the i-th attribute index of that ghost */141#define T8_GHOST_ATTR_INFO(g, i) T8_TREE_ATTR_INFO (g, i)142143/** Given a ghost and an attribute info return the attribute */144#define T8_GHOST_ATTR(g, ai) T8_TREE_ATTR (g, ai)145146/** Given a ghost return its face_neighbor array */147#define T8_GHOST_FACE(g) T8_TREE_FACE (g)148149/** Given a ghost return its tree_to_face array */150#define T8_GHOST_TTF(g) (int8_t *) (T8_GHOST_FACE (g) + t8_eclass_num_faces[(g)->eclass] * sizeof (t8_gloidx_t))151152/** This struct is an entry of the trees global_id to local_id153* hash table for ghost trees. */154typedef struct155{156t8_gloidx_t global_id; /**< The global id */157t8_locidx_t local_id; /**< The local id */158} t8_trees_glo_lo_hash_t;159160/** Initialize a trees structure and allocate its parts.161* This function allocates the from_procs array without filling it, it162* also allocates the tree_to_proc and ghost_to_proc arrays.163* No memory for trees or ghosts is allocated.164* \param [in,out] ptrees The trees structure to be initialized.165* \param [in] num_procs The number of entries of its from_proc array166* (can be different for each process).167* \param [in] num_trees The number of trees that will be stored in this168* structure.169* \param [in] num_ghosts The number of ghosts that will be stored in this170* structure.171*/172void173t8_cmesh_trees_init (t8_cmesh_trees_t *ptrees, int num_procs, t8_locidx_t num_trees, t8_locidx_t num_ghosts);174175/** Return one part of a specified tree array.176* \param [in] trees The tree array to be queried177* \param [in] proc An index specifying the part to be returned.178* \return The part number \a proc of \a trees.179*/180t8_part_tree_t181t8_cmesh_trees_get_part (const t8_cmesh_trees_t trees, const int proc);182183/* !!! This does only allocate memory for the trees and ghosts184* not yet for the face data and the attributes. See below !!!185*/186/** Allocate the first_tree array of a given tree_part in a tree struct187* with a given number of trees and ghosts.188* This function allocates the memory for the trees and the ghosts189* but not for their face neighbor entries or attributes. These must190* be allocated later when the eclasses of the trees and ghosts are known191* \ref t8_cmesh_trees_finish_part.192* \param [in,out] trees The trees structure to be updated.193* \param [in] proc The index of the part to be updated.194* \param [in] lfirst_tree The local id of the first tree of that part.195* \param [in] num_trees The number of trees of that part.196* \param [in] lfirst_ghost The local id of the first ghost of that part.197* \param [in] num_ghosts The number of ghosts of that part.198* \param [in] alloc If true then the first_tree array is allocated for199* the number of trees and ghosts.200* When a cmesh is copied we do not want this, so in we pass alloc = 0 then.201*/202void203t8_cmesh_trees_start_part (t8_cmesh_trees_t trees, int proc, t8_locidx_t lfirst_tree, t8_locidx_t num_trees,204t8_locidx_t lfirst_ghost, t8_locidx_t num_ghosts, int alloc);205206/** After all classes of trees and ghosts have been set and after the207* number of tree attributes was set and their total size (per tree)208* stored temporarily in the att_offset variable209* we grow the part array by the needed amount of memory and set the210* offsets appropriately.211* The workflow should be: call \ref t8_cmesh_trees_start_part,212* set tree and ghost classes manually via \ref t8_cmesh_trees_add_tree213* and \ref t8_cmesh_trees_add_ghost, call214* \ref t8_cmesh_trees_init_attributes, then call this function.215* Afterwards successively call \ref t8_cmesh_trees_add_attribute for216* each attribute and217* also set all face neighbors (TODO: write function).218* \param [in,out] trees The trees structure to be updated.219* \param [in] proc The number of the part to be finished.220*/221void222t8_cmesh_trees_finish_part (t8_cmesh_trees_t trees, int proc);223224/** Copy the tree_to_proc and ghost_to_proc arrays of one tree structure to225* another one.226* \param [in,out] trees_dest The destination trees structure.227* \param [in] trees_src The source trees structure.228* \param [in] lnum_trees The total number of trees stored in \a trees_src.229* \param [in] lnum_ghosts The total number of ghosts stored in \a trees_src.230*/231void232t8_cmesh_trees_copy_toproc (t8_cmesh_trees_t trees_dest, t8_cmesh_trees_t trees_src, t8_locidx_t lnum_trees,233t8_locidx_t lnum_ghosts);234235/** Copy the trees array from one part to another.236* \param [in,out] trees_dest The trees struct of the destination part.237* \param [in] part_dest The index of the destination part. Must be initialized238* by \ref t8_cmesh_trees_start_part with alloc = 0.239* \param [in] trees_src The trees struct of the source part.240* \param [in] part_src The index of the destination part.241* Must be a valid part, thus \ref t8_cmesh_trees_finish_part242* must have been called.243*/244void245t8_cmesh_trees_copy_part (t8_cmesh_trees_t trees_dest, int part_dest, t8_cmesh_trees_t trees_src, int part_src);246247/** Add a tree to a trees structure.248* \param [in,out] trees The trees structure to be updated.249* \param [in] ltree_id The local id of the tree to be inserted.250* \param [in] proc The mpirank of the process from which the tree was251* received.252* \param [in] eclass The tree's element class.253*/254void255t8_cmesh_trees_add_tree (t8_cmesh_trees_t trees, t8_locidx_t ltree_id, int proc, t8_eclass_t eclass);256257/** Add a ghost to a trees structure.258* \param [in,out] trees The trees structure to be updated.259* \param [in] lghost_index The index in the part array of the ghost to be inserted.260* \param [in] gtree_id The global index of the ghost.261* \param [in] proc The mpirank of the process from which the ghost was262* received.263* \param [in] eclass The ghost's element class.264* \param [in] num_local_trees The number of local trees in the cmesh.265*/266void267t8_cmesh_trees_add_ghost (t8_cmesh_trees_t trees, t8_locidx_t lghost_index, t8_gloidx_t gtree_id, int proc,268t8_eclass_t eclass, t8_locidx_t num_local_trees);269270/** Set all neighbor fields of all local trees and ghosts to boundary.271* \param [in,out] cmesh The associated cmesh.272* \param [in,out] trees The trees structure.273* A face f of tree t counts as boundary if the face-neighbor is also t274* at face f.275*/276void277t8_cmesh_trees_set_all_boundary (t8_cmesh_t cmesh, t8_cmesh_trees_t trees);278279/**280* Return the part data of a trees struct.281*282* \param[in] trees The trees structure to be queried.283* \param[in] proc The part number to be queried.284* \param[out] first_tree The local id of the first tree in the part.285* \param[out] num_trees The number of trees in the part.286* \param[out] first_ghost The local id of the first ghost in the part.287* \param[out] num_ghosts The number of ghosts in the part.288*/289void290t8_cmesh_trees_get_part_data (t8_cmesh_trees_t trees, int proc, t8_locidx_t *first_tree, t8_locidx_t *num_trees,291t8_locidx_t *first_ghost, t8_locidx_t *num_ghosts);292293/* TODO: This function returns NULL if the tree is not present.294* So far no error checking is done here. */295/** Return a pointer to a specific tree in a trees struct.296* \param [in] trees The tress structure where the tree is to be looked up.297* \param [in] ltree The local id of the tree.298* \return A pointer to the tree with local id \a tree.299*/300t8_ctree_t301t8_cmesh_trees_get_tree (t8_cmesh_trees_t trees, t8_locidx_t ltree);302303/** Return a pointer to a specific tree in a trees struct plus pointers to304* its face_neighbor and tree_to_face arrays.305* \param [in] trees The trees structure where the tree is to be looked up.306* \param [in] ltree_id The local id of the tree.307* \param [out] face_neigh If not NULL a pointer to the trees face_neighbor308* array is stored here on return.309* \param [out] ttf If not NULL a pointer to the trees tree_to_face310* array is stored here on return.311* \return A pointer to the tree with local id \a tree.312*/313t8_ctree_t314t8_cmesh_trees_get_tree_ext (t8_cmesh_trees_t trees, t8_locidx_t ltree_id, t8_locidx_t **face_neigh, int8_t **ttf);315316/** Return the face neighbor of a tree at a given face and return the tree_to_face info317* \param [in] trees The trees structure where the tree is to be looked up.318* \param [in] ltreeid The local id of the tree.319* \param [in] face A face of the tree.320* \param [out] ttf If not NULL the tree_to_face value of the face connection.321* \return The face neighbor that is stored for this face322*/323t8_locidx_t324t8_cmesh_trees_get_face_info (t8_cmesh_trees_t trees, t8_locidx_t ltreeid, int face, int8_t *ttf);325326/** Given a coarse tree and a face number, return the local id of the neighbor tree.327* \param [in] tree The coarse tree.328* \param [in] face The face number.329* \return The local id of the neighbor tree. */330t8_locidx_t331t8_cmesh_trees_get_face_neighbor (const t8_ctree_t tree, const int face);332333/** Given a coarse tree and a face number, return the local id of the neighbor tree334* together with its tree-to-face info.335* \param [in] tree The coarse tree.336* \param [in] face The face number.337* \param [out] ttf If not NULL it is filled with the tree-to-face value338* for this face.339* \return The local id of the neighbor tree. */340t8_locidx_t341t8_cmesh_trees_get_face_neighbor_ext (const t8_ctree_t tree, const int face, int8_t *ttf);342343/** Given a coarse ghost and a face number, return the local id of the neighbor tree344* together with its tree-to-face info.345* \param [in] ghost The coarse ghost.346* \param [in] face The face number.347* \param [out] ttf If not NULL it is filled with the tree-to-face value348* for this face.349* \return The global id of the neighbor tree. */350t8_gloidx_t351t8_cmesh_trees_get_ghost_face_neighbor_ext (const t8_cghost_t ghost, const int face, int8_t *ttf);352353/* TODO: This function returns NULL if the ghost is not present.354* So far no error checking is done here. */355/** Return a pointer to a specific ghost in a trees struct.356* \param [in] trees The tress structure where the tree is to be looked up.357* \param [in] lghost The local id of the ghost.358* \return A pointer to the ghost with local id \a ghost.359*/360t8_cghost_t361t8_cmesh_trees_get_ghost (t8_cmesh_trees_t trees, t8_locidx_t lghost);362363/** Return a pointer to a specific ghost in a trees struct plus pointers to364* its face_neighbor and tree_to_face arrays.365* \param [in] trees The trees structure where the ghost is to be looked up.366* \param [in] lghost_id The local id of the ghost.367* \param [out] face_neigh If not NULL a pointer to the ghosts face_neighbor368* array is stored here on return.369* \param [out] ttf If not NULL a pointer to the ghosts tree_to_face370* array is stored here on return.371* \return A pointer to the tree with local id \a tree.372*/373t8_cghost_t374t8_cmesh_trees_get_ghost_ext (t8_cmesh_trees_t trees, t8_locidx_t lghost_id, t8_gloidx_t **face_neigh, int8_t **ttf);375376/** Given the global tree id of a ghost tree in a trees structure,377* return its local ghost id.378* \param [in] trees The trees structure.379* \param [in] global_id A global tree id.380* \return The local id of the tree \a global_id if it is a ghost381* in \a trees. A negative number if it isn't.382* The local id is a number l with383* num_local_trees <= \a l < num_local_trees + num_ghosts384*/385t8_locidx_t386t8_cmesh_trees_get_ghost_local_id (t8_cmesh_trees_t trees, t8_gloidx_t global_id);387388/**389* Return the total size in bytes of a trees structure.390*391* \param [in] trees The trees structure.392* \return The total size in bytes of \a trees.393*/394size_t395t8_cmesh_trees_size (t8_cmesh_trees_t trees);396397/** For one tree in a trees structure set the number of attributes398* and temporarily store the total size of all of this tree's attributes.399* This temporary value is used in \ref t8_cmesh_trees_finish_part.400* \param [in,out] trees The trees structure to be updated.401* \param [in] ltree_id The local id of one tree in \a trees.402* \param [in] num_attributes The number of attributes of this tree.403* \param [in] attr_bytes The total number of bytes of all attributes404* of this tree.405*/406void407t8_cmesh_trees_init_attributes (t8_cmesh_trees_t trees, t8_locidx_t ltree_id, size_t num_attributes, size_t attr_bytes);408409/** Return an attribute that is stored at a tree.410* \param [in] trees The trees structure.411* \param [in] ltree_id The local id of the tree whose attribute is querid.412* \param [in] package_id The package identifier of the attribute.413* \param [in] key The key of the attribute within all attributes of414* the same package identifier.415* \param [out] size If not NULL, the size (in bytes) of the attribute416* will be stored here.417* \param [in] is_ghost If true, then \a ltree_id is interpreted as the local_id418* of a ghost.419* \return A pointer to the queried attribute, NULL if the attribute420* does not exist.421*/422void *423t8_cmesh_trees_get_attribute (const t8_cmesh_trees_t trees, const t8_locidx_t ltree_id, const int package_id,424const int key, size_t *size, int is_ghost);425426/** Return the total size of all attributes stored at a specified tree.427* \param [in] tree A tree structure.428* \return The total size (in bytes) of the attributes of \a tree.429*/430size_t431t8_cmesh_trees_attribute_size (t8_ctree_t tree);432433/** Return the total size of all attributes stored at a specified ghost.434* \param [in] ghost A ghost structure.435* \return The total size (in bytes) of the attributes of \a ghost.436*/437size_t438t8_cmesh_trees_ghost_attribute_size (t8_cghost_t ghost);439440/* TODO: Currently there is a bug that forces us to give each tree an attribute */441/* TODO: this uses char * and cmesh_set_attribute uses void *. Unify! */442/* attr_tree_index is index of attr in tree's attribute array.443* We assume that the attributes are already sorted! */444/**445* Add an attribute to a tree.446*447* \param [in,out] trees The trees structure, whose attribute array is updated.448* \param [in] proc The process id of the process that owns the tree.449* \param [in] attr The stash attribute that is added.450* \param [in] tree_id The local id of the tree to which the attribute is added.451* \param [in] index The attribute index of the attribute to be added.452*/453void454t8_cmesh_trees_add_attribute (const t8_cmesh_trees_t trees, int proc, const t8_stash_attribute_struct_t *attr,455t8_locidx_t tree_id, size_t index);456457/** Add the next ghost attribute from stash to the correct position in the char pointer structure458* Since it is created from stash, all attributes are added to part 0.459* The following attribute offset gets updated already.460* \param [in,out] trees The trees structure, whose char array is updated.461* \param [in] attr The stash attribute that is added.462* \param [in] local_ghost_id The local ghost id.463* \param [in] ghosts_inserted The number of ghost that were already inserted, so that we do not write over the end.464* \param [in] index The attribute index of the attribute to be added.465*/466467void468t8_cmesh_trees_add_ghost_attribute (const t8_cmesh_trees_t trees, const t8_stash_attribute_struct_t *attr,469t8_locidx_t local_ghost_id, t8_locidx_t ghosts_inserted, size_t index);470471/** Return the number of parts of a trees structure.472* \param [in] trees The trees structure.473* \return The number of parts in \a trees.474*/475size_t476t8_cmesh_trees_get_numproc (const t8_cmesh_trees_t trees);477478/** Compute the tree-to-face information given a face and orientation value479* of a face connection.480* \param [in] dimension The dimension of the corresponding eclasses.481* \param [in] face A face number482* \param [in] orientation A face-to-face orientation.483* \return The tree-to-face entry corresponding to the face/orientation combination.484* It is computed as t8_eclass_max_num_faces[dimension] * orientation + face485*/486int8_t487t8_cmesh_tree_to_face_encode (const int dimension, const t8_locidx_t face, const int orientation);488489/** Given a tree-to-face value, get its encoded face number and orientation.490* \param [in] dimension The dimension of the corresponding eclasses.491* \param [in] tree_to_face A tree-to-face value492* \param [out] face On output filled with the stored face value.493* \param [out] orientation On output filled with the stored orientation value.494* \note This function is the inverse operation of \ref t8_cmesh_tree_to_face_encode495* If F = t8_eclass_max_num_faces[dimension], we get496* orientation = tree_to_face / F497* face = tree_to_face % F498*/499void500t8_cmesh_tree_to_face_decode (const int dimension, const int8_t tree_to_face, int *face, int *orientation);501502// TODO: To fit to the interface a trees struct is given as parameter here,503// however we could just take the one associated to the cmesh given.504/** Print the trees,ghosts and their neighbors in ASCII format t stdout.505* This function is used for debugging purposes.506* \param [in] cmesh A coarse mesh structure that must be committed.507* \param [in] trees The trees structure of \a cmesh.508*/509void510t8_cmesh_trees_print (t8_cmesh_t cmesh, t8_cmesh_trees_t trees);511512/** Broadcast an existing valid trees structure from a root rank to513* all other ranks.514* The trees structure must belong to cmeshes whose meta_information is515* already set. \ref t8_cmesh_bcast.516* \param [in] cmesh_in On \a root a committed, replicated cmesh.517* On the other ranks an initialized cmesh with518* the same number of trees as on \a root.519* \param [in] root The rank that broadcasts \a cmesh_in to all520* other ranks.521* \param [in] comm MPI communicator to use.522*/523void524t8_cmesh_trees_bcast (t8_cmesh_t cmesh_in, int root, sc_MPI_Comm comm);525526/** Check whether the face connection of a trees structure are consistent.527* That is if tree1 lists tree2 as neighbor at face i with ttf entries (or,face j),528* then tree2 must list tree1 as neighbor at face j with ttf entries (or, face i).529* \param[in] cmesh A cmesh structure to be checked.530* \param[in] trees The cmesh's trees struct.531* \return True if the face connections are consistent,532* False if not.533*/534int535t8_cmesh_trees_is_face_consistent (t8_cmesh_t cmesh, t8_cmesh_trees_t trees);536537/**538* Check whether two trees structures are equal.539* \param [in] cmesh The coarse mesh structure that contains the trees.540* \param [in] trees_a A trees structure to be compared.541* \param [in] trees_b A trees structure to be compared.542* \return 0 if the trees structures are equal, 1 if they are not equal.543*/544int545t8_cmesh_trees_is_equal (t8_cmesh_t cmesh, t8_cmesh_trees_t trees_a, t8_cmesh_trees_t trees_b);546547/** Free all memory allocated with a trees structure.548* This means that all coarse trees and ghosts, their face neighbor entries549* and attributes and the additional structures of trees are freed.550* \param [in,out] trees The tree structure to be destroyed. Set to NULL on output.551*/552void553t8_cmesh_trees_destroy (t8_cmesh_trees_t *trees);554555T8_EXTERN_C_END ();556557#endif /* !T8_CMESH_PART_TREE_H */558559560