MOAB: Mesh Oriented datABase
(version 5.4.1)
|
#include "moab/Core.hpp"
#include "moab/ParallelComm.hpp"
#include "MBTagConventions.hpp"
#include "moab_mpi.h"
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <cstring>
#include <cmath>
#include <cassert>
#include <cstdio>
#include <sstream>
Go to the source code of this file.
Defines | |
#define | TPRINT(A) tprint( ( A ) ) |
#define | IDX(i, j, k) ( ( num_interval + 1 ) * ( ( num_interval + 1 ) * ( k ) + ( j ) ) + ( i ) ) |
Functions | |
static void | tprint (const char *A) |
ErrorCode | generate_mesh (Interface &moab, int intervals) |
void | help () |
int | main (int argc, char *argv[]) |
Variables | |
const int | DEFAULT_INTERVALS = 2 |
const char * | DEFAULT_FILE_NAME = "parallel_write_test.h5m" |
const char | args [] = "[-i <intervals>] [-o <filename>] [-L <filename>] [-g <n>]" |
#define IDX | ( | i, | |
j, | |||
k | |||
) | ( ( num_interval + 1 ) * ( ( num_interval + 1 ) * ( k ) + ( j ) ) + ( i ) ) |
Definition at line 280 of file parallel_write_test.cpp.
Referenced by generate_mesh().
Definition at line 16 of file parallel_write_test.cpp.
Referenced by main().
ErrorCode generate_mesh | ( | Interface & | moab, |
int | intervals | ||
) |
Definition at line 282 of file parallel_write_test.cpp.
References moab::Interface::create_element(), moab::Interface::create_vertex(), ErrorCode, moab::Interface::globalId_tag(), IDX, MB_SUCCESS, MBHEX, MPI_COMM_WORLD, rank, size, and moab::Interface::tag_set_data().
Referenced by main().
{ int rank, size; MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); ErrorCode rval; Tag global_id = moab.globalId_tag(); // Each processor will own one cube of mesh within // an 3D grid of cubes. Calculate the dimensions of // that grid in numbers of cubes. int root = 1; while( root * root * root < size ) ++root; int num_x_blocks = root; int num_y_blocks = root - 1; int num_z_blocks = root - 1; if( num_x_blocks * num_y_blocks * num_z_blocks < size ) ++num_y_blocks; if( num_x_blocks * num_y_blocks * num_z_blocks < size ) ++num_z_blocks; // calculate position of this processor in grid int my_z_block = rank / ( num_x_blocks * num_y_blocks ); int rem = rank % ( num_x_blocks * num_y_blocks ); int my_y_block = rem / num_x_blocks; int my_x_block = rem % num_x_blocks; // Each processor's cube of mesh will be num_iterval^3 elements // and will be 1.0 units on a side // create vertices const int num_x_vtx = num_interval * num_x_blocks + 1; const int num_y_vtx = num_interval * num_y_blocks + 1; const int x_offset = my_x_block * num_interval; const int y_offset = my_y_block * num_interval; const int z_offset = my_z_block * num_interval; double step = 1.0 / num_interval; std::vector< EntityHandle > vertices( ( num_interval + 1 ) * ( num_interval + 1 ) * ( num_interval + 1 ) ); std::vector< EntityHandle >::iterator v = vertices.begin(); for( int k = 0; k <= num_interval; ++k ) { for( int j = 0; j <= num_interval; ++j ) { for( int i = 0; i <= num_interval; ++i ) { double coords[] = { my_x_block + i * step, my_y_block + j * step, my_z_block + k * step }; EntityHandle h; rval = moab.create_vertex( coords, h ); if( MB_SUCCESS != rval ) return rval; int id = 1 + x_offset + i + ( y_offset + j ) * num_x_vtx + ( z_offset + k ) * num_x_vtx * num_y_vtx; rval = moab.tag_set_data( global_id, &h, 1, &id ); if( MB_SUCCESS != rval ) return rval; assert( v != vertices.end() ); *v++ = h; } } } // create hexes for( int k = 0; k < num_interval; ++k ) { for( int j = 0; j < num_interval; ++j ) { for( int i = 0; i < num_interval; ++i ) { assert( IDX( i + 1, j + 1, k + 1 ) < (int)vertices.size() ); const EntityHandle conn[] = { vertices[IDX( i, j, k )], vertices[IDX( i + 1, j, k )], vertices[IDX( i + 1, j + 1, k )], vertices[IDX( i, j + 1, k )], vertices[IDX( i, j, k + 1 )], vertices[IDX( i + 1, j, k + 1 )], vertices[IDX( i + 1, j + 1, k + 1 )], vertices[IDX( i, j + 1, k + 1 )] }; EntityHandle elem; rval = moab.create_element( MBHEX, conn, 8, elem ); if( MB_SUCCESS != rval ) return rval; } } } /* // create interface quads for (int j = 0; j < num_interval; ++j) { for (int i = 0; i < num_interval; ++i) { EntityHandle h; const EntityHandle conn1[] = { vertices[IDX(i, j, 0)], vertices[IDX(i+1,j, 0)], vertices[IDX(i+1,j+1,0)], vertices[IDX(i, j+1,0)] }; rval = moab.create_element( MBQUAD, conn1, 4, h ); if (MB_SUCCESS != rval) return rval; const EntityHandle conn2[] = { vertices[IDX(i, j, num_interval)], vertices[IDX(i+1,j, num_interval)], vertices[IDX(i+1,j+1,num_interval)], vertices[IDX(i, j+1,num_interval)] }; rval = moab.create_element( MBQUAD, conn2, 4, h ); if (MB_SUCCESS != rval) return rval; } } for (int k = 0; k < num_interval; ++k) { for (int i = 0; i < num_interval; ++i) { EntityHandle h; const EntityHandle conn1[] = { vertices[IDX(i, 0,k )], vertices[IDX(i+1,0,k )], vertices[IDX(i+1,0,k+1)], vertices[IDX(i, 0,k+1)] }; rval = moab.create_element( MBQUAD, conn1, 4, h ); if (MB_SUCCESS != rval) return rval; const EntityHandle conn2[] = { vertices[IDX(i, num_interval,k )], vertices[IDX(i+1,num_interval,k )], vertices[IDX(i+1,num_interval,k+1)], vertices[IDX(i, num_interval,k+1)] }; rval = moab.create_element( MBQUAD, conn2, 4, h ); if (MB_SUCCESS != rval) return rval; } } for (int k = 0; k < num_interval; ++k) { for (int j = 0; j < num_interval; ++j) { EntityHandle h; const EntityHandle conn1[] = { vertices[IDX(0,j, k )], vertices[IDX(0,j+1,k )], vertices[IDX(0,j+1,k+1)], vertices[IDX(0,j, k+1)] }; rval = moab.create_element( MBQUAD, conn1, 4, h ); if (MB_SUCCESS != rval) return rval; const EntityHandle conn2[] = { vertices[IDX(num_interval,j, k )], vertices[IDX(num_interval,j+1,k )], vertices[IDX(num_interval,j+1,k+1)], vertices[IDX(num_interval,j, k+1)] }; rval = moab.create_element( MBQUAD, conn2, 4, h ); if (MB_SUCCESS != rval) return rval; } } */ return MB_SUCCESS; }
void help | ( | ) |
Definition at line 41 of file parallel_write_test.cpp.
References args, and DEFAULT_INTERVALS.
{ std::cout << "parallel_write_test " << args << std::endl << " -i <N> Each processor owns an NxNxN cube of hex elements (default: " << DEFAULT_INTERVALS << ")" << std::endl << " -o <name> Retain output file and name it as specified." << std::endl << " -L <name> Write local mesh to file name prefixed with MPI rank" << std::endl << " -g <n> Specify writer debug output level" << std::endl << " -R Skip resolve of shared entities (interface ents will be duplicated in file)" << std::endl << std::endl << "This program creates a (non-strict) subset of a regular hex mesh " "such that the mesh is already partitioned, and then attempts to " "write that mesh using MOAB's parallel HDF5 writer. The mesh size " "will scale with the number of processors and the number of elements " "per processor (the latter is a function of the value specified " "with the '-i' flag.)" << std::endl << std::endl << "Let N = ceil(cbrt(P)), where P is the number of processes. " "The mesh will be some subset of a cube with one corner at the " "origin and the other at (N,N,N). Each processor will own a " "non-overlapping 1x1x1 unit block of mesh within that cube. " "If P is a power of 3, then the entire NxNxN cube will be " "filled with hex elements. Otherwise, some connected subset " "of the cube will be meshed. Each processor is assigned a " "sub-block of the cube by rank where the blocks are enumerated " "sequentally with x increasing most rapidly and z least rapidly." << std::endl << std::endl << "The size of the mesh owned by each processor is controlled by " "the number of intervals along each edge of its block of mesh. " "If each block has N intervals, than each processor will have " "N^3 hex elements." << std::endl << std::endl; }
int main | ( | int | argc, |
char * | argv[] | ||
) |
Definition at line 78 of file parallel_write_test.cpp.
References args, buffer, DEFAULT_FILE_NAME, DEFAULT_INTERVALS, ErrorCode, generate_mesh(), moab::Interface::get_entities_by_type(), moab::Interface::get_error_string(), moab::Interface::get_last_error(), help(), ierr, mb, MB_SUCCESS, MBHEX, MPI_COMM_WORLD, rank, moab::ParallelComm::resolve_shared_ents(), size, moab::Range::size(), t, TPRINT, and moab::Interface::write_file().
{ int ierr = MPI_Init( &argc, &argv ); if( ierr ) { std::cerr << "MPI_Init failed with error code: " << ierr << std::endl; return ierr; } int rank; ierr = MPI_Comm_rank( MPI_COMM_WORLD, &rank ); if( ierr ) { std::cerr << "MPI_Comm_rank failed with error code: " << ierr << std::endl; return ierr; } int size; ierr = MPI_Comm_size( MPI_COMM_WORLD, &size ); if( ierr ) { std::cerr << "MPI_Comm_size failed with error code: " << ierr << std::endl; return ierr; } // settings controlled by CL flags const char* output_file_name = 0; const char* indiv_file_name = 0; int intervals = 0, debug_level = 0; // state for CL flag processing bool expect_intervals = false; bool expect_file_name = false; bool expect_indiv_file = false; bool skip_resolve_shared = false; bool expect_debug_level = false; // process CL args for( int i = 1; i < argc; ++i ) { if( expect_intervals ) { char* endptr = 0; intervals = (int)strtol( argv[i], &endptr, 0 ); if( *endptr || intervals < 1 ) { std::cerr << "Invalid block interval value: " << argv[i] << std::endl; return 1; } expect_intervals = false; } else if( expect_indiv_file ) { indiv_file_name = argv[i]; expect_indiv_file = false; } else if( expect_file_name ) { output_file_name = argv[i]; expect_file_name = false; } else if( expect_debug_level ) { debug_level = atoi( argv[i] ); if( debug_level < 1 ) { std::cerr << "Invalid argument following -g flag: \"" << argv[i] << '"' << std::endl; return 1; } expect_debug_level = false; } else if( !strcmp( "-i", argv[i] ) ) expect_intervals = true; else if( !strcmp( "-o", argv[i] ) ) expect_file_name = true; else if( !strcmp( "-L", argv[i] ) ) expect_indiv_file = true; else if( !strcmp( "-R", argv[i] ) ) skip_resolve_shared = true; else if( !strcmp( "-g", argv[i] ) ) expect_debug_level = true; else if( !strcmp( "-h", argv[i] ) ) { help(); return 0; } else { std::cerr << "Unexpected argument: " << argv[i] << std::endl << "Usage: " << argv[0] << " " << args << std::endl << " " << argv[0] << " -h" << std::endl << " Try '-h' for help." << std::endl; return 1; } } // Check for missing argument after last CL flag if( expect_file_name || expect_intervals || expect_indiv_file ) { std::cerr << "Missing argument for '" << argv[argc - 1] << "'" << std::endl; return 1; } // If intervals weren't specified, use default if( intervals == 0 ) { std::cout << "Using default interval count: " << DEFAULT_INTERVALS << std::endl; intervals = DEFAULT_INTERVALS; } // If no output file was specified, use default one and note that // we need to delete it when the test completes. bool keep_output_file = true; if( !output_file_name ) { output_file_name = DEFAULT_FILE_NAME; keep_output_file = false; } // Create mesh TPRINT( "Generating mesh" ); double gen_time = MPI_Wtime(); Core mb; Interface& moab = mb; ErrorCode rval = generate_mesh( moab, intervals ); if( MB_SUCCESS != rval ) { std::cerr << "Mesh creation failed with error code: " << rval << std::endl; return (int)rval; } gen_time = MPI_Wtime() - gen_time; // Write out local mesh on each processor if requested. if( indiv_file_name ) { TPRINT( "Writing individual file" ); char buffer[64]; int width = (int)ceil( log10( size ) ); sprintf( buffer, "%0*d-", width, rank ); std::string name( buffer ); name += indiv_file_name; rval = moab.write_file( name.c_str() ); if( MB_SUCCESS != rval ) { std::cerr << "Failed to write file: " << name << std::endl; return (int)rval; } } double res_time = MPI_Wtime(); Range hexes; moab.get_entities_by_type( 0, MBHEX, hexes ); if( !skip_resolve_shared ) { TPRINT( "Resolving shared entities" ); // Negotiate shared entities using vertex global IDs ParallelComm* pcomm = new ParallelComm( &moab, MPI_COMM_WORLD ); rval = pcomm->resolve_shared_ents( 0, hexes, 3, 0 ); if( MB_SUCCESS != rval ) { std::cerr << "ParallelComm::resolve_shared_ents failed" << std::endl; return rval; } } res_time = MPI_Wtime() - res_time; TPRINT( "Beginning parallel write" ); double write_time = MPI_Wtime(); // Do parallel write clock_t t = clock(); std::ostringstream opts; opts << "PARALLEL=WRITE_PART"; if( debug_level > 0 ) opts << ";DEBUG_IO=" << debug_level; rval = moab.write_file( output_file_name, "MOAB", opts.str().c_str() ); t = clock() - t; if( MB_SUCCESS != rval ) { std::string msg; moab.get_last_error( msg ); std::cerr << "File creation failed with error code: " << moab.get_error_string( rval ) << std::endl; std::cerr << "\t\"" << msg << '"' << std::endl; return (int)rval; } write_time = MPI_Wtime() - write_time; double times[3] = { gen_time, res_time, write_time }; double max[3] = { 0, 0, 0 }; MPI_Reduce( times, max, 3, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD ); // Clean up and summarize if( 0 == rank ) { double sec = (double)t / CLOCKS_PER_SEC; std::cout << "Wrote " << hexes.size() * size << " hexes in " << sec << " seconds." << std::endl; if( !keep_output_file ) { TPRINT( "Removing written file" ); remove( output_file_name ); } std::cout << "Wall time: generate: " << max[0] << ", resovle shared: " << max[1] << ", write_file: " << max[2] << std::endl; } TPRINT( "Finalizing MPI" ); return MPI_Finalize(); }
static void tprint | ( | const char * | A | ) | [static] |
Definition at line 17 of file parallel_write_test.cpp.
References buffer, MPI_COMM_WORLD, and rank.
Definition at line 40 of file parallel_write_test.cpp.
Referenced by help(), main(), mhdf_setFail(), ProgOptions::parseCommandLine(), and moab::Error::set_last_error().
const char* DEFAULT_FILE_NAME = "parallel_write_test.h5m" |
Definition at line 27 of file parallel_write_test.cpp.
Referenced by main().
const int DEFAULT_INTERVALS = 2 |
Definition at line 26 of file parallel_write_test.cpp.