Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
CoupleMGen.cpp
Go to the documentation of this file.
1 /*
2  * Driver to test coupling online, without using IO hdf5 files
3  * Will instantiate 2 different meshes, that cover the same domain; reports in the end the L
4  * infinity norm of a field
5  *
6  * will report time to build the meshes, instantiate coupler, locate points and interpolate
7  * M and K are options for number of parts in x and z directions
8  *
9  * partitions are ordered lexicographically, (MxNxK)
10  *
11  * it needs to be np = MxNxK
12  *
13  * if M==K, then the partitions are perfectly aligned
14  *
15  * the second mesh is ordered (KxNxM), so if you want them to not be perfectly aligned, make M and
16  * K different
17  *
18  * for example, run with
19  * M = 16, N=K=1, will verify slabs
20  *
21  * -b controls the number of elements in each partition
22  *
23  * example
24  *
25  * mpiexec -np 16 CoupleMGen -K 4 -N 4
26  *
27  * Right now, to build, it needs to install MOAB; coupler is harder if not installed (would need to
28  * add
29  * ../tools/mbcoupler , etc, to include and lib paths)
30  *
31  *
32  */
33 // MOAB includes
34 #include "moab/ParallelComm.hpp"
35 #include "MBParallelConventions.h"
36 #include "moab/Core.hpp"
37 #include "mbcoupler/Coupler.hpp"
38 #include "moab_mpi.h"
39 #include "mbcoupler/ElemUtil.hpp"
40 #include "moab/MeshGeneration.hpp"
41 #include "moab/ProgOptions.hpp"
42 
43 using namespace moab;
44 using std::string;
45 
46 double physField( double x, double y, double z )
47 {
48 
49  double out = sin( M_PI * x ) * cos( M_PI * y ) * sin( M_PI * z );
50 
51  return out;
52 }
53 
54 int main( int argc, char* argv[] )
55 {
56  int proc_id = 0, size = 1;
57 
58  MPI_Init( &argc, &argv );
59  MPI_Comm_rank( MPI_COMM_WORLD, &proc_id );
60  MPI_Comm_size( MPI_COMM_WORLD, &size );
61 
62  Core mcore;
63  Interface* mb = &mcore;
64  EntityHandle fileset1, fileset2; // for 2 different meshes
66  // default options
67  opts.A = opts.B = opts.C = 1;
68  opts.M = opts.N = opts.K = 1;
69  opts.blockSize = 4;
70  opts.xsize = opts.ysize = opts.zsize = 1.;
71  opts.ui = CartVect( 1., 0, 0. );
72  opts.uj = CartVect( 0., 1., 0. );
73  opts.uk = CartVect( 0., 0., 1. );
74  opts.newMergeMethod = opts.quadratic = opts.keep_skins = opts.tetra = false;
75  opts.adjEnts = opts.parmerge = false;
76  opts.GL = 0;
77 
78  ProgOptions popts;
79 
80  popts.addOpt< int >( string( "blockSize,b" ), string( "Block size of mesh (default=4)" ), &opts.blockSize );
81  popts.addOpt< int >( string( "xproc,M" ), string( "Number of processors in x dir (default=1)" ), &opts.M );
82  popts.addOpt< int >( string( "yproc,N" ), string( "Number of processors in y dir (default=1)" ), &opts.N );
83  popts.addOpt< int >( string( "zproc,K" ), string( "Number of processors in z dir (default=1)" ), &opts.K );
84 
85  popts.addOpt< int >( string( "xblocks,A" ), string( "Number of blocks on a task in x dir (default=2)" ), &opts.A );
86  popts.addOpt< int >( string( "yblocks,B" ), string( "Number of blocks on a task in y dir (default=2)" ), &opts.B );
87  popts.addOpt< int >( string( "zblocks,C" ), string( "Number of blocks on a task in x dir (default=2)" ), &opts.C );
88 
89  popts.addOpt< double >( string( "xsize,x" ), string( "Total size in x direction (default=1.)" ), &opts.xsize );
90  popts.addOpt< double >( string( "ysize,y" ), string( "Total size in y direction (default=1.)" ), &opts.ysize );
91  popts.addOpt< double >( string( "zsize,z" ), string( "Total size in z direction (default=1.)" ), &opts.zsize );
92 
93  popts.addOpt< void >( "newMerge,w", "use new merging method", &opts.newMergeMethod );
94 
95  popts.addOpt< void >( "quadratic,q", "use hex 27 elements", &opts.quadratic );
96 
97  popts.addOpt< void >( "keep_skins,k", "keep skins with shared entities", &opts.keep_skins );
98 
99  popts.addOpt< void >( "tetrahedrons,t", "generate tetrahedrons", &opts.tetra );
100 
101  popts.addOpt< void >( "faces_edges,f", "create all faces and edges", &opts.adjEnts );
102 
103  popts.addOpt< int >( string( "ghost_layers,g" ), string( "Number of ghost layers (default=0)" ), &opts.GL );
104 
105  popts.addOpt< void >( "parallel_merge,p", "use parallel mesh merge, not vertex ID based merge", &opts.parmerge );
106 
108 
109  double toler = 1.e-6;
110  popts.addOpt< double >( string( "eps,e" ), string( "tolerance for coupling, used in locating points" ), &toler );
111 
112  bool writeMeshes = false;
113  popts.addOpt< void >( "print,p", "write meshes", &writeMeshes );
114 
115  popts.parseCommandLine( argc, argv );
116 
117  double start_time = MPI_Wtime();
118 
119  ErrorCode rval = mb->create_meshset( MESHSET_SET, fileset1 );MB_CHK_ERR( rval );
120  rval = mb->create_meshset( MESHSET_SET, fileset2 );MB_CHK_ERR( rval );
121 
122  ParallelComm* pc1 = new ParallelComm( mb, MPI_COMM_WORLD );
123  MeshGeneration* mgen1 = new MeshGeneration( mb, pc1, fileset1 );
124 
125  rval = mgen1->BrickInstance( opts );MB_CHK_ERR( rval ); // this will generate first mesh on fileset1
126 
127  double instance_time = MPI_Wtime();
128  double current = instance_time;
129  if( !proc_id ) std::cout << " instantiate first mesh " << instance_time - start_time << "\n";
130  // set an interpolation tag on source mesh, from phys field
131  std::string interpTag( "interp_tag" );
132  Tag tag;
133  rval = mb->tag_get_handle( interpTag.c_str(), 1, MB_TYPE_DOUBLE, tag, MB_TAG_CREAT | MB_TAG_DENSE );MB_CHK_ERR( rval );
134 
135  Range src_elems;
136  rval = pc1->get_part_entities( src_elems, 3 );MB_CHK_ERR( rval );
137  Range src_verts;
138  rval = mb->get_connectivity( src_elems, src_verts );MB_CHK_ERR( rval );
139  for( Range::iterator vit = src_verts.begin(); vit != src_verts.end(); ++vit )
140  {
141  EntityHandle vert = *vit; //?
142 
143  double vertPos[3];
144  mb->get_coords( &vert, 1, vertPos );
145 
146  double fieldValue = physField( vertPos[0], vertPos[1], vertPos[2] );
147 
148  rval = mb->tag_set_data( tag, &vert, 1, &fieldValue );MB_CHK_ERR( rval );
149  }
150 
151  double setTag_time = MPI_Wtime();
152  if( !proc_id ) std::cout << " set tag " << setTag_time - current;
153  current = instance_time;
154  // change some options, so it is a different mesh
155  int tmp1 = opts.K;
156  opts.K = opts.M;
157  opts.M = tmp1; // swap (opts.K, opts.M)
158  opts.tetra = !opts.tetra;
159  opts.blockSize++;
160 
161  ParallelComm* pc2 = new ParallelComm( mb, MPI_COMM_WORLD );
162  MeshGeneration* mgen2 = new MeshGeneration( mb, pc2, fileset2 );
163 
164  rval = mgen2->BrickInstance( opts );MB_CHK_ERR( rval ); // this will generate second mesh on fileset2
165 
166  double instance_second = MPI_Wtime();
167  if( !proc_id ) std::cout << " instance second mesh" << instance_second - current << "\n";
168  current = instance_second;
169 
170  // test the sets are fine
171  if( writeMeshes )
172  {
173  rval = mb->write_file( "mesh1.h5m", 0, ";;PARALLEL=WRITE_PART;CPUTIME;PARALLEL_COMM=0;", &fileset1, 1 );MB_CHK_SET_ERR( rval, "Can't write in parallel mesh 1" );
174  rval = mb->write_file( "mesh2.h5m", 0, ";;PARALLEL=WRITE_PART;CPUTIME;PARALLEL_COMM=1;", &fileset2, 1 );MB_CHK_SET_ERR( rval, "Can't write in parallel mesh 1" );
175  double write_files = MPI_Wtime();
176  if( !proc_id ) std::cout << " write files " << write_files - current << "\n";
177  current = write_files;
178  }
179 
180  // Instantiate a coupler, which also initializes the tree
181  Coupler mbc( mb, pc1, src_elems, 0 );
182 
183  double instancecoupler = MPI_Wtime();
184  if( !proc_id ) std::cout << " instance coupler " << instancecoupler - current << "\n";
185  current = instancecoupler;
186 
187  // Get points from the target mesh to interpolate
188  // We have to treat differently the case when the target is a spectral mesh
189  // In that case, the points of interest are the GL points, not the vertex nodes
190  std::vector< double > vpos; // This will have the positions we are interested in
191  int numPointsOfInterest = 0;
192 
193  Range targ_elems;
194  Range targ_verts;
195 
196  // First get all vertices adj to partition entities in target mesh
197  rval = pc2->get_part_entities( targ_elems, 3 );MB_CHK_ERR( rval );
198 
199  rval = mb->get_adjacencies( targ_elems, 0, false, targ_verts, Interface::UNION );MB_CHK_ERR( rval );
200  Range tmp_verts;
201  // Then get non-owned verts and subtract
202  rval = pc2->get_pstatus_entities( 0, PSTATUS_NOT_OWNED, tmp_verts );MB_CHK_ERR( rval );
203  targ_verts = subtract( targ_verts, tmp_verts );
204  // get position of these entities; these are the target points
205  numPointsOfInterest = (int)targ_verts.size();
206  vpos.resize( 3 * targ_verts.size() );
207  rval = mb->get_coords( targ_verts, &vpos[0] );MB_CHK_ERR( rval );
208  // Locate those points in the source mesh
209  // std::cout<<"rank "<< proc_id<< " points of interest: " << numPointsOfInterest << "\n";
210  rval = mbc.locate_points( &vpos[0], numPointsOfInterest, 0, toler );MB_CHK_ERR( rval );
211 
212  double locatetime = MPI_Wtime();
213  if( !proc_id ) std::cout << " locate points: " << locatetime - current << "\n";
214  current = locatetime;
215 
216  // Now interpolate tag onto target points
217  std::vector< double > field( numPointsOfInterest );
218 
219  rval = mbc.interpolate( method, interpTag, &field[0] );MB_CHK_ERR( rval );
220 
221  // compare with the actual phys field
222  double err_max = 0;
223  for( int i = 0; i < numPointsOfInterest; i++ )
224  {
225  double trval = physField( vpos[3 * i], vpos[3 * i + 1], vpos[3 * i + 2] );
226  double err2 = fabs( trval - field[i] );
227  if( err2 > err_max ) err_max = err2;
228  }
229 
230  double interpolateTime = MPI_Wtime();
231  if( !proc_id ) std::cout << " interpolate points: " << interpolateTime - current << "\n";
232  current = interpolateTime;
233 
234  double gerr;
235  MPI_Allreduce( &err_max, &gerr, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD );
236  if( 0 == proc_id ) std::cout << "max err " << gerr << "\n";
237 
238  delete mgen1;
239  delete mgen2;
240 
241  MPI_Finalize();
242 
243  return 0;
244 }