Files
mfem/tests/unit/mesh/test_bb_grid_map.cpp
T

165 lines
4.5 KiB
C++

// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "mfem.hpp"
#include "unit_tests.hpp"
using namespace mfem;
TEST_CASE("BBoxTensorGridMap nD", "[BBoxTensorGridMap]")
{
// Create a Cartesian mesh on [0,1]^D.
int dim = GENERATE(1, 2, 3);
CAPTURE(dim);
Mesh mesh;
if (dim == 1)
{
mesh = Mesh::MakeCartesian1D(2);
}
else if (dim == 2)
{
mesh = Mesh::MakeCartesian2D(2, 2, Element::QUADRILATERAL);
}
else if (dim == 3)
{
mesh = Mesh::MakeCartesian3D(2, 2, 2, Element::HEXAHEDRON);
}
// Create map with a 4^dim tensor grid.
int nx = 4;
BBoxTensorGridMap map(mesh, nx);
// Test each element's center
Vector center(dim);
for (int e = 0; e < mesh.GetNE(); e++)
{
mesh.GetElementCenter(e, center);
Array<int> elems = map.MapPointToElements(center);
REQUIRE(elems.Size() > 0);
REQUIRE(elems.Find(e) >= 0);
}
// Test point outside
Vector pt(dim);
pt = 0.0;
pt(0) = 1.5;
Array<int> elems = map.MapPointToElements(pt);
REQUIRE(elems.Size() == 0);
}
TEST_CASE("BBoxTensorGridMap Boundary", "[BBoxTensorGridMap]")
{
// Create a 1x1 quad mesh on [0,1]x[0,1]
Mesh mesh = Mesh::MakeCartesian2D(2, 2, Element::QUADRILATERAL);
// Create map with 2x2 grid
int nx = 2;
BBoxTensorGridMap map(mesh, nx);
// Point exactly on the boundary of all 4 tensor grid cells
Vector pt(2);
pt(0) = 0.5; pt(1) = 0.5;
int grid_cell = map.GetGridCellFromPoint(pt);
REQUIRE(grid_cell == 3); // cell index should be 3 (top-right)
// This should include mesh element 2 (top-right) in the candidate list.
Array<int> elems = map.MapPointToElements(pt);
REQUIRE(elems.Size() > 0);
REQUIRE(elems.Find(2) >= 0);
}
TEST_CASE("BBoxTensorGridMap Empty", "[BBoxTensorGridMap]")
{
int dim = GENERATE(1, 2, 3);
bool by_max_size = GENERATE(false, true);
CAPTURE(dim);
CAPTURE(by_max_size);
Vector elmin, elmax;
Array<int> nx(dim);
nx = 4;
const int n = 4;
BBoxTensorGridMap map_array(elmin, elmax, 0, dim, nx, by_max_size);
BBoxTensorGridMap map_scalar(elmin, elmax, 0, dim, n, by_max_size);
Vector pt(dim);
pt = 0.5;
Array<int> elems = map_array.MapPointToElements(pt);
REQUIRE(elems.Size() == 0);
elems = map_scalar.MapPointToElements(pt);
REQUIRE(elems.Size() == 0);
}
#if defined(MFEM_USE_MPI) && defined(MFEM_USE_GSLIB)
TEST_CASE("GlobalBBoxTensorGridMap Parallel",
"[GlobalBBoxTensorGridMap][Parallel]")
{
int num_procs;
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
int myid;
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// Create a mesh on [0,1]^D
int dim = GENERATE(2, 3);
CAPTURE(dim);
Mesh mesh;
if (dim == 2)
{
mesh = Mesh::MakeCartesian2D(4, 4, Element::QUADRILATERAL);
}
else if (dim == 3)
{
mesh = Mesh::MakeCartesian3D(4, 4, 4, Element::HEXAHEDRON);
}
int nel = mesh.GetNE();
Array<int> partitioning(mesh.GetNE());
for (int e = 0; e < mesh.GetNE(); e++)
{
partitioning[e] = e % num_procs;
}
ParMesh pmesh(MPI_COMM_WORLD, mesh, partitioning.GetData());
// Setup a list of points to find - center of each element, plus one point
// outside the global bounding box.
Vector centers((nel + 1)*dim);
for (int e = 0; e < nel; e++)
{
Vector center_el(centers.GetData() + e*dim, dim);
mesh.GetElementCenter(e, center_el);
}
for (int d = 0; d < dim; d++)
{
centers(nel*dim + d) = 2.0;
}
// Create map with 4x4x4 global grid
int nx = 4;
GlobalBBoxTensorGridMap map(pmesh, nx);
// Test MapPointsToProcs - each point should map to the processor owning the
// element, and outside points should have an empty candidate list.
std::map<int, std::vector<int>> pt_to_procs;
map.MapPointsToProcs(centers, 1, pt_to_procs);
REQUIRE(pt_to_procs.size() == nel + 1);
for (int i = 0; i < nel; i++)
{
std::vector<int> procs = pt_to_procs[i];
REQUIRE(procs.size() > 0);
REQUIRE(procs[0] == i % num_procs);
}
REQUIRE(pt_to_procs[nel].empty());
}
#endif