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