Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
Coupler.cpp
Go to the documentation of this file.
1 #include "Coupler.hpp"
2 #include "moab/ParallelComm.hpp"
4 #include "ElemUtil.hpp"
5 #include "moab/CN.hpp"
6 #include "moab/gs.hpp"
7 #include "moab/TupleList.hpp"
8 #include "moab/Error.hpp"
9 
10 /* C++ includes */
11 #include <cstdio>
12 #include <cassert>
13 #include <iostream>
14 #include <algorithm>
15 #include <sstream>
16 
17 #define ERROR( a ) \
18  { \
19  if( MB_SUCCESS != err ) std::cerr << ( a ) << std::endl; \
20  }
21 #define ERRORR( a, b ) \
22  { \
23  if( MB_SUCCESS != ( b ) ) \
24  { \
25  std::cerr << ( a ) << std::endl; \
26  return b; \
27  } \
28  }
29 #define ERRORMPI( a, b ) \
30  { \
31  if( MPI_SUCCESS != ( b ) ) \
32  { \
33  std::cerr << ( a ) << std::endl; \
34  return MB_FAILURE; \
35  } \
36  }
37 
38 #define MASTER_PROC 0
39 
40 namespace moab
41 {
42 
43 bool debug = false;
44 int pack_tuples( TupleList* tl, void** ptr );
45 void unpack_tuples( void* ptr, TupleList** tlp );
46 
48  ParallelComm* pc,
49  Range& local_elems,
50  int coupler_id,
51  bool init_tree,
52  int max_ent_dim )
53  : mbImpl( impl ), myPc( pc ), myId( coupler_id ), numIts( 3 ), max_dim( max_ent_dim ), _ntot( 0 ),
54  spherical( false )
55 {
56  assert( NULL != impl && ( pc || !local_elems.empty() ) );
57 
58  // Keep track of the local points, at least for now
59  myRange = local_elems;
60  myTree = NULL;
61 
62  // Now initialize the tree
63  if( init_tree ) initialize_tree();
64 
65  // Initialize tuple lists to indicate not initialized
66  mappedPts = NULL;
67  targetPts = NULL;
69 }
70 
71 /* Destructor
72  */
74 {
75  // This will clear the cache
78  delete myTree;
79  delete targetPts;
80  delete mappedPts;
81 }
82 
84 {
85  Range local_ents;
86 
87  // Get entities on the local part
88  ErrorCode result = MB_SUCCESS;
89  if( myPc )
90  {
91  result = myPc->get_part_entities( local_ents, max_dim );
92  if( local_ents.empty() )
93  {
94  max_dim--;
95  result = myPc->get_part_entities( local_ents, max_dim ); // go one dimension lower
96  // right now, this is used for spherical meshes only
97  }
98  }
99  else
100  local_ents = myRange;
101  if( MB_SUCCESS != result || local_ents.empty() )
102  {
103  std::cout << "Problems getting source entities" << std::endl;
104  return result;
105  }
106 
107  // Build the tree for local processor
108  int max_per_leaf = 6;
109  for( int i = 0; i < numIts; i++ )
110  {
111  std::ostringstream str;
112  str << "PLANE_SET=0;"
113  << "MAX_PER_LEAF=" << max_per_leaf << ";";
114  if( spherical && !local_ents.empty() )
115  {
116  // get coordinates of one vertex, and use for radius computation
117  EntityHandle elem = local_ents[0];
118  const EntityHandle* conn;
119  int numn = 0;
120  mbImpl->get_connectivity( elem, conn, numn );
121  CartVect pos0;
122  mbImpl->get_coords( conn, 1, &( pos0[0] ) );
123  double radius = pos0.length();
124  str << "SPHERICAL=true;RADIUS=" << radius << ";";
125  }
126  FileOptions opts( str.str().c_str() );
127  myTree = new AdaptiveKDTree( mbImpl );
128  result = myTree->build_tree( local_ents, &localRoot, &opts );
129  if( MB_SUCCESS != result )
130  {
131  std::cout << "Problems building tree";
132  if( numIts != i )
133  {
134  delete myTree;
135  max_per_leaf *= 2;
136  std::cout << "; increasing elements/leaf to " << max_per_leaf << std::endl;
137  }
138  else
139  {
140  std::cout << "; exiting" << std::endl;
141  return result;
142  }
143  }
144  else
145  break; // Get out of tree building
146  }
147 
148  // Get the bounding box for local tree
149  if( myPc )
150  allBoxes.resize( 6 * myPc->proc_config().proc_size() );
151  else
152  allBoxes.resize( 6 );
153 
154  unsigned int my_rank = ( myPc ? myPc->proc_config().proc_rank() : 0 );
155  BoundBox box;
156  result = myTree->get_bounding_box( box, &localRoot );
157  if( MB_SUCCESS != result ) return result;
158  box.bMin.get( &allBoxes[6 * my_rank] );
159  box.bMax.get( &allBoxes[6 * my_rank + 3] );
160 
161  // Now communicate to get all boxes
162  if( myPc )
163  {
164  int mpi_err;
165 #if( MPI_VERSION >= 2 )
166  // Use "in place" option
167  mpi_err = MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, &allBoxes[0], 6, MPI_DOUBLE,
168  myPc->proc_config().proc_comm() );
169 #else
170  {
171  std::vector< double > allBoxes_tmp( 6 * myPc->proc_config().proc_size() );
172  mpi_err = MPI_Allgather( &allBoxes[6 * my_rank], 6, MPI_DOUBLE, &allBoxes_tmp[0], 6, MPI_DOUBLE,
173  myPc->proc_config().proc_comm() );
174  allBoxes = allBoxes_tmp;
175  }
176 #endif
177  if( MPI_SUCCESS != mpi_err ) return MB_FAILURE;
178  }
179 
180  /* std::ostringstream blah;
181  for(int i = 0; i < allBoxes.size(); i++)
182  blah << allBoxes[i] << " ";
183  std::cout << blah.str() << "\n";*/
184 
185 #ifdef VERBOSE
186  double min[3] = { 0, 0, 0 }, max[3] = { 0, 0, 0 };
187  unsigned int dep;
188  myTree->get_info( localRoot, min, max, dep );
189  std::cout << "Proc " << my_rank << ": box min/max, tree depth = (" << min[0] << "," << min[1] << "," << min[2]
190  << "), (" << max[0] << "," << max[1] << "," << max[2] << "), " << dep << std::endl;
191 #endif
192 
193  return result;
194 }
195 
197  EntityHandle rootTarget,
198  bool& specSou,
199  bool& specTar )
200 {
201  /*void * _spectralSource;
202  void * _spectralTarget;*/
203 
204  moab::Range spectral_sets;
205  moab::Tag sem_tag;
206  int sem_dims[3];
207  ErrorCode rval = mbImpl->tag_get_handle( "SEM_DIMS", 3, moab::MB_TYPE_INTEGER, sem_tag );
208  if( moab::MB_SUCCESS != rval )
209  {
210  std::cout << "Can't find tag, no spectral set\n";
211  return MB_SUCCESS; // Nothing to do, no spectral elements
212  }
213  rval = mbImpl->get_entities_by_type_and_tag( rootSource, moab::MBENTITYSET, &sem_tag, NULL, 1, spectral_sets );
214  if( moab::MB_SUCCESS != rval || spectral_sets.empty() )
215  std::cout << "Can't get sem set on source\n";
216  else
217  {
218  moab::EntityHandle firstSemSet = spectral_sets[0];
219  rval = mbImpl->tag_get_data( sem_tag, &firstSemSet, 1, (void*)sem_dims );
220  if( moab::MB_SUCCESS != rval ) return MB_FAILURE;
221 
222  if( sem_dims[0] != sem_dims[1] || sem_dims[0] != sem_dims[2] )
223  {
224  std::cout << " dimensions are different. bail out\n";
225  return MB_FAILURE;
226  }
227  // Repeat for target sets
228  spectral_sets.empty();
229  // Now initialize a source spectral element !
230  _spectralSource = new moab::Element::SpectralHex( sem_dims[0] );
231  specSou = true;
232  }
233  // Repeat for target source
234  rval = mbImpl->get_entities_by_type_and_tag( rootTarget, moab::MBENTITYSET, &sem_tag, NULL, 1, spectral_sets );
235  if( moab::MB_SUCCESS != rval || spectral_sets.empty() )
236  std::cout << "Can't get sem set on target\n";
237  else
238  {
239  moab::EntityHandle firstSemSet = spectral_sets[0];
240  rval = mbImpl->tag_get_data( sem_tag, &firstSemSet, 1, (void*)sem_dims );
241  if( moab::MB_SUCCESS != rval ) return MB_FAILURE;
242 
243  if( sem_dims[0] != sem_dims[1] || sem_dims[0] != sem_dims[2] )
244  {
245  std::cout << " dimensions are different. bail out\n";
246  return MB_FAILURE;
247  }
248  // Repeat for target sets
249  spectral_sets.empty();
250  // Now initialize a target spectral element !
251  _spectralTarget = new moab::Element::SpectralHex( sem_dims[0] );
252  specTar = true;
253  }
254 
255  _ntot = sem_dims[0] * sem_dims[1] * sem_dims[2];
257  if( moab::MB_SUCCESS != rval )
258  {
259  std::cout << "Can't get xm1tag \n";
260  return MB_FAILURE;
261  }
263  if( moab::MB_SUCCESS != rval )
264  {
265  std::cout << "Can't get ym1tag \n";
266  return MB_FAILURE;
267  }
269  if( moab::MB_SUCCESS != rval )
270  {
271  std::cout << "Can't get zm1tag \n";
272  return MB_FAILURE;
273  }
274 
275  return MB_SUCCESS;
276 }
277 
278 ErrorCode Coupler::locate_points( Range& targ_ents, double rel_eps, double abs_eps, TupleList* tl, bool store_local )
279 {
280  // Get locations
281  std::vector< double > locs( 3 * targ_ents.size() );
282  Range verts = targ_ents.subset_by_type( MBVERTEX );
283  ErrorCode rval = mbImpl->get_coords( verts, &locs[0] );
284  if( MB_SUCCESS != rval ) return rval;
285  // Now get other ents; reuse verts
286  unsigned int num_verts = verts.size();
287  verts = subtract( targ_ents, verts );
288  // Compute centroids
289  std::vector< EntityHandle > dum_conn( CN::MAX_NODES_PER_ELEMENT );
290  std::vector< double > dum_pos( CN::MAX_NODES_PER_ELEMENT );
291  const EntityHandle* conn;
292  int num_conn;
293  double* coords = &locs[num_verts];
294  // Do this here instead of a function to allow reuse of dum_pos and dum_conn
295  for( Range::const_iterator rit = verts.begin(); rit != verts.end(); ++rit )
296  {
297  rval = mbImpl->get_connectivity( *rit, conn, num_conn, false, &dum_conn );
298  if( MB_SUCCESS != rval ) return rval;
299  rval = mbImpl->get_coords( conn, num_conn, &dum_pos[0] );
300  if( MB_SUCCESS != rval ) return rval;
301  coords[0] = coords[1] = coords[2] = 0.0;
302  for( int i = 0; i < num_conn; i++ )
303  {
304  coords[0] += dum_pos[3 * i];
305  coords[1] += dum_pos[3 * i + 1];
306  coords[2] += dum_pos[3 * i + 2];
307  }
308  coords[0] /= num_conn;
309  coords[1] /= num_conn;
310  coords[2] /= num_conn;
311  coords += 3;
312  }
313 
314  if( store_local ) targetEnts = targ_ents;
315 
316  return locate_points( &locs[0], targ_ents.size(), rel_eps, abs_eps, tl, store_local );
317 }
318 
320  unsigned int num_points,
321  double rel_eps,
322  double abs_eps,
323  TupleList* tl,
324  bool store_local )
325 {
326  assert( tl || store_local );
327 
328  // target_pts: TL(to_proc, tgt_index, x, y, z): tuples sent to source mesh procs representing
329  // pts to be located source_pts: TL(from_proc, tgt_index, src_index): results of source mesh
330  // proc point location, ready to send
331  // back to tgt procs; src_index of -1 indicates point not located (arguably not
332  // useful...)
333  TupleList target_pts;
334  target_pts.initialize( 2, 0, 0, 3, num_points );
335  target_pts.enableWriteAccess();
336 
337  TupleList source_pts;
338  mappedPts = new TupleList( 0, 0, 1, 3, target_pts.get_max() );
340 
341  source_pts.initialize( 3, 0, 0, 0, target_pts.get_max() );
342  source_pts.enableWriteAccess();
343 
344  mappedPts->set_n( 0 );
345  source_pts.set_n( 0 );
346  ErrorCode result;
347 
348  unsigned int my_rank = ( myPc ? myPc->proc_config().proc_rank() : 0 );
349  bool point_located;
350 
351  // For each point, find box(es) containing the point,
352  // appending results to tuple_list;
353  // keep local points separately, in local_pts, which has pairs
354  // of <local_index, mapped_index>, where mapped_index is the index
355  // into the mappedPts tuple list
356  for( unsigned int i = 0; i < 3 * num_points; i += 3 )
357  {
358 
359  std::vector< int > procs_to_send_to;
360  for( unsigned int j = 0; j < ( myPc ? myPc->proc_config().proc_size() : 0 ); j++ )
361  {
362  // Test if point is in proc's box
363  if( ( allBoxes[6 * j] <= xyz[i] + abs_eps ) && ( xyz[i] <= allBoxes[6 * j + 3] + abs_eps ) &&
364  ( allBoxes[6 * j + 1] <= xyz[i + 1] + abs_eps ) && ( xyz[i + 1] <= allBoxes[6 * j + 4] + abs_eps ) &&
365  ( allBoxes[6 * j + 2] <= xyz[i + 2] + abs_eps ) && ( xyz[i + 2] <= allBoxes[6 * j + 5] + abs_eps ) )
366  {
367  // If in this proc's box, will send to proc to test further
368  procs_to_send_to.push_back( j );
369  }
370  }
371  if( procs_to_send_to.empty() )
372  {
373 #ifdef VERBOSE
374  std::cout << " point index " << i / 3 << ": " << xyz[i] << " " << xyz[i + 1] << " " << xyz[i + 2]
375  << " not found in any box\n";
376 #endif
377  // try to find the closest box, and put it in that box, anyway
378  double min_dist = 1.e+20;
379  int index = -1;
380  for( unsigned int j = 0; j < ( myPc ? myPc->proc_config().proc_size() : 0 ); j++ )
381  {
382  BoundBox box( &allBoxes[6 * j] ); // form back the box
383  double distance = box.distance( &xyz[i] ); // will compute the distance in 3d, from the box
384  if( distance < min_dist )
385  {
386  index = j;
387  min_dist = distance;
388  }
389  }
390  if( index == -1 )
391  {
392  // need to abort early, nothing we can do
393  assert( "cannot locate any box for some points" );
394  // need a better exit strategy
395  }
396 #ifdef VERBOSE
397  std::cout << " point index " << i / 3 << " added to box for proc j:" << index << "\n";
398 #endif
399  procs_to_send_to.push_back( index ); // will send to just one proc, that has the closest box
400  }
401  // we finally decided to populate the tuple list for a list of processors
402  for( size_t k = 0; k < procs_to_send_to.size(); k++ )
403  {
404  unsigned int j = procs_to_send_to[k];
405  // Check size of tuple list, grow if we're at max
406  if( target_pts.get_n() == target_pts.get_max() )
407  target_pts.resize( std::max( 10.0, 1.5 * target_pts.get_max() ) );
408 
409  target_pts.vi_wr[2 * target_pts.get_n()] = j;
410  target_pts.vi_wr[2 * target_pts.get_n() + 1] = i / 3;
411 
412  target_pts.vr_wr[3 * target_pts.get_n()] = xyz[i];
413  target_pts.vr_wr[3 * target_pts.get_n() + 1] = xyz[i + 1];
414  target_pts.vr_wr[3 * target_pts.get_n() + 2] = xyz[i + 2];
415  target_pts.inc_n();
416  }
417 
418  } // end for (unsigned int i = 0; ..
419 
420  int num_to_me = 0;
421  for( unsigned int i = 0; i < target_pts.get_n(); i++ )
422  if( target_pts.vi_rd[2 * i] == (int)my_rank ) num_to_me++;
423 #ifdef VERBOSE
424  printf( "rank: %u local points: %u, nb sent target pts: %u mappedPts: %u num to me: %d \n", my_rank, num_points,
425  target_pts.get_n(), mappedPts->get_n(), num_to_me );
426 #endif
427  // Perform scatter/gather, to gather points to source mesh procs
428  if( myPc )
429  {
430  ( myPc->proc_config().crystal_router() )->gs_transfer( 1, target_pts, 0 );
431 
432  num_to_me = 0;
433  for( unsigned int i = 0; i < target_pts.get_n(); i++ )
434  {
435  if( target_pts.vi_rd[2 * i] == (int)my_rank ) num_to_me++;
436  }
437 #ifdef VERBOSE
438  printf( "rank: %u after first gs nb received_pts: %u; num_from_me = %d\n", my_rank, target_pts.get_n(),
439  num_to_me );
440 #endif
441  // After scatter/gather:
442  // target_pts.set_n(# points local proc has to map);
443  // target_pts.vi_wr[2*i] = proc sending point i
444  // target_pts.vi_wr[2*i + 1] = index of point i on sending proc
445  // target_pts.vr_wr[3*i..3*i + 2] = xyz of point i
446  //
447  // Mapping builds the tuple list:
448  // source_pts.set_n(target_pts.get_n())
449  // source_pts.vi_wr[3*i] = target_pts.vi_wr[2*i] = sending proc
450  // source_pts.vi_wr[3*i + 1] = index of point i on sending proc
451  // source_pts.vi_wr[3*i + 2] = index of mapped point (-1 if not mapped)
452  //
453  // Also, mapping builds local tuple_list mappedPts:
454  // mappedPts->set_n( # mapped points );
455  // mappedPts->vul_wr[i] = local handle of mapped entity
456  // mappedPts->vr_wr[3*i..3*i + 2] = natural coordinates in mapped entity
457 
458  // Test target points against my elements
459  for( unsigned i = 0; i < target_pts.get_n(); i++ )
460  {
461  result = test_local_box( target_pts.vr_wr + 3 * i, target_pts.vi_rd[2 * i], target_pts.vi_rd[2 * i + 1], i,
462  point_located, rel_eps, abs_eps, &source_pts );
463  if( MB_SUCCESS != result ) return result;
464  }
465 
466  // No longer need target_pts
467  target_pts.reset();
468 #ifdef VERBOSE
469  printf( "rank: %u nb sent source pts: %u, mappedPts now: %u\n", my_rank, source_pts.get_n(),
470  mappedPts->get_n() );
471 #endif
472  // Send target points back to target procs
473  ( myPc->proc_config().crystal_router() )->gs_transfer( 1, source_pts, 0 );
474 
475 #ifdef VERBOSE
476  printf( "rank: %u nb received source pts: %u\n", my_rank, source_pts.get_n() );
477 #endif
478  }
479 
480  // Store proc/index tuples in targetPts, and/or pass back to application;
481  // the tuple this gets stored to looks like:
482  // tl.set_n(# mapped points);
483  // tl.vi_wr[3*i] = remote proc mapping point
484  // tl.vi_wr[3*i + 1] = local index of mapped point
485  // tl.vi_wr[3*i + 2] = remote index of mapped point
486  //
487  // Local index is mapped into either myRange, holding the handles of
488  // local mapped entities, or myXyz, holding locations of mapped pts
489 
490  // Store information about located points
491  TupleList* tl_tmp;
492  if( !store_local )
493  tl_tmp = tl;
494  else
495  {
496  targetPts = new TupleList();
497  tl_tmp = targetPts;
498  }
499 
500  tl_tmp->initialize( 3, 0, 0, 0, num_points );
501  tl_tmp->set_n( num_points ); // Automatically sets tl to write_enabled
502  // Initialize so we know afterwards how many pts weren't located
503  std::fill( tl_tmp->vi_wr, tl_tmp->vi_wr + 3 * num_points, -1 );
504 
505  unsigned int local_pts = 0;
506  for( unsigned int i = 0; i < source_pts.get_n(); i++ )
507  {
508  if( -1 != source_pts.vi_rd[3 * i + 2] )
509  { // Why bother sending message saying "i don't have the point" if it gets discarded?
510  int tgt_index = 3 * source_pts.vi_rd[3 * i + 1];
511  // Prefer always entities that are local, from the source_pts
512  // if a local entity was already found to contain the target point, skip
513  // tl_tmp->vi_wr[tgt_index] is -1 initially, but it could already be set with
514  // a remote processor
515  if( tl_tmp->vi_wr[tgt_index] != (int)my_rank )
516  {
517  tl_tmp->vi_wr[tgt_index] = source_pts.vi_rd[3 * i];
518  tl_tmp->vi_wr[tgt_index + 1] = source_pts.vi_rd[3 * i + 1];
519  tl_tmp->vi_wr[tgt_index + 2] = source_pts.vi_rd[3 * i + 2];
520  }
521  }
522  }
523 
524  // Count missing points
525  unsigned int missing_pts = 0;
526  for( unsigned int i = 0; i < num_points; i++ )
527  {
528  if( tl_tmp->vi_rd[3 * i + 1] == -1 )
529  {
530  missing_pts++;
531 #ifdef VERBOSE
532  printf( "missing point at index i: %d -> %15.10f %15.10f %15.10f\n", i, xyz[3 * i], xyz[3 * i + 1],
533  xyz[3 * i + 2] );
534 #endif
535  }
536  else if( tl_tmp->vi_rd[3 * i] == (int)my_rank )
537  local_pts++;
538  }
539 #ifdef VERBOSE
540  printf( "rank: %u point location: wanted %u got %u locally, %u remote, missing %u\n", my_rank, num_points,
541  local_pts, num_points - missing_pts - local_pts, missing_pts );
542 #endif
543  assert( 0 == missing_pts ); // Will likely break on curved geometries
544 
545  // No longer need source_pts
546  source_pts.reset();
547 
548  // Copy into tl if passed in and storing locally
549  if( tl && store_local )
550  {
551  tl->initialize( 3, 0, 0, 0, num_points );
552  tl->enableWriteAccess();
553  memcpy( tl->vi_wr, tl_tmp->vi_rd, 3 * tl_tmp->get_n() * sizeof( int ) );
554  tl->set_n( tl_tmp->get_n() );
555  tl->disableWriteAccess();
556  }
557 
558  tl_tmp->disableWriteAccess();
559 
560  // Done
561  return MB_SUCCESS;
562 }
563 
565  int from_proc,
566  int remote_index,
567  int /*index*/,
568  bool& point_located,
569  double rel_eps,
570  double abs_eps,
571  TupleList* tl )
572 {
573  std::vector< EntityHandle > entities;
574  std::vector< CartVect > nat_coords;
575  bool canWrite = false;
576  if( tl )
577  {
578  canWrite = tl->get_writeEnabled();
579  if( !canWrite )
580  {
581  tl->enableWriteAccess();
582  canWrite = true;
583  }
584  }
585 
586  if( rel_eps && !abs_eps )
587  {
588  // Relative epsilon given, translate to absolute epsilon using box dimensions
589  BoundBox box;
591  abs_eps = rel_eps * box.diagonal_length();
592  }
593 
594  ErrorCode result = nat_param( xyz, entities, nat_coords, abs_eps );
595  if( MB_SUCCESS != result ) return result;
596 
597  // If we didn't find any ents and we're looking locally, nothing more to do
598  if( entities.empty() )
599  {
600  if( tl->get_n() == tl->get_max() ) tl->resize( std::max( 10.0, 1.5 * tl->get_max() ) );
601 
602  tl->vi_wr[3 * tl->get_n()] = from_proc;
603  tl->vi_wr[3 * tl->get_n() + 1] = remote_index;
604  tl->vi_wr[3 * tl->get_n() + 2] = -1;
605  tl->inc_n();
606 
607  point_located = false;
608  return MB_SUCCESS;
609  }
610 
611  // Grow if we know we'll exceed size
612  if( mappedPts->get_n() + entities.size() >= mappedPts->get_max() )
613  mappedPts->resize( std::max( 10.0, 1.5 * mappedPts->get_max() ) );
614 
615  std::vector< EntityHandle >::iterator eit = entities.begin();
616  std::vector< CartVect >::iterator ncit = nat_coords.begin();
617 
619  for( ; eit != entities.end(); ++eit, ++ncit )
620  {
621  // Store in tuple mappedPts
622  mappedPts->vr_wr[3 * mappedPts->get_n()] = ( *ncit )[0];
623  mappedPts->vr_wr[3 * mappedPts->get_n() + 1] = ( *ncit )[1];
624  mappedPts->vr_wr[3 * mappedPts->get_n() + 2] = ( *ncit )[2];
625  mappedPts->vul_wr[mappedPts->get_n()] = *eit;
626  mappedPts->inc_n();
627 
628  // Also store local point, mapped point indices
629  if( tl->get_n() == tl->get_max() ) tl->resize( std::max( 10.0, 1.5 * tl->get_max() ) );
630 
631  // Store in tuple source_pts
632  tl->vi_wr[3 * tl->get_n()] = from_proc;
633  tl->vi_wr[3 * tl->get_n() + 1] = remote_index;
634  tl->vi_wr[3 * tl->get_n() + 2] = mappedPts->get_n() - 1;
635  tl->inc_n();
636  }
637 
638  point_located = true;
639 
640  if( tl && !canWrite ) tl->disableWriteAccess();
641 
642  return MB_SUCCESS;
643 }
644 
646  const std::string& interp_tag,
647  double* interp_vals,
648  TupleList* tl,
649  bool normalize )
650 {
651  Tag tag;
652  ErrorCode result;
653  if( _spectralSource )
654  {
655  result = mbImpl->tag_get_handle( interp_tag.c_str(), _ntot, MB_TYPE_DOUBLE, tag );MB_CHK_SET_ERR( result, "Failed to get handle for interpolation tag \"" << interp_tag << "\"" );
656  }
657  else
658  {
659  result = mbImpl->tag_get_handle( interp_tag.c_str(), 1, MB_TYPE_DOUBLE, tag );MB_CHK_SET_ERR( result, "Failed to get handle for interpolation tag \"" << interp_tag << "\"" );
660  }
661 
662  return interpolate( method, tag, interp_vals, tl, normalize );
663 }
664 
666  Tag* tags,
667  int* points_per_method,
668  int num_methods,
669  double* interp_vals,
670  TupleList* tl,
671  bool /* normalize */ )
672 {
673  // if (!((LINEAR_FE == method) || (CONSTANT == method)))
674  // return MB_FAILURE;
675 
676  // remote pts first
677  TupleList* tl_tmp = ( tl ? tl : targetPts );
678 
679  ErrorCode result = MB_SUCCESS;
680 
681  unsigned int pts_total = 0;
682  for( int i = 0; i < num_methods; i++ )
683  pts_total += points_per_method[i];
684 
685  // If tl was passed in non-NULL, just have those points, otherwise have targetPts plus
686  // locally mapped pts
687  if( pts_total != tl_tmp->get_n() ) return MB_FAILURE;
688 
689  TupleList tinterp;
690  tinterp.initialize( 5, 0, 0, 1, tl_tmp->get_n() );
691  int t = 0;
692  tinterp.enableWriteAccess();
693  for( int i = 0; i < num_methods; i++ )
694  {
695  for( int j = 0; j < points_per_method[i]; j++ )
696  {
697  tinterp.vi_wr[5 * t] = tl_tmp->vi_rd[3 * t];
698  tinterp.vi_wr[5 * t + 1] = tl_tmp->vi_rd[3 * t + 1];
699  tinterp.vi_wr[5 * t + 2] = tl_tmp->vi_rd[3 * t + 2];
700  tinterp.vi_wr[5 * t + 3] = methods[i];
701  tinterp.vi_wr[5 * t + 4] = i;
702  tinterp.vr_wr[t] = 0.0;
703  tinterp.inc_n();
704  t++;
705  }
706  }
707 
708  // Scatter/gather interpolation points
709  if( myPc )
710  {
711  ( myPc->proc_config().crystal_router() )->gs_transfer( 1, tinterp, 0 );
712 
713  // Perform interpolation on local source mesh; put results into
714  // tinterp.vr_wr[i]
715 
717  for( unsigned int i = 0; i < tinterp.get_n(); i++ )
718  {
719  int mindex = tinterp.vi_rd[5 * i + 2];
720  Method method = (Method)tinterp.vi_rd[5 * i + 3];
721  Tag tag = tags[tinterp.vi_rd[5 * i + 4]];
722 
723  result = MB_FAILURE;
724  if( LINEAR_FE == method || QUADRATIC_FE == method || SPHERICAL == method )
725  {
726  result = interp_field( mappedPts->vul_rd[mindex], CartVect( mappedPts->vr_wr + 3 * mindex ), tag,
727  tinterp.vr_wr[i] );
728  }
729  else if( CONSTANT == method )
730  {
731  result = constant_interp( mappedPts->vul_rd[mindex], tag, tinterp.vr_wr[i] );
732  }
733 
734  if( MB_SUCCESS != result ) return result;
735  }
736 
737  // Scatter/gather interpolation data
738  myPc->proc_config().crystal_router()->gs_transfer( 1, tinterp, 0 );
739  }
740 
741  // Copy the interpolated field as a unit
742  for( unsigned int i = 0; i < tinterp.get_n(); i++ )
743  interp_vals[tinterp.vi_rd[5 * i + 1]] = tinterp.vr_rd[i];
744 
745  // Done
746  return MB_SUCCESS;
747 }
748 
750  std::vector< EntityHandle >& entities,
751  std::vector< CartVect >& nat_coords,
752  double epsilon )
753 {
754  if( !myTree ) return MB_FAILURE;
755 
756  AdaptiveKDTreeIter treeiter;
757  ErrorCode result = myTree->get_tree_iterator( localRoot, treeiter );
758  if( MB_SUCCESS != result )
759  {
760  std::cout << "Problems getting iterator" << std::endl;
761  return result;
762  }
763 
764  EntityHandle closest_leaf;
765  if( epsilon )
766  {
767  std::vector< double > dists;
768  std::vector< EntityHandle > leaves;
769 
770  // Two tolerances
771  result = myTree->distance_search( xyz, epsilon, leaves,
772  /*iter_tol*/ epsilon,
773  /*inside_tol*/ 10 * epsilon, &dists, NULL, &localRoot );
774  if( leaves.empty() )
775  // Not found returns success here, with empty list, just like case with no epsilon
776  return MB_SUCCESS;
777  // Get closest leaf
778  double min_dist = *dists.begin();
779  closest_leaf = *leaves.begin();
780  std::vector< EntityHandle >::iterator vit = leaves.begin() + 1;
781  std::vector< double >::iterator dit = dists.begin() + 1;
782  for( ; vit != leaves.end() && min_dist; ++vit, ++dit )
783  {
784  if( *dit < min_dist )
785  {
786  min_dist = *dit;
787  closest_leaf = *vit;
788  }
789  }
790  }
791  else
792  {
793  result = myTree->point_search( xyz, treeiter, 1.0e-10, 1.0e-6, NULL, &localRoot );
794  if( MB_ENTITY_NOT_FOUND == result ) // Point is outside of myTree's bounding box
795  return MB_SUCCESS;
796  else if( MB_SUCCESS != result )
797  {
798  std::cout << "Problems getting leaf \n";
799  return result;
800  }
801  closest_leaf = treeiter.handle();
802  }
803 
804  // Find natural coordinates of point in element(s) in that leaf
805  CartVect tmp_nat_coords;
806  Range range_leaf;
807  result = mbImpl->get_entities_by_dimension( closest_leaf, max_dim, range_leaf, false );
808  if( MB_SUCCESS != result ) std::cout << "Problem getting leaf in a range" << std::endl;
809 
810  // Loop over the range_leaf
811  for( Range::iterator iter = range_leaf.begin(); iter != range_leaf.end(); ++iter )
812  {
813  // Test to find out in which entity the point is
814  // Get the EntityType and create the appropriate Element::Map subtype
815  // If spectral, do not need coordinates, just the GL points
816  EntityType etype = mbImpl->type_from_handle( *iter );
817  if( NULL != this->_spectralSource && MBHEX == etype )
818  {
819  EntityHandle eh = *iter;
820  const double* xval;
821  const double* yval;
822  const double* zval;
823  ErrorCode rval = mbImpl->tag_get_by_ptr( _xm1Tag, &eh, 1, (const void**)&xval );
824  if( moab::MB_SUCCESS != rval )
825  {
826  std::cout << "Can't get xm1 values \n";
827  return MB_FAILURE;
828  }
829  rval = mbImpl->tag_get_by_ptr( _ym1Tag, &eh, 1, (const void**)&yval );
830  if( moab::MB_SUCCESS != rval )
831  {
832  std::cout << "Can't get ym1 values \n";
833  return MB_FAILURE;
834  }
835  rval = mbImpl->tag_get_by_ptr( _zm1Tag, &eh, 1, (const void**)&zval );
836  if( moab::MB_SUCCESS != rval )
837  {
838  std::cout << "Can't get zm1 values \n";
839  return MB_FAILURE;
840  }
842 
843  spcHex->set_gl_points( (double*)xval, (double*)yval, (double*)zval );
844  try
845  {
846  tmp_nat_coords = spcHex->ievaluate( CartVect( xyz ), epsilon ); // introduce
847  bool inside = spcHex->inside_nat_space( CartVect( tmp_nat_coords ), epsilon );
848  if( !inside )
849  {
850 #ifdef VERBOSE
851  std::cout << "point " << xyz[0] << " " << xyz[1] << " " << xyz[2]
852  << " is not converging inside hex " << mbImpl->id_from_handle( eh ) << "\n";
853 #endif
854  continue; // It is possible that the point is outside, so it will not converge
855  }
856  }
858  {
859  continue;
860  }
861  }
862  else
863  {
864  const EntityHandle* connect;
865  int num_connect;
866 
867  // Get connectivity
868  result = mbImpl->get_connectivity( *iter, connect, num_connect, true );
869  if( MB_SUCCESS != result ) return result;
870 
871  // Get coordinates of the vertices
872  std::vector< CartVect > coords_vert( num_connect );
873  result = mbImpl->get_coords( connect, num_connect, &( coords_vert[0][0] ) );
874  if( MB_SUCCESS != result )
875  {
876  std::cout << "Problems getting coordinates of vertices\n";
877  return result;
878  }
879  CartVect pos( xyz );
880  if( MBHEX == etype )
881  {
882  if( 8 == num_connect )
883  {
884  Element::LinearHex hexmap( coords_vert );
885  if( !hexmap.inside_box( pos, epsilon ) ) continue;
886  try
887  {
888  tmp_nat_coords = hexmap.ievaluate( pos, epsilon );
889  bool inside = hexmap.inside_nat_space( tmp_nat_coords, epsilon );
890  if( !inside ) continue;
891  }
893  {
894  continue;
895  }
896  }
897  else if( 27 == num_connect )
898  {
899  Element::QuadraticHex hexmap( coords_vert );
900  if( !hexmap.inside_box( pos, epsilon ) ) continue;
901  try
902  {
903  tmp_nat_coords = hexmap.ievaluate( pos, epsilon );
904  bool inside = hexmap.inside_nat_space( tmp_nat_coords, epsilon );
905  if( !inside ) continue;
906  }
908  {
909  continue;
910  }
911  }
912  else // TODO this case not treated yet, no interpolation
913  continue;
914  }
915  else if( MBTET == etype )
916  {
917  Element::LinearTet tetmap( coords_vert );
918  // This is just a linear solve; unless degenerate, will not except
919  tmp_nat_coords = tetmap.ievaluate( pos );
920  bool inside = tetmap.inside_nat_space( tmp_nat_coords, epsilon );
921  if( !inside ) continue;
922  }
923  else if( MBQUAD == etype && spherical )
924  {
925  Element::SphericalQuad sphermap( coords_vert );
926  /* skip box test, because it can filter out good elements with high curvature
927  * if (!sphermap.inside_box(pos, epsilon))
928  continue;*/
929  try
930  {
931  tmp_nat_coords = sphermap.ievaluate( pos, epsilon );
932  bool inside = sphermap.inside_nat_space( tmp_nat_coords, epsilon );
933  if( !inside ) continue;
934  }
936  {
937  continue;
938  }
939  }
940  else if( MBTRI == etype && spherical )
941  {
942  Element::SphericalTri sphermap( coords_vert );
943  /* skip box test, because it can filter out good elements with high curvature
944  * if (!sphermap.inside_box(pos, epsilon))
945  continue;*/
946  try
947  {
948  tmp_nat_coords = sphermap.ievaluate( pos, epsilon );
949  bool inside = sphermap.inside_nat_space( tmp_nat_coords, epsilon );
950  if( !inside ) continue;
951  }
953  {
954  continue;
955  }
956  }
957 
958  else if( MBQUAD == etype )
959  {
960  Element::LinearQuad quadmap( coords_vert );
961  if( !quadmap.inside_box( pos, epsilon ) ) continue;
962  try
963  {
964  tmp_nat_coords = quadmap.ievaluate( pos, epsilon );
965  bool inside = quadmap.inside_nat_space( tmp_nat_coords, epsilon );
966  if( !inside ) continue;
967  }
969  {
970  continue;
971  }
972  if( !quadmap.inside_nat_space( tmp_nat_coords, epsilon ) ) continue;
973  }
974  /*
975  else if (etype == MBTRI){
976  Element::LinearTri trimap(coords_vert);
977  if (!trimap.inside_box( pos, epsilon))
978  continue;
979  try {
980  tmp_nat_coords = trimap.ievaluate(pos, epsilon);
981  bool inside = trimap.inside_nat_space(tmp_nat_coords, epsilon);
982  if (!inside) continue;
983  }
984  catch (Element::Map::EvaluationError) {
985  continue;
986  }
987  if (!trimap.inside_nat_space(tmp_nat_coords, epsilon))
988  continue;
989  }
990  */
991  else if( etype == MBEDGE )
992  {
993  Element::LinearEdge edgemap( coords_vert );
994  try
995  {
996  tmp_nat_coords = edgemap.ievaluate( CartVect( xyz ), epsilon );
997  }
999  {
1000  continue;
1001  }
1002  if( !edgemap.inside_nat_space( tmp_nat_coords, epsilon ) ) continue;
1003  }
1004  else
1005  {
1006  std::cout << "Entity not Hex/Tet/Quad/Tri/Edge. Please verify." << std::endl;
1007  continue;
1008  }
1009  }
1010  // If we get here then we've found the coordinates.
1011  // Save them and the entity and return success.
1012  entities.push_back( *iter );
1013  nat_coords.push_back( tmp_nat_coords );
1014  return MB_SUCCESS;
1015  }
1016 
1017  // Didn't find any elements containing the point
1018  return MB_SUCCESS;
1019 }
1020 
1021 ErrorCode Coupler::interp_field( EntityHandle elem, CartVect nat_coord, Tag tag, double& field )
1022 {
1023  if( _spectralSource )
1024  {
1025  // Get tag values at the GL points for some field (Tag)
1026  const double* vx;
1027  ErrorCode rval = mbImpl->tag_get_by_ptr( tag, &elem, 1, (const void**)&vx );
1028  if( moab::MB_SUCCESS != rval )
1029  {
1030  std::cout << "Can't get field values for the tag \n";
1031  return MB_FAILURE;
1032  }
1034  field = spcHex->evaluate_scalar_field( nat_coord, vx );
1035  }
1036  else
1037  {
1038  double vfields[27]; // Will work for linear hex, quadratic hex or Tets
1039  moab::Element::Map* elemMap = NULL;
1040  int num_verts = 0;
1041  // Get the EntityType
1042  // Get the tag values at the vertices
1043  const EntityHandle* connect;
1044  int num_connect;
1045  ErrorCode result = mbImpl->get_connectivity( elem, connect, num_connect );
1046  if( MB_SUCCESS != result ) return result;
1047  EntityType etype = mbImpl->type_from_handle( elem );
1048  if( MBHEX == etype )
1049  {
1050  if( 8 == num_connect )
1051  {
1052  elemMap = new moab::Element::LinearHex();
1053  num_verts = 8;
1054  }
1055  else
1056  { /* (MBHEX == etype && 27 == num_connect) */
1057  elemMap = new moab::Element::QuadraticHex();
1058  num_verts = 27;
1059  }
1060  }
1061  else if( MBTET == etype )
1062  {
1063  elemMap = new moab::Element::LinearTet();
1064  num_verts = 4;
1065  }
1066  else if( MBQUAD == etype )
1067  {
1068  elemMap = new moab::Element::LinearQuad();
1069  num_verts = 4;
1070  }
1071  else if( MBTRI == etype )
1072  {
1073  elemMap = new moab::Element::LinearTri();
1074  num_verts = 3;
1075  }
1076  else
1077  return MB_FAILURE;
1078 
1079  result = mbImpl->tag_get_data( tag, connect, std::min( num_verts, num_connect ), vfields );
1080  if( MB_SUCCESS != result )
1081  {
1082  delete elemMap;
1083  return result;
1084  }
1085 
1086  // Function for the interpolation
1087  field = 0;
1088 
1089  // Check the number of vertices
1090  assert( num_connect >= num_verts );
1091 
1092  // Calculate the field
1093  try
1094  {
1095  field = elemMap->evaluate_scalar_field( nat_coord, vfields );
1096  }
1098  {
1099  delete elemMap;
1100  return MB_FAILURE;
1101  }
1102 
1103  delete elemMap;
1104  }
1105 
1106  return MB_SUCCESS;
1107 }
1108 
1109 // Simplest "interpolation" for element-based source fields. Set the value of the field
1110 // at the target point to that of the field in the source element it lies in.
1112 {
1113  double tempField;
1114 
1115  // Get the tag values at the vertices
1116  ErrorCode result = mbImpl->tag_get_data( tag, &elem, 1, &tempField );
1117  if( MB_SUCCESS != result ) return result;
1118 
1119  field = tempField;
1120 
1121  return MB_SUCCESS;
1122 }
1123 
1124 // Normalize a field over the entire mesh represented by the root_set.
1126  const char* norm_tag,
1127  Coupler::IntegType integ_type,
1128  int num_integ_pts )
1129 {
1130  ErrorCode err;
1131 
1132  // SLAVE START ****************************************************************
1133  // Search for entities based on tag_handles and tag_values
1134  std::vector< std::vector< EntityHandle > > entity_sets;
1135  std::vector< std::vector< EntityHandle > > entity_groups;
1136 
1137  // put the root_set into entity_sets
1138  std::vector< EntityHandle > ent_set;
1139  ent_set.push_back( root_set );
1140  entity_sets.push_back( ent_set );
1141 
1142  // get all entities from root_set and put into entity_groups
1143  std::vector< EntityHandle > entities;
1144  err = mbImpl->get_entities_by_handle( root_set, entities, true );ERRORR( "Failed to get entities in root_set.", err );
1145 
1146  entity_groups.push_back( entities );
1147 
1148  // Call do_normalization() to continue common normalization processing
1149  err = do_normalization( norm_tag, entity_sets, entity_groups, integ_type, num_integ_pts );ERRORR( "Failure in do_normalization().", err );
1150  // SLAVE END ****************************************************************
1151 
1152  return err;
1153 }
1154 
1155 // Normalize a field over the subset of entities identified by the tags and values passed
1157  const char* norm_tag,
1158  const char** tag_names,
1159  int num_tags,
1160  const char** tag_values,
1161  Coupler::IntegType integ_type,
1162  int num_integ_pts )
1163 {
1164  moab::ErrorCode err;
1165  std::vector< Tag > tag_handles;
1166 
1167  // Lookup tag handles from tag names
1168  for( int t = 0; t < num_tags; t++ )
1169  {
1170  // get tag handle & size
1171  Tag th;
1172  err = mbImpl->tag_get_handle( tag_names[t], 1, moab::MB_TYPE_DOUBLE, th, moab::MB_TAG_ANY );ERRORR( "Failed to get tag handle.", err );
1173  tag_handles.push_back( th );
1174  }
1175 
1176  return normalize_subset( root_set, norm_tag, &tag_handles[0], num_tags, tag_values, integ_type, num_integ_pts );
1177 }
1178 
1180  const char* norm_tag,
1181  Tag* tag_handles,
1182  int num_tags,
1183  const char** tag_values,
1184  Coupler::IntegType integ_type,
1185  int num_integ_pts )
1186 {
1187  ErrorCode err;
1188 
1189  // SLAVE START ****************************************************************
1190  // Search for entities based on tag_handles and tag_values
1191  std::vector< std::vector< EntityHandle > > entity_sets;
1192  std::vector< std::vector< EntityHandle > > entity_groups;
1193 
1194  err = get_matching_entities( root_set, tag_handles, tag_values, num_tags, &entity_sets, &entity_groups );ERRORR( "Failed to get matching entities.", err );
1195 
1196  // Call do_normalization() to continue common normalization processing
1197  err = do_normalization( norm_tag, entity_sets, entity_groups, integ_type, num_integ_pts );ERRORR( "Failure in do_normalization().", err );
1198  // SLAVE END ****************************************************************
1199 
1200  return err;
1201 }
1202 
1203 ErrorCode Coupler::do_normalization( const char* norm_tag,
1204  std::vector< std::vector< EntityHandle > >& entity_sets,
1205  std::vector< std::vector< EntityHandle > >& entity_groups,
1206  Coupler::IntegType integ_type,
1207  int num_integ_pts )
1208 {
1209  // SLAVE START ****************************************************************
1210  ErrorCode err;
1211  int ierr = 0;
1212 
1213  // Setup data for parallel computing
1214  int nprocs, rank;
1215  ierr = MPI_Comm_size( MPI_COMM_WORLD, &nprocs );
1216  ERRORMPI( "Getting number of procs failed.", ierr );
1217  ierr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1218  ERRORMPI( "Getting rank failed.", ierr );
1219 
1220  // Get the integrated field value for each group(vector) of entities.
1221  // If no entities are in a group then a zero will be put in the list
1222  // of return values.
1223  unsigned int num_ent_grps = entity_groups.size();
1224  std::vector< double > integ_vals( num_ent_grps );
1225 
1226  err = get_group_integ_vals( entity_groups, integ_vals, norm_tag, num_integ_pts, integ_type );ERRORR( "Failed to get integrated field values for groups in mesh.", err );
1227  // SLAVE END ****************************************************************
1228 
1229  // SLAVE/MASTER START #########################################################
1230  // Send list of integrated values back to master proc. The ordering of the
1231  // values will match the ordering of the entity groups (i.e. vector of vectors)
1232  // sent from master to slaves earlier. The values for each entity group will
1233  // be summed during the transfer.
1234  std::vector< double > sum_integ_vals( num_ent_grps );
1235 
1236  if( nprocs > 1 )
1237  {
1238  // If parallel then send the values back to the master.
1239  ierr = MPI_Reduce( &integ_vals[0], &sum_integ_vals[0], num_ent_grps, MPI_DOUBLE, MPI_SUM, MASTER_PROC,
1240  myPc->proc_config().proc_comm() );
1241  ERRORMPI( "Transfer and reduction of integrated values failed.", ierr );
1242  }
1243  else
1244  {
1245  // Otherwise just copy the vector
1246  sum_integ_vals = integ_vals;
1247  }
1248  // SLAVE/MASTER END #########################################################
1249 
1250  // MASTER START ***************************************************************
1251  // Calculate the normalization factor for each group by taking the
1252  // inverse of each integrated field value. Put the normalization factor
1253  // for each group back into the list in the same order.
1254  for( unsigned int i = 0; i < num_ent_grps; i++ )
1255  {
1256  double val = sum_integ_vals[i];
1257  if( fabs( val ) > 1e-8 )
1258  sum_integ_vals[i] = 1.0 / val;
1259  else
1260  {
1261  sum_integ_vals[i] = 0.0; /* VSM: not sure what we should do here ? */
1262  /* commenting out error below since if integral(value)=0.0, then normalization
1263  is probably unnecessary to start with ? */
1264  /* ERRORR("Integrating an invalid field -- integral("<<norm_tag<<") = "<<val<<".", err);
1265  */
1266  }
1267  }
1268  // MASTER END ***************************************************************
1269 
1270  // MASTER/SLAVE START #########################################################
1271  if( nprocs > 1 )
1272  {
1273  // If parallel then broadcast the normalization factors to the procs.
1274  ierr = MPI_Bcast( &sum_integ_vals[0], num_ent_grps, MPI_DOUBLE, MASTER_PROC, myPc->proc_config().proc_comm() );
1275  ERRORMPI( "Broadcast of normalization factors failed.", ierr );
1276  }
1277  // MASTER/SLAVE END #########################################################
1278 
1279  // SLAVE START ****************************************************************
1280  // Save the normalization factors to a new tag with name of norm_tag's value
1281  // and the string "_normF" appended. This new tag will be created on the entity
1282  // set that contains all of the entities from a group.
1283 
1284  err = apply_group_norm_factor( entity_sets, sum_integ_vals, norm_tag, integ_type );ERRORR( "Failed to set the normalization factor for groups in mesh.", err );
1285  // SLAVE END ****************************************************************
1286 
1287  return err;
1288 }
1289 
1290 // Functions supporting the subset normalization function
1291 
1292 // Retrieve groups of entities matching tags and values if present
1294  const char** tag_names,
1295  const char** tag_values,
1296  int num_tags,
1297  std::vector< std::vector< EntityHandle > >* entity_sets,
1298  std::vector< std::vector< EntityHandle > >* entity_groups )
1299 {
1300  ErrorCode err;
1301  std::vector< Tag > tag_handles;
1302 
1303  for( int t = 0; t < num_tags; t++ )
1304  {
1305  // Get tag handle & size
1306  Tag th;
1307  err = mbImpl->tag_get_handle( tag_names[t], 1, moab::MB_TYPE_DOUBLE, th, moab::MB_TAG_ANY );ERRORR( "Failed to get tag handle.", err );
1308  tag_handles.push_back( th );
1309  }
1310 
1311  return get_matching_entities( root_set, &tag_handles[0], tag_values, num_tags, entity_sets, entity_groups );
1312 }
1313 
1314 // Retrieve groups of entities matching tags and values if present
1316  Tag* tag_handles,
1317  const char** tag_values,
1318  int num_tags,
1319  std::vector< std::vector< EntityHandle > >* entity_sets,
1320  std::vector< std::vector< EntityHandle > >* entity_groups )
1321 {
1322  // SLAVE START ****************************************************************
1323 
1324  // Setup data for parallel computing
1325  ErrorCode err;
1326  int ierr = 0;
1327  int nprocs, rank;
1328  ierr = MPI_Comm_size( MPI_COMM_WORLD, &nprocs );
1329  ERRORMPI( "Getting number of procs failed.", ierr );
1330  ierr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
1331  ERRORMPI( "Getting rank failed.", ierr );
1332 
1333  Range ent_sets;
1334  err =
1335  mbImpl->get_entities_by_type_and_tag( root_set, moab::MBENTITYSET, tag_handles, (const void* const*)tag_values,
1336  num_tags, ent_sets, Interface::INTERSECT, false );ERRORR( "Core::get_entities_by_type_and_tag failed.", err );
1337 
1338  TupleList* tag_list = NULL;
1339  err = create_tuples( ent_sets, tag_handles, num_tags, &tag_list );ERRORR( "Failed to create tuples from entity sets.", err );
1340 
1341  // Free up range
1342  ent_sets.clear();
1343  // SLAVE END ****************************************************************
1344 
1345  // If we are running in a multi-proc session then send tuple list back to master
1346  // proc for consolidation. Otherwise just copy the pointer to the tuple_list.
1347  TupleList* cons_tuples;
1348  if( nprocs > 1 )
1349  {
1350  // SLAVE/MASTER START #########################################################
1351 
1352  // Pack the tuple_list in a buffer.
1353  uint* tuple_buf;
1354  int tuple_buf_len;
1355  tuple_buf_len = pack_tuples( tag_list, (void**)&tuple_buf );
1356 
1357  // Free tag_list here as its not used again if nprocs > 1
1358  tag_list->reset();
1359 
1360  // Send back the buffer sizes to the master proc
1361  int* recv_cnts = (int*)malloc( nprocs * sizeof( int ) );
1362  int* offsets = (int*)malloc( nprocs * sizeof( int ) );
1363  uint* all_tuples_buf = NULL;
1364 
1365  MPI_Gather( &tuple_buf_len, 1, MPI_INT, recv_cnts, 1, MPI_INT, MASTER_PROC, myPc->proc_config().proc_comm() );
1366  ERRORMPI( "Gathering buffer sizes failed.", err );
1367 
1368  // Allocate a buffer large enough for all the data
1369  if( rank == MASTER_PROC )
1370  {
1371  int all_tuples_len = recv_cnts[0];
1372  offsets[0] = 0;
1373  for( int i = 1; i < nprocs; i++ )
1374  {
1375  offsets[i] = offsets[i - 1] + recv_cnts[i - 1];
1376  all_tuples_len += recv_cnts[i];
1377  }
1378 
1379  all_tuples_buf = (uint*)malloc( all_tuples_len * sizeof( uint ) );
1380  }
1381 
1382  // Send all buffers to the master proc for consolidation
1383  MPI_Gatherv( (void*)tuple_buf, tuple_buf_len, MPI_INT, (void*)all_tuples_buf, recv_cnts, offsets, MPI_INT,
1385  ERRORMPI( "Gathering tuple_lists failed.", err );
1386  free( tuple_buf ); // malloc'd in pack_tuples
1387 
1388  if( rank == MASTER_PROC )
1389  {
1390  // Unpack the tuple_list from the buffer.
1391  TupleList** tl_array = (TupleList**)malloc( nprocs * sizeof( TupleList* ) );
1392  for( int i = 0; i < nprocs; i++ )
1393  unpack_tuples( (void*)&all_tuples_buf[offsets[i]], &tl_array[i] );
1394 
1395  // Free all_tuples_buf here as it is only allocated on the MASTER_PROC
1396  free( all_tuples_buf );
1397  // SLAVE/MASTER END #########################################################
1398 
1399  // MASTER START ***************************************************************
1400  // Consolidate all tuple_lists into one tuple_list with no duplicates.
1401  err = consolidate_tuples( tl_array, nprocs, &cons_tuples );ERRORR( "Failed to consolidate tuples.", err );
1402 
1403  for( int i = 0; i < nprocs; i++ )
1404  tl_array[i]->reset();
1405  free( tl_array );
1406  // MASTER END ***************************************************************
1407  }
1408 
1409  // Free offsets and recv_cnts as they are allocated on all procs
1410  free( offsets );
1411  free( recv_cnts );
1412 
1413  // MASTER/SLAVE START #########################################################
1414  // Broadcast condensed tuple list back to all procs.
1415  uint* ctl_buf;
1416  int ctl_buf_sz;
1417  if( rank == MASTER_PROC ) ctl_buf_sz = pack_tuples( cons_tuples, (void**)&ctl_buf );
1418 
1419  // Send buffer size
1420  ierr = MPI_Bcast( &ctl_buf_sz, 1, MPI_INT, MASTER_PROC, myPc->proc_config().proc_comm() );
1421  ERRORMPI( "Broadcasting tuple_list size failed.", ierr );
1422 
1423  // Allocate a buffer in the other procs
1424  if( rank != MASTER_PROC ) ctl_buf = (uint*)malloc( ctl_buf_sz * sizeof( uint ) );
1425 
1426  ierr = MPI_Bcast( (void*)ctl_buf, ctl_buf_sz, MPI_INT, MASTER_PROC, myPc->proc_config().proc_comm() );
1427  ERRORMPI( "Broadcasting tuple_list failed.", ierr );
1428 
1429  if( rank != MASTER_PROC ) unpack_tuples( ctl_buf, &cons_tuples );
1430  free( ctl_buf );
1431  // MASTER/SLAVE END #########################################################
1432  }
1433  else
1434  cons_tuples = tag_list;
1435 
1436  // SLAVE START ****************************************************************
1437  // Loop over the tuple list getting the entities with the tags in the tuple_list entry
1438  uint mi, ml, mul, mr;
1439  cons_tuples->getTupleSize( mi, ml, mul, mr );
1440 
1441  for( unsigned int i = 0; i < cons_tuples->get_n(); i++ )
1442  {
1443  // Get Entity Sets that match the tags and values.
1444 
1445  // Convert the data in the tuple_list to an array of pointers to the data
1446  // in the tuple_list as that is what the iMesh API call is expecting.
1447  int** vals = (int**)malloc( mi * sizeof( int* ) );
1448  for( unsigned int j = 0; j < mi; j++ )
1449  vals[j] = (int*)&( cons_tuples->vi_rd[( i * mi ) + j] );
1450 
1451  // Get entities recursively based on type and tag data
1452  err = mbImpl->get_entities_by_type_and_tag( root_set, moab::MBENTITYSET, tag_handles, (const void* const*)vals,
1453  mi, ent_sets, Interface::INTERSECT, false );ERRORR( "Core::get_entities_by_type_and_tag failed.", err );
1454  if( debug ) std::cout << "ent_sets_size=" << ent_sets.size() << std::endl;
1455 
1456  // Free up the array of pointers
1457  free( vals );
1458 
1459  // Loop over the entity sets and then free the memory for ent_sets.
1460  std::vector< EntityHandle > ent_set_hdls;
1461  std::vector< EntityHandle > ent_hdls;
1462  for( unsigned int j = 0; j < ent_sets.size(); j++ )
1463  {
1464  // Save the entity set
1465  ent_set_hdls.push_back( ent_sets[j] );
1466 
1467  // Get all entities for the entity set
1468  Range ents;
1469 
1470  /* VSM: do we need to filter out entity sets ? */
1471  err = mbImpl->get_entities_by_handle( ent_sets[j], ents, false );ERRORR( "Core::get_entities_by_handle failed.", err );
1472  if( debug ) std::cout << "ents_size=" << ents.size() << std::endl;
1473 
1474  // Save all of the entities from the entity set and free the memory for ents.
1475  for( unsigned int k = 0; k < ents.size(); k++ )
1476  {
1477  ent_hdls.push_back( ents[k] );
1478  }
1479  ents.clear();
1480  if( debug ) std::cout << "ent_hdls.size=" << ent_hdls.size() << std::endl;
1481  }
1482 
1483  // Free the entity set list for next tuple iteration.
1484  ent_sets.clear();
1485 
1486  // Push ent_set_hdls onto entity_sets, ent_hdls onto entity_groups
1487  // and clear both ent_set_hdls and ent_hdls.
1488  entity_sets->push_back( ent_set_hdls );
1489  ent_set_hdls.clear();
1490  entity_groups->push_back( ent_hdls );
1491  ent_hdls.clear();
1492  if( debug )
1493  std::cout << "entity_sets->size=" << entity_sets->size()
1494  << ", entity_groups->size=" << entity_groups->size() << std::endl;
1495  }
1496 
1497  cons_tuples->reset();
1498  // SLAVE END ****************************************************************
1499 
1500  return err;
1501 }
1502 
1503 // Return a tuple_list containing tag values for each Entity Set
1504 // The tuple_list will have a column for each tag and a row for each
1505 // Entity Set. It is assumed all of the tags are integer tags.
1507  const char** tag_names,
1508  unsigned int num_tags,
1509  TupleList** tuple_list )
1510 {
1511  ErrorCode err;
1512  std::vector< Tag > tag_handles;
1513 
1514  for( unsigned int t = 0; t < num_tags; t++ )
1515  {
1516  // Get tag handle & size
1517  Tag th;
1518  err = mbImpl->tag_get_handle( tag_names[t], 1, moab::MB_TYPE_DOUBLE, th, moab::MB_TAG_ANY );ERRORR( "Failed to get tag handle.", err );
1519  tag_handles.push_back( th );
1520  }
1521 
1522  return create_tuples( ent_sets, &tag_handles[0], num_tags, tuple_list );
1523 }
1524 
1525 // Return a tuple_list containing tag values for each Entity Set
1526 // The tuple_list will have a column for each tag and a row for each
1527 // Entity Set. It is assumed all of the tags are integer tags.
1528 ErrorCode Coupler::create_tuples( Range& ent_sets, Tag* tag_handles, unsigned int num_tags, TupleList** tuples )
1529 {
1530  // ASSUMPTION: All tags are of type integer. This may need to be expanded in future.
1531  ErrorCode err;
1532 
1533  // Allocate a tuple_list for the number of entity sets passed in
1534  TupleList* tag_tuples = new TupleList( num_tags, 0, 0, 0, (int)ent_sets.size() );
1535  // tag_tuples->initialize(num_tags, 0, 0, 0, num_sets);
1536  uint mi, ml, mul, mr;
1537  tag_tuples->getTupleSize( mi, ml, mul, mr );
1538  tag_tuples->enableWriteAccess();
1539 
1540  if( mi == 0 ) ERRORR( "Failed to initialize tuple_list.", MB_FAILURE );
1541 
1542  // Loop over the filtered entity sets retrieving each matching tag value one by one.
1543  int val;
1544  for( unsigned int i = 0; i < ent_sets.size(); i++ )
1545  {
1546  for( unsigned int j = 0; j < num_tags; j++ )
1547  {
1548  EntityHandle set_handle = ent_sets[i];
1549  err = mbImpl->tag_get_data( tag_handles[j], &set_handle, 1, &val );ERRORR( "Failed to get integer tag data.", err );
1550  tag_tuples->vi_wr[i * mi + j] = val;
1551  }
1552 
1553  // If we get here there was no error so increment n in the tuple_list
1554  tag_tuples->inc_n();
1555  }
1556  tag_tuples->disableWriteAccess();
1557  *tuples = tag_tuples;
1558 
1559  return MB_SUCCESS;
1560 }
1561 
1562 // Consolidate tuple_lists into one list with no duplicates
1563 ErrorCode Coupler::consolidate_tuples( TupleList** all_tuples, unsigned int num_tuples, TupleList** unique_tuples )
1564 {
1565  int total_rcv_tuples = 0;
1566  int offset = 0, copysz = 0;
1567  unsigned num_tags = 0;
1568 
1569  uint ml, mul, mr;
1570  uint* mi = (uint*)malloc( sizeof( uint ) * num_tuples );
1571 
1572  for( unsigned int i = 0; i < num_tuples; i++ )
1573  {
1574  all_tuples[i]->getTupleSize( mi[i], ml, mul, mr );
1575  }
1576 
1577  for( unsigned int i = 0; i < num_tuples; i++ )
1578  {
1579  if( all_tuples[i] != NULL )
1580  {
1581  total_rcv_tuples += all_tuples[i]->get_n();
1582  num_tags = mi[i];
1583  }
1584  }
1585  const unsigned int_size = sizeof( sint );
1586  const unsigned int_width = num_tags * int_size;
1587 
1588  // Get the total size of all of the tuple_lists in all_tuples.
1589  for( unsigned int i = 0; i < num_tuples; i++ )
1590  {
1591  if( all_tuples[i] != NULL ) total_rcv_tuples += all_tuples[i]->get_n();
1592  }
1593 
1594  // Copy the tuple_lists into a single tuple_list.
1595  TupleList* all_tuples_list = new TupleList( num_tags, 0, 0, 0, total_rcv_tuples );
1596  all_tuples_list->enableWriteAccess();
1597  // all_tuples_list->initialize(num_tags, 0, 0, 0, total_rcv_tuples);
1598  for( unsigned int i = 0; i < num_tuples; i++ )
1599  {
1600  if( all_tuples[i] != NULL )
1601  {
1602  copysz = all_tuples[i]->get_n() * int_width;
1603  memcpy( all_tuples_list->vi_wr + offset, all_tuples[i]->vi_rd, copysz );
1604  offset = offset + ( all_tuples[i]->get_n() * mi[i] );
1605  all_tuples_list->set_n( all_tuples_list->get_n() + all_tuples[i]->get_n() );
1606  }
1607  }
1608 
1609  // Sort the new tuple_list. Use a radix type sort, starting with the last (or least significant)
1610  // tag column in the vi array and working towards the first (or most significant) tag column.
1611  TupleList::buffer sort_buffer;
1612  sort_buffer.buffer_init( 2 * total_rcv_tuples * int_width );
1613  for( int i = num_tags - 1; i >= 0; i-- )
1614  {
1615  all_tuples_list->sort( i, &sort_buffer );
1616  }
1617 
1618  // Cycle through the sorted list eliminating duplicates.
1619  // Keep counters to the current end of the tuple_list (w/out dups) and the last tuple examined.
1620  unsigned int end_idx = 0, last_idx = 1;
1621  while( last_idx < all_tuples_list->get_n() )
1622  {
1623  if( memcmp( all_tuples_list->vi_rd + ( end_idx * num_tags ), all_tuples_list->vi_rd + ( last_idx * num_tags ),
1624  int_width ) == 0 )
1625  {
1626  // Values equal - skip
1627  last_idx += 1;
1628  }
1629  else
1630  {
1631  // Values different - copy
1632  // Move up the end index
1633  end_idx += 1;
1634  memcpy( all_tuples_list->vi_wr + ( end_idx * num_tags ), all_tuples_list->vi_rd + ( last_idx * num_tags ),
1635  int_width );
1636  last_idx += 1;
1637  }
1638  }
1639  // Update the count in all_tuples_list
1640  all_tuples_list->set_n( end_idx + 1 );
1641 
1642  // Resize the tuple_list
1643  all_tuples_list->resize( all_tuples_list->get_n() );
1644 
1645  // Set the output parameter
1646  *unique_tuples = all_tuples_list;
1647 
1648  return MB_SUCCESS;
1649 }
1650 
1651 // Calculate integrated field values for groups of entities
1652 ErrorCode Coupler::get_group_integ_vals( std::vector< std::vector< EntityHandle > >& groups,
1653  std::vector< double >& integ_vals,
1654  const char* norm_tag,
1655  int /*num_integ_vals*/,
1656  Coupler::IntegType integ_type )
1657 {
1658  ErrorCode err;
1659 
1660  std::vector< std::vector< EntityHandle > >::iterator iter_i;
1661  std::vector< EntityHandle >::iterator iter_j;
1662  double grp_intrgr_val, intgr_val;
1663 
1664  // Get the tag handle for norm_tag
1665  Tag norm_hdl;
1666  err =
1667  mbImpl->tag_get_handle( norm_tag, 1, moab::MB_TYPE_DOUBLE, norm_hdl, moab::MB_TAG_SPARSE | moab::MB_TAG_CREAT );ERRORR( "Failed to get norm_tag handle.", err );
1668 
1669  // Check size of integ_vals vector
1670  if( integ_vals.size() != groups.size() ) integ_vals.resize( groups.size() );
1671 
1672  // Loop over the groups(vectors) of entities
1673  unsigned int i;
1674  for( i = 0, iter_i = groups.begin(); iter_i != groups.end(); i++, ++iter_i )
1675  {
1676  grp_intrgr_val = 0;
1677 
1678  // Loop over the all the entities in the group, integrating
1679  // the field_fn over the entity in iter_j
1680  for( iter_j = ( *iter_i ).begin(); iter_j != ( *iter_i ).end(); ++iter_j )
1681  {
1682  EntityHandle ehandle = ( *iter_j );
1683 
1684  // Check that the entity in iter_j is of the same dimension as the
1685  // integ_type we are performing
1686  EntityType j_type;
1687  j_type = mbImpl->type_from_handle( ehandle );ERRORR( "Failed to get entity type.", err );
1688  // Skip any entities in the group that are not of the type being considered
1689  if( ( integ_type == VOLUME ) && ( j_type < MBTET || j_type >= MBENTITYSET ) ) continue;
1690 
1691  intgr_val = 0;
1692 
1693  // Retrieve the vertices from the element
1694  const EntityHandle* verts = NULL;
1695  int connectivity_size = 0;
1696 
1697  err = mbImpl->get_connectivity( ehandle, verts, connectivity_size, false );ERRORR( "Failed to get vertices from entity.", err );
1698 
1699  // Get the vertex coordinates and the field values at the vertices.
1700  double* coords = (double*)malloc( sizeof( double ) * ( 3 * connectivity_size ) );
1701  /* TODO: VSM: check if this works for lower dimensions also without problems */
1702  /* if (3 == geom_dim) */
1703  err = mbImpl->get_coords( verts, connectivity_size, coords );ERRORR( "Failed to get vertex coordinates.", err );
1704 
1705  /* allocate the field data array */
1706  double* vfield = (double*)malloc( sizeof( double ) * ( connectivity_size ) );
1707  err = mbImpl->tag_get_data( norm_hdl, verts, connectivity_size, vfield );
1708  if( MB_SUCCESS != err )
1709  {
1710  free( coords );
1711  }
1712  ERRORR( "Failed to get vertex coordinates.", err );
1713 
1714  // Get coordinates of all corner vertices (in normal order) and
1715  // put in array of CartVec.
1716  std::vector< CartVect > vertices( connectivity_size );
1717 
1718  // Put the vertices into a CartVect vector
1719  double* x = coords;
1720  for( int j = 0; j < connectivity_size; j++, x += 3 )
1721  {
1722  vertices[j] = CartVect( x );
1723  }
1724  free( coords );
1725 
1726  moab::Element::Map* elemMap;
1727  if( j_type == MBHEX )
1728  {
1729  if( connectivity_size == 8 )
1730  elemMap = new moab::Element::LinearHex( vertices );
1731  else
1732  elemMap = new moab::Element::QuadraticHex( vertices );
1733  }
1734  else if( j_type == MBTET )
1735  {
1736  elemMap = new moab::Element::LinearTet( vertices );
1737  }
1738  else if( j_type == MBQUAD )
1739  {
1740  elemMap = new moab::Element::LinearQuad( vertices );
1741  }
1742  /*
1743  else if (j_type == MBTRI) {
1744  elemMap = new moab::Element::LinearTri(vertices);
1745  }
1746  */
1747  else if( j_type == MBEDGE )
1748  {
1749  elemMap = new moab::Element::LinearEdge( vertices );
1750  }
1751  else
1752  ERRORR( "Unknown topology type.", MB_UNSUPPORTED_OPERATION );
1753 
1754  // Set the vertices in the Map and perform the integration
1755  try
1756  {
1757  /* VSM: Do we need this call ?? */
1758  // elemMap->set_vertices(vertices);
1759 
1760  // Perform the actual integration over the element
1761  intgr_val = elemMap->integrate_scalar_field( vfield );
1762 
1763  // Combine the result with those of the group
1764  grp_intrgr_val += intgr_val;
1765  }
1767  {
1768  std::cerr << "Failed to set vertices on Element::Map." << std::endl;
1769  }
1771  {
1772  std::cerr << "Failed to get inverse evaluation of coordinate on Element::Map." << std::endl;
1773  }
1774 
1775  delete( elemMap );
1776  free( vfield );
1777  }
1778 
1779  // Set the group integrated value in the vector
1780  integ_vals[i] = grp_intrgr_val;
1781  }
1782 
1783  return err;
1784 }
1785 
1786 // Apply a normalization factor to group of entities
1787 ErrorCode Coupler::apply_group_norm_factor( std::vector< std::vector< EntityHandle > >& entity_sets,
1788  std::vector< double >& norm_factors,
1789  const char* norm_tag,
1790  Coupler::IntegType /*integ_type*/ )
1791 {
1792  ErrorCode err;
1793 
1794  // Construct the new tag for the normalization factor from the norm_tag name
1795  // and "_normf".
1796  int norm_tag_len = strlen( norm_tag );
1797  const char* normf_appd = "_normf";
1798  int normf_appd_len = strlen( normf_appd );
1799 
1800  char* normf_tag = (char*)malloc( norm_tag_len + normf_appd_len + 1 );
1801  char* tmp_ptr = normf_tag;
1802 
1803  memcpy( tmp_ptr, norm_tag, norm_tag_len );
1804  tmp_ptr += norm_tag_len;
1805  memcpy( tmp_ptr, normf_appd, normf_appd_len );
1806  tmp_ptr += normf_appd_len;
1807  *tmp_ptr = '\0';
1808 
1809  Tag normf_hdl;
1810  // Check to see if the tag exists. If not then create it and get the handle.
1811  err = mbImpl->tag_get_handle( normf_tag, 1, moab::MB_TYPE_DOUBLE, normf_hdl,
1812  moab::MB_TAG_SPARSE | moab::MB_TAG_CREAT );ERRORR( "Failed to create normalization factor tag.", err );
1813  if( normf_hdl == NULL )
1814  {
1815  std::string msg( "Failed to create normalization factor tag named '" );
1816  msg += std::string( normf_tag ) + std::string( "'" );ERRORR( msg.c_str(), MB_FAILURE );
1817  }
1818  free( normf_tag );
1819 
1820  std::vector< std::vector< EntityHandle > >::iterator iter_i;
1821  std::vector< EntityHandle >::iterator iter_j;
1822  std::vector< double >::iterator iter_f;
1823  double grp_norm_factor = 0.0;
1824 
1825  // Loop over the entity sets
1826  for( iter_i = entity_sets.begin(), iter_f = norm_factors.begin();
1827  ( iter_i != entity_sets.end() ) && ( iter_f != norm_factors.end() ); ++iter_i, ++iter_f )
1828  {
1829  grp_norm_factor = *iter_f;
1830 
1831  // Loop over the all the entity sets in iter_i and set the
1832  // new normf_tag with the norm factor value on each
1833  for( iter_j = ( *iter_i ).begin(); iter_j != ( *iter_i ).end(); ++iter_j )
1834  {
1835  EntityHandle entset = *iter_j;
1836 
1837  std::cout << "Coupler: applying normalization for entity set=" << entset
1838  << ", normalization_factor=" << grp_norm_factor << std::endl;
1839 
1840  err = mbImpl->tag_set_data( normf_hdl, &entset, 1, &grp_norm_factor );ERRORR( "Failed to set normalization factor on entity set.", err );
1841  }
1842  }
1843 
1844  return MB_SUCCESS;
1845 }
1846 
1847 #define UINT_PER_X( X ) ( ( sizeof( X ) + sizeof( uint ) - 1 ) / sizeof( uint ) )
1848 #define UINT_PER_REAL UINT_PER_X( realType )
1849 #define UINT_PER_LONG UINT_PER_X( slong )
1850 #define UINT_PER_UNSIGNED UINT_PER_X( unsigned )
1851 
1852 // Function for packing tuple_list. Returns number of uints copied into buffer.
1853 int pack_tuples( TupleList* tl, void** ptr )
1854 {
1855  uint mi, ml, mul, mr;
1856  tl->getTupleSize( mi, ml, mul, mr );
1857 
1858  uint n = tl->get_n();
1859 
1860  int sz_buf = 1 + 4 * UINT_PER_UNSIGNED +
1861  tl->get_n() * ( mi + ml * UINT_PER_LONG + mul * UINT_PER_LONG + mr * UINT_PER_REAL );
1862 
1863  uint* buf = (uint*)malloc( sz_buf * sizeof( uint ) );
1864  *ptr = (void*)buf;
1865 
1866  // Copy n
1867  memcpy( buf, &n, sizeof( uint ) ), buf += 1;
1868  // Copy mi
1869  memcpy( buf, &mi, sizeof( unsigned ) ), buf += UINT_PER_UNSIGNED;
1870  // Copy ml
1871  memcpy( buf, &ml, sizeof( unsigned ) ), buf += UINT_PER_UNSIGNED;
1872  // Copy mul
1873  memcpy( buf, &mul, sizeof( unsigned ) ), buf += UINT_PER_UNSIGNED;
1874  // Copy mr
1875  memcpy( buf, &mr, sizeof( unsigned ) ), buf += UINT_PER_UNSIGNED;
1876  // Copy vi_wr
1877  memcpy( buf, tl->vi_rd, tl->get_n() * mi * sizeof( sint ) ), buf += tl->get_n() * mi;
1878  // Copy vl_wr
1879  memcpy( buf, tl->vl_rd, tl->get_n() * ml * sizeof( slong ) ), buf += tl->get_n() * ml * UINT_PER_LONG;
1880  // Copy vul_wr
1881  memcpy( buf, tl->vul_rd, tl->get_n() * mul * sizeof( ulong ) ), buf += tl->get_n() * mul * UINT_PER_LONG;
1882  // Copy vr_wr
1883  memcpy( buf, tl->vr_rd, tl->get_n() * mr * sizeof( realType ) ), buf += tl->get_n() * mr * UINT_PER_REAL;
1884 
1885  return sz_buf;
1886 }
1887 
1888 // Function for packing tuple_list
1889 void unpack_tuples( void* ptr, TupleList** tlp )
1890 {
1891  TupleList* tl = new TupleList();
1892  *tlp = tl;
1893 
1894  uint nt;
1895  unsigned mit, mlt, mult, mrt;
1896  uint* buf = (uint*)ptr;
1897 
1898  // Get n
1899  memcpy( &nt, buf, sizeof( uint ) ), buf += 1;
1900  // Get mi
1901  memcpy( &mit, buf, sizeof( unsigned ) ), buf += UINT_PER_UNSIGNED;
1902  // Get ml
1903  memcpy( &mlt, buf, sizeof( unsigned ) ), buf += UINT_PER_UNSIGNED;
1904  // Get mul
1905  memcpy( &mult, buf, sizeof( unsigned ) ), buf += UINT_PER_UNSIGNED;
1906  // Get mr
1907  memcpy( &mrt, buf, sizeof( unsigned ) ), buf += UINT_PER_UNSIGNED;
1908 
1909  // Initialize tl
1910  tl->initialize( mit, mlt, mult, mrt, nt );
1911  tl->enableWriteAccess();
1912  tl->set_n( nt );
1913 
1914  uint mi, ml, mul, mr;
1915  tl->getTupleSize( mi, ml, mul, mr );
1916 
1917  // Get vi_rd
1918  memcpy( tl->vi_wr, buf, tl->get_n() * mi * sizeof( sint ) ), buf += tl->get_n() * mi;
1919  // Get vl_rd
1920  memcpy( tl->vl_wr, buf, tl->get_n() * ml * sizeof( slong ) ), buf += tl->get_n() * ml * UINT_PER_LONG;
1921  // Get vul_rd
1922  memcpy( tl->vul_wr, buf, tl->get_n() * mul * sizeof( ulong ) ), buf += tl->get_n() * mul * UINT_PER_LONG;
1923  // Get vr_rd
1924  memcpy( tl->vr_wr, buf, tl->get_n() * mr * sizeof( realType ) ), buf += tl->get_n() * mr * UINT_PER_REAL;
1925 
1926  tl->disableWriteAccess();
1927  return;
1928 }
1929 
1930 ErrorCode Coupler::get_gl_points_on_elements( Range& targ_elems, std::vector< double >& vpos, int& numPointsOfInterest )
1931 {
1932  numPointsOfInterest = targ_elems.size() * _ntot;
1933  vpos.resize( 3 * numPointsOfInterest );
1934  int ielem = 0;
1935  for( Range::iterator eit = targ_elems.begin(); eit != targ_elems.end(); ++eit, ielem += _ntot * 3 )
1936  {
1937  EntityHandle eh = *eit;
1938  const double* xval;
1939  const double* yval;
1940  const double* zval;
1941  ErrorCode rval = mbImpl->tag_get_by_ptr( _xm1Tag, &eh, 1, (const void**)&xval );
1942  if( moab::MB_SUCCESS != rval )
1943  {
1944  std::cout << "Can't get xm1 values \n";
1945  return MB_FAILURE;
1946  }
1947  rval = mbImpl->tag_get_by_ptr( _ym1Tag, &eh, 1, (const void**)&yval );
1948  if( moab::MB_SUCCESS != rval )
1949  {
1950  std::cout << "Can't get ym1 values \n";
1951  return MB_FAILURE;
1952  }
1953  rval = mbImpl->tag_get_by_ptr( _zm1Tag, &eh, 1, (const void**)&zval );
1954  if( moab::MB_SUCCESS != rval )
1955  {
1956  std::cout << "Can't get zm1 values \n";
1957  return MB_FAILURE;
1958  }
1959  // Now, in a stride, populate vpos
1960  for( int i = 0; i < _ntot; i++ )
1961  {
1962  vpos[ielem + 3 * i] = xval[i];
1963  vpos[ielem + 3 * i + 1] = yval[i];
1964  vpos[ielem + 3 * i + 2] = zval[i];
1965  }
1966  }
1967 
1968  return MB_SUCCESS;
1969 }
1970 
1971 } // namespace moab