12 #include "../config/config.hpp"
17 #include "../general/sort_pairs.hpp"
25 ParFiniteElementSpace::ParFiniteElementSpace(ParFiniteElementSpace &pf)
26 : FiniteElementSpace(pf)
34 ltdof_size = pf.ltdof_size;
35 Swap(ldof_group, pf.ldof_group);
36 Swap(ldof_ltdof, pf.ldof_ltdof);
37 Swap(dof_offsets, pf.dof_offsets);
38 Swap(tdof_offsets, pf.tdof_offsets);
39 Swap(tdof_nb_offsets, pf.tdof_nb_offsets);
40 Swap(ldof_sign, pf.ldof_sign);
45 num_face_nbr_dofs = pf.num_face_nbr_dofs;
46 pf.num_face_nbr_dofs = -1;
47 Swap<Table>(face_nbr_element_dof, pf.face_nbr_element_dof);
49 Swap(face_nbr_glob_dof_map, pf.face_nbr_glob_dof_map);
50 Swap<Table>(send_face_nbr_ldof, pf.send_face_nbr_ldof);
53 ParFiniteElementSpace::ParFiniteElementSpace(
60 MPI_Comm_size(MyComm, &NRanks);
61 MPI_Comm_rank(MyComm, &MyRank);
72 GetParallelConformingInterpolation();
90 ConstructTrueNURBSDofs();
97 GenerateGlobalOffsets();
100 void ParFiniteElementSpace::GetGroupComm(
108 int group_ldof_counter;
122 group_ldof_counter = 0;
123 for (gr = 1; gr < ng; gr++)
126 group_ldof_counter += ned * pmesh->
GroupNEdges(gr);
127 group_ldof_counter += nfd * pmesh->
GroupNFaces(gr);
131 group_ldof_counter *=
vdim;
134 group_ldof.
SetDims(ng, group_ldof_counter);
137 group_ldof_counter = 0;
138 group_ldof.
GetI()[0] = group_ldof.
GetI()[1] = 0;
139 for (gr = 1; gr < ng; gr++)
141 int j, k, l, m, o, nv, ne, nf;
151 for (j = 0; j < nv; j++)
157 for (l = 0; l < nvd; l++, m++)
167 for (l = 0; l < dofs.
Size(); l++)
169 group_ldof.
GetJ()[group_ldof_counter++] = dofs[l];
177 for (j = 0; j < ne; j++)
184 for (l = 0; l < ned; l++)
187 dofs[l] = m + (-1-ind[l]);
190 (*ldof_sign)[dofs[l]] = -1;
195 dofs[l] = m + ind[l];
203 for (l = 0; l < dofs.
Size(); l++)
205 group_ldof.
GetJ()[group_ldof_counter++] = dofs[l];
213 for (j = 0; j < nf; j++)
221 for (l = 0; l < nfd; l++)
224 dofs[l] = m + (-1-ind[l]);
227 (*ldof_sign)[dofs[l]] = -1;
232 dofs[l] = m + ind[l];
240 for (l = 0; l < dofs.
Size(); l++)
242 group_ldof.
GetJ()[group_ldof_counter++] = dofs[l];
247 group_ldof.
GetI()[gr+1] = group_ldof_counter;
253 void ParFiniteElementSpace::ApplyLDofSigns(Array<int> &dofs)
const
255 for (
int i = 0; i < dofs.Size(); i++)
259 if (ldof_sign[-1-dofs[i]] < 0)
261 dofs[i] = -1-dofs[i];
266 if (ldof_sign[dofs[i]] < 0)
268 dofs[i] = -1-dofs[i];
284 ApplyLDofSigns(dofs);
298 ApplyLDofSigns(dofs);
307 ApplyLDofSigns(dofs);
311 void ParFiniteElementSpace::GenerateGlobalOffsets()
313 if (HYPRE_AssumedPartitionCheck())
323 MPI_Scan(ldof, &dof_offsets[0], 2, HYPRE_MPI_INT, MPI_SUM, MyComm);
325 tdof_offsets[1] = dof_offsets[1];
326 tdof_offsets[0] = tdof_offsets[1] - ldof[1];
328 dof_offsets[1] = dof_offsets[0];
329 dof_offsets[0] = dof_offsets[1] - ldof[0];
332 if (MyRank == NRanks-1)
334 ldof[0] = dof_offsets[1];
335 ldof[1] = tdof_offsets[1];
338 MPI_Bcast(ldof, 2, HYPRE_MPI_INT, NRanks-1, MyComm);
339 dof_offsets[2] = ldof[0];
340 tdof_offsets[2] = ldof[1];
343 MFEM_VERIFY(dof_offsets[0] >= 0 && dof_offsets[1] >= 0,
344 "overflow in global dof_offsets");
345 MFEM_VERIFY(tdof_offsets[0] >= 0 && tdof_offsets[1] >= 0,
346 "overflow in global tdof_offsets");
351 GroupTopology > = GetGroupTopo();
352 int nsize = gt.GetNumNeighbors()-1;
353 MPI_Request *requests =
new MPI_Request[2*nsize];
354 MPI_Status *statuses =
new MPI_Status[2*nsize];
355 tdof_nb_offsets.
SetSize(nsize+1);
356 tdof_nb_offsets[0] = tdof_offsets[0];
358 int request_counter = 0;
360 for (
int i = 1; i <= nsize; i++)
362 MPI_Irecv(&tdof_nb_offsets[i], 1, HYPRE_MPI_INT,
363 gt.GetNeighborRank(i), 5365, MyComm,
364 &requests[request_counter++]);
366 for (
int i = 1; i <= nsize; i++)
368 MPI_Isend(&tdof_nb_offsets[0], 1, HYPRE_MPI_INT,
369 gt.GetNeighborRank(i), 5365, MyComm,
370 &requests[request_counter++]);
372 MPI_Waitall(request_counter, requests, statuses);
388 dof_offsets.
SetSize (NRanks+1);
389 tdof_offsets.
SetSize(NRanks+1);
391 MPI_Allgather(&ldof, 1, HYPRE_MPI_INT,
392 &dof_offsets[1], 1, HYPRE_MPI_INT, MyComm);
393 MPI_Allgather(<dof, 1, HYPRE_MPI_INT,
394 &tdof_offsets[1], 1, HYPRE_MPI_INT, MyComm);
396 dof_offsets[0] = tdof_offsets[0] = 0;
397 for (i = 1; i < NRanks; i++)
399 dof_offsets [i+1] += dof_offsets [i];
400 tdof_offsets[i+1] += tdof_offsets[i];
404 MFEM_VERIFY(dof_offsets[MyRank] >= 0 && dof_offsets[MyRank+1] >= 0,
405 "overflow in global dof_offsets");
406 MFEM_VERIFY(tdof_offsets[MyRank] >= 0 && tdof_offsets[MyRank+1] >= 0,
407 "overflow in global tdof_offsets");
420 GetParallelConformingInterpolation();
427 HYPRE_Int *i_diag =
new HYPRE_Int[ldof+1];
428 HYPRE_Int *j_diag =
new HYPRE_Int[ltdof];
431 HYPRE_Int *i_offd =
new HYPRE_Int[ldof+1];
432 HYPRE_Int *j_offd =
new HYPRE_Int[ldof-ltdof];
435 HYPRE_Int *cmap =
new HYPRE_Int[ldof-ltdof];
442 i_diag[0] = i_offd[0] = 0;
443 diag_counter = offd_counter = 0;
444 for (
int i = 0; i < ldof; i++)
449 j_diag[diag_counter++] = ltdof;
454 cmap_j_offd[offd_counter].two = offd_counter;
457 i_diag[i+1] = diag_counter;
458 i_offd[i+1] = offd_counter;
463 for (
int i = 0; i < offd_counter; i++)
465 cmap[i] = cmap_j_offd[i].one;
466 j_offd[cmap_j_offd[i].two] = i;
469 P =
new HypreParMatrix(MyComm, MyRank, NRanks, row_starts, col_starts,
470 i_diag, j_diag, i_offd, j_offd, cmap, offd_counter);
483 MFEM_ABORT(
"Not implemented for NC mesh.");
488 for (
int i = 0; i < ldof_group.
Size(); i++)
499 MFEM_WARNING(
"Not implemented for NC mesh.");
506 gc->
Create(pNURBSext()->ldof_group);
510 GetGroupComm(*gc, 0);
519 MFEM_ABORT(
"Not implemented for NC mesh.");
524 mfem_error(
"ParFiniteElementSpace::Synchronize");
529 gcomm->
Bcast(ldof_marker);
559 MFEM_VERIFY(P,
"Dof_TrueDof_Matrix() needs to be called before "
560 "GetLocalTDofNumber()");
562 return ldof_ltdof[ldof];
566 if (GetGroupTopo().IAmMaster(ldof_group[ldof]))
568 return ldof_ltdof[ldof];
581 MFEM_VERIFY(ldof_ltdof[ldof] >= 0,
"ldof " << ldof <<
" not a true DOF.");
587 if (HYPRE_AssumedPartitionCheck())
589 return ldof_ltdof[ldof] +
594 return ldof_ltdof[ldof] +
604 MFEM_ABORT(
"Not implemented for NC mesh.");
607 if (HYPRE_AssumedPartitionCheck())
611 return ldof_ltdof[sldof] +
613 ldof_group[sldof])] /
vdim;
617 return (ldof_ltdof[sldof*
vdim] +
618 tdof_nb_offsets[GetGroupTopo().GetGroupMaster(
625 return ldof_ltdof[sldof] +
627 ldof_group[sldof])] /
vdim;
631 return (ldof_ltdof[sldof*
vdim] +
632 tdof_offsets[GetGroupTopo().GetGroupMasterRank(
639 return HYPRE_AssumedPartitionCheck() ? dof_offsets[0] : dof_offsets[MyRank];
644 return HYPRE_AssumedPartitionCheck()? tdof_offsets[0] : tdof_offsets[MyRank];
655 if (num_face_nbrs == 0)
661 MPI_Request *requests =
new MPI_Request[2*num_face_nbrs];
662 MPI_Request *send_requests = requests;
663 MPI_Request *recv_requests = requests + num_face_nbrs;
664 MPI_Status *statuses =
new MPI_Status[num_face_nbrs];
670 Table send_nbr_elem_dof;
677 for (
int fn = 0; fn < num_face_nbrs; fn++)
682 for (
int i = 0; i < num_my_elems; i++)
685 for (
int j = 0; j < ldofs.
Size(); j++)
686 if (ldof_marker[ldofs[j]] != fn)
688 ldof_marker[ldofs[j]] = fn;
697 MyComm, &send_requests[fn]);
700 MyComm, &recv_requests[fn]);
703 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
708 MPI_Waitall(num_face_nbrs, send_requests, statuses);
716 int *send_I = send_nbr_elem_dof.
GetI();
718 for (
int fn = 0; fn < num_face_nbrs; fn++)
722 MPI_Isend(send_I + send_el_off[fn], send_el_off[fn+1] - send_el_off[fn],
723 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
725 MPI_Irecv(recv_I + recv_el_off[fn], recv_el_off[fn+1] - recv_el_off[fn],
726 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
729 MPI_Waitall(num_face_nbrs, send_requests, statuses);
730 send_nbr_elem_dof.
MakeJ();
734 for (
int fn = 0; fn < num_face_nbrs; fn++)
739 for (
int i = 0; i < num_my_elems; i++)
742 for (
int j = 0; j < ldofs.
Size(); j++)
744 if (ldof_marker[ldofs[j]] != fn)
746 ldof_marker[ldofs[j]] = fn;
751 send_el_off[fn] + i, ldofs, ldofs.
Size());
758 int *send_J = send_nbr_elem_dof.
GetJ();
759 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
763 int j_end = send_I[send_el_off[fn+1]];
765 for (
int i = 0; i < num_ldofs; i++)
767 ldof_marker[ldofs[i]] = i;
770 for ( ; j < j_end; j++)
772 send_J[j] = ldof_marker[send_J[j]];
776 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
783 for (
int fn = 0; fn < num_face_nbrs; fn++)
788 MPI_Isend(send_J + send_I[send_el_off[fn]],
789 send_I[send_el_off[fn+1]] - send_I[send_el_off[fn]],
790 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
792 MPI_Irecv(recv_J + recv_I[recv_el_off[fn]],
793 recv_I[recv_el_off[fn+1]] - recv_I[recv_el_off[fn]],
794 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
797 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
800 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
803 int j_end = recv_I[recv_el_off[fn+1]];
805 for ( ; j < j_end; j++)
811 MPI_Waitall(num_face_nbrs, send_requests, statuses);
816 for (
int fn = 0; fn < num_face_nbrs; fn++)
823 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
827 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
830 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
831 MPI_Waitall(num_face_nbrs, send_requests, statuses);
838 for (
int fn = 0; fn < num_face_nbrs; fn++)
843 MPI_Isend(&my_dof_offset, 1, HYPRE_MPI_INT, nbr_rank, tag,
844 MyComm, &send_requests[fn]);
846 MPI_Irecv(&dof_face_nbr_offsets[fn], 1, HYPRE_MPI_INT, nbr_rank, tag,
847 MyComm, &recv_requests[fn]);
850 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
854 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
861 MPI_Waitall(num_face_nbrs, send_requests, statuses);
881 mfem_error(
"ParFiniteElementSpace::GetFaceNbrFE"
882 " does not support NURBS!");
889 hypre_ParCSRMatrix *csrP = (hypre_ParCSRMatrix*)(*P);
890 hypre_ParCSRMatrixOwnsRowStarts(csrP) = 1;
891 hypre_ParCSRMatrixOwnsColStarts(csrP) = 1;
897 void ParFiniteElementSpace::ConstructTrueDofs()
904 GetGroupComm(*gcomm, 1, &ldof_sign);
914 for (gr = 1; gr < group_ldof.
Size(); gr++)
916 const int *ldofs = group_ldof.
GetRow(gr);
917 const int nldofs = group_ldof.
RowSize(gr);
918 for (i = 0; i < nldofs; i++)
920 ldof_group[ldofs[i]] = gr;
925 for (i = 0; i < nldofs; i++)
927 ldof_ltdof[ldofs[i]] = -2;
934 for (i = 0; i < n; i++)
936 if (ldof_ltdof[i] == -1)
938 ldof_ltdof[i] = ltdof_size++;
943 gcomm->
Bcast(ldof_ltdof);
946 void ParFiniteElementSpace::ConstructTrueNURBSDofs()
949 GroupTopology > = pNURBSext()->
gtopo;
950 gcomm =
new GroupCommunicator(gt);
955 ldof_group.
MakeRef(pNURBSext()->ldof_group);
959 const int *scalar_ldof_group = pNURBSext()->
ldof_group;
961 for (
int i = 0; i < n; i++)
963 ldof_group[i] = scalar_ldof_group[
VDofToDof(i)];
967 gcomm->
Create(ldof_group);
975 for (
int i = 0; i < n; i++)
977 if (gt.IAmMaster(ldof_group[i]))
979 ldof_ltdof[i] = ltdof_size;
989 gcomm->
Bcast(ldof_ltdof);
994 return (dof >= 0) ? (sign = 1, dof) : (sign = -1, (-1 - dof));
1012 if (pm.
Width() == 2)
1016 for (i = 0; i < 2; i++)
1018 if (pm(0, i) == 0.0 || pm(0, i) == 1.0)
1020 for (k = 0; k < nv; k++) { slave_dofs[i*nv + k] =
INVALID_DOF; }
1027 MFEM_ASSERT(pm.
Width() == 4,
"");
1030 for (i = 0; i < 4; i++)
1032 double x = pm(0,i), y = pm(1,i);
1033 corner[i] = ((x == 0.0 || x == 1.0) && (y == 0.0 || y == 1.0));
1037 for (i = 0; i < 4; i++)
1041 for (k = 0; k < nv; k++) { slave_dofs[i*nv + k] =
INVALID_DOF; }
1047 for (i = 0; i < 4; i++)
1049 if (corner[i] && corner[(i+1) % 4])
1051 for (k = 0; k < ne; k++)
1061 void ParFiniteElementSpace
1062 ::AddSlaveDependencies(DepList deps[],
int master_rank,
1063 const Array<int> &master_dofs,
int master_ndofs,
1064 const Array<int> &slave_dofs, DenseMatrix& I)
1067 for (
int i = 0; i < slave_dofs.Size(); i++)
1073 for (
int vd = 0; vd <
vdim; vd++)
1078 Array<Dependency> tmp_list;
1079 for (
int j = 0; j < master_dofs.Size(); j++)
1081 double coef = I(i, j);
1082 if (std::abs(coef) > 1e-12)
1085 int mvdof =
DofToVDof(mdof, vd, master_ndofs);
1086 tmp_list.Append(Dependency(master_rank, mvdof, coef*ms*ss));
1090 tmp_list.Copy(dl.list);
1096 void ParFiniteElementSpace
1097 ::Add1To1Dependencies(DepList deps[],
int owner_rank,
1098 const Array<int> &owner_dofs,
int owner_ndofs,
1099 const Array<int> &dependent_dofs)
1101 MFEM_ASSERT(owner_dofs.Size() == dependent_dofs.Size(),
"");
1103 for (
int vd = 0; vd <
vdim; vd++)
1105 for (
int i = 0; i < owner_dofs.Size(); i++)
1107 double osign, dsign;
1109 int ddof =
decode_dof(dependent_dofs[i], dsign);
1112 int ovdof =
DofToVDof(odof, vd, owner_ndofs);
1115 DepList &dl = deps[dvdof];
1119 dl.list.Append(Dependency(owner_rank, ovdof, osign*dsign));
1121 else if (dl.type == 1 && dl.list[0].rank > owner_rank)
1124 dl.list[0] = Dependency(owner_rank, ovdof, osign*dsign);
1130 void ParFiniteElementSpace
1131 ::ReorderFaceDofs(Array<int> &dofs,
int orient)
1141 int ve_dofs = 4*(nv + ne);
1142 for (
int i = 0; i < ve_dofs; i++)
1147 int f_dofs = dofs.Size() - ve_dofs;
1148 for (
int i = 0; i < f_dofs; i++)
1152 dofs[ve_dofs + i] = tmp[ve_dofs + ind[i]];
1156 dofs[ve_dofs + i] = -1 - tmp[ve_dofs + (-1 - ind[i])];
1161 void ParFiniteElementSpace::GetDofs(
int type,
int index, Array<int>& dofs)
1171 void ParFiniteElementSpace::GetParallelConformingInterpolation()
1173 ParNCMesh* pncmesh = pmesh->
pncmesh;
1180 for (
int type = 0; type < 3; type++)
1182 const NCMesh::NCList &list = pncmesh->GetSharedList(type);
1185 int cs = list.conforming.size(), ms = list.masters.size();
1186 for (
int i = 0; i < cs+ms; i++)
1189 const NCMesh::MeshId&
id =
1190 (i < cs) ? (
const NCMesh::MeshId&) list.conforming[i]
1191 : (
const NCMesh::MeshId&) list.masters[i-cs];
1193 int owner = pncmesh->GetOwner(type,
id.index), gsize;
1194 if (owner == MyRank)
1197 GetDofs(type,
id.index, dofs);
1199 const int *group = pncmesh->GetGroup(type,
id.index, gsize);
1200 for (
int j = 0; j < gsize; j++)
1202 if (group[j] != MyRank)
1204 NeighborDofMessage &send_msg = send_dofs[group[j]];
1205 send_msg.Init(pncmesh,
fec,
ndofs);
1206 send_msg.AddDofs(type,
id, dofs);
1213 recv_dofs[owner].Init(pncmesh,
fec, 0);
1225 DepList* deps =
new DepList[num_dofs];
1227 Array<int> master_dofs, slave_dofs;
1228 Array<int> owner_dofs, my_dofs;
1231 for (
int type = 1; type < 3; type++)
1233 const NCMesh::NCList &list = (type > 1) ? pncmesh->GetFaceList()
1234 : pncmesh->GetEdgeList();
1235 if (!list.masters.size()) {
continue; }
1237 IsoparametricTransformation T;
1243 if (!fe) {
continue; }
1245 DenseMatrix I(fe->GetDof());
1248 for (
unsigned mi = 0; mi < list.masters.size(); mi++)
1250 const NCMesh::Master &mf = list.masters[mi];
1251 if (!pncmesh->RankInGroup(type, mf.index, MyRank)) {
continue; }
1254 int master_ndofs, master_rank = pncmesh->GetOwner(type, mf.index);
1255 if (master_rank == MyRank)
1257 GetDofs(type, mf.index, master_dofs);
1258 master_ndofs =
ndofs;
1262 recv_dofs[master_rank].GetDofs(type, mf, master_dofs, master_ndofs);
1265 if (!master_dofs.Size()) {
continue; }
1268 for (
int si = mf.slaves_begin; si < mf.slaves_end; si++)
1270 const NCMesh::Slave &sf = list.slaves[si];
1271 if (pncmesh->IsGhost(type, sf.index)) {
continue; }
1273 GetDofs(type, sf.index, slave_dofs);
1274 if (!slave_dofs.Size()) {
continue; }
1276 T.GetPointMat() = sf.point_matrix;
1277 fe->GetLocalInterpolation(T, I);
1280 MaskSlaveDofs(slave_dofs, sf.point_matrix,
fec);
1281 AddSlaveDependencies(deps, master_rank, master_dofs, master_ndofs,
1287 if (master_rank != MyRank && !pncmesh->IsGhost(type, mf.index))
1289 GetDofs(type, mf.index, my_dofs);
1290 Add1To1Dependencies(deps, master_rank, master_dofs, master_ndofs,
1297 for (
int type = 0; type < 3; type++)
1299 const NCMesh::NCList &list = pncmesh->GetSharedList(type);
1300 for (
unsigned i = 0; i < list.conforming.size(); i++)
1302 const NCMesh::MeshId &
id = list.conforming[i];
1303 GetDofs(type,
id.index, my_dofs);
1306 int owner_ndofs, owner = pncmesh->GetOwner(type,
id.index);
1307 if (owner != MyRank)
1309 recv_dofs[owner].GetDofs(type,
id, owner_dofs, owner_ndofs);
1312 int fo = pncmesh->GetFaceOrientation(
id.index);
1313 ReorderFaceDofs(owner_dofs, fo);
1315 Add1To1Dependencies(deps, owner, owner_dofs, owner_ndofs, my_dofs);
1320 Add1To1Dependencies(deps, owner, my_dofs,
ndofs, my_dofs);
1330 NeighborDofMessage::Map::iterator it;
1331 for (it = send_dofs.begin(); it != send_dofs.end(); ++it)
1333 recv_requests[it->first];
1335 for (it = recv_dofs.begin(); it != recv_dofs.end(); ++it)
1337 send_requests[it->first];
1341 for (
int i = 0; i < num_dofs; i++)
1343 const DepList &dl = deps[i];
1344 for (
int j = 0; j < dl.list.Size(); j++)
1346 const Dependency &dep = dl.list[j];
1347 if (dep.rank != MyRank)
1349 send_requests[dep.rank].RequestRow(dep.dof);
1361 for (
int i = 0; i < num_dofs; i++)
1363 if (deps[i].IsTrueDof(MyRank)) { ltdof_size++; }
1366 GenerateGlobalOffsets();
1368 HYPRE_Int glob_true_dofs = tdof_offsets.
Last();
1369 HYPRE_Int glob_cdofs = dof_offsets.
Last();
1373 MFEM_VERIFY(glob_true_dofs >= 0 && glob_true_dofs < (1ll << 31),
1374 "64bit matrix size not supported yet in non-conforming P.")
1376 MFEM_VERIFY(glob_true_dofs >= 0,
1377 "overflow of non-conforming P matrix columns.")
1379 SparseMatrix localP(num_dofs, glob_true_dofs);
1382 R =
new SparseMatrix(ltdof_size, num_dofs);
1384 Array<bool> finalized(num_dofs);
1391 for (
int i = 0, true_dof = 0; i < num_dofs; i++)
1393 if (deps[i].IsTrueDof(MyRank))
1395 localP.Add(i, my_tdof_offset + true_dof, 1.0);
1396 R->
Add(true_dof, i, 1.0);
1397 finalized[i] =
true;
1398 ldof_ltdof[i] = true_dof;
1407 std::list<NeighborRowReply::Map> send_replies;
1409 int num_finalized = ltdof_size;
1417 for (
int dof = 0, i; dof < num_dofs; dof++)
1419 if (finalized[dof]) {
continue; }
1422 const DepList &dl = deps[dof];
1423 for (i = 0; i < dl.list.Size(); i++)
1425 const Dependency &dep = dl.list[i];
1426 if (dep.rank == MyRank)
1428 if (!finalized[dep.dof]) {
break; }
1430 else if (!recv_replies[dep.rank].HaveRow(dep.dof))
1435 if (i < dl.list.Size()) {
continue; }
1438 for (i = 0; i < dl.list.Size(); i++)
1440 const Dependency &dep = dl.list[i];
1441 if (dep.rank == MyRank)
1443 localP.GetRow(dep.dof, cols, srow);
1447 recv_replies[dep.rank].GetRow(dep.dof, cols, srow);
1450 localP.AddRow(dof, cols, srow);
1453 finalized[dof] =
true;
1463 NeighborRowRequest::Map::iterator it;
1464 for (it = recv_requests.begin(); it != recv_requests.end(); ++it)
1466 NeighborRowRequest &req = it->second;
1467 std::set<int>::iterator row;
1468 for (row = req.rows.begin(); row != req.rows.end(); )
1470 if (finalized[*row])
1472 localP.GetRow(*row, cols, srow);
1473 send_replies.back()[it->first].AddRow(*row, cols, srow);
1474 req.rows.erase(row++);
1482 if (num_finalized >= num_dofs) {
break; }
1487 recv_replies[rank].Recv(rank, size, MyComm);
1492 recv_replies[rank].Recv(rank, size, MyComm);
1500 #ifndef HYPRE_BIGINT
1501 P =
new HypreParMatrix(MyComm, num_dofs, glob_cdofs, glob_true_dofs,
1502 localP.GetI(), localP.GetJ(), localP.GetData(),
1506 MFEM_ABORT(
"HYPRE_BIGINT not supported yet.");
1515 for (std::list<NeighborRowReply::Map>::iterator
1516 it = send_replies.begin(); it != send_replies.end(); ++it)
1545 ConstructTrueDofs();
1546 GenerateGlobalOffsets();
1550 GetParallelConformingInterpolation();
1560 ConstructTrueDofs();
1561 GenerateGlobalOffsets();
1565 GetParallelConformingInterpolation();
Abstract class for Finite Elements.
int GetNFaceNeighbors() const
int GetGroupMasterRank(int g) const
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.
template void SortPairs< HYPRE_Int, int >(Pair< HYPRE_Int, int > *, int)
int DofToVDof(int dof, int vd, int ndofs=-1) const
void AddColumnsInRow(int r, int ncol)
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
void Swap< Table >(Table &a, Table &b)
Specialization of the template function Swap<> for class Table.
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
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, but treat all elements as booleans (zero=false, nonzero=true).
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols.
int GetGroupSize(int g) const
void SetDims(int rows, int nnz)
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)
void DivideByGroupSize(double *vec)
Scale a vector of true dofs.
Abstract parallel finite element space.
void Synchronize(Array< int > &ldof_marker) const
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()
const FiniteElementCollection * fec
int Size_of_connections() const
HYPRE_Int GetMyDofOffset() 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
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)
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()
void Finalize()
Allocate internal buffers after the GroupLDofTable is defined.
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)
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)
void GetEdgeDofs(int i, Array< int > &dofs) const
int GetGroupMaster(int g) const
HypreParMatrix * Dof_TrueDof_Matrix()
The true dof-to-dof interpolation matrix.
void Swap(Array< T > &, Array< T > &)
Abstract finite element 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)
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.
Table face_nbr_element_dof
void GroupFace(int group, int i, int &face, int &o)
Mesh * mesh
The mesh that FE space lives on.
int GroupNFaces(int group)
void Reduce(T *ldata, void(*Op)(OpData< T >))
void Create(Array< int > &ldof_group)
T & Last()
Return the last element in the array.
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.
void DofsToVDofs(Array< int > &dofs) const
int GetFaceBaseGeometry(int i) 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.
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.
BiLinear2DFiniteElement QuadrilateralFE
Class for parallel meshes.
virtual FiniteElementSpace * SaveUpdate()
Return a copy of the current FE space and update.
int GetFaceNbrRank(int fn) const
Linear1DFiniteElement SegmentFE
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
static void BitOR(OpData< T >)
Reduce operation bitwise OR, instantiated for int only.
Array< HYPRE_Int > face_nbr_glob_dof_map