diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 995a37e2c..3fec9cc27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: zlib1g-dev libmpich-dev mpich - name: Checkout source code - uses: actions/checkout@v4 + uses: actions/checkout@main with: submodules: true @@ -63,7 +63,7 @@ jobs: - name: Upload log files if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@main with: name: linux_multi1_log path: | @@ -83,7 +83,7 @@ jobs: zlib1g-dev libmpich-dev mpich - name: Checkout source code - uses: actions/checkout@v4 + uses: actions/checkout@main with: submodules: true @@ -108,7 +108,7 @@ jobs: - name: Upload log files if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@main with: name: linux_multi2_log path: | @@ -128,7 +128,7 @@ jobs: zlib1g-dev libmpich-dev mpich - name: Checkout source code - uses: actions/checkout@v4 + uses: actions/checkout@main with: submodules: true fetch-depth: 0 @@ -139,7 +139,7 @@ jobs: cd sc git fetch --tags git checkout v2.8.6 - # git checkout -b test-branch 2c1496904c485d4ca6f844c396b32f608b72438c + # git checkout -b test-branch 91cc8a456bd857dec67cf703afb3b3276aebb016 - name: Run bootstrap script run: ./bootstrap @@ -169,7 +169,7 @@ jobs: - name: Upload log files if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@main with: name: linux_install_log path: | @@ -189,7 +189,7 @@ jobs: zlib1g-dev libmpich-dev mpich - name: Checkout source code - uses: actions/checkout@v4 + uses: actions/checkout@main with: submodules: true fetch-depth: 0 @@ -216,14 +216,14 @@ jobs: mv p4est-*.tar.gz .. - name: Upload tarball - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@main with: name: p4est_tarball path: ./p4est-*.tar.gz - name: Upload log files if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@main with: name: linux_tarball_log path: | diff --git a/.github/workflows/ci_cmake.yml b/.github/workflows/ci_cmake.yml index 582dc8910..9d5169ba9 100644 --- a/.github/workflows/ci_cmake.yml +++ b/.github/workflows/ci_cmake.yml @@ -16,20 +16,23 @@ on: types: [published] env: - CTEST_PARALLEL_LEVEL: 4 + CTEST_PARALLEL_LEVEL: 0 CMAKE_BUILD_PARALLEL_LEVEL: 4 CTEST_NO_TESTS_ACTION: "error" + CMAKE_INSTALL_PREFIX: ~/local + CMAKE_PREFIX_PATH: ~/local jobs: linux: - runs-on: ubuntu-22.04 - name: CMake build on Linux + runs-on: ubuntu-latest + name: Linux mpi=${{ matrix.mpi }} CC=${{ matrix.cc }} shared=${{ matrix.shared }} timeout-minutes: 60 strategy: + fail-fast: false matrix: - cc: [gcc-9, gcc-10, gcc-11, gcc-12, gcc-13] + cc: [gcc] shared: [false] mpi: [mpich] include: @@ -48,70 +51,25 @@ jobs: - uses: actions/checkout@v4 name: Checkout source code - - name: Install system dependencies - run: | - sudo apt-get update -yq - sudo apt-get install -yq --no-install-recommends zlib1g-dev lib${{ matrix.mpi }}-dev + - name: Install deps + uses: ./.github/workflows/composite-deps - - name: CMake configure - run: >- - cmake --preset default - --install-prefix=${{ runner.temp }} - -DBUILD_SHARED_LIBS:BOOL=${{ matrix.shared }} - - - name: CMake build - run: cmake --build --preset default - - - name: CMake self-tests - run: ctest --preset default - - - name: install p4est CMake package - run: cmake --install build - - # standalone examples tests that CMake packaging is correct - - name: CMake configure examples - run: >- - cmake -B example/build -S example - -DCMAKE_PREFIX_PATH:PATH=${{ runner.temp }} - -DBUILD_SHARED_LIBS:BOOL=${{ matrix.shared }} - - - name: CMake build examples - run: cmake --build example/build - - - name: Create package - if: github.event.action == 'published' - run: cpack --config build/CPackConfig.cmake + - name: CMake build-test-install-package + uses: ./.github/workflows/composite-unix - name: Upload package - if: github.event.action == 'published' - uses: actions/upload-artifact@v4 - with: - name: linux_binary_archive-${{ matrix.cc }}-${{ matrix.mpi }}-shared-${{ matrix.shared }} - path: build/package + uses: ./.github/workflows/composite-pkg - - name: Upload log files - if: always() - uses: actions/upload-artifact@v4 - with: - name: linux_cmake_log-${{ matrix.cc }}-${{ matrix.mpi }}-shared-${{ matrix.shared }} - path: | - ./build/CMakeFiles/CMakeConfigureLog.yaml - ./build/Testing/Temporary/LastTest.log mac: - # macos-14 is to use Apple Silicon hardware - # https://github.blog/changelog/2024-01-30-github-actions-introducing-the-new-m1-macos-runner-available-to-open-source/ - runs-on: macos-14 - name: CMake build on MacOS + runs-on: macos-latest + name: macOS CC=${{ matrix.cc }} shared=${{ matrix.shared }} timeout-minutes: 60 strategy: matrix: - cc: [clang, gcc-13] - shared: [false] - include: - - cc: clang - shared: true + cc: [clang] + shared: [false, true] env: HOMEBREW_NO_INSTALL_CLEANUP: 1 @@ -121,62 +79,21 @@ jobs: - uses: actions/checkout@v4 name: Checkout source code - - name: Install system dependencies - run: brew install open-mpi - - - name: CMake configure - run: >- - cmake --preset default - --install-prefix=${{ runner.temp }} - -DBUILD_SHARED_LIBS:BOOL=${{ matrix.shared }} - - - name: CMake build - run: cmake --build --preset default - - - name: CMake self-tests - run: ctest --preset default - - - name: install p4est CMake package - run: cmake --install build - - - name: CMake configure examples - run: >- - cmake -B example/build -S example - -DCMAKE_PREFIX_PATH:PATH=${{ runner.temp }} - -DBUILD_SHARED_LIBS:BOOL=${{ matrix.shared }} + - name: Install deps + uses: ./.github/workflows/composite-deps - - name: CMake build examples - run: cmake --build example/build - - - name: Create package - if: github.event.action == 'published' - run: cpack --config build/CPackConfig.cmake + - name: CMake build-test-install-package + uses: ./.github/workflows/composite-unix - name: Upload package - if: github.event.action == 'published' - uses: actions/upload-artifact@v4 - with: - name: mac_binary_archive-${{ matrix.cc }}-shared-${{ matrix.shared }} - path: build/package + uses: ./.github/workflows/composite-pkg - - name: Upload log files - if: always() - uses: actions/upload-artifact@v4 - with: - name: mac_cmake_log-${{ matrix.cc }}-shared-${{ matrix.shared }} - path: | - ./build/CMakeFiles/CMakeConfigureLog.yaml - ./build/Testing/Temporary/LastTest.log windows: runs-on: windows-latest - name: CMake build on Windows + name: Windows timeout-minutes: 60 - strategy: - matrix: - shared: [false] - env: CMAKE_GENERATOR: "MinGW Makefiles" @@ -193,14 +110,13 @@ jobs: - uses: actions/checkout@v4 name: Checkout source code + - run: echo "CMAKE_INSTALL_PREFIX=$HOME/local" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + - run: echo "CMAKE_PREFIX_PATH=$HOME/local" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + - run: echo "ZLIB_ROOT=$env:RUNNER_TEMP/msys64/mingw64" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + # Windows MPI is shaky in general on GitHub Actions, so we don't use it - name: CMake configure without MPI - run: >- - cmake --preset default - -Dmpi:BOOL=no - --install-prefix=${{ runner.temp }} - -DBUILD_SHARED_LIBS:BOOL=${{ matrix.shared }} - -DZLIB_ROOT:PATH=${{ runner.temp }}/msys64/mingw64/ + run: cmake --preset default -Dmpi:BOOL=no - name: CMake build run: cmake --build --preset default @@ -212,11 +128,7 @@ jobs: run: cmake --install build - name: CMake configure examples - run: >- - cmake -B example/build -S example - -DCMAKE_PREFIX_PATH:PATH=${{ runner.temp }} - -DBUILD_SHARED_LIBS:BOOL=${{ matrix.shared }} - -DZLIB_ROOT:PATH=${{ runner.temp }}/msys64/mingw64/ + run: cmake -B example/build -S example - name: CMake build examples run: cmake --build example/build @@ -226,17 +138,4 @@ jobs: run: cpack --config build/CPackConfig.cmake - name: Upload package - if: github.event.action == 'published' - uses: actions/upload-artifact@v4 - with: - name: windows_binary_archive - path: build/package - - - name: Upload log files - if: always() - uses: actions/upload-artifact@v4 - with: - name: windows_cmake_log - path: | - ./build/CMakeFiles/CMakeConfigureLog.yaml - ./build/Testing/Temporary/LastTest.log + uses: ./.github/workflows/composite-pkg diff --git a/.github/workflows/ci_darwin.yml b/.github/workflows/ci_darwin.yml index 06f3c143d..1dce73701 100644 --- a/.github/workflows/ci_darwin.yml +++ b/.github/workflows/ci_darwin.yml @@ -24,13 +24,13 @@ jobs: steps: - run: echo "This job is running on a ${{ runner.os }} server hosted by GitHub" - - uses: actions/checkout@v4 + - uses: actions/checkout@main name: Checkout source code with: submodules: true - name: Install system dependencies - run: brew install open-mpi ninja automake + run: brew install open-mpi automake libtool - name: Run bootstrap script run: ./bootstrap @@ -55,7 +55,7 @@ jobs: - name: Upload log files if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@main with: name: darwin1_log path: | @@ -72,13 +72,13 @@ jobs: steps: - run: echo "This job is running on a ${{ runner.os }} server hosted by GitHub" - - uses: actions/checkout@v4 + - uses: actions/checkout@main name: Checkout source code with: submodules: true - name: Install system dependencies - run: brew install open-mpi ninja automake + run: brew install open-mpi automake libtool - name: Run bootstrap script run: ./bootstrap @@ -94,7 +94,7 @@ jobs: - name: Upload log files if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@main with: name: darwin2_log path: | diff --git a/.github/workflows/ci_valgrind.yml b/.github/workflows/ci_valgrind.yml index 306b9fd9d..bf2260a96 100644 --- a/.github/workflows/ci_valgrind.yml +++ b/.github/workflows/ci_valgrind.yml @@ -21,7 +21,7 @@ jobs: zlib1g-dev libmpich-dev mpich valgrind - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@main with: submodules: true @@ -42,7 +42,7 @@ jobs: - name: Upload log files if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@main with: name: linux_autotools_valgrind_log path: | @@ -62,7 +62,7 @@ jobs: zlib1g-dev libmpich-dev mpich valgrind - name: Checkout source code - uses: actions/checkout@v3 + uses: actions/checkout@main with: submodules: true @@ -76,7 +76,7 @@ jobs: - name: Upload log files if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@main with: name: linux_cmake_valgrind_log path: | diff --git a/.github/workflows/composite-deps/action.yml b/.github/workflows/composite-deps/action.yml new file mode 100644 index 000000000..116bcf617 --- /dev/null +++ b/.github/workflows/composite-deps/action.yml @@ -0,0 +1,17 @@ +runs: + + using: 'composite' + + steps: + + - name: Install Linux dependencies + shell: bash + if: runner.os == 'Linux' + run: | + sudo apt-get update -yq + sudo apt-get install -yq --no-install-recommends zlib1g-dev lib${{ matrix.mpi }}-dev + + - name: Install macOS dependencies + shell: bash + if: runner.os == 'macOS' + run: brew install open-mpi diff --git a/.github/workflows/composite-pkg/action.yml b/.github/workflows/composite-pkg/action.yml new file mode 100644 index 000000000..cd27ce129 --- /dev/null +++ b/.github/workflows/composite-pkg/action.yml @@ -0,0 +1,20 @@ +runs: + + using: 'composite' + + steps: + - name: Upload package + if: github.event.action == 'published' + uses: actions/upload-artifact@v4 + with: + name: ${{ runner.os }}_binary_archive-${{ matrix.cc }}-${{ matrix.mpi }}-shared-${{ matrix.shared }} + path: build/package + + - name: Upload log files + if: always() + uses: actions/upload-artifact@v4 + with: + name: ${{ runner.os }}_cmake_log-${{ matrix.cc }}-${{ matrix.mpi }}-shared-${{ matrix.shared }} + path: | + ./build/CMakeFiles/CMakeConfigureLog.yaml + ./build/Testing/Temporary/LastTest.log diff --git a/.github/workflows/composite-unix/action.yml b/.github/workflows/composite-unix/action.yml new file mode 100644 index 000000000..6147af870 --- /dev/null +++ b/.github/workflows/composite-unix/action.yml @@ -0,0 +1,38 @@ +runs: + + using: 'composite' + + steps: + - name: CMake configure + shell: bash + run: >- + cmake --preset default + -DBUILD_SHARED_LIBS:BOOL=${{ matrix.shared }} + + - name: CMake build + shell: bash + run: cmake --build --preset default + + - name: CMake self-tests + shell: bash + run: ctest --preset default + + - name: install p4est CMake package + shell: bash + run: cmake --install build + + # standalone examples tests that CMake packaging is correct + - name: CMake configure examples + shell: bash + run: >- + cmake -B example/build -S example + -DBUILD_SHARED_LIBS:BOOL=${{ matrix.shared }} + + - name: CMake build examples + shell: bash + run: cmake --build example/build + + - name: Create package + shell: bash + if: github.event.action == 'published' + run: cpack --config build/CPackConfig.cmake diff --git a/cmake/options.cmake b/cmake/options.cmake index 46fdb2658..7145794e1 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -12,20 +12,6 @@ if(vtk_binary) set(P4EST_ENABLE_VTK_BINARY 1) endif() -# --- default install directory under build/local -# users can specify like "cmake -B build -DCMAKE_INSTALL_PREFIX=~/mydir" -if(CMAKE_VERSION VERSION_LESS 3.21) - get_property(_not_top DIRECTORY PROPERTY PARENT_DIRECTORY) - if(NOT _not_top) - set(P4EST_IS_TOP_LEVEL true) - endif() -endif() - -if(P4EST_IS_TOP_LEVEL AND CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - # will not take effect without FORCE - set(CMAKE_INSTALL_PREFIX "${PROJECT_BINARY_DIR}/local" CACHE PATH "Install top-level directory" FORCE) -endif() - # Necessary for shared library with Visual Studio / Windows oneAPI set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS true) diff --git a/doc/doxygen/example_particles.dox b/doc/doxygen/example_particles.dox new file mode 100644 index 000000000..4c95a571e --- /dev/null +++ b/doc/doxygen/example_particles.dox @@ -0,0 +1,143 @@ +/* + This file is part of p4est. + p4est is a C library to manage a collection (a forest) of multiple + connected adaptive quadtrees or octrees in parallel. + + Copyright (C) 2010 The University of Texas System + Written by Carsten Burstedde, Lucas C. Wilcox, and Tobin Isaac + + p4est 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. + + p4est 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 p4est; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/** \page example_particles A particle tracking example + * + * We include an example to track particles with a dynamic mesh. + * The mesh elements are refined such that the number of particles per + * element stays limited to a configurable number. + * While the particles move in space, they also move between elements, + * which means that they may move between processes. + * We reassign particles to their holding elements in every time step and + * then repartition the mesh to maintain load balance, where we transfer + * the particles to new processes together with the holding elements. + * + * We provide both a 2D version in \ref particles/particles2.c and a 3D + * version in \ref particles/particles3.c. + * + * ## Searching the proper element for each particle + * + * At any time step, any particle may make an arbitrary move through space. + * This often moves it out of its original holding element, and we need to + * find a new one. This new element may be on the same or a remote process. + * This example is a demo for a scalable procedure to identify it. + * The method works for arbitrary moves and is \a not restricted to + * nearest neighbor elements. In consequence, we do not rely on the + * \ref p4est_ghost algorithm but on remote and local recursive searches. + * + * ### Searching the process responsible for each particle + * + * We proceed in several stages. First, we determine the process that + * owns the element that the particle has moved into. We can do this in + * p4est \a without knowing about any local or remote elements, since the + * shape of the partition boundaries is encoded internally using a minimal + * scheme. The function to determine the process association is + * \ref p4est_search_partition. + * It expects the user to provide a callback to indicate whether a point + * matches a given search element. This search element is not necessarily + * one of the mesh, but may be a virtual ancestor of any local or remote + * element, and is generated temporarily by the search recursion. + * The callback is informed with the current range of suspected processes + * as a convenience. The point is dropped if the range becomes empty, + * and the recursion terminates if the range shrinks to one process. + * + * ### Transfering particles to their elements + * + * In this example, if a particle changes process we send it there. + * Thus every process sends one message per receiver process containing + * all particles leaving towards it. + * Since the receivers do not know a priori which processes send to it, we + * explicitly reverse the communication pattern using the `sc_notify` + * functionality of the sc library (see there). + * Once the notification algorithm returns, we have a list of sender and + * receiver pairs, which we pass to asynchronous MPI point-to-point + * communication calls. + * + * ### Searching the element responsible for each local particle + * + * Some particles stay on the same process, and those that don't are sent + * away. Conversely, new particles are received that have left their + * previous remote process. This means that at this point, every particle + * is properly assigned to the process. It remains to find the local + * element that should be holding each one, which we accomplish by calling + * \ref p4est_search_local. + * It expects a callback similar to that of the partition search. + * The recursion terminates at the proper element for each particle. + * + * ## Remeshing and particle transfer + * + * After the particles have moved between elements, most elements will have + * gained or lost some. We should refine elements with increased particle + * density and coarsen those where the particles have thinned. To do this, + * we employ the classic p4est mesh adaptation mechanism and then retransfer + * the particles along with the updated partition. + * Thus, particles move between processes a second time. + * + * ### Adapting and repartitioning the mesh + * + * Given the current mesh that was used to time step the particles, we + * have now redistributed the particles according to their move through + * space, and possibly transferred them from a different process. The + * particles have been newly reassigned to the process local elements. + * We are left with the following challenges: + * + * - Some elements hold much less or much more particles than desired. + * - The number of particles per process has become imbalanced. + * + * We solve the first issue by adapting the mesh using the functions + * \ref p4est_refine_ext and \ref p4est_coarsen_ext non-recursively. + * Optionally, we call \ref p4est_balance_ext to smooth the refinement + * pattern. + * These calls produce a mesh within the same partition boundaries, but + * possibly replacing a parent element with its children or vice versa. + * Using the \ref p4est_replace_t callback, we reassign the particles to the + * parent or the proper child, respectively, during the adaptation. + * + * To solve the second problem, we \ref p4est_copy the mesh first and + * then \ref p4est_partition it using a \ref p4est_weight_t function + * that takes into account the number of particles per element. + * + * ### Transfering particles on repartitioning + * + * We have kept the original refined mesh holding the particles and made + * a repartitioned mesh that is properly load balanced but still missing the + * particles. We use the \ref p4est_transfer_custom functionality to + * message the particles to the new process partition. The element + * association need not be recomputed, since the global refinement structure + * is left unchanged by repartitioning. At this point, we delete the old + * mesh and are ready for the next time step. + */ + +/** \example particles/particles2.c + * + * 2D version of a generic particle tracking demo. + * For a high-level description of the concepts implemented and + * references to important p4est calls please see \ref example_particles. + */ + +/** \example particles/particles3.c + * + * The 3D version of the particle tracking demo compiles from the same + * code as the 2D example \ref particles/particles2.c with minimal + * redefinitions. In this sense, the code is mostly dimension independent. + */ diff --git a/doc/release_notes.txt b/doc/release_notes.txt index cc5a1591a..ce0ec8990 100644 --- a/doc/release_notes.txt +++ b/doc/release_notes.txt @@ -13,6 +13,11 @@ software API or ABI. In this case, we'll bump the libtool version with the next release version. Please also note if there have been A*I extensions, in which case we'll bump the libtool minor version. + - Please add an item with every contribution under *Next release* below. + +## Next release + + - CMake system updates analogous to those in libsc. ## 2.8.6 diff --git a/example/particles/particles2.c b/example/particles/particles2.c index c20900306..12bf1c381 100644 --- a/example/particles/particles2.c +++ b/example/particles/particles2.c @@ -22,6 +22,11 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/* + * The particle demo compiles from this file twice into one 2D version + * and one 3D version. Most of the code is dimension independent. + */ + #ifndef P4_TO_P8 #include #include @@ -45,10 +50,10 @@ #define PARTICLES_str(s) #s #define PARTICLES_48() PARTICLES_xstr(P4EST_CHILDREN) -/** Send full particle information in first message, comment out if not */ +/* Send full particle information in first message, comment out if not */ #define PART_SENDFULL -/** Context data to compute initial particle positions */ +/* Context data to compute initial particle positions */ typedef struct pi_data { double sigma; @@ -58,22 +63,22 @@ typedef struct pi_data } pi_data_t; -/** Data type for payload data inside each quadrant */ +/* Data type for payload data inside each quadrant */ typedef struct qu_data { union { - /** Offset into local array of all particles after this quadrant */ + /* Offset into local array of all particles after this quadrant */ p4est_locidx_t lpend; double d; } u; - /** counts of local particles remaining on this quadrant and received ones */ + /* counts of local particles remaining on this quadrant and received ones */ p4est_locidx_t premain, preceive; } qu_data_t; -/** Property data stored in a flat array over all particles */ +/* Property data stored in a flat array over all particles */ typedef struct pa_data { double xv[6]; @@ -130,19 +135,19 @@ lrem (part_global_t * g, const char *lead) #define PART_MSGSIZE (3 * sizeof (double)) #endif -/** Hash table entry for a process that we send messages to */ +/* Hash table entry for a process that we send messages to */ typedef struct comm_psend { int rank; - sc_array_t message; /** Message data to send */ + sc_array_t message; /*< Message data to send */ } comm_psend_t; -/** Array entry for a process that we send messages to */ +/* Array entry for a process that we send messages to */ typedef struct comm_prank { int rank; - comm_psend_t *psend; /**< Points to hash table entry */ + comm_psend_t *psend; /*< Points to hash table entry */ } comm_prank_t; @@ -169,7 +174,7 @@ static const double pidensy_center[3] = { .3, .4, .5 }; static double qpoints[PART_NQPOINTS]; static double qweights[PART_NQPOINTS]; -static const double rk1b[1] = { 0. }; /* avoid -pedantic warning for [0] */ +static const double rk1b[1] = { 0. }; /*< avoid -pedantic warning for [0] */ static const double rk1g[1] = { 1. }; static const double rk2b[1] = { 1. }; static const double rk2g[2] = { .5, .5 }; @@ -285,7 +290,7 @@ sc_array_index_end (sc_array_t * arr) #endif -/** With two initialized arrays of same metadata, copy array data */ +/* With two initialized arrays of same metadata, copy array data */ static void sc_array_paste (sc_array_t * dest, sc_array_t * src) { @@ -295,7 +300,7 @@ sc_array_paste (sc_array_t * dest, sc_array_t * src) memcpy (dest->array, src->array, src->elem_count * src->elem_size); } -/** Initialize one array with contents from other, reinit the other */ +/* Initialize one array with contents from other, reinit the other */ static void sc_array_swap_init (sc_array_t * array, sc_array_t * from, size_t elem_size) { @@ -303,7 +308,7 @@ sc_array_swap_init (sc_array_t * array, sc_array_t * from, size_t elem_size) sc_array_init (from, elem_size); } -/** Turn statistics collected so far into one value */ +/* Turn statistics collected so far into one value */ static void sc_stats_collapse (sc_statinfo_t * stats) { diff --git a/example/particles/particles3.c b/example/particles/particles3.c index 1d0146f0f..15a85487e 100644 --- a/example/particles/particles3.c +++ b/example/particles/particles3.c @@ -22,5 +22,11 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/* + * We compile the 3D example from the same code as the 2D example. + * We just redefine the mesh functions from 2D to 3D and use a few + * `#ifdef P4_TO_P8` branches to switch from 2D- to 3D-specific code. + */ + #include #include "particles2.c" diff --git a/sc b/sc index d95bc1488..91cc8a456 160000 --- a/sc +++ b/sc @@ -1 +1 @@ -Subproject commit d95bc14889bf46b03e57dc1a7482e0754adbd4c8 +Subproject commit 91cc8a456bd857dec67cf703afb3b3276aebb016 diff --git a/src/p4est.c b/src/p4est.c index 2b512596b..6720f9e7f 100644 --- a/src/p4est.c +++ b/src/p4est.c @@ -3477,12 +3477,12 @@ p4est_save_ext (const char *filename, p4est_t * p4est, size_t data_size, qbuf_size, comb_size, head_count; size_t zz, zcount; uint64_t *u64a; - FILE *file; #ifdef P4EST_MPIIO_WRITE MPI_File mpifile; MPI_Offset mpipos; MPI_Offset mpithis; #else + FILE *file; long fthis; #endif p4est_topidx_t jt, num_trees; @@ -3490,8 +3490,10 @@ p4est_save_ext (const char *filename, p4est_t * p4est, p4est_tree_t *tree; p4est_quadrant_t *q; char *lbuf, *bp; + char nul[2] = "\0"; p4est_qcoord_t *qpos; sc_array_t *tquadrants; + sc_io_sink_t *sink = NULL; P4EST_GLOBAL_PRODUCTIONF ("Into " P4EST_STRING "_save %s\n", filename); p4est_log_indent_push (); @@ -3519,22 +3521,17 @@ p4est_save_ext (const char *filename, p4est_t * p4est, p4est_comm_count_pertree (p4est, pertree); if (rank == 0) { - p4est_connectivity_save (filename, p4est->connectivity); - - /* open file after writing connectivity to it */ - file = fopen (filename, "ab"); - SC_CHECK_ABORT (file != NULL, "file open"); - - /* explicitly seek to end to avoid bad ftell return value on Windows */ - retval = fseek (file, 0, SEEK_END); - SC_CHECK_ABORT (retval == 0, "file seek"); + sink = sc_io_sink_new (SC_IO_TYPE_FILENAME, SC_IO_MODE_WRITE, + SC_IO_ENCODE_NONE, filename); + SC_CHECK_ABORT (sink != NULL, "file open"); + p4est_connectivity_sink (p4est->connectivity, sink); /* align the start of the header */ - fpos = ftell (file); + fpos = sink->bytes_out; SC_CHECK_ABORT (fpos > 0, "first file tell"); while (fpos % align != 0) { - retval = fputc ('\0', file); - SC_CHECK_ABORT (retval == 0, "first file align"); + retval = sc_io_sink_write (sink, nul, 1); + SC_CHECK_ABORT (retval == SC_IO_ERROR_NONE, "first file align"); ++fpos; } @@ -3559,31 +3556,28 @@ p4est_save_ext (const char *filename, p4est_t * p4est, for (jt = 0; jt < num_trees; ++jt) { u64a[headc + save_num_procs + jt] = (uint64_t) pertree[jt + 1]; } - sc_fwrite (u64a, sizeof (uint64_t), head_count, - file, "write header information"); + retval = sc_io_sink_write (sink, u64a, sizeof (uint64_t) * head_count); + SC_CHECK_ABORT (retval == SC_IO_ERROR_NONE, "write header information"); P4EST_FREE (u64a); fpos += head_count * sizeof (uint64_t); /* align the start of the quadrants */ - fpos = ftell (file); + fpos = sink->bytes_out; SC_CHECK_ABORT (fpos > 0, "second file tell"); while (fpos % align != 0) { - retval = fputc ('\0', file); - SC_CHECK_ABORT (retval == 0, "second file align"); + retval = sc_io_sink_write (sink, nul, 1); + SC_CHECK_ABORT (retval == SC_IO_ERROR_NONE, "second file align"); ++fpos; } #ifdef P4EST_MPIIO_WRITE /* we will close the sequential access to the file */ - sc_fflush_fsync_fclose (file); - file = NULL; + sc_io_sink_destroy (sink); + sink = NULL; #else /* file is still open for sequential write mode */ #endif } - else { - file = NULL; - } P4EST_FREE (pertree); #ifndef P4EST_MPIIO_WRITE @@ -3599,6 +3593,9 @@ p4est_save_ext (const char *filename, p4est_t * p4est, file = fopen (filename, "rb+"); SC_CHECK_ABORT (file != NULL, "file open"); } + else { + file = NULL; + } #else /* Every core opens the file in append mode -- file must exist */ mpiret = sc_MPI_Barrier (p4est->mpicomm); @@ -3649,7 +3646,13 @@ p4est_save_ext (const char *filename, p4est_t * p4est, bp += comb_size; } #ifndef P4EST_MPIIO_WRITE - sc_fwrite (lbuf, comb_size, zcount, file, "write quadrants"); + if (p4est->mpirank == 0) { + retval = sc_io_sink_write (sink, lbuf, comb_size * zcount); + SC_CHECK_ABORT (retval == SC_IO_ERROR_NONE, "write quadrants"); + } + else { + sc_fwrite (lbuf, comb_size, zcount, file, "write quadrants"); + } #else sc_mpi_write (mpifile, lbuf, comb_size * zcount, MPI_BYTE, "write quadrants"); @@ -3658,8 +3661,14 @@ p4est_save_ext (const char *filename, p4est_t * p4est, } #ifndef P4EST_MPIIO_WRITE - sc_fflush_fsync_fclose (file); - file = NULL; + if (p4est->mpirank == 0) { + sc_io_sink_destroy (sink); + sink = NULL; + } + else { + sc_fflush_fsync_fclose (file); + file = NULL; + } /* initiate sequential synchronization */ #ifdef P4EST_ENABLE_MPI diff --git a/src/p4est_communication.h b/src/p4est_communication.h index 52909e0a5..f4a970357 100644 --- a/src/p4est_communication.h +++ b/src/p4est_communication.h @@ -22,6 +22,13 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/** \file p4est_communication.h + * + * Parallel messaging and support code. + * + * \ingroup p4est + */ + #ifndef P4EST_COMMUNICATION_H #define P4EST_COMMUNICATION_H @@ -36,7 +43,7 @@ SC_EXTERN_C_BEGIN; * search. * \param [in] nmemb Number of entries in array MINUS ONE. * \return Index p such that `gfq[p] <= target < gfq[p + 1]`. - * \note This function differs from \ref p4est_find_partiton + * \note This function differs from \ref p4est_find_partition * since \ref p4est_find_partition searches for two * targets using binary search in an optimized way * but \ref p4est_bsearch_partition only performs a @@ -86,7 +93,7 @@ int p4est_comm_parallel_env_is_null (p4est_t * p4est); /** Reduce MPI communicator to non-empty ranks (i.e., nonzero quadrant counts). * - * \param [in/out] p4est_supercomm Object which communicator is reduced. + * \param [in,out] p4est_supercomm Object which communicator is reduced. * Points to NULL if this p4est does not * exists. * @@ -99,7 +106,7 @@ int p4est_comm_parallel_env_reduce (p4est_t ** * will remain in the reduced communicator regardless whether they are empty * or not. * - * \param [in/out] p4est_supercomm Object which communicator is reduced. + * \param [in,out] p4est_supercomm Object which communicator is reduced. * Points to NULL if this p4est does not * exists. * \param [in] group_add Group of ranks that will remain in @@ -245,8 +252,8 @@ int p4est_comm_find_owner (p4est_t * p4est, * This is determined separately for the beginning and end of the tree. * \param [in] p4est The p4est to work on. * \param [in] which_tree The tree in question must be partially owned. - * \param [out] full_tree[2] Full ownership of beginning and end of tree. - * \param [out] tree_contact[4] True if there are neighbors across the face. + * \param [out] full_tree Full ownership of beginning and end of tree. + * \param [out] tree_contact True if there are neighbors across the face. * \param [out] firstq Smallest possible first quadrant on this core. * \param [out] nextq Smallest possible first quadrant on next core. * Any of tree_contact, firstq and nextq may be NULL. @@ -261,8 +268,8 @@ void p4est_comm_tree_info (p4est_t * p4est, /** Test if the 3x3 neighborhood of a quadrant is owned by this processor. * \param [in] p4est The p4est to work on. * \param [in] which_tree The tree index to work on. - * \param [in] full_tree[2] Flags as computed by p4est_comm_tree_info. - * \param [in] tree_contact[4] Flags as computed by p4est_comm_tree_info. + * \param [in] full_tree Flags as computed by p4est_comm_tree_info. + * \param [in] tree_contact Flags as computed by p4est_comm_tree_info. * \param [in] q The quadrant to be checked. * \return Returns true iff this quadrant's 3x3 neighborhood is owned. */ diff --git a/src/p4est_connectivity.c b/src/p4est_connectivity.c index 78b1875eb..9ba5a5b6b 100644 --- a/src/p4est_connectivity.c +++ b/src/p4est_connectivity.c @@ -33,11 +33,14 @@ #ifndef P4_TO_P8 /* *INDENT-OFF* */ +const int p4est_volume_point = 4; + const int p4est_face_corners[4][2] = {{ 0, 2 }, { 1, 3 }, { 0, 1 }, { 2, 3 }}; +const int p4est_face_points[4] = { 3, 5, 1, 7 }; const int p4est_face_dual[4] = { 1, 0, 3, 2 }; const int p4est_corner_faces[4][2] = @@ -45,6 +48,7 @@ const int p4est_corner_faces[4][2] = { 1, 2 }, { 0, 3 }, { 1, 3 }}; +const int p4est_corner_points[4] = { 0, 2, 6, 8 }; const int p4est_corner_face_corners[4][4] = {{ 0, -1, 0, -1 }, { -1, 0, 1, -1 }, diff --git a/src/p4est_connectivity.h b/src/p4est_connectivity.h index 203c30aa6..6c0cc0c90 100644 --- a/src/p4est_connectivity.h +++ b/src/p4est_connectivity.h @@ -306,15 +306,24 @@ void p4est_connectivity_get_neighbor_transforms /* *INDENT-ON* */ +/** Store the boundary point of the volume in [0, P4EST_INSUL). */ +extern const int p4est_volume_point; + /** Store the corner numbers 0..4 for each tree face. */ extern const int p4est_face_corners[4][2]; +/** For each face number, its boundary point in [0, P4EST_INSUL). */ +extern const int p4est_face_points[4]; + /** Store the face numbers in the face neighbor's system. */ extern const int p4est_face_dual[4]; /** Store the face numbers 0..3 for each tree corner. */ extern const int p4est_corner_faces[4][2]; +/** For each corner number, its boundary point in [0, P4EST_INSUL). */ +extern const int p4est_corner_points[4]; + /** Store the face corner numbers for the faces touching a tree corner. */ extern const int p4est_corner_face_corners[4][4]; diff --git a/src/p4est_iterate.h b/src/p4est_iterate.h index 47ec82a55..937f9938e 100644 --- a/src/p4est_iterate.h +++ b/src/p4est_iterate.h @@ -62,6 +62,25 @@ p4est_iter_volume_info_t; typedef void (*p4est_iter_volume_t) (p4est_iter_volume_info_t * info, void *user_data); +/** Shortcut to access full face information */ +typedef struct p4est_iter_face_side_full +{ + int8_t is_ghost; /**< boolean: local (0) or ghost */ + p4est_quadrant_t *quad; /**< the actual quadrant */ + p4est_locidx_t quadid; /**< index in tree or ghost array */ + +} +p4est_iter_face_side_full_t; + +/** Shortcut to access hanging face information */ +typedef struct p4est_iter_face_side_hanging +{ + int8_t is_ghost[2]; /**< boolean: local (0) or ghost */ + p4est_quadrant_t *quad[2]; /**< the actual quadrant */ + p4est_locidx_t quadid[2]; /**< index in tree or ghost array */ +} +p4est_iter_face_side_hanging_t; + /** Information about one side of a face in the forest. * * If a \a quad is local @@ -80,22 +99,11 @@ typedef struct p4est_iter_face_side two smaller quads (1) */ union p4est_iter_face_side_data { - struct - { - int8_t is_ghost; /**< boolean: local (0) or ghost (1) */ - p4est_quadrant_t *quad; /**< the actual quadrant */ - p4est_locidx_t quadid; /**< index in tree or ghost array */ - } - full; /**< if \a is_hanging = 0, - use is.full to access per-quadrant data */ - struct - { - int8_t is_ghost[2]; /**< boolean: local (0) or ghost (1) */ - p4est_quadrant_t *quad[2]; /**< the actual quadrant */ - p4est_locidx_t quadid[2]; /**< index in tree or ghost array */ - } - hanging; /**< if \a is_hanging = 1, - use is.hanging to access per-quadrant data */ + /** if \a !is_hanging, use is.full to access per-quadrant data */ + p4est_iter_face_side_full_t full; + + /** if \a is_hanging, use is.hanging to access per-quadrant data */ + p4est_iter_face_side_hanging_t hanging; } is; } diff --git a/src/p4est_lnodes.c b/src/p4est_lnodes.c index cb42952ac..d4482c161 100644 --- a/src/p4est_lnodes.c +++ b/src/p4est_lnodes.c @@ -43,9 +43,13 @@ #ifndef P4_TO_P8 #define P4EST_LN_C_OFFSET 4 +const int p4est_lnodes_corner_hanging[4] = + {-1, 1, 0, -1 }; #else #define P8EST_LN_E_OFFSET 6 #define P4EST_LN_C_OFFSET 18 +const int p8est_lnodes_corner_hanging[8] = + {-1, 3, 4, 2, 5, 1, 0, -1 }; #endif static int diff --git a/src/p4est_lnodes.h b/src/p4est_lnodes.h index 3807b3f00..972c4d61a 100644 --- a/src/p4est_lnodes.h +++ b/src/p4est_lnodes.h @@ -29,6 +29,13 @@ SC_EXTERN_C_BEGIN; +/** For each corner, the normal direction of the hanging face. + * The corner index is with respect to a zero child quadrant. + * Corners that may never hang store the value -1. + */ +extern const int p4est_lnodes_corner_hanging[4]; + +/** The face code encodes the configuration of a hanging quadrant. */ typedef int8_t p4est_lnodes_code_t; /** Store a parallel numbering of Lobatto points of a given degree > 0. diff --git a/src/p4est_search.h b/src/p4est_search.h index a68101a86..a49186f26 100644 --- a/src/p4est_search.h +++ b/src/p4est_search.h @@ -62,6 +62,7 @@ SC_EXTERN_C_BEGIN; /** Binary search in partition array. + * * Given two targets \a my_begin and \a my_end, find offsets such that * `search_in[begin] >= my_begin`, `my_end <= search_in[end]`. * If more than one index satisfies the conditions, then the minimal index is the @@ -72,6 +73,7 @@ SC_EXTERN_C_BEGIN; * value of \a search_in \a end is set to \a num_procs - 1. * If none of the above conditions is satisfied, the output is not well defined. * We require `my_begin <= my_begin'. + * * \param [in] num_procs Number of processes to get the length of * \a search_in. * \param [in] search_in The sorted array (ascending) in that the function @@ -138,6 +140,7 @@ p4est_quadrant_t *p4est_find_quadrant_cumulative (p4est_t * p4est, * Given a sorted \b array of quadrants that have a common ancestor at level * \b level, compute the \b indices of the first quadrant in each of the common * ancestor's children at level \b level + 1. + * * \param [in] array The sorted array of quadrants of level > \b level. * \param [in] level The level at which there is a common ancestor. * \param [in,out] indices The indices of the first quadrant in each of @@ -157,6 +160,7 @@ void p4est_split_array (sc_array_t * array, int level, * Given two smallest quadrants, \b lq and \b uq, that mark the first and the * last quadrant in a range of quadrants, determine which portions of the tree * boundary the range touches. + * * \param [in] lq The smallest quadrant at the start of the range: if * NULL, the tree's first quadrant is taken to be the * start of the range. @@ -215,6 +219,7 @@ typedef int (*p4est_search_local_t) (p4est_t * p4est, typedef p4est_search_local_t p4est_search_query_t; /** Search through the local part of a forest. + * * The search is especially efficient if multiple targets, called "points" * below, are searched for simultaneously. * @@ -287,6 +292,7 @@ void p4est_search (p4est_t * p4est, sc_array_t * points); /** Callback function to query, reorder, and reduce a set of quadrants. + * * It receives an array of quadrants and an array of array indices on input. * On output, the array of quadrants is unmodified but the indices may be. * This function may permute the indices and/or choose a subset. @@ -294,6 +300,7 @@ void p4est_search (p4est_t * p4est, * before or after, but not during eventual sorting, since resizing may * reallocate and thus move the array memory. * Indices must remain a permutation. + * * \param [in] p4est The forest to be queried. * \param [in] quadrants The quadrant array under consideration, * each with valid coordinates and level. @@ -311,6 +318,7 @@ typedef int (*p4est_search_reorder_t) (p4est_t * p4est, sc_array_t * indices); /** Run a depth-first traversal, optionally filtering search points. + * * There are three main differences to \ref p4est_search_local : * * * Before beginning the recursion, we call the \a reorder_fn callback @@ -362,6 +370,7 @@ void p4est_search_reorder (p4est_t * p4est, sc_array_t * points); /** Callback function for the partition recursion. + * * \param [in] p4est The forest to traverse. * Its local quadrants are never accessed. * \param [in] which_tree The tree number under consideration. @@ -386,6 +395,7 @@ typedef int (*p4est_search_partition_t) (p4est_t * p4est, void *point); /** Traverse the global partition top-down. + * * This is not a collective function. It does not communicate. * We proceed top-down through the partition, identically on all processors * except for the results of two user-provided callbacks. The recursion will only @@ -393,8 +403,7 @@ typedef int (*p4est_search_partition_t) (p4est_t * p4est, * functions can be used to stop a branch recursion even for split branches. * This function offers the option to search for arbitrary user-defined points * analogously to \ref p4est_search_local. - * \note Traversing the whole processor partition will be at least O(P), - * so sensible use of the callback function is advised to cut it short. + * * \param [in] p4est The forest to traverse. * Its local quadrants are never accessed. * \param [in] call_post If true, call quadrant callback both pre and post @@ -417,6 +426,7 @@ void p4est_search_partition (p4est_t *p4est, int call_post, sc_array_t *points); /** Traverse some given global partition top-down. + * * The partition can be that of any p4est, not necessarily known to the * caller. This is not a collective function. It does not communicate. * We proceed top-down through the partition, identically on all processors @@ -425,8 +435,7 @@ void p4est_search_partition (p4est_t *p4est, int call_post, * functions can be used to stop a branch recursion even for split branches. * This function offers the option to search for arbitrary user-defined points * analogously to \ref p4est_search_local. - * \note Traversing the whole given partition will be at least O(P), - * so sensible use of the callback function is advised to cut it short. + * * \param [in] gfq Partition offsets to traverse. Length \a nmemb + 1. * \param [in] gfp Partition position to traverse. Length \a nmemb + 1. * \param [in] nmemb Number of processors encoded in \a gfq (plus one). @@ -453,6 +462,7 @@ void p4est_search_partition_gfx sc_array_t *points); /** Traverse some given global partition top-down. + * * The partition can be that of any p4est, not necessarily known to the * caller. This is not a collective function. It does not communicate. * We proceed top-down through the partition, identically on all processors @@ -464,8 +474,7 @@ void p4est_search_partition_gfx * This function is similar to \ref p4est_search_partition_gfx, but does not * require the \ref p4est_gloidx_t array gfq. If gfq is available, using * \ref p4est_search_partition_gfx is recommended, because it is slightly faster. - * \note Traversing the whole given partition will be at least O(P), - * so sensible use of the callback function is advised to cut it short. + * * \param [in] gfp Partition position to traverse. Length \a nmemb + 1. * \param [in] nmemb Number of processors encoded in \a gfp (plus one). * \param [in] num_trees Tree number must match the contents of \a gfp. @@ -490,6 +499,7 @@ void p4est_search_partition_gfp p4est_search_partition_t point_fn, sc_array_t *points); /** Callback function for the top-down search through the whole forest. + * * \param [in] p4est The forest to search. * We recurse through the trees one after another. * \param [in] which_tree The current tree number. diff --git a/src/p4est_to_p8est.h b/src/p4est_to_p8est.h index 46ce7c01f..c34efcd09 100644 --- a/src/p4est_to_p8est.h +++ b/src/p4est_to_p8est.h @@ -156,6 +156,8 @@ #define p4est_lnodes_buffer_t p8est_lnodes_buffer_t #define p4est_iter_volume_t p8est_iter_volume_t #define p4est_iter_volume_info_t p8est_iter_volume_info_t +#define p4est_iter_face_side_full_t p8est_iter_face_side_full_t +#define p4est_iter_face_side_hanging_t p8est_iter_face_side_hanging_t #define p4est_iter_face_t p8est_iter_face_t #define p4est_iter_face_info_t p8est_iter_face_info_t #define p4est_iter_face_side_t p8est_iter_face_side_t @@ -183,11 +185,15 @@ #define p4est_file_section_metadata_t p8est_file_section_metadata_t /* redefine external variables */ +#define p4est_volume_point p8est_volume_point #define p4est_face_corners p8est_face_corners +#define p4est_face_points p8est_face_points #define p4est_face_dual p8est_face_dual #define p4est_corner_faces p8est_corner_faces #define p4est_corner_face_corners p8est_corner_face_corners +#define p4est_corner_points p8est_corner_points #define p4est_child_corner_faces p8est_child_corner_faces +#define p4est_lnodes_corner_hanging p8est_lnodes_corner_hanging #define P4EST_DATA_UNINITIALIZED P8EST_DATA_UNINITIALIZED /* functions in p4est_connectivity */ diff --git a/src/p4est_wrap.c b/src/p4est_wrap.c index 0697fc830..da6342206 100644 --- a/src/p4est_wrap.c +++ b/src/p4est_wrap.c @@ -182,6 +182,7 @@ p4est_wrap_params_init (p4est_wrap_params_t *params) params->coarsen_delay = 0; params->coarsen_affect = 0; params->partition_for_coarsening = 1; + params->store_adapted = 0; params->user_pointer = NULL; } @@ -300,7 +301,7 @@ p4est_wrap_new_copy (p4est_wrap_t * source, size_t data_size, pp = P4EST_ALLOC_ZERO (p4est_wrap_t, 1); - /* copy the sources wrap paramters; however the copy will is hollow */ + /* copy the sources wrap parameters; however the copy is hollow */ pp->params = source->params; pp->params.hollow = 1; @@ -319,6 +320,24 @@ p4est_wrap_new_copy (p4est_wrap_t * source, size_t data_size, p4est_reset_data (pp->p4est, data_size, NULL, NULL); } + /* copy newly_adapted arrays if set */ + P4EST_ASSERT ((source->newly_refined == NULL) == + (source->newly_coarsened == NULL)); + if (source->newly_refined != NULL) { + P4EST_ASSERT (source->newly_refined->elem_size == + sizeof (p4est_locidx_t)); + P4EST_ASSERT (source->newly_coarsened->elem_size == + sizeof (p4est_locidx_t)); + pp->newly_refined = + sc_array_new_count (sizeof (p4est_locidx_t), + source->newly_refined->elem_count); + sc_array_copy (pp->newly_refined, source->newly_refined); + pp->newly_coarsened = + sc_array_new_count (sizeof (p4est_locidx_t), + source->newly_coarsened->elem_count); + sc_array_copy (pp->newly_coarsened, source->newly_coarsened); + } + pp->weight_exponent = 0; /* keep this even though using ALLOC_ZERO */ pp->p4est->user_pointer = pp; @@ -462,6 +481,14 @@ p4est_wrap_destroy (p4est_wrap_t * pp) p4est_ghost_destroy (pp->ghost); } + P4EST_ASSERT ((pp->newly_refined == NULL) == (pp->newly_coarsened == NULL)); + if (pp->newly_refined != NULL) { + P4EST_ASSERT (pp->newly_refined->elem_size == sizeof (p4est_locidx_t)); + P4EST_ASSERT (pp->newly_coarsened->elem_size == sizeof (p4est_locidx_t)); + sc_array_destroy (pp->newly_refined); + sc_array_destroy (pp->newly_coarsened); + } + P4EST_FREE (pp->flags); P4EST_FREE (pp->temp_flags); @@ -558,6 +585,7 @@ p4est_wrap_set_coarsen_delay (p4est_wrap_t * pp, } } +/*** OUTDATED FUNCTION ***/ void p4est_wrap_set_partitioning (p4est_wrap_t *pp, int partition_for_coarsening) { @@ -646,6 +674,14 @@ p4est_wrap_adapt (p4est_wrap_t * pp) p4est_gloidx_t global_num, global_num_entry; unsigned checksum_entry, checksum_exit; p4est_t *p4est = pp->p4est; + sc_array_t *quad_levels; + int8_t *level; + size_t qz, zz; + p4est_topidx_t tt; + p4est_tree_t *tree; + sc_array_t *tquadrants; + p4est_quadrant_t *quadrant; + p4est_locidx_t *lqid; P4EST_ASSERT (!pp->params.hollow); P4EST_ASSERT (pp->params.coarsen_delay >= 0); @@ -660,12 +696,34 @@ p4est_wrap_adapt (p4est_wrap_t * pp) P4EST_ASSERT (pp->num_refine_flags >= 0 && pp->num_refine_flags <= p4est->local_num_quadrants); + quad_levels = sc_array_new (sizeof (int8_t)); + if (pp->params.store_adapted) { + P4EST_ASSERT (p4est_is_balanced + (pp->p4est, pp->params.mesh_params.btype)); + + /* store quadrant levels to compare with future adapted version */ + sc_array_resize (quad_levels, p4est->local_num_quadrants); + + /* iterate over p4est and store leaf levels */ + for (tt = p4est->first_local_tree, qz = 0; tt <= p4est->last_local_tree; + ++tt) { + tree = p4est_tree_array_index (p4est->trees, tt); + tquadrants = &tree->quadrants; + for (zz = 0; zz < tquadrants->elem_count; ++zz, ++qz) { + level = (int8_t *) sc_array_index (quad_levels, qz); + quadrant = p4est_quadrant_array_index (tquadrants, zz); + *level = quadrant->level; + } + } + } + /* This allocation is optimistic when not all refine requests are honored */ pp->temp_flags = P4EST_ALLOC_ZERO (uint8_t, p4est->local_num_quadrants + (P4EST_CHILDREN - 1) * pp->num_refine_flags); + checksum_entry = 0; if ((have_zlib = p4est_have_zlib())) { /* store p4est checksum on entry to compare with results after balancing */ global_num_entry = p4est->global_num_quadrants; @@ -739,6 +797,53 @@ p4est_wrap_adapt (p4est_wrap_t * pp) #endif pp->num_refine_flags = 0; + /* update newly_adapted arrays */ + P4EST_ASSERT ((pp->newly_refined == NULL) == (pp->newly_coarsened == NULL)); + if (pp->newly_refined != NULL) { + /* delete previous newly_adapted arrays, if there are any */ + sc_array_destroy_null (&pp->newly_refined); + sc_array_destroy_null (&pp->newly_coarsened); + } + if (pp->params.store_adapted) { + pp->newly_refined = sc_array_new (sizeof (p4est_locidx_t)); + pp->newly_coarsened = sc_array_new (sizeof (p4est_locidx_t)); + + for (tt = p4est->first_local_tree, qz = 0; tt <= p4est->last_local_tree; + ++tt) { + /* refine, coarsen and balance does not affect the range of local trees */ + tree = p4est_tree_array_index (p4est->trees, tt); + tquadrants = &tree->quadrants; + for (zz = 0; zz < tquadrants->elem_count;) { + quadrant = p4est_quadrant_array_index (tquadrants, zz); + level = (int8_t *) sc_array_index (quad_levels, qz); + + /* compare levels to identify adaptation */ + if (quadrant->level > *level) { + /* quadrant was newly refined, store its index in the new p4est */ + lqid = (p4est_locidx_t *) sc_array_push (pp->newly_refined); + *lqid = (p4est_locidx_t) zz; + zz += P4EST_CHILDREN; + qz++; + } + else if (quadrant->level < *level) { + /* quadrant was newly coarsened, store its index in the new p4est */ + lqid = (p4est_locidx_t *) sc_array_push (pp->newly_coarsened); + *lqid = (p4est_locidx_t) zz; + zz++; + qz += P4EST_CHILDREN; + } + else { + /* quadrant was not newly adapted */ + zz++; + qz++; + } + } + P4EST_ASSERT (zz == tquadrants->elem_count); + } + P4EST_ASSERT (qz == quad_levels->elem_count); + } + sc_array_destroy (quad_levels); + return changed; } @@ -822,9 +927,11 @@ p4est_wrap_partition (p4est_wrap_t * pp, int weight_exponent, p4est_ghost_destroy (pp->ghost); pp->match_aux = 0; - /* Remember the window onto global quadrant sequence before partition */ - pre_me = pp->p4est->global_first_quadrant[pp->p4est->mpirank]; - pre_next = pp->p4est->global_first_quadrant[pp->p4est->mpirank + 1]; + /* Remember the global first quadrants before partition */ + pp->old_global_first_quadrant = + P4EST_ALLOC (p4est_gloidx_t, pp->p4est->mpisize + 1); + memcpy (pp->old_global_first_quadrant, pp->p4est->global_first_quadrant, + sizeof (p4est_gloidx_t) * (pp->p4est->mpisize + 1)); /* Initialize output for the case that the partition does not change */ if (unchanged_first != NULL) { @@ -858,6 +965,8 @@ p4est_wrap_partition (p4est_wrap_t * pp, int weight_exponent, unchanged_old_first != NULL) { /* compute new windof of local quadrants */ + pre_me = pp->old_global_first_quadrant[pp->p4est->mpirank]; + pre_next = pp->old_global_first_quadrant[pp->p4est->mpirank + 1]; post_me = pp->p4est->global_first_quadrant[pp->p4est->mpirank]; post_next = pp->p4est->global_first_quadrant[pp->p4est->mpirank + 1]; @@ -874,6 +983,8 @@ p4est_wrap_partition (p4est_wrap_t * pp, int weight_exponent, pp->mesh = pp->mesh_aux; pp->ghost_aux = NULL; pp->mesh_aux = NULL; + P4EST_FREE (pp->old_global_first_quadrant); + pp->old_global_first_quadrant = NULL; } return changed; @@ -889,11 +1000,14 @@ p4est_wrap_complete (p4est_wrap_t * pp) P4EST_ASSERT (pp->ghost_aux != NULL); P4EST_ASSERT (pp->mesh_aux != NULL); P4EST_ASSERT (pp->match_aux == 0); + P4EST_ASSERT (pp->old_global_first_quadrant != NULL); p4est_mesh_destroy (pp->mesh_aux); p4est_ghost_destroy (pp->ghost_aux); pp->ghost_aux = NULL; pp->mesh_aux = NULL; + P4EST_FREE (pp->old_global_first_quadrant); + pp->old_global_first_quadrant = NULL; } static p4est_wrap_leaf_t * diff --git a/src/p4est_wrap.h b/src/p4est_wrap.h index 9e4bd0f76..f34180820 100644 --- a/src/p4est_wrap.h +++ b/src/p4est_wrap.h @@ -26,10 +26,15 @@ #define P4EST_WRAP_H /** \file p4est_wrap.h - * The logic in p4est_wrap encapsulates core p4est data structures and provides + * + * This wrapper API encapsulates core p4est data structures and provides * functions that clarify the mark-adapt-partition cycle. There is also an * element iterator that can replace the nested loops over trees and tree * quadrants, respectively, which can help make application code cleaner. + * + * For most new code, using this API is likely not necessary. + * + * \ingroup p4est */ #include @@ -75,12 +80,19 @@ typedef struct modified to allow one level of coarsening when calling \ref p4est_wrap_partition. */ - void *user_pointer; /**< Set the user pointer in - \ref p4est_wrap_t. Subsequently, we + int store_adapted; /**< Boolean: If true, the indices of + most recently adapted quadrants are + stored in the \c newly_refined + and \c newly_coarsened array of + the wrap. */ + void *user_pointer; /**< Set the user pointer in the + \ref p4est_wrap. Subsequently, we will never access it. */ } p4est_wrap_params_t; +/** Wrapping a \ref p4est object for an alternative API. + */ typedef struct p4est_wrap { /* collection of wrap-related parameters */ @@ -102,10 +114,25 @@ typedef struct p4est_wrap int p4est_children; p4est_t *p4est; /**< p4est->user_pointer is used internally */ + /* If \a params.store_adapted is true, these arrays store the indices of the + * quadrants refined and coarsened during the most recent call to + * \ref p4est_wrap_adapt. The wrap's \a p4est has to be balanced when entering + * the adaptation, to avoid multi-level refinement. + * The arrays are allocated during the first call of \ref p4est_wrap_adapt. + * At every time the arrays index into the local quadrants of the p4est as it + * was directly after completion of \ref p4est_wrap_adapt. So, they are not + * updated in \ref p4est_wrap_partition. Newly_refined only stores newly + * refined quadrants with child id 0. */ + sc_array_t *newly_refined; /**< Indices of quadrants refined during + most recent \ref p4est_wrap_adapt */ + sc_array_t *newly_coarsened; /**< Indices of quadrants coarsened during + most recent \ref p4est_wrap_adapt */ + /* anything below here is considered private und should not be touched */ int weight_exponent; uint8_t *flags, *temp_flags; p4est_locidx_t num_refine_flags, inside_counter, num_replaced; + p4est_gloidx_t *old_global_first_quadrant; /* for ghost and mesh use p4est_wrap_get_ghost, _mesh declared below */ p4est_ghost_t *ghost; @@ -228,11 +255,12 @@ p4est_wrap_t *p4est_wrap_new_copy (p4est_wrap_t * source, p4est_replace_t replace_fn, void *user_pointer); -/** Create p4est and auxiliary data structures. +/** Create a \ref p4est_wrap and internal helper data structures. * Expects sc_MPI_Init to be called beforehand. */ p4est_wrap_t *p4est_wrap_new_unitsquare (sc_MPI_Comm mpicomm, int initial_level); + p4est_wrap_t *p4est_wrap_new_periodic (sc_MPI_Comm mpicomm, int initial_level); p4est_wrap_t *p4est_wrap_new_rotwrap (sc_MPI_Comm mpicomm, @@ -245,8 +273,12 @@ p4est_wrap_t *p4est_wrap_new_moebius (sc_MPI_Comm mpicomm, int initial_level); p4est_wrap_t *p4est_wrap_new_cubed (sc_MPI_Comm mpicomm, int initial_level); + +/** Create a five-tree setup suitable to build a 2D disk. */ p4est_wrap_t *p4est_wrap_new_disk (sc_MPI_Comm mpicomm, int px, int py, int initial_level); + +/** The rectangular brick is one of the most useful connectivities. */ p4est_wrap_t *p4est_wrap_new_brick (sc_MPI_Comm mpicomm, int bx, int by, int px, int py, int initial_level); @@ -292,6 +324,10 @@ void p4est_wrap_set_coarsen_delay (p4est_wrap_t * pp, * in a manner that allows one level of coarsening. This function does not * automatically repartition the mesh, when switching partition_for_coarsening * to a non-zero value. + * + * \deprecated The function will be removed in the future. Flags for + * partitioning can be set using \ref p4est_wrap_new_params. + * * \param [in,out] pp A valid p4est_wrap structure. * \param [in] partition_for_coarsening Boolean: If true, all future partitions * of the wrap allow one level of coarsening. diff --git a/src/p6est_communication.h b/src/p6est_communication.h index be2fdee46..dc39b7bd2 100644 --- a/src/p6est_communication.h +++ b/src/p6est_communication.h @@ -27,7 +27,7 @@ /** \file p6est_communication.h * - * MPI_Comm management. + * Parallel messaging and support code. * * \ingroup p6est */ @@ -76,7 +76,7 @@ int p6est_comm_parallel_env_is_null (p6est_t * p6est); /** Reduce MPI communicator to non-empty ranks (i.e., nonzero quadrant counts). * - * \param [in/out] p6est_supercomm Object which communicator is reduced. + * \param [in,out] p6est_supercomm Object which communicator is reduced. * points to NULL if this p6est does not * exists. * @@ -89,7 +89,7 @@ int p6est_comm_parallel_env_reduce (p6est_t ** * will remain in the reduced communicator regardless whether they are empty * or not. * - * \param [in/out] p6est_supercomm Object which communicator is reduced. + * \param [in,out] p6est_supercomm Object which communicator is reduced. * Points to NULL if this p6est does not * exists. * \param [in] group_add Group of ranks that will remain in diff --git a/src/p8est_communication.h b/src/p8est_communication.h index 6f2385164..7db399461 100644 --- a/src/p8est_communication.h +++ b/src/p8est_communication.h @@ -22,6 +22,13 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/** \file p8est_communication.h + * + * Parallel messaging and support code. + * + * \ingroup p8est + */ + #ifndef P8EST_COMMUNICATION_H #define P8EST_COMMUNICATION_H @@ -36,7 +43,7 @@ SC_EXTERN_C_BEGIN; * search. * \param [in] nmemb Number of entries in array MINUS ONE. * \return Index p such that `gfq[p] <= target < gfq[p + 1]`. - * \note This function differs from \ref p8est_find_partiton + * \note This function differs from \ref p8est_find_partition * since \ref p8est_find_partition searches for two * targets using binary search in an optimized way * but \ref p8est_bsearch_partition only performs a @@ -86,7 +93,7 @@ int p8est_comm_parallel_env_is_null (p8est_t * p8est); /** Reduce MPI communicator to non-empty ranks (i.e., nonzero quadrant counts). * - * \param [in/out] p8est_supercomm Object which communicator is reduced. + * \param [in,out] p8est_supercomm Object which communicator is reduced. * Points to NULL if this p8est does not * exists. * @@ -99,7 +106,7 @@ int p8est_comm_parallel_env_reduce (p8est_t ** * will remain in the reduced communicator regardless whether they are empty * or not. * - * \param [in/out] p8est_supercomm Object which communicator is reduced. + * \param [in,out] p8est_supercomm Object which communicator is reduced. * Points to NULL if this p8est does not * exists. * \param [in] group_add Group of ranks that will remain in @@ -245,8 +252,8 @@ int p8est_comm_find_owner (p8est_t * p8est, * This is determined separately for the beginning and end of the tree. * \param [in] p8est The p8est to work on. * \param [in] which_tree The tree in question must be partially owned. - * \param [out] full_tree[2] Full ownership of beginning and end of tree. - * \param [out] tree_contact[6] True if there are neighbors across the face. + * \param [out] full_tree Full ownership of beginning and end of tree. + * \param [out] tree_contact True if there are neighbors across the face. * \param [out] firstq Smallest possible first quadrant on this core. * \param [out] nextq Smallest possible first quadrant on next core. * Any of tree_contact, firstq and nextq may be NULL. @@ -261,8 +268,8 @@ void p8est_comm_tree_info (p8est_t * p8est, /** Test if the 3x3 neighborhood of a quadrant is owned by this processor. * \param [in] p8est The p8est to work on. * \param [in] which_tree The tree index to work on. - * \param [in] full_tree[2] Flags as computed by p8est_comm_tree_info. - * \param [in] tree_contact[6] Flags as computed by p8est_comm_tree_info. + * \param [in] full_tree Flags as computed by p8est_comm_tree_info. + * \param [in] tree_contact Flags as computed by p8est_comm_tree_info. * \param [in] q The quadrant to be checked. * \return Returns true iff this quadrant's 3x3 neighborhood is owned. */ diff --git a/src/p8est_connectivity.c b/src/p8est_connectivity.c index bc1e8f867..977d2b45c 100644 --- a/src/p8est_connectivity.c +++ b/src/p8est_connectivity.c @@ -27,6 +27,8 @@ #include /* *INDENT-OFF* */ +const int p8est_volume_point = 13; + const int p8est_face_corners[6][4] = {{ 0, 2, 4, 6 }, { 1, 3, 5, 7 }, @@ -41,7 +43,9 @@ const int p8est_face_edges[6][4] = { 1, 3, 10, 11 }, { 0, 1, 4, 5 }, { 2, 3, 6, 7 }}; +const int p8est_face_points[6] = { 12, 14, 10, 16, 4, 22 }; const int p8est_face_dual[6] = { 1, 0, 3, 2, 5, 4 }; + const int p8est_face_permutations[8][4] = {{ 0, 1, 2, 3 }, /* no. 0 of 0..23 */ { 0, 2, 1, 3 }, /* no. 2 of 0..23 */ @@ -103,6 +107,10 @@ const int p8est_edge_corners[12][2] = { 1, 5 }, { 2, 6 }, { 3, 7 }}; +const int p8est_edge_points[12] = +{ 1, 7, 19, 25, + 3, 5, 21, 23, + 9, 11, 15, 17 }; const int p8est_edge_edge_corners[12][8] = {{ 0, 1, -1, -1, -1, -1, -1, -1}, { -1, -1, 0, 1, -1, -1, -1, -1}, @@ -161,6 +169,7 @@ const int p8est_corner_edges[8][3] = { 2, 7, 9 }, { 3, 6, 10 }, { 3, 7, 11 }}; +const int p8est_corner_points[8] = { 0, 2, 6, 8, 18, 20, 24, 26 }; const int p8est_corner_face_corners[8][6] = {{ 0, -1, 0, -1, 0, -1 }, { -1, 0, 1, -1, 1, -1 }, diff --git a/src/p8est_connectivity.h b/src/p8est_connectivity.h index 033496ca0..14e2ec282 100644 --- a/src/p8est_connectivity.h +++ b/src/p8est_connectivity.h @@ -360,12 +360,18 @@ void p8est_connectivity_get_neighbor_transforms /* *INDENT-ON* */ +/** Store the boundary point of the volume in [0, P8EST_INSUL). */ +extern const int p8est_volume_point; + /** Store the corner numbers 0..7 for each tree face. */ extern const int p8est_face_corners[6][4]; /** Store the edge numbers 0..12 for each tree face. */ extern const int p8est_face_edges[6][4]; +/** For each face number, its boundary point in [0, P8EST_INSUL). */ +extern const int p8est_face_points[6]; + /** Store the face numbers in the face neighbor's system. */ extern const int p8est_face_dual[6]; @@ -395,6 +401,9 @@ extern const int p8est_edge_faces[12][2]; /** Store the corner numbers 0..8 for each tree edge. */ extern const int p8est_edge_corners[12][2]; +/** For each edge number, its boundary point in [0, P8EST_INSUL). */ +extern const int p8est_edge_points[12]; + /** Store the edge corner numbers 0..1 for the corners touching a tree edge or -1 if combination is invalid */ extern const int p8est_edge_edge_corners[12][8]; @@ -413,6 +422,9 @@ extern const int p8est_corner_faces[8][3]; /** Store the edge numbers 0..11 for each tree corner. */ extern const int p8est_corner_edges[8][3]; +/** For each corner number, its boundary point in [0, P8EST_INSUL). */ +extern const int p8est_corner_points[8]; + /** Store the face corner numbers for the faces touching a tree corner. Is -1 for invalid combinations. */ extern const int p8est_corner_face_corners[8][6]; diff --git a/src/p8est_iterate.h b/src/p8est_iterate.h index f8124c015..081ea1625 100644 --- a/src/p8est_iterate.h +++ b/src/p8est_iterate.h @@ -62,6 +62,25 @@ p8est_iter_volume_info_t; typedef void (*p8est_iter_volume_t) (p8est_iter_volume_info_t * info, void *user_data); +/** Shortcut to access full face information */ +typedef struct p8est_iter_face_side_full +{ + int8_t is_ghost; /**< boolean: local (0) or ghost */ + p8est_quadrant_t *quad; /**< the actual quadrant */ + p4est_locidx_t quadid; /**< index in tree or ghost array */ + +} +p8est_iter_face_side_full_t; + +/** Shortcut to access hanging face information */ +typedef struct p8est_iter_face_side_hanging +{ + int8_t is_ghost[4]; /**< boolean: local (0) or ghost */ + p8est_quadrant_t *quad[4]; /**< the actual quadrant */ + p4est_locidx_t quadid[4]; /**< index in tree or ghost array */ +} +p8est_iter_face_side_hanging_t; + /** Information about one side of a face in the forest. If a \a quad is local * (\a is_ghost is false), then its \a quadid indexes the tree's quadrant array; * otherwise, it indexes the ghosts array. If the face is hanging, then the @@ -78,22 +97,11 @@ typedef struct p8est_iter_face_side four smaller quads (1) */ union p8est_iter_face_side_data { - struct - { - int8_t is_ghost; /**< boolean: local (0) or ghost (1) */ - p8est_quadrant_t *quad; /**< the actual quadrant */ - p4est_locidx_t quadid; /**< index in tree or ghost array */ - } - full; /**< if \a is_hanging = 0, - use is.full to access per-quadrant data */ - struct - { - int8_t is_ghost[4]; /**< boolean: local (0) or ghost (1) */ - p8est_quadrant_t *quad[4]; /**< the actual quadrant */ - p4est_locidx_t quadid[4]; /**< index in tree or ghost array */ - } - hanging; /**< if \a is_hanging = 1, - use is.hanging to access per-quadrant data */ + /** if \a !is_hanging, use is.full to access per-quadrant data */ + p8est_iter_face_side_full_t full; + + /** if \a is_hanging, use is.hanging to access per-quadrant data */ + p8est_iter_face_side_hanging_t hanging; } is; } diff --git a/src/p8est_lnodes.h b/src/p8est_lnodes.h index be060ed9c..9f0feb9f3 100644 --- a/src/p8est_lnodes.h +++ b/src/p8est_lnodes.h @@ -29,6 +29,15 @@ SC_EXTERN_C_BEGIN; +/** For each corner, the direction of the hanging face/edge. + * The corner index is with respect to a zero child quadrant. + * Corners that may hang on a face store its normal direction. + * Corners that may hang on an edge store the edge direction + 3. + * Corners that may never hang store the value -1. + */ +extern const int p8est_lnodes_corner_hanging[8]; + +/** The face code encodes the configuration of a hanging quadrant. */ typedef int16_t p8est_lnodes_code_t; /** Store a parallel numbering of Lobatto points of a given degree > 0. diff --git a/src/p8est_search.h b/src/p8est_search.h index 0d32b1009..1f8c102bb 100644 --- a/src/p8est_search.h +++ b/src/p8est_search.h @@ -62,6 +62,7 @@ SC_EXTERN_C_BEGIN; /** Binary search in partition array. + * * Given two targets \a my_begin and \a my_end, find offsets such that * `search_in[begin] >= my_begin`, `my_end <= search_in[end]`. * If more than one index satisfies the conditions, then the minimal index is the @@ -72,6 +73,7 @@ SC_EXTERN_C_BEGIN; * value of \a search_in \a end is set to \a num_procs - 1. * If none of the above conditions is satisfied, the output is not well defined. * We require `my_begin <= my_begin'. + * * \param [in] num_procs Number of processes to get the length of * \a search_in. * \param [in] search_in The sorted array (ascending) in that the function @@ -138,6 +140,7 @@ p8est_quadrant_t *p8est_find_quadrant_cumulative (p8est_t * p8est, * Given a sorted \b array of quadrants that have a common ancestor at level * \b level, compute the \b indices of the first quadrant in each of the common * ancestor's children at level \b level + 1. + * * \param [in] array The sorted array of quadrants of level > \b level. * \param [in] level The level at which there is a common ancestor. * \param [in,out] indices The indices of the first quadrant in each of @@ -157,6 +160,7 @@ void p8est_split_array (sc_array_t * array, int level, * Given two smallest quadrants, \b lq and \b uq, that mark the first and the * last quadrant in a range of quadrants, determine which portions of the tree * boundary the range touches. + * * \param [in] lq The smallest quadrant at the start of the range: if * NULL, the tree's first quadrant is taken to be the * start of the range. @@ -218,6 +222,7 @@ typedef int (*p8est_search_local_t) (p8est_t * p4est, typedef p8est_search_local_t p8est_search_query_t; /** Search through the local part of a forest. + * * The search is especially efficient if multiple targets, called "points" * below, are searched for simultaneously. * @@ -290,6 +295,7 @@ void p8est_search (p8est_t * p4est, sc_array_t * points); /** Callback function to query, reorder, and reduce a set of quadrants. + * * It receives an array of quadrants and an array of array indices on input. * On output, the array of quadrants is unmodified but the indices may be. * This function may permute the indices and/or choose a subset. @@ -297,6 +303,7 @@ void p8est_search (p8est_t * p4est, * before or after, but not during eventual sorting, since resizing may * reallocate and thus move the array memory. * Indices must remain a permutation. + * * \param [in] p4est The forest to be queried. * \param [in] quadrants The quadrant array under consideration, * each with valid coordinates and level. @@ -314,6 +321,7 @@ typedef int (*p8est_search_reorder_t) (p8est_t * p4est, sc_array_t * indices); /** Run a depth-first traversal, optionally filtering search points. + * * There are three main differences to \ref p8est_search_local : * * * Before beginning the recursion, we call the \a reorder_fn callback @@ -365,6 +373,7 @@ void p8est_search_reorder (p8est_t * p4est, sc_array_t * points); /** Callback function for the partition recursion. + * * \param [in] p4est The forest to traverse. * Its local quadrants are never accessed. * \param [in] which_tree The tree number under consideration. @@ -389,14 +398,14 @@ typedef int (*p8est_search_partition_t) (p8est_t * p4est, void *point); /** Traverse the global partition top-down. + * * We proceed top-down through the partition, identically on all processors * except for the results of two user-provided callbacks. The recursion will only * go down branches that are split between multiple processors. The callback * functions can be used to stop a branch recursion even for split branches. * This function offers the option to search for arbitrary user-defined points * analogously to \ref p8est_search_local. - * \note Traversing the whole processor partition will be at least O(P), - * so sensible use of the callback function is advised to cut it short. + * * \param [in] p4est The forest to traverse. * Its local quadrants are never accessed. * \param [in] call_post If true, call quadrant callback both pre and post @@ -419,6 +428,7 @@ void p8est_search_partition (p8est_t *p4est, int call_post, sc_array_t *points); /** Traverse some given global partition top-down. + * * The partition can be that of any p8est, not necessarily known to the * caller. This is not a collective function. It does not communicate. * We proceed top-down through the partition, identically on all processors @@ -427,8 +437,7 @@ void p8est_search_partition (p8est_t *p4est, int call_post, * functions can be used to stop a branch recursion even for split branches. * This function offers the option to search for arbitrary user-defined points * analogously to \ref p8est_search_local. - * \note Traversing the whole given partition will be at least O(P), - * so sensible use of the callback function is advised to cut it short. + * * \param [in] gfq Partition offsets to traverse. Length \a nmemb + 1. * \param [in] gfp Partition position to traverse. Length \a nmemb + 1. * \param [in] nmemb Number of processors encoded in \a gfq (plus one). @@ -455,6 +464,7 @@ void p8est_search_partition_gfx sc_array_t *points); /** Traverse some given global partition top-down. + * * The partition can be that of any p4est, not necessarily known to the * caller. This is not a collective function. It does not communicate. * We proceed top-down through the partition, identically on all processors @@ -466,8 +476,7 @@ void p8est_search_partition_gfx * This function is similar to \ref p8est_search_partition_gfx, but does not * require the \ref p4est_gloidx_t array gfq. If gfq is available, using * \ref p8est_search_partition_gfx is recommended, because it is slightly faster. - * \note Traversing the whole given partition will be at least O(P), - * so sensible use of the callback function is advised to cut it short. + * * \param [in] gfp Partition position to traverse. Length \a nmemb + 1. * \param [in] nmemb Number of processors encoded in \a gfp (plus one). * \param [in] num_trees Tree number must match the contents of \a gfp. @@ -492,6 +501,7 @@ void p8est_search_partition_gfp p8est_search_partition_t point_fn, sc_array_t *points); /** Callback function for the top-down search through the whole forest. + * * \param [in] p4est The forest to search. * We recurse through the trees one after another. * \param [in] which_tree The current tree number. @@ -540,7 +550,7 @@ void p8est_search_partition_gfp * if they are both equal to \b p4est->mpirank and * the recursion has not reached a leaf yet. */ -typedef int (*p8est_search_all_t) (p8est_t * p8est, +typedef int (*p8est_search_all_t) (p8est_t * p4est, p4est_topidx_t which_tree, p8est_quadrant_t * quadrant, int pfirst, int plast, diff --git a/src/p8est_wrap.h b/src/p8est_wrap.h index ae4ac5f2a..16d912242 100644 --- a/src/p8est_wrap.h +++ b/src/p8est_wrap.h @@ -26,10 +26,15 @@ #define P8EST_WRAP_H /** \file p8est_wrap.h - * The logic in p8est_wrap encapsulates core p4est data structures and provides + * + * This wrapper API encapsulates core p4est data structures and provides * functions that clarify the mark-adapt-partition cycle. There is also an * element iterator that can replace the nested loops over trees and tree * quadrants, respectively, which can help make application code cleaner. + * + * For most new code, using this API is likely not necessary. + * + * \ingroup p8est */ #include @@ -75,12 +80,19 @@ typedef struct modified to allow one level of coarsening when calling \ref p8est_wrap_partition. */ - void *user_pointer; /**< Set the user pointer in - \ref p8est_wrap_t. Subsequently, we + int store_adapted; /**< Boolean: If true, the indices of + most recently adapted quadrants are + stored in the \c newly_refined + and \c newly_coarsened array of + the wrap. */ + void *user_pointer; /**< Set the user pointer in the + \ref p8est_wrap. Subsequently, we will never access it. */ } p8est_wrap_params_t; +/** Wrapping a \ref p8est object for an alternative API. + */ typedef struct p8est_wrap { /* collection of wrap-related parameters */ @@ -102,10 +114,25 @@ typedef struct p8est_wrap int p4est_children; p8est_t *p4est; /**< p4est->user_pointer is used internally */ + /* If \a params.store_adapted is true, these arrays store the indices of the + * quadrants refined and coarsened during the most recent call to + * \ref p8est_wrap_adapt. The wrap's \a p4est has to be balanced when entering + * the adaptation, to avoid multi-level refinement. + * The arrays are allocated during the first call of \ref p8est_wrap_adapt. + * At every time the arrays index into the local quadrants of the p8est as it + * was directly after completion of \ref p8est_wrap_adapt. So, they are not + * updated in \ref p8est_wrap_partition. Newly_refined only stores newly + * refined quadrants with child id 0. */ + sc_array_t *newly_refined; /**< Indices of quadrants refined during + most recent \ref p8est_wrap_adapt */ + sc_array_t *newly_coarsened; /**< Indices of quadrants coarsened during + most recent \ref p8est_wrap_adapt */ + /* anything below here is considered private und should not be touched */ int weight_exponent; uint8_t *flags, *temp_flags; p4est_locidx_t num_refine_flags, inside_counter, num_replaced; + p4est_gloidx_t *old_global_first_quadrant; /* for ghost and mesh use p8est_wrap_get_ghost, _mesh declared below */ p8est_ghost_t *ghost; @@ -228,7 +255,7 @@ p8est_wrap_t *p8est_wrap_new_copy (p8est_wrap_t * source, p8est_replace_t replace_fn, void *user_pointer); -/** Create p8est and auxiliary data structures. +/** Create a \ref p8est_wrap and internal helper data structures. * Expects sc_MPI_Init to be called beforehand. */ p8est_wrap_t *p8est_wrap_new_unitcube (sc_MPI_Comm mpicomm, @@ -277,7 +304,11 @@ void p8est_wrap_set_coarsen_delay (p8est_wrap_t * pp, * in a manner that allows one level of coarsening. This function does not * automatically repartition the mesh, when switching partition_for_coarsening * to a non-zero value. - * \param [in,out] pp A valid p8est_wrap structure. + * + * \deprecated The function will be removed in the future. Flags for + * partitioning can be set using \ref p8est_wrap_new_params. + * + * \param [in,out] pp A valid p4est_wrap structure. * \param [in] partition_for_coarsening Boolean: If true, all future partitions * of the wrap allow one level of coarsening. * Suggested default: 1.