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