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);
58 void ParFiniteElementSpace::Construct()
73 ConstructTrueNURBSDofs();
74 GenerateGlobalOffsets();
79 GenerateGlobalOffsets();
84 GetParallelConformingInterpolation();
88 void ParFiniteElementSpace::GetGroupComm(
89 GroupCommunicator &gc,
int ldof_type, Array<int> *ldof_sign)
96 int group_ldof_counter;
97 Table &group_ldof = gc.GroupLDofTable();
110 group_ldof_counter = 0;
111 for (gr = 1; gr < ng; gr++)
114 group_ldof_counter += ned * pmesh->
GroupNEdges(gr);
115 group_ldof_counter += nfd * pmesh->
GroupNFaces(gr);
119 group_ldof_counter *=
vdim;
122 group_ldof.SetDims(ng, group_ldof_counter);
125 group_ldof_counter = 0;
126 group_ldof.GetI()[0] = group_ldof.GetI()[1] = 0;
127 for (gr = 1; gr < ng; gr++)
129 int j, k, l, m, o, nv, ne, nf;
139 for (j = 0; j < nv; j++)
145 for (l = 0; l < nvd; l++, m++)
155 for (l = 0; l < dofs.Size(); l++)
157 group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
165 for (j = 0; j < ne; j++)
172 for (l = 0; l < ned; l++)
176 dofs[l] = m + (-1-ind[l]);
179 (*ldof_sign)[dofs[l]] = -1;
184 dofs[l] = m + ind[l];
193 for (l = 0; l < dofs.Size(); l++)
195 group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
203 for (j = 0; j < nf; j++)
211 for (l = 0; l < nfd; l++)
215 dofs[l] = m + (-1-ind[l]);
218 (*ldof_sign)[dofs[l]] = -1;
223 dofs[l] = m + ind[l];
232 for (l = 0; l < dofs.Size(); l++)
234 group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
239 group_ldof.GetI()[gr+1] = group_ldof_counter;
245 void ParFiniteElementSpace::ApplyLDofSigns(Array<int> &dofs)
const
247 for (
int i = 0; i < dofs.Size(); i++)
251 if (ldof_sign[-1-dofs[i]] < 0)
253 dofs[i] = -1-dofs[i];
258 if (ldof_sign[dofs[i]] < 0)
260 dofs[i] = -1-dofs[i];
276 ApplyLDofSigns(dofs);
290 ApplyLDofSigns(dofs);
299 ApplyLDofSigns(dofs);
307 MFEM_ASSERT(0 <= ei && ei < pmesh->GroupNEdges(group),
"invalid edge index");
308 pmesh->
GroupEdge(group, ei, l_edge, ori);
318 for (
int i = 0; i < dofs.
Size(); i++)
320 const int di = dofs[i];
321 dofs[i] = (di >= 0) ? rdofs[di] : -1-rdofs[-1-di];
330 MFEM_ASSERT(0 <= fi && fi < pmesh->GroupNFaces(group),
"invalid face index");
331 pmesh->
GroupFace(group, fi, l_face, ori);
341 for (
int i = 0; i < dofs.
Size(); i++)
343 const int di = dofs[i];
344 dofs[i] = (di >= 0) ? rdofs[di] : -1-rdofs[-1-di];
349 void ParFiniteElementSpace::GenerateGlobalOffsets()
const
359 if (HYPRE_AssumedPartitionCheck())
364 GroupTopology > = GetGroupTopo();
365 int nsize = gt.GetNumNeighbors()-1;
366 MPI_Request *requests =
new MPI_Request[2*nsize];
367 MPI_Status *statuses =
new MPI_Status[2*nsize];
368 tdof_nb_offsets.
SetSize(nsize+1);
369 tdof_nb_offsets[0] = tdof_offsets[0];
371 int request_counter = 0;
373 for (
int i = 1; i <= nsize; i++)
375 MPI_Irecv(&tdof_nb_offsets[i], 1, HYPRE_MPI_INT,
376 gt.GetNeighborRank(i), 5365, MyComm,
377 &requests[request_counter++]);
379 for (
int i = 1; i <= nsize; i++)
381 MPI_Isend(&tdof_nb_offsets[0], 1, HYPRE_MPI_INT,
382 gt.GetNeighborRank(i), 5365, MyComm,
383 &requests[request_counter++]);
385 MPI_Waitall(request_counter, requests, statuses);
397 void ParFiniteElementSpace::Build_Dof_TrueDof_Matrix() const
403 GetParallelConformingInterpolation();
410 HYPRE_Int *i_diag =
new HYPRE_Int[ldof+1];
411 HYPRE_Int *j_diag =
new HYPRE_Int[ltdof];
414 HYPRE_Int *i_offd =
new HYPRE_Int[ldof+1];
415 HYPRE_Int *j_offd =
new HYPRE_Int[ldof-ltdof];
418 HYPRE_Int *cmap =
new HYPRE_Int[ldof-ltdof];
423 Array<Pair<HYPRE_Int, int> > cmap_j_offd(ldof-ltdof);
425 i_diag[0] = i_offd[0] = 0;
426 diag_counter = offd_counter = 0;
427 for (
int i = 0; i < ldof; i++)
432 j_diag[diag_counter++] = ltdof;
437 cmap_j_offd[offd_counter].two = offd_counter;
440 i_diag[i+1] = diag_counter;
441 i_offd[i+1] = offd_counter;
444 SortPairs<HYPRE_Int, int>(cmap_j_offd, offd_counter);
446 for (
int i = 0; i < offd_counter; i++)
448 cmap[i] = cmap_j_offd[i].one;
449 j_offd[cmap_j_offd[i].two] = i;
452 P =
new HypreParMatrix(MyComm, MyRank, NRanks, row_starts, col_starts,
453 i_diag, j_diag, i_offd, j_offd, cmap, offd_counter);
464 MFEM_ABORT(
"Not implemented for NC mesh.");
469 for (
int i = 0; i < ldof_group.
Size(); i++)
489 gc->
Create(pNURBSext()->ldof_group);
493 GetGroupComm(*gc, 0);
502 MFEM_ABORT(
"Not implemented for NC mesh.");
507 mfem_error(
"ParFiniteElementSpace::Synchronize");
512 gcomm->
Bcast(ldof_marker);
547 return ldof_ltdof[ldof];
551 if (GetGroupTopo().IAmMaster(ldof_group[ldof]))
553 return ldof_ltdof[ldof];
566 MFEM_VERIFY(ldof_ltdof[ldof] >= 0,
"ldof " << ldof <<
" not a true DOF.");
572 if (HYPRE_AssumedPartitionCheck())
574 return ldof_ltdof[ldof] +
579 return ldof_ltdof[ldof] +
589 MFEM_ABORT(
"Not implemented for NC mesh.");
592 if (HYPRE_AssumedPartitionCheck())
596 return ldof_ltdof[sldof] +
598 ldof_group[sldof])] /
vdim;
602 return (ldof_ltdof[sldof*
vdim] +
603 tdof_nb_offsets[GetGroupTopo().GetGroupMaster(
610 return ldof_ltdof[sldof] +
612 ldof_group[sldof])] /
vdim;
616 return (ldof_ltdof[sldof*
vdim] +
617 tdof_offsets[GetGroupTopo().GetGroupMasterRank(
624 return HYPRE_AssumedPartitionCheck() ? dof_offsets[0] : dof_offsets[MyRank];
629 return HYPRE_AssumedPartitionCheck()? tdof_offsets[0] : tdof_offsets[MyRank];
653 if (num_face_nbrs == 0)
659 MPI_Request *requests =
new MPI_Request[2*num_face_nbrs];
660 MPI_Request *send_requests = requests;
661 MPI_Request *recv_requests = requests + num_face_nbrs;
662 MPI_Status *statuses =
new MPI_Status[num_face_nbrs];
668 Table send_nbr_elem_dof;
675 for (
int fn = 0; fn < num_face_nbrs; fn++)
680 for (
int i = 0; i < num_my_elems; i++)
683 for (
int j = 0; j < ldofs.
Size(); j++)
684 if (ldof_marker[ldofs[j]] != fn)
686 ldof_marker[ldofs[j]] = fn;
695 MyComm, &send_requests[fn]);
698 MyComm, &recv_requests[fn]);
701 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
706 MPI_Waitall(num_face_nbrs, send_requests, statuses);
714 int *send_I = send_nbr_elem_dof.
GetI();
716 for (
int fn = 0; fn < num_face_nbrs; fn++)
720 MPI_Isend(send_I + send_el_off[fn], send_el_off[fn+1] - send_el_off[fn],
721 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
723 MPI_Irecv(recv_I + recv_el_off[fn], recv_el_off[fn+1] - recv_el_off[fn],
724 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
727 MPI_Waitall(num_face_nbrs, send_requests, statuses);
728 send_nbr_elem_dof.
MakeJ();
732 for (
int fn = 0; fn < num_face_nbrs; fn++)
737 for (
int i = 0; i < num_my_elems; i++)
740 for (
int j = 0; j < ldofs.
Size(); j++)
742 if (ldof_marker[ldofs[j]] != fn)
744 ldof_marker[ldofs[j]] = fn;
749 send_el_off[fn] + i, ldofs, ldofs.
Size());
756 int *send_J = send_nbr_elem_dof.
GetJ();
757 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
761 int j_end = send_I[send_el_off[fn+1]];
763 for (
int i = 0; i < num_ldofs; i++)
765 ldof_marker[ldofs[i]] = i;
768 for ( ; j < j_end; j++)
770 send_J[j] = ldof_marker[send_J[j]];
774 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
781 for (
int fn = 0; fn < num_face_nbrs; fn++)
786 MPI_Isend(send_J + send_I[send_el_off[fn]],
787 send_I[send_el_off[fn+1]] - send_I[send_el_off[fn]],
788 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
790 MPI_Irecv(recv_J + recv_I[recv_el_off[fn]],
791 recv_I[recv_el_off[fn+1]] - recv_I[recv_el_off[fn]],
792 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
795 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
798 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
801 int j_end = recv_I[recv_el_off[fn+1]];
803 for ( ; j < j_end; j++)
809 MPI_Waitall(num_face_nbrs, send_requests, statuses);
814 for (
int fn = 0; fn < num_face_nbrs; fn++)
821 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
825 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
828 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
829 MPI_Waitall(num_face_nbrs, send_requests, statuses);
836 for (
int fn = 0; fn < num_face_nbrs; fn++)
841 MPI_Isend(&my_dof_offset, 1, HYPRE_MPI_INT, nbr_rank, tag,
842 MyComm, &send_requests[fn]);
844 MPI_Irecv(&dof_face_nbr_offsets[fn], 1, HYPRE_MPI_INT, nbr_rank, tag,
845 MyComm, &recv_requests[fn]);
848 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
852 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
859 MPI_Waitall(num_face_nbrs, send_requests, statuses);
877 int el1, el2, inf1, inf2;
890 Ordering::DofsToVDofs<Ordering::byNODES>(nd/
vdim,
vdim, vdofs);
892 for (
int j = 0; j < vdofs.
Size(); j++)
894 const int ldof = vdofs[j];
895 vdofs[j] = (ldof >= 0) ? vol_vdofs[ldof] : -1-vol_vdofs[-1-ldof];
907 mfem_error(
"ParFiniteElementSpace::GetFaceNbrFE"
908 " does not support NURBS!");
924 hypre_ParCSRMatrix *csrP = (hypre_ParCSRMatrix*)(*P);
925 hypre_ParCSRMatrixOwnsRowStarts(csrP) = 1;
926 hypre_ParCSRMatrixOwnsColStarts(csrP) = 1;
932 void ParFiniteElementSpace::ConstructTrueDofs()
939 GetGroupComm(*gcomm, 1, &ldof_sign);
949 for (gr = 1; gr < group_ldof.
Size(); gr++)
951 const int *ldofs = group_ldof.
GetRow(gr);
952 const int nldofs = group_ldof.
RowSize(gr);
953 for (i = 0; i < nldofs; i++)
955 ldof_group[ldofs[i]] = gr;
960 for (i = 0; i < nldofs; i++)
962 ldof_ltdof[ldofs[i]] = -2;
969 for (i = 0; i < n; i++)
971 if (ldof_ltdof[i] == -1)
973 ldof_ltdof[i] = ltdof_size++;
979 gcomm->
Bcast(ldof_ltdof);
982 void ParFiniteElementSpace::ConstructTrueNURBSDofs()
985 GroupTopology > = pNURBSext()->
gtopo;
986 gcomm =
new GroupCommunicator(gt);
991 ldof_group.
MakeRef(pNURBSext()->ldof_group);
995 const int *scalar_ldof_group = pNURBSext()->
ldof_group;
997 for (
int i = 0; i < n; i++)
999 ldof_group[i] = scalar_ldof_group[
VDofToDof(i)];
1003 gcomm->
Create(ldof_group);
1007 ldof_sign.DeleteAll();
1011 for (
int i = 0; i < n; i++)
1013 if (gt.IAmMaster(ldof_group[i]))
1015 ldof_ltdof[i] = ltdof_size;
1026 gcomm->
Bcast(ldof_ltdof);
1031 return (dof >= 0) ? (sign = 1, dof) : (sign = -1, (-1 - dof));
1049 if (pm.
Width() == 2)
1053 for (i = 0; i < 2; i++)
1055 if (pm(0, i) == 0.0 || pm(0, i) == 1.0)
1057 for (k = 0; k < nv; k++) { slave_dofs[i*nv + k] =
INVALID_DOF; }
1064 MFEM_ASSERT(pm.
Width() == 4,
"");
1067 for (i = 0; i < 4; i++)
1069 double x = pm(0,i), y = pm(1,i);
1070 corner[i] = ((x == 0.0 || x == 1.0) && (y == 0.0 || y == 1.0));
1074 for (i = 0; i < 4; i++)
1078 for (k = 0; k < nv; k++) { slave_dofs[i*nv + k] =
INVALID_DOF; }
1084 for (i = 0; i < 4; i++)
1086 if (corner[i] && corner[(i+1) % 4])
1088 for (k = 0; k < ne; k++)
1098 void ParFiniteElementSpace
1099 ::AddSlaveDependencies(DepList deps[],
int master_rank,
1100 const Array<int> &master_dofs,
int master_ndofs,
1101 const Array<int> &slave_dofs, DenseMatrix& I)
const
1104 for (
int i = 0; i < slave_dofs.Size(); i++)
1110 for (
int vd = 0; vd <
vdim; vd++)
1115 Array<Dependency> tmp_list;
1116 for (
int j = 0; j < master_dofs.Size(); j++)
1118 double coef = I(i, j);
1119 if (std::abs(coef) > 1e-12)
1122 int mvdof =
DofToVDof(mdof, vd, master_ndofs);
1123 tmp_list.Append(Dependency(master_rank, mvdof, coef*ms*ss));
1127 tmp_list.Copy(dl.list);
1133 void ParFiniteElementSpace
1134 ::Add1To1Dependencies(DepList deps[],
int owner_rank,
1135 const Array<int> &owner_dofs,
int owner_ndofs,
1136 const Array<int> &dependent_dofs)
const
1138 MFEM_ASSERT(owner_dofs.Size() == dependent_dofs.Size(),
"");
1140 for (
int vd = 0; vd <
vdim; vd++)
1142 for (
int i = 0; i < owner_dofs.Size(); i++)
1144 double osign, dsign;
1146 int ddof =
decode_dof(dependent_dofs[i], dsign);
1149 int ovdof =
DofToVDof(odof, vd, owner_ndofs);
1152 DepList &dl = deps[dvdof];
1156 dl.list.Append(Dependency(owner_rank, ovdof, osign*dsign));
1158 else if (dl.type == 1 && dl.list[0].rank > owner_rank)
1161 dl.list[0] = Dependency(owner_rank, ovdof, osign*dsign);
1167 void ParFiniteElementSpace
1168 ::ReorderFaceDofs(Array<int> &dofs,
int orient)
const
1178 int ve_dofs = 4*(nv + ne);
1179 for (
int i = 0; i < ve_dofs; i++)
1184 int f_dofs = dofs.Size() - ve_dofs;
1185 for (
int i = 0; i < f_dofs; i++)
1189 dofs[ve_dofs + i] = tmp[ve_dofs + ind[i]];
1193 dofs[ve_dofs + i] = -1 - tmp[ve_dofs + (-1 - ind[i])];
1198 void ParFiniteElementSpace::GetDofs(
int type,
int index, Array<int>& dofs)
const
1209 void ParFiniteElementSpace::GetParallelConformingInterpolation()
const
1211 ParNCMesh* pncmesh = pmesh->
pncmesh;
1222 for (
int type = 0; type < 3; type++)
1224 const NCMesh::NCList &list = pncmesh->GetSharedList(type);
1227 int cs = list.conforming.size(), ms = list.masters.size();
1228 for (
int i = 0; i < cs+ms; i++)
1231 const NCMesh::MeshId&
id =
1232 (i < cs) ? (
const NCMesh::MeshId&) list.conforming[i]
1233 : (
const NCMesh::MeshId&) list.masters[i-cs];
1235 int owner = pncmesh->GetOwner(type,
id.index), gsize;
1236 if (owner == MyRank)
1239 GetDofs(type,
id.index, dofs);
1240 const int *group = pncmesh->GetGroup(type,
id.index, gsize);
1241 for (
int j = 0; j < gsize; j++)
1243 if (group[j] != MyRank)
1245 NeighborDofMessage &send_msg = send_dofs[group[j]];
1246 send_msg.Init(pncmesh,
fec,
ndofs);
1247 send_msg.AddDofs(type,
id, dofs);
1254 recv_dofs[owner].Init(pncmesh,
fec, 0);
1267 DepList* deps =
new DepList[num_dofs];
1269 Array<int> master_dofs, slave_dofs;
1270 Array<int> owner_dofs, my_dofs;
1275 for (
int type = 1; type < 3; type++)
1277 const NCMesh::NCList &list = (type > 1) ? pncmesh->GetFaceList()
1278 : pncmesh->GetEdgeList();
1279 if (!list.masters.size()) {
continue; }
1281 IsoparametricTransformation
T;
1287 if (!fe) {
continue; }
1289 DenseMatrix I(fe->GetDof());
1292 for (
unsigned mi = 0; mi < list.masters.size(); mi++)
1294 const NCMesh::Master &mf = list.masters[mi];
1295 if (!pncmesh->RankInGroup(type, mf.index, MyRank)) {
continue; }
1298 int master_ndofs, master_rank = pncmesh->GetOwner(type, mf.index);
1299 if (master_rank == MyRank)
1301 GetDofs(type, mf.index, master_dofs);
1302 master_ndofs =
ndofs;
1306 recv_dofs[master_rank].GetDofs(type, mf, master_dofs,
1310 if (!master_dofs.Size()) {
continue; }
1313 for (
int si = mf.slaves_begin; si < mf.slaves_end; si++)
1315 const NCMesh::Slave &sf = list.slaves[si];
1316 if (pncmesh->IsGhost(type, sf.index)) {
continue; }
1318 GetDofs(type, sf.index, slave_dofs);
1319 if (!slave_dofs.Size()) {
continue; }
1321 sf.OrientedPointMatrix(T.GetPointMat());
1322 T.FinalizeTransformation();
1323 fe->GetLocalInterpolation(T, I);
1326 MaskSlaveDofs(slave_dofs, T.GetPointMat(),
fec);
1327 AddSlaveDependencies(deps, master_rank, master_dofs, master_ndofs,
1334 if (master_rank != MyRank && !pncmesh->IsGhost(type, mf.index))
1336 GetDofs(type, mf.index, my_dofs);
1337 Add1To1Dependencies(deps, master_rank, master_dofs, master_ndofs,
1344 for (
int type = 0; type < 3; type++)
1346 const NCMesh::NCList &list = pncmesh->GetSharedList(type);
1347 for (
unsigned i = 0; i < list.conforming.size(); i++)
1349 const NCMesh::MeshId &
id = list.conforming[i];
1350 GetDofs(type,
id.index, my_dofs);
1352 int owner_ndofs, owner = pncmesh->GetOwner(type,
id.index);
1353 if (owner != MyRank)
1355 recv_dofs[owner].GetDofs(type,
id, owner_dofs, owner_ndofs);
1358 int fo = pncmesh->GetFaceOrientation(
id.index);
1359 ReorderFaceDofs(owner_dofs, fo);
1361 Add1To1Dependencies(deps, owner, owner_dofs, owner_ndofs,
1367 Add1To1Dependencies(deps, owner, my_dofs,
ndofs, my_dofs);
1378 NeighborDofMessage::Map::iterator it;
1379 for (it = send_dofs.begin(); it != send_dofs.end(); ++it)
1381 recv_requests[it->first];
1383 for (it = recv_dofs.begin(); it != recv_dofs.end(); ++it)
1385 send_requests[it->first];
1389 for (
int i = 0; i < num_dofs; i++)
1391 const DepList &dl = deps[i];
1392 for (
int j = 0; j < dl.list.Size(); j++)
1394 const Dependency &dep = dl.list[j];
1395 if (dep.rank != MyRank)
1397 send_requests[dep.rank].RequestRow(dep.dof);
1407 for (
int i = 0; i < num_dofs; i++)
1409 if (deps[i].IsTrueDof(MyRank)) { ltdof_size++; }
1412 GenerateGlobalOffsets();
1414 HYPRE_Int glob_true_dofs = tdof_offsets.
Last();
1415 HYPRE_Int glob_cdofs = dof_offsets.
Last();
1419 MFEM_VERIFY(glob_true_dofs >= 0 && glob_true_dofs < (1ll << 31),
1420 "64bit matrix size not supported yet in non-conforming P.");
1422 MFEM_VERIFY(glob_true_dofs >= 0,
1423 "overflow of non-conforming P matrix columns.");
1425 SparseMatrix localP(num_dofs, glob_true_dofs);
1428 R =
new SparseMatrix(ltdof_size, num_dofs);
1430 Array<bool> finalized(num_dofs);
1437 for (
int i = 0, true_dof = 0; i < num_dofs; i++)
1439 if (deps[i].IsTrueDof(MyRank))
1441 localP.Add(i, my_tdof_offset + true_dof, 1.0);
1442 R->
Add(true_dof, i, 1.0);
1443 finalized[i] =
true;
1444 ldof_ltdof[i] = true_dof;
1453 std::list<NeighborRowReply::Map> send_replies;
1457 int num_finalized = ltdof_size;
1465 for (
int dof = 0, i; dof < num_dofs; dof++)
1467 if (finalized[dof]) {
continue; }
1470 const DepList &dl = deps[dof];
1471 for (i = 0; i < dl.list.Size(); i++)
1473 const Dependency &dep = dl.list[i];
1474 if (dep.rank == MyRank)
1476 if (!finalized[dep.dof]) {
break; }
1478 else if (!recv_replies[dep.rank].HaveRow(dep.dof))
1483 if (i < dl.list.Size()) {
continue; }
1486 for (i = 0; i < dl.list.Size(); i++)
1488 const Dependency &dep = dl.list[i];
1489 if (dep.rank == MyRank)
1491 localP.GetRow(dep.dof, cols, srow);
1495 recv_replies[dep.rank].GetRow(dep.dof, cols, srow);
1498 localP.AddRow(dof, cols, srow);
1501 finalized[dof] =
true;
1511 NeighborRowRequest::Map::iterator it;
1512 for (it = recv_requests.begin(); it != recv_requests.end(); ++it)
1514 NeighborRowRequest &req = it->second;
1515 std::set<int>::iterator row;
1516 for (row = req.rows.begin(); row != req.rows.end(); )
1518 if (finalized[*row])
1520 localP.GetRow(*row, cols, srow);
1521 send_replies.back()[it->first].AddRow(*row, cols, srow);
1522 req.rows.erase(row++);
1530 if (num_finalized >= num_dofs) {
break; }
1535 recv_replies[rank].Recv(rank, size, MyComm);
1540 recv_replies[rank].Recv(rank, size, MyComm);
1548 #ifndef HYPRE_BIGINT
1549 P =
new HypreParMatrix(MyComm, num_dofs, glob_cdofs, glob_true_dofs,
1550 localP.GetI(), localP.GetJ(), localP.GetData(),
1554 MFEM_ABORT(
"HYPRE_BIGINT not supported yet.");
1563 for (std::list<NeighborRowReply::Map>::iterator
1564 it = send_replies.begin(); it != send_replies.end(); ++it)
1588 for (
int type = 0; type < 3; type++)
1594 for (
int i = 0; i < cs+ms; i++)
1601 int owner = pncmesh->
GetOwner(type,
id.index), gsize;
1602 if (owner == MyRank)
1605 GetDofs(type,
id.index, dofs);
1606 const int *group = pncmesh->
GetGroup(type,
id.index, gsize);
1607 for (
int j = 0; j < gsize; j++)
1609 if (group[j] != MyRank)
1613 send_msg.
AddDofs(type,
id, dofs);
1620 recv_dofs[owner].Init(pncmesh,
fec, 0);
1633 DepList* deps =
new DepList[num_dofs];
1641 for (
int type = 0; type < 3; type++)
1644 for (
unsigned i = 0; i < list.
conforming.size(); i++)
1647 GetDofs(type,
id.index, my_dofs);
1649 int owner_ndofs, owner = pncmesh->
GetOwner(type,
id.index);
1650 if (owner != MyRank)
1652 recv_dofs[owner].GetDofs(type,
id, owner_dofs, owner_ndofs);
1656 ReorderFaceDofs(owner_dofs, fo);
1658 Add1To1Dependencies(deps, owner, owner_dofs, owner_ndofs,
1664 Add1To1Dependencies(deps, owner, my_dofs,
ndofs, my_dofs);
1675 NeighborDofMessage::Map::iterator it;
1676 for (it = send_dofs.begin(); it != send_dofs.end(); ++it)
1678 recv_requests[it->first];
1680 for (it = recv_dofs.begin(); it != recv_dofs.end(); ++it)
1682 send_requests[it->first];
1686 for (
int i = 0; i < num_dofs; i++)
1688 const DepList &dl = deps[i];
1689 for (
int j = 0; j < dl.list.Size(); j++)
1691 const Dependency &dep = dl.list[j];
1692 if (dep.rank != MyRank)
1694 send_requests[dep.rank].RequestRow(dep.dof);
1703 HYPRE_Int ltdof_sz = 0;
1704 for (
int i = 0; i < num_dofs; i++)
1706 if (deps[i].IsTrueDof(MyRank)) { ltdof_sz++; }
1712 HYPRE_Int glob_true_dofs = tdof_off.
Last();
1713 HYPRE_Int glob_cdofs = dof_offsets.
Last();
1717 MFEM_VERIFY(glob_true_dofs >= 0 && glob_true_dofs < (1ll << 31),
1718 "64bit matrix size not supported yet in non-conforming P.");
1720 MFEM_VERIFY(glob_true_dofs >= 0,
1721 "overflow of non-conforming P matrix columns.");
1730 HYPRE_Int my_tdof_offset = HYPRE_AssumedPartitionCheck() ?
1731 tdof_off[0] : tdof_off[MyRank];
1732 for (
int i = 0, true_dof = 0; i < num_dofs; i++)
1734 if (deps[i].IsTrueDof(MyRank))
1736 localP.
Add(i, my_tdof_offset + true_dof, 1.0);
1737 finalized[i] =
true;
1746 std::list<NeighborRowReply::Map> send_replies;
1750 int num_finalized = ltdof_sz;
1758 for (
int dof = 0, i; dof < num_dofs; dof++)
1760 if (finalized[dof]) {
continue; }
1763 const DepList &dl = deps[dof];
1764 for (i = 0; i < dl.list.Size(); i++)
1766 const Dependency &dep = dl.list[i];
1767 if (dep.rank == MyRank)
1769 if (!finalized[dep.dof]) {
break; }
1771 else if (!recv_replies[dep.rank].HaveRow(dep.dof))
1776 if (i < dl.list.Size()) {
continue; }
1779 for (i = 0; i < dl.list.Size(); i++)
1781 const Dependency &dep = dl.list[i];
1782 if (dep.rank == MyRank)
1784 localP.
GetRow(dep.dof, cols, srow);
1788 recv_replies[dep.rank].GetRow(dep.dof, cols, srow);
1791 localP.
AddRow(dof, cols, srow);
1794 finalized[dof] =
true;
1804 NeighborRowRequest::Map::iterator it;
1805 for (it = recv_requests.begin(); it != recv_requests.end(); ++it)
1808 std::set<int>::iterator row;
1809 for (row = req.
rows.begin(); row != req.
rows.end(); )
1811 if (finalized[*row])
1813 localP.
GetRow(*row, cols, srow);
1814 send_replies.back()[it->first].AddRow(*row, cols, srow);
1815 req.
rows.erase(row++);
1823 if (num_finalized >= num_dofs) {
break; }
1828 recv_replies[rank].Recv(rank, size, MyComm);
1833 recv_replies[rank].Recv(rank, size, MyComm);
1842 #ifndef HYPRE_BIGINT
1843 PP =
new HypreParMatrix(MyComm, num_dofs, glob_cdofs, glob_true_dofs,
1849 MFEM_ABORT(
"HYPRE_BIGINT not supported yet.");
1856 for (std::list<NeighborRowReply::Map>::iterator
1857 it = send_replies.begin(); it != send_replies.end(); ++it)
1865 static HYPRE_Int* make_i_array(
int nrows)
1867 HYPRE_Int *I =
new HYPRE_Int[nrows+1];
1868 for (
int i = 0; i <= nrows; i++) { I[i] = -1; }
1872 static HYPRE_Int* make_j_array(HYPRE_Int* I,
int nrows)
1875 for (
int i = 0; i < nrows; i++)
1877 if (I[i] >= 0) { nnz++; }
1879 HYPRE_Int *J =
new HYPRE_Int[nnz];
1882 for (
int i = 0, k = 0; i <= nrows; i++)
1884 HYPRE_Int col = I[i];
1886 if (col >= 0) { J[k++] = col; }
1892 ParFiniteElementSpace::RebalanceMatrix(
int old_ndofs,
1893 const Table* old_elem_dof)
1895 MFEM_VERIFY(
Nonconforming(),
"Only supported for nonconforming meshes.");
1896 MFEM_VERIFY(old_dof_offsets.
Size(),
"ParFiniteElementSpace::Update needs to "
1897 "be called before ParFiniteElementSpace::RebalanceMatrix");
1899 HYPRE_Int old_offset = HYPRE_AssumedPartitionCheck()
1900 ? old_dof_offsets[0] : old_dof_offsets[MyRank];
1903 ParNCMesh* pncmesh = pmesh->
pncmesh;
1909 const Array<int> &old_index = pncmesh->GetRebalanceOldIndex();
1910 MFEM_VERIFY(old_index.Size() == pmesh->
GetNE(),
1911 "Mesh::Rebalance was not called before "
1912 "ParFiniteElementSpace::RebalanceMatrix");
1915 HYPRE_Int* i_diag = make_i_array(vsize);
1916 for (
int i = 0; i < pmesh->
GetNE(); i++)
1918 if (old_index[i] >= 0)
1920 const int* old_dofs = old_elem_dof->GetRow(old_index[i]);
1923 for (
int vd = 0; vd <
vdim; vd++)
1925 for (
int j = 0; j < dofs.Size(); j++)
1928 if (row < 0) { row = -1 - row; }
1930 int col =
DofToVDof(old_dofs[j], vd, old_ndofs);
1931 if (col < 0) { col = -1 - col; }
1938 HYPRE_Int* j_diag = make_j_array(i_diag, vsize);
1941 Array<int> new_elements;
1942 Array<long> old_remote_dofs;
1943 pncmesh->RecvRebalanceDofs(new_elements, old_remote_dofs);
1946 HYPRE_Int* i_offd = make_i_array(vsize);
1947 for (
int i = 0; i < new_elements.Size(); i++)
1950 const long* old_dofs = &old_remote_dofs[i * dofs.Size() *
vdim];
1952 for (
int vd = 0; vd <
vdim; vd++)
1954 for (
int j = 0; j < dofs.Size(); j++)
1957 if (row < 0) { row = -1 - row; }
1959 if (i_diag[row] == i_diag[row+1])
1961 i_offd[row] = old_dofs[j + vd * dofs.Size()];
1966 HYPRE_Int* j_offd = make_j_array(i_offd, vsize);
1969 int offd_cols = i_offd[vsize];
1970 Array<Pair<HYPRE_Int, int> > cmap_offd(offd_cols);
1971 for (
int i = 0; i < offd_cols; i++)
1973 cmap_offd[i].one = j_offd[i];
1974 cmap_offd[i].two = i;
1976 SortPairs<HYPRE_Int, int>(cmap_offd, offd_cols);
1978 HYPRE_Int* cmap =
new HYPRE_Int[offd_cols];
1979 for (
int i = 0; i < offd_cols; i++)
1981 cmap[i] = cmap_offd[i].one;
1982 j_offd[cmap_offd[i].two] = i;
1986 M =
new HypreParMatrix(MyComm, MyRank, NRanks, dof_offsets, old_dof_offsets,
1987 i_diag, j_diag, i_offd, j_offd, cmap, offd_cols);
1992 struct DerefDofMessage
1994 std::vector<HYPRE_Int> dofs;
1995 MPI_Request request;
1999 ParFiniteElementSpace::ParallelDerefinementMatrix(
int old_ndofs,
2000 const Table* old_elem_dof)
2002 int nrk = HYPRE_AssumedPartitionCheck() ? 2 : NRanks;
2004 MFEM_VERIFY(
Nonconforming(),
"Not implemented for conforming meshes.");
2005 MFEM_VERIFY(old_dof_offsets[nrk],
"Missing previous (finer) space.");
2006 MFEM_VERIFY(dof_offsets[nrk] <= old_dof_offsets[nrk],
2007 "Previous space is not finer.");
2014 Array<int> dofs, old_dofs, old_vdofs;
2017 ParNCMesh* pncmesh = pmesh->
pncmesh;
2021 const CoarseFineTransformations &dtrans = pncmesh->GetDerefinementTransforms();
2022 const Array<int> &old_ranks = pncmesh->GetDerefineOldRanks();
2024 std::map<int, DerefDofMessage> messages;
2026 HYPRE_Int old_offset = HYPRE_AssumedPartitionCheck()
2027 ? old_dof_offsets[0] : old_dof_offsets[MyRank];
2031 for (
int k = 0; k < dtrans.embeddings.Size(); k++)
2033 const Embedding &emb = dtrans.embeddings[k];
2035 int fine_rank = old_ranks[k];
2036 int coarse_rank = (emb.parent < 0) ? (-1 - emb.parent)
2037 : pncmesh->ElementRank(emb.parent);
2039 if (coarse_rank != MyRank && fine_rank == MyRank)
2041 old_elem_dof->GetRow(k, dofs);
2044 DerefDofMessage &msg = messages[k];
2045 msg.dofs.resize(dofs.Size());
2046 for (
int i = 0; i < dofs.Size(); i++)
2048 msg.dofs[i] = old_offset + dofs[i];
2051 MPI_Isend(&msg.dofs[0], msg.dofs.size(), HYPRE_MPI_INT,
2052 coarse_rank, 291, MyComm, &msg.request);
2054 else if (coarse_rank == MyRank && fine_rank != MyRank)
2056 DerefDofMessage &msg = messages[k];
2057 msg.dofs.resize(ldof*vdim);
2059 MPI_Irecv(&msg.dofs[0], ldof*vdim, HYPRE_MPI_INT,
2060 fine_rank, 291, MyComm, &msg.request);
2071 SparseMatrix *diag =
new SparseMatrix(
ndofs*vdim, old_ndofs*vdim);
2073 Array<char> mark(diag->Height());
2075 for (
int k = 0; k < dtrans.embeddings.Size(); k++)
2077 const Embedding &emb = dtrans.embeddings[k];
2078 if (emb.parent < 0) {
continue; }
2080 int coarse_rank = pncmesh->ElementRank(emb.parent);
2081 int fine_rank = old_ranks[k];
2083 if (coarse_rank == MyRank && fine_rank == MyRank)
2085 DenseMatrix &lR = localR(emb.matrix);
2088 old_elem_dof->GetRow(k, old_dofs);
2090 for (
int vd = 0; vd <
vdim; vd++)
2092 old_dofs.Copy(old_vdofs);
2095 for (
int i = 0; i < lR.Height(); i++)
2097 if (lR(i, 0) == std::numeric_limits<double>::infinity())
2101 int m = (r >= 0) ? r : (-1 - r);
2106 diag->SetRow(r, old_vdofs, row);
2116 for (std::map<int, DerefDofMessage>::iterator
2117 it = messages.begin(); it != messages.end(); ++it)
2119 MPI_Wait(&it->second.request, MPI_STATUS_IGNORE);
2123 SparseMatrix *offd =
new SparseMatrix(
ndofs*vdim, 1);
2125 std::map<HYPRE_Int, int> col_map;
2126 for (
int k = 0; k < dtrans.embeddings.Size(); k++)
2128 const Embedding &emb = dtrans.embeddings[k];
2129 if (emb.parent < 0) {
continue; }
2131 int coarse_rank = pncmesh->ElementRank(emb.parent);
2132 int fine_rank = old_ranks[k];
2134 if (coarse_rank == MyRank && fine_rank != MyRank)
2136 DenseMatrix &lR = localR(emb.matrix);
2140 DerefDofMessage &msg = messages[k];
2141 MFEM_ASSERT(msg.dofs.size(),
"");
2143 for (
int vd = 0; vd <
vdim; vd++)
2145 HYPRE_Int* remote_dofs = &msg.dofs[vd*ldof];
2147 for (
int i = 0; i < lR.Height(); i++)
2149 if (lR(i, 0) == std::numeric_limits<double>::infinity())
2153 int m = (r >= 0) ? r : (-1 - r);
2158 for (
int j = 0; j < ldof; j++)
2160 if (std::abs(row[j]) < 1e-12) {
continue; }
2161 int &lcol = col_map[remote_dofs[j]];
2162 if (!lcol) { lcol = col_map.size(); }
2163 offd->_Set_(m, lcol-1, row[j]);
2173 offd->SetWidth(col_map.size());
2176 HYPRE_Int *cmap =
new HYPRE_Int[col_map.size()];
2177 for (std::map<HYPRE_Int, int>::iterator
2178 it = col_map.begin(); it != col_map.end(); ++it)
2180 cmap[it->second-1] = it->first;
2184 R =
new HypreParMatrix(MyComm, dof_offsets[nrk], old_dof_offsets[nrk],
2185 dof_offsets, old_dof_offsets, diag, offd, cmap);
2187 #ifndef HYPRE_BIGINT
2191 diag->SetDataOwner(
false);
2192 offd->SetDataOwner(
false);
2197 R->SetOwnerFlags(3, 3, 1);
2202 void ParFiniteElementSpace::Destroy()
2210 ldof_sign.DeleteAll();
2213 delete Pconf; Pconf = NULL;
2216 delete gcomm; gcomm = NULL;
2233 MFEM_ABORT(
"Error in update sequence. Space needs to be updated after "
2234 "each mesh modification.");
2244 Table* old_elem_dof = NULL;
2253 Swap(dof_offsets, old_dof_offsets);
2277 T = ParallelDerefinementMatrix(old_ndofs, old_elem_dof);
2287 T = RebalanceMatrix(old_ndofs, old_elem_dof);
2294 delete old_elem_dof;
2301 :
Operator(pfes.GetVSize(), pfes.GetTrueVSize()),
2303 gc(pfes.GroupComm())
2307 Table &group_ldof = gc.GroupLDofTable();
2309 for (
int gr = 1; gr < group_ldof.
Size(); gr++)
2311 if (!gc.GetGroupTopology().IAmMaster(gr))
2313 ldofs.MakeRef(group_ldof.
GetRow(gr), group_ldof.
RowSize(gr));
2329 for ( ; j < end; j++)
2335 for ( ; j <
Height(); j++)
2349 const double *xdata = x.
GetData();
2353 const int in_layout = 2;
2354 gc.BcastBegin(const_cast<double*>(xdata), in_layout);
2357 for (
int i = 0; i < m; i++)
2360 std::copy(xdata+j-i, xdata+end-i, ydata+j);
2363 std::copy(xdata+j-m, xdata+
Width(), ydata+j);
2365 const int out_layout = 0;
2366 gc.BcastEnd(ydata, out_layout);
2375 const double *xdata = x.
GetData();
2379 gc.ReduceBegin(xdata);
2382 for (
int i = 0; i < m; i++)
2385 std::copy(xdata+j, xdata+end, ydata+j-i);
2388 std::copy(xdata+j, xdata+
Height(), ydata+j-m);
2390 const int out_layout = 2;
Abstract class for Finite Elements.
virtual const Operator * GetProlongationMatrix()
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.
virtual void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1)
void Add(const int i, const int j, const double a)
HYPRE_Int GetGlobalTDofNumber(int ldof) const
Returns the global tdof number of the given local degree of freedom.
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)
virtual void GetEssentialVDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_dofs, int component=-1) const
Determine the boundary degrees of freedom.
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
HYPRE_Int * GetDofOffsets() const
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
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.
virtual void GetEssentialVDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_vdofs, int component=-1) const
Data type dense matrix using column-major storage.
int vdim
Vector dimension (number of unknowns per degree of freedom).
int Size() const
Returns the size of the vector.
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.
Abstract parallel finite element space.
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 GetLocalTDofNumber(int ldof) const
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
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
Communicator performing operations within groups defined by a GroupTopology with arbitrary-size data ...
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]
static void Sum(OpData< T >)
Reduce operation Sum, instantiated for int and double.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
int Append(const T &el)
Append element to array, resize if necessary.
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.
HypreParMatrix * Dof_TrueDof_Matrix() const
The true dof-to-dof interpolation matrix.
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 Reserve(int capacity)
Ensures that the allocated size is at least the given size.
void Transpose(const Table &A, Table &At, int _ncols_A)
Transpose a Table.
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.
void Sort()
Sorts the array. This requires operator< to be defined for T.
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.
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)
Table & GroupLDofTable()
Fill-in the returned Table reference to initialize the GroupCommunicator then call Finalize()...
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)
Initialize the communicator from a local-dof to group map. Finalize() is called internally.
int GetFaceOrientation(int index) const
Return (shared) face orientation relative to the owner element.
T & Last()
Return the last element in the array.
HYPRE_Int * GetTrueDofOffsets() const
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
void SetLTDofTable(Array< int > &ldof_ltdof)
Initialize the internal group_ltdof Table.
std::map< int, NeighborRowReply > Map
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.
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)
static void Probe(int &rank, int &size, MPI_Comm comm)
void Bcast(T *ldata, int layout)
Broadcast within each group where the master is the root.
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