MOAB: Mesh Oriented datABase  (version 5.5.0)
hireconst_test_parallel.cpp
Go to the documentation of this file.
1 /*This unit test is for high order reconstruction capability, which could be used for mesh
2  * refinement*/
3 #include <iostream>
4 #include <string>
5 #include <sstream>
6 #if defined( __MINGW32__ )
7 #include <sys/time.h>
8 #else
9 #include <ctime>
10 #endif
11 
12 #include <vector>
13 #include <algorithm>
14 #include "moab/Core.hpp"
15 #include "moab/Range.hpp"
16 #include "moab/CartVect.hpp"
17 #include "moab/MeshTopoUtil.hpp"
18 #include "moab/NestedRefine.hpp"
20 #include "TestUtil.hpp"
21 #include <cmath>
22 
23 #ifdef MOAB_HAVE_MPI
24 #include "moab/ParallelComm.hpp"
25 #include "MBParallelConventions.h"
26 #include "ReadParallel.hpp"
27 #include "moab/FileOptions.hpp"
28 #include "MBTagConventions.hpp"
29 #include "moab_mpi.h"
30 #endif
31 
32 using namespace moab;
33 
34 #ifdef MOAB_HAVE_MPI
35 std::string read_options;
36 #endif
37 
38 #ifdef MOAB_HAVE_HDF5
39 #undef MOAB_HAVE_HDF5
40 #endif
41 ErrorCode load_meshset_hirec( const char* infile,
42  Interface* mbimpl,
43  EntityHandle& meshset,
44  ParallelComm*& pc,
45  const int degree = 0,
46  const int dim = 2 );
47 ErrorCode test_mesh( const char* infile, const int degree, const bool interp, const int dim );
48 
49 void compute_linear_coords( const int nvpe, double* elemcoords, double* naturals, double* linearcoords );
50 
51 void usage()
52 {
53  std::cout << "usage: mpirun -np <number of processors> ./hireconst_test_parallel <mesh file> "
54  "-degree <degree> -interp <0=least square, 1=interpolation> -dim <mesh dimension>"
55  << std::endl;
56 }
57 
58 int main( int argc, char* argv[] )
59 {
60 #ifdef MOAB_HAVE_MPI
61  MPI_Init( &argc, &argv );
62  int nprocs, rank;
63  MPI_Comm_size( MPI_COMM_WORLD, &nprocs );
64  MPI_Comm_rank( MPI_COMM_WORLD, &rank );
65 #endif
66  int degree = 3, dim = 2;
67  bool interp = false;
69 
70 #ifdef MOAB_HAVE_HDF5
71  std::string infile = TestDir + "unittest/mbcslam/fine4.h5m";
72 #else
73  std::string infile = TestDir + "unittest/sphere_quads_20.vtk";
74 #endif
75 
76  if( argc == 1 )
77  {
78  usage();
79  std::cout << "Using default arguments: ./hireconst_test_parallel " << infile << " -degree 3 -interp 0 -dim 2"
80  << std::endl;
81  }
82  else
83  {
84  infile = argv[1];
85  bool hasdim = false;
86 
87  for( int i = 2; i < argc; ++i )
88  {
89  if( i + 1 != argc )
90  {
91  if( std::string( argv[i] ) == "-degree" )
92  {
93  degree = atoi( argv[++i] );
94  }
95  else if( std::string( argv[i] ) == "-interp" )
96  {
97  interp = atoi( argv[++i] );
98  }
99  else if( std::string( argv[i] ) == "-dim" )
100  {
101  dim = atoi( argv[++i] );
102  hasdim = true;
103  }
104  else
105  {
106 #ifdef MOAB_HAVE_MPI
107 
108  if( 0 == rank )
109  {
110  usage();
111  }
112 
113  MPI_Finalize();
114 #else
115  usage();
116 #endif
117  return 0;
118  }
119  }
120  }
121 
122  if( !hasdim )
123  {
124 #ifdef MOAB_HAVE_MPI
125 
126  if( 0 == rank )
127  {
128  std::cout << "Dimension of input mesh should be provided, positive and less than 3" << std::endl;
129  }
130 
131 #else
132  std::cout << "Dimension of input mesh should be provided, positive and less than 3" << std::endl;
133 #endif
134  return 0;
135  }
136 
137  if( degree <= 0 || dim > 2 || dim <= 0 )
138  {
139 #ifdef MOAB_HAVE_MPI
140 
141  if( 0 == rank )
142  {
143  std::cout << "Input degree should be positive number;\n";
144  std::cout << "Input dimesion should be positive and less than 3;" << std::endl;
145  }
146 
147 #else
148  std::cout << "Input degree should be positive number;\n";
149  std::cout << "Input dimesion should be positive and less than 3;" << std::endl;
150 #endif
151  return 0;
152  }
153 
154 #ifdef MOAB_HAVE_MPI
155 
156  if( 0 == rank )
157  {
158  std::cout << "Testing on " << infile << " with dimension " << dim << "\n";
159  std::string opts = interp ? "interpolation" : "least square fitting";
160  std::cout << "High order reconstruction with degree " << degree << " " << opts << std::endl;
161  }
162 
163 #else
164  std::cout << "Testing on " << infile << " with dimension " << dim << "\n";
165  std::string opts = interp ? "interpolation" : "least square fitting";
166  std::cout << "High order reconstruction with degree " << degree << " " << opts << std::endl;
167 #endif
168  }
169 
170  error = test_mesh( infile.c_str(), degree, interp, dim );MB_CHK_ERR( error );
171 
172 #ifdef MOAB_HAVE_MPI
173  MPI_Finalize();
174 #endif
175 }
176 
177 ErrorCode load_meshset_hirec( const char* infile,
178  Interface* mbimpl,
179  EntityHandle& meshset,
180  ParallelComm*& pc,
181  const int degree,
182  const int dim )
183 {
185  error = mbimpl->create_meshset( moab::MESHSET_SET, meshset );MB_CHK_ERR( error );
186 #ifdef MOAB_HAVE_MPI
187  int nprocs, rank;
188  MPI_Comm comm = MPI_COMM_WORLD;
189  MPI_Comm_size( comm, &nprocs );
190  MPI_Comm_rank( comm, &rank );
191  EntityHandle partnset;
192  error = mbimpl->create_meshset( moab::MESHSET_SET, partnset );MB_CHK_ERR( error );
193 
194  if( nprocs > 1 )
195  {
196  pc = moab::ParallelComm::get_pcomm( mbimpl, partnset, &comm );
197  }
198 
199  if( nprocs > 1 )
200  {
201  int nghlayers = degree > 0 ? HiReconstruction::estimate_num_ghost_layers( degree, true ) : 0;
202  std::string part_method = "PARALLEL=READ_PART;PARTITION=PARALLEL_PARTITION;";
203 #ifndef MOAB_HAVE_HDF5
204  part_method = "PARALLEL=BCAST_DELETE;PARTITION=TRIVIAL;";
205 #endif
206 
207  if( nghlayers )
208  {
209  // get ghost layers
210  if( dim == 2 )
211  {
212  read_options = part_method + ";PARALLEL_RESOLVE_SHARED_ENTS;PARALLEL_GHOSTS=2.0.";
213  }
214  else if( dim == 1 )
215  {
216  read_options = part_method + ";PARALLEL_RESOLVE_SHARED_ENTS;PARALLEL_GHOSTS=1.0.";
217  }
218  else
219  {
220  MB_SET_ERR( MB_FAILURE, "unsupported dimension" );
221  }
222 
223  read_options += (char)( '0' + nghlayers );
224  }
225  else
226  {
227  read_options = part_method + ";PARALLEL_RESOLVE_SHARED_ENTS;";
228  }
229 
230  error = mbimpl->load_file( infile, &meshset, read_options.c_str() );MB_CHK_ERR( error );
231  }
232  else
233  {
234  error = mbimpl->load_file( infile, &meshset );MB_CHK_ERR( error );
235  }
236 
237 #else
238  assert( !pc && degree && dim );
239  error = mbimpl->load_file( infile, &meshset );MB_CHK_ERR( error );
240 #endif
241  return error;
242 }
243 
244 ErrorCode test_mesh( const char* infile, const int degree, const bool interp, const int dim )
245 {
246  Core moab;
247  Interface* mbimpl = &moab;
248  ParallelComm* pc = NULL;
249  EntityHandle meshset;
250 #ifdef MOAB_HAVE_MPI
251  int nprocs, rank;
252  MPI_Comm comm = MPI_COMM_WORLD;
253  MPI_Comm_size( comm, &nprocs );
254  MPI_Comm_rank( comm, &rank );
255 #endif
256 
258  // mesh will be loaded and communicator pc will be updated
259  error = load_meshset_hirec( infile, mbimpl, meshset, pc, degree, dim );MB_CHK_ERR( error );
260  // initialize
261  HiReconstruction hirec( dynamic_cast< Core* >( mbimpl ), pc, meshset );
262  Range elems, elems_owned;
263  error = mbimpl->get_entities_by_dimension( meshset, dim, elems );MB_CHK_ERR( error );
264  int nelems = elems.size();
265 
266 #ifdef MOAB_HAVE_MPI
267 
268  if( pc )
269  {
270  error = pc->filter_pstatus( elems, PSTATUS_GHOST, PSTATUS_NOT, -1, &elems_owned );MB_CHK_ERR( error );
271  }
272  else
273  {
274  elems_owned = elems;
275  }
276 
277 #endif
278 
279 #ifdef MOAB_HAVE_MPI
280  std::cout << "Mesh has " << nelems << " elements on Processor " << rank << " in total;";
281  std::cout << elems_owned.size() << " of which are locally owned elements" << std::endl;
282 #else
283  std::cout << "Mesh has " << nelems << " elements" << std::endl;
284 #endif
285 
286  // reconstruction
287  if( dim == 2 )
288  {
289  error = hirec.reconstruct3D_surf_geom( degree, interp, false );MB_CHK_ERR( error );
290  }
291  else if( dim == 1 )
292  {
293  error = hirec.reconstruct3D_curve_geom( degree, interp, false );MB_CHK_ERR( error );
294  }
295 
296 #ifdef MOAB_HAVE_MPI
297  std::cout << "HiRec has been done on Processor " << rank << std::endl;
298 #else
299  std::cout << "HiRec has been done " << std::endl;
300 #endif
301  // fitting
302  double mxdist = 0;
303 
304  for( Range::iterator ielem = elems_owned.begin(); ielem != elems_owned.end(); ++ielem )
305  {
306  int nvpe;
307  const EntityHandle* conn;
308  error = mbimpl->get_connectivity( *ielem, conn, nvpe );MB_CHK_ERR( error );
309  double w = 1.0 / (double)nvpe;
310  std::vector< double > naturalcoords2fit( nvpe, w );
311  CartVect newcoords, linearcoords;
312  error = hirec.hiproj_walf_in_element( *ielem, nvpe, 1, &( naturalcoords2fit[0] ), newcoords.array() );
313 
314  if( MB_FAILURE == error )
315  {
316  continue;
317  }
318 
319  std::vector< double > coords( 3 * nvpe );
320  error = mbimpl->get_coords( conn, nvpe, &( coords[0] ) );MB_CHK_ERR( error );
321  compute_linear_coords( nvpe, &( coords[0] ), &( naturalcoords2fit[0] ), linearcoords.array() );
322  CartVect nlcoords = newcoords - linearcoords;
323  mxdist = std::max( mxdist, nlcoords.length() );
324  /*#ifdef MOAB_HAVE_MPI
325  std::cout << "Error on element " << *ielem << " is " << nlcoords.length() << "on
326  Processor " << rank << std::endl; #else std::cout << "Error on element " << *ielem << " is "
327  << nlcoords.length() << std::endl; #endif*/
328  }
329 
330 #ifdef MOAB_HAVE_MPI
331  std::cout << "Maximum projection lift is " << mxdist << " on Processor " << rank << std::endl;
332 #else
333  std::cout << "Maximum projection lift is " << mxdist << std::endl;
334 #endif
335  return error;
336 }
337 
338 void compute_linear_coords( const int nvpe, double* elemcoords, double* naturals, double* linearcoords )
339 {
340  assert( elemcoords && linearcoords );
341 
342  for( int i = 0; i < 3; ++i )
343  {
344  linearcoords[i] = 0;
345 
346  for( int j = 0; j < nvpe; ++j )
347  {
348  linearcoords[i] += naturals[j] * elemcoords[3 * j + i];
349  }
350  }
351 }