Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
StructuredMeshSimple.cpp File Reference

Example demonstrating creation and query of structured meshes in MOAB. More...

#include "moab/Core.hpp"
#include "moab/ScdInterface.hpp"
#include "moab/ProgOptions.hpp"
#include "moab/CN.hpp"
#include <array>
#include <cmath>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <vector>
+ Include dependency graph for StructuredMeshSimple.cpp:

Go to the source code of this file.

Namespaces

 anonymous_namespace{StructuredMeshSimple.cpp}
 

Functions

int main (int argc, char **argv)
 

Variables

constexpr int anonymous_namespace{StructuredMeshSimple.cpp}::DEFAULT_DIMENSION = 3
 
constexpr int anonymous_namespace{StructuredMeshSimple.cpp}::DEFAULT_ELEMENTS_PER_SIDE = 10
 

Detailed Description

Example demonstrating creation and query of structured meshes in MOAB.

This example shows how to:

  • Create structured meshes in 1D, 2D, or 3D
  • Work with structured mesh interfaces (ScdInterface)
  • Handle both serial and parallel structured mesh creation
  • Query mesh entities and their connectivity
  • Access element coordinates and connectivity
  • Use parametric indexing for structured meshes

In serial mode, a single N*N*N block of elements is created. In parallel mode, each processor gets an N*N*N block arranged in a 1D column, sharing vertices and faces at interfaces.

Author
MOAB Development Team
Date
2024

Show creation and query of structured mesh, serial or parallel, through MOAB's structured mesh interface. This is an example showing creation and query of a 3D structured mesh. In serial, a single N*N*N block of elements is created; in parallel, each proc gets an N*N*N block, with blocks arranged in a 1d column, sharing vertices and faces at their interfaces (proc 0 has no left neighbor and proc P-1 no right neighbor). Each square block of hex elements is then referenced by its ijk parameterization. 1D and 2D examples could be made simply by changing the dimension parameter passed into the MOAB functions.
This example :

  1. Instantiate MOAB and get the structured mesh interface
  2. Decide what the local parameters of the mesh will be, based on parallel/serial and rank.
  3. Create a N^d structured mesh, which includes (N+1)^d vertices and N^d elements.
  4. Get the vertices and elements from moab and check their numbers against (N+1)^d and N^d, resp.
  5. Loop over elements in d nested loops over i, j, k; for each (i,j,k):
    1. Get the element corresponding to (i,j,k)
    2. Get the connectivity of the element
    3. Get the coordinates of the vertices comprising that element
  6. Release the structured mesh interface and destroy the MOAB instance

To run: ./StructuredMeshSimple [d [N] ]
(default values so can run w/ no user interaction)

Parameters
argcNumber of command line arguments
argvCommand line arguments array
Returns
0 on success, 1 on failure

Definition in file StructuredMeshSimple.cpp.

Function Documentation

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 81 of file StructuredMeshSimple.cpp.

82 {
83  // Initialize MPI if available
84 #ifdef MOAB_HAVE_MPI
85  if( MPI_Init( &argc, &argv ) != MPI_SUCCESS )
86  {
87  std::cerr << "MPI_Init failed" << std::endl;
88  return 1;
89  }
90 
91  // Ensure MPI is properly finalized when we exit
92  struct MPIFinalizer
93  {
94  void operator()( int* ) const
95  {
96  MPI_Finalize();
97  }
98  };
99  std::unique_ptr< int, MPIFinalizer > mpi_guard( nullptr );
100 #endif
101 
102  // Parse command line options
103  int dimension = DEFAULT_DIMENSION;
104  int elements_per_side = DEFAULT_ELEMENTS_PER_SIDE;
105 
106  try
107  {
108  ProgOptions opts;
109  opts.addOpt< int >( "dim,d", "Dimension of mesh (default=3)", &dimension );
110  opts.addOpt< int >( ",n", "Number of elements on a side (default=10)", &elements_per_side );
111  opts.parseCommandLine( argc, argv );
112 
113  // Validate input
114  if( dimension < 1 || dimension > 3 )
115  {
116  throw std::invalid_argument( "Dimension must be 1, 2, or 3" );
117  }
118  if( elements_per_side < 1 )
119  {
120  throw std::invalid_argument( "Number of elements must be positive" );
121  }
122  }
123  catch( const std::exception& e )
124  {
125  std::cerr << "Error parsing command line: " << e.what() << std::endl;
126  return 1;
127  }
128 
129  // Initialize MOAB
130  std::unique_ptr< Core > moab_instance = std::make_unique< Core >();
131  if( !moab_instance )
132  {
133  std::cerr << "Failed to create MOAB instance" << std::endl;
134  return 1;
135  }
136 
137  // Get the structured mesh interface
138  ScdInterface* scd_interface = nullptr;
139  MB_CHK_SET_ERR( moab_instance->query_interface( scd_interface ), "Failed to get ScdInterface" );
140  if( !scd_interface )
141  {
142  std::cerr << "Failed to get ScdInterface: null pointer returned" << std::endl;
143  return 1;
144  }
145 
146  // 1. Determine local parameters based on parallel/serial and rank
147  int rank = 0;
148  int ilow = 0;
149  int ihigh = elements_per_side;
150 
151 #ifdef MOAB_HAVE_MPI
152  int nprocs = 1;
153  MPI_Comm_rank( MPI_COMM_WORLD, &rank );
154  MPI_Comm_size( MPI_COMM_WORLD, &nprocs );
155 
156  // Calculate local range for this process
157  const int elements_per_proc = elements_per_side / nprocs;
158  const int remainder = elements_per_side % nprocs;
159 
160  // Distribute elements among processes
161  ilow = rank * elements_per_proc + std::min( rank, remainder );
162  ihigh = ilow + elements_per_proc + ( rank < remainder ? 1 : 0 );
163 #endif
164 
165  std::string write_options = "";
166  if( nprocs > 1 ) write_options = "PARALLEL=WRITE_PART";
167 
168  // 2. Create a N^d structured mesh, which includes (N+1)^d vertices and N^d elements.
169  ScdBox* box = nullptr;
170 
171  // Calculate box bounds based on dimension
172  const moab::HomCoord low( ilow, ( dimension > 1 ) ? 0 : -1, ( dimension > 2 ) ? 0 : -1 );
173 
174  const moab::HomCoord high( ihigh, ( dimension > 1 ) ? elements_per_side : -1,
175  ( dimension > 2 ) ? elements_per_side : -1 );
176 
177  // Create the structured mesh box
178  MB_CHK_SET_ERR( scd_interface->construct_box( low, high,
179  nullptr, // No coordinates array
180  0, // No coordinates
181  box, // Output parameter
182  nullptr, // Periodicity
183  nullptr, // Parallel data
184  true, // No coordinates
185  0 // Resolve dimensionality
186  ),
187  "Failed to construct structured box" );
188 
189  if( !box )
190  {
191  std::cerr << "Failed to construct structured box: null box returned" << std::endl;
192  return 1;
193  }
194 
195  // 3. Get the vertices and elements from moab and check their numbers against (N+1)^d and N^d
196  Range vertices, elements;
197 
198  // Get all vertices (dimension = 0) and elements (dimension = mesh dimension)
199  MB_CHK_SET_ERR( moab_instance->get_entities_by_dimension( 0, 0, vertices ), "Failed to get vertices" );
200  MB_CHK_SET_ERR( moab_instance->get_entities_by_dimension( 0, dimension, elements ), "Failed to get elements" );
201 
202 #ifdef MOAB_HAVE_MPI
203  std::size_t local_entities_size[2] = { vertices.size(), elements.size() }, global_entities_size[2] = { 0, 0 };
204  MPI_Allreduce( local_entities_size, global_entities_size, 2, MPI_UNSIGNED_LONG_LONG, MPI_SUM, MPI_COMM_WORLD );
205 #endif
206 
207  // Calculate expected number of vertices and elements
208  const std::size_t expected_vertices = static_cast< std::size_t >( std::pow( elements_per_side + 1, dimension ) );
209  const std::size_t expected_elements = static_cast< std::size_t >( std::pow( elements_per_side, dimension ) );
210 
211  // Only print from rank 0 in parallel
212  auto print_message = [rank]( const auto& message ) {
213  if( rank == 0 )
214  {
215  std::cout << message << std::endl;
216  }
217  };
218 
219  // Verify the number of created elements and vertices
220  if( expected_elements == global_entities_size[1] )
221  {
222  const auto element_type = moab_instance->type_from_handle( *elements.begin() );
223  std::ostringstream msg;
224  msg << "Created " << global_entities_size[1] << " " << moab::CN::EntityTypeName( element_type )
225  << " elements and " << global_entities_size[0] << " vertices.";
226  print_message( msg.str() );
227  }
228  else
229  {
230  std::ostringstream err_msg;
231  err_msg << "Error: Expected " << expected_elements << " elements and " << expected_vertices
232  << " vertices, but got " << global_entities_size[1] << " elements and " << global_entities_size[0]
233  << " vertices.";
234  print_message( err_msg.str() );
235  return 1;
236  }
237 
238  // 4. Loop over elements in nested loops over i, j, k based on dimension
239  // const int i_max = elements_per_side - 1; // 0-based indexing
240  const int j_max = ( dimension > 1 ) ? elements_per_side - 1 : 0;
241  const int k_max = ( dimension > 2 ) ? elements_per_side - 1 : 0;
242 
243  // Pre-allocate vectors to avoid reallocation
244 
245  std::vector< double > coordinates;
246  for( int k = 0; k <= k_max; ++k )
247  {
248  for( int j = 0; j <= j_max; ++j )
249  {
250  for( int i = ilow; i < ihigh; ++i )
251  {
252  // 4a. Get the element corresponding to (i,j,k)
253  const EntityHandle element = box->get_element( i, j, k );
254  if( 0 == element )
255  {
256  std::cerr << "Failed to get element at (" << i << ", " << j << ", " << k << ")" << std::endl;
257  // return 1;
258  continue;
259  }
260 
261  // 4b. Get the connectivity of the element
262  std::vector< EntityHandle > connectivity;
263  MB_CHK_SET_ERR( moab_instance->get_connectivity( &element, 1, connectivity ),
264  "Failed to get connectivity for element at (" << i << ", " << j << ", " << k
265  << ") with handle " << element );
266 
267  // 4c. Get the coordinates of the vertices comprising that element
268  coordinates.resize( 3 * connectivity.size() );
269  MB_CHK_SET_ERR( moab_instance->get_coords( connectivity.data(), connectivity.size(),
270  coordinates.data() ),
271  "Failed to get coordinates for element at (" << i << ", " << j << ", " << k
272  << ") with handle " << element );
273  }
274  }
275  }
276 
277  // 5. Write the mesh file to disk
278  MB_CHK_SET_ERR( moab_instance->write_file( "structured_mesh.h5m", "h5m", write_options.c_str() ),
279  "Failed to write mesh file" );
280 
281  // 6. Clean up
282  MB_CHK_SET_ERR( moab_instance->release_interface( scd_interface ), "Failed to release interface" );
283 
284  // MPI_Finalize is handled by the mpi_guard destructor if MPI is enabled
285  return 0;
286 }

References ProgOptions::addOpt(), moab::Range::begin(), moab::ScdInterface::construct_box(), anonymous_namespace{StructuredMeshSimple.cpp}::DEFAULT_DIMENSION, anonymous_namespace{StructuredMeshSimple.cpp}::DEFAULT_ELEMENTS_PER_SIDE, moab::CN::EntityTypeName(), moab::ScdBox::get_element(), MB_CHK_SET_ERR, ProgOptions::parseCommandLine(), and moab::Range::size().