MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
gslib.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#include "gslib.hpp"
13#include "geom.hpp"
14
15#ifdef MFEM_USE_GSLIB
16
17// Ignore warnings from the gslib header (GCC version)
18#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
19#pragma GCC diagnostic push
20#pragma GCC diagnostic ignored "-Wunused-function"
21#endif
22
23#define CODE_INTERNAL 0
24#define CODE_BORDER 1
25#define CODE_NOT_FOUND 2
26
27// External GSLIB header (the MFEM header is gslib.hpp)
28namespace gslib
29{
30#include "gslib.h"
31#ifndef GSLIB_RELEASE_VERSION //gslib v1.0.7
32#define GSLIB_RELEASE_VERSION 10007
33#endif
34extern "C" {
35 struct hash_data_3
36 {
37 ulong hash_n;
38 struct dbl_range bnd[3];
39 double fac[3];
40 uint *offset;
41 };
42
43 struct hash_data_2
44 {
45 ulong hash_n;
46 struct dbl_range bnd[2];
47 double fac[2];
48 uint *offset;
49 };
50
51 struct findpts_dummy_ms_data
52 {
53 unsigned int *nsid;
54 double *distfint;
55 };
56
57 struct findpts_data_3
58 {
59 struct crystal cr;
60 struct findpts_local_data_3 local;
61 struct hash_data_3 hash;
62 struct array savpt;
63 struct findpts_dummy_ms_data fdms;
64 uint fevsetup;
65 };
66
67 struct findpts_data_2
68 {
69 struct crystal cr;
70 struct findpts_local_data_2 local;
71 struct hash_data_2 hash;
72 struct array savpt;
73 struct findpts_dummy_ms_data fdms;
74 uint fevsetup;
75 };
76} //extern C
77
78} //namespace gslib
79
80#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
81#pragma GCC diagnostic pop
82#endif
83
84namespace mfem
85{
86
88 : mesh(nullptr),
89 fec_map_lin(nullptr),
90 fdataD(nullptr), cr(nullptr), gsl_comm(nullptr),
91 dim(-1), points_cnt(-1), setupflag(false), default_interp_value(0),
92 avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
93{
94 mesh_split.SetSize(4);
95 ir_split.SetSize(4);
96 fes_rst_map.SetSize(4);
97 gf_rst_map.SetSize(4);
98 for (int i = 0; i < mesh_split.Size(); i++)
99 {
100 mesh_split[i] = nullptr;
101 ir_split[i] = nullptr;
102 fes_rst_map[i] = nullptr;
103 gf_rst_map[i] = nullptr;
104 }
105
106 gsl_comm = new gslib::comm;
107 cr = new gslib::crystal;
108#ifdef MFEM_USE_MPI
109 int initialized = 0;
110 MPI_Initialized(&initialized);
111 if (!initialized) { MPI_Init(NULL, NULL); }
112 MPI_Comm comm = MPI_COMM_WORLD;
113 comm_init(gsl_comm, comm);
114#else
115 comm_init(gsl_comm, 0);
116#endif
117 crystal_init(cr, gsl_comm);
118}
119
120FindPointsGSLIB::FindPointsGSLIB(Mesh &mesh_in, const double bb_t,
121 const double newt_tol, const int npt_max)
123{
124 Setup(mesh_in, bb_t, newt_tol, npt_max);
125}
126
128{
129 FreeData();
130#ifdef MFEM_USE_MPI
131 if (!Mpi::IsFinalized()) // currently segfaults inside gslib otherwise
132#endif
133 {
134 crystal_free(cr);
135 comm_free(gsl_comm);
136 delete gsl_comm;
137 delete cr;
138 }
139 for (int i = 0; i < mesh_split.Size(); i++)
140 {
141 if (mesh_split[i]) { delete mesh_split[i]; mesh_split[i] = nullptr; }
142 if (ir_split[i]) { delete ir_split[i]; ir_split[i] = nullptr; }
143 if (fes_rst_map[i]) { delete fes_rst_map[i]; fes_rst_map[i] = nullptr; }
144 if (gf_rst_map[i]) { delete gf_rst_map[i]; gf_rst_map[i] = nullptr; }
145 }
146 if (fec_map_lin) { delete fec_map_lin; fec_map_lin = nullptr; }
147}
148
149#ifdef MFEM_USE_MPI
151 : mesh(nullptr),
152 fec_map_lin(nullptr),
153 fdataD(nullptr), cr(nullptr), gsl_comm(nullptr),
154 dim(-1), points_cnt(-1), setupflag(false), default_interp_value(0),
155 avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
156{
157 mesh_split.SetSize(4);
158 ir_split.SetSize(4);
159 fes_rst_map.SetSize(4);
160 gf_rst_map.SetSize(4);
161 for (int i = 0; i < mesh_split.Size(); i++)
162 {
163 mesh_split[i] = nullptr;
164 ir_split[i] = nullptr;
165 fes_rst_map[i] = nullptr;
166 gf_rst_map[i] = nullptr;
167 }
168
169 gsl_comm = new gslib::comm;
170 cr = new gslib::crystal;
171 comm_init(gsl_comm, comm_);
172 crystal_init(cr, gsl_comm);
173}
174
175FindPointsGSLIB::FindPointsGSLIB(ParMesh &mesh_in, const double bb_t,
176 const double newt_tol, const int npt_max)
177 : FindPointsGSLIB(mesh_in.GetComm())
178{
179 Setup(mesh_in, bb_t, newt_tol, npt_max);
180}
181#endif
182
183void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
184 const int npt_max)
185{
186 MFEM_VERIFY(m.GetNodes() != NULL, "Mesh nodes are required.");
187 MFEM_VERIFY(m.SpaceDimension() == m.Dimension(),
188 "Mesh spatial dimension and reference element dimension must be the same");
189 const int meshOrder = m.GetNodes()->FESpace()->GetMaxElementOrder();
190
191 // call FreeData if FindPointsGSLIB::Setup has been called already
192 if (setupflag) { FreeData(); }
193
194 mesh = &m;
195 dim = mesh->Dimension();
196 const unsigned int dof1D = meshOrder+1;
197
199
201
203
204 DEV.local_hash_size = mesh_points_cnt;
205 DEV.dof1d = (int)dof1D;
206 if (dim == 2)
207 {
208 unsigned nr[2] = { dof1D, dof1D };
209 unsigned mr[2] = { 2*dof1D, 2*dof1D };
210 double * const elx[2] =
211 {
212 mesh_points_cnt == 0 ? nullptr : &gsl_mesh(0),
213 mesh_points_cnt == 0 ? nullptr : &gsl_mesh(mesh_points_cnt)
214 };
215 fdataD = findpts_setup_2(gsl_comm, elx, nr, NE_split_total, mr, bb_t,
216 DEV.local_hash_size,
217 mesh_points_cnt, npt_max, newt_tol);
218 }
219 else
220 {
221 unsigned nr[3] = { dof1D, dof1D, dof1D };
222 unsigned mr[3] = { 2*dof1D, 2*dof1D, 2*dof1D };
223 double * const elx[3] =
224 {
225 mesh_points_cnt == 0 ? nullptr : &gsl_mesh(0),
226 mesh_points_cnt == 0 ? nullptr : &gsl_mesh(mesh_points_cnt),
227 mesh_points_cnt == 0 ? nullptr : &gsl_mesh(2*mesh_points_cnt)
228 };
229 fdataD = findpts_setup_3(gsl_comm, elx, nr, NE_split_total, mr, bb_t,
230 DEV.local_hash_size,
231 mesh_points_cnt, npt_max, newt_tol);
232 }
233 setupflag = true;
234}
235
237 int point_pos_ordering)
238{
239 MFEM_VERIFY(setupflag, "Use FindPointsGSLIB::Setup before finding points.");
240 bool dev_mode = (point_pos.UseDevice() && Device::IsEnabled());
241 points_cnt = point_pos.Size() / dim;
247
248 bool tensor_product_only = mesh->GetNE() == 0 ||
249 (mesh->GetNumGeometries(dim) == 1 &&
252#ifdef MFEM_USE_MPI
253 MPI_Allreduce(MPI_IN_PLACE, &tensor_product_only, 1, MFEM_MPI_CXX_BOOL,
254 MPI_LAND, gsl_comm->c);
255#endif
256
257 if (dev_mode && tensor_product_only)
258 {
259#if GSLIB_RELEASE_VERSION == 10007
261 {
262 MFEM_ABORT("Either update to gslib v1.0.9 for GPU support "
263 "or use SetGPUtoCPUFallback to use host-functions. See "
264 "INSTALL for instructions to update GSLIB.");
265 }
266#else
267 FindPointsOnDevice(point_pos, point_pos_ordering);
268 return;
269#endif
271
272 auto pp = point_pos.HostRead();
273 auto xvFill = [&](const double *xv_base[], unsigned xv_stride[])
275 for (int d = 0; d < dim; d++)
276 {
277 if (point_pos_ordering == Ordering::byNODES)
278 {
279 xv_base[d] = pp + d*points_cnt;
280 xv_stride[d] = sizeof(double);
281 }
282 else
283 {
284 xv_base[d] = pp + d;
285 xv_stride[d] = dim*sizeof(double);
286 }
287 }
288 };
289
290 if (dim == 2)
291 {
292 auto *findptsData = (gslib::findpts_data_2 *)this->fdataD;
293 const double *xv_base[2];
294 unsigned xv_stride[2];
295 xvFill(xv_base, xv_stride);
296 findpts_2(gsl_code.GetData(), sizeof(unsigned int),
297 gsl_proc.GetData(), sizeof(unsigned int),
298 gsl_elem.GetData(), sizeof(unsigned int),
299 gsl_ref.GetData(), sizeof(double) * dim,
300 gsl_dist.GetData(), sizeof(double),
301 xv_base, xv_stride, points_cnt, findptsData);
302 }
303 else // dim == 3
304 {
305 auto *findptsData = (gslib::findpts_data_3 *)this->fdataD;
306 const double *xv_base[3];
307 unsigned xv_stride[3];
308 xvFill(xv_base, xv_stride);
309 findpts_3(gsl_code.GetData(), sizeof(unsigned int),
310 gsl_proc.GetData(), sizeof(unsigned int),
311 gsl_elem.GetData(), sizeof(unsigned int),
312 gsl_ref.GetData(), sizeof(double) * dim,
313 gsl_dist.GetData(), sizeof(double),
314 xv_base, xv_stride, points_cnt,
315 findptsData);
316 }
317
318 // Set the element number and reference position to 0 for points not found
319 for (int i = 0; i < points_cnt; i++)
320 {
321 if (gsl_code[i] == 2 ||
322 (gsl_code[i] == 1 && gsl_dist(i) > bdr_tol))
323 {
324 gsl_elem[i] = 0;
325 for (int d = 0; d < dim; d++) { gsl_ref(i*dim + d) = -1.; }
326 gsl_code[i] = 2;
327 gsl_proc[i] = gsl_comm->id;
328 }
329 }
330
331 // Map element number for simplices, and ref_pos from [-1,1] to [0,1] for
332 // both simplices and quads. Also sets code to 1 for points found on element
333 // faces/edges.
335}
336
337#if GSLIB_RELEASE_VERSION >= 10009
338slong lfloor(double x) { return floor(x); }
339
340// Local hash mesh index in 1D for a given point
341ulong hash_index_aux(double low, double fac, ulong n, double x)
342{
343 const slong i = lfloor((x - low) * fac);
344 return i < 0 ? 0 : (n - 1 < (ulong)i ? n - 1 : (ulong)i);
345}
346
347// Local hash mesh index in 3D for a given point
348ulong hash_index_3(const gslib::hash_data_3 *p, const double x[3])
349{
350 const ulong n = p->hash_n;
351 return (hash_index_aux(p->bnd[2].min, p->fac[2], n, x[2]) * n +
352 hash_index_aux(p->bnd[1].min, p->fac[1], n, x[1])) *
353 n +
354 hash_index_aux(p->bnd[0].min, p->fac[0], n, x[0]);
355}
356
357// Local hash mesh index in 2D for a given point
358ulong hash_index_2(const gslib::hash_data_2 *p, const double x[2])
359{
360 const ulong n = p->hash_n;
361 return (hash_index_aux(p->bnd[1].min, p->fac[1], n, x[1])) * n
362 + hash_index_aux(p->bnd[0].min, p->fac[0], n, x[0]);
363}
364
366{
367 auto *findptsData3 = (gslib::findpts_data_3 *)this->fdataD;
368 auto *findptsData2 = (gslib::findpts_data_2 *)this->fdataD;
369
370 DEV.newt_tol = dim == 2 ? findptsData2->local.tol : findptsData3->local.tol;
371 if (dim == 3)
372 {
373 DEV.hash3 = &findptsData3->hash;
374 }
375 else
376 {
377 DEV.hash2 = &findptsData2->hash;
378 }
379 DEV.cr = dim == 2 ? &findptsData2->cr : &findptsData3->cr;
380
381 gsl_mesh.UseDevice(true);
382
383 int n_box_ents = 3*dim + dim*dim;
384 DEV.bb.UseDevice(true); DEV.bb.SetSize(n_box_ents*NE_split_total);
385 auto p_bb = DEV.bb.HostWrite();
386
387 const int dim2 = dim*dim;
388 if (dim == 3)
389 {
390 for (int e = 0; e < NE_split_total; e++)
391 {
392 auto box = findptsData3->local.obb[e];
393 for (int d = 0; d < dim; d++)
394 {
395 p_bb[n_box_ents*e + d] = box.c0[d];
396 p_bb[n_box_ents*e + dim + d] = box.x[d].min;
397 p_bb[n_box_ents*e + 2*dim + d] = box.x[d].max;
398 }
399 for (int d = 0; d < dim2; ++d)
400 {
401 p_bb[n_box_ents*e + 3*dim + d] = box.A[d];
402 }
403 }
404 }
405 else
406 {
407 for (int e = 0; e < NE_split_total; e++)
408 {
409 auto box = findptsData2->local.obb[e];
410 for (int d = 0; d < dim; d++)
411 {
412 p_bb[n_box_ents*e + d] = box.c0[d];
413 p_bb[n_box_ents*e + dim + d] = box.x[d].min;
414 p_bb[n_box_ents*e + 2*dim + d] = box.x[d].max;
415 }
416 for (int d = 0; d < dim2; ++d)
417 {
418 p_bb[n_box_ents*e + 3*dim + d] = box.A[d];
419 }
420 }
421 }
422
423 DEV.loc_hash_min.UseDevice(true); DEV.loc_hash_min.SetSize(dim);
424 DEV.loc_hash_fac.UseDevice(true); DEV.loc_hash_fac.SetSize(dim);
425 if (dim == 2)
426 {
427 auto hash = findptsData2->local.hd;
428 auto p_loc_hash_min = DEV.loc_hash_min.HostWrite();
429 auto p_loc_hash_fac = DEV.loc_hash_fac.HostWrite();
430 for (int d = 0; d < dim; d++)
431 {
432 p_loc_hash_min[d] = hash.bnd[d].min;
433 p_loc_hash_fac[d] = hash.fac[d];
434 }
435 DEV.h_nx = hash.hash_n;
436 }
437 else
438 {
439 auto hash = findptsData3->local.hd;
440 auto p_loc_hash_min = DEV.loc_hash_min.HostWrite();
441 auto p_loc_hash_fac = DEV.loc_hash_fac.HostWrite();
442 for (int d = 0; d < dim; d++)
443 {
444 p_loc_hash_min[d] = hash.bnd[d].min;
445 p_loc_hash_fac[d] = hash.fac[d];
446 }
447 DEV.h_nx = hash.hash_n;
448 }
449
450 DEV.h_o_size = dim == 2 ?
451 findptsData2->local.hd.offset[(int)std::pow(DEV.h_nx, dim)] :
452 findptsData3->local.hd.offset[(int)std::pow(DEV.h_nx, dim)];
453
454 DEV.loc_hash_offset.SetSize(DEV.h_o_size);
455 auto p_ou_offset = DEV.loc_hash_offset.HostWrite();
456 for (int i = 0; i < DEV.h_o_size; i++)
457 {
458 p_ou_offset[i] = dim == 2 ? findptsData2->local.hd.offset[i] :
459 findptsData3->local.hd.offset[i];
460 }
461
462 DEV.wtend.UseDevice(true);
463 DEV.wtend.SetSize(6*DEV.dof1d);
464 DEV.wtend.HostWrite();
465 DEV.wtend = dim == 2 ? findptsData2->local.fed.wtend[0] :
466 findptsData3->local.fed.wtend[0];
467
468 // Get gll points
469 DEV.gll1d.UseDevice(true);
470 DEV.gll1d.SetSize(DEV.dof1d);
471 DEV.gll1d.HostWrite();
472 DEV.gll1d = dim == 2 ? findptsData2->local.fed.z[0] :
473 findptsData3->local.fed.z[0];
474
475 DEV.lagcoeff.UseDevice(true);
476 DEV.lagcoeff.SetSize(DEV.dof1d);
477 DEV.lagcoeff.HostWrite();
478 DEV.lagcoeff = dim == 2 ? findptsData2->local.fed.lag_data[0] :
479 findptsData3->local.fed.lag_data[0];
480
481 DEV.setup_device = true;
482}
483
485 int point_pos_ordering)
486{
487 if (!DEV.setup_device)
488 {
489 SetupDevice();
490 }
491 DEV.find_device = true;
492
493 const int id = gsl_comm->id, np = gsl_comm->np;
494
497 gsl_ref.UseDevice(true);
498 gsl_dist.UseDevice(true);
499 // Initialize arrays for all points (gsl_code is set to not found on device)
500 gsl_ref = -1.0;
501 gsl_mfem_ref = 0.0;
502 gsl_elem = 0;
503 gsl_mfem_elem = 0;
504 gsl_proc = id;
505
506 if (dim == 2)
507 {
508 FindPointsLocal2(point_pos, point_pos_ordering, gsl_code, gsl_elem, gsl_ref,
510 }
511 else
512 {
513 FindPointsLocal3(point_pos, point_pos_ordering, gsl_code, gsl_elem, gsl_ref,
515 }
516
517 // Sync from device to host
522 point_pos.HostRead();
523
524 // Tolerance for point to be marked as on element edge/face based on the
525 // obtained reference-space coordinates.
526 double rbtol = 1e-12; // must match MapRefPosAndElemIndices for consistency
527
528 if (np == 1)
529 {
530 // Set gsl_mfem_elem using gsl_elem, gsl_mfem_ref using gsl_ref,
531 // and gsl_code using element type, gsl_mfem_ref, and gsl_dist.
532 for (int index = 0; index < points_cnt; index++)
533 {
534 if (gsl_code[index] == CODE_NOT_FOUND)
535 {
536 continue;
537 }
539 for (int d = 0; d < dim; d++)
540 {
541 gsl_mfem_ref(index * dim + d) = 0.5 * (gsl_ref(index * dim + d) + 1.0);
542 }
544 if (dim == 2)
545 {
547 }
548 else if (dim == 3)
549 {
551 }
552 const int elem = gsl_elem[index];
553 const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(elem);
554 const Geometry::Type gt = fe->GetGeomType(); // assumes quad/hex
555 int setcode =
556 Geometry::CheckPoint(gt, ip, -rbtol) ? CODE_INTERNAL : CODE_BORDER;
557 gsl_code[index] = setcode == CODE_BORDER && gsl_dist(index) > bdr_tol
558 ? CODE_NOT_FOUND
559 : setcode;
560 }
561 return;
562 }
563
564#ifdef MFEM_USE_MPI
565 MPI_Barrier(gsl_comm->c);
566#endif
567 /* send unfound and border points to global hash cells */
568 struct gslib::array hash_pt, src_pt, out_pt;
569
570 struct srcPt_t
571 {
572 double x[3];
573 unsigned int index, proc;
574 };
575
576 struct outPt_t
577 {
578 double r[3], dist2;
579 unsigned int index, code, el, proc;
580 };
581
582 {
583 int index;
584 struct srcPt_t *pt;
585
586 array_init(struct srcPt_t, &hash_pt, points_cnt);
587 pt = (struct srcPt_t *)hash_pt.ptr;
588
589 auto x = new double[dim];
590 for (index = 0; index < points_cnt; ++index)
591 {
592 if (gsl_code[index] != CODE_INTERNAL)
593 {
594 for (int d = 0; d < dim; ++d)
595 {
596 int idx = point_pos_ordering == 0 ?
597 index + d*points_cnt :
598 index*dim + d;
599 x[d] = point_pos(idx);
600 }
601 const auto hi = dim == 2 ? hash_index_2(DEV.hash2, x) :
602 hash_index_3(DEV.hash3, x);
603 for (int d = 0; d < dim; ++d)
604 {
605 pt->x[d] = x[d];
606 }
607 pt->index = index;
608 pt->proc = hi % np;
609 ++pt;
610 }
611 }
612 delete[] x;
613 hash_pt.n = pt - (struct srcPt_t *)hash_pt.ptr;
614 sarray_transfer(struct srcPt_t, &hash_pt, proc, 1, DEV.cr);
615 }
616#ifdef MFEM_USE_MPI
617 MPI_Barrier(gsl_comm->c);
618#endif
619
620 /* look up points in hash cells, route to possible procs */
621 {
622 const unsigned int *const hash_offset = dim == 2 ? DEV.hash2->offset :
623 DEV.hash3->offset;
624 int count = 0;
625 unsigned int *proc, *proc_p;
626 const struct srcPt_t *p = (struct srcPt_t *)hash_pt.ptr,
627 *const pe = p + hash_pt.n;
628 struct srcPt_t *q;
629
630 for (; p != pe; ++p)
631 {
632 const int hi = dim == 2 ? hash_index_2(DEV.hash2, p->x)/np :
633 hash_index_3(DEV.hash3, p->x)/np;
634 const int i = hash_offset[hi], ie = hash_offset[hi + 1];
635 count += ie - i;
636 }
637
638 Array<unsigned int> proc_array(count);
639 proc = proc_array.GetData();
640 proc_p = proc;
641 array_init(struct srcPt_t, &src_pt, count);
642 q = (struct srcPt_t *)src_pt.ptr;
643
644 p = (struct srcPt_t *)hash_pt.ptr;
645 for (; p != pe; ++p)
646 {
647 const int hi = dim == 2 ? hash_index_2(DEV.hash2, p->x)/np :
648 hash_index_3(DEV.hash3, p->x)/np;
649 int i = hash_offset[hi];
650 const int ie = hash_offset[hi + 1];
651 for (; i != ie; ++i)
652 {
653 const int pp = hash_offset[i];
654 /* don't send back to where it just came from */
655 if (pp == p->proc)
656 {
657 continue;
658 }
659 *proc_p++ = pp;
660 *q++ = *p;
661 }
662 }
663
664 array_free(&hash_pt);
665 src_pt.n = proc_p - proc;
666
667 sarray_transfer_ext(struct srcPt_t, &src_pt, proc, sizeof(uint), DEV.cr);
668 }
669#ifdef MFEM_USE_MPI
670 MPI_Barrier(gsl_comm->c);
671#endif
672
673 /* look for other procs' points, send back */
674 {
675 int n = src_pt.n;
676 const struct srcPt_t *spt;
677 struct outPt_t *opt;
678 array_init(struct outPt_t, &out_pt, n);
679 out_pt.n = n;
680 spt = (struct srcPt_t *)src_pt.ptr;
681 opt = (struct outPt_t *)out_pt.ptr;
682 for (; n; --n, ++spt, ++opt)
683 {
684 opt->index = spt->index;
685 opt->proc = spt->proc;
686 }
687 spt = (struct srcPt_t *)src_pt.ptr;
688 opt = (struct outPt_t *)out_pt.ptr;
689
690 n = out_pt.n;
691 Vector gsl_ref_l, gsl_dist_l;
692 gsl_ref_l.UseDevice(true); gsl_ref_l.SetSize(n*dim);
693 gsl_dist_l.UseDevice(true); gsl_dist_l.SetSize(n);
694
695 Vector point_pos_l;
696 point_pos_l.UseDevice(true); point_pos_l.SetSize(n*dim);
697 auto pointl = point_pos_l.HostWrite();
698
699 Array<unsigned int> gsl_code_l(n), gsl_elem_l(n);
700
701 for (int point = 0; point < n; ++point)
702 {
703 for (int d = 0; d < dim; d++)
704 {
705 int idx = point_pos_ordering == 0 ? point + d*n : point*dim + d;
706 pointl[idx] = spt[point].x[d];
707 }
708 }
709
710 if (dim == 2)
711 {
712 FindPointsLocal2(point_pos_l, point_pos_ordering, gsl_code_l,
713 gsl_elem_l, gsl_ref_l, gsl_dist_l, n);
714 }
715 else
716 {
717 FindPointsLocal3(point_pos_l, point_pos_ordering, gsl_code_l,
718 gsl_elem_l, gsl_ref_l, gsl_dist_l, n);
719 }
720
721 gsl_ref_l.HostRead();
722 gsl_dist_l.HostRead();
723 gsl_code_l.HostRead();
724 gsl_elem_l.HostRead();
725
726 // unpack arrays into opt
727 for (int point = 0; point < n; point++)
728 {
729 opt[point].code = AsConst(gsl_code_l)[point];
730 if (opt[point].code == CODE_NOT_FOUND)
731 {
732 continue;
733 }
734 opt[point].el = AsConst(gsl_elem_l)[point];
735 opt[point].dist2 = AsConst(gsl_dist_l)[point];
736 for (int d = 0; d < dim; ++d)
737 {
738 opt[point].r[d] = AsConst(gsl_ref_l)[dim * point + d];
739 }
740 // for found points set gsl_code using reference space coords.
742 if (dim == 2)
743 {
744 ip.Set2(0.5*opt[point].r[0]+0.5, 0.5*opt[point].r[1]+0.5);
745 }
746 else
747 {
748 ip.Set3(0.5*opt[point].r[0]+0.5, 0.5*opt[point].r[1]+0.5,
749 0.5*opt[point].r[2]+0.5);
750 }
751 const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(opt[point].el);
752 const Geometry::Type gt = fe->GetGeomType();
753 int setcode = Geometry::CheckPoint(gt, ip, -rbtol) ?
754 CODE_INTERNAL : CODE_BORDER;
755 opt[point].code = setcode==CODE_BORDER && opt[point].dist2>bdr_tol ?
756 CODE_NOT_FOUND : setcode;
757 }
758
759 array_free(&src_pt);
760
761 /* group by code to eliminate unfound points */
762 sarray_sort(struct outPt_t, opt, out_pt.n, code, 0, &DEV.cr->data);
763
764 n = out_pt.n;
765 while (n && opt[n - 1].code == CODE_NOT_FOUND)
766 {
767 --n;
768 }
769 out_pt.n = n;
770
771 sarray_transfer(struct outPt_t, &out_pt, proc, 1, DEV.cr);
772 }
773#ifdef MFEM_USE_MPI
774 MPI_Barrier(gsl_comm->c);
775#endif
776
777 /* merge remote results with user data */
778 // For points found on other procs, we set gsl_mfem_elem, gsl_mfem_ref,
779 // and gsl_code now.
780 {
781 int n = out_pt.n;
782 struct outPt_t *opt = (struct outPt_t *)out_pt.ptr;
783 for (; n; --n, ++opt)
784 {
785 const int index = opt->index;
786 if (gsl_code[index] == CODE_INTERNAL)
787 {
788 continue;
789 }
790 if (gsl_code[index] == CODE_NOT_FOUND || opt->code == CODE_INTERNAL ||
791 opt->dist2 < gsl_dist[index])
792 {
793 for (int d = 0; d < dim; ++d)
794 {
795 gsl_ref(dim * index + d) = opt->r[d];
796 gsl_mfem_ref(dim*index + d) = 0.5*(opt->r[d] + 1.);
797 }
798 gsl_dist[index] = opt->dist2;
799 gsl_proc[index] = opt->proc;
800 gsl_elem[index] = opt->el;
801 gsl_mfem_elem[index] = opt->el;
802 gsl_code[index] = opt->code;
803 }
804 }
805 array_free(&out_pt);
806 }
807
808 // For points found locally, we set gsl_mfem_elem, gsl_mfem_ref, and gsl_code.
809 for (int index = 0; index < points_cnt; index++)
810 {
811 if (gsl_code[index] == CODE_NOT_FOUND || gsl_proc[index] != id)
812 {
813 continue;
814 }
816 for (int d = 0; d < dim; d++)
817 {
818 gsl_mfem_ref(index*dim + d) = 0.5*(gsl_ref(index*dim + d)+1.0);
819 }
821 if (dim == 2)
822 {
824 }
825 else if (dim == 3)
826 {
828 }
829 const int elem = gsl_elem[index];
830 const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(elem);
831 const Geometry::Type gt = fe->GetGeomType(); // assumes quad/hex
832 int setcode = Geometry::CheckPoint(gt, ip, -rbtol) ?
833 CODE_INTERNAL : CODE_BORDER;
834 gsl_code[index] = setcode==CODE_BORDER && gsl_dist(index)>bdr_tol ?
835 CODE_NOT_FOUND : setcode;
836 }
837}
838
839struct evalSrcPt_t
840{
841 double r[3];
842 unsigned int index, proc, el;
843};
844
845struct evalOutPt_t
846{
847 double out;
848 unsigned int index, proc;
849};
850
852 Vector &field_out,
853 const int nel,
854 const int ncomp,
855 const int dof1Dsol,
856 const int ordering)
857{
858 field_out.UseDevice(true);
859 field_out.SetSize(points_cnt*ncomp);
860 field_out = default_interp_value;
861
862 DEV.dof1d_sol = dof1Dsol;
863 DEV.gll1d_sol.UseDevice(true); DEV.gll1d_sol.SetSize(dof1Dsol);
864 DEV.lagcoeff_sol.UseDevice(true); DEV.lagcoeff_sol.SetSize(dof1Dsol);
865 if (DEV.dof1d_sol != DEV.dof1d || !DEV.find_device)
866 {
867 gslib::lobatto_nodes(DEV.gll1d_sol.HostWrite(), dof1Dsol);
868 gslib::gll_lag_setup(DEV.lagcoeff_sol.HostWrite(), dof1Dsol);
869 }
870 else
871 {
872 DEV.gll1d_sol = DEV.gll1d.HostRead();
873 DEV.lagcoeff_sol = DEV.lagcoeff.HostRead();
874 }
875
876 field_out.HostReadWrite(); //Reads in default value from device
877
878 struct gslib::array src, outpt;
879 int nlocal = 0;
880 /* weed out unfound points, send out */
881 Array<int> gsl_elem_temp;
882 Vector gsl_ref_temp;
883 Array<int> index_temp;
884 {
885 int index;
886 const unsigned int *code = gsl_code.GetData(), *proc = gsl_proc.GetData(),
887 *el = gsl_elem.GetData();
888 const double *r = gsl_ref.GetData();
889
890 int numSend = 0;
891
892 for (index = 0; index < points_cnt; ++index)
893 {
894 numSend += (gsl_code[index] != CODE_NOT_FOUND &&
895 gsl_proc[index] != gsl_comm->id);
896 nlocal += (gsl_code[index] != CODE_NOT_FOUND &&
897 gsl_proc[index] == gsl_comm->id);
898 }
899
900 gsl_elem_temp.SetSize(nlocal);
901 gsl_elem_temp.HostWrite();
902
903 gsl_ref_temp.SetSize(nlocal*dim);
904 gsl_ref_temp.UseDevice(true);
905 gsl_ref_temp.HostWrite();
906
907 index_temp.SetSize(nlocal);
908
909 evalSrcPt_t *pt;
910 array_init(evalSrcPt_t, &src, numSend);
911 pt = (evalSrcPt_t *)src.ptr;
912
913 int ctr = 0;
914 for (index = 0; index < points_cnt; ++index)
915 {
916 if (*code != CODE_NOT_FOUND && *proc != gsl_comm->id)
917 {
918 for (int d = 0; d < dim; ++d)
919 {
920 pt->r[d] = r[d];
921 }
922 pt->index = index;
923 pt->proc = *proc;
924 pt->el = *el;
925 ++pt;
926 }
927 else if (*code != CODE_NOT_FOUND && *proc == gsl_comm->id)
928 {
929 gsl_elem_temp[ctr] = *el;
930 for (int d = 0; d < dim; ++d)
931 {
932 gsl_ref_temp(dim*ctr+d) = r[d];
933 }
934 index_temp[ctr] = index;
935
936 ctr++;
937 }
938 r += dim;
939 code++;
940 proc++;
941 el++;
942 }
943
944 src.n = pt - (evalSrcPt_t *)src.ptr;
945 sarray_transfer(evalSrcPt_t, &src, proc, 1, cr);
946 }
947
948 //evaluate points that are already local
949 {
950 Vector interp_vals(nlocal*ncomp);
951 interp_vals.UseDevice(true);
952
953 if (dim == 2)
954 {
955 InterpolateLocal2(field_in_evec,
956 gsl_elem_temp,
957 gsl_ref_temp,
958 interp_vals,
959 nlocal, ncomp,
960 nel, dof1Dsol);
961 }
962 else
963 {
964 InterpolateLocal3(field_in_evec,
965 gsl_elem_temp,
966 gsl_ref_temp,
967 interp_vals,
968 nlocal, ncomp,
969 nel, dof1Dsol);
970
971 }
972#ifdef MFEM_USE_MPI
973 MPI_Barrier(gsl_comm->c);
974#endif
975
976 interp_vals.HostRead();
977
978 // now put these in correct positions
979 int interp_Offset = interp_vals.Size()/ncomp;
980 for (int i = 0; i < ncomp; i++)
981 {
982 for (int j = 0; j < nlocal; j++)
983 {
984 int pt_index = index_temp[j];
985 int idx = ordering == Ordering::byNODES ?
986 pt_index + i*points_cnt :
987 pt_index*ncomp + i;
988 field_out(idx) = AsConst(interp_vals)(j + interp_Offset*i);
989 }
990 }
991 }
992#ifdef MFEM_USE_MPI
993 MPI_Barrier(gsl_comm->c);
994#endif
995
996 if (gsl_comm->np == 1)
997 {
998 array_free(&src);
999 return;
1000 }
1001
1002 // evaluate points locally
1003 {
1004 int n = src.n;
1005 const evalSrcPt_t *spt;
1006 evalOutPt_t *opt;
1007 spt = (evalSrcPt_t *)src.ptr;
1008
1009 // Copy to host vector
1010 gsl_elem_temp.SetSize(n);
1011 gsl_elem_temp.HostWrite();
1012
1013 gsl_ref_temp.SetSize(n*dim);
1014 gsl_ref_temp.HostWrite();
1015
1016 spt = (evalSrcPt_t *)src.ptr;
1017 // opt = (evalOutPt_t *)outpt.ptr;
1018 for (int i = 0; i < n; i++, ++spt)
1019 {
1020 gsl_elem_temp[i] = spt->el;
1021 for (int d = 0; d < dim; d++)
1022 {
1023 gsl_ref_temp(i*dim + d) = spt->r[d];
1024 }
1025 }
1026
1027 Vector interp_vals(n*ncomp);
1028 interp_vals.UseDevice(true);
1029 if (dim == 2)
1030 {
1031 InterpolateLocal2(field_in_evec,
1032 gsl_elem_temp,
1033 gsl_ref_temp,
1034 interp_vals, n, ncomp,
1035 nel, dof1Dsol);
1036 }
1037 else
1038 {
1039 InterpolateLocal3(field_in_evec,
1040 gsl_elem_temp,
1041 gsl_ref_temp,
1042 interp_vals, n, ncomp,
1043 nel, dof1Dsol);
1044 }
1045#ifdef MFEM_USE_MPI
1046 MPI_Barrier(gsl_comm->c);
1047#endif
1048 interp_vals.HostRead();
1049
1050 // Now the interpolated values need to be sent back component wise
1051 int Offset = interp_vals.Size()/ncomp;
1052 for (int i = 0; i < ncomp; i++)
1053 {
1054 spt = (evalSrcPt_t *)src.ptr;
1055 array_init(evalOutPt_t, &outpt, n);
1056 outpt.n = n;
1057 opt = (evalOutPt_t *)outpt.ptr;
1058
1059 for (int j = 0; j < n; j++)
1060 {
1061 opt->index = spt->index;
1062 opt->proc = spt->proc;
1063 opt->out = AsConst(interp_vals)(j + Offset*i);
1064 spt++;
1065 opt++;
1066 }
1067
1068 sarray_transfer(struct evalOutPt_t, &outpt, proc, 1, cr);
1069
1070 opt = (evalOutPt_t *)outpt.ptr;
1071 for (int index = 0; index < outpt.n; index++)
1072 {
1073 int idx = ordering == Ordering::byNODES ?
1074 opt->index + i*points_cnt :
1075 opt->index*ncomp + i;
1076 field_out(idx) = opt->out;
1077 ++opt;
1078 }
1079 array_free(&outpt);
1080 }
1081 array_free(&src);
1082 }
1083 //finished evaluating points received from other processors.
1084}
1085#else
1087void FindPointsGSLIB::FindPointsOnDevice(const Vector &point_pos,
1088 int point_pos_ordering) {};
1089void FindPointsGSLIB::InterpolateOnDevice(const Vector &field_in_evec,
1090 Vector &field_out,
1091 const int nel, const int ncomp,
1092 const int dof1dsol,
1093 const int ordering) {};
1094#endif
1095
1096void FindPointsGSLIB::FindPoints(Mesh &m, const Vector &point_pos,
1097 int point_pos_ordering, const double bb_t,
1098 const double newt_tol, const int npt_max)
1099{
1100 if (!setupflag || (mesh != &m) )
1101 {
1102 Setup(m, bb_t, newt_tol, npt_max);
1103 }
1104 FindPoints(point_pos, point_pos_ordering);
1105}
1106
1108 const GridFunction &field_in, Vector &field_out,
1109 int point_pos_ordering)
1110{
1111 FindPoints(point_pos, point_pos_ordering);
1112 Interpolate(field_in, field_out);
1113}
1114
1115void FindPointsGSLIB::Interpolate(Mesh &m, const Vector &point_pos,
1116 const GridFunction &field_in, Vector &field_out,
1117 int point_pos_ordering)
1118{
1119 FindPoints(m, point_pos, point_pos_ordering);
1120 Interpolate(field_in, field_out);
1121}
1122
1124{
1125 if (!setupflag) { return; }
1126#ifdef MFEM_USE_MPI
1127 if (!Mpi::IsFinalized()) // currently segfaults inside gslib otherwise
1128#endif
1129 {
1130 if (dim == 2)
1131 {
1132 findpts_free_2((gslib::findpts_data_2 *)this->fdataD);
1133 }
1134 else
1135 {
1136 findpts_free_3((gslib::findpts_data_3 *)this->fdataD);
1137 }
1138 }
1142 gsl_mesh.Destroy();
1143 gsl_ref.Destroy();
1144 gsl_dist.Destroy();
1145 for (int i = 0; i < 4; i++)
1146 {
1147 if (mesh_split[i]) { delete mesh_split[i]; mesh_split[i] = NULL; }
1148 if (ir_split[i]) { delete ir_split[i]; ir_split[i] = NULL; }
1149 if (fes_rst_map[i]) { delete fes_rst_map[i]; fes_rst_map[i] = NULL; }
1150 if (gf_rst_map[i]) { delete gf_rst_map[i]; gf_rst_map[i] = NULL; }
1151 }
1152 if (fec_map_lin) { delete fec_map_lin; fec_map_lin = NULL; }
1153 setupflag = false;
1154 DEV.setup_device = false;
1155 DEV.find_device = false;
1156 points_cnt = -1;
1157}
1158
1160{
1161 if (fec_map_lin == nullptr) { fec_map_lin = new H1_FECollection(1, dim); }
1162 if (dim == 2)
1163 {
1164 int Nvert = 7;
1165 int NEsplit = 3;
1166 mesh_split[0] = new Mesh(2, Nvert, NEsplit, 0, 2);
1167
1168 const double quad_v[7][2] =
1169 {
1170 {0, 0}, {0.5, 0}, {1, 0}, {0, 0.5},
1171 {1./3., 1./3.}, {0.5, 0.5}, {0, 1}
1172 };
1173 const int quad_e[3][4] =
1174 {
1175 {0, 1, 4, 3}, {1, 2, 5, 4}, {3, 4, 5, 6}
1176 };
1177
1178 for (int j = 0; j < Nvert; j++)
1179 {
1180 mesh_split[0]->AddVertex(quad_v[j]);
1181 }
1182 for (int j = 0; j < NEsplit; j++)
1183 {
1184 int attribute = j + 1;
1185 mesh_split[0]->AddQuad(quad_e[j], attribute);
1186 }
1187 mesh_split[0]->FinalizeQuadMesh(1, 1, true);
1188
1190 gf_rst_map[0] = new GridFunction(fes_rst_map[0]);
1191 gf_rst_map[0]->UseDevice(false);
1192 const int npt = gf_rst_map[0]->Size()/dim;
1193 for (int k = 0; k < dim; k++)
1194 {
1195 for (int j = 0; j < npt; j++)
1196 {
1197 (*gf_rst_map[0])(j+k*npt) = quad_v[j][k];
1198 }
1199 }
1200
1203 }
1204 else if (dim == 3)
1205 {
1206 mesh_split[0] = new Mesh(Mesh::MakeCartesian3D(1, 1, 1,
1208 // Tetrahedron
1209 {
1210 int Nvert = 15;
1211 int NEsplit = 4;
1212 mesh_split[1] = new Mesh(3, Nvert, NEsplit, 0, 3);
1213
1214 const double hex_v[15][3] =
1215 {
1216 {0, 0, 0.}, {1, 0., 0.}, {0., 1., 0.}, {0, 0., 1.},
1217 {0.5, 0., 0.}, {0.5, 0.5, 0.}, {0., 0.5, 0.},
1218 {0., 0., 0.5}, {0.5, 0., 0.5}, {0., 0.5, 0.5},
1219 {1./3., 0., 1./3.}, {1./3., 1./3., 1./3.}, {0, 1./3., 1./3.},
1220 {1./3., 1./3., 0}, {0.25, 0.25, 0.25}
1221 };
1222 const int hex_e[4][8] =
1223 {
1224 {7, 10, 4, 0, 12, 14, 13, 6},
1225 {10, 8, 1, 4, 14, 11, 5, 13},
1226 {14, 11, 5, 13, 12, 9, 2, 6},
1227 {7, 3, 8, 10, 12, 9, 11, 14}
1228 };
1229
1230 for (int j = 0; j < Nvert; j++)
1231 {
1232 mesh_split[1]->AddVertex(hex_v[j]);
1233 }
1234 for (int j = 0; j < NEsplit; j++)
1235 {
1236 int attribute = j + 1;
1237 mesh_split[1]->AddHex(hex_e[j], attribute);
1238 }
1239 mesh_split[1]->FinalizeHexMesh(1, 1, true);
1240
1242 gf_rst_map[1] = new GridFunction(fes_rst_map[1]);
1243 gf_rst_map[1]->UseDevice(false);
1244 const int npt = gf_rst_map[1]->Size()/dim;
1245 for (int k = 0; k < dim; k++)
1246 {
1247 for (int j = 0; j < npt; j++)
1248 {
1249 (*gf_rst_map[1])(j+k*npt) = hex_v[j][k];
1250 }
1251 }
1252 }
1253 // Prism
1254 {
1255 int Nvert = 14;
1256 int NEsplit = 3;
1257 mesh_split[2] = new Mesh(3, Nvert, NEsplit, 0, 3);
1258
1259 const double hex_v[14][3] =
1260 {
1261 {0, 0, 0}, {0.5, 0, 0}, {1, 0, 0}, {0, 0.5, 0},
1262 {1./3., 1./3., 0}, {0.5, 0.5, 0}, {0, 1, 0},
1263 {0, 0, 1}, {0.5, 0, 1}, {1, 0, 1}, {0, 0.5, 1},
1264 {1./3., 1./3., 1}, {0.5, 0.5, 1}, {0, 1, 1}
1265 };
1266 const int hex_e[3][8] =
1267 {
1268 {0, 1, 4, 3, 7, 8, 11, 10},
1269 {1, 2, 5, 4, 8, 9, 12, 11},
1270 {3, 4, 5, 6, 10, 11, 12, 13}
1271 };
1272
1273 for (int j = 0; j < Nvert; j++)
1274 {
1275 mesh_split[2]->AddVertex(hex_v[j]);
1276 }
1277 for (int j = 0; j < NEsplit; j++)
1278 {
1279 int attribute = j + 1;
1280 mesh_split[2]->AddHex(hex_e[j], attribute);
1281 }
1282 mesh_split[2]->FinalizeHexMesh(1, 1, true);
1283
1285 gf_rst_map[2] = new GridFunction(fes_rst_map[2]);
1286 gf_rst_map[2]->UseDevice(false);
1287 const int npt = gf_rst_map[2]->Size()/dim;
1288 for (int k = 0; k < dim; k++)
1289 {
1290 for (int j = 0; j < npt; j++)
1291 {
1292 (*gf_rst_map[2])(j+k*npt) = hex_v[j][k];
1293 }
1294 }
1295 }
1296 // Pyramid
1297 {
1298 int Nvert = 23;
1299 int NEsplit = 8;
1300 mesh_split[3] = new Mesh(3, Nvert, NEsplit, 0, 3);
1301
1302 const double hex_v[23][3] =
1303 {
1304 {0.0000, 0.0000, 0.0000}, {0.5000, 0.0000, 0.0000},
1305 {0.0000, 0.0000, 0.5000}, {0.3333, 0.0000, 0.3333},
1306 {0.0000, 0.5000, 0.0000}, {0.3333, 0.3333, 0.0000},
1307 {0.0000, 0.3333, 0.3333}, {0.2500, 0.2500, 0.2500},
1308 {1.0000, 0.0000, 0.0000}, {0.5000, 0.0000, 0.5000},
1309 {0.5000, 0.5000, 0.0000}, {0.3333, 0.3333, 0.3333},
1310 {0.0000, 1.0000, 0.0000}, {0.0000, 0.5000, 0.5000},
1311 {0.0000, 0.0000, 1.0000}, {1.0000, 0.5000, 0.0000},
1312 {0.6667, 0.3333, 0.3333}, {0.6667, 0.6667, 0.0000},
1313 {0.5000, 0.5000, 0.2500}, {1.0000, 1.0000, 0.0000},
1314 {0.5000, 0.5000, 0.5000}, {0.5000, 1.0000, 0.0000},
1315 {0.3333, 0.6667, 0.3333}
1316 };
1317 const int hex_e[8][8] =
1318 {
1319 {2, 3, 1, 0, 6, 7, 5, 4}, {3, 9, 8, 1, 7, 11, 10, 5},
1320 {7, 11, 10, 5, 6, 13, 12, 4}, {2, 14, 9, 3, 6, 13, 11, 7},
1321 {9, 16, 15, 8, 11, 18, 17, 10}, {16, 20, 19, 15, 18, 22, 21, 17},
1322 {18, 22, 21, 17, 11, 13, 12, 10}, {9, 14, 20, 16, 11, 13, 22, 18}
1323 };
1324
1325 for (int j = 0; j < Nvert; j++)
1326 {
1327 mesh_split[3]->AddVertex(hex_v[j]);
1328 }
1329 for (int j = 0; j < NEsplit; j++)
1330 {
1331 int attribute = j + 1;
1332 mesh_split[3]->AddHex(hex_e[j], attribute);
1333 }
1334 mesh_split[3]->FinalizeHexMesh(1, 1, true);
1335
1337 gf_rst_map[3] = new GridFunction(fes_rst_map[3]);
1338 gf_rst_map[3]->UseDevice(false);
1339 const int npt = gf_rst_map[3]->Size()/dim;
1340 for (int k = 0; k < dim; k++)
1341 {
1342 for (int j = 0; j < npt; j++)
1343 {
1344 (*gf_rst_map[3])(j+k*npt) = hex_v[j][k];
1345 }
1346 }
1347 }
1348 }
1349}
1350
1352 IntegrationRule *irule,
1353 int order)
1354{
1355 H1_FECollection fec(order, dim);
1356 FiniteElementSpace nodal_fes(meshin, &fec, dim);
1357 meshin->SetNodalFESpace(&nodal_fes);
1358 const int NEsplit = meshin->GetNE();
1359
1360 const int dof_cnt = nodal_fes.GetTypicalFE()->GetDof(),
1361 pts_cnt = NEsplit * dof_cnt;
1362 Vector irlist(dim * pts_cnt);
1363
1364 const TensorBasisElement *tbe =
1365 dynamic_cast<const TensorBasisElement *>(nodal_fes.GetTypicalFE());
1366 MFEM_VERIFY(tbe != NULL, "TensorBasis FiniteElement expected.");
1367 const Array<int> &dof_map = tbe->GetDofMap();
1368
1369 DenseMatrix pos(dof_cnt, dim);
1370 Vector posV(pos.Data(), dof_cnt * dim);
1371 Array<int> xdofs(dof_cnt * dim);
1372
1373 // Create an IntegrationRule on the nodes of the reference submesh.
1374 MFEM_ASSERT(irule->GetNPoints() == pts_cnt, "IntegrationRule does not have"
1375 "the correct number of points.");
1376 GridFunction *nodesplit = meshin->GetNodes();
1377 int pt_id = 0;
1378 for (int i = 0; i < NEsplit; i++)
1379 {
1380 nodal_fes.GetElementVDofs(i, xdofs);
1381 nodesplit->GetSubVector(xdofs, posV);
1382 for (int j = 0; j < dof_cnt; j++)
1383 {
1384 for (int d = 0; d < dim; d++)
1385 {
1386 irlist(pts_cnt * d + pt_id) = pos(dof_map[j], d);
1387 }
1388 irule->IntPoint(pt_id).x = irlist(pt_id);
1389 irule->IntPoint(pt_id).y = irlist(pts_cnt + pt_id);
1390 if (dim == 3)
1391 {
1392 irule->IntPoint(pt_id).z = irlist(2*pts_cnt + pt_id);
1393 }
1394 pt_id++;
1395 }
1396 }
1397}
1398
1400{
1401 MFEM_VERIFY(mesh, "Setup FindPointsGSLIB with mesh first.");
1402 const int dof1D = order+1;
1403 const int dim = mesh->Dimension();
1404
1406 if (dim == 2)
1407 {
1408 if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
1409 ir_split[0] = new IntegrationRule(3*pow(dof1D, dim));
1411
1412 if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
1413 ir_split[1] = new IntegrationRule(pow(dof1D, dim));
1415 }
1416 else if (dim == 3)
1417 {
1418 if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
1419 ir_split[0] = new IntegrationRule(pow(dof1D, dim));
1421
1422 if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
1423 ir_split[1] = new IntegrationRule(4*pow(dof1D, dim));
1425
1426 if (ir_split[2]) { delete ir_split[2]; ir_split[2] = NULL; }
1427 ir_split[2] = new IntegrationRule(3*pow(dof1D, dim));
1429
1430 if (ir_split[3]) { delete ir_split[3]; ir_split[3] = NULL; }
1431 ir_split[3] = new IntegrationRule(8*pow(dof1D, dim));
1433 }
1434
1435 // Setup map for non tensor-product elements
1436 NE_split_total = 0;
1439 int NEsplit = 0;
1440 for (int e = 0; e < mesh->GetNE(); e++)
1441 {
1443 if (gt == Geometry::TRIANGLE || gt == Geometry::PRISM)
1444 {
1445 NEsplit = 3;
1446 }
1447 else if (gt == Geometry::TETRAHEDRON)
1448 {
1449 NEsplit = 4;
1450 }
1451 else if (gt == Geometry::PYRAMID)
1452 {
1453 NEsplit = 8;
1454 }
1455 else if (gt == Geometry::SQUARE || gt == Geometry::CUBE)
1456 {
1457 NEsplit = 1;
1458 }
1459 else
1460 {
1461 MFEM_ABORT("Unsupported geometry type.");
1462 }
1463 NE_split_total += NEsplit;
1464 for (int i = 0; i < NEsplit; i++)
1465 {
1468 }
1469 }
1470}
1471
1473 Vector &node_vals)
1474{
1475 const GridFunction *nodes = gf_in;
1476 const FiniteElementSpace *fes = nodes->FESpace();
1477 const int NE = mesh->GetNE();
1478 const int vdim = fes->GetVDim();
1479
1480 IntegrationRule *ir_split_temp = NULL;
1481
1482 const int maxOrder = fes->GetMaxElementOrder();
1483 const int dof_1D = maxOrder+1;
1484 const int pts_el = std::pow(dof_1D, dim);
1485 const int pts_cnt = NE_split_total * pts_el;
1486 node_vals.SetSize(vdim * pts_cnt);
1487
1488 if (node_vals.UseDevice())
1489 {
1490 node_vals.HostWrite();
1491 }
1492
1493 int gsl_mesh_pt_index = 0;
1494
1495 for (int e = 0; e < NE; e++)
1496 {
1497 const FiniteElement *fe = fes->GetFE(e);
1498 const Geometry::Type gt = fe->GetGeomType();
1499 bool el_to_split = true;
1500 if (gt == Geometry::TRIANGLE)
1501 {
1502 ir_split_temp = ir_split[0];
1503 }
1504 else if (gt == Geometry::TETRAHEDRON)
1505 {
1506 ir_split_temp = ir_split[1];
1507 }
1508 else if (gt == Geometry::PRISM)
1509 {
1510 ir_split_temp = ir_split[2];
1511 }
1512 else if (gt == Geometry::PYRAMID)
1513 {
1514 ir_split_temp = ir_split[3];
1515 }
1516 else if (gt == Geometry::SQUARE)
1517 {
1518 ir_split_temp = ir_split[1];
1519 // "split" if input mesh is not a tensor basis or has mixed order
1520 el_to_split =
1521 gf_in->FESpace()->IsVariableOrder() ||
1522 dynamic_cast<const TensorBasisElement *>(fes->GetFE(e)) == nullptr;
1523 }
1524 else if (gt == Geometry::CUBE)
1525 {
1526 ir_split_temp = ir_split[0];
1527 // "split" if input mesh is not a tensor basis or has mixed order
1528 el_to_split =
1529 gf_in->FESpace()->IsVariableOrder() ||
1530 dynamic_cast<const TensorBasisElement *>(fes->GetFE(e)) == nullptr;
1531 }
1532 else
1533 {
1534 MFEM_ABORT("Unsupported geometry type.");
1535 }
1536
1537 if (el_to_split) // Triangle/Tet/Prism or Quads/Hex but variable order
1538 {
1539 // Fill gsl_mesh with location of split points.
1540 Vector locval(vdim);
1541 for (int i = 0; i < ir_split_temp->GetNPoints(); i++)
1542 {
1543 const IntegrationPoint &ip = ir_split_temp->IntPoint(i);
1544 nodes->GetVectorValue(e, ip, locval);
1545 for (int d = 0; d < vdim; d++)
1546 {
1547 node_vals(pts_cnt*d + gsl_mesh_pt_index) = locval(d);
1548 }
1549 gsl_mesh_pt_index++;
1550 }
1551 }
1552 else // Quad/Hex and constant polynomial order
1553 {
1554 const int dof_cnt_split = fe->GetDof();
1555
1556 const TensorBasisElement *tbe =
1557 dynamic_cast<const TensorBasisElement *>(fes->GetFE(e));
1558 MFEM_VERIFY(tbe != NULL, "TensorBasis FiniteElement expected.");
1559 Array<int> dof_map(dof_cnt_split);
1560 const Array<int> &dm = tbe->GetDofMap();
1561 if (dm.Size() > 0) { dof_map = dm; }
1562 else { for (int i = 0; i < dof_cnt_split; i++) { dof_map[i] = i; } }
1563
1564 DenseMatrix pos(dof_cnt_split, vdim);
1565 Vector posV(pos.Data(), dof_cnt_split * vdim);
1566 Array<int> xdofs(dof_cnt_split * vdim);
1567
1568 fes->GetElementVDofs(e, xdofs);
1569 nodes->GetSubVector(xdofs, posV);
1570 for (int j = 0; j < dof_cnt_split; j++)
1571 {
1572 for (int d = 0; d < vdim; d++)
1573 {
1574 node_vals(pts_cnt * d + gsl_mesh_pt_index) = pos(dof_map[j], d);
1575 }
1576 gsl_mesh_pt_index++;
1577 }
1578 }
1579 }
1580}
1581
1583{
1588
1589 gsl_mfem_ref += 1.; // map [-1, 1] to [0, 2] to [0, 1]
1590 gsl_mfem_ref *= 0.5;
1591
1592 int nptorig = points_cnt,
1593 npt = points_cnt;
1594
1595 // Tolerance for point to be marked as on element edge/face based on the
1596 // obtained reference-space coordinates.
1597 double rbtol = 1e-12;
1598
1599 GridFunction *gf_rst_map_temp = NULL;
1600 int nptsend = 0;
1601
1602 for (int index = 0; index < npt; index++)
1603 {
1604 if (gsl_code[index] != 2 && gsl_proc[index] != gsl_comm->id)
1605 {
1606 nptsend +=1;
1607 }
1608 }
1609
1610 // Pack data to send via crystal router
1611 struct gslib::array *outpt = new gslib::array;
1612 struct out_pt { double r[3]; uint index, el, proc, code; };
1613 struct out_pt *pt;
1614 array_init(struct out_pt, outpt, nptsend);
1615 outpt->n=nptsend;
1616 pt = (struct out_pt *)outpt->ptr;
1617 for (int index = 0; index < npt; index++)
1618 {
1619 if (gsl_code[index] == 2 || gsl_proc[index] == gsl_comm->id)
1620 {
1621 continue;
1622 }
1623 for (int d = 0; d < dim; ++d)
1624 {
1625 pt->r[d]= gsl_mfem_ref(index*dim + d);
1626 }
1627 pt->index = index;
1628 pt->proc = gsl_proc[index];
1629 pt->el = gsl_elem[index];
1630 pt->code = gsl_code[index];
1631 ++pt;
1632 }
1633
1634 // Transfer data to target MPI ranks
1635 sarray_transfer(struct out_pt, outpt, proc, 1, cr);
1636
1637 // Map received points
1638 npt = outpt->n;
1639 pt = (struct out_pt *)outpt->ptr;
1640 for (int index = 0; index < npt; index++)
1641 {
1643 ip.Set3(&pt->r[0]);
1644 const int elem = pt->el;
1645 const int mesh_elem = split_element_map[elem];
1646 const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(mesh_elem);
1647
1648 const Geometry::Type gt = fe->GetGeomType();
1649 pt->el = mesh_elem;
1650
1651 if (gt == Geometry::SQUARE || gt == Geometry::CUBE)
1652 {
1653 // check if it is on element boundary
1654 pt->code = Geometry::CheckPoint(gt, ip, -rbtol) ? 0 : 1;
1655 ++pt;
1656 continue;
1657 }
1658 else if (gt == Geometry::TRIANGLE)
1659 {
1660 gf_rst_map_temp = gf_rst_map[0];
1661 }
1662 else if (gt == Geometry::TETRAHEDRON)
1663 {
1664 gf_rst_map_temp = gf_rst_map[1];
1665 }
1666 else if (gt == Geometry::PRISM)
1667 {
1668 gf_rst_map_temp = gf_rst_map[2];
1669 }
1670 else if (gt == Geometry::PYRAMID)
1671 {
1672 gf_rst_map_temp = gf_rst_map[3];
1673 }
1674
1675 int local_elem = split_element_index[elem];
1676 Vector mfem_ref(dim);
1677 // map to rst of macro element
1678 gf_rst_map_temp->GetVectorValue(local_elem, ip, mfem_ref);
1679
1680 for (int d = 0; d < dim; d++)
1681 {
1682 pt->r[d] = mfem_ref(d);
1683 }
1684
1685 // check if point is on element boundary
1686 ip.Set3(&pt->r[0]);
1687 pt->code = Geometry::CheckPoint(gt, ip, -rbtol) ? 0 : 1;
1688 ++pt;
1689 }
1690
1691 // Transfer data back to source MPI rank
1692 sarray_transfer(struct out_pt, outpt, proc, 1, cr);
1693 npt = outpt->n;
1694
1695 // First copy mapped information for points on other procs
1696 pt = (struct out_pt *)outpt->ptr;
1697 for (int index = 0; index < npt; index++)
1698 {
1699 gsl_mfem_elem[pt->index] = pt->el;
1700 for (int d = 0; d < dim; d++)
1701 {
1702 gsl_mfem_ref(d + pt->index*dim) = pt->r[d];
1703 }
1704 gsl_code[pt->index] = pt->code;
1705 ++pt;
1706 }
1707 array_free(outpt);
1708 delete outpt;
1709
1710 // Now map information for points on the same proc
1711 for (int index = 0; index < nptorig; index++)
1712 {
1713 if (gsl_code[index] != 2 && gsl_proc[index] == gsl_comm->id)
1714 {
1715
1717 Vector mfem_ref(gsl_mfem_ref.GetData()+index*dim, dim);
1718 ip.Set2(mfem_ref.GetData());
1719 if (dim == 3) { ip.z = mfem_ref(2); }
1720
1721 const int elem = gsl_elem[index];
1722 const int mesh_elem = split_element_map[elem];
1723 const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(mesh_elem);
1724 const Geometry::Type gt = fe->GetGeomType();
1725 gsl_mfem_elem[index] = mesh_elem;
1726 if (gt == Geometry::SQUARE || gt == Geometry::CUBE)
1727 {
1728 gsl_code[index] = Geometry::CheckPoint(gt, ip, -rbtol) ? 0 : 1;
1729 continue;
1730 }
1731 else if (gt == Geometry::TRIANGLE)
1732 {
1733 gf_rst_map_temp = gf_rst_map[0];
1734 }
1735 else if (gt == Geometry::TETRAHEDRON)
1736 {
1737 gf_rst_map_temp = gf_rst_map[1];
1738 }
1739 else if (gt == Geometry::PRISM)
1740 {
1741 gf_rst_map_temp = gf_rst_map[2];
1742 }
1743 else if (gt == Geometry::PYRAMID)
1744 {
1745 gf_rst_map_temp = gf_rst_map[3];
1746 }
1747
1748 int local_elem = split_element_index[elem];
1749 gf_rst_map_temp->GetVectorValue(local_elem, ip, mfem_ref);
1750
1751 // Check if the point is on element boundary
1752 ip.Set2(mfem_ref.GetData());
1753 if (dim == 3) { ip.z = mfem_ref(2); }
1754 gsl_code[index] = Geometry::CheckPoint(gt, ip, -rbtol) ? 0 : 1;
1755 }
1756 }
1757}
1758
1760 Vector &field_out)
1761{
1762 const int gf_order = field_in.FESpace()->GetMaxElementOrder(),
1763 mesh_order = mesh->GetNodalFESpace()->GetMaxElementOrder();
1764
1765 const FiniteElementCollection *fec_in = field_in.FESpace()->FEColl();
1766 const H1_FECollection *fec_h1 = dynamic_cast<const H1_FECollection *>(fec_in);
1767 const L2_FECollection *fec_l2 = dynamic_cast<const L2_FECollection *>(fec_in);
1768
1769 bool tensor_product_only = mesh->GetNE() == 0 ||
1770 (mesh->GetNumGeometries(dim) == 1 &&
1773#ifdef MFEM_USE_MPI
1774 MPI_Allreduce(MPI_IN_PLACE, &tensor_product_only, 1, MFEM_MPI_CXX_BOOL,
1775 MPI_LAND, gsl_comm->c);
1776#endif
1777
1778 if (Device::IsEnabled() && field_in.UseDevice() && fec_h1 &&
1779 !field_in.FESpace()->IsVariableOrder() && tensor_product_only)
1780 {
1781#if GSLIB_RELEASE_VERSION == 10007
1783 {
1784 MFEM_ABORT("Either update to gslib v1.0.9 for GPU support "
1785 "or use SetGPUtoCPUFallback to use host-functions. See "
1786 "INSTALL for instructions to update GSLIB");
1787 }
1788#else
1789 MFEM_VERIFY(fec_h1->GetBasisType() == BasisType::GaussLobatto,
1790 "basis not supported");
1791 Vector node_vals;
1793 const Operator *R = field_in.FESpace()->GetElementRestriction(ordering);
1794 node_vals.UseDevice(true);
1795 node_vals.SetSize(R->Height(), Device::GetMemoryType());
1796 R->Mult(field_in, node_vals);
1797 // GetNodalValues(&field_in, node_vals);
1798
1799 const int ncomp = field_in.FESpace()->GetVDim();
1800 const int maxOrder = field_in.FESpace()->GetMaxElementOrder();
1801
1802 InterpolateOnDevice(node_vals, field_out, NE_split_total, ncomp,
1803 maxOrder+1, field_in.FESpace()->GetOrdering());
1804 return;
1805#endif
1806 }
1807 field_in.HostRead();
1808 field_out.HostWrite();
1809
1810 if (fec_h1 && gf_order == mesh_order &&
1812 field_in.FESpace()->IsVariableOrder() ==
1814 {
1815 InterpolateH1(field_in, field_out);
1816 return;
1817 }
1818 else
1819 {
1820 InterpolateGeneral(field_in, field_out);
1821 if (!fec_l2 || avgtype == AvgType::NONE) { return; }
1822 }
1823
1824 // For points on element borders, project the L2 GridFunction to H1 and
1825 // re-interpolate.
1826 if (fec_l2)
1827 {
1828 Array<int> indl2;
1829 for (int i = 0; i < points_cnt; i++)
1830 {
1831 if (gsl_code[i] == 1) { indl2.Append(i); }
1832 }
1833 int borderPts = indl2.Size();
1834#ifdef MFEM_USE_MPI
1835 MPI_Allreduce(MPI_IN_PLACE, &borderPts, 1, MPI_INT, MPI_SUM, gsl_comm->c);
1836#endif
1837 if (borderPts == 0) { return; } // no points on element borders
1838
1839 Vector field_out_l2(field_out.Size());
1840 VectorGridFunctionCoefficient field_in_dg(&field_in);
1841 int gf_order_h1 = std::max(gf_order, 1); // H1 should be at least order 1
1842 H1_FECollection fec(gf_order_h1, dim);
1843 const int ncomp = field_in.FESpace()->GetVDim();
1844 FiniteElementSpace fes(mesh, &fec, ncomp,
1845 field_in.FESpace()->GetOrdering());
1846 GridFunction field_in_h1(&fes);
1847 field_in_h1.UseDevice(false);
1848
1850 {
1851 field_in_h1.ProjectDiscCoefficient(field_in_dg, GridFunction::ARITHMETIC);
1852 }
1853 else if (avgtype == AvgType::HARMONIC)
1854 {
1855 field_in_h1.ProjectDiscCoefficient(field_in_dg, GridFunction::HARMONIC);
1856 }
1857 else
1858 {
1859 MFEM_ABORT("Invalid averaging type.");
1860 }
1861
1862 if (gf_order_h1 == mesh_order) // basis is GaussLobatto by default
1863 {
1864 InterpolateH1(field_in_h1, field_out_l2);
1865 }
1866 else
1867 {
1868 InterpolateGeneral(field_in_h1, field_out_l2);
1869 }
1870
1871 // Copy interpolated values for the points on element border
1872 for (int j = 0; j < ncomp; j++)
1873 {
1874 for (int i = 0; i < indl2.Size(); i++)
1875 {
1876 int idx = field_in_h1.FESpace()->GetOrdering() == Ordering::byNODES?
1877 indl2[i] + j*points_cnt:
1878 indl2[i]*ncomp + j;
1879 field_out(idx) = field_out_l2(idx);
1880 }
1881 }
1882 }
1883}
1884
1886 Vector &field_out)
1887{
1888 FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl());
1889 if (field_in.FESpace()->IsVariableOrder())
1890 {
1891 for (int e = 0; e < ind_fes.GetMesh()->GetNE(); e++)
1892 {
1893 ind_fes.SetElementOrder(e, field_in.FESpace()->GetElementOrder(e));
1894 }
1895 ind_fes.Update(false);
1896 }
1897 GridFunction field_in_scalar(&ind_fes);
1898 field_in_scalar.UseDevice(false);
1899 Vector node_vals;
1900
1901 const int ncomp = field_in.FESpace()->GetVDim(),
1902 points_fld = field_in.Size() / ncomp;
1903 MFEM_VERIFY(points_cnt == gsl_code.Size(),
1904 "FindPointsGSLIB::InterpolateH1: Inconsistent size of gsl_code");
1905
1906 field_out.SetSize(points_cnt*ncomp);
1907 field_out = default_interp_value;
1908 field_out.HostReadWrite();
1909
1910 for (int i = 0; i < ncomp; i++)
1911 {
1912 const int dataptrin = i*points_fld,
1913 dataptrout = i*points_cnt;
1914 if (field_in.FESpace()->GetOrdering() == Ordering::byNODES)
1915 {
1916 field_in_scalar.NewDataAndSize(field_in.GetData()+dataptrin, points_fld);
1917 }
1918 else
1919 {
1920 for (int j = 0; j < points_fld; j++)
1921 {
1922 field_in_scalar(j) = field_in(i + j*ncomp);
1923 }
1924 }
1925 GetNodalValues(&field_in_scalar, node_vals);
1926
1927 if (dim==2)
1928 {
1929 findpts_eval_2(field_out.GetData()+dataptrout, sizeof(double),
1930 gsl_code.GetData(), sizeof(unsigned int),
1931 gsl_proc.GetData(), sizeof(unsigned int),
1932 gsl_elem.GetData(), sizeof(unsigned int),
1933 gsl_ref.GetData(), sizeof(double) * dim,
1934 points_cnt, node_vals.GetData(),
1935 (gslib::findpts_data_2 *)this->fdataD);
1936 }
1937 else
1938 {
1939 findpts_eval_3(field_out.GetData()+dataptrout, sizeof(double),
1940 gsl_code.GetData(), sizeof(unsigned int),
1941 gsl_proc.GetData(), sizeof(unsigned int),
1942 gsl_elem.GetData(), sizeof(unsigned int),
1943 gsl_ref.GetData(), sizeof(double) * dim,
1944 points_cnt, node_vals.GetData(),
1945 (gslib::findpts_data_3 *)this->fdataD);
1946 }
1947 }
1948 if (field_in.FESpace()->GetOrdering() == Ordering::byVDIM)
1949 {
1950 Vector field_out_temp = field_out;
1951 for (int i = 0; i < ncomp; i++)
1952 {
1953 for (int j = 0; j < points_cnt; j++)
1954 {
1955 field_out(i + j*ncomp) = field_out_temp(j + i*points_cnt);
1956 }
1957 }
1958 }
1959}
1960
1962 Vector &field_out)
1963{
1964 int ncomp = field_in.VectorDim(),
1965 nptorig = points_cnt,
1966 npt = points_cnt;
1967
1968 field_out.SetSize(points_cnt*ncomp);
1969 field_out = default_interp_value;
1970 field_out.HostReadWrite();
1971
1972 if (gsl_comm->np == 1) // serial
1973 {
1974 for (int index = 0; index < npt; index++)
1975 {
1976 if (gsl_code[index] == 2) { continue; }
1979 if (dim == 3) { ip.z = gsl_mfem_ref(index*dim + 2); }
1980 Vector localval(ncomp);
1981 field_in.GetVectorValue(gsl_mfem_elem[index], ip, localval);
1982 if (field_in.FESpace()->GetOrdering() == Ordering::byNODES)
1983 {
1984 for (int i = 0; i < ncomp; i++)
1985 {
1986 field_out(index + i*npt) = localval(i);
1987 }
1988 }
1989 else //byVDIM
1990 {
1991 for (int i = 0; i < ncomp; i++)
1992 {
1993 field_out(index*ncomp + i) = localval(i);
1994 }
1995 }
1996 }
1997 }
1998 else // parallel
1999 {
2000 // Determine number of points to be sent
2001 int nptsend = 0;
2002 for (int index = 0; index < npt; index++)
2003 {
2004 if (gsl_code[index] != 2) { nptsend +=1; }
2005 }
2006
2007 // Pack data to send via crystal router
2008 struct gslib::array *outpt = new gslib::array;
2009 struct out_pt { double r[3], ival; uint index, el, proc; };
2010 struct out_pt *pt;
2011 array_init(struct out_pt, outpt, nptsend);
2012 outpt->n=nptsend;
2013 pt = (struct out_pt *)outpt->ptr;
2014 for (int index = 0; index < npt; index++)
2015 {
2016 if (gsl_code[index] == 2) { continue; }
2017 for (int d = 0; d < dim; ++d) { pt->r[d]= gsl_mfem_ref(index*dim + d); }
2018 pt->index = index;
2019 pt->proc = gsl_proc[index];
2020 pt->el = gsl_mfem_elem[index];
2021 ++pt;
2022 }
2023
2024 // Transfer data to target MPI ranks
2025 sarray_transfer(struct out_pt, outpt, proc, 1, cr);
2026
2027 if (ncomp == 1)
2028 {
2029 // Interpolate the grid function
2030 npt = outpt->n;
2031 pt = (struct out_pt *)outpt->ptr;
2032 for (int index = 0; index < npt; index++)
2033 {
2035 ip.Set3(&pt->r[0]);
2036 pt->ival = field_in.GetValue(pt->el, ip, 1);
2037 ++pt;
2038 }
2039
2040 // Transfer data back to source MPI rank
2041 sarray_transfer(struct out_pt, outpt, proc, 1, cr);
2042 npt = outpt->n;
2043 pt = (struct out_pt *)outpt->ptr;
2044 for (int index = 0; index < npt; index++)
2045 {
2046 field_out(pt->index) = pt->ival;
2047 ++pt;
2048 }
2049 array_free(outpt);
2050 delete outpt;
2051 }
2052 else // ncomp > 1
2053 {
2054 // Interpolate data and store in a Vector
2055 npt = outpt->n;
2056 pt = (struct out_pt *)outpt->ptr;
2057 Vector vec_int_vals(npt*ncomp);
2058 for (int index = 0; index < npt; index++)
2059 {
2061 ip.Set3(&pt->r[0]);
2062 Vector localval(vec_int_vals.GetData()+index*ncomp, ncomp);
2063 field_in.GetVectorValue(pt->el, ip, localval);
2064 ++pt;
2065 }
2066
2067 // Save index and proc data in a struct
2068 struct gslib::array *savpt = new gslib::array;
2069 struct sav_pt { uint index, proc; };
2070 struct sav_pt *spt;
2071 array_init(struct sav_pt, savpt, npt);
2072 savpt->n=npt;
2073 spt = (struct sav_pt *)savpt->ptr;
2074 pt = (struct out_pt *)outpt->ptr;
2075 for (int index = 0; index < npt; index++)
2076 {
2077 spt->index = pt->index;
2078 spt->proc = pt->proc;
2079 ++pt; ++spt;
2080 }
2081
2082 array_free(outpt);
2083 delete outpt;
2084
2085 // Copy data from save struct to send struct and send component wise
2086 struct gslib::array *sendpt = new gslib::array;
2087 struct send_pt { double ival; uint index, proc; };
2088 struct send_pt *sdpt;
2089 for (int j = 0; j < ncomp; j++)
2090 {
2091 array_init(struct send_pt, sendpt, npt);
2092 sendpt->n=npt;
2093 spt = (struct sav_pt *)savpt->ptr;
2094 sdpt = (struct send_pt *)sendpt->ptr;
2095 for (int index = 0; index < npt; index++)
2096 {
2097 sdpt->index = spt->index;
2098 sdpt->proc = spt->proc;
2099 sdpt->ival = vec_int_vals(j + index*ncomp);
2100 ++sdpt; ++spt;
2101 }
2102
2103 sarray_transfer(struct send_pt, sendpt, proc, 1, cr);
2104 sdpt = (struct send_pt *)sendpt->ptr;
2105 for (int index = 0; index < static_cast<int>(sendpt->n); index++)
2106 {
2107 int idx = field_in.FESpace()->GetOrdering() == Ordering::byNODES ?
2108 sdpt->index + j*nptorig :
2109 sdpt->index*ncomp + j;
2110 field_out(idx) = sdpt->ival;
2111 ++sdpt;
2112 }
2113 array_free(sendpt);
2114 }
2115 array_free(savpt);
2116 delete sendpt;
2117 delete savpt;
2118 } // ncomp > 1
2119 } // parallel
2120}
2121
2123{
2124 Array<unsigned int> nf_idxs;
2125 for (int i = 0; i < gsl_code.Size(); i++)
2126 {
2127 if (gsl_code[i] == 2)
2128 {
2129 nf_idxs.Append(i);
2130 }
2131 }
2132 return nf_idxs;
2133}
2134
2136 Array<unsigned int> &recv_elem, Vector &recv_ref,
2137 Array<unsigned int> &recv_code)
2138{
2139 MFEM_VERIFY(points_cnt >= 0,
2140 "Invalid size. Please make sure to call FindPoints method "
2141 "before calling this function.");
2142
2143 // Pack data to send via crystal router
2144 struct gslib::array *outpt = new gslib::array;
2145
2146 struct out_pt { double rst[3]; uint index, elem, proc, code; };
2147 struct out_pt *pt;
2148 array_init(struct out_pt, outpt, points_cnt);
2149 outpt->n=points_cnt;
2150 pt = (struct out_pt *)outpt->ptr;
2151
2152 for (int index = 0; index < points_cnt; index++)
2153 {
2154 pt->index = index;
2155 pt->elem = gsl_mfem_elem[index];
2156 pt->proc = gsl_proc[index];
2157 pt->code = gsl_code[index];
2158 for (int d = 0; d < dim; ++d)
2159 {
2160 pt->rst[d]= gsl_mfem_ref(index*dim + d);
2161 }
2162 ++pt;
2163 }
2164
2165 // Transfer data to target MPI ranks
2166 sarray_transfer(struct out_pt, outpt, proc, 1, cr);
2167
2168 // Store received data
2169 const int points_recv = outpt->n;
2170 recv_proc.SetSize(points_recv);
2171 recv_elem.SetSize(points_recv);
2172 recv_index.SetSize(points_recv);
2173 recv_code.SetSize(points_recv);
2174 recv_ref.SetSize(points_recv*dim);
2175
2176 pt = (struct out_pt *)outpt->ptr;
2177 for (int index = 0; index < points_recv; index++)
2178 {
2179 recv_index[index] = pt->index;
2180 recv_elem[index] = pt->elem;
2181 recv_proc[index] = pt->proc;
2182 recv_code[index] = pt->code;
2183 for (int d = 0; d < dim; ++d)
2184 {
2185 recv_ref(index*dim + d)= pt->rst[d];
2186 }
2187 ++pt;
2188 }
2189
2190 array_free(outpt);
2191 delete outpt;
2192}
2193
2195 const int vdim,
2196 const int ordering,
2197 Vector &field_out) const
2198{
2199 const int points_recv = recv_index.Size();;
2200 MFEM_VERIFY(points_recv == 0 ||
2201 int_vals.Size() % points_recv == 0,
2202 "Incompatible size. Please return interpolated values"
2203 "corresponding to points received using"
2204 "SendCoordinatesToOwningProcessors.");
2205 field_out.SetSize(points_cnt*vdim);
2206
2207 for (int v = 0; v < vdim; v++)
2208 {
2209 // Pack data to send via crystal router
2210 struct gslib::array *outpt = new gslib::array;
2211 struct out_pt { double val; uint index, proc; };
2212 struct out_pt *pt;
2213 array_init(struct out_pt, outpt, points_recv);
2214 outpt->n=points_recv;
2215 pt = (struct out_pt *)outpt->ptr;
2216 for (int index = 0; index < points_recv; index++)
2217 {
2218 pt->index = recv_index[index];
2219 pt->proc = recv_proc[index];
2220 pt->val = ordering == Ordering::byNODES ?
2221 int_vals(index + v*points_recv) :
2222 int_vals(index*vdim + v);
2223 ++pt;
2224 }
2225
2226 // Transfer data to target MPI ranks
2227 sarray_transfer(struct out_pt, outpt, proc, 1, cr);
2228
2229 // Store received data
2230 MFEM_VERIFY(outpt->n == points_cnt, "Incompatible size. Number of points "
2231 "received does not match the number of points originally "
2232 "found using FindPoints.");
2233
2234 pt = (struct out_pt *)outpt->ptr;
2235 for (int index = 0; index < points_cnt; index++)
2236 {
2237 int idx = ordering == Ordering::byNODES ?
2238 pt->index + v*points_cnt :
2239 pt->index*vdim + v;
2240 field_out(idx) = pt->val;
2241 ++pt;
2242 }
2243
2244 array_free(outpt);
2245 delete outpt;
2246 }
2247}
2248
2250{
2251 MFEM_VERIFY(setupflag, "Call FindPointsGSLIB::Setup method first");
2252 auto *findptsData3 = (gslib::findpts_data_3 *)this->fdataD;
2253 auto *findptsData2 = (gslib::findpts_data_2 *)this->fdataD;
2254 int nve = dim == 2 ? 4 : 8;
2255 int nel = NE_split_total;
2256
2257 aabb.SetSize(dim*nve*nel);
2258 if (dim == 3)
2259 {
2260 for (int e = 0; e < nel; e++)
2261 {
2262 auto box = findptsData3->local.obb[e];
2263 Vector minn(dim), maxx(dim);
2264 for (int d = 0; d < dim; d++)
2265 {
2266 minn[d] = box.x[d].min;
2267 maxx[d] = box.x[d].max;
2268 }
2269 int c = 0;
2270 aabb(e*nve*dim + c++) = minn[0]; /* first vertex - x */
2271 aabb(e*nve*dim + c++) = minn[1]; /* y */
2272 aabb(e*nve*dim + c++) = minn[2]; /* z */
2273 aabb(e*nve*dim + c++) = maxx[0]; /* second vertex - x */
2274 aabb(e*nve*dim + c++) = minn[1]; /* . */
2275 aabb(e*nve*dim + c++) = minn[2]; /* . */
2276 aabb(e*nve*dim + c++) = maxx[0];
2277 aabb(e*nve*dim + c++) = maxx[1];
2278 aabb(e*nve*dim + c++) = minn[2];
2279 aabb(e*nve*dim + c++) = minn[0];
2280 aabb(e*nve*dim + c++) = maxx[1];
2281 aabb(e*nve*dim + c++) = minn[2];
2282 aabb(e*nve*dim + c++) = minn[0];
2283 aabb(e*nve*dim + c++) = minn[1];
2284 aabb(e*nve*dim + c++) = maxx[2];
2285 aabb(e*nve*dim + c++) = maxx[0];
2286 aabb(e*nve*dim + c++) = minn[1];
2287 aabb(e*nve*dim + c++) = maxx[2];
2288 aabb(e*nve*dim + c++) = maxx[0];
2289 aabb(e*nve*dim + c++) = maxx[1];
2290 aabb(e*nve*dim + c++) = maxx[2];
2291 aabb(e*nve*dim + c++) = minn[0];
2292 aabb(e*nve*dim + c++) = maxx[1];
2293 aabb(e*nve*dim + c++) = maxx[2];
2294 }
2295 }
2296 else // dim = 2
2297 {
2298 for (int e = 0; e < nel; e++)
2299 {
2300 auto box = findptsData2->local.obb[e];
2301 Vector minn(dim), maxx(dim);
2302 for (int d = 0; d < dim; d++)
2303 {
2304 minn[d] = box.x[d].min;
2305 maxx[d] = box.x[d].max;
2306 }
2307 aabb(e*nve*dim + 0) = minn[0]; /* first vertex - x */
2308 aabb(e*nve*dim + 1) = minn[1]; /* y */
2309 aabb(e*nve*dim + 2) = maxx[0]; /* second vertex - x */
2310 aabb(e*nve*dim + 3) = minn[1]; /* . */
2311 aabb(e*nve*dim + 4) = maxx[0]; /* . */
2312 aabb(e*nve*dim + 5) = maxx[1];
2313 aabb(e*nve*dim + 6) = minn[0];
2314 aabb(e*nve*dim + 7) = maxx[1];
2315 }
2316 }
2317}
2318
2320 Vector &obbV)
2321{
2322 MFEM_VERIFY(setupflag, "Call FindPointsGSLIB::Setup method first");
2323 auto *findptsData3 = (gslib::findpts_data_3 *)this->fdataD;
2324 auto *findptsData2 = (gslib::findpts_data_2 *)this->fdataD;
2325 int nve = dim == 2 ? 4 : 8;
2326 int nel = NE_split_total;
2327
2328 obbA.SetSize(dim, dim, nel);
2329 obbC.SetSize(dim*nel);
2330 obbV.SetSize(dim*nve*nel);
2331 if (dim == 3)
2332 {
2333 for (int e = 0; e < nel; e++)
2334 {
2335 auto box = findptsData3->local.obb[e];
2336 double *Ad = obbA.GetData(e);
2337 for (int d = 0; d < dim; d++)
2338 {
2339 obbC(e*dim + d) = box.c0[d];
2340 }
2341 for (int i = 0; i < dim; i++)
2342 {
2343 for (int j = 0; j < dim; j++)
2344 {
2345 Ad[i*dim + j] = box.A[i + j*dim]; // GSLIB uses row-major storage
2346 }
2347 }
2348
2349 DenseMatrix Amat = obbA(e);
2350 Amat.Invert();
2351 Vector center(obbC.GetData() + e*dim, dim);
2352
2353 Vector v1(dim);
2354 Vector temp;
2355 v1(0) = -1.0; v1(1) = -1.0; v1(2) = -1.0;
2356 temp.SetDataAndSize(obbV.GetData() + e*nve*dim + 0, dim);
2357 Amat.Mult(v1, temp);
2358 temp += center;
2359 v1(0) = 1.0; v1(1) = -1.0; v1(2) = -1.0;
2360 temp.SetDataAndSize(obbV.GetData() + e*nve*dim + 3, dim);
2361 Amat.Mult(v1, temp);
2362 temp += center;
2363 v1(0) = 1.0; v1(1) = 1.0; v1(2) = -1.0;
2364 temp.SetDataAndSize(obbV.GetData() + e*nve*dim + 6, dim);
2365 Amat.Mult(v1, temp);
2366 temp += center;
2367 v1(0) = -1.0; v1(1) = 1.0; v1(2) = -1.0;
2368 temp.SetDataAndSize(obbV.GetData() + e*nve*dim + 9, dim);
2369 Amat.Mult(v1, temp);
2370 temp += center;
2371 v1(0) = -1.0; v1(1) = -1.0; v1(2) = 1.0;
2372 temp.SetDataAndSize(obbV.GetData() + e*nve*dim + 12, dim);
2373 Amat.Mult(v1, temp);
2374 temp += center;
2375 v1(0) = 1.0; v1(1) = -1.0; v1(2) = 1.0;
2376 temp.SetDataAndSize(obbV.GetData() + e*nve*dim + 15, dim);
2377 Amat.Mult(v1, temp);
2378 temp += center;
2379 v1(0) = 1.0; v1(1) = 1.0; v1(2) = 1.0;
2380 temp.SetDataAndSize(obbV.GetData() + e*nve*dim + 18, dim);
2381 Amat.Mult(v1, temp);
2382 temp += center;
2383 v1(0) = -1.0; v1(1) = 1.0; v1(2) = 1.0;
2384 temp.SetDataAndSize(obbV.GetData() + e*nve*dim + 21, dim);
2385 Amat.Mult(v1, temp);
2386 temp += center;
2387 }
2388 }
2389 else // dim = 2
2390 {
2391 for (int e = 0; e < nel; e++)
2392 {
2393 auto box = findptsData2->local.obb[e];
2394 double *Ad = obbA.GetData(e);
2395 for (int d = 0; d < dim; d++)
2396 {
2397 obbC(e*dim + d) = box.c0[d];
2398 }
2399 for (int i = 0; i < dim; i++)
2400 {
2401 for (int j = 0; j < dim; j++)
2402 {
2403 Ad[i*dim + j] = box.A[i + j*dim]; // GSLIB uses row-major storage
2404 }
2405 }
2406
2407 DenseMatrix Amat = obbA(e);
2408 Amat.Invert();
2409 Vector center(obbC.GetData() + e*dim, dim);
2410
2411 Vector v1(dim);
2412 Vector temp;
2413 v1(0) = -1.0; v1(1) = -1.0;
2414 temp.SetDataAndSize(obbV.GetData() + e*nve*dim + 0, dim);
2415 Amat.Mult(v1, temp);
2416 temp += center;
2417 v1(0) = 1.0; v1(1) = -1.0;
2418 temp.SetDataAndSize(obbV.GetData() + e*nve*dim + 2, dim);
2419 Amat.Mult(v1, temp);
2420 temp += center;
2421 v1(0) = 1.0; v1(1) = 1.0;
2422 temp.SetDataAndSize(obbV.GetData() + e*nve*dim + 4, dim);
2423 Amat.Mult(v1, temp);
2424 temp += center;
2425 v1(0) = -1.0; v1(1) = 1.0;
2426 temp.SetDataAndSize(obbV.GetData() + e*nve*dim + 6, dim);
2427 Amat.Mult(v1, temp);
2428 temp += center;
2429 }
2430 }
2431}
2432
2433void OversetFindPointsGSLIB::Setup(Mesh &m, const int meshid,
2434 GridFunction *gfmax,
2435 const double bb_t, const double newt_tol,
2436 const int npt_max)
2437{
2438 MFEM_VERIFY(m.GetNodes() != NULL, "Mesh nodes are required.");
2439 const int meshOrder = m.GetNodes()->FESpace()->GetMaxElementOrder();
2440 const int gfOrder = gfmax ? gfmax->FESpace()->GetMaxElementOrder() :
2441 meshOrder;
2442 MFEM_VERIFY(meshOrder == gfOrder,
2443 "Mesh order must match gfmax order in OversetFindPointsGSLIB.");
2444
2445 // FreeData if OversetFindPointsGSLIB::Setup has been called already
2446 if (setupflag) { FreeData(); }
2447
2448 mesh = &m;
2449 dim = mesh->Dimension();
2451 unsigned dof1D = fe->GetOrder() + 1;
2452
2454
2456
2457 MFEM_ASSERT(meshid>=0, " The ID should be greater than or equal to 0.");
2458
2459 const int pts_cnt = gsl_mesh.Size()/dim,
2460 NEtot = pts_cnt/(int)pow(dof1D, dim);
2461
2462 distfint.SetSize(pts_cnt);
2463 if (!gfmax)
2464 {
2465 distfint = 0.0;
2466 }
2467 else
2468 {
2469 GetNodalValues(gfmax, distfint);
2470 }
2471 u_meshid = (unsigned int)meshid;
2472
2473 if (dim == 2)
2474 {
2475 unsigned nr[2] = { dof1D, dof1D };
2476 unsigned mr[2] = { 2*dof1D, 2*dof1D };
2477 double * const elx[2] =
2478 {
2479 pts_cnt == 0 ? nullptr : &gsl_mesh(0),
2480 pts_cnt == 0 ? nullptr : &gsl_mesh(pts_cnt)
2481 };
2482 fdataD = findptsms_setup_2(gsl_comm, elx, nr, NEtot, mr, bb_t,
2483 pts_cnt, pts_cnt, npt_max, newt_tol,
2484 &u_meshid, &distfint(0));
2485 }
2486 else
2487 {
2488 unsigned nr[3] = { dof1D, dof1D, dof1D };
2489 unsigned mr[3] = { 2*dof1D, 2*dof1D, 2*dof1D };
2490 double * const elx[3] =
2491 {
2492 pts_cnt == 0 ? nullptr : &gsl_mesh(0),
2493 pts_cnt == 0 ? nullptr : &gsl_mesh(pts_cnt),
2494 pts_cnt == 0 ? nullptr : &gsl_mesh(2*pts_cnt)
2495 };
2496 fdataD = findptsms_setup_3(gsl_comm, elx, nr, NEtot, mr, bb_t,
2497 pts_cnt, pts_cnt, npt_max, newt_tol,
2498 &u_meshid, &distfint(0));
2499 }
2500 setupflag = true;
2501 overset = true;
2502}
2503
2505 Array<unsigned int> &point_id,
2506 int point_pos_ordering)
2507{
2508 MFEM_VERIFY(setupflag, "Use OversetFindPointsGSLIB::Setup before "
2509 "finding points.");
2510 MFEM_VERIFY(overset, "Please use OversetFindPoints for overlapping grids.");
2511 points_cnt = point_pos.Size() / dim;
2512 unsigned int match = 0; // Don't find points in the mesh if point_id=mesh_id
2513
2519
2520 auto xvFill = [&](const double *xv_base[], unsigned xv_stride[])
2521 {
2522 for (int d = 0; d < dim; d++)
2523 {
2524 if (point_pos_ordering == Ordering::byNODES)
2525 {
2526 xv_base[d] = point_pos.GetData() + d*points_cnt;
2527 xv_stride[d] = sizeof(double);
2528 }
2529 else
2530 {
2531 xv_base[d] = point_pos.GetData() + d;
2532 xv_stride[d] = dim*sizeof(double);
2533 }
2534 }
2535 };
2536 if (dim == 2)
2537 {
2538 auto *findptsData = (gslib::findpts_data_2 *)this->fdataD;
2539 const double *xv_base[2];
2540 unsigned xv_stride[2];
2541 xvFill(xv_base, xv_stride);
2542 findptsms_2(gsl_code.GetData(), sizeof(unsigned int),
2543 gsl_proc.GetData(), sizeof(unsigned int),
2544 gsl_elem.GetData(), sizeof(unsigned int),
2545 gsl_ref.GetData(), sizeof(double) * dim,
2546 gsl_dist.GetData(), sizeof(double),
2547 xv_base, xv_stride,
2548 point_id.GetData(), sizeof(unsigned int), &match,
2549 points_cnt, findptsData);
2550 }
2551 else // dim == 3
2552 {
2553 auto *findptsData = (gslib::findpts_data_3 *)this->fdataD;
2554 const double *xv_base[3];
2555 unsigned xv_stride[3];
2556 xvFill(xv_base, xv_stride);
2557 findptsms_3(gsl_code.GetData(), sizeof(unsigned int),
2558 gsl_proc.GetData(), sizeof(unsigned int),
2559 gsl_elem.GetData(), sizeof(unsigned int),
2560 gsl_ref.GetData(), sizeof(double) * dim,
2561 gsl_dist.GetData(), sizeof(double),
2562 xv_base, xv_stride,
2563 point_id.GetData(), sizeof(unsigned int), &match,
2564 points_cnt, findptsData);
2565 }
2566
2567 // Set the element number and reference position to 0 for points not found
2568 for (int i = 0; i < points_cnt; i++)
2569 {
2570 if (gsl_code[i] == 2 ||
2571 (gsl_code[i] == 1 && gsl_dist(i) > bdr_tol))
2572 {
2573 gsl_elem[i] = 0;
2574 for (int d = 0; d < dim; d++) { gsl_ref(i*dim + d) = -1.; }
2575 gsl_code[i] = 2;
2576 }
2577 }
2578
2579 // Map element number for simplices, and ref_pos from [-1,1] to [0,1] for both
2580 // simplices and quads.
2582}
2583
2585 Array<unsigned int> &point_id,
2586 const GridFunction &field_in,
2587 Vector &field_out,
2588 int point_pos_ordering)
2589{
2590 FindPoints(point_pos, point_id, point_pos_ordering);
2591 Interpolate(field_in, field_out);
2592}
2593
2595{
2596 gsl_comm = new gslib::comm;
2597 cr = new gslib::crystal;
2598#ifdef MFEM_USE_MPI
2599 int initialized;
2600 MPI_Initialized(&initialized);
2601 if (!initialized) { MPI_Init(NULL, NULL); }
2602 MPI_Comm comm = MPI_COMM_WORLD;
2603 comm_init(gsl_comm, comm);
2604#else
2605 comm_init(gsl_comm, 0);
2606#endif
2607 crystal_init(cr, gsl_comm);
2608 UpdateIdentifiers(ids);
2609}
2610
2611#ifdef MFEM_USE_MPI
2613 : cr(NULL), gsl_comm(NULL)
2614{
2615 gsl_comm = new gslib::comm;
2616 cr = new gslib::crystal;
2617 comm_init(gsl_comm, comm_);
2618 crystal_init(cr, gsl_comm);
2619 UpdateIdentifiers(ids);
2620}
2621#endif
2622
2624{
2625 crystal_free(cr);
2626 gslib_gs_free(gsl_data);
2627 comm_free(gsl_comm);
2628 delete gsl_comm;
2629 delete cr;
2630}
2631
2633{
2634 long long minval = ids.Min();
2635#ifdef MFEM_USE_MPI
2636 MPI_Allreduce(MPI_IN_PLACE, &minval, 1, MPI_LONG_LONG_INT,
2637 MPI_MIN, gsl_comm->c);
2638#endif
2639 MFEM_VERIFY(minval >= 0, "Unique identifier cannot be negative.");
2640 if (gsl_data != NULL) { gslib_gs_free(gsl_data); }
2641 num_ids = ids.Size();
2642 gsl_data = gslib_gs_setup(ids.GetData(),
2643 ids.Size(),
2644 gsl_comm, 0,
2645 gslib::gs_crystal_router, 0);
2646}
2647
2648void GSOPGSLIB::GS(Vector &senddata, GSOp op)
2649{
2650 MFEM_VERIFY(senddata.Size() == num_ids,
2651 "Incompatible setup and GOP operation.");
2652 if (op == GSOp::ADD)
2653 {
2654 gslib_gs(senddata.GetData(),gslib::gs_double,gslib::gs_add,0,gsl_data,0);
2655 }
2656 else if (op == GSOp::MUL)
2657 {
2658 gslib_gs(senddata.GetData(),gslib::gs_double,gslib::gs_mul,0,gsl_data,0);
2659 }
2660 else if (op == GSOp::MAX)
2661 {
2662 gslib_gs(senddata.GetData(),gslib::gs_double,gslib::gs_max,0,gsl_data,0);
2663 }
2664 else if (op == GSOp::MIN)
2665 {
2666 gslib_gs(senddata.GetData(),gslib::gs_double,gslib::gs_min,0,gsl_data,0);
2667 }
2668 else
2669 {
2670 MFEM_ABORT("Invalid GSOp operation.");
2671 }
2672}
2673
2674} // namespace mfem
2675#undef CODE_INTERNAL
2676#undef CODE_BORDER
2677#undef CODE_NOT_FOUND
2678
2679#endif // MFEM_USE_GSLIB
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition array.hpp:385
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:840
T Min() const
Find the minimal element in the array, using the comparison operator < for class T.
Definition array.cpp:86
int Size() const
Return the logical size of the array.
Definition array.hpp:166
void DeleteAll()
Delete the whole array.
Definition array.hpp:1033
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:912
T * GetData()
Returns the data.
Definition array.hpp:140
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
Definition array.hpp:401
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
Definition array.hpp:393
@ GaussLobatto
Closed type.
Definition fe_base.hpp:36
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
void Mult(const real_t *x, real_t *y) const
Matrix vector multiplication.
Definition densemat.cpp:108
real_t * Data() const
Returns the matrix data array. Warning: this method casts away constness.
Definition densemat.hpp:122
void Invert()
Replaces the current matrix with its inverse.
Definition densemat.cpp:674
Rank 3 tensor (array of matrices)
void SetSize(int i, int j, int k, MemoryType mt_=MemoryType::PRESERVE)
real_t * GetData(int k)
static MemoryType GetMemoryType()
(DEPRECATED) Equivalent to GetDeviceMemoryType().
Definition device.hpp:281
static bool IsEnabled()
Return true if any backend other than Backend::CPU is enabled.
Definition device.hpp:247
Geometry::Type GetGeometryType() const
Definition element.hpp:55
FindPointsGSLIB can robustly evaluate a GridFunction on an arbitrary collection of points....
Definition gslib.hpp:73
virtual void DistributePointInfoToOwningMPIRanks(Array< unsigned int > &recv_elem, Vector &recv_ref, Array< unsigned int > &recv_code)
Definition gslib.cpp:2135
struct mfem::FindPointsGSLIB::@24 DEV
virtual ~FindPointsGSLIB()
Definition gslib.cpp:127
void FindPointsOnDevice(const Vector &point_pos, int point_pos_ordering=Ordering::byNODES)
Definition gslib.cpp:484
Array< unsigned int > gsl_code
Definition gslib.hpp:90
Array< Mesh * > mesh_split
Definition gslib.hpp:79
void InterpolateLocal2(const Vector &field_in, Array< int > &gsl_elem_dev_l, Vector &gsl_ref_l, Vector &field_out, int npt, int ncomp, int nel, int dof1dsol)
void FindPoints(const Vector &point_pos, int point_pos_ordering=Ordering::byNODES)
Definition gslib.cpp:236
void GetAxisAlignedBoundingBoxes(Vector &aabb)
Definition gslib.cpp:2249
void FindPointsLocal3(const Vector &point_pos, int point_pos_ordering, Array< unsigned int > &gsl_code_dev_l, Array< unsigned int > &gsl_elem_dev_l, Vector &gsl_ref_l, Vector &gsl_dist_l, int npt)
void Setup(Mesh &m, const double bb_t=0.1, const double newt_tol=1.0e-12, const int npt_max=256)
Definition gslib.cpp:183
virtual void Interpolate(const GridFunction &field_in, Vector &field_out)
Definition gslib.cpp:1759
virtual void InterpolateH1(const GridFunction &field_in, Vector &field_out)
Use GSLIB for communication and interpolation.
Definition gslib.cpp:1885
Array< FiniteElementSpace * > fes_rst_map
Definition gslib.hpp:83
virtual void GetNodalValues(const GridFunction *gf_in, Vector &node_vals)
Get GridFunction value at the points expected by GSLIB.
Definition gslib.cpp:1472
Array< int > split_element_index
Definition gslib.hpp:97
FiniteElementCollection * fec_map_lin
Definition gslib.hpp:85
virtual void DistributeInterpolatedValues(const Vector &int_vals, const int vdim, const int ordering, Vector &field_out) const
Definition gslib.cpp:2194
struct gslib::comm * gsl_comm
Definition gslib.hpp:88
void InterpolateLocal3(const Vector &field_in, Array< int > &gsl_elem_dev_l, Vector &gsl_ref_l, Vector &field_out, int npt, int ncomp, int nel, int dof1dsol)
Array< unsigned int > gsl_elem
Definition gslib.hpp:90
Array< unsigned int > recv_proc
Definition gslib.hpp:92
virtual void SetupSplitMeshesAndIntegrationRules(const int order)
Definition gslib.cpp:1399
Array< unsigned int > gsl_proc
Definition gslib.hpp:90
virtual void SetupIntegrationRuleForSplitMesh(Mesh *mesh, IntegrationRule *irule, int order)
Definition gslib.cpp:1351
Array< unsigned int > gsl_mfem_elem
Definition gslib.hpp:90
Array< IntegrationRule * > ir_split
Definition gslib.hpp:82
double default_interp_value
Definition gslib.hpp:94
virtual void SetupSplitMeshes()
Definition gslib.cpp:1159
virtual void MapRefPosAndElemIndices()
Definition gslib.cpp:1582
virtual void FreeData()
Definition gslib.cpp:1123
Array< unsigned int > GetPointsNotFoundIndices() const
Get array of indices of not-found points.
Definition gslib.cpp:2122
virtual void InterpolateGeneral(const GridFunction &field_in, Vector &field_out)
Definition gslib.cpp:1961
Array< GridFunction * > gf_rst_map
Definition gslib.hpp:84
Array< int > split_element_map
Definition gslib.hpp:96
void GetOrientedBoundingBoxes(DenseTensor &obbA, Vector &obbC, Vector &obbV)
Definition gslib.cpp:2319
void InterpolateOnDevice(const Vector &field_in_evec, Vector &field_out, const int nel, const int ncomp, const int dof1dsol, const int ordering)
Definition gslib.cpp:851
Array< unsigned int > recv_index
Definition gslib.hpp:92
void FindPointsLocal2(const Vector &point_pos, int point_pos_ordering, Array< unsigned int > &gsl_code_dev_l, Array< unsigned int > &gsl_elem_dev_l, Vector &gsl_ref_l, Vector &gsl_dist_l, int npt)
struct gslib::crystal * cr
Definition gslib.hpp:87
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:208
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition fespace.hpp:678
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for the i'th element. The returned indices are offsets into an ...
Definition fespace.cpp:304
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Definition fespace.cpp:3824
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:854
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition fespace.cpp:1480
virtual void Update(bool want_transform=true)
Reflect changes in the mesh: update number of DOFs, etc. Also, calculate GridFunction transformation ...
Definition fespace.cpp:4146
int GetElementOrder(int i) const
Returns the order of the i'th finite element.
Definition fespace.cpp:193
void SetElementOrder(int i, int p)
Sets the order of the i'th finite element.
Definition fespace.cpp:168
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:856
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:819
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Definition fespace.cpp:3860
virtual int GetMaxElementOrder() const
Return the maximum polynomial order over all elements.
Definition fespace.hpp:674
Abstract class for all finite elements.
Definition fe_base.hpp:247
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition fe_base.hpp:341
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition fe_base.hpp:334
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:337
struct gslib::comm * gsl_comm
Definition gslib.hpp:490
void GS(Vector &senddata, GSOp op)
Definition gslib.cpp:2648
GSOPGSLIB(Array< long long > &ids)
Definition gslib.cpp:2594
virtual ~GSOPGSLIB()
Definition gslib.cpp:2623
GSOp
Supported operation types. See class description.
Definition gslib.hpp:504
struct gslib::crystal * cr
Definition gslib.hpp:489
struct gslib::gs_data * gsl_data
Definition gslib.hpp:491
void UpdateIdentifiers(const Array< long long > &ids)
Definition gslib.cpp:2632
static bool CheckPoint(int GeomType, const IntegrationPoint &ip)
Check if the given point is inside the given reference element.
Definition geom.cpp:435
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:32
virtual real_t GetValue(int i, const IntegrationPoint &ip, int vdim=1) const
Definition gridfunc.cpp:449
FiniteElementSpace * FESpace()
void ProjectDiscCoefficient(VectorCoefficient &coeff, Array< int > &dof_attr)
int VectorDim() const
Shortcut for calling FiniteElementSpace::GetVectorDim() on the underlying fes.
Definition gridfunc.cpp:347
virtual void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const
Definition gridfunc.cpp:474
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:279
int GetBasisType() const
Definition fe_coll.hpp:305
Class for integration point with weight.
Definition intrules.hpp:35
void Set2(const real_t x1, const real_t x2)
Definition intrules.hpp:89
void Set3(const real_t x1, const real_t x2, const real_t x3)
Definition intrules.hpp:79
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:256
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:259
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:350
Mesh data type.
Definition mesh.hpp:65
Element::Type GetElementType(int i) const
Returns the type of element i.
Definition mesh.cpp:7962
const FiniteElementSpace * GetNodalFESpace() const
Definition mesh.cpp:6794
const Element * GetElement(int i) const
Return pointer to the i'th element object.
Definition mesh.hpp:1434
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1377
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1309
static Mesh MakeCartesian3D(int nx, int ny, int nz, Element::Type type, real_t sx=1.0, real_t sy=1.0, real_t sz=1.0, bool sfc_ordering=true)
Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into nx*ny*nz hexahedra if type =...
Definition mesh.cpp:4627
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:9627
virtual void SetNodalFESpace(FiniteElementSpace *nfes)
Definition mesh.cpp:6741
static Mesh MakeCartesian2D(int nx, int ny, Element::Type type, bool generate_edges=false, real_t sx=1.0, real_t sy=1.0, bool sfc_ordering=true)
Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny quadrilaterals if type = QUADRILATER...
Definition mesh.cpp:4617
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition mesh.cpp:7558
static bool IsFinalized()
Return true if MPI has been finalized.
Abstract operator.
Definition operator.hpp:25
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
void Setup(Mesh &m, const int meshid, GridFunction *gfmax=NULL, const double bb_t=0.1, const double newt_tol=1.0e-12, const int npt_max=256)
Definition gslib.cpp:2433
void Interpolate(const Vector &point_pos, Array< unsigned int > &point_id, const GridFunction &field_in, Vector &field_out, int point_pos_ordering=Ordering::byNODES)
Definition gslib.cpp:2584
void FindPoints(const Vector &point_pos, Array< unsigned int > &point_id, int point_pos_ordering=Ordering::byNODES)
Definition gslib.cpp:2504
Class for parallel meshes.
Definition pmesh.hpp:34
const Array< int > & GetDofMap() const
Get an Array<int> that maps lexicographically ordered indices to the indices of the respective nodes/...
Definition fe_base.hpp:1276
Vector coefficient defined by a vector GridFunction.
Vector data type.
Definition vector.hpp:82
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:524
void SetDataAndSize(real_t *d, int s)
Set the Vector data and size.
Definition vector.hpp:191
void Destroy()
Destroy a vector.
Definition vector.hpp:673
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition vector.hpp:145
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:584
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:532
void NewDataAndSize(real_t *d, int s)
Set the Vector data and size, deleting the old data, if owned.
Definition vector.hpp:197
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:243
virtual real_t * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:540
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:676
int dim
Definition ex24.cpp:53
int index(int i, int j, int nx, int ny)
Definition life.cpp:236
ulong hash_index_2(const gslib::hash_data_2 *p, const double x[2])
Definition gslib.cpp:358
ulong hash_index_3(const gslib::hash_data_3 *p, const double x[3])
Definition gslib.cpp:348
slong lfloor(double x)
Definition gslib.cpp:338
const T & AsConst(const T &a)
Utility function similar to std::as_const in c++17.
Definition array.hpp:424
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition fespace.hpp:47
ulong hash_index_aux(double low, double fac, ulong n, double x)
Definition gslib.cpp:341
real_t p(const Vector &x, real_t t)
std::array< int, NCMesh::MaxFaceNodes > nodes