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