Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions mesh_handle/competence_pack.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ using all_cache_competences
= competence_pack<cache_volume, cache_diameter, cache_vertex_coordinates, cache_centroid, cache_face_areas,
cache_face_centroids, cache_face_normals, cache_neighbors>;

/** Empty competence pack. */
using no_competences = competence_pack<>;

/** Predefined competence pack combining all competences related to faces. */
using cache_face_competences
= competence_pack<cache_face_areas, cache_face_centroids, cache_face_normals, cache_neighbors>;
Expand Down
57 changes: 57 additions & 0 deletions mesh_handle/mesh.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include "element.hxx"
#include "competence_pack.hxx"
#include "adapt.hxx"
#include "t8_forest/t8_forest_balance.h"
#include "t8_forest/t8_forest_types.h"
#include <t8_forest/t8_forest_general.h>
#include <t8_forest/t8_forest_ghost.h>
#include <vector>
Expand Down Expand Up @@ -163,6 +165,17 @@ class mesh {
return m_forest;
}

/** Check if the local elements of the mesh are balanced.
* The mesh is said to be balanced if each element has face neighbors of level
* at most +1 or -1 of the element's level.
* \return true if the local elements are balanced, false otherwise.
*/
bool
is_balanced ()
{
return t8_forest_is_balanced (m_forest);
}

// --- Methods to access elements. ---
/**
* Returns a constant iterator to the first (local) mesh element.
Expand Down Expand Up @@ -277,6 +290,50 @@ class mesh {
t8_forest_set_adapt (m_uncommitted_forest.value (), m_forest, detail::mesh_adapt_callback_wrapper, recursive);
}

/** If this function is called, the mesh will be partitioned on committing.
* The partitioning is done according to the SFC and each rank is assigned
* the same (maybe +1) number of elements.
* \note The partition is carried out only when \ref commit is called.
* \note This setting can be combined with \ref set_adapt and \ref set_balance. The order in which
* these operations are executed is always 1) Adapt 2) Partition 3) Balance.
* \param [in] set_for_coarsening If true, the partitions are choose such that coarsening
* an element once is a process local operation. Default is false.
*/
void
set_partition (bool set_for_coarsening = false)
{
if (!m_uncommitted_forest.has_value ()) {
t8_forest_t new_forest;
t8_forest_init (&new_forest);
m_uncommitted_forest = new_forest;
}
t8_forest_set_partition (m_uncommitted_forest.value (), m_forest, set_for_coarsening);
}

/** If this function is called, the mesh will be balanced on committing.
* The mesh is said to be balanced if each element has face neighbors of level
* at most +1 or -1 of the element's level.
* \note The balance is carried out only when \ref commit is called.
* \param [in] no_repartition Balance constructs several intermediate steps that
* are refined from each other. In order to maintain a balanced load, a repartitioning is performed in each
* round and the resulting mesh is load-balanced per default.
* Set \a no_repartition to true if this behaviour is not desired.
* If \a no_repartition is false (default), an additional call of \ref set_partition is not necessary.
* \note This setting can be combined with \ref set_adapt and \ref set_partition. The order in which
* these operations are executed is always 1) Adapt 2) Partition 3) Balance.
*/
void
set_balance (bool no_repartition = false)
{
if (!m_uncommitted_forest.has_value ()) {
t8_forest_t new_forest;
t8_forest_init (&new_forest);
m_uncommitted_forest = new_forest;
}
// Disable repartitioning and let the user call set_partition if desired.
t8_forest_set_balance (m_uncommitted_forest.value (), m_forest, no_repartition);
}

/** Enable or disable the creation of a layer of ghost elements.
* \param [in] do_ghost If true a ghost layer will be created.
* \param [in] ghost_type Controls which neighbors count as ghost elements,
Expand Down
92 changes: 92 additions & 0 deletions mesh_handle/mesh_io.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
This file is part of t8code.
t8code is a C library to manage a collection (a forest) of multiple
connected adaptive space-trees of general element classes in parallel.

Copyright (C) 2026 the developers

t8code is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

t8code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with t8code; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

/** \file mesh_io.hxx
* In- and output of meshes. For example, writing a mesh to vtk format.
*/

#pragma once
#include <t8_forest/t8_forest_io.h>
namespace t8_mesh_handle
{

/**
* Write the mesh in a parallel vtu format. Extended version.
* See \see write_mesh_to_vtk for the standard version of this function.
* Writes one master .pvtu file and each process writes in its own .vtu file.
* If linked and not otherwise specified, the VTK API is used.
* If the VTK library is not linked, an ASCII file is written.
* This may change in accordance with \a write_ghosts, \a write_curved and
* \a do_not_use_API, because the export of ghosts is not yet available with
* the VTK API and the export of curved elements is not available with the
* inbuilt function to write ASCII files. The function will for example
* still use the VTK API to satisfy \a write_curved, even if \a do_not_use_API
* is set to true.
* This function is collective and must be called on each process.
* \param [in] mesh The mesh to write.
* \param [in] fileprefix The prefix of the files where the vtk will be stored.
* The master file is then fileprefix.pvtu and the process with rank r writes in the file fileprefix_r.vtu.
* \param [in] num_data Number of user defined double valued data fields to write.
* \param [in] data Array of t8_vtk_data_field_t of length \a num_data providing the user defined
* per element data. If scalar and vector fields are used, all scalar fields must come first in the array.
* \param [in] write_treeid If true, the global tree id of the underlying forest is written for each element.
* \param [in] write_mpirank If true, the mpirank is written for each element.
* \param [in] write_level If true, the refinement level is written for each element.
* \param [in] write_element_id If true, the global element id is written for each element.
* \param [in] write_ghosts If true, each process additionally writes its ghost elements.
* For ghost element the treeid of the underlying forest is -1.
* \param [in] write_curved If true, write the elements as curved element types from vtk.
* \param [in] do_not_use_API Do not use the VTK API, even if linked and available.
* \return True if successful, false if not (process local).
*/
template <typename TMeshClass>
int
write_mesh_to_vtk_ext (TMeshClass &mesh, const char *fileprefix, const int num_data, t8_vtk_data_field_t *data,
bool write_treeid = false, bool write_mpirank = true, bool write_level = true,
bool write_element_id = true, bool write_ghosts = false, bool write_curved = false,
bool do_not_use_API = false)
{
return t8_forest_write_vtk_ext (mesh->get_forest (), fileprefix, write_treeid, write_mpirank, write_level,
write_element_id, write_ghosts, write_curved, do_not_use_API, num_data, data);
}

/**
* Write the mesh in a parallel vtu format. Writes one master
* .pvtu file and each process writes in its own .vtu file.
* If linked, the VTK API is used.
* If the VTK library is not linked, an ASCII file is written.
* This function writes the elements, level, mpirank, element id and the tree id of the underlying forest as data.
* This function is collective and must be called on each process.
* For more options use \see write_mesh_to_vtk_ext.
* \param [in] mesh The mesh to write.
* \param [in] fileprefix The prefix of the files where the vtk will be stored.
* The master file is then fileprefix.pvtu and the process with rank r writes in the file fileprefix_r.vtu.
* \return True if successful, false if not (process local).
*/
template <typename TMeshClass>
int
write_mesh_to_vtk (TMeshClass &mesh, const char *fileprefix)
{
return t8_forest_write_vtk (mesh->get_forest (), fileprefix);
}

} // namespace t8_mesh_handle
14 changes: 7 additions & 7 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,11 @@ endif()
add_t8_cpp_test( NAME t8_gtest_vector_split_serial SOURCES t8_helper_functions/t8_gtest_vector_split.cxx )

if( T8CODE_BUILD_MESH_HANDLE )
add_t8_cpp_test( NAME t8_gtest_mesh_handle_parallel SOURCES mesh_handle/t8_gtest_mesh_handle.cxx )
add_t8_cpp_test( NAME t8_gtest_compare_handle_to_forest_serial SOURCES mesh_handle/t8_gtest_compare_handle_to_forest.cxx )
add_t8_cpp_test( NAME t8_gtest_handle_ghost_parallel SOURCES mesh_handle/t8_gtest_ghost.cxx )
add_t8_cpp_test( NAME t8_gtest_custom_competence_serial SOURCES mesh_handle/t8_gtest_custom_competence.cxx )
add_t8_cpp_test( NAME t8_gtest_cache_competence_serial SOURCES mesh_handle/t8_gtest_cache_competence.cxx )
add_t8_cpp_test( NAME t8_gtest_handle_data_parallel SOURCES mesh_handle/t8_gtest_handle_data.cxx )
add_t8_cpp_test( NAME t8_gtest_handle_adapt_serial SOURCES mesh_handle/t8_gtest_adapt.cxx )
add_t8_cpp_test( NAME t8_gtest_mesh_handle_parallel SOURCES mesh_handle/t8_gtest_mesh_handle.cxx )
add_t8_cpp_test( NAME t8_gtest_compare_handle_to_forest_serial SOURCES mesh_handle/t8_gtest_compare_handle_to_forest.cxx )
add_t8_cpp_test( NAME t8_gtest_handle_ghost_parallel SOURCES mesh_handle/t8_gtest_ghost.cxx )
add_t8_cpp_test( NAME t8_gtest_custom_competence_serial SOURCES mesh_handle/t8_gtest_custom_competence.cxx )
add_t8_cpp_test( NAME t8_gtest_cache_competence_serial SOURCES mesh_handle/t8_gtest_cache_competence.cxx )
add_t8_cpp_test( NAME t8_gtest_handle_data_parallel SOURCES mesh_handle/t8_gtest_handle_data.cxx )
add_t8_cpp_test( NAME t8_gtest_adapt_partition_balance_parallel SOURCES mesh_handle/t8_gtest_adapt_partition_balance.cxx )
endif()
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,19 @@ along with t8code; if not, write to the Free Software Foundation, Inc.,
*/

/**
* \file t8_gtest_adapt.cxx
* Tests for the adapt routines of mesh handles.
* This tests uses the callback and user data of tutorial step 3 as example.
* \file t8_gtest_adapt_partition_balance.cxx
* Tests for the adapt, partition and balance routines of mesh handles.
* For the adapt routine, we use the callback and user data of tutorial step 3 as example.
* The adaptation criterion is to look at the midpoint coordinates of the current element and if
* they are inside a sphere around a given midpoint we refine, if they are outside, we coarsen.
* The test compares the results of the mesh handle to a forest adapted with the same criterion and balanced and partitioned similarly.
* Therefore, the check is based on the assumption that the forest functionality works as intended and is tested elsewhere.
*/
#include <gtest/gtest.h>
#include <t8.h>

#include <mesh_handle/mesh.hxx>
#include <mesh_handle/competence_pack.hxx>
#include <mesh_handle/adapt.hxx>
#include <t8_cmesh/t8_cmesh.h>
#include <t8_cmesh/t8_cmesh_examples.h>
#include <t8_forest/t8_forest_general.h>
Expand Down Expand Up @@ -98,8 +99,9 @@ forest_adapt_callback_example (t8_forest_t forest, t8_forest_t forest_from, t8_l
return 0;
}

/** Test the adapt routine of a mesh handle.
* We compare the result to a classically adapted forest with similar callback.
/** Test the adapt partition and balance routine of a mesh handle.
* The test compares the results of the mesh handle to a forest adapted with the same criterion and balanced and partitioned similarly.
* Therefore, the check is based on the assumption that the forest functionality works as intended and is tested elsewhere.
*/
TEST (t8_gtest_handle_adapt, compare_adapt_with_forest)
{
Expand All @@ -124,11 +126,29 @@ TEST (t8_gtest_handle_adapt, compare_adapt_with_forest)
mesh_class::mesh_adapt_callback_wrapper<dummy_user_data> (adapt_callback_test<mesh_class>, user_data), false);
mesh_handle.commit ();
// Adapt forest classically.
forest = t8_forest_new_adapt (forest, forest_adapt_callback_example, 0, 1, &user_data);
forest = t8_forest_new_adapt (forest, forest_adapt_callback_example, 0, 0, &user_data);

// Compare results.
EXPECT_TRUE (t8_forest_is_equal (mesh_handle.get_forest (), forest));

// Adapt the mesh handle again and apply partition and balance.
mesh_handle.set_balance ();
mesh_handle.set_partition ();
mesh_handle.set_adapt (
mesh_class::mesh_adapt_callback_wrapper<dummy_user_data> (adapt_callback_test<mesh_class>, user_data), false);
mesh_handle.commit ();
EXPECT_TRUE (mesh_handle.is_balanced ());

// Compare the results again to an appropriate forest.
t8_forest_t forest_compare;
t8_forest_init (&forest_compare);
t8_forest_set_user_data (forest_compare, &user_data);
t8_forest_set_adapt (forest_compare, forest, forest_adapt_callback_example, false);
t8_forest_set_partition (forest_compare, NULL, false);
t8_forest_set_balance (forest_compare, NULL, false);
t8_forest_commit (forest_compare);
EXPECT_TRUE (t8_forest_is_equal (mesh_handle.get_forest (), forest_compare));

// Clean up.
t8_forest_unref (&forest);
t8_forest_unref (&forest_compare);
}
12 changes: 11 additions & 1 deletion tutorials/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ function( add_t8_tutorial )
set(TUTORIAL_BUILD_DIR "${CMAKE_BINARY_DIR}/${TUTORIAL_RELATIVE_DIR}")

add_executable( ${ADD_T8_TUTORIAL_NAME} ${ADD_T8_TUTORIAL_SOURCES} )
target_link_libraries( ${ADD_T8_TUTORIAL_NAME} PRIVATE T8 SC::SC )
target_link_libraries( ${ADD_T8_TUTORIAL_NAME} PRIVATE T8 SC::SC)

string( FIND ${ADD_T8_TUTORIAL_NAME} "mesh_handle" is_mesh_handle_file )
if ( (${is_mesh_handle_file} GREATER_EQUAL 0) )
target_link_libraries(${ADD_T8_TUTORIAL_NAME} PRIVATE T8_MESH_HANDLE )
endif ()

target_include_directories( ${ADD_T8_TUTORIAL_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/.. )

set_target_properties(${ADD_T8_TUTORIAL_NAME} PROPERTIES
Expand Down Expand Up @@ -69,3 +75,7 @@ copy_tutorial_file (features/t8_features_curved_meshes_generate_cmesh_hex.geo)
copy_tutorial_file (features/t8_features_curved_meshes_generate_cmesh_quad.geo)
copy_tutorial_file (features/t8_features_curved_meshes_generate_cmesh_tet.geo)
copy_tutorial_file (features/t8_features_curved_meshes_generate_cmesh_tri.geo)

if( T8CODE_BUILD_MESH_HANDLE )
add_t8_tutorial( NAME t8_step5_mesh_handle SOURCES general/t8_step5_mesh_handle.cxx )
endif()
Loading
Loading