12 #include "../config/config.hpp"
17 #include "../general/sort_pairs.hpp"
18 #include "../mesh/mesh_headers.hpp"
34 MPI_Comm_size(MyComm, &NRanks);
35 MPI_Comm_rank(MyComm, &MyRank);
57 void ParFiniteElementSpace::Construct()
72 ConstructTrueNURBSDofs();
73 GenerateGlobalOffsets();
78 GenerateGlobalOffsets();
83 GetParallelConformingInterpolation();
87 void ParFiniteElementSpace::GetGroupComm(
88 GroupCommunicator &gc,
int ldof_type, Array<int> *ldof_sign)
95 int group_ldof_counter;
96 Table &group_ldof = gc.GroupLDofTable();
109 group_ldof_counter = 0;
110 for (gr = 1; gr < ng; gr++)
113 group_ldof_counter += ned * pmesh->
GroupNEdges(gr);
114 group_ldof_counter += nfd * pmesh->
GroupNFaces(gr);
118 group_ldof_counter *=
vdim;
121 group_ldof.SetDims(ng, group_ldof_counter);
124 group_ldof_counter = 0;
125 group_ldof.GetI()[0] = group_ldof.GetI()[1] = 0;
126 for (gr = 1; gr < ng; gr++)
128 int j, k, l, m, o, nv, ne, nf;
138 for (j = 0; j < nv; j++)
144 for (l = 0; l < nvd; l++, m++)
154 for (l = 0; l < dofs.Size(); l++)
156 group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
164 for (j = 0; j < ne; j++)
171 for (l = 0; l < ned; l++)
174 dofs[l] = m + (-1-ind[l]);
177 (*ldof_sign)[dofs[l]] = -1;
182 dofs[l] = m + ind[l];
190 for (l = 0; l < dofs.Size(); l++)
192 group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
200 for (j = 0; j < nf; j++)
208 for (l = 0; l < nfd; l++)
211 dofs[l] = m + (-1-ind[l]);
214 (*ldof_sign)[dofs[l]] = -1;
219 dofs[l] = m + ind[l];
227 for (l = 0; l < dofs.Size(); l++)
229 group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
234 group_ldof.GetI()[gr+1] = group_ldof_counter;
240 void ParFiniteElementSpace::ApplyLDofSigns(Array<int> &dofs)
const
242 for (
int i = 0; i < dofs.Size(); i++)
246 if (ldof_sign[-1-dofs[i]] < 0)
248 dofs[i] = -1-dofs[i];
253 if (ldof_sign[dofs[i]] < 0)
255 dofs[i] = -1-dofs[i];
271 ApplyLDofSigns(dofs);
285 ApplyLDofSigns(dofs);
294 ApplyLDofSigns(dofs);
302 MFEM_ASSERT(0 <= ei && ei < pmesh->GroupNEdges(group),
"invalid edge index");
303 pmesh->
GroupEdge(group, ei, l_edge, ori);
313 for (
int i = 0; i < dofs.
Size(); i++)
315 const int di = dofs[i];
316 dofs[i] = (di >= 0) ? rdofs[di] : -1-rdofs[-1-di];
325 MFEM_ASSERT(0 <= fi && fi < pmesh->GroupNFaces(group),
"invalid face index");
326 pmesh->
GroupFace(group, fi, l_face, ori);
336 for (
int i = 0; i < dofs.
Size(); i++)
338 const int di = dofs[i];
339 dofs[i] = (di >= 0) ? rdofs[di] : -1-rdofs[-1-di];
344 void ParFiniteElementSpace::GenerateGlobalOffsets()
354 if (HYPRE_AssumedPartitionCheck())
359 GroupTopology > = GetGroupTopo();
360 int nsize = gt.GetNumNeighbors()-1;
361 MPI_Request *requests =
new MPI_Request[2*nsize];
362 MPI_Status *statuses =
new MPI_Status[2*nsize];
363 tdof_nb_offsets.
SetSize(nsize+1);
364 tdof_nb_offsets[0] = tdof_offsets[0];
366 int request_counter = 0;
368 for (
int i = 1; i <= nsize; i++)
370 MPI_Irecv(&tdof_nb_offsets[i], 1, HYPRE_MPI_INT,
371 gt.GetNeighborRank(i), 5365, MyComm,
372 &requests[request_counter++]);
374 for (
int i = 1; i <= nsize; i++)
376 MPI_Isend(&tdof_nb_offsets[0], 1, HYPRE_MPI_INT,
377 gt.GetNeighborRank(i), 5365, MyComm,
378 &requests[request_counter++]);
380 MPI_Waitall(request_counter, requests, statuses);
392 void ParFiniteElementSpace::Build_Dof_TrueDof_Matrix()
398 GetParallelConformingInterpolation();
405 HYPRE_Int *i_diag =
new HYPRE_Int[ldof+1];
406 HYPRE_Int *j_diag =
new HYPRE_Int[ltdof];
409 HYPRE_Int *i_offd =
new HYPRE_Int[ldof+1];
410 HYPRE_Int *j_offd =
new HYPRE_Int[ldof-ltdof];
413 HYPRE_Int *cmap =
new HYPRE_Int[ldof-ltdof];
418 Array<Pair<HYPRE_Int, int> > cmap_j_offd(ldof-ltdof);
420 i_diag[0] = i_offd[0] = 0;
421 diag_counter = offd_counter = 0;
422 for (
int i = 0; i < ldof; i++)
427 j_diag[diag_counter++] = ltdof;
432 cmap_j_offd[offd_counter].two = offd_counter;
435 i_diag[i+1] = diag_counter;
436 i_offd[i+1] = offd_counter;
439 SortPairs<HYPRE_Int, int>(cmap_j_offd, offd_counter);
441 for (
int i = 0; i < offd_counter; i++)
443 cmap[i] = cmap_j_offd[i].one;
444 j_offd[cmap_j_offd[i].two] = i;
447 P =
new HypreParMatrix(MyComm, MyRank, NRanks, row_starts, col_starts,
448 i_diag, j_diag, i_offd, j_offd, cmap, offd_counter);
459 MFEM_ABORT(
"Not implemented for NC mesh.");
464 for (
int i = 0; i < ldof_group.
Size(); i++)
482 gc->
Create(pNURBSext()->ldof_group);
486 GetGroupComm(*gc, 0);
495 MFEM_ABORT(
"Not implemented for NC mesh.");
500 mfem_error(
"ParFiniteElementSpace::Synchronize");
505 gcomm->
Bcast(ldof_marker);
537 return ldof_ltdof[ldof];
541 if (GetGroupTopo().IAmMaster(ldof_group[ldof]))
543 return ldof_ltdof[ldof];
556 MFEM_VERIFY(ldof_ltdof[ldof] >= 0,
"ldof " << ldof <<
" not a true DOF.");
562 if (HYPRE_AssumedPartitionCheck())
564 return ldof_ltdof[ldof] +
569 return ldof_ltdof[ldof] +
579 MFEM_ABORT(
"Not implemented for NC mesh.");
582 if (HYPRE_AssumedPartitionCheck())
586 return ldof_ltdof[sldof] +
588 ldof_group[sldof])] /
vdim;
592 return (ldof_ltdof[sldof*
vdim] +
593 tdof_nb_offsets[GetGroupTopo().GetGroupMaster(
600 return ldof_ltdof[sldof] +
602 ldof_group[sldof])] /
vdim;
606 return (ldof_ltdof[sldof*
vdim] +
607 tdof_offsets[GetGroupTopo().GetGroupMasterRank(
614 return HYPRE_AssumedPartitionCheck() ? dof_offsets[0] : dof_offsets[MyRank];
619 return HYPRE_AssumedPartitionCheck()? tdof_offsets[0] : tdof_offsets[MyRank];
630 if (num_face_nbrs == 0)
636 MPI_Request *requests =
new MPI_Request[2*num_face_nbrs];
637 MPI_Request *send_requests = requests;
638 MPI_Request *recv_requests = requests + num_face_nbrs;
639 MPI_Status *statuses =
new MPI_Status[num_face_nbrs];
645 Table send_nbr_elem_dof;
652 for (
int fn = 0; fn < num_face_nbrs; fn++)
657 for (
int i = 0; i < num_my_elems; i++)
660 for (
int j = 0; j < ldofs.
Size(); j++)
661 if (ldof_marker[ldofs[j]] != fn)
663 ldof_marker[ldofs[j]] = fn;
672 MyComm, &send_requests[fn]);
675 MyComm, &recv_requests[fn]);
678 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
683 MPI_Waitall(num_face_nbrs, send_requests, statuses);
691 int *send_I = send_nbr_elem_dof.
GetI();
693 for (
int fn = 0; fn < num_face_nbrs; fn++)
697 MPI_Isend(send_I + send_el_off[fn], send_el_off[fn+1] - send_el_off[fn],
698 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
700 MPI_Irecv(recv_I + recv_el_off[fn], recv_el_off[fn+1] - recv_el_off[fn],
701 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
704 MPI_Waitall(num_face_nbrs, send_requests, statuses);
705 send_nbr_elem_dof.
MakeJ();
709 for (
int fn = 0; fn < num_face_nbrs; fn++)
714 for (
int i = 0; i < num_my_elems; i++)
717 for (
int j = 0; j < ldofs.
Size(); j++)
719 if (ldof_marker[ldofs[j]] != fn)
721 ldof_marker[ldofs[j]] = fn;
726 send_el_off[fn] + i, ldofs, ldofs.
Size());
733 int *send_J = send_nbr_elem_dof.
GetJ();
734 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
738 int j_end = send_I[send_el_off[fn+1]];
740 for (
int i = 0; i < num_ldofs; i++)
742 ldof_marker[ldofs[i]] = i;
745 for ( ; j < j_end; j++)
747 send_J[j] = ldof_marker[send_J[j]];
751 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
758 for (
int fn = 0; fn < num_face_nbrs; fn++)
763 MPI_Isend(send_J + send_I[send_el_off[fn]],
764 send_I[send_el_off[fn+1]] - send_I[send_el_off[fn]],
765 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
767 MPI_Irecv(recv_J + recv_I[recv_el_off[fn]],
768 recv_I[recv_el_off[fn+1]] - recv_I[recv_el_off[fn]],
769 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
772 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
775 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
778 int j_end = recv_I[recv_el_off[fn+1]];
780 for ( ; j < j_end; j++)
786 MPI_Waitall(num_face_nbrs, send_requests, statuses);
791 for (
int fn = 0; fn < num_face_nbrs; fn++)
798 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
802 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
805 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
806 MPI_Waitall(num_face_nbrs, send_requests, statuses);
813 for (
int fn = 0; fn < num_face_nbrs; fn++)
818 MPI_Isend(&my_dof_offset, 1, HYPRE_MPI_INT, nbr_rank, tag,
819 MyComm, &send_requests[fn]);
821 MPI_Irecv(&dof_face_nbr_offsets[fn], 1, HYPRE_MPI_INT, nbr_rank, tag,
822 MyComm, &recv_requests[fn]);
825 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
829 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
836 MPI_Waitall(num_face_nbrs, send_requests, statuses);
854 int el1, el2, inf1, inf2;
867 Ordering::DofsToVDofs<Ordering::byNODES>(nd/
vdim,
vdim, vdofs);
869 for (
int j = 0; j < vdofs.
Size(); j++)
871 const int ldof = vdofs[j];
872 vdofs[j] = (ldof >= 0) ? vol_vdofs[ldof] : -1-vol_vdofs[-1-ldof];
884 mfem_error(
"ParFiniteElementSpace::GetFaceNbrFE"
885 " does not support NURBS!");
901 hypre_ParCSRMatrix *csrP = (hypre_ParCSRMatrix*)(*P);
902 hypre_ParCSRMatrixOwnsRowStarts(csrP) = 1;
903 hypre_ParCSRMatrixOwnsColStarts(csrP) = 1;
909 void ParFiniteElementSpace::ConstructTrueDofs()
916 GetGroupComm(*gcomm, 1, &ldof_sign);
926 for (gr = 1; gr < group_ldof.
Size(); gr++)
928 const int *ldofs = group_ldof.
GetRow(gr);
929 const int nldofs = group_ldof.
RowSize(gr);
930 for (i = 0; i < nldofs; i++)
932 ldof_group[ldofs[i]] = gr;
937 for (i = 0; i < nldofs; i++)
939 ldof_ltdof[ldofs[i]] = -2;
946 for (i = 0; i < n; i++)
948 if (ldof_ltdof[i] == -1)
950 ldof_ltdof[i] = ltdof_size++;
955 gcomm->
Bcast(ldof_ltdof);
958 void ParFiniteElementSpace::ConstructTrueNURBSDofs()
961 GroupTopology > = pNURBSext()->
gtopo;
962 gcomm =
new GroupCommunicator(gt);
967 ldof_group.
MakeRef(pNURBSext()->ldof_group);
971 const int *scalar_ldof_group = pNURBSext()->
ldof_group;
973 for (
int i = 0; i < n; i++)
975 ldof_group[i] = scalar_ldof_group[
VDofToDof(i)];
979 gcomm->
Create(ldof_group);
983 ldof_sign.DeleteAll();
987 for (
int i = 0; i < n; i++)
989 if (gt.IAmMaster(ldof_group[i]))
991 ldof_ltdof[i] = ltdof_size;
1001 gcomm->
Bcast(ldof_ltdof);
1006 return (dof >= 0) ? (sign = 1, dof) : (sign = -1, (-1 - dof));
1024 if (pm.
Width() == 2)
1028 for (i = 0; i < 2; i++)
1030 if (pm(0, i) == 0.0 || pm(0, i) == 1.0)
1032 for (k = 0; k < nv; k++) { slave_dofs[i*nv + k] =
INVALID_DOF; }
1039 MFEM_ASSERT(pm.
Width() == 4,
"");
1042 for (i = 0; i < 4; i++)
1044 double x = pm(0,i), y = pm(1,i);
1045 corner[i] = ((x == 0.0 || x == 1.0) && (y == 0.0 || y == 1.0));
1049 for (i = 0; i < 4; i++)
1053 for (k = 0; k < nv; k++) { slave_dofs[i*nv + k] =
INVALID_DOF; }
1059 for (i = 0; i < 4; i++)
1061 if (corner[i] && corner[(i+1) % 4])
1063 for (k = 0; k < ne; k++)
1073 void ParFiniteElementSpace
1074 ::AddSlaveDependencies(DepList deps[],
int master_rank,
1075 const Array<int> &master_dofs,
int master_ndofs,
1076 const Array<int> &slave_dofs, DenseMatrix& I)
1079 for (
int i = 0; i < slave_dofs.Size(); i++)
1085 for (
int vd = 0; vd <
vdim; vd++)
1090 Array<Dependency> tmp_list;
1091 for (
int j = 0; j < master_dofs.Size(); j++)
1093 double coef = I(i, j);
1094 if (std::abs(coef) > 1e-12)
1097 int mvdof =
DofToVDof(mdof, vd, master_ndofs);
1098 tmp_list.Append(Dependency(master_rank, mvdof, coef*ms*ss));
1102 tmp_list.Copy(dl.list);
1108 void ParFiniteElementSpace
1109 ::Add1To1Dependencies(DepList deps[],
int owner_rank,
1110 const Array<int> &owner_dofs,
int owner_ndofs,
1111 const Array<int> &dependent_dofs)
1113 MFEM_ASSERT(owner_dofs.Size() == dependent_dofs.Size(),
"");
1115 for (
int vd = 0; vd <
vdim; vd++)
1117 for (
int i = 0; i < owner_dofs.Size(); i++)
1119 double osign, dsign;
1121 int ddof =
decode_dof(dependent_dofs[i], dsign);
1124 int ovdof =
DofToVDof(odof, vd, owner_ndofs);
1127 DepList &dl = deps[dvdof];
1131 dl.list.Append(Dependency(owner_rank, ovdof, osign*dsign));
1133 else if (dl.type == 1 && dl.list[0].rank > owner_rank)
1136 dl.list[0] = Dependency(owner_rank, ovdof, osign*dsign);
1142 void ParFiniteElementSpace
1143 ::ReorderFaceDofs(Array<int> &dofs,
int orient)
1153 int ve_dofs = 4*(nv + ne);
1154 for (
int i = 0; i < ve_dofs; i++)
1159 int f_dofs = dofs.Size() - ve_dofs;
1160 for (
int i = 0; i < f_dofs; i++)
1164 dofs[ve_dofs + i] = tmp[ve_dofs + ind[i]];
1168 dofs[ve_dofs + i] = -1 - tmp[ve_dofs + (-1 - ind[i])];
1173 void ParFiniteElementSpace::GetDofs(
int type,
int index, Array<int>& dofs)
1184 void ParFiniteElementSpace::GetParallelConformingInterpolation()
1186 ParNCMesh* pncmesh = pmesh->
pncmesh;
1197 for (
int type = 0; type < 3; type++)
1199 const NCMesh::NCList &list = pncmesh->GetSharedList(type);
1202 int cs = list.conforming.size(), ms = list.masters.size();
1203 for (
int i = 0; i < cs+ms; i++)
1206 const NCMesh::MeshId&
id =
1207 (i < cs) ? (
const NCMesh::MeshId&) list.conforming[i]
1208 : (
const NCMesh::MeshId&) list.masters[i-cs];
1210 int owner = pncmesh->GetOwner(type,
id.index), gsize;
1211 if (owner == MyRank)
1214 GetDofs(type,
id.index, dofs);
1215 const int *group = pncmesh->GetGroup(type,
id.index, gsize);
1216 for (
int j = 0; j < gsize; j++)
1218 if (group[j] != MyRank)
1220 NeighborDofMessage &send_msg = send_dofs[group[j]];
1221 send_msg.Init(pncmesh,
fec,
ndofs);
1222 send_msg.AddDofs(type,
id, dofs);
1229 recv_dofs[owner].Init(pncmesh,
fec, 0);
1242 DepList* deps =
new DepList[num_dofs];
1244 Array<int> master_dofs, slave_dofs;
1245 Array<int> owner_dofs, my_dofs;
1250 for (
int type = 1; type < 3; type++)
1252 const NCMesh::NCList &list = (type > 1) ? pncmesh->GetFaceList()
1253 : pncmesh->GetEdgeList();
1254 if (!list.masters.size()) {
continue; }
1256 IsoparametricTransformation
T;
1262 if (!fe) {
continue; }
1264 DenseMatrix I(fe->GetDof());
1267 for (
unsigned mi = 0; mi < list.masters.size(); mi++)
1269 const NCMesh::Master &mf = list.masters[mi];
1270 if (!pncmesh->RankInGroup(type, mf.index, MyRank)) {
continue; }
1273 int master_ndofs, master_rank = pncmesh->GetOwner(type, mf.index);
1274 if (master_rank == MyRank)
1276 GetDofs(type, mf.index, master_dofs);
1277 master_ndofs =
ndofs;
1281 recv_dofs[master_rank].GetDofs(type, mf, master_dofs,
1285 if (!master_dofs.Size()) {
continue; }
1288 for (
int si = mf.slaves_begin; si < mf.slaves_end; si++)
1290 const NCMesh::Slave &sf = list.slaves[si];
1291 if (pncmesh->IsGhost(type, sf.index)) {
continue; }
1293 GetDofs(type, sf.index, slave_dofs);
1294 if (!slave_dofs.Size()) {
continue; }
1296 sf.OrientedPointMatrix(T.GetPointMat());
1297 fe->GetLocalInterpolation(T, I);
1300 MaskSlaveDofs(slave_dofs, T.GetPointMat(),
fec);
1301 AddSlaveDependencies(deps, master_rank, master_dofs, master_ndofs,
1308 if (master_rank != MyRank && !pncmesh->IsGhost(type, mf.index))
1310 GetDofs(type, mf.index, my_dofs);
1311 Add1To1Dependencies(deps, master_rank, master_dofs, master_ndofs,
1318 for (
int type = 0; type < 3; type++)
1320 const NCMesh::NCList &list = pncmesh->GetSharedList(type);
1321 for (
unsigned i = 0; i < list.conforming.size(); i++)
1323 const NCMesh::MeshId &
id = list.conforming[i];
1324 GetDofs(type,
id.index, my_dofs);
1326 int owner_ndofs, owner = pncmesh->GetOwner(type,
id.index);
1327 if (owner != MyRank)
1329 recv_dofs[owner].GetDofs(type,
id, owner_dofs, owner_ndofs);
1332 int fo = pncmesh->GetFaceOrientation(
id.index);
1333 ReorderFaceDofs(owner_dofs, fo);
1335 Add1To1Dependencies(deps, owner, owner_dofs, owner_ndofs,
1341 Add1To1Dependencies(deps, owner, my_dofs,
ndofs, my_dofs);
1352 NeighborDofMessage::Map::iterator it;
1353 for (it = send_dofs.begin(); it != send_dofs.end(); ++it)
1355 recv_requests[it->first];
1357 for (it = recv_dofs.begin(); it != recv_dofs.end(); ++it)
1359 send_requests[it->first];
1363 for (
int i = 0; i < num_dofs; i++)
1365 const DepList &dl = deps[i];
1366 for (
int j = 0; j < dl.list.Size(); j++)
1368 const Dependency &dep = dl.list[j];
1369 if (dep.rank != MyRank)
1371 send_requests[dep.rank].RequestRow(dep.dof);
1381 for (
int i = 0; i < num_dofs; i++)
1383 if (deps[i].IsTrueDof(MyRank)) { ltdof_size++; }
1386 GenerateGlobalOffsets();
1388 HYPRE_Int glob_true_dofs = tdof_offsets.
Last();
1389 HYPRE_Int glob_cdofs = dof_offsets.
Last();
1393 MFEM_VERIFY(glob_true_dofs >= 0 && glob_true_dofs < (1ll << 31),
1394 "64bit matrix size not supported yet in non-conforming P.");
1396 MFEM_VERIFY(glob_true_dofs >= 0,
1397 "overflow of non-conforming P matrix columns.");
1399 SparseMatrix localP(num_dofs, glob_true_dofs);
1402 R =
new SparseMatrix(ltdof_size, num_dofs);
1404 Array<bool> finalized(num_dofs);
1411 for (
int i = 0, true_dof = 0; i < num_dofs; i++)
1413 if (deps[i].IsTrueDof(MyRank))
1415 localP.Add(i, my_tdof_offset + true_dof, 1.0);
1416 R->
Add(true_dof, i, 1.0);
1417 finalized[i] =
true;
1418 ldof_ltdof[i] = true_dof;
1427 std::list<NeighborRowReply::Map> send_replies;
1431 int num_finalized = ltdof_size;
1439 for (
int dof = 0, i; dof < num_dofs; dof++)
1441 if (finalized[dof]) {
continue; }
1444 const DepList &dl = deps[dof];
1445 for (i = 0; i < dl.list.Size(); i++)
1447 const Dependency &dep = dl.list[i];
1448 if (dep.rank == MyRank)
1450 if (!finalized[dep.dof]) {
break; }
1452 else if (!recv_replies[dep.rank].HaveRow(dep.dof))
1457 if (i < dl.list.Size()) {
continue; }
1460 for (i = 0; i < dl.list.Size(); i++)
1462 const Dependency &dep = dl.list[i];
1463 if (dep.rank == MyRank)
1465 localP.GetRow(dep.dof, cols, srow);
1469 recv_replies[dep.rank].GetRow(dep.dof, cols, srow);
1472 localP.AddRow(dof, cols, srow);
1475 finalized[dof] =
true;
1485 NeighborRowRequest::Map::iterator it;
1486 for (it = recv_requests.begin(); it != recv_requests.end(); ++it)
1488 NeighborRowRequest &req = it->second;
1489 std::set<int>::iterator row;
1490 for (row = req.rows.begin(); row != req.rows.end(); )
1492 if (finalized[*row])
1494 localP.GetRow(*row, cols, srow);
1495 send_replies.back()[it->first].AddRow(*row, cols, srow);
1496 req.rows.erase(row++);
1504 if (num_finalized >= num_dofs) {
break; }
1509 recv_replies[rank].Recv(rank, size, MyComm);
1514 recv_replies[rank].Recv(rank, size, MyComm);
1522 #ifndef HYPRE_BIGINT
1523 P =
new HypreParMatrix(MyComm, num_dofs, glob_cdofs, glob_true_dofs,
1524 localP.GetI(), localP.GetJ(), localP.GetData(),
1528 MFEM_ABORT(
"HYPRE_BIGINT not supported yet.");
1537 for (std::list<NeighborRowReply::Map>::iterator
1538 it = send_replies.begin(); it != send_replies.end(); ++it)
1562 for (
int type = 0; type < 3; type++)
1568 for (
int i = 0; i < cs+ms; i++)
1575 int owner = pncmesh->
GetOwner(type,
id.index), gsize;
1576 if (owner == MyRank)
1579 GetDofs(type,
id.index, dofs);
1580 const int *group = pncmesh->
GetGroup(type,
id.index, gsize);
1581 for (
int j = 0; j < gsize; j++)
1583 if (group[j] != MyRank)
1587 send_msg.
AddDofs(type,
id, dofs);
1594 recv_dofs[owner].Init(pncmesh,
fec, 0);
1607 DepList* deps =
new DepList[num_dofs];
1615 for (
int type = 0; type < 3; type++)
1618 for (
unsigned i = 0; i < list.
conforming.size(); i++)
1621 GetDofs(type,
id.index, my_dofs);
1623 int owner_ndofs, owner = pncmesh->
GetOwner(type,
id.index);
1624 if (owner != MyRank)
1626 recv_dofs[owner].GetDofs(type,
id, owner_dofs, owner_ndofs);
1630 ReorderFaceDofs(owner_dofs, fo);
1632 Add1To1Dependencies(deps, owner, owner_dofs, owner_ndofs,
1638 Add1To1Dependencies(deps, owner, my_dofs,
ndofs, my_dofs);
1649 NeighborDofMessage::Map::iterator it;
1650 for (it = send_dofs.begin(); it != send_dofs.end(); ++it)
1652 recv_requests[it->first];
1654 for (it = recv_dofs.begin(); it != recv_dofs.end(); ++it)
1656 send_requests[it->first];
1660 for (
int i = 0; i < num_dofs; i++)
1662 const DepList &dl = deps[i];
1663 for (
int j = 0; j < dl.list.Size(); j++)
1665 const Dependency &dep = dl.list[j];
1666 if (dep.rank != MyRank)
1668 send_requests[dep.rank].RequestRow(dep.dof);
1677 HYPRE_Int ltdof_sz = 0;
1678 for (
int i = 0; i < num_dofs; i++)
1680 if (deps[i].IsTrueDof(MyRank)) { ltdof_sz++; }
1686 HYPRE_Int glob_true_dofs = tdof_off.
Last();
1687 HYPRE_Int glob_cdofs = dof_offsets.
Last();
1691 MFEM_VERIFY(glob_true_dofs >= 0 && glob_true_dofs < (1ll << 31),
1692 "64bit matrix size not supported yet in non-conforming P.");
1694 MFEM_VERIFY(glob_true_dofs >= 0,
1695 "overflow of non-conforming P matrix columns.");
1704 HYPRE_Int my_tdof_offset = HYPRE_AssumedPartitionCheck() ?
1705 tdof_off[0] : tdof_off[MyRank];
1706 for (
int i = 0, true_dof = 0; i < num_dofs; i++)
1708 if (deps[i].IsTrueDof(MyRank))
1710 localP.
Add(i, my_tdof_offset + true_dof, 1.0);
1711 finalized[i] =
true;
1720 std::list<NeighborRowReply::Map> send_replies;
1724 int num_finalized = ltdof_sz;
1732 for (
int dof = 0, i; dof < num_dofs; dof++)
1734 if (finalized[dof]) {
continue; }
1737 const DepList &dl = deps[dof];
1738 for (i = 0; i < dl.list.Size(); i++)
1740 const Dependency &dep = dl.list[i];
1741 if (dep.rank == MyRank)
1743 if (!finalized[dep.dof]) {
break; }
1745 else if (!recv_replies[dep.rank].HaveRow(dep.dof))
1750 if (i < dl.list.Size()) {
continue; }
1753 for (i = 0; i < dl.list.Size(); i++)
1755 const Dependency &dep = dl.list[i];
1756 if (dep.rank == MyRank)
1758 localP.
GetRow(dep.dof, cols, srow);
1762 recv_replies[dep.rank].GetRow(dep.dof, cols, srow);
1765 localP.
AddRow(dof, cols, srow);
1768 finalized[dof] =
true;
1778 NeighborRowRequest::Map::iterator it;
1779 for (it = recv_requests.begin(); it != recv_requests.end(); ++it)
1782 std::set<int>::iterator row;
1783 for (row = req.
rows.begin(); row != req.
rows.end(); )
1785 if (finalized[*row])
1787 localP.
GetRow(*row, cols, srow);
1788 send_replies.back()[it->first].AddRow(*row, cols, srow);
1789 req.
rows.erase(row++);
1797 if (num_finalized >= num_dofs) {
break; }
1802 recv_replies[rank].Recv(rank, size, MyComm);
1807 recv_replies[rank].Recv(rank, size, MyComm);
1816 #ifndef HYPRE_BIGINT
1817 PP =
new HypreParMatrix(MyComm, num_dofs, glob_cdofs, glob_true_dofs,
1823 MFEM_ABORT(
"HYPRE_BIGINT not supported yet.");
1830 for (std::list<NeighborRowReply::Map>::iterator
1831 it = send_replies.begin(); it != send_replies.end(); ++it)
1839 static HYPRE_Int* make_i_array(
int nrows)
1841 HYPRE_Int *I =
new HYPRE_Int[nrows+1];
1842 for (
int i = 0; i <= nrows; i++) { I[i] = -1; }
1846 static HYPRE_Int* make_j_array(HYPRE_Int* I,
int nrows)
1849 for (
int i = 0; i < nrows; i++)
1851 if (I[i] >= 0) { nnz++; }
1853 HYPRE_Int *J =
new HYPRE_Int[nnz];
1856 for (
int i = 0, k = 0; i <= nrows; i++)
1858 HYPRE_Int col = I[i];
1860 if (col >= 0) { J[k++] = col; }
1866 ParFiniteElementSpace::RebalanceMatrix(
int old_ndofs,
1867 const Table* old_elem_dof)
1869 MFEM_VERIFY(
Nonconforming(),
"Only supported for nonconforming meshes.");
1870 MFEM_VERIFY(old_dof_offsets.
Size(),
"ParFiniteElementSpace::Update needs to "
1871 "be called before ParFiniteElementSpace::RebalanceMatrix");
1873 HYPRE_Int old_offset = HYPRE_AssumedPartitionCheck()
1874 ? old_dof_offsets[0] : old_dof_offsets[MyRank];
1877 ParNCMesh* pncmesh = pmesh->
pncmesh;
1883 const Array<int> &old_index = pncmesh->GetRebalanceOldIndex();
1884 MFEM_VERIFY(old_index.Size() == pmesh->
GetNE(),
1885 "Mesh::Rebalance was not called before "
1886 "ParFiniteElementSpace::RebalanceMatrix");
1889 HYPRE_Int* i_diag = make_i_array(vsize);
1890 for (
int i = 0; i < pmesh->
GetNE(); i++)
1892 if (old_index[i] >= 0)
1894 const int* old_dofs = old_elem_dof->GetRow(old_index[i]);
1897 for (
int vd = 0; vd <
vdim; vd++)
1899 for (
int j = 0; j < dofs.Size(); j++)
1902 if (row < 0) { row = -1 - row; }
1904 int col =
DofToVDof(old_dofs[j], vd, old_ndofs);
1905 if (col < 0) { col = -1 - col; }
1912 HYPRE_Int* j_diag = make_j_array(i_diag, vsize);
1915 Array<int> new_elements;
1916 Array<long> old_remote_dofs;
1917 pncmesh->RecvRebalanceDofs(new_elements, old_remote_dofs);
1920 HYPRE_Int* i_offd = make_i_array(vsize);
1921 for (
int i = 0; i < new_elements.Size(); i++)
1924 const long* old_dofs = &old_remote_dofs[i * dofs.Size() *
vdim];
1926 for (
int vd = 0; vd <
vdim; vd++)
1928 for (
int j = 0; j < dofs.Size(); j++)
1931 if (row < 0) { row = -1 - row; }
1933 if (i_diag[row] == i_diag[row+1])
1935 i_offd[row] = old_dofs[j + vd * dofs.Size()];
1940 HYPRE_Int* j_offd = make_j_array(i_offd, vsize);
1943 int offd_cols = i_offd[vsize];
1944 Array<Pair<HYPRE_Int, int> > cmap_offd(offd_cols);
1945 for (
int i = 0; i < offd_cols; i++)
1947 cmap_offd[i].one = j_offd[i];
1948 cmap_offd[i].two = i;
1950 SortPairs<HYPRE_Int, int>(cmap_offd, offd_cols);
1952 HYPRE_Int* cmap =
new HYPRE_Int[offd_cols];
1953 for (
int i = 0; i < offd_cols; i++)
1955 cmap[i] = cmap_offd[i].one;
1956 j_offd[cmap_offd[i].two] = i;
1960 M =
new HypreParMatrix(MyComm, MyRank, NRanks, dof_offsets, old_dof_offsets,
1961 i_diag, j_diag, i_offd, j_offd, cmap, offd_cols);
1966 struct DerefDofMessage
1968 std::vector<HYPRE_Int> dofs;
1969 MPI_Request request;
1973 ParFiniteElementSpace::ParallelDerefinementMatrix(
int old_ndofs,
1974 const Table* old_elem_dof)
1976 int nrk = HYPRE_AssumedPartitionCheck() ? 2 : NRanks;
1978 MFEM_VERIFY(
Nonconforming(),
"Not implemented for conforming meshes.");
1979 MFEM_VERIFY(old_dof_offsets[nrk],
"Missing previous (finer) space.");
1980 MFEM_VERIFY(dof_offsets[nrk] <= old_dof_offsets[nrk],
1981 "Previous space is not finer.");
1988 Array<int> dofs, old_dofs, old_vdofs;
1991 ParNCMesh* pncmesh = pmesh->
pncmesh;
1995 const CoarseFineTransformations &dtrans = pncmesh->GetDerefinementTransforms();
1996 const Array<int> &old_ranks = pncmesh->GetDerefineOldRanks();
1998 std::map<int, DerefDofMessage> messages;
2000 HYPRE_Int old_offset = HYPRE_AssumedPartitionCheck()
2001 ? old_dof_offsets[0] : old_dof_offsets[MyRank];
2005 for (
int k = 0; k < dtrans.embeddings.Size(); k++)
2007 const Embedding &emb = dtrans.embeddings[k];
2009 int fine_rank = old_ranks[k];
2010 int coarse_rank = (emb.parent < 0) ? (-1 - emb.parent)
2011 : pncmesh->ElementRank(emb.parent);
2013 if (coarse_rank != MyRank && fine_rank == MyRank)
2015 old_elem_dof->GetRow(k, dofs);
2018 DerefDofMessage &msg = messages[k];
2019 msg.dofs.resize(dofs.Size());
2020 for (
int i = 0; i < dofs.Size(); i++)
2022 msg.dofs[i] = old_offset + dofs[i];
2025 MPI_Isend(&msg.dofs[0], msg.dofs.size(), HYPRE_MPI_INT,
2026 coarse_rank, 291, MyComm, &msg.request);
2028 else if (coarse_rank == MyRank && fine_rank != MyRank)
2030 DerefDofMessage &msg = messages[k];
2031 msg.dofs.resize(ldof*vdim);
2033 MPI_Irecv(&msg.dofs[0], ldof*vdim, HYPRE_MPI_INT,
2034 fine_rank, 291, MyComm, &msg.request);
2045 SparseMatrix *diag =
new SparseMatrix(
ndofs*vdim, old_ndofs*vdim);
2047 Array<char> mark(diag->Height());
2049 for (
int k = 0; k < dtrans.embeddings.Size(); k++)
2051 const Embedding &emb = dtrans.embeddings[k];
2052 if (emb.parent < 0) {
continue; }
2054 int coarse_rank = pncmesh->ElementRank(emb.parent);
2055 int fine_rank = old_ranks[k];
2057 if (coarse_rank == MyRank && fine_rank == MyRank)
2059 DenseMatrix &lR = localR(emb.matrix);
2062 old_elem_dof->GetRow(k, old_dofs);
2064 for (
int vd = 0; vd <
vdim; vd++)
2066 old_dofs.Copy(old_vdofs);
2069 for (
int i = 0; i < lR.Height(); i++)
2071 if (lR(i, 0) == std::numeric_limits<double>::infinity())
2075 int m = (r >= 0) ? r : (-1 - r);
2080 diag->SetRow(r, old_vdofs, row);
2090 for (std::map<int, DerefDofMessage>::iterator
2091 it = messages.begin(); it != messages.end(); ++it)
2093 MPI_Wait(&it->second.request, MPI_STATUS_IGNORE);
2097 SparseMatrix *offd =
new SparseMatrix(
ndofs*vdim, 1);
2099 std::map<HYPRE_Int, int> col_map;
2100 for (
int k = 0; k < dtrans.embeddings.Size(); k++)
2102 const Embedding &emb = dtrans.embeddings[k];
2103 if (emb.parent < 0) {
continue; }
2105 int coarse_rank = pncmesh->ElementRank(emb.parent);
2106 int fine_rank = old_ranks[k];
2108 if (coarse_rank == MyRank && fine_rank != MyRank)
2110 DenseMatrix &lR = localR(emb.matrix);
2114 DerefDofMessage &msg = messages[k];
2115 MFEM_ASSERT(msg.dofs.size(),
"");
2117 for (
int vd = 0; vd <
vdim; vd++)
2119 HYPRE_Int* remote_dofs = &msg.dofs[vd*ldof];
2121 for (
int i = 0; i < lR.Height(); i++)
2123 if (lR(i, 0) == std::numeric_limits<double>::infinity())
2127 int m = (r >= 0) ? r : (-1 - r);
2132 for (
int j = 0; j < ldof; j++)
2134 if (std::abs(row[j]) < 1e-12) {
continue; }
2135 int &lcol = col_map[remote_dofs[j]];
2136 if (!lcol) { lcol = col_map.size(); }
2137 offd->_Set_(m, lcol-1, row[j]);
2147 offd->SetWidth(col_map.size());
2150 HYPRE_Int *cmap =
new HYPRE_Int[col_map.size()];
2151 for (std::map<HYPRE_Int, int>::iterator
2152 it = col_map.begin(); it != col_map.end(); ++it)
2154 cmap[it->second-1] = it->first;
2158 R =
new HypreParMatrix(MyComm, dof_offsets[nrk], old_dof_offsets[nrk],
2159 dof_offsets, old_dof_offsets, diag, offd, cmap);
2161 #ifndef HYPRE_BIGINT
2165 diag->SetDataOwner(
false);
2166 offd->SetDataOwner(
false);
2171 R->SetOwnerFlags(3, 3, 1);
2176 void ParFiniteElementSpace::Destroy()
2184 ldof_sign.DeleteAll();
2189 delete gcomm; gcomm = NULL;
2206 MFEM_ABORT(
"Error in update sequence. Space needs to be updated after "
2207 "each mesh modification.");
2217 Table* old_elem_dof = NULL;
2226 Swap(dof_offsets, old_dof_offsets);
2250 T = ParallelDerefinementMatrix(old_ndofs, old_elem_dof);
2260 T = RebalanceMatrix(old_ndofs, old_elem_dof);
2267 delete old_elem_dof;
Abstract class for Finite Elements.
int GetNFaceNeighbors() const
int GetGroupMasterRank(int g) const
void SendRebalanceDofs(int old_ndofs, const Table &old_element_dofs, long old_global_offset, FiniteElementSpace *space)
Use the communication pattern from last Rebalance() to send element DOFs.
int Size() const
Logical size of the array.
void Add(const int i, const int j, const double a)
int GetNDofs() const
Returns number of degrees of freedom.
int ndofs
Number of degrees of freedom. Number of unknowns are ndofs*vdim.
int DofToVDof(int dof, int vd, int ndofs=-1) const
void GetFaceInfos(int Face, int *Inf1, int *Inf2)
void AddDofs(int type, const NCMesh::MeshId &id, const Array< int > &dofs)
Add vertex/edge/face DOFs to an outgoing message.
void SubDofOrder(int Geom, int SDim, int Info, Array< int > &dofs) const
Get the local dofs for a given sub-manifold.
void BuildElementToDofTable() const
void AddColumnsInRow(int r, int ncol)
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
void GetFaceElements(int Face, int *Elem1, int *Elem2)
virtual void Finalize(int skip_zeros=1)
Finalize the matrix initialization, switching the storage format from LIL to CSR. ...
SparseMatrix * RefinementMatrix(int old_ndofs, const Table *old_elem_dof)
Calculate GridFunction interpolation matrix after mesh refinement.
void GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i'th element.
Array< Element * > face_nbr_elements
virtual void GetEssentialVDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_vdofs) const
int GetElementGeometry() const
Return the type of elements in the mesh.
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, but treat all elements as booleans (zero=false, nonzero=true).
Lists all edges/faces in the nonconforming mesh.
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
int GetGroupSize(int g) const
virtual void Update(bool want_transform=true)
int VDofToDof(int vdof) const
T * GetData()
Returns the data.
HYPRE_Int * GetDofOffsets()
Data type dense matrix using column-major storage.
int vdim
Vector dimension (number of unknowns per degree of freedom).
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
int GetNE() const
Returns number of elements.
void DivideByGroupSize(double *vec)
Scale a vector of true dofs.
void Synchronize(Array< int > &ldof_marker) const
std::vector< MeshId > conforming
virtual const SparseMatrix * GetRestrictionMatrix()
Get the R matrix which restricts a local dof vector to true dof vector.
std::map< int, NeighborRowRequest > Map
void Lose_Dof_TrueDof_Matrix()
int GetOwner(int type, int index) const
Return vertex/edge/face ('type' == 0/1/2, resp.) owner.
HypreParMatrix * GetPartialConformingInterpolation()
For a non-conforming mesh, construct and return the interpolation matrix from the partially conformin...
void AddRow(const int row, const Array< int > &cols, const Vector &srow)
const FiniteElementCollection * fec
int Size_of_connections() const
HYPRE_Int GetMyDofOffset() const
int GetGeometryType() const
void DeleteAll()
Delete whole array.
void AddConnections(int r, const int *c, int nc)
static void MarkerToList(const Array< int > &marker, Array< int > &list)
Convert a Boolean marker array to a list containing all marked indices.
bool IAmMaster(int g) const
A parallel extension of the NCMesh class.
void GetSharedEdgeDofs(int group, int ei, Array< int > &dofs) const
HYPRE_Int * GetTrueDofOffsets()
virtual void GetFaceDofs(int i, Array< int > &dofs) const
virtual void GetBdrElementDofs(int i, Array< int > &dofs) const
Returns indexes of degrees of freedom for i'th boundary element.
int GroupVertex(int group, int i)
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
void GetFaceNbrElementVDofs(int i, Array< int > &vdofs) const
void ExchangeFaceNbrData()
void GetVertexDofs(int i, Array< int > &dofs) const
const FiniteElement * GetFaceNbrFE(int i) const
void GetSharedFaceDofs(int group, int fi, Array< int > &dofs) const
Array< int > face_nbr_elements_offset
void ExchangeFaceNbrData()
virtual int GetRow(const int row, Array< int > &cols, Vector &srow) const
Extract all column indices and values from a given row.
static const int Dimension[NumGeom]
Operator * T
Transformation to apply to GridFunctions after space Update().
int to_int(const std::string &str)
std::vector< Master > masters
void AddConnection(int r, int c)
void LoseData()
NULL-ifies the data.
virtual void GetElementDofs(int i, Array< int > &dofs) const
Returns indexes of degrees of freedom in array dofs for i'th element.
HYPRE_Int GetMyTDofOffset() const
void Transpose(const Table &A, Table &At, int _ncols_A)
Transpose a Table.
int GetLocalTDofNumber(int ldof)
Identifies a vertex/edge/face in both Mesh and NCMesh.
static void IsendAll(MapT &rank_msg, MPI_Comm comm)
Helper to send all messages in a rank-to-message map container.
void GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
int GroupNVertices(int group)
virtual void GetFaceDofs(int i, Array< int > &dofs) const
int decode_dof(int dof, double &sign)
int Size() const
Returns the number of TYPE I elements.
double * GetData() const
Return element data, i.e. array A.
void GetEdgeDofs(int i, Array< int > &dofs) const
int * GetI() const
Return the array I.
int GetGroupMaster(int g) const
void Swap(Array< T > &, Array< T > &)
int GetDof() const
Returns the number of degrees of freedom in the finite element.
virtual void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list)
void AddAColumnInRow(int r)
void mfem_error(const char *msg)
void SetSize(int nsize)
Change logical size of the array, keep existing entries.
static void RecvAll(MapT &rank_msg, MPI_Comm comm)
Helper to receive all messages in a rank-to-message map container.
HYPRE_Int GetGlobalScalarTDofNumber(int sldof)
Operation GetLastOperation() const
Return type of last modification of the mesh.
bool Nonconforming() const
virtual int * DofOrderForOrientation(int GeomType, int Or) const =0
virtual void GetBdrElementDofs(int i, Array< int > &dofs) const
Returns indexes of degrees of freedom for i'th boundary element.
NURBSExtension * NURBSext
Optional NURBS mesh extension.
virtual void GetElementDofs(int i, Array< int > &dofs) const
Returns indexes of degrees of freedom in array dofs for i'th element.
void Init(ParNCMesh *pncmesh, const FiniteElementCollection *fec, int ndofs)
Table face_nbr_element_dof
void GroupFace(int group, int i, int &face, int &o)
Mesh * mesh
The mesh that FE space lives on.
General triple product operator x -> A*B*C*x, with ownership of the factors.
int GroupNFaces(int group)
void Reduce(T *ldata, void(*Op)(OpData< T >))
Reduce within each group where the master is the root.
const FiniteElement * GetFaceNbrFaceFE(int i) const
void Create(Array< int > &ldof_group)
int GetFaceOrientation(int index) const
Return (shared) face orientation relative to the owner element.
T & Last()
Return the last element in the array.
void GetFaceNbrFaceVDofs(int i, Array< int > &vdofs) const
std::map< int, NeighborDofMessage > Map
void MakeRef(T *, int)
Make this Array a reference to a pointer.
void GroupEdge(int group, int i, int &edge, int &o)
static void WaitAllSent(MapT &rank_msg)
Helper to wait for all messages in a map container to be sent.
const NCList & GetSharedList(int type)
Helper to get shared vertices/edges/faces ('type' == 0/1/2 resp.).
int GetFaceBaseGeometry(int i) const
void GenerateOffsets(int N, HYPRE_Int loc_sizes[], Array< HYPRE_Int > *offsets[]) const
std::map< int, NeighborRowReply > Map
virtual void GetEssentialVDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_dofs) const
Determine the boundary degrees of freedom.
const int * GetGroup(int type, int index, int &size) const
NURBSExtension * NURBSext
virtual int DofForGeometry(int GeomType) const =0
static bool IProbe(int &rank, int &size, MPI_Comm comm)
Table send_face_nbr_elements
Wrapper for hypre's ParCSR matrix class.
HypreParMatrix * Dof_TrueDof_Matrix()
The true dof-to-dof interpolation matrix.
GroupCommunicator * ScalarGroupComm()
Return a new GroupCommunicator on Dofs.
int * GetJ() const
Return the array J.
BiLinear2DFiniteElement QuadrilateralFE
Class for parallel meshes.
Abstract data type element.
int GetFaceNbrRank(int fn) const
Linear1DFiniteElement SegmentFE
ParFiniteElementSpace(ParMesh *pm, const FiniteElementCollection *f, int dim=1, int ordering=Ordering::byNODES)
HYPRE_Int GetGlobalTDofNumber(int ldof)
Returns the global tdof number of the given local degree of freedom.
void Bcast(T *data, int layout)
Broadcast within each group where the master is the root. The data layout can be: ...
static void Probe(int &rank, int &size, MPI_Comm comm)
int GroupNEdges(int group)
virtual const FiniteElement * FiniteElementForGeometry(int GeomType) const =0
void GetLocalDerefinementMatrices(int geom, const CoarseFineTransformations &dt, DenseTensor &localR)
static void BitOR(OpData< T >)
Reduce operation bitwise OR, instantiated for int only.
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Array< HYPRE_Int > face_nbr_glob_dof_map