Advanced Utilities
Advanced mesh operations and transformations.
Rodin provides advanced utilities for mesh manipulation, transformation, and analysis.
Introduction
Beyond basic mesh creation and queries, Rodin offers powerful utilities for mesh transformation, domain decomposition, and advanced operations.
Mesh Transformations
Scaling
Scale all mesh coordinates by a factor:
#include <Rodin/Geometry.h> using namespace Rodin; using namespace Rodin::Geometry; int main() { Mesh mesh; mesh = mesh.UniformGrid(Polytope::Type::Triangle, {16, 16}); // Scale mesh by factor of 2.0 mesh.scale(2.0); // Domain is now [0, 2] x [0, 2] std::cout << "Volume after scaling: " << mesh.getVolume() << std::endl; return 0; }
Displacement
Displace mesh nodes using a vector-valued function:
#include <Rodin/Geometry.h> #include <Rodin/Variational.h> using namespace Rodin; using namespace Rodin::Geometry; using namespace Rodin::Variational; int main() { Mesh mesh; mesh = mesh.UniformGrid(Polytope::Type::Triangle, {16, 16}); P1 Vh(mesh); // Define displacement field VectorFunction displacement( [](const Point& p) { Math::Vector<Real> u(2); u(0) = 0.1 * std::sin(2 * M_PI * p.x()); u(1) = 0.1 * std::sin(2 * M_PI * p.y()); return u; }, mesh.getSpaceDimension()); // Displace mesh mesh.displace(displacement); return 0; }
SubMeshes
Create submeshes representing subregions:
Creating SubMeshes
#include <Rodin/Geometry.h> using namespace Rodin; using namespace Rodin::Geometry; int main() { Mesh mesh; mesh = mesh.UniformGrid(Polytope::Type::Triangle, {16, 16}); // Create submesh from attribute 1 SubMesh submesh = mesh.trace(1); std::cout << "Parent mesh cells: " << mesh.getCellCount() << std::endl; std::cout << "SubMesh cells: " << submesh.getCellCount() << std::endl; // Access parent mesh const Mesh& parent = submesh.getParent(); return 0; }
Boundary SubMesh
mesh.getConnectivity().compute(1, 2); // Create submesh of boundary SubMesh boundary = mesh.skin(); std::cout << "Boundary elements: " << boundary.getCellCount() << std::endl;
Connected Component Labeling
Find connected components in the mesh:
mesh.getConnectivity().compute(2, 2); // Find connected components auto ccl = mesh.ccl( [](const Polytope& p1, const Polytope& p2) { // Define adjacency criterion return true; // All adjacent cells are connected }); std::cout << "Found " << ccl.getCount() << " connected components" << std::endl; for (const auto& component : ccl) { std::cout << "Component with " << component.size() << " cells" << std::endl; }
Domain Decomposition
Partition meshes for parallel computing:
Balanced Partitioning
#include <Rodin/Geometry.h> using namespace Rodin; using namespace Rodin::Geometry; int main() { Mesh mesh; mesh = mesh.UniformGrid(Polytope::Type::Triangle, {64, 64}); // Partition into 4 subdomains size_t numParts = 4; BalancedCompactPartitioner partitioner; auto shards = partitioner.partition(mesh, numParts); for (size_t i = 0; i < shards.size(); ++i) { std::cout << "Shard " << i << " has " << shards[i].getCellCount() << " cells" << std::endl; } return 0; }
Greedy Partitioning
GreedyPartitioner partitioner; auto shards = partitioner.partition(mesh, numParts);
Coordinate Operations
Setting Coordinates
// Set coordinates of vertex 0 mesh.setVertexCoordinates(0, 1.5, 0); // x-coordinate mesh.setVertexCoordinates(0, 2.5, 1); // y-coordinate // Or set all at once Math::SpatialPoint coords(2); coords << 1.5, 2.5; mesh.setVertexCoordinates(0, coords);
Cache Management
Clear cached data:
// Flush cached transformations and derived data mesh.flush();
This is useful after modifying mesh coordinates to ensure transformations are recomputed.
Complete Example
#include <Rodin/Geometry.h> using namespace Rodin; using namespace Rodin::Geometry; int main() { // Create mesh Mesh mesh; mesh = mesh.UniformGrid(Polytope::Type::Triangle, {32, 32}); std::cout << "Original mesh:" << std::endl; std::cout << " Volume: " << mesh.getVolume() << std::endl; // Scale mesh mesh.scale(2.0); std::cout << "\nAfter scaling by 2.0:" << std::endl; std::cout << " Volume: " << mesh.getVolume() << std::endl; // Create boundary submesh mesh.getConnectivity().compute(1, 2); SubMesh boundary = mesh.skin(); std::cout << "\nBoundary:" << std::endl; std::cout << " Elements: " << boundary.getCellCount() << std::endl; std::cout << " Perimeter: " << boundary.getMeasure(1) << std::endl; // Find connected components mesh.getConnectivity().compute(2, 2); auto ccl = mesh.ccl( [](const Polytope& p1, const Polytope& p2) { return true; }); std::cout << "\nConnected components: " << ccl.getCount() << std::endl; // Partition mesh BalancedCompactPartitioner partitioner; auto shards = partitioner.partition(mesh, 4); std::cout << "\nPartitioned into " << shards.size() << " shards" << std::endl; for (size_t i = 0; i < shards.size(); ++i) { std::cout << " Shard " << i << ": " << shards[i].getCellCount() << " cells" << std::endl; } return 0; }
Advanced Topics
Custom Builder
Use the builder for complete control:
auto builder = Mesh::Build(); builder.initialize(2) .reserve(2, 100) // Reserve space for 100 cells .nodes(50); // 50 vertices // Add vertices and cells... Mesh mesh = builder.finalize();
Transformations
Access and modify polytope transformations:
const auto& trans = mesh.getPolytopeTransformation(2, 0); // Cell 0 // Use transformation for geometric computations
See Also
- Meshes overview
- SubMesh reference
- Partitioner reference
- Examples:
- examples/Geometry/Displace.cpp
- examples/Geometry/Skin.cpp
- examples/Geometry/CCL.cpp
- examples/Geometry/BalancedCompactPartitioner.cpp