Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
wrap_intx.cpp
Go to the documentation of this file.
1 /*
2  * wrap_intx.cpp
3  * Will implement the intersection method that will be callable from fortran too
4  * will be added to the sub-library IntxMesh
5  *
6  *
7  * Created on: Dec 14, 2013
8  * Author: iulian
9  */
10 #include "iMesh.h"
11 #include "iMeshP.h"
12 #include "MBiMesh.hpp"
13 #include "moab/Core.hpp"
14 #include "moab/Range.hpp"
15 #include "moab/Intx2MeshOnSphere.hpp"
16 #include "moab/ReadUtilIface.hpp"
17 #include "moab/ParallelComm.hpp"
18 #include "MBTagConventions.hpp"
20 #include "moab/IntxUtils.hpp"
21 
22 #include <sstream>
23 #include <mpi.h>
24 
25 using namespace moab;
26 static double radius = 1.;
27 static double gtol = 1.e-9;
28 static bool debug = false;
29 
30 // this mapping to coordinates will keep an index into the coords and dep_coords array
31 // more exactly, the fine vertices are in a Range fineVerts;
32 // then the vertex index i in fineVerts , fineVerts[i] will have 3 coordinates at
33 // index mapping_to_coords[i] * 3
34 // more exactly, x = coords[ mapping_to_coords[i] * 3 ]
35 // y = coords[ mapping_to_coords[i] * 3 + 1]
36 // z = coords[ mapping_to_coords[i] * 3 + 2]
37 
38 // in the same way, departure position for vertex depVerts[i] will be at index
39 // mapping_to_coords[i] * 2 in dep_coords array (it has just latitude and longitude)
40 //
41 static int* mapping_to_coords = NULL;
42 static int numVertices = 0;
43 // this will be instantiated at create mesh step
44 // should be cleaned up at the end
45 static Intx2MeshOnSphere* pworker = NULL;
46 
47 // should get rid of this; instead of using array[NC+1][NC+1], use row based indexing (C-style):
48 // parray = new int[ (NC+1)*(NC+1) ] , and instead of array[i][j], use parray[ i*(NC+1) + j ]
49 #define NC 3
50 
51 /*
52  * methods defined here:
53  * void update_tracer(iMesh_Instance instance,
54  iBase_EntitySetHandle imesh_euler_set, int * ierr);
55 
56  void create_mesh(iMesh_Instance instance,
57  iBase_EntitySetHandle * imesh_euler_set, double * coords, int * corners,
58  int nc, int nelem, MPI_Fint comm, int * ierr) ;
59 
60  void intersection_at_level(iMesh_Instance instance,
61  iBase_EntitySetHandle fine_set, iBase_EntitySetHandle * intx_set, double * dep_coords, double
62  radius, int nc, int nelem, MPI_Fint comm, int * ierr)
63 
64  */
65 #ifdef __cplusplus
66 extern "C" {
67 #endif
68 
69 void initialize_area_and_tracer( iMesh_Instance instance,
70  iBase_EntitySetHandle imesh_euler_set,
71  double* area_vals,
72  int* ierr )
73 {
74 
75  EntityHandle eul_set = (EntityHandle)imesh_euler_set;
76 
77  moab::Interface* mb = MOABI;
78  *ierr = 1;
79 
80  ErrorCode rval;
81 
82  Range eulQuads;
83  rval = mb->get_entities_by_type( eul_set, MBQUAD, eulQuads );
84  ERRORV( rval, "can't get eulerian quads" );
85 
86  // area of the euler element is fixed, store it; it is used to recompute the averages at each
87  // time step
88  Tag tagArea = 0;
89  std::string tag_name4( "Area" );
90  rval = mb->tag_get_handle( tag_name4.c_str(), 1, MB_TYPE_DOUBLE, tagArea, MB_TAG_DENSE | MB_TAG_CREAT );
91  ERRORV( rval, "can't get area tag" );
92 
93  std::cout << " num quads = " << eulQuads.size() << "\n";
94  ERRORV( rval, "can't set area for each quad" );
95 
96  rval = mb->tag_set_data( tagArea, eulQuads, &area_vals[0] );
97 
98  *ierr = 0;
99  return;
100 }
101 
102 void update_tracer_test( iMesh_Instance instance,
103  iBase_EntitySetHandle imesh_euler_set,
104  iBase_EntitySetHandle imesh_output_set,
105  int numTracers,
106  double* tracer_vals,
107  int* ierr )
108 {
109 
110  EntityHandle eul_set = (EntityHandle)imesh_euler_set;
111  EntityHandle output_set = (EntityHandle)imesh_output_set;
112 
113  moab::Interface* mb = MOABI;
114  *ierr = 1;
115 
116  ErrorCode rval;
117 
118  Range eulQuads;
119  rval = mb->get_entities_by_type( eul_set, MBQUAD, eulQuads );
120  ERRORV( rval, "can't get eulerian quads" );
121 
122  // tagElem is the average computed at each element, from nodal values
123  Tag tagElem = 0;
124  std::string tag_name2( "TracerAverage" );
125  rval = mb->tag_get_handle( tag_name2.c_str(), numTracers, MB_TYPE_DOUBLE, tagElem, MB_TAG_DENSE | MB_TAG_CREAT );
126  ERRORV( rval, "can't get tracer tag " );
127 
128  // area of the euler element is fixed, store it; it is used to recompute the averages at each
129  // time step
130  Tag tagArea = 0;
131  std::string tag_name4( "Area" );
132  rval = mb->tag_get_handle( tag_name4.c_str(), 1, MB_TYPE_DOUBLE, tagArea, MB_TAG_DENSE | MB_TAG_CREAT );
133  ERRORV( rval, "can't get area tag" );
134 
135  std::cout << " num quads = " << eulQuads.size() << "\n";
136 
137  rval = mb->tag_set_data( tagElem, eulQuads, &tracer_vals[0] );
138  ERRORV( rval, "can't set tracer data" );
139 
140  rval = pworker->update_tracer_data( output_set, tagElem, tagArea );
141  ERRORV( rval, "can't update tracer " );
142 
143  rval = mb->tag_get_data( tagElem, eulQuads, &tracer_vals[0] );
144  ERRORV( rval, "can't get tracer data" );
145 
146  *ierr = 0;
147  return;
148 }
149 
150 void update_tracer( iMesh_Instance instance, iBase_EntitySetHandle imesh_euler_set, int* ierr )
151 {
152  using namespace moab;
153  const double radius = 1.;
154  const double gtol = 1.e-9;
155  const bool debug = false;
156 
157  Range ents;
158  moab::Interface* mb = MOABI;
159  *ierr = 1;
160 
161  EntityHandle euler_set = (EntityHandle)imesh_euler_set;
162 
163  Intx2MeshOnSphere worker( mb );
164  worker.SetRadius( radius );
165 
166  worker.SetErrorTolerance( gtol );
167 
168  EntityHandle covering_lagr_set;
169 
170  ErrorCode rval = mb->create_meshset( MESHSET_SET, covering_lagr_set );
171  ERRORV( rval, "can't create covering set " );
172 
173  // we need to update the correlation tag and remote tuples
174  rval = worker.create_departure_mesh_2nd_alg( euler_set, covering_lagr_set );
175  ERRORV( rval, "can't populate covering set " );
176 
177  if( debug )
178  {
179  rval = mb->write_file( "lagr.h5m", 0, 0, &covering_lagr_set, 1 );
180  ERRORV( rval, "can't write covering set " );
181  }
182 
183  //
184  rval = enforce_convexity( mb, covering_lagr_set );
185  ERRORV( rval, "can't write covering set " );
186 
187  EntityHandle outputSet;
188  rval = mb->create_meshset( MESHSET_SET, outputSet );
189  ERRORV( rval, "can't create output set " );
190 
191  rval = worker.intersect_meshes( covering_lagr_set, euler_set, outputSet );
192  ERRORV( rval, "can't intersect " );
193 
194  if( debug )
195  {
196  rval = mb->write_file( "output.vtk", 0, 0, &outputSet, 1 );
197  ERRORV( rval, "can't write covering set " );
198  }
199 
200  // tagElem is the average computed at each element, from nodal values
201  Tag tagElem = 0;
202  std::string tag_name2( "TracerAverage" );
203  rval = mb->tag_get_handle( tag_name2.c_str(), 1, MB_TYPE_DOUBLE, tagElem, MB_TAG_DENSE | MB_TAG_CREAT );
204  ERRORV( rval, "can't get tracer tag " );
205 
206  // area of the euler element is fixed, store it; it is used to recompute the averages at each
207  // time step
208  Tag tagArea = 0;
209  std::string tag_name4( "Area" );
210  rval = mb->tag_get_handle( tag_name4.c_str(), 1, MB_TYPE_DOUBLE, tagArea, MB_TAG_DENSE | MB_TAG_CREAT );
211  ERRORV( rval, "can't get area tag" );
212 
213  rval = worker.update_tracer_data( outputSet, tagElem, tagArea );
214  ERRORV( rval, "can't update tracer " );
215 
216  // everything can be deleted now from intx data; polygons, etc.
217 
218  *ierr = 0;
219  return;
220 }
221 
223  ParallelComm* pcomm,
224  EntityHandle coarseSet,
225  double* coords,
226  int* corners,
227  int nc,
228  int nelem,
229  EntityHandle& start_vert,
230  int& totalNumVertices,
231  int& numCornerVertices,
232  std::vector< double* >& coordv )
233 {
234 
235  int rank = pcomm->proc_config().proc_rank();
236 
237  Tag tagid; // global id at corners
238  ErrorCode rval;
239  tagid = mb->globalId_tag();
240 
241  int dum_id = -1;
242  Tag partitionTag;
244  &dum_id );
245 
246  // there are nelem*4 corners, and 3*(nc2+1)*(nc2+1)*nelem coordinates
247  // create first a coarse mesh,
248  int size_corners = 4 * nelem;
249  // int size_coords=3*(nc+1)*(nc+1)*nelem;
250  // order first the corners array, and eliminate duplicates
251  std::vector< int > corn1( size_corners );
252  std::copy( corners, corners + size_corners, corn1.begin() );
253  std::sort( corn1.begin(), corn1.end() );
254  corn1.erase( std::unique( corn1.begin(), corn1.end() ), corn1.end() );
255 
256  numCornerVertices = (int)corn1.size();
257 
258  // these corners are actually dofs in spectral mesh, so they will vary from 0 to
259  // np*np*nel_global (at most) they are shared on edges, corners of spectral elements, so number
260  // of dofs is lower than this estimate still, the number of coarse vertices is close to number
261  // of cells + 2
262 
263  std::map< int, int > index_map;
264  for( size_t i = 0; i < corn1.size(); i++ )
265  index_map[corn1[i]] = i;
266 
267  // estimate for the vertices that will get created, from euler formula
268  // v-e+f = 2 for whole sphere
269  // for one task (distributed) v-e+f = 1, for one connected region
270  // if multiple connex regions (out of HFSC distribution from homme), v-e+f = k, k is number of
271  // connectivity regs so in any case, e = v+f -k, where k is at least 1 (1, 2, 3, etc) so in any
272  // case number of coarse edges is at most e_max = v+f-1
273 
274  // this will give an estimate for the number of "fine" vertices
275  int e_max = nelem + numCornerVertices - 1;
276  // total number of extra vertices will be
277  int numVertsOnEdges = ( nc - 1 ) * e_max;
278  int numExtraVerts = numVertsOnEdges + ( nc - 1 ) * ( nc - 1 ) * nelem; // internal fine vertices
279 
280  totalNumVertices = numCornerVertices + numExtraVerts; // this could be overestimated, because we are not sure
281  // about the number of edges
282 
283  // used to determine the if the nodes are matching at corners of elements
284  std::vector< int > index_used( numCornerVertices, 0 );
285 
286  ReadUtilIface* read_iface;
287  rval = mb->query_interface( read_iface );ERRORR( rval, "can't get query intf " );
288 
289  EntityHandle start_elem, *connect;
290  // create verts, num is 2(nquads+1) because they're in a 1d row; will initialize coords in loop
291  // over quads later
292  rval = read_iface->get_node_coords( 3, totalNumVertices, 0, start_vert, coordv );ERRORR( rval, "can't get node coords " );
293  // fill it up
294  int stride = ( nc + 1 ) * ( nc + 1 ); // 16, for nc ==3
295  // int order_in_coord[] = {0, 3, 15, 12}; // for nc=3
296  /*
297 
298  * first j, then i, so this is the order of the points in coords array, now:
299  *
300  * nc(nc+1), ... (nc+1)*(nc+1)-1
301  *
302  * 2(nc+1),
303  * nc+1, nc+2, 2*(nc+1)-1
304  * 0, 1 , 2, ..........., nc
305  */
306  int order_in_coord[] = { 0, nc, ( nc + 1 ) * ( nc + 1 ) - 1, nc * ( nc + 1 ) };
307  for( int i = 0; i < size_corners; i++ )
308  {
309  int id = corners[i];
310  int index = index_map[id];
311 
312  int j = i % 4;
313  int ind_coord = i / 4;
314  ind_coord = ( ind_coord * stride + order_in_coord[j] ) * 3;
315  if( index_used[index] )
316  {
317  if( fabs( coordv[0][index] - coords[ind_coord] ) > 0.000001 )
318  std::cout << " id:" << corners[i] << " i:" << i << " j:" << j << " " << coordv[0][index] << " "
319  << coords[ind_coord] << "\n";
320  continue;
321  }
322  coordv[0][index] = coords[ind_coord];
323  coordv[1][index] = coords[ind_coord + 1];
324  coordv[2][index] = coords[ind_coord + 2];
325  index_used[index] = 1;
326  EntityHandle vertexh = start_vert + index;
327  rval = mb->tag_set_data( tagid, &vertexh, 1, (void*)&id );ERRORR( rval, "can't set tag id on vertex " );
328  }
329  // create quads; one quad for each spectral element; later, we will create fine quads
330  rval = read_iface->get_element_connect( nelem, 4, MBQUAD, 0, start_elem, connect );ERRORR( rval, "can't create elements " );
331 
332  for( int i = 0; i < nelem; i++ )
333  {
334  for( int j = 0; j < 4; j++ )
335  {
336  int index_v = index_map[corners[i * 4 + j]];
337  connect[i * 4 + j] = start_vert + index_v;
338  }
339  }
340 
341  Range quads( start_elem, start_elem + nelem - 1 );
342 
343  mb->add_entities( coarseSet, quads );
344 
345  // create all edges adjacent to quads
346  Range coarseEdges;
347  rval = mb->get_adjacencies( quads, 1, true, coarseEdges, Interface::UNION );ERRORR( rval, "can't create edges " );
348 
349  mb->add_entities( coarseSet, coarseEdges );
350 
351  // see how much we overestimated the number e_max
352  std::cout << " on rank " << rank << " e_max is " << e_max << " actual number of edges: " << coarseEdges.size()
353  << "\n";
354  rval = pcomm->resolve_shared_ents( coarseSet, 2, 1 ); // resolve vertices and edges
355  ERRORR( rval, "can't resolve shared vertices and edges " );
356 
357  mb->tag_set_data( partitionTag, &coarseSet, 1, &rank );
358 
359  /* // do we have any edges?
360  Range edges;
361  mb->get_entities_by_dimension(0, 1, edges);
362  if (rank == 0)
363  std::cout << " number of edges after resolve share ents:" << edges.size()
364  << "\n";*/
365 
366  rval = mb->write_file( "coarse.h5m", 0, "PARALLEL=WRITE_PART", &coarseSet, 1 );ERRORR( rval, "can't write in parallel coarse mesh" );
367  // coarse mesh, from corners
368 
369  return rval;
370 }
371 
372 // start_v and coordv refer to all vertices, including the coarse ones
374  std::vector< double* >& coordv,
375  double* coords,
376  Range& edges,
377  EntityHandle start_v,
378  Range& coarseQuads,
379  int nc,
380  int numCornerVertices,
381  Tag& fineVertOnEdgeTag )
382 {
383  ErrorCode rval = MB_SUCCESS;
384 
385  double* coordv2[3];
386  for( int k = 0; k < 3; k++ )
387  coordv2[k] = coordv[k] + numCornerVertices; // they will start later
388 
389  assert( NC == nc );
390 
391  int edges_index[4][NC - 1]; // indices in the coords array for vertices, oriented positively
392  /*
393  * first j, then i, so this is the order of the points in coords array, now:
394  *
395  * nc(nc+1), ... (nc+1)*(nc+1)-1
396  *
397  * 2(nc+1),
398  * nc+1, nc+2, 2*(nc+1)-1
399  * 0, 1 , 2, ..........., nc
400  */
401  // for first edge, oriented positive, the coords indices (*3) are 1, 2, (nc-1)
402  // second edge 2*(nc+1)-1, 3*(nc+1) -1, ...,
403  // nc*(nc+1)-1 third edge: (nc+1) * (nc+1) -2,
404  // ..., nc*(nc+1) +1 fourth edge: (nc-1)*(nc+1),
405  // ..., (nc+1)
406  for( int j = 1; j <= nc - 1; j++ )
407  {
408  edges_index[0][j - 1] = j; // for nc = 3: 1, 2
409  edges_index[1][j - 1] = ( j + 1 ) * ( nc + 1 ) - 1; // 7, 11
410  edges_index[2][j - 1] = ( nc + 1 ) * ( nc + 1 ) - j - 1; // 14, 13
411  edges_index[3][j - 1] = ( nc - j ) * ( nc + 1 ); // 8, 4
412  }
413  // int num_quads=(int)coarseQuads.size();
414  int stride = ( nc + 1 ) * ( nc + 1 );
415  int indexv = 0;
416  for( Range::iterator eit = edges.begin(); eit != edges.end(); ++eit )
417  {
418  EntityHandle edge = *eit;
419  std::vector< EntityHandle > faces;
420  rval = mb->get_adjacencies( &edge, 1, 2, false, faces );ERRORR( rval, "can't get adjacent faces." );
421  if( faces.size() < 1 ) return MB_FAILURE;
422  int sense = 0, side_number = -1, offset = -1;
423  EntityHandle quad = faces[0]; // just consider first quad
424  rval = mb->side_number( quad, edge, side_number, sense, offset );ERRORR( rval, "can't get side number" );
425  int indexq = coarseQuads.index( quad );
426 
427  if( indexq == -1 ) return MB_FAILURE;
428 
429  EntityHandle firstRefinedV = start_v + numCornerVertices + indexv;
430  rval = mb->tag_set_data( fineVertOnEdgeTag, &edge, 1, &firstRefinedV );ERRORR( rval, "can't set refined vertex tag" );
431  // copy the right coordinates from the coords array to coordv2 array
432 
433  double* start_quad = &coords[3 * stride * indexq];
434  if( sense > 0 )
435  {
436  for( int k = 1; k <= nc - 1; k++ )
437  {
438  int index_in_quad = edges_index[side_number][k - 1] * 3;
439  coordv2[0][indexv] = start_quad[index_in_quad];
440  coordv2[1][indexv] = start_quad[index_in_quad + 1];
441  coordv2[2][indexv] = start_quad[index_in_quad + 2];
442  indexv++;
443  }
444  }
445  else
446  {
447  // sense < 0, so we will traverse the edge in inverse sense
448  for( int k = 1; k <= nc - 1; k++ )
449  {
450  int index_in_quad = edges_index[side_number][nc - 1 - k] * 3;
451  coordv2[0][indexv] = start_quad[index_in_quad];
452  coordv2[1][indexv] = start_quad[index_in_quad + 1];
453  coordv2[2][indexv] = start_quad[index_in_quad + 2];
454  indexv++;
455  }
456  }
457  }
458  return rval;
459 }
460 /*
461  ErrorCode resolve_interior_verts_on_bound_edges(Interface * mb, ParallelComm * pcomm,
462  Range & edges)
463  {
464  // edges are coarse edges;
465  ErrorCode rval;
466  int rank=pcomm->proc_config().proc_rank();
467  Range sharedCoarseEdges=edges;// filter the non shared ones
468  rval = pcomm->filter_pstatus(sharedCoarseEdges, PSTATUS_SHARED, PSTATUS_AND);ERRORR(rval, "can't filter coarse edges
469  "); ParallelMergeMesh pmerge(pcomm, 0.0001); ErrorCode rval = pmerge.merge();
470 
471  return rval;
472  }*/
474  ParallelComm* pcomm,
475  EntityHandle coarseSet,
476  EntityHandle fine_set,
477  double* coords,
478  int nc,
479  int nelem,
480  EntityHandle start_vert,
481  int numCornerVertices,
482  std::vector< double* >& coordv )
483 {
484  int rank = pcomm->proc_config().proc_rank();
485  int stride = ( nc + 1 ) * ( nc + 1 ); // 16, for nc ==3
486  // there are stride*3 coordinates for each coarse quad, representing the fine mesh
487 
488  Tag fineVertTag;
489  // will store the first refined vertex on an edge in a entity handle tag
490  EntityHandle def = 0;
491  ErrorCode rval =
492  mb->tag_get_handle( "__firstvertex", 1, MB_TYPE_HANDLE, fineVertTag, MB_TAG_DENSE | MB_TAG_CREAT, &def );ERRORR( rval, "can't get tag on first vertex" );
493 
494  Range coarseQuads;
495  Range edges;
496  rval = mb->get_entities_by_dimension( coarseSet, 2, coarseQuads );ERRORR( rval, "can't get coarse quads " );
497 
498  rval = mb->get_entities_by_dimension( coarseSet, 1, edges );ERRORR( rval, "can't get coarse edges " );
499 
500  Range verts;
501  rval = mb->get_connectivity( coarseQuads, verts );ERRORR( rval, "can't get coarse vertices " );
502 
503  /*std::cout <<" local coarse mesh on rank " << rank << " "<< coarseQuads.size() << " quads, "
504  << edges.size() << " edges, " << verts.size() << " vertices.\n";*/
505 
506  int dum_id = -1;
507  Tag partitionTag;
509  &dum_id );
510  // fine mesh, with all coordinates
511  // std::vector<double *> coordv2;
512 
513  ReadUtilIface* read_iface;
514  rval = mb->query_interface( read_iface );ERRORR( rval, "can't get query intf " );
515 
516  ;
517  // create verts, (nc+1)*(nc+1)*nelem - verts.size()
518  //
519  /* int numVertsOnEdges = (nc-1)*(int)edges.size();
520  int numExtraVerts = numVertsOnEdges + (nc-1)*(nc-1)*nelem; // internal fine vertices
521  rval = read_iface->get_node_coords(3, numExtraVerts, 0,
522  start_vert, coordv2);*/
523  // ERRORR(rval, "can't get coords fine mesh");
524  // fill coordinates for vertices on the edges, then vertices in the interior of coarse quads
525  // we know that all quads are in order, their index corresponds to index in coords array
526  rval =
527  fill_coord_on_edges( mb, coordv, coords, edges, start_vert, coarseQuads, nc, numCornerVertices, fineVertTag );ERRORR( rval, "can't fill edges vertex coords on fine mesh" );
528 
529  EntityHandle start_elem, *connect;
530  rval = read_iface->get_element_connect( nelem * nc * nc, 4, MBQUAD, 0, start_elem, connect );ERRORR( rval, "can't create elements fine mesh" );
531 
532  int iv = ( nc - 1 ) * edges.size() + numCornerVertices; // iv is in the coordv array indices
533  start_vert = start_vert + numCornerVertices + ( nc - 1 ) * edges.size();
534 
535  /* // add a child to the mesh set, with the ordered vertices, as they come out in the list of
536  coordinates EntityHandle vertSet; rval = mb->create_meshset(MESHSET_ORDERED, vertSet);ERRORR(rval, "can't create
537  vertex set ");
538 
539  rval = mb->add_parent_child(fine_set, vertSet);ERRORR(rval, "can't create parent child relation between fine set
540  and vertSet ");*/
541 
542  std::vector< EntityHandle > vertList;
543  vertList.reserve( nelem * ( nc + 1 ) * ( nc + 1 ) ); // will have a list of vertices, in order
544 
545  // now fill coordinates on interior nodes; also mark the start for each interior vertex
546  // in a coarse quad
547  for( int ie = 0; ie < nelem; ie++ )
548  {
549  // just fill coordinates for an array of (nc-1)*(nc-1) vertices
550  EntityHandle firstVert = start_vert + ( nc - 1 ) * ( nc - 1 ) * ie;
551  EntityHandle eh = coarseQuads[ie];
552  rval = mb->tag_set_data( fineVertTag, &eh, 1, &firstVert );ERRORR( rval, "can't set refined vertex tag" );
553 
554  int index_coords = stride * ie;
555  for( int j = 1; j <= ( nc - 1 ); j++ )
556  {
557  for( int i = 1; i <= ( nc - 1 ); i++ )
558  {
559  int indx2 = 3 * ( index_coords + ( nc + 1 ) * j + i );
560  coordv[0][iv] = coords[indx2];
561  coordv[1][iv] = coords[indx2 + 1];
562  coordv[2][iv] = coords[indx2 + 2];
563  iv++;
564  }
565  }
566  }
567 
568  Range quads3( start_elem, start_elem + nelem * nc * nc - 1 );
569 
570  int ic = 0;
571  for( int ie = 0; ie < nelem; ie++ )
572  {
573  // just fill coordinates for an array of (nc-1)*(nc-1) vertices
574  EntityHandle arr2[NC + 1][NC + 1]; //
575  /*
576  * (nc,0) (nc,nc)
577  *
578  *
579  * (1,0) (1,nc)
580  * (0,0) (0,1) (0,nc)
581  */
582  EntityHandle coarseQ = coarseQuads[ie];
583  const EntityHandle* conn4 = NULL;
584  int nnodes = 0;
585  rval = mb->get_connectivity( coarseQ, conn4, nnodes );ERRORR( rval, "can't get conn of coarse quad" );
586  if( nnodes != 4 ) return MB_FAILURE;
587 
588  arr2[0][0] = conn4[0];
589  arr2[nc][0] = conn4[1];
590  arr2[nc][nc] = conn4[2];
591  arr2[0][nc] = conn4[3];
592 
593  // get the coarse edges
594  std::vector< EntityHandle > aedges;
595  rval = mb->get_adjacencies( &coarseQ, 1, 1, false, aedges );ERRORR( rval, "can't get adje edges of coarse quad" );
596  assert( (int)aedges.size() == 4 );
597 
598  for( int k = 0; k < 4; k++ )
599  {
600  EntityHandle edh = aedges[k];
601  /*
602  edges_index[0][j-1] = j; // for nc = 3: 1, 2
603  edges_index[1][j-1] = (j+1)*(nc+1) - 1; // 7, 11
604  edges_index[2][j-1] = (nc+1)*(nc+1) - j - 1; // 14, 13
605  edges_index[3][j-1] = (nc-j) * (nc+1) ; // 8, 4
606  */
607  int sense = 0, side_number = -1, offset = -1;
608  rval = mb->side_number( coarseQ, edh, side_number, sense, offset );ERRORR( rval, "can't get side number" );
609  EntityHandle firstV; // first vertex on edge, if edge oriented positively
610  rval = mb->tag_get_data( fineVertTag, &edh, 1, &firstV );ERRORR( rval, "can't get first vertex tag on edge" );
611  if( sense > 0 )
612  {
613  if( 0 == side_number )
614  {
615  for( int i = 1; i <= nc - 1; i++ )
616  arr2[i][0] = firstV + i - 1;
617  }
618  else if( 1 == side_number )
619  {
620  for( int j = 1; j <= nc - 1; j++ )
621  arr2[nc][j] = firstV + j - 1;
622  }
623  else if( 2 == side_number )
624  {
625  for( int i = nc - 1; i >= 1; i-- )
626  arr2[i][nc] = firstV + nc - 1 - i;
627  }
628  else if( 3 == side_number )
629  {
630  for( int j = nc - 1; j >= 1; j-- )
631  arr2[0][j] = firstV + nc - 1 - j;
632  }
633  }
634  else // if (sense<0)
635  {
636  if( 0 == side_number )
637  {
638  for( int i = 1; i <= nc - 1; i++ )
639  arr2[i][0] = firstV + nc - 1 - i;
640  }
641  else if( 1 == side_number )
642  {
643  for( int j = 1; j <= nc - 1; j++ )
644  arr2[nc][j] = firstV + nc - 1 - j;
645  }
646  else if( 2 == side_number )
647  {
648  for( int i = nc - 1; i >= 1; i-- )
649  arr2[i][nc] = firstV + i - 1;
650  }
651  else if( 3 == side_number )
652  {
653  for( int j = nc - 1; j >= 1; j-- )
654  arr2[0][j] = firstV + j - 1;
655  }
656  }
657  }
658  // fill the interior points matrix
659  EntityHandle firstV; // first vertex on interior of coarse quad
660  rval = mb->tag_get_data( fineVertTag, &coarseQ, 1, &firstV );ERRORR( rval, "can't get first vertex tag on coarse tag" );
661  int inc = 0;
662  for( int j = 1; j <= nc - 1; j++ )
663  {
664  for( int i = 1; i <= nc - 1; i++ )
665  {
666  arr2[i][j] = firstV + inc;
667  inc++;
668  }
669  }
670  // fill now the matrix of quads; vertices are from 0 to (nc+1)*(nc+1)-1
671  for( int j1 = 0; j1 < nc; j1++ )
672  {
673  for( int i1 = 0; i1 < nc; i1++ )
674  {
675  connect[ic++] = arr2[i1][j1]; // first one
676  connect[ic++] = arr2[i1 + 1][j1]; //
677  connect[ic++] = arr2[i1 + 1][j1 + 1]; // opp diagonal
678  connect[ic++] = arr2[i1][j1 + 1]; //
679  }
680  }
681 
682  for( int j1 = 0; j1 <= nc; j1++ )
683  {
684  for( int i1 = 0; i1 <= nc; i1++ )
685  {
686  vertList.push_back( arr2[i1][j1] );
687  }
688  }
689  }
690  /*
691  rval = mb->add_entities(vertSet, &vertList[0], (int)vertList.size());ERRORR(rval,"can't add to the vert set the
692  list of ordered vertices");*/
693 
694  mb->add_entities( fine_set, quads3 );
695  // notify MOAB of the new elements
696  rval = read_iface->update_adjacencies( start_elem, nelem * nc * nc, 4, connect );ERRORR( rval, "can't update adjacencies on fine quads" );
697 
698  rval = mb->tag_set_data( partitionTag, &fine_set, 1, &rank );ERRORR( rval, "can't set partition tag on fine set" );
699 
700  /*
701  // delete the coarse mesh, except vertices
702  mb->delete_entities(coarseQuads);
703  mb->delete_entities(edges);
704  */
705 
706  // the vertices on the boundary edges of the partition need to be shared and resolved
707  ParallelMergeMesh pmerge( pcomm, 0.0001 );
708  rval = pmerge.merge();ERRORR( rval, "can't resolve vertices on interior of boundary edges " );
709 
710  rval = mb->get_connectivity( quads3, verts );ERRORR( rval, "can't get vertices " );
711 
712  Range owned_verts = verts;
713  rval = pcomm->filter_pstatus( owned_verts, PSTATUS_NOT_OWNED, PSTATUS_NOT );ERRORR( rval, "can't filter for owned vertices only" );
714 
715  Range entities[4];
716  entities[0] = owned_verts;
717  entities[2] = quads3;
718  // assign new ids only for owned entities
719  // will eliminate gaps in global id space for vertices
720  rval = pcomm->assign_global_ids( entities, 2, 1, true, false );ERRORR( rval, "can't assign global ids for vertices " );
721 
722  /*ErrorCode ParallelComm::assign_global_ids( Range entities[],
723  const int dimension,
724  const int start_id,
725  const bool parallel,
726  const bool owned_only) */
727 
728  std::stringstream fff;
729  fff << "fine0" << pcomm->proc_config().proc_rank() << ".h5m";
730  mb->write_mesh( fff.str().c_str(), &fine_set, 1 );
731 
732  rval = mb->write_file( "fine.h5m", 0, "PARALLEL=WRITE_PART", &fine_set, 1 );ERRORR( rval, "can't write set 3, fine " );
733 
734  // we need to keep a mapping index, from the coords array to the vertex handles
735  // so, for a given vertex entity handle, at what index in the coords array the vertex
736  // coordinates are?
737  // in the coords array, vertices are repeated 2 times if they are interior to a coarse edge, and
738  // repeated 3 or 4 times if they are a corner vertex in a coarse quad
739 
740  numVertices = (int)verts.size();
741  mapping_to_coords = new int[numVertices];
742  for( int k = 0; k < numVertices; k++ )
743  mapping_to_coords[k] = -1; // it means it was not located yet in vertList
744  // vertList is parallel to the coords and dep_coords array
745 
746  // now loop over vertsList, and see where
747  // vertList has nelem * (nc+1)*(nc+1) vertices; loop over them, and see where are they located
748 
749  for( int kk = 0; kk < (int)vertList.size(); kk++ )
750  {
751  EntityHandle v = vertList[kk];
752  int index = verts.index( v );
753  if( -1 == index )
754  {
755  std::cout << " can't locate vertex " << v << " in vertex Range \n";
756  return MB_FAILURE;
757  }
758  if( mapping_to_coords[index] == -1 ) // it means the vertex v was not yet encountered in the vertList
759  {
760  mapping_to_coords[index] = kk;
761  }
762  }
763  // check that every mapping has an index different from -1
764  for( int k = 0; k < numVertices; k++ )
765  {
766  if( mapping_to_coords[k] == -1 )
767  {
768  {
769  std::cout << " vertex at index " << k << " in vertex Range " << verts[k] << " is not mapped \n";
770  return MB_FAILURE; //
771  }
772  }
773  }
774 
775  return rval;
776 }
777 
778 // this is called from Fortran 90
779 void create_mesh( iMesh_Instance instance,
780  iBase_EntitySetHandle* imesh_euler_set,
781  iBase_EntitySetHandle* imesh_departure_set,
782  iBase_EntitySetHandle* imesh_intx_set,
783  double* coords,
784  int* corners,
785  int nc,
786  int nelem,
787  MPI_Fint comm,
788  int* ierr )
789 {
790  /* double * coords=(double*) icoords;
791  int * corners = (int*) icorners;*/
792  *ierr = 1;
793  Interface* mb = MOABI;
794  MPI_Comm mpicomm = MPI_Comm_f2c( comm );
795  // instantiate parallel comm now or not?
796  ParallelComm* pcomm = new ParallelComm( mb, mpicomm );
797 
798  EntityHandle coarseSet;
799  ErrorCode rval = mb->create_meshset( MESHSET_SET, coarseSet );
800  ERRORV( rval, "can't create coarse set " );
801 
802  EntityHandle start_vert;
803  int totalNumVertices;
804  int numCornerVertices;
805  std::vector< double* > coordv;
806  rval = create_coarse_mesh( mb, pcomm, coarseSet, coords, corners, nc, nelem, start_vert, totalNumVertices,
807  numCornerVertices, coordv );
808  ERRORV( rval, "can't create coarse set " );
809 
810  EntityHandle fine_set;
811  rval = mb->create_meshset( MESHSET_SET, fine_set );
812  ERRORV( rval, "can't create fine set " );
813 
814  rval = create_fine_mesh( mb, pcomm, coarseSet, fine_set, coords, nc, nelem, start_vert, numCornerVertices, coordv );
815  ERRORV( rval, "can't create fine mesh set " );
816 
817  *imesh_departure_set = (iBase_EntitySetHandle)fine_set;
818 
819  EntityHandle euler_set;
820  rval = mb->create_meshset( MESHSET_SET, euler_set );
821  ERRORV( rval, "can't create moab euler set " );
822  *imesh_euler_set = (iBase_EntitySetHandle)euler_set;
823 
824  // call in Intx utils
825  // it will copy the second set from the first set
826  rval = deep_copy_set_with_quads( mb, fine_set, euler_set );
827  ERRORV( rval, "can't populate lagrange set " );
828 
829  EntityHandle intx_set;
830  rval = mb->create_meshset( MESHSET_SET, intx_set );
831  ERRORV( rval, "can't create output set " );
832 
833  *imesh_intx_set = (iBase_EntitySetHandle)intx_set;
834 
835  pworker = new Intx2MeshOnSphere( mb );
836 
837  pworker->set_box_error( 100 * gtol );
838  Range local_verts;
839  rval = pworker->build_processor_euler_boxes( euler_set,
840  local_verts ); // output also the local_verts
841  ERRORV( rval, "can't compute euler boxes " );
842  pworker->SetErrorTolerance( gtol );
843 
844  *ierr = 0;
845  return;
846 }
847 ErrorCode set_departure_points_position( Interface* mb, EntityHandle lagrSet, double* dep_coords, double radius2 )
848 {
849 
850  // the departure quads are created in the same order as the fine quads
851  // for each coarse element, there are nc*nc fine quads
852  // their vertices are in order
853  Range lagr_quads;
854  ErrorCode rval = mb->get_entities_by_type( lagrSet, MBQUAD, lagr_quads );ERRORR( rval, "can't get lagrange quads" );
855 
856  // get all vertices from lagr_quads
857  Range lVerts;
858  rval = mb->get_connectivity( lagr_quads, lVerts );ERRORR( rval, "can't get lagrangian vertices (departure)" );
859 
860  // they are parallel to the verts Array, they must have the same number of vertices
861  assert( numVertices == (int)lVerts.size() );
862 
863  for( int i = 0; i < numVertices; i++ )
864  {
865  EntityHandle v = lVerts[i];
866  int index = mapping_to_coords[i];
867  assert( -1 != index );
868 
869  SphereCoords sph;
870  sph.R = radius2;
871  sph.lat = dep_coords[2 * index];
872  sph.lon = dep_coords[2 * index + 1];
873 
874  CartVect depPoint = spherical_to_cart( sph );
875  rval = mb->set_coords( &v, 1, (double*)depPoint.array() );ERRORR( rval, "can't set position of vertex" );
876  }
877 
878  return MB_SUCCESS;
879 }
880 void intersection_at_level( iMesh_Instance instance,
881  iBase_EntitySetHandle fine_set,
882  iBase_EntitySetHandle lagr_set,
883  iBase_EntitySetHandle intx_set,
884  double* dep_coords,
885  double radius2,
886  int* ierr )
887 {
888  *ierr = 1;
889  Interface* mb = MOABI;
890  // MPI_Comm mpicomm = MPI_Comm_f2c(comm);
891  // instantiate parallel comm now or not?
892 
893  EntityHandle lagrMeshSet = (EntityHandle)lagr_set;
894 
895  ParallelComm* pcomm = ParallelComm::get_pcomm( mb, 0 );
896  if( NULL == pcomm ) return; // error is 1
897 
898  // set the departure tag on the fine mesh vertices
899  ErrorCode rval = set_departure_points_position( mb, lagrMeshSet, dep_coords, radius2 );
900  ERRORV( rval, "can't set departure tag" );
901  if( debug )
902  {
903  std::stringstream fff;
904  fff << "lagr0" << pcomm->proc_config().proc_rank() << ".vtk";
905  rval = mb->write_mesh( fff.str().c_str(), &lagrMeshSet, 1 );
906  ERRORV( rval, "can't write covering set " );
907  }
908 
909  // it should be done earlier
910  pworker->SetRadius( radius );
911 
912  EntityHandle covering_set;
913  rval = pworker->create_departure_mesh_3rd_alg( lagrMeshSet, covering_set );
914  ERRORV( rval, "can't compute covering set " );
915 
916  if( debug )
917  {
918  std::stringstream fff;
919  fff << "cover" << pcomm->proc_config().proc_rank() << ".vtk";
920  rval = mb->write_mesh( fff.str().c_str(), &covering_set, 1 );
921 
922  ERRORV( rval, "can't write covering set " );
923  }
924  EntityHandle intxSet = (EntityHandle)intx_set;
925  rval = pworker->intersect_meshes( covering_set, (EntityHandle)fine_set, intxSet );
926  ERRORV( rval, "can't intersect " );
927 
928  if( debug )
929  {
930  std::stringstream fff;
931  fff << "intx0" << pcomm->proc_config().proc_rank() << ".vtk";
932  rval = mb->write_mesh( fff.str().c_str(), &intxSet, 1 );
933  ERRORV( rval, "can't write covering set " );
934  }
935 
936  return;
937 }
938 void cleanup_after_intersection( iMesh_Instance instance,
939  iBase_EntitySetHandle fine_set,
940  iBase_EntitySetHandle lagr_set,
941  iBase_EntitySetHandle intx_set,
942  int* ierr )
943 {
944  *ierr = 1;
945  Interface* mb = MOABI;
946  // delete elements
947  // delete now the polygons and the elements of out_set
948  // also, all verts that are not in euler set or lagr_set
949  Range allVerts;
950  ErrorCode rval = mb->get_entities_by_dimension( 0, 0, allVerts );
951  ERRORV( rval, "can't get all vertices" );
952 
953  Range allElems;
954  rval = mb->get_entities_by_dimension( 0, 2, allElems );
955  ERRORV( rval, "can't get all elems" );
956 
957  Range polys; // first euler polys
958  rval = mb->get_entities_by_dimension( (EntityHandle)fine_set, 2, polys );
959  ERRORV( rval, "can't get all polys from fine set" );
960 
961  // add to polys range the lagr polys
962  rval = mb->get_entities_by_dimension( (EntityHandle)lagr_set, 2,
963  polys ); // do not delete lagr set either, with its vertices
964  ERRORV( rval, "can't get all polys from lagr set" );
965  // add to the connecVerts range all verts, from all initial polys
966  Range vertsToStay;
967  rval = mb->get_connectivity( polys, vertsToStay );
968  ERRORV( rval, "get verts that stay" );
969 
970  Range todeleteVerts = subtract( allVerts, vertsToStay );
971 
972  Range todeleteElem = subtract( allElems, polys ); // this is coarse mesh too (if still here)
973 
974  // empty the out mesh set
975  EntityHandle out_set = (EntityHandle)intx_set;
976  rval = mb->clear_meshset( &out_set, 1 );
977  ERRORV( rval, "clear mesh set" );
978 
979  rval = mb->delete_entities( todeleteElem );
980  ERRORV( rval, "delete intx elements" );
981  rval = mb->delete_entities( todeleteVerts );
982  ERRORV( rval, "failed to delete intx vertices" );
983 
984  *ierr = 0;
985  return;
986 }
987 
988 void cleanup_after_simulation( int* ierr )
989 {
990  delete[] mapping_to_coords;
991  numVertices = 0;
992  *ierr = 0;
993  return;
994 }
995 #ifdef __cplusplus
996 } // extern "C"
997 #endif