12 #include "../config/config.hpp"
17 #include "../general/sort_pairs.hpp"
33 MPI_Comm_size(MyComm, &NRanks);
34 MPI_Comm_rank(MyComm, &MyRank);
56 void ParFiniteElementSpace::Construct()
71 ConstructTrueNURBSDofs();
72 GenerateGlobalOffsets();
77 GenerateGlobalOffsets();
82 GetParallelConformingInterpolation();
86 void ParFiniteElementSpace::GetGroupComm(
87 GroupCommunicator &gc,
int ldof_type, Array<int> *ldof_sign)
94 int group_ldof_counter;
95 Table &group_ldof = gc.GroupLDofTable();
108 group_ldof_counter = 0;
109 for (gr = 1; gr < ng; gr++)
112 group_ldof_counter += ned * pmesh->
GroupNEdges(gr);
113 group_ldof_counter += nfd * pmesh->
GroupNFaces(gr);
117 group_ldof_counter *=
vdim;
120 group_ldof.SetDims(ng, group_ldof_counter);
123 group_ldof_counter = 0;
124 group_ldof.GetI()[0] = group_ldof.GetI()[1] = 0;
125 for (gr = 1; gr < ng; gr++)
127 int j, k, l, m, o, nv, ne, nf;
137 for (j = 0; j < nv; j++)
143 for (l = 0; l < nvd; l++, m++)
153 for (l = 0; l < dofs.Size(); l++)
155 group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
163 for (j = 0; j < ne; j++)
170 for (l = 0; l < ned; l++)
173 dofs[l] = m + (-1-ind[l]);
176 (*ldof_sign)[dofs[l]] = -1;
181 dofs[l] = m + ind[l];
189 for (l = 0; l < dofs.Size(); l++)
191 group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
199 for (j = 0; j < nf; j++)
207 for (l = 0; l < nfd; l++)
210 dofs[l] = m + (-1-ind[l]);
213 (*ldof_sign)[dofs[l]] = -1;
218 dofs[l] = m + ind[l];
226 for (l = 0; l < dofs.Size(); l++)
228 group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
233 group_ldof.GetI()[gr+1] = group_ldof_counter;
239 void ParFiniteElementSpace::ApplyLDofSigns(Array<int> &dofs)
const
241 for (
int i = 0; i < dofs.Size(); i++)
245 if (ldof_sign[-1-dofs[i]] < 0)
247 dofs[i] = -1-dofs[i];
252 if (ldof_sign[dofs[i]] < 0)
254 dofs[i] = -1-dofs[i];
270 ApplyLDofSigns(dofs);
284 ApplyLDofSigns(dofs);
293 ApplyLDofSigns(dofs);
297 void ParFiniteElementSpace::GenerateGlobalOffsets()
307 if (HYPRE_AssumedPartitionCheck())
312 GroupTopology > = GetGroupTopo();
313 int nsize = gt.GetNumNeighbors()-1;
314 MPI_Request *requests =
new MPI_Request[2*nsize];
315 MPI_Status *statuses =
new MPI_Status[2*nsize];
316 tdof_nb_offsets.
SetSize(nsize+1);
317 tdof_nb_offsets[0] = tdof_offsets[0];
319 int request_counter = 0;
321 for (
int i = 1; i <= nsize; i++)
323 MPI_Irecv(&tdof_nb_offsets[i], 1, HYPRE_MPI_INT,
324 gt.GetNeighborRank(i), 5365, MyComm,
325 &requests[request_counter++]);
327 for (
int i = 1; i <= nsize; i++)
329 MPI_Isend(&tdof_nb_offsets[0], 1, HYPRE_MPI_INT,
330 gt.GetNeighborRank(i), 5365, MyComm,
331 &requests[request_counter++]);
333 MPI_Waitall(request_counter, requests, statuses);
354 GetParallelConformingInterpolation();
361 HYPRE_Int *i_diag =
new HYPRE_Int[ldof+1];
362 HYPRE_Int *j_diag =
new HYPRE_Int[ltdof];
365 HYPRE_Int *i_offd =
new HYPRE_Int[ldof+1];
366 HYPRE_Int *j_offd =
new HYPRE_Int[ldof-ltdof];
369 HYPRE_Int *cmap =
new HYPRE_Int[ldof-ltdof];
376 i_diag[0] = i_offd[0] = 0;
377 diag_counter = offd_counter = 0;
378 for (
int i = 0; i < ldof; i++)
383 j_diag[diag_counter++] = ltdof;
388 cmap_j_offd[offd_counter].two = offd_counter;
391 i_diag[i+1] = diag_counter;
392 i_offd[i+1] = offd_counter;
395 SortPairs<HYPRE_Int, int>(cmap_j_offd, offd_counter);
397 for (
int i = 0; i < offd_counter; i++)
399 cmap[i] = cmap_j_offd[i].one;
400 j_offd[cmap_j_offd[i].two] = i;
403 P =
new HypreParMatrix(MyComm, MyRank, NRanks, row_starts, col_starts,
404 i_diag, j_diag, i_offd, j_offd, cmap, offd_counter);
417 MFEM_ABORT(
"Not implemented for NC mesh.");
422 for (
int i = 0; i < ldof_group.
Size(); i++)
440 gc->
Create(pNURBSext()->ldof_group);
444 GetGroupComm(*gc, 0);
453 MFEM_ABORT(
"Not implemented for NC mesh.");
458 mfem_error(
"ParFiniteElementSpace::Synchronize");
463 gcomm->
Bcast(ldof_marker);
493 MFEM_VERIFY(P,
"Dof_TrueDof_Matrix() needs to be called before "
494 "GetLocalTDofNumber()");
496 return ldof_ltdof[ldof];
500 if (GetGroupTopo().IAmMaster(ldof_group[ldof]))
502 return ldof_ltdof[ldof];
515 MFEM_VERIFY(ldof_ltdof[ldof] >= 0,
"ldof " << ldof <<
" not a true DOF.");
521 if (HYPRE_AssumedPartitionCheck())
523 return ldof_ltdof[ldof] +
528 return ldof_ltdof[ldof] +
538 MFEM_ABORT(
"Not implemented for NC mesh.");
541 if (HYPRE_AssumedPartitionCheck())
545 return ldof_ltdof[sldof] +
547 ldof_group[sldof])] /
vdim;
551 return (ldof_ltdof[sldof*
vdim] +
552 tdof_nb_offsets[GetGroupTopo().GetGroupMaster(
559 return ldof_ltdof[sldof] +
561 ldof_group[sldof])] /
vdim;
565 return (ldof_ltdof[sldof*
vdim] +
566 tdof_offsets[GetGroupTopo().GetGroupMasterRank(
573 return HYPRE_AssumedPartitionCheck() ? dof_offsets[0] : dof_offsets[MyRank];
578 return HYPRE_AssumedPartitionCheck()? tdof_offsets[0] : tdof_offsets[MyRank];
589 if (num_face_nbrs == 0)
595 MPI_Request *requests =
new MPI_Request[2*num_face_nbrs];
596 MPI_Request *send_requests = requests;
597 MPI_Request *recv_requests = requests + num_face_nbrs;
598 MPI_Status *statuses =
new MPI_Status[num_face_nbrs];
604 Table send_nbr_elem_dof;
611 for (
int fn = 0; fn < num_face_nbrs; fn++)
616 for (
int i = 0; i < num_my_elems; i++)
619 for (
int j = 0; j < ldofs.
Size(); j++)
620 if (ldof_marker[ldofs[j]] != fn)
622 ldof_marker[ldofs[j]] = fn;
631 MyComm, &send_requests[fn]);
634 MyComm, &recv_requests[fn]);
637 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
642 MPI_Waitall(num_face_nbrs, send_requests, statuses);
650 int *send_I = send_nbr_elem_dof.
GetI();
652 for (
int fn = 0; fn < num_face_nbrs; fn++)
656 MPI_Isend(send_I + send_el_off[fn], send_el_off[fn+1] - send_el_off[fn],
657 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
659 MPI_Irecv(recv_I + recv_el_off[fn], recv_el_off[fn+1] - recv_el_off[fn],
660 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
663 MPI_Waitall(num_face_nbrs, send_requests, statuses);
664 send_nbr_elem_dof.
MakeJ();
668 for (
int fn = 0; fn < num_face_nbrs; fn++)
673 for (
int i = 0; i < num_my_elems; i++)
676 for (
int j = 0; j < ldofs.
Size(); j++)
678 if (ldof_marker[ldofs[j]] != fn)
680 ldof_marker[ldofs[j]] = fn;
685 send_el_off[fn] + i, ldofs, ldofs.
Size());
692 int *send_J = send_nbr_elem_dof.
GetJ();
693 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
697 int j_end = send_I[send_el_off[fn+1]];
699 for (
int i = 0; i < num_ldofs; i++)
701 ldof_marker[ldofs[i]] = i;
704 for ( ; j < j_end; j++)
706 send_J[j] = ldof_marker[send_J[j]];
710 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
717 for (
int fn = 0; fn < num_face_nbrs; fn++)
722 MPI_Isend(send_J + send_I[send_el_off[fn]],
723 send_I[send_el_off[fn+1]] - send_I[send_el_off[fn]],
724 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
726 MPI_Irecv(recv_J + recv_I[recv_el_off[fn]],
727 recv_I[recv_el_off[fn+1]] - recv_I[recv_el_off[fn]],
728 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
731 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
734 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
737 int j_end = recv_I[recv_el_off[fn+1]];
739 for ( ; j < j_end; j++)
745 MPI_Waitall(num_face_nbrs, send_requests, statuses);
750 for (
int fn = 0; fn < num_face_nbrs; fn++)
757 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
761 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
764 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
765 MPI_Waitall(num_face_nbrs, send_requests, statuses);
772 for (
int fn = 0; fn < num_face_nbrs; fn++)
777 MPI_Isend(&my_dof_offset, 1, HYPRE_MPI_INT, nbr_rank, tag,
778 MyComm, &send_requests[fn]);
780 MPI_Irecv(&dof_face_nbr_offsets[fn], 1, HYPRE_MPI_INT, nbr_rank, tag,
781 MyComm, &recv_requests[fn]);
784 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
788 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
795 MPI_Waitall(num_face_nbrs, send_requests, statuses);
813 int el1, el2, inf1, inf2;
826 Ordering::DofsToVDofs<Ordering::byNODES>(nd/
vdim,
vdim, vdofs);
828 for (
int j = 0; j < vdofs.
Size(); j++)
830 const int ldof = vdofs[j];
831 vdofs[j] = (ldof >= 0) ? vol_vdofs[ldof] : -1-vol_vdofs[-1-ldof];
843 mfem_error(
"ParFiniteElementSpace::GetFaceNbrFE"
844 " does not support NURBS!");
860 hypre_ParCSRMatrix *csrP = (hypre_ParCSRMatrix*)(*P);
861 hypre_ParCSRMatrixOwnsRowStarts(csrP) = 1;
862 hypre_ParCSRMatrixOwnsColStarts(csrP) = 1;
868 void ParFiniteElementSpace::ConstructTrueDofs()
875 GetGroupComm(*gcomm, 1, &ldof_sign);
885 for (gr = 1; gr < group_ldof.
Size(); gr++)
887 const int *ldofs = group_ldof.
GetRow(gr);
888 const int nldofs = group_ldof.
RowSize(gr);
889 for (i = 0; i < nldofs; i++)
891 ldof_group[ldofs[i]] = gr;
896 for (i = 0; i < nldofs; i++)
898 ldof_ltdof[ldofs[i]] = -2;
905 for (i = 0; i < n; i++)
907 if (ldof_ltdof[i] == -1)
909 ldof_ltdof[i] = ltdof_size++;
914 gcomm->
Bcast(ldof_ltdof);
917 void ParFiniteElementSpace::ConstructTrueNURBSDofs()
920 GroupTopology > = pNURBSext()->
gtopo;
921 gcomm =
new GroupCommunicator(gt);
926 ldof_group.
MakeRef(pNURBSext()->ldof_group);
930 const int *scalar_ldof_group = pNURBSext()->
ldof_group;
932 for (
int i = 0; i < n; i++)
934 ldof_group[i] = scalar_ldof_group[
VDofToDof(i)];
938 gcomm->
Create(ldof_group);
942 ldof_sign.DeleteAll();
946 for (
int i = 0; i < n; i++)
948 if (gt.IAmMaster(ldof_group[i]))
950 ldof_ltdof[i] = ltdof_size;
960 gcomm->
Bcast(ldof_ltdof);
965 return (dof >= 0) ? (sign = 1, dof) : (sign = -1, (-1 - dof));
987 for (i = 0; i < 2; i++)
989 if (pm(0, i) == 0.0 || pm(0, i) == 1.0)
991 for (k = 0; k < nv; k++) { slave_dofs[i*nv + k] =
INVALID_DOF; }
998 MFEM_ASSERT(pm.
Width() == 4,
"");
1001 for (i = 0; i < 4; i++)
1003 double x = pm(0,i), y = pm(1,i);
1004 corner[i] = ((x == 0.0 || x == 1.0) && (y == 0.0 || y == 1.0));
1008 for (i = 0; i < 4; i++)
1012 for (k = 0; k < nv; k++) { slave_dofs[i*nv + k] =
INVALID_DOF; }
1018 for (i = 0; i < 4; i++)
1020 if (corner[i] && corner[(i+1) % 4])
1022 for (k = 0; k < ne; k++)
1032 void ParFiniteElementSpace
1033 ::AddSlaveDependencies(DepList deps[],
int master_rank,
1034 const Array<int> &master_dofs,
int master_ndofs,
1035 const Array<int> &slave_dofs, DenseMatrix& I)
1038 for (
int i = 0; i < slave_dofs.Size(); i++)
1044 for (
int vd = 0; vd <
vdim; vd++)
1049 Array<Dependency> tmp_list;
1050 for (
int j = 0; j < master_dofs.Size(); j++)
1052 double coef = I(i, j);
1053 if (std::abs(coef) > 1e-12)
1056 int mvdof =
DofToVDof(mdof, vd, master_ndofs);
1057 tmp_list.Append(Dependency(master_rank, mvdof, coef*ms*ss));
1061 tmp_list.Copy(dl.list);
1067 void ParFiniteElementSpace
1068 ::Add1To1Dependencies(DepList deps[],
int owner_rank,
1069 const Array<int> &owner_dofs,
int owner_ndofs,
1070 const Array<int> &dependent_dofs)
1072 MFEM_ASSERT(owner_dofs.Size() == dependent_dofs.Size(),
"");
1074 for (
int vd = 0; vd <
vdim; vd++)
1076 for (
int i = 0; i < owner_dofs.Size(); i++)
1078 double osign, dsign;
1080 int ddof =
decode_dof(dependent_dofs[i], dsign);
1083 int ovdof =
DofToVDof(odof, vd, owner_ndofs);
1086 DepList &dl = deps[dvdof];
1090 dl.list.Append(Dependency(owner_rank, ovdof, osign*dsign));
1092 else if (dl.type == 1 && dl.list[0].rank > owner_rank)
1095 dl.list[0] = Dependency(owner_rank, ovdof, osign*dsign);
1101 void ParFiniteElementSpace
1102 ::ReorderFaceDofs(Array<int> &dofs,
int orient)
1112 int ve_dofs = 4*(nv + ne);
1113 for (
int i = 0; i < ve_dofs; i++)
1118 int f_dofs = dofs.Size() - ve_dofs;
1119 for (
int i = 0; i < f_dofs; i++)
1123 dofs[ve_dofs + i] = tmp[ve_dofs + ind[i]];
1127 dofs[ve_dofs + i] = -1 - tmp[ve_dofs + (-1 - ind[i])];
1132 void ParFiniteElementSpace::GetDofs(
int type,
int index, Array<int>& dofs)
1143 void ParFiniteElementSpace::GetParallelConformingInterpolation()
1145 ParNCMesh* pncmesh = pmesh->
pncmesh;
1156 for (
int type = 0; type < 3; type++)
1158 const NCMesh::NCList &list = pncmesh->GetSharedList(type);
1161 int cs = list.conforming.size(), ms = list.masters.size();
1162 for (
int i = 0; i < cs+ms; i++)
1165 const NCMesh::MeshId&
id =
1166 (i < cs) ? (
const NCMesh::MeshId&) list.conforming[i]
1167 : (
const NCMesh::MeshId&) list.masters[i-cs];
1169 int owner = pncmesh->GetOwner(type,
id.index), gsize;
1170 if (owner == MyRank)
1173 GetDofs(type,
id.index, dofs);
1174 const int *group = pncmesh->GetGroup(type,
id.index, gsize);
1175 for (
int j = 0; j < gsize; j++)
1177 if (group[j] != MyRank)
1179 NeighborDofMessage &send_msg = send_dofs[group[j]];
1180 send_msg.Init(pncmesh,
fec,
ndofs);
1181 send_msg.AddDofs(type,
id, dofs);
1188 recv_dofs[owner].Init(pncmesh,
fec, 0);
1201 DepList* deps =
new DepList[num_dofs];
1203 Array<int> master_dofs, slave_dofs;
1204 Array<int> owner_dofs, my_dofs;
1209 for (
int type = 1; type < 3; type++)
1211 const NCMesh::NCList &list = (type > 1) ? pncmesh->GetFaceList()
1212 : pncmesh->GetEdgeList();
1213 if (!list.masters.size()) {
continue; }
1215 IsoparametricTransformation
T;
1221 if (!fe) {
continue; }
1223 DenseMatrix I(fe->GetDof());
1226 for (
unsigned mi = 0; mi < list.masters.size(); mi++)
1228 const NCMesh::Master &mf = list.masters[mi];
1229 if (!pncmesh->RankInGroup(type, mf.index, MyRank)) {
continue; }
1232 int master_ndofs, master_rank = pncmesh->GetOwner(type, mf.index);
1233 if (master_rank == MyRank)
1235 GetDofs(type, mf.index, master_dofs);
1236 master_ndofs =
ndofs;
1240 recv_dofs[master_rank].GetDofs(type, mf, master_dofs,
1244 if (!master_dofs.Size()) {
continue; }
1247 for (
int si = mf.slaves_begin; si < mf.slaves_end; si++)
1249 const NCMesh::Slave &sf = list.slaves[si];
1250 if (pncmesh->IsGhost(type, sf.index)) {
continue; }
1252 GetDofs(type, sf.index, slave_dofs);
1253 if (!slave_dofs.Size()) {
continue; }
1255 sf.OrientedPointMatrix(T.GetPointMat());
1256 fe->GetLocalInterpolation(T, I);
1259 MaskSlaveDofs(slave_dofs, T.GetPointMat(),
fec);
1260 AddSlaveDependencies(deps, master_rank, master_dofs, master_ndofs,
1267 if (master_rank != MyRank && !pncmesh->IsGhost(type, mf.index))
1269 GetDofs(type, mf.index, my_dofs);
1270 Add1To1Dependencies(deps, master_rank, master_dofs, master_ndofs,
1277 for (
int type = 0; type < 3; type++)
1279 const NCMesh::NCList &list = pncmesh->GetSharedList(type);
1280 for (
unsigned i = 0; i < list.conforming.size(); i++)
1282 const NCMesh::MeshId &
id = list.conforming[i];
1283 GetDofs(type,
id.index, my_dofs);
1285 int owner_ndofs, owner = pncmesh->GetOwner(type,
id.index);
1286 if (owner != MyRank)
1288 recv_dofs[owner].GetDofs(type,
id, owner_dofs, owner_ndofs);
1291 int fo = pncmesh->GetFaceOrientation(
id.index);
1292 ReorderFaceDofs(owner_dofs, fo);
1294 Add1To1Dependencies(deps, owner, owner_dofs, owner_ndofs,
1300 Add1To1Dependencies(deps, owner, my_dofs,
ndofs, my_dofs);
1311 NeighborDofMessage::Map::iterator it;
1312 for (it = send_dofs.begin(); it != send_dofs.end(); ++it)
1314 recv_requests[it->first];
1316 for (it = recv_dofs.begin(); it != recv_dofs.end(); ++it)
1318 send_requests[it->first];
1322 for (
int i = 0; i < num_dofs; i++)
1324 const DepList &dl = deps[i];
1325 for (
int j = 0; j < dl.list.Size(); j++)
1327 const Dependency &dep = dl.list[j];
1328 if (dep.rank != MyRank)
1330 send_requests[dep.rank].RequestRow(dep.dof);
1340 for (
int i = 0; i < num_dofs; i++)
1342 if (deps[i].IsTrueDof(MyRank)) { ltdof_size++; }
1345 GenerateGlobalOffsets();
1347 HYPRE_Int glob_true_dofs = tdof_offsets.
Last();
1348 HYPRE_Int glob_cdofs = dof_offsets.
Last();
1352 MFEM_VERIFY(glob_true_dofs >= 0 && glob_true_dofs < (1ll << 31),
1353 "64bit matrix size not supported yet in non-conforming P.");
1355 MFEM_VERIFY(glob_true_dofs >= 0,
1356 "overflow of non-conforming P matrix columns.");
1358 SparseMatrix localP(num_dofs, glob_true_dofs);
1361 R =
new SparseMatrix(ltdof_size, num_dofs);
1363 Array<bool> finalized(num_dofs);
1370 for (
int i = 0, true_dof = 0; i < num_dofs; i++)
1372 if (deps[i].IsTrueDof(MyRank))
1374 localP.Add(i, my_tdof_offset + true_dof, 1.0);
1375 R->
Add(true_dof, i, 1.0);
1376 finalized[i] =
true;
1377 ldof_ltdof[i] = true_dof;
1386 std::list<NeighborRowReply::Map> send_replies;
1390 int num_finalized = ltdof_size;
1398 for (
int dof = 0, i; dof < num_dofs; dof++)
1400 if (finalized[dof]) {
continue; }
1403 const DepList &dl = deps[dof];
1404 for (i = 0; i < dl.list.Size(); i++)
1406 const Dependency &dep = dl.list[i];
1407 if (dep.rank == MyRank)
1409 if (!finalized[dep.dof]) {
break; }
1411 else if (!recv_replies[dep.rank].HaveRow(dep.dof))
1416 if (i < dl.list.Size()) {
continue; }
1419 for (i = 0; i < dl.list.Size(); i++)
1421 const Dependency &dep = dl.list[i];
1422 if (dep.rank == MyRank)
1424 localP.GetRow(dep.dof, cols, srow);
1428 recv_replies[dep.rank].GetRow(dep.dof, cols, srow);
1431 localP.AddRow(dof, cols, srow);
1434 finalized[dof] =
true;
1444 NeighborRowRequest::Map::iterator it;
1445 for (it = recv_requests.begin(); it != recv_requests.end(); ++it)
1447 NeighborRowRequest &req = it->second;
1448 std::set<int>::iterator row;
1449 for (row = req.rows.begin(); row != req.rows.end(); )
1451 if (finalized[*row])
1453 localP.GetRow(*row, cols, srow);
1454 send_replies.back()[it->first].AddRow(*row, cols, srow);
1455 req.rows.erase(row++);
1463 if (num_finalized >= num_dofs) {
break; }
1468 recv_replies[rank].Recv(rank, size, MyComm);
1473 recv_replies[rank].Recv(rank, size, MyComm);
1481 #ifndef HYPRE_BIGINT
1482 P =
new HypreParMatrix(MyComm, num_dofs, glob_cdofs, glob_true_dofs,
1483 localP.GetI(), localP.GetJ(), localP.GetData(),
1487 MFEM_ABORT(
"HYPRE_BIGINT not supported yet.");
1496 for (std::list<NeighborRowReply::Map>::iterator
1497 it = send_replies.begin(); it != send_replies.end(); ++it)
1521 for (
int type = 0; type < 3; type++)
1527 for (
int i = 0; i < cs+ms; i++)
1534 int owner = pncmesh->
GetOwner(type,
id.index), gsize;
1535 if (owner == MyRank)
1538 GetDofs(type,
id.index, dofs);
1539 const int *group = pncmesh->
GetGroup(type,
id.index, gsize);
1540 for (
int j = 0; j < gsize; j++)
1542 if (group[j] != MyRank)
1546 send_msg.
AddDofs(type,
id, dofs);
1553 recv_dofs[owner].Init(pncmesh,
fec, 0);
1566 DepList* deps =
new DepList[num_dofs];
1574 for (
int type = 0; type < 3; type++)
1577 for (
unsigned i = 0; i < list.
conforming.size(); i++)
1580 GetDofs(type,
id.index, my_dofs);
1582 int owner_ndofs, owner = pncmesh->
GetOwner(type,
id.index);
1583 if (owner != MyRank)
1585 recv_dofs[owner].GetDofs(type,
id, owner_dofs, owner_ndofs);
1589 ReorderFaceDofs(owner_dofs, fo);
1591 Add1To1Dependencies(deps, owner, owner_dofs, owner_ndofs,
1597 Add1To1Dependencies(deps, owner, my_dofs,
ndofs, my_dofs);
1608 NeighborDofMessage::Map::iterator it;
1609 for (it = send_dofs.begin(); it != send_dofs.end(); ++it)
1611 recv_requests[it->first];
1613 for (it = recv_dofs.begin(); it != recv_dofs.end(); ++it)
1615 send_requests[it->first];
1619 for (
int i = 0; i < num_dofs; i++)
1621 const DepList &dl = deps[i];
1622 for (
int j = 0; j < dl.list.Size(); j++)
1624 const Dependency &dep = dl.list[j];
1625 if (dep.rank != MyRank)
1627 send_requests[dep.rank].RequestRow(dep.dof);
1637 for (
int i = 0; i < num_dofs; i++)
1639 if (deps[i].IsTrueDof(MyRank)) { ltdof_sz++; }
1645 HYPRE_Int glob_true_dofs = tdof_off.
Last();
1646 HYPRE_Int glob_cdofs = dof_offsets.
Last();
1650 MFEM_VERIFY(glob_true_dofs >= 0 && glob_true_dofs < (1ll << 31),
1651 "64bit matrix size not supported yet in non-conforming P.");
1653 MFEM_VERIFY(glob_true_dofs >= 0,
1654 "overflow of non-conforming P matrix columns.");
1662 HYPRE_Int my_tdof_offset = HYPRE_AssumedPartitionCheck() ?
1663 tdof_off[0] : tdof_off[MyRank];
1664 for (
int i = 0, true_dof = 0; i < num_dofs; i++)
1666 if (deps[i].IsTrueDof(MyRank))
1668 localP.
Add(i, my_tdof_offset + true_dof, 1.0);
1669 finalized[i] =
true;
1678 std::list<NeighborRowReply::Map> send_replies;
1682 int num_finalized = ltdof_sz;
1690 for (
int dof = 0, i; dof < num_dofs; dof++)
1692 if (finalized[dof]) {
continue; }
1695 const DepList &dl = deps[dof];
1696 for (i = 0; i < dl.list.Size(); i++)
1698 const Dependency &dep = dl.list[i];
1699 if (dep.rank == MyRank)
1701 if (!finalized[dep.dof]) {
break; }
1703 else if (!recv_replies[dep.rank].HaveRow(dep.dof))
1708 if (i < dl.list.Size()) {
continue; }
1711 for (i = 0; i < dl.list.Size(); i++)
1713 const Dependency &dep = dl.list[i];
1714 if (dep.rank == MyRank)
1716 localP.
GetRow(dep.dof, cols, srow);
1720 recv_replies[dep.rank].GetRow(dep.dof, cols, srow);
1723 localP.
AddRow(dof, cols, srow);
1726 finalized[dof] =
true;
1736 NeighborRowRequest::Map::iterator it;
1737 for (it = recv_requests.begin(); it != recv_requests.end(); ++it)
1740 std::set<int>::iterator row;
1741 for (row = req.
rows.begin(); row != req.
rows.end(); )
1743 if (finalized[*row])
1745 localP.
GetRow(*row, cols, srow);
1746 send_replies.back()[it->first].AddRow(*row, cols, srow);
1747 req.
rows.erase(row++);
1755 if (num_finalized >= num_dofs) {
break; }
1760 recv_replies[rank].Recv(rank, size, MyComm);
1765 recv_replies[rank].Recv(rank, size, MyComm);
1774 #ifndef HYPRE_BIGINT
1775 PP =
new HypreParMatrix(MyComm, num_dofs, glob_cdofs, glob_true_dofs,
1780 MFEM_ABORT(
"HYPRE_BIGINT not supported yet.");
1787 for (std::list<NeighborRowReply::Map>::iterator
1788 it = send_replies.begin(); it != send_replies.end(); ++it)
1796 static HYPRE_Int* make_i_array(
int nrows)
1798 int *I =
new HYPRE_Int[nrows+1];
1799 for (
int i = 0; i <= nrows; i++) { I[i] = -1; }
1803 static HYPRE_Int* make_j_array(HYPRE_Int* I,
int nrows)
1806 for (
int i = 0; i < nrows; i++)
1808 if (I[i] >= 0) { nnz++; }
1810 int *J =
new HYPRE_Int[nnz];
1813 for (
int i = 0, k = 0; i <= nrows; i++)
1815 HYPRE_Int col = I[i];
1817 if (col >= 0) { J[k++] = col; }
1823 ParFiniteElementSpace::RebalanceMatrix(
int old_ndofs,
1824 const Table* old_elem_dof)
1826 MFEM_VERIFY(
Nonconforming(),
"Only supported for nonconforming meshes.");
1827 MFEM_VERIFY(old_dof_offsets.
Size(),
"ParFiniteElementSpace::Update needs to "
1828 "be called before ParFiniteElementSpace::RebalanceMatrix");
1830 HYPRE_Int old_offset = HYPRE_AssumedPartitionCheck()
1831 ? old_dof_offsets[0] : old_dof_offsets[MyRank];
1834 ParNCMesh* pncmesh = pmesh->
pncmesh;
1840 const Array<int> &old_index = pncmesh->GetRebalanceOldIndex();
1841 MFEM_VERIFY(old_index.Size() == pmesh->
GetNE(),
1842 "Mesh::Rebalance was not called before "
1843 "ParFiniteElementSpace::RebalanceMatrix");
1846 HYPRE_Int* i_diag = make_i_array(vsize);
1847 for (
int i = 0; i < pmesh->
GetNE(); i++)
1849 if (old_index[i] >= 0)
1851 const int* old_dofs = old_elem_dof->GetRow(old_index[i]);
1854 for (
int vd = 0; vd <
vdim; vd++)
1856 for (
int j = 0; j < dofs.Size(); j++)
1859 if (row < 0) { row = -1 - row; }
1861 int col =
DofToVDof(old_dofs[j], vd, old_ndofs);
1862 if (col < 0) { col = -1 - col; }
1869 HYPRE_Int* j_diag = make_j_array(i_diag, vsize);
1872 Array<int> new_elements;
1873 Array<long> old_remote_dofs;
1874 pncmesh->RecvRebalanceDofs(new_elements, old_remote_dofs);
1877 HYPRE_Int* i_offd = make_i_array(vsize);
1878 for (
int i = 0; i < new_elements.Size(); i++)
1881 const long* old_dofs = &old_remote_dofs[i * dofs.Size() *
vdim];
1883 for (
int vd = 0; vd <
vdim; vd++)
1885 for (
int j = 0; j < dofs.Size(); j++)
1888 if (row < 0) { row = -1 - row; }
1890 if (i_diag[row] == i_diag[row+1])
1892 i_offd[row] = old_dofs[j + vd * dofs.Size()];
1897 HYPRE_Int* j_offd = make_j_array(i_offd, vsize);
1900 int offd_cols = i_offd[vsize];
1901 Array<Pair<HYPRE_Int, int> > cmap_offd(offd_cols);
1902 for (
int i = 0; i < offd_cols; i++)
1904 cmap_offd[i].one = j_offd[i];
1905 cmap_offd[i].two = i;
1907 SortPairs<HYPRE_Int, int>(cmap_offd, offd_cols);
1909 HYPRE_Int* cmap =
new HYPRE_Int[offd_cols];
1910 for (
int i = 0; i < offd_cols; i++)
1912 cmap[i] = cmap_offd[i].one;
1913 j_offd[cmap_offd[i].two] = i;
1917 M =
new HypreParMatrix(MyComm, MyRank, NRanks, dof_offsets, old_dof_offsets,
1918 i_diag, j_diag, i_offd, j_offd, cmap, offd_cols);
1923 struct DerefDofMessage
1925 std::vector<HYPRE_Int> dofs;
1926 MPI_Request request;
1930 ParFiniteElementSpace::ParallelDerefinementMatrix(
int old_ndofs,
1931 const Table* old_elem_dof)
1933 int nrk = HYPRE_AssumedPartitionCheck() ? 2 : NRanks;
1935 MFEM_VERIFY(
Nonconforming(),
"Not implemented for conforming meshes.");
1936 MFEM_VERIFY(old_dof_offsets[nrk],
"Missing previous (finer) space.");
1937 MFEM_VERIFY(dof_offsets[nrk] <= old_dof_offsets[nrk],
1938 "Previous space is not finer.");
1945 Array<int> dofs, old_dofs, old_vdofs;
1948 ParNCMesh* pncmesh = pmesh->
pncmesh;
1952 const CoarseFineTransformations &dtrans = pncmesh->GetDerefinementTransforms();
1953 const Array<int> &old_ranks = pncmesh->GetDerefineOldRanks();
1955 std::map<int, DerefDofMessage> messages;
1957 HYPRE_Int old_offset = HYPRE_AssumedPartitionCheck()
1958 ? old_dof_offsets[0] : old_dof_offsets[MyRank];
1962 for (
int k = 0; k < dtrans.embeddings.Size(); k++)
1964 const Embedding &emb = dtrans.embeddings[k];
1966 int fine_rank = old_ranks[k];
1967 int coarse_rank = (emb.parent < 0) ? (-1 - emb.parent)
1968 : pncmesh->ElementRank(emb.parent);
1970 if (coarse_rank != MyRank && fine_rank == MyRank)
1972 old_elem_dof->GetRow(k, dofs);
1975 DerefDofMessage &msg = messages[k];
1976 msg.dofs.resize(dofs.Size());
1977 for (
int i = 0; i < dofs.Size(); i++)
1979 msg.dofs[i] = old_offset + dofs[i];
1982 MPI_Isend(&msg.dofs[0], msg.dofs.size(), HYPRE_MPI_INT,
1983 coarse_rank, 291, MyComm, &msg.request);
1985 else if (coarse_rank == MyRank && fine_rank != MyRank)
1987 DerefDofMessage &msg = messages[k];
1988 msg.dofs.resize(ldof*vdim);
1990 MPI_Irecv(&msg.dofs[0], ldof*vdim, HYPRE_MPI_INT,
1991 fine_rank, 291, MyComm, &msg.request);
2002 SparseMatrix *diag =
new SparseMatrix(
ndofs*vdim, old_ndofs*vdim);
2004 Array<char> mark(diag->Height());
2006 for (
int k = 0; k < dtrans.embeddings.Size(); k++)
2008 const Embedding &emb = dtrans.embeddings[k];
2009 if (emb.parent < 0) {
continue; }
2011 int coarse_rank = pncmesh->ElementRank(emb.parent);
2012 int fine_rank = old_ranks[k];
2014 if (coarse_rank == MyRank && fine_rank == MyRank)
2016 DenseMatrix &lR = localR(emb.matrix);
2019 old_elem_dof->GetRow(k, old_dofs);
2021 for (
int vd = 0; vd <
vdim; vd++)
2023 old_dofs.Copy(old_vdofs);
2026 for (
int i = 0; i < lR.Height(); i++)
2028 if (lR(i, 0) == std::numeric_limits<double>::infinity())
2032 int m = (r >= 0) ? r : (-1 - r);
2037 diag->SetRow(r, old_vdofs, row);
2047 for (std::map<int, DerefDofMessage>::iterator
2048 it = messages.begin(); it != messages.end(); ++it)
2050 MPI_Wait(&it->second.request, MPI_STATUS_IGNORE);
2054 SparseMatrix *offd =
new SparseMatrix(
ndofs*vdim, 1);
2056 std::map<HYPRE_Int, int> col_map;
2057 for (
int k = 0; k < dtrans.embeddings.Size(); k++)
2059 const Embedding &emb = dtrans.embeddings[k];
2060 if (emb.parent < 0) {
continue; }
2062 int coarse_rank = pncmesh->ElementRank(emb.parent);
2063 int fine_rank = old_ranks[k];
2065 if (coarse_rank == MyRank && fine_rank != MyRank)
2067 DenseMatrix &lR = localR(emb.matrix);
2071 DerefDofMessage &msg = messages[k];
2072 MFEM_ASSERT(msg.dofs.size(),
"");
2074 for (
int vd = 0; vd <
vdim; vd++)
2076 HYPRE_Int* remote_dofs = &msg.dofs[vd*ldof];
2078 for (
int i = 0; i < lR.Height(); i++)
2080 if (lR(i, 0) == std::numeric_limits<double>::infinity())
2084 int m = (r >= 0) ? r : (-1 - r);
2089 for (
int j = 0; j < ldof; j++)
2091 if (std::abs(row[j]) < 1e-12) {
continue; }
2092 int &lcol = col_map[remote_dofs[j]];
2093 if (!lcol) { lcol = col_map.size(); }
2094 offd->_Set_(m, lcol-1, row[j]);
2104 offd->SetWidth(col_map.size());
2107 HYPRE_Int *cmap =
new HYPRE_Int[col_map.size()];
2108 for (std::map<HYPRE_Int, int>::iterator
2109 it = col_map.begin(); it != col_map.end(); ++it)
2111 cmap[it->second-1] = it->first;
2115 R =
new HypreParMatrix(MyComm, dof_offsets[nrk], old_dof_offsets[nrk],
2116 dof_offsets, old_dof_offsets, diag, offd, cmap);
2118 #ifndef HYPRE_BIGINT
2122 diag->SetDataOwner(
false);
2123 offd->SetDataOwner(
false);
2128 R->SetOwnerFlags(3, 3, 1);
2133 void ParFiniteElementSpace::Destroy()
2141 ldof_sign.DeleteAll();
2146 delete gcomm; gcomm = NULL;
2163 MFEM_ABORT(
"Error in update sequence. Space needs to be updated after "
2164 "each mesh modification.");
2174 Table* old_elem_dof = NULL;
2183 Swap(dof_offsets, old_dof_offsets);
2207 T = ParallelDerefinementMatrix(old_ndofs, old_elem_dof);
2217 T = RebalanceMatrix(old_ndofs, old_elem_dof);
2224 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)
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.
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
Array< int > face_nbr_elements_offset
void ExchangeFaceNbrData()
virtual int GetRow(const int row, Array< int > &cols, Vector &srow) const
static const int Dimension[NumGeom]
Operator * T
Transformation to apply to GridFunctions after space Update().
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.
virtual void Finalize(int skip_zeros=1)
double * GetData() const
Return element data.
void GetEdgeDofs(int i, Array< int > &dofs) const
int * GetI() const
Return the array I.
int GetGroupMaster(int g) const
HypreParMatrix * Dof_TrueDof_Matrix()
The true dof-to-dof interpolation matrix.
void Swap(Array< T > &, Array< T > &)
int GetDof() const
Returns the degrees of freedom in the FE space.
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
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 >))
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.
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.
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