From f231c85ab45780f984c604eabdbaa28f8e2177d3 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 24 Jun 2026 16:45:52 +0200 Subject: [PATCH 01/11] try reading the platform BUFSIZ from t8_vtk_data_field_t --- examples/t8_brick_partition_balance_ghost.jl | 202 +++++++++++++++++++ examples/t8_step5_element_data.jl | 14 +- examples/t8_step6_stencil.jl | 12 +- src/T8code.jl | 3 + 4 files changed, 217 insertions(+), 14 deletions(-) create mode 100644 examples/t8_brick_partition_balance_ghost.jl diff --git a/examples/t8_brick_partition_balance_ghost.jl b/examples/t8_brick_partition_balance_ghost.jl new file mode 100644 index 0000000..f41ae32 --- /dev/null +++ b/examples/t8_brick_partition_balance_ghost.jl @@ -0,0 +1,202 @@ +using MPI +using T8code +using T8code.Libt8: sc_init +using T8code.Libt8: sc_finalize +using T8code.Libt8: SC_LP_ESSENTIAL +using T8code.Libt8: SC_LP_PRODUCTION + + +# Print the local and global number of elements of a forest. +function t8_step3_print_forest_information(forest) + # Check that forest is a committed, that is valid and usable, forest. + @T8_ASSERT(t8_forest_is_committed(forest)==1) + + # Get the local number of elements. + local_num_elements = t8_forest_get_local_num_leaf_elements(forest) + # Get the global number of elements. + global_num_elements = t8_forest_get_global_num_leaf_elements(forest) + + t8_global_productionf(" [step3] Local number of elements:\t\t%i\n", local_num_elements) + t8_global_productionf(" [step3] Global number of elements:\t%li\n", global_num_elements) +end + + +# Gather the 3x3 stencil for each element and compute finite difference approximations +# for schlieren and curvature of the stored heights in the elements. +function t8_traverse_forest(forest, comm) + # Check that forest is a committed, that is valid and usable, forest. + @T8_ASSERT(t8_forest_is_committed(forest)==1) + + # Get the number of trees that have elements of this process. + num_local_trees = t8_forest_get_num_local_trees(forest) + + scheme = t8_forest_get_scheme(forest) + + # Loop over all local trees in the forest. + for itree in 0:(num_local_trees - 1) + tree_class = t8_forest_get_tree_class(forest, itree) + num_elements_in_tree = t8_forest_get_tree_num_leaf_elements(forest, itree) + + # Loop over all local elements in the tree. + for ielement in 0:(num_elements_in_tree - 1) + + element = t8_forest_get_leaf_element_in_tree(forest, itree, ielement) + + level = t8_element_get_level(scheme, tree_class, element) + + # Loop over all faces of an element. + num_faces = t8_element_get_num_faces(scheme, tree_class, element) + for iface in 1:num_faces + neighids_ref = Ref{Ptr{t8_locidx_t}}() + neighbors_ref = Ref{Ptr{Ptr{t8_element}}}() + neigh_scheme_ref = Ref{t8_eclass_t}() + + dual_faces_ref = Ref{Ptr{Cint}}() + num_neighbors_ref = Ref{Cint}() + + t8_forest_leaf_face_neighbors(forest, itree, element, + neighbors_ref, iface - 1, dual_faces_ref, + num_neighbors_ref, + neighids_ref, neigh_scheme_ref) + + num_neighbors = num_neighbors_ref[] + dual_faces = 1 .+ unsafe_wrap(Array, dual_faces_ref[], num_neighbors) + neighids = 1 .+ unsafe_wrap(Array, neighids_ref[], num_neighbors) + neighbors = unsafe_wrap(Array, neighbors_ref[], num_neighbors) + neigh_scheme = neigh_scheme_ref[] + + if num_neighbors > 0 + neighbor_level = t8_element_get_level(scheme, neigh_scheme, + neighbors[1]) + @info MPI.Comm_rank(comm), itree, ielement, iface, level, neighbor_level + end + + # Free allocated memory. + t8_free(dual_faces_ref[]) + t8_free(neighbors_ref[]) + t8_free(neighids_ref[]) + end + end + end +end + + +# In this function we create a new forest that repartitions a given forest +# and has a layer of ghost elements. +function t8_step4_partition_ghost(forest) + # Check that forest is a committed, that is a valid and usable, forest. + @T8_ASSERT(t8_forest_is_committed(forest)==1) + + # Initialize. + new_forest_ref = Ref(t8_forest_t()) + t8_forest_init(new_forest_ref) + new_forest = new_forest_ref[] + + # Tell the new_forest that is should partition the existing forest. + # This will change the distribution of the forest elements among the processes + # in such a way that afterwards each process has the same number of elements + # (+- 1 if the number of elements is not divisible by the number of processes). + # + # The third 0 argument is the flag 'partition_for_coarsening' which is currently not + # implemented. Once it is, this will ensure that a family of elements will not be split + # across multiple processes and thus one level coarsening is always possible (see also the + # comments on coarsening in t8_step3). + t8_forest_set_partition(new_forest, forest, 1) + + # Tell the new_forest to create a ghost layer. + # This will gather those face neighbor elements of process local element that reside + # on a different process. + # + # We currently support ghost mode T8_GHOST_FACES that creates face neighbor ghost elements + # and will in future also support other modes for edge/vertex neighbor ghost elements. + t8_forest_set_ghost(new_forest, 1, T8_GHOST_FACES) + + # Commit the forest, this step will perform the partitioning and ghost layer creation. + t8_forest_commit(new_forest) + + return new_forest +end + +# In this function we adapt a forest as in step3 and balance it. In our main +# program the input forest is already adapted and then the resulting twice +# adapted forest will be unbalanced. +function t8_step4_balance(forest) + + # Initialize new forest. + balanced_forest_ref = Ref(t8_forest_t()) + t8_forest_init(balanced_forest_ref) + balanced_forest = balanced_forest_ref[] + + # Specify that this forest should result from balancing unbalanced_forest. + # The last argument is the flag 'no_repartition'. + # Since balancing will refine elements, the load-balance will be broken afterwards. + # Setting this flag to false (no_repartition = false -> yes repartition) will repartition + # the forest after balance, such that every process has the same number of elements afterwards. + t8_forest_set_balance(balanced_forest, forest, 1) + t8_forest_set_ghost(balanced_forest, 1, T8_GHOST_FACES) + + # Commit the forest. + t8_forest_commit(balanced_forest) + + return balanced_forest +end + +#include("t8_step3_common.jl") + + + + +# The uniform refinement level of the forest. +level = 0 + +# Initialize MPI. This has to happen before we initialize sc or t8code. +mpiret = MPI.Init() + +# We will use MPI_COMM_WORLD as a communicator. +comm = MPI.COMM_WORLD + +# Initialize the sc library, has to happen before we initialize t8code. +sc_init(comm, 0, 1, C_NULL, SC_LP_ESSENTIAL) + +# Initialize t8code with log level SC_LP_PRODUCTION. See sc.h for more info on the log levels. +t8_init(SC_LP_PRODUCTION) + + +# Build a cube cmesh with tet, hex, and prism trees. +cmesh = t8_cmesh_new_brick_2d(3, 7, 0, 0, comm) +t8_global_productionf(" [step4] Created coarse mesh.\n") + +forest = t8_forest_new_uniform(cmesh, t8_scheme_new_default(), level, 1, comm) + +# Print information of the forest. +t8_step3_print_forest_information(forest); + + + +# +# Balance +# +forest = t8_step4_balance(forest) +t8_global_productionf(" [step4] Balanced forest.\n") +t8_step3_print_forest_information(forest) + + +# +# Partition and create ghost elements. +# +forest = t8_step4_partition_ghost(forest) + +t8_global_productionf(" [step4] Repartitioned forest and built ghost layer.\n") +t8_step3_print_forest_information(forest) + + +t8_traverse_forest(forest, comm) + +# +# clean-up +# + +# Destroy the forest. +t8_forest_unref(Ref(forest)) + +sc_finalize() diff --git a/examples/t8_step5_element_data.jl b/examples/t8_step5_element_data.jl index 526ecb9..2b5092d 100644 --- a/examples/t8_step5_element_data.jl +++ b/examples/t8_step5_element_data.jl @@ -194,8 +194,10 @@ function t8_step5_output_data_to_vtu(forest, element_data, prefix) # WARNING: This code hangs for Julia v1.8.* or older. Use at least Julia v1.9. # For each user defined data field we need one t8_vtk_data_field_t variable. - vtk_data = t8_vtk_data_field_t(T8_VTK_SCALAR, # Set the type of this variable. Since we have one value per element, we pick T8_VTK_SCALAR. - NTuple{8192, Cchar}(rpad("Element volume\0", 8192, ' ')), # The name of the field as should be written to the file. + vtk_data = t8_vtk_data_field_t(T8_VTK_SCALAR, + # Sets the type of this variable. Since we have one value per element, we pick T8_VTK_SCALAR. + NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("Element volume\0", T8code.T8_BUFSIZ, ' ')), + # The name of the field as should be written to the file. pointer(element_volumes)) # To write user defined data, we need to extended output function @@ -277,11 +279,9 @@ if t8_forest_get_num_ghosts(forest) > 0 end # Output the volume data to vtu. -if !(CI_ON_WINDOWS || CI_ON_MACOS) - t8_step5_output_data_to_vtu(forest, element_data, prefix_forest_with_data) - t8_global_productionf(" [step5] Wrote forest and volume data to %s*.\n", - prefix_forest_with_data) -end +t8_step5_output_data_to_vtu(forest, element_data, prefix_forest_with_data) +t8_global_productionf(" [step5] Wrote forest and volume data to %s*.\n", + prefix_forest_with_data) # # Clean-up. diff --git a/examples/t8_step6_stencil.jl b/examples/t8_step6_stencil.jl index 6d3f338..6a72465 100644 --- a/examples/t8_step6_stencil.jl +++ b/examples/t8_step6_stencil.jl @@ -339,13 +339,13 @@ function t8_step6_output_data_to_vtu(forest, element_data, prefix) # WARNING: This code hangs for Julia v1.8.* or older. Use at least Julia v1.9. vtk_data = [ t8_vtk_data_field_t(T8_VTK_SCALAR, - NTuple{8192, Cchar}(rpad("height\0", 8192, ' ')), + NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("height\0", T8code.T8_BUFSIZ, ' ')), pointer(heights)), t8_vtk_data_field_t(T8_VTK_SCALAR, - NTuple{8192, Cchar}(rpad("schlieren\0", 8192, ' ')), + NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("schlieren\0", T8code.T8_BUFSIZ, ' ')), pointer(schlieren)), t8_vtk_data_field_t(T8_VTK_SCALAR, - NTuple{8192, Cchar}(rpad("curvature\0", 8192, ' ')), + NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("curvature\0", T8code.T8_BUFSIZ, ' ')), pointer(curvature)) ] @@ -402,10 +402,8 @@ t8_step6_exchange_ghost_data(forest, element_data) t8_step6_compute_stencil(forest, element_data) # Output the data to vtu files. -if !(CI_ON_WINDOWS || CI_ON_MACOS) - t8_step6_output_data_to_vtu(forest, element_data, prefix_forest_with_data) - t8_global_productionf(" Wrote forest and data to %s*.\n", prefix_forest_with_data) -end +t8_step6_output_data_to_vtu(forest, element_data, prefix_forest_with_data) +t8_global_productionf(" Wrote forest and data to %s*.\n", prefix_forest_with_data) # # Clean-up diff --git a/src/T8code.jl b/src/T8code.jl index 1075d53..3af3e90 100644 --- a/src/T8code.jl +++ b/src/T8code.jl @@ -258,6 +258,9 @@ macro T8_ASSERT(q) :($(esc(q)) ? nothing : throw(AssertionError($(string(q))))) end +# platform specific BUFSIZ used in t8_vtk_data_field_t +const T8_BUFSIZ = sizeof(t8_vtk_data_field_t.types[2]) + function t8_free(ptr) Libt8.sc_free(t8_get_package_id(), ptr) end From 9bfeb0d6e614b670fb6bcc0a180ad7e871dcd4f7 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 24 Jun 2026 16:46:59 +0200 Subject: [PATCH 02/11] remove CI check for Apple or Windows --- test/test_all.jl | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/test_all.jl b/test/test_all.jl index cfc21da..db46548 100644 --- a/test/test_all.jl +++ b/test/test_all.jl @@ -12,11 +12,6 @@ MPI.Init() comm = MPI.COMM_WORLD -# Check whether we run CI in the cloud with Windows or Mac, see also -# https://docs.github.com/en/actions/learn-github-actions/environment-variables -CI_ON_WINDOWS = (get(ENV, "GITHUB_ACTIONS", false) == "true") && Sys.iswindows() -CI_ON_MACOS = (get(ENV, "GITHUB_ACTIONS", false) == "true") && Sys.isapple() - @testset "init" begin include("test_init.jl") end From 853b481b9e27fa0bef21b4d1408d9a9d5f39b8d7 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 24 Jun 2026 16:48:39 +0200 Subject: [PATCH 03/11] remove accidentally added example --- examples/t8_brick_partition_balance_ghost.jl | 202 ------------------- 1 file changed, 202 deletions(-) delete mode 100644 examples/t8_brick_partition_balance_ghost.jl diff --git a/examples/t8_brick_partition_balance_ghost.jl b/examples/t8_brick_partition_balance_ghost.jl deleted file mode 100644 index f41ae32..0000000 --- a/examples/t8_brick_partition_balance_ghost.jl +++ /dev/null @@ -1,202 +0,0 @@ -using MPI -using T8code -using T8code.Libt8: sc_init -using T8code.Libt8: sc_finalize -using T8code.Libt8: SC_LP_ESSENTIAL -using T8code.Libt8: SC_LP_PRODUCTION - - -# Print the local and global number of elements of a forest. -function t8_step3_print_forest_information(forest) - # Check that forest is a committed, that is valid and usable, forest. - @T8_ASSERT(t8_forest_is_committed(forest)==1) - - # Get the local number of elements. - local_num_elements = t8_forest_get_local_num_leaf_elements(forest) - # Get the global number of elements. - global_num_elements = t8_forest_get_global_num_leaf_elements(forest) - - t8_global_productionf(" [step3] Local number of elements:\t\t%i\n", local_num_elements) - t8_global_productionf(" [step3] Global number of elements:\t%li\n", global_num_elements) -end - - -# Gather the 3x3 stencil for each element and compute finite difference approximations -# for schlieren and curvature of the stored heights in the elements. -function t8_traverse_forest(forest, comm) - # Check that forest is a committed, that is valid and usable, forest. - @T8_ASSERT(t8_forest_is_committed(forest)==1) - - # Get the number of trees that have elements of this process. - num_local_trees = t8_forest_get_num_local_trees(forest) - - scheme = t8_forest_get_scheme(forest) - - # Loop over all local trees in the forest. - for itree in 0:(num_local_trees - 1) - tree_class = t8_forest_get_tree_class(forest, itree) - num_elements_in_tree = t8_forest_get_tree_num_leaf_elements(forest, itree) - - # Loop over all local elements in the tree. - for ielement in 0:(num_elements_in_tree - 1) - - element = t8_forest_get_leaf_element_in_tree(forest, itree, ielement) - - level = t8_element_get_level(scheme, tree_class, element) - - # Loop over all faces of an element. - num_faces = t8_element_get_num_faces(scheme, tree_class, element) - for iface in 1:num_faces - neighids_ref = Ref{Ptr{t8_locidx_t}}() - neighbors_ref = Ref{Ptr{Ptr{t8_element}}}() - neigh_scheme_ref = Ref{t8_eclass_t}() - - dual_faces_ref = Ref{Ptr{Cint}}() - num_neighbors_ref = Ref{Cint}() - - t8_forest_leaf_face_neighbors(forest, itree, element, - neighbors_ref, iface - 1, dual_faces_ref, - num_neighbors_ref, - neighids_ref, neigh_scheme_ref) - - num_neighbors = num_neighbors_ref[] - dual_faces = 1 .+ unsafe_wrap(Array, dual_faces_ref[], num_neighbors) - neighids = 1 .+ unsafe_wrap(Array, neighids_ref[], num_neighbors) - neighbors = unsafe_wrap(Array, neighbors_ref[], num_neighbors) - neigh_scheme = neigh_scheme_ref[] - - if num_neighbors > 0 - neighbor_level = t8_element_get_level(scheme, neigh_scheme, - neighbors[1]) - @info MPI.Comm_rank(comm), itree, ielement, iface, level, neighbor_level - end - - # Free allocated memory. - t8_free(dual_faces_ref[]) - t8_free(neighbors_ref[]) - t8_free(neighids_ref[]) - end - end - end -end - - -# In this function we create a new forest that repartitions a given forest -# and has a layer of ghost elements. -function t8_step4_partition_ghost(forest) - # Check that forest is a committed, that is a valid and usable, forest. - @T8_ASSERT(t8_forest_is_committed(forest)==1) - - # Initialize. - new_forest_ref = Ref(t8_forest_t()) - t8_forest_init(new_forest_ref) - new_forest = new_forest_ref[] - - # Tell the new_forest that is should partition the existing forest. - # This will change the distribution of the forest elements among the processes - # in such a way that afterwards each process has the same number of elements - # (+- 1 if the number of elements is not divisible by the number of processes). - # - # The third 0 argument is the flag 'partition_for_coarsening' which is currently not - # implemented. Once it is, this will ensure that a family of elements will not be split - # across multiple processes and thus one level coarsening is always possible (see also the - # comments on coarsening in t8_step3). - t8_forest_set_partition(new_forest, forest, 1) - - # Tell the new_forest to create a ghost layer. - # This will gather those face neighbor elements of process local element that reside - # on a different process. - # - # We currently support ghost mode T8_GHOST_FACES that creates face neighbor ghost elements - # and will in future also support other modes for edge/vertex neighbor ghost elements. - t8_forest_set_ghost(new_forest, 1, T8_GHOST_FACES) - - # Commit the forest, this step will perform the partitioning and ghost layer creation. - t8_forest_commit(new_forest) - - return new_forest -end - -# In this function we adapt a forest as in step3 and balance it. In our main -# program the input forest is already adapted and then the resulting twice -# adapted forest will be unbalanced. -function t8_step4_balance(forest) - - # Initialize new forest. - balanced_forest_ref = Ref(t8_forest_t()) - t8_forest_init(balanced_forest_ref) - balanced_forest = balanced_forest_ref[] - - # Specify that this forest should result from balancing unbalanced_forest. - # The last argument is the flag 'no_repartition'. - # Since balancing will refine elements, the load-balance will be broken afterwards. - # Setting this flag to false (no_repartition = false -> yes repartition) will repartition - # the forest after balance, such that every process has the same number of elements afterwards. - t8_forest_set_balance(balanced_forest, forest, 1) - t8_forest_set_ghost(balanced_forest, 1, T8_GHOST_FACES) - - # Commit the forest. - t8_forest_commit(balanced_forest) - - return balanced_forest -end - -#include("t8_step3_common.jl") - - - - -# The uniform refinement level of the forest. -level = 0 - -# Initialize MPI. This has to happen before we initialize sc or t8code. -mpiret = MPI.Init() - -# We will use MPI_COMM_WORLD as a communicator. -comm = MPI.COMM_WORLD - -# Initialize the sc library, has to happen before we initialize t8code. -sc_init(comm, 0, 1, C_NULL, SC_LP_ESSENTIAL) - -# Initialize t8code with log level SC_LP_PRODUCTION. See sc.h for more info on the log levels. -t8_init(SC_LP_PRODUCTION) - - -# Build a cube cmesh with tet, hex, and prism trees. -cmesh = t8_cmesh_new_brick_2d(3, 7, 0, 0, comm) -t8_global_productionf(" [step4] Created coarse mesh.\n") - -forest = t8_forest_new_uniform(cmesh, t8_scheme_new_default(), level, 1, comm) - -# Print information of the forest. -t8_step3_print_forest_information(forest); - - - -# -# Balance -# -forest = t8_step4_balance(forest) -t8_global_productionf(" [step4] Balanced forest.\n") -t8_step3_print_forest_information(forest) - - -# -# Partition and create ghost elements. -# -forest = t8_step4_partition_ghost(forest) - -t8_global_productionf(" [step4] Repartitioned forest and built ghost layer.\n") -t8_step3_print_forest_information(forest) - - -t8_traverse_forest(forest, comm) - -# -# clean-up -# - -# Destroy the forest. -t8_forest_unref(Ref(forest)) - -sc_finalize() From 6ada26b2050810ce07f4a40a9b52d39e0c6391ae Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 24 Jun 2026 17:01:59 +0200 Subject: [PATCH 04/11] use guesses --- src/T8code.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/T8code.jl b/src/T8code.jl index 3af3e90..a381e35 100644 --- a/src/T8code.jl +++ b/src/T8code.jl @@ -259,7 +259,14 @@ macro T8_ASSERT(q) end # platform specific BUFSIZ used in t8_vtk_data_field_t -const T8_BUFSIZ = sizeof(t8_vtk_data_field_t.types[2]) +# TODO: Just a guess! +if Sys.isapple() + const T8_BUFSIZ = 1024 +elseif Sys.iswindows() + const T8_BUFSIZ = 512 +else + const T8_BUFSIZ = 8192 +end function t8_free(ptr) Libt8.sc_free(t8_get_package_id(), ptr) From f8f67d27ec3659869f069f8bbc7a138049b83537 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 24 Jun 2026 17:02:57 +0200 Subject: [PATCH 05/11] fmt --- examples/t8_step5_element_data.jl | 6 ++++-- examples/t8_step6_stencil.jl | 9 ++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/t8_step5_element_data.jl b/examples/t8_step5_element_data.jl index 2b5092d..27a5330 100644 --- a/examples/t8_step5_element_data.jl +++ b/examples/t8_step5_element_data.jl @@ -196,7 +196,9 @@ function t8_step5_output_data_to_vtu(forest, element_data, prefix) # For each user defined data field we need one t8_vtk_data_field_t variable. vtk_data = t8_vtk_data_field_t(T8_VTK_SCALAR, # Sets the type of this variable. Since we have one value per element, we pick T8_VTK_SCALAR. - NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("Element volume\0", T8code.T8_BUFSIZ, ' ')), + NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("Element volume\0", + T8code.T8_BUFSIZ, + ' ')), # The name of the field as should be written to the file. pointer(element_volumes)) @@ -281,7 +283,7 @@ end # Output the volume data to vtu. t8_step5_output_data_to_vtu(forest, element_data, prefix_forest_with_data) t8_global_productionf(" [step5] Wrote forest and volume data to %s*.\n", - prefix_forest_with_data) + prefix_forest_with_data) # # Clean-up. diff --git a/examples/t8_step6_stencil.jl b/examples/t8_step6_stencil.jl index 6a72465..bdc7cfb 100644 --- a/examples/t8_step6_stencil.jl +++ b/examples/t8_step6_stencil.jl @@ -339,13 +339,16 @@ function t8_step6_output_data_to_vtu(forest, element_data, prefix) # WARNING: This code hangs for Julia v1.8.* or older. Use at least Julia v1.9. vtk_data = [ t8_vtk_data_field_t(T8_VTK_SCALAR, - NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("height\0", T8code.T8_BUFSIZ, ' ')), + NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("height\0", + T8code.T8_BUFSIZ, ' ')), pointer(heights)), t8_vtk_data_field_t(T8_VTK_SCALAR, - NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("schlieren\0", T8code.T8_BUFSIZ, ' ')), + NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("schlieren\0", + T8code.T8_BUFSIZ, ' ')), pointer(schlieren)), t8_vtk_data_field_t(T8_VTK_SCALAR, - NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("curvature\0", T8code.T8_BUFSIZ, ' ')), + NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("curvature\0", + T8code.T8_BUFSIZ, ' ')), pointer(curvature)) ] From 00ef6bb058eaacdba1689e11efaad7fe3b538113 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 24 Jun 2026 23:56:51 +0200 Subject: [PATCH 06/11] parametrize vtk_data_struct and write_vtk method --- examples/t8_step5_element_data.jl | 11 ++++------- src/Libt8.jl | 8 ++++---- src/T8code.jl | 10 ++++++++++ 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/examples/t8_step5_element_data.jl b/examples/t8_step5_element_data.jl index 27a5330..258711b 100644 --- a/examples/t8_step5_element_data.jl +++ b/examples/t8_step5_element_data.jl @@ -194,13 +194,10 @@ function t8_step5_output_data_to_vtu(forest, element_data, prefix) # WARNING: This code hangs for Julia v1.8.* or older. Use at least Julia v1.9. # For each user defined data field we need one t8_vtk_data_field_t variable. - vtk_data = t8_vtk_data_field_t(T8_VTK_SCALAR, - # Sets the type of this variable. Since we have one value per element, we pick T8_VTK_SCALAR. - NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("Element volume\0", - T8code.T8_BUFSIZ, - ' ')), - # The name of the field as should be written to the file. - pointer(element_volumes)) + # We set the type of this variable. Since we have one value per element, we pick + # T8_VTK_SCALAR. + # We also set the name of the field as should be written to the file. + vtk_data = t8_vtk_data_field_t(T8_VTK_SCALAR, "Element volume", element_volumes) # To write user defined data, we need to extended output function # t8_forest_vtk_write_file from t8_forest_vtk.h. Despite writin user data, diff --git a/src/Libt8.jl b/src/Libt8.jl index 1f7aab6..5e6be41 100644 --- a/src/Libt8.jl +++ b/src/Libt8.jl @@ -12866,9 +12866,9 @@ A data field for VTK output. This struct is used to store data that is written t | type | Describes of which type the data array is | | description | String that describes the data. | """ -struct t8_vtk_data_field_t +struct t8_vtk_data_field_t{BUFSIZ} type::t8_vtk_data_type_t - description::NTuple{8192, Cchar} + description::NTuple{BUFSIZ, Cchar} data::Ptr{Cdouble} end @@ -12880,8 +12880,8 @@ end int t8_forest_write_vtk_ext (t8_forest_t forest, const char *fileprefix, const int write_treeid, const int write_mpirank, const int write_level, const int write_element_id, const int write_ghosts, const int write_curved, int do_not_use_API, const int num_data, t8_vtk_data_field_t *data); ``` """ -function t8_forest_write_vtk_ext(forest, fileprefix, write_treeid, write_mpirank, write_level, write_element_id, write_ghosts, write_curved, do_not_use_API, num_data, data) - @ccall libt8.t8_forest_write_vtk_ext(forest::t8_forest_t, fileprefix::Cstring, write_treeid::Cint, write_mpirank::Cint, write_level::Cint, write_element_id::Cint, write_ghosts::Cint, write_curved::Cint, do_not_use_API::Cint, num_data::Cint, data::Ptr{t8_vtk_data_field_t})::Cint +function t8_forest_write_vtk_ext(forest, fileprefix, write_treeid, write_mpirank, write_level, write_element_id, write_ghosts, write_curved, do_not_use_API, num_data, data::Base.RefValue{DataFieldType}) where DataFieldType + @ccall libt8.t8_forest_write_vtk_ext(forest::t8_forest_t, fileprefix::Cstring, write_treeid::Cint, write_mpirank::Cint, write_level::Cint, write_element_id::Cint, write_ghosts::Cint, write_curved::Cint, do_not_use_API::Cint, num_data::Cint, data::Ptr{DataFieldType})::Cint end """ diff --git a/src/T8code.jl b/src/T8code.jl index a381e35..0ca520b 100644 --- a/src/T8code.jl +++ b/src/T8code.jl @@ -268,6 +268,16 @@ else const T8_BUFSIZ = 8192 end +# convenience constructor +# - adds 0 termination and padding to description string +# - takes pointer of data +function Libt8.t8_vtk_data_field_t(type, description::String, data) + @info "external ctor", T8_BUFSIZ + return t8_vtk_data_field_t(type, + NTuple{T8_BUFSIZ, Cchar}(rpad(description * "\0", T8_BUFSIZ, ' ')), + pointer(data)) +end + function t8_free(ptr) Libt8.sc_free(t8_get_package_id(), ptr) end From 01afd3e8164cb2f301cfcbc9f1952488cb4a7885 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 24 Jun 2026 23:57:54 +0200 Subject: [PATCH 07/11] set version to DEV --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4928151..d2bb0cf 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "T8code" uuid = "d0cc0030-9a40-4274-8435-baadcfd54fa1" authors = ["Johannes Markert "] -version = "0.9.1" +version = "0.9.2-DEV" [deps] CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82" From 5db9020221e771c1cc6898a2929066bffa737f6c Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Thu, 25 Jun 2026 00:34:27 +0200 Subject: [PATCH 08/11] change to Ptr for data_field types --- examples/t8_step5_element_data.jl | 4 ++-- examples/t8_step6_stencil.jl | 15 +++------------ src/Libt8.jl | 2 +- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/examples/t8_step5_element_data.jl b/examples/t8_step5_element_data.jl index 258711b..2daf248 100644 --- a/examples/t8_step5_element_data.jl +++ b/examples/t8_step5_element_data.jl @@ -197,7 +197,7 @@ function t8_step5_output_data_to_vtu(forest, element_data, prefix) # We set the type of this variable. Since we have one value per element, we pick # T8_VTK_SCALAR. # We also set the name of the field as should be written to the file. - vtk_data = t8_vtk_data_field_t(T8_VTK_SCALAR, "Element volume", element_volumes) + vtk_data = [t8_vtk_data_field_t(T8_VTK_SCALAR, "Element volume", element_volumes)] # To write user defined data, we need to extended output function # t8_forest_vtk_write_file from t8_forest_vtk.h. Despite writin user data, @@ -209,7 +209,7 @@ function t8_step5_output_data_to_vtu(forest, element_data, prefix) write_ghosts = 0 t8_forest_write_vtk_ext(forest, prefix, write_treeid, write_mpirank, write_level, write_element_id, write_ghosts, - 0, 0, num_data, Ref(vtk_data)) + 0, 0, num_data, pointer(vtk_data)) end # The prefix for our output files. diff --git a/examples/t8_step6_stencil.jl b/examples/t8_step6_stencil.jl index bdc7cfb..7dfd462 100644 --- a/examples/t8_step6_stencil.jl +++ b/examples/t8_step6_stencil.jl @@ -338,18 +338,9 @@ function t8_step6_output_data_to_vtu(forest, element_data, prefix) # WARNING: This code hangs for Julia v1.8.* or older. Use at least Julia v1.9. vtk_data = [ - t8_vtk_data_field_t(T8_VTK_SCALAR, - NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("height\0", - T8code.T8_BUFSIZ, ' ')), - pointer(heights)), - t8_vtk_data_field_t(T8_VTK_SCALAR, - NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("schlieren\0", - T8code.T8_BUFSIZ, ' ')), - pointer(schlieren)), - t8_vtk_data_field_t(T8_VTK_SCALAR, - NTuple{T8code.T8_BUFSIZ, Cchar}(rpad("curvature\0", - T8code.T8_BUFSIZ, ' ')), - pointer(curvature)) + t8_vtk_data_field_t(T8_VTK_SCALAR, "height", heights), + t8_vtk_data_field_t(T8_VTK_SCALAR, "schlieren", schlieren), + t8_vtk_data_field_t(T8_VTK_SCALAR, "curvature", curvature) ] # The number of user defined data fields to write. diff --git a/src/Libt8.jl b/src/Libt8.jl index 5e6be41..af5f2c0 100644 --- a/src/Libt8.jl +++ b/src/Libt8.jl @@ -12880,7 +12880,7 @@ end int t8_forest_write_vtk_ext (t8_forest_t forest, const char *fileprefix, const int write_treeid, const int write_mpirank, const int write_level, const int write_element_id, const int write_ghosts, const int write_curved, int do_not_use_API, const int num_data, t8_vtk_data_field_t *data); ``` """ -function t8_forest_write_vtk_ext(forest, fileprefix, write_treeid, write_mpirank, write_level, write_element_id, write_ghosts, write_curved, do_not_use_API, num_data, data::Base.RefValue{DataFieldType}) where DataFieldType +function t8_forest_write_vtk_ext(forest, fileprefix, write_treeid, write_mpirank, write_level, write_element_id, write_ghosts, write_curved, do_not_use_API, num_data, data::Ptr{DataFieldType}) where DataFieldType @ccall libt8.t8_forest_write_vtk_ext(forest::t8_forest_t, fileprefix::Cstring, write_treeid::Cint, write_mpirank::Cint, write_level::Cint, write_element_id::Cint, write_ghosts::Cint, write_curved::Cint, do_not_use_API::Cint, num_data::Cint, data::Ptr{DataFieldType})::Cint end From 688db5d898ae95a05e0cfefeb59465604ba1dba4 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Thu, 25 Jun 2026 00:35:17 +0200 Subject: [PATCH 09/11] fmt --- src/T8code.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/T8code.jl b/src/T8code.jl index 0ca520b..847329f 100644 --- a/src/T8code.jl +++ b/src/T8code.jl @@ -274,8 +274,9 @@ end function Libt8.t8_vtk_data_field_t(type, description::String, data) @info "external ctor", T8_BUFSIZ return t8_vtk_data_field_t(type, - NTuple{T8_BUFSIZ, Cchar}(rpad(description * "\0", T8_BUFSIZ, ' ')), - pointer(data)) + NTuple{T8_BUFSIZ, Cchar}(rpad(description * "\0", T8_BUFSIZ, + ' ')), + pointer(data)) end function t8_free(ptr) From cf650db099828d54955492a8af3f8fa04a6d7f5e Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Thu, 25 Jun 2026 09:33:05 +0200 Subject: [PATCH 10/11] comment --- test/test_examples.jl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/test_examples.jl b/test/test_examples.jl index 3637113..736c821 100644 --- a/test/test_examples.jl +++ b/test/test_examples.jl @@ -22,11 +22,8 @@ end include("../examples/t8_step4_partition_balance_ghost.jl") end -# Unfortunately, step 5 and step 6 currently crash (1.) in Windows, (2.) in MacOS, -# and (3.) with Julia older than 1.9, see related issues -# https://github.com/DLR-AMR/T8code.jl/issues/26, -# https://github.com/DLR-AMR/T8code.jl/issues/30, -# https://github.com/DLR-AMR/T8code.jl/issues/104. +# Step 5 and step 6 crash with Julia older than 1.9, see related issue +# https://github.com/DLR-AMR/T8code.jl/issues/26 @testset "t8_step5_element_data" begin include("../examples/t8_step5_element_data.jl") From fc5aa15d6294b0babc7558f8dedbefe4a2484882 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 1 Jul 2026 10:13:53 +0200 Subject: [PATCH 11/11] rm debug output --- src/T8code.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/T8code.jl b/src/T8code.jl index 847329f..9c95496 100644 --- a/src/T8code.jl +++ b/src/T8code.jl @@ -272,7 +272,6 @@ end # - adds 0 termination and padding to description string # - takes pointer of data function Libt8.t8_vtk_data_field_t(type, description::String, data) - @info "external ctor", T8_BUFSIZ return t8_vtk_data_field_t(type, NTuple{T8_BUFSIZ, Cchar}(rpad(description * "\0", T8_BUFSIZ, ' ')),