12 #include "../config/config.hpp"
17 #include "../general/sort_pairs.hpp"
18 #include "../mesh/mesh_headers.hpp"
19 #include "../general/binaryio.hpp"
33 ParInit(pmesh ? pmesh : orig.pmesh);
49 f ? f : global_fes->FEColl(),
50 global_fes->GetVDim(), global_fes->GetOrdering())
69 int dim,
int ordering)
79 if (globNURBSext == NULL) {
return NULL; }
80 const ParNURBSExtension *pNURBSext =
81 dynamic_cast<const ParNURBSExtension*
>(parNURBSext);
82 MFEM_ASSERT(pNURBSext,
"need a ParNURBSExtension");
84 NURBSExtension *tmp_globNURBSext =
new NURBSExtension(*globNURBSext);
86 return new ParNURBSExtension(tmp_globNURBSext, pNURBSext);
89 void ParFiniteElementSpace::ParInit(ParMesh *pm)
92 pncmesh = pm->pncmesh;
111 MFEM_ASSERT(
own_ext,
"internal error");
113 ParNURBSExtension *pNe =
new ParNURBSExtension(
129 void ParFiniteElementSpace::Construct()
133 ConstructTrueNURBSDofs();
134 GenerateGlobalOffsets();
139 GenerateGlobalOffsets();
147 ngedofs = ngfdofs = 0;
161 ngdofs = ngvdofs + ngedofs + ngfdofs;
165 ltdof_size = BuildParallelConformingInterpolation(
166 &P, &R, dof_offsets, tdof_offsets, &ldof_ltdof,
false);
174 void ParFiniteElementSpace::GetGroupComm(
175 GroupCommunicator &gc,
int ldof_type, Array<int> *ldof_sign)
182 int group_ldof_counter;
183 Table &group_ldof = gc.GroupLDofTable();
197 group_ldof_counter = 0;
198 for (gr = 1; gr < ng; gr++)
201 group_ldof_counter += ned * pmesh->
GroupNEdges(gr);
202 group_ldof_counter += nfd * pmesh->
GroupNFaces(gr);
206 group_ldof_counter *=
vdim;
209 group_ldof.SetDims(ng, group_ldof_counter);
212 group_ldof_counter = 0;
213 group_ldof.GetI()[0] = group_ldof.GetI()[1] = 0;
214 for (gr = 1; gr < ng; gr++)
216 int j, k, l, m, o, nv, ne, nf;
226 for (j = 0; j < nv; j++)
232 for (l = 0; l < nvd; l++, m++)
242 for (l = 0; l < dofs.Size(); l++)
244 group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
252 for (j = 0; j < ne; j++)
259 for (l = 0; l < ned; l++)
263 dofs[l] = m + (-1-ind[l]);
266 (*ldof_sign)[dofs[l]] = -1;
271 dofs[l] = m + ind[l];
280 for (l = 0; l < dofs.Size(); l++)
282 group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
290 for (j = 0; j < nf; j++)
298 for (l = 0; l < nfd; l++)
302 dofs[l] = m + (-1-ind[l]);
305 (*ldof_sign)[dofs[l]] = -1;
310 dofs[l] = m + ind[l];
319 for (l = 0; l < dofs.Size(); l++)
321 group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
326 group_ldof.GetI()[gr+1] = group_ldof_counter;
332 void ParFiniteElementSpace::ApplyLDofSigns(Array<int> &dofs)
const
336 for (
int i = 0; i < dofs.Size(); i++)
340 if (ldof_sign[-1-dofs[i]] < 0)
342 dofs[i] = -1-dofs[i];
347 if (ldof_sign[dofs[i]] < 0)
349 dofs[i] = -1-dofs[i];
355 void ParFiniteElementSpace::ApplyLDofSigns(Table &el_dof)
const
357 Array<int> all_dofs(el_dof.GetJ(), el_dof.Size_of_connections());
358 ApplyLDofSigns(all_dofs);
371 ApplyLDofSigns(dofs);
385 ApplyLDofSigns(dofs);
394 ApplyLDofSigns(dofs);
402 MFEM_ASSERT(0 <= ei && ei < pmesh->GroupNEdges(group),
"invalid edge index");
403 pmesh->
GroupEdge(group, ei, l_edge, ori);
413 for (
int i = 0; i < dofs.
Size(); i++)
415 const int di = dofs[i];
416 dofs[i] = (di >= 0) ? rdofs[di] : -1-rdofs[-1-di];
425 MFEM_ASSERT(0 <= fi && fi < pmesh->GroupNFaces(group),
"invalid face index");
426 pmesh->
GroupFace(group, fi, l_face, ori);
436 for (
int i = 0; i < dofs.
Size(); i++)
438 const int di = dofs[i];
439 dofs[i] = (di >= 0) ? rdofs[di] : -1-rdofs[-1-di];
444 void ParFiniteElementSpace::GenerateGlobalOffsets()
const
456 if (HYPRE_AssumedPartitionCheck())
459 GroupTopology > = GetGroupTopo();
460 int nsize = gt.GetNumNeighbors()-1;
461 MPI_Request *requests =
new MPI_Request[2*nsize];
462 MPI_Status *statuses =
new MPI_Status[2*nsize];
463 tdof_nb_offsets.
SetSize(nsize+1);
464 tdof_nb_offsets[0] = tdof_offsets[0];
467 int request_counter = 0;
468 for (
int i = 1; i <= nsize; i++)
470 MPI_Irecv(&tdof_nb_offsets[i], 1, HYPRE_MPI_INT,
471 gt.GetNeighborRank(i), 5365, MyComm,
472 &requests[request_counter++]);
474 for (
int i = 1; i <= nsize; i++)
476 MPI_Isend(&tdof_nb_offsets[0], 1, HYPRE_MPI_INT,
477 gt.GetNeighborRank(i), 5365, MyComm,
478 &requests[request_counter++]);
480 MPI_Waitall(request_counter, requests, statuses);
487 void ParFiniteElementSpace::Build_Dof_TrueDof_Matrix() const
496 HYPRE_Int *i_diag =
new HYPRE_Int[ldof+1];
497 HYPRE_Int *j_diag =
new HYPRE_Int[ltdof];
500 HYPRE_Int *i_offd =
new HYPRE_Int[ldof+1];
501 HYPRE_Int *j_offd =
new HYPRE_Int[ldof-ltdof];
504 HYPRE_Int *cmap =
new HYPRE_Int[ldof-ltdof];
509 Array<Pair<HYPRE_Int, int> > cmap_j_offd(ldof-ltdof);
511 i_diag[0] = i_offd[0] = 0;
512 diag_counter = offd_counter = 0;
513 for (
int i = 0; i < ldof; i++)
518 j_diag[diag_counter++] = ltdof;
523 cmap_j_offd[offd_counter].two = offd_counter;
526 i_diag[i+1] = diag_counter;
527 i_offd[i+1] = offd_counter;
530 SortPairs<HYPRE_Int, int>(cmap_j_offd, offd_counter);
532 for (
int i = 0; i < offd_counter; i++)
534 cmap[i] = cmap_j_offd[i].one;
535 j_offd[cmap_j_offd[i].two] = i;
538 P =
new HypreParMatrix(MyComm, MyRank, NRanks, row_starts, col_starts,
539 i_diag, j_diag, i_offd, j_offd, cmap, offd_counter);
550 BuildParallelConformingInterpolation(&P_pc, NULL, P_pc_row_starts,
551 P_pc_col_starts, NULL,
true);
561 MFEM_ABORT(
"Not implemented for NC mesh.");
566 for (
int i = 0; i < ldof_group.
Size(); i++)
586 gc->
Create(pNURBSext()->ldof_group);
590 GetGroupComm(*gc, 0);
599 MFEM_ABORT(
"Not implemented for NC mesh.");
604 mfem_error(
"ParFiniteElementSpace::Synchronize");
609 gcomm->
Bcast(ldof_marker);
639 Pt->BooleanMult(1, ess_dofs, 0, true_ess_dofs2);
642 for (
int i = 0; i < true_ess_dofs.
Size(); i++)
644 if (
bool(true_ess_dofs[i]) != bool(true_ess_dofs2[i])) { counter++; }
646 MFEM_VERIFY(counter == 0,
"internal MFEM error: counter = " << counter);
657 return ldof_ltdof[ldof];
661 if (GetGroupTopo().IAmMaster(ldof_group[ldof]))
663 return ldof_ltdof[ldof];
676 MFEM_VERIFY(ldof_ltdof[ldof] >= 0,
"ldof " << ldof <<
" not a true DOF.");
682 if (HYPRE_AssumedPartitionCheck())
684 return ldof_ltdof[ldof] +
689 return ldof_ltdof[ldof] +
699 MFEM_ABORT(
"Not implemented for NC mesh.");
702 if (HYPRE_AssumedPartitionCheck())
706 return ldof_ltdof[sldof] +
708 ldof_group[sldof])] /
vdim;
712 return (ldof_ltdof[sldof*
vdim] +
713 tdof_nb_offsets[GetGroupTopo().GetGroupMaster(
720 return ldof_ltdof[sldof] +
722 ldof_group[sldof])] /
vdim;
726 return (ldof_ltdof[sldof*
vdim] +
727 tdof_offsets[GetGroupTopo().GetGroupMasterRank(
734 return HYPRE_AssumedPartitionCheck() ? dof_offsets[0] : dof_offsets[MyRank];
739 return HYPRE_AssumedPartitionCheck()? tdof_offsets[0] : tdof_offsets[MyRank];
763 if (num_face_nbrs == 0)
769 MPI_Request *requests =
new MPI_Request[2*num_face_nbrs];
770 MPI_Request *send_requests = requests;
771 MPI_Request *recv_requests = requests + num_face_nbrs;
772 MPI_Status *statuses =
new MPI_Status[num_face_nbrs];
778 Table send_nbr_elem_dof;
785 for (
int fn = 0; fn < num_face_nbrs; fn++)
790 for (
int i = 0; i < num_my_elems; i++)
793 for (
int j = 0; j < ldofs.
Size(); j++)
794 if (ldof_marker[ldofs[j]] != fn)
796 ldof_marker[ldofs[j]] = fn;
805 MyComm, &send_requests[fn]);
808 MyComm, &recv_requests[fn]);
811 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
816 MPI_Waitall(num_face_nbrs, send_requests, statuses);
824 int *send_I = send_nbr_elem_dof.
GetI();
826 for (
int fn = 0; fn < num_face_nbrs; fn++)
830 MPI_Isend(send_I + send_el_off[fn], send_el_off[fn+1] - send_el_off[fn],
831 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
833 MPI_Irecv(recv_I + recv_el_off[fn], recv_el_off[fn+1] - recv_el_off[fn],
834 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
837 MPI_Waitall(num_face_nbrs, send_requests, statuses);
838 send_nbr_elem_dof.
MakeJ();
842 for (
int fn = 0; fn < num_face_nbrs; fn++)
847 for (
int i = 0; i < num_my_elems; i++)
850 for (
int j = 0; j < ldofs.
Size(); j++)
852 if (ldof_marker[ldofs[j]] != fn)
854 ldof_marker[ldofs[j]] = fn;
859 send_el_off[fn] + i, ldofs, ldofs.
Size());
866 int *send_J = send_nbr_elem_dof.
GetJ();
867 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
871 int j_end = send_I[send_el_off[fn+1]];
873 for (
int i = 0; i < num_ldofs; i++)
875 ldof_marker[ldofs[i]] = i;
878 for ( ; j < j_end; j++)
880 send_J[j] = ldof_marker[send_J[j]];
884 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
891 for (
int fn = 0; fn < num_face_nbrs; fn++)
896 MPI_Isend(send_J + send_I[send_el_off[fn]],
897 send_I[send_el_off[fn+1]] - send_I[send_el_off[fn]],
898 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
900 MPI_Irecv(recv_J + recv_I[recv_el_off[fn]],
901 recv_I[recv_el_off[fn+1]] - recv_I[recv_el_off[fn]],
902 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
905 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
908 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
911 int j_end = recv_I[recv_el_off[fn+1]];
913 for ( ; j < j_end; j++)
919 MPI_Waitall(num_face_nbrs, send_requests, statuses);
923 for (
int fn = 0; fn < num_face_nbrs; fn++)
930 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
934 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
937 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
938 MPI_Waitall(num_face_nbrs, send_requests, statuses);
945 for (
int fn = 0; fn < num_face_nbrs; fn++)
950 MPI_Isend(&my_dof_offset, 1, HYPRE_MPI_INT, nbr_rank, tag,
951 MyComm, &send_requests[fn]);
953 MPI_Irecv(&dof_face_nbr_offsets[fn], 1, HYPRE_MPI_INT, nbr_rank, tag,
954 MyComm, &recv_requests[fn]);
957 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
961 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
968 MPI_Waitall(num_face_nbrs, send_requests, statuses);
986 int el1, el2, inf1, inf2;
999 Ordering::DofsToVDofs<Ordering::byNODES>(nd/
vdim,
vdim, vdofs);
1001 for (
int j = 0; j < vdofs.
Size(); j++)
1003 const int ldof = vdofs[j];
1004 vdofs[j] = (ldof >= 0) ? vol_vdofs[ldof] : -1-vol_vdofs[-1-ldof];
1016 mfem_error(
"ParFiniteElementSpace::GetFaceNbrFE"
1017 " does not support NURBS!");
1033 hypre_ParCSRMatrix *csrP = (hypre_ParCSRMatrix*)(*P);
1034 hypre_ParCSRMatrixOwnsRowStarts(csrP) = 1;
1035 hypre_ParCSRMatrixOwnsColStarts(csrP) = 1;
1041 void ParFiniteElementSpace::ConstructTrueDofs()
1048 GetGroupComm(*gcomm, 1, &ldof_sign);
1058 for (gr = 1; gr < group_ldof.
Size(); gr++)
1060 const int *ldofs = group_ldof.
GetRow(gr);
1061 const int nldofs = group_ldof.
RowSize(gr);
1062 for (i = 0; i < nldofs; i++)
1064 ldof_group[ldofs[i]] = gr;
1069 for (i = 0; i < nldofs; i++)
1071 ldof_ltdof[ldofs[i]] = -2;
1078 for (i = 0; i < n; i++)
1080 if (ldof_ltdof[i] == -1)
1082 ldof_ltdof[i] = ltdof_size++;
1088 gcomm->
Bcast(ldof_ltdof);
1091 void ParFiniteElementSpace::ConstructTrueNURBSDofs()
1094 GroupTopology > = pNURBSext()->
gtopo;
1095 gcomm =
new GroupCommunicator(gt);
1100 ldof_group.
MakeRef(pNURBSext()->ldof_group);
1104 const int *scalar_ldof_group = pNURBSext()->
ldof_group;
1106 for (
int i = 0; i < n; i++)
1108 ldof_group[i] = scalar_ldof_group[
VDofToDof(i)];
1112 gcomm->
Create(ldof_group);
1116 ldof_sign.DeleteAll();
1120 for (
int i = 0; i < n; i++)
1122 if (gt.IAmMaster(ldof_group[i]))
1124 ldof_ltdof[i] = ltdof_size;
1135 gcomm->
Bcast(ldof_ltdof);
1138 void ParFiniteElementSpace::GetGhostVertexDofs(
const MeshId &
id,
1139 Array<int> &dofs)
const
1143 for (
int j = 0; j < nv; j++)
1145 dofs[j] =
ndofs + nv*
id.index + j;
1149 void ParFiniteElementSpace::GetGhostEdgeDofs(
const MeshId &edge_id,
1150 Array<int> &dofs)
const
1154 dofs.SetSize(2*nv + ne);
1159 for (
int i = 0; i < 2; i++)
1161 int k = (V[i] < ghost) ? V[i]*nv : (
ndofs + (V[i] - ghost)*nv);
1162 for (
int j = 0; j < nv; j++)
1164 dofs[i*nv + j] = k++;
1168 int k =
ndofs + ngvdofs + (edge_id.index - pncmesh->
GetNEdges())*ne;
1169 for (
int j = 0; j < ne; j++)
1171 dofs[2*nv + j] = k++;
1175 void ParFiniteElementSpace::GetGhostFaceDofs(
const MeshId &face_id,
1176 Array<int> &dofs)
const
1183 dofs.SetSize(4*nv + 4*ne + nf);
1185 int V[4], E[4], Eo[4];
1189 for (
int i = 0; i < 4; i++)
1192 int first = (V[i] < ghost) ? V[i]*nv : (
ndofs + (V[i] - ghost)*nv);
1193 for (
int j = 0; j < nv; j++)
1195 dofs[offset++] = first + j;
1199 for (
int i = 0; i < 4; i++)
1202 int first = (E[i] < ghost) ?
nvdofs + E[i]*ne
1203 :
ndofs + ngvdofs + (E[i] - ghost)*ne;
1205 for (
int j = 0; j < ne; j++)
1207 dofs[offset++] = (ind[j] >= 0) ? (first + ind[j])
1208 : (-1 - (first + (-1 - ind[j])));
1212 int first =
ndofs + ngvdofs + ngedofs +
1213 (face_id.index - pncmesh->
GetNFaces())*nf;
1214 for (
int j = 0; j < nf; j++)
1216 dofs[offset++] = first + j;
1220 void ParFiniteElementSpace::GetGhostDofs(
int entity,
const MeshId &
id,
1221 Array<int> &dofs)
const
1226 case 0: GetGhostVertexDofs(
id, dofs);
break;
1227 case 1: GetGhostEdgeDofs(
id, dofs);
break;
1228 case 2: GetGhostFaceDofs(
id, dofs);
break;
1232 void ParFiniteElementSpace::GetBareDofs(
int entity,
const MeshId &
id,
1233 Array<int> &dofs)
const
1235 int ned, ghost, first;
1241 first = (
id.index < ghost)
1243 :
ndofs + (
id.index - ghost)*ned;
1249 first = (
id.index < ghost)
1251 :
ndofs + ngvdofs + (
id.index - ghost)*ned;
1257 first = (
id.index < ghost)
1259 :
ndofs + ngvdofs + ngedofs + (
id.index - ghost)*ned;
1264 for (
int i = 0; i < ned; i++)
1266 dofs[i] = first + i;
1270 int ParFiniteElementSpace::PackDof(
int entity,
int index,
int edof)
const
1282 return (index < ghost)
1284 :
ndofs + (index - ghost)*ned + edof;
1290 return (index < ghost)
1291 ?
nvdofs + index*ned + edof
1292 :
ndofs + ngvdofs + (index - ghost)*ned + edof;
1298 return (index < ghost)
1300 :
ndofs + ngvdofs + ngedofs + (index - ghost)*ned + edof;
1307 void ParFiniteElementSpace::UnpackDof(
int dof,
1308 int &entity,
int &index,
int &edof)
const
1310 MFEM_VERIFY(dof >= 0,
"");
1316 entity = 0, index = dof / nv, edof = dof % nv;
1323 entity = 1, index = dof / ne, edof = dof % ne;
1330 entity = 2, index = dof / nf, edof = dof % nf;
1333 MFEM_ABORT(
"Cannot unpack internal DOF");
1341 entity = 0, index = pncmesh->
GetNVertices() + dof / nv, edof = dof % nv;
1348 entity = 1, index = pncmesh->
GetNEdges() + dof / ne, edof = dof % ne;
1355 entity = 2, index = pncmesh->
GetNFaces() + dof / nf, edof = dof % nf;
1358 MFEM_ABORT(
"Out of range DOF.");
1366 struct PMatrixElement
1368 HYPRE_Int column, stride;
1371 PMatrixElement(HYPRE_Int col = 0, HYPRE_Int str = 0,
double val = 0)
1372 : column(col), stride(str), value(val) {}
1374 bool operator<(
const PMatrixElement &other)
const
1375 {
return column < other.column; }
1377 typedef std::vector<PMatrixElement> List;
1385 PMatrixElement::List elems;
1388 void AddRow(
const PMatrixRow &other,
double coef)
1390 elems.reserve(elems.size() + other.elems.size());
1391 for (
unsigned i = 0; i < other.elems.size(); i++)
1393 const PMatrixElement &oei = other.elems[i];
1395 PMatrixElement(oei.column, oei.stride, coef * oei.value));
1402 if (!elems.size()) {
return; }
1403 std::sort(elems.begin(), elems.end());
1406 for (
unsigned i = 1; i < elems.size(); i++)
1408 if (elems[j].column == elems[i].column)
1410 elems[j].value += elems[i].value;
1414 elems[++j] = elems[i];
1420 void write(std::ostream &os,
double sign)
const
1422 bin_io::write<int>(os, elems.size());
1423 for (
unsigned i = 0; i < elems.size(); i++)
1425 const PMatrixElement &e = elems[i];
1426 bin_io::write<HYPRE_Int>(os, e.column);
1427 bin_io::write<int>(os, e.stride);
1428 bin_io::write<double>(os, e.value * sign);
1432 void read(std::istream &is,
double sign)
1434 elems.resize(bin_io::read<int>(is));
1435 for (
unsigned i = 0; i < elems.size(); i++)
1437 PMatrixElement &e = elems[i];
1438 e.column = bin_io::read<HYPRE_Int>(is);
1439 e.stride = bin_io::read<int>(is);
1440 e.value = bin_io::read<double>(is) * sign;
1448 class NeighborRowMessage :
public VarMessage<314>
1451 typedef NCMesh::MeshId MeshId;
1456 int entity, index, edof;
1460 RowInfo(
int ent,
int idx,
int edof, GroupId grp,
const PMatrixRow &row)
1461 : entity(ent), index(idx), edof(edof), group(grp), row(row) {}
1463 RowInfo(
int ent,
int idx,
int edof, GroupId grp)
1464 : entity(ent), index(idx), edof(edof), group(grp) {}
1466 typedef std::vector<RowInfo> List;
1469 NeighborRowMessage() : pncmesh(NULL) {}
1471 void AddRow(
int entity,
int index,
int edof, GroupId group,
1472 const PMatrixRow &row)
1474 rows.push_back(RowInfo(entity, index, edof, group, row));
1477 const RowInfo::List& GetRows()
const {
return rows; }
1479 void SetNCMesh(ParNCMesh* pnc) { pncmesh = pnc; }
1480 void SetFEC(
const FiniteElementCollection* fec) { this->fec = fec; }
1482 typedef std::map<int, NeighborRowMessage> Map;
1488 const FiniteElementCollection* fec;
1490 virtual void Encode(
int rank);
1491 virtual void Decode(
int);
1495 void NeighborRowMessage::Encode(
int rank)
1497 std::ostringstream stream;
1499 Array<MeshId> ent_ids[3];
1500 Array<GroupId> group_ids[3];
1501 Array<int> row_idx[3];
1504 for (
unsigned i = 0; i < rows.size(); i++)
1506 const RowInfo &ri = rows[i];
1507 const MeshId &
id = pncmesh->GetNCList(ri.entity).LookUp(ri.index);
1508 ent_ids[ri.entity].Append(
id);
1509 row_idx[ri.entity].Append(i);
1510 group_ids[ri.entity].Append(ri.group);
1513 Array<GroupId> all_group_ids;
1514 all_group_ids.Reserve(rows.size());
1515 for (
int i = 0; i < 3; i++)
1517 all_group_ids.Append(group_ids[i]);
1520 pncmesh->AdjustMeshIds(ent_ids, rank);
1521 pncmesh->EncodeMeshIds(stream, ent_ids);
1522 pncmesh->EncodeGroups(stream, all_group_ids);
1525 for (
int ent = 0; ent < 3; ent++)
1527 const Array<MeshId> &ids = ent_ids[ent];
1528 for (
int i = 0; i < ids.Size(); i++)
1530 const MeshId &
id = ids[i];
1531 const RowInfo &ri = rows[row_idx[ent][i]];
1532 MFEM_ASSERT(ent == ri.entity,
"");
1534 #ifdef MFEM_DEBUG_PMATRIX
1535 mfem::out <<
"Rank " << pncmesh->MyRank <<
" sending to " << rank
1536 <<
": ent " << ri.entity <<
", index " << ri.index
1537 <<
", edof " << ri.edof <<
" (id " <<
id.element <<
"/"
1538 <<
id.local <<
")" << std::endl;
1546 int eo = pncmesh->GetEdgeNCOrientation(
id);
1548 if ((edof = ind[edof]) < 0)
1555 bin_io::write<int>(stream, edof);
1556 ri.row.write(stream, s);
1561 stream.str().swap(data);
1564 void NeighborRowMessage::Decode(
int rank)
1566 std::istringstream stream(data);
1568 Array<MeshId> ent_ids[3];
1569 Array<GroupId> group_ids;
1572 pncmesh->DecodeMeshIds(stream, ent_ids);
1573 pncmesh->DecodeGroups(stream, group_ids);
1575 int nrows = ent_ids[0].Size() + ent_ids[1].Size() + ent_ids[2].Size();
1576 MFEM_ASSERT(nrows == group_ids.Size(),
"");
1579 rows.reserve(nrows);
1581 int fgeom = pncmesh->GetFaceGeometry();
1584 for (
int ent = 0, gi = 0; ent < 3; ent++)
1586 const Array<MeshId> &ids = ent_ids[ent];
1587 for (
int i = 0; i < ids.Size(); i++)
1589 const MeshId &
id = ids[i];
1590 int edof = bin_io::read<int>(stream);
1593 const int *ind = NULL;
1596 int eo = pncmesh->GetEdgeNCOrientation(
id);
1601 int fo = pncmesh->GetFaceOrientation(
id.index);
1602 ind = fec->DofOrderForOrientation(fgeom, fo);
1606 if (ind && (edof = ind[edof]) < 0)
1612 rows.push_back(RowInfo(ent,
id.index, edof, group_ids[gi++]));
1613 rows.back().row.read(stream, s);
1615 #ifdef MFEM_DEBUG_PMATRIX
1616 mfem::out <<
"Rank " << pncmesh->MyRank <<
" receiving from " << rank
1617 <<
": ent " << rows.back().entity <<
", index "
1618 << rows.back().index <<
", edof " << rows.back().edof
1626 ParFiniteElementSpace::ScheduleSendRow(
const PMatrixRow &row,
int dof,
1628 NeighborRowMessage::Map &send_msg)
const
1631 UnpackDof(dof, ent, idx, edof);
1634 for (
unsigned i = 0; i < group.size(); i++)
1636 int rank = group[i];
1639 NeighborRowMessage &msg = send_msg[rank];
1640 msg.AddRow(ent, idx, edof, group_id, row);
1641 msg.SetNCMesh(pncmesh);
1647 void ParFiniteElementSpace::ForwardRow(
const PMatrixRow &row,
int dof,
1648 GroupId group_sent_id, GroupId group_id,
1649 NeighborRowMessage::Map &send_msg)
const
1652 UnpackDof(dof, ent, idx, edof);
1655 for (
unsigned i = 0; i < group.size(); i++)
1657 int rank = group[i];
1658 if (rank != MyRank && !pncmesh->
GroupContains(group_sent_id, rank))
1660 NeighborRowMessage &msg = send_msg[rank];
1661 GroupId invalid = -1;
1662 msg.AddRow(ent, idx, edof, invalid, row);
1663 msg.SetNCMesh(pncmesh);
1666 #ifdef MFEM_DEBUG_PMATRIX
1668 << rank <<
": ent " << ent <<
", index" << idx
1669 <<
", edof " << edof << std::endl;
1675 #ifdef MFEM_DEBUG_PMATRIX
1676 void ParFiniteElementSpace
1677 ::DebugDumpDOFs(std::ofstream &os,
1678 const SparseMatrix &deps,
1679 const Array<GroupId> &dof_group,
1680 const Array<GroupId> &dof_owner,
1681 const Array<bool> &finalized)
const
1683 for (
int i = 0; i < dof_group.Size(); i++)
1689 UnpackDof(i, ent, idx, edof);
1691 os << edof <<
" @ ";
1692 if (i >
ndofs) { os <<
"ghost "; }
1695 case 0: os <<
"vertex ";
break;
1696 case 1: os <<
"edge ";
break;
1697 default: os <<
"face ";
break;
1701 if (i < deps.Height() && deps.RowSize(i))
1703 os <<
"depends on ";
1704 for (
int j = 0; j < deps.RowSize(i); j++)
1706 os << deps.GetRowColumns(i)[j] <<
" ("
1707 << deps.GetRowEntries(i)[j] <<
")";
1708 if (j < deps.RowSize(i)-1) { os <<
", "; }
1717 os <<
"group " << dof_group[i] <<
" (";
1719 for (
unsigned j = 0; j < g.size(); j++)
1721 if (j) { os <<
", "; }
1725 os <<
"), owner " << dof_owner[i] <<
" (rank "
1726 << pncmesh->
GetGroup(dof_owner[i])[0] <<
"); "
1727 << (finalized[i] ?
"finalized" :
"NOT finalized");
1738 int ParFiniteElementSpace
1739 ::BuildParallelConformingInterpolation(HypreParMatrix **P, SparseMatrix **R,
1740 Array<HYPRE_Int> &dof_offs,
1741 Array<HYPRE_Int> &tdof_offs,
1742 Array<int> *dof_tdof,
1749 int total_dofs =
ndofs + ngdofs;
1750 SparseMatrix deps(
ndofs, total_dofs);
1752 if (!dg && !partial)
1754 Array<int> master_dofs, slave_dofs;
1757 for (
int entity = 0; entity <= 2; entity++)
1759 const NCMesh::NCList &list = pncmesh->
GetNCList(entity);
1760 if (!list.masters.size()) {
continue; }
1762 IsoparametricTransformation T;
1768 if (!fe) {
continue; }
1770 DenseMatrix I(fe->GetDof());
1773 for (
unsigned mi = 0; mi < list.masters.size(); mi++)
1775 const NCMesh::Master &mf = list.masters[mi];
1778 pncmesh->
IsGhost(entity, mf.index)
1779 ? GetGhostDofs(entity, mf, master_dofs)
1782 if (!master_dofs.Size()) {
continue; }
1785 for (
int si = mf.slaves_begin; si < mf.slaves_end; si++)
1787 const NCMesh::Slave &sf = list.slaves[si];
1788 if (pncmesh->
IsGhost(entity, sf.index)) {
continue; }
1791 if (!slave_dofs.Size()) {
continue; }
1793 sf.OrientedPointMatrix(T.GetPointMat());
1794 T.FinalizeTransformation();
1795 fe->GetLocalInterpolation(T, I);
1811 Array<GroupId> dof_group(total_dofs);
1812 Array<GroupId> dof_owner(total_dofs);
1821 for (
int entity = 0; entity <= 2; entity++)
1823 const NCMesh::NCList &list = pncmesh->
GetSharedList(entity);
1825 std::size_t lsize[3] =
1826 { list.conforming.size(), list.masters.size(), list.slaves.size() };
1828 for (
int l = 0; l < 3; l++)
1830 for (std::size_t i = 0; i < lsize[l]; i++)
1833 (l == 0) ? list.conforming[i] :
1834 (l == 1) ? (
const MeshId&) list.masters[i]
1835 : (
const MeshId&) list.slaves[i];
1837 GetBareDofs(entity,
id, dofs);
1839 for (
int j = 0; j < dofs.Size(); j++)
1842 dof_owner[dof] = pncmesh->
GetOwnerId(entity,
id.index);
1843 dof_group[dof] = pncmesh->
GetGroupId(entity,
id.index);
1852 Array<bool> finalized(total_dofs);
1856 int num_true_dofs = 0;
1857 for (
int i = 0; i <
ndofs; i++)
1859 if (dof_owner[i] == 0 && deps.RowSize(i) == 0)
1862 finalized[i] =
true;
1867 HYPRE_Int loc_sizes[2] = { ndofs*
vdim, num_true_dofs*vdim };
1868 Array<HYPRE_Int>* offsets[2] = { &dof_offs, &tdof_offs };
1871 HYPRE_Int my_tdof_offset =
1872 tdof_offs[HYPRE_AssumedPartitionCheck() ? 0 : MyRank];
1877 *R =
new SparseMatrix(num_true_dofs*
vdim, ndofs*vdim);
1881 dof_tdof->SetSize(ndofs*
vdim);
1885 std::vector<PMatrixRow> pmatrix(total_dofs);
1888 int vdim_factor = bynodes ? 1 :
vdim;
1889 int dof_stride = bynodes ? ndofs : 1;
1890 int tdof_stride = bynodes ? num_true_dofs : 1;
1893 std::list<NeighborRowMessage::Map> send_msg;
1894 send_msg.push_back(NeighborRowMessage::Map());
1897 for (
int dof = 0, tdof = 0; dof <
ndofs; dof++)
1901 pmatrix[dof].elems.push_back(
1902 PMatrixElement(my_tdof_offset + vdim_factor*tdof, tdof_stride, 1.));
1905 if (dof_group[dof] != 0)
1907 ScheduleSendRow(pmatrix[dof], dof, dof_group[dof], send_msg.back());
1910 for (
int vd = 0; vd <
vdim; vd++)
1912 int vdof = dof*vdim_factor + vd*dof_stride;
1913 int vtdof = tdof*vdim_factor + vd*tdof_stride;
1915 if (R) { (*R)->Add(vtdof, vdof, 1.0); }
1916 if (dof_tdof) { (*dof_tdof)[vdof] = vtdof; }
1923 NeighborRowMessage::IsendAll(send_msg.back(), MyComm);
1925 if (R) { (*R)->Finalize(); }
1930 NeighborRowMessage recv_msg;
1931 recv_msg.SetNCMesh(pncmesh);
1932 recv_msg.SetFEC(
fec);
1934 int num_finalized = num_true_dofs;
1936 buffer.elems.reserve(1024);
1938 while (num_finalized < ndofs)
1941 if (send_msg.back().size())
1943 send_msg.push_back(NeighborRowMessage::Map());
1948 while (NeighborRowMessage::IProbe(rank, size, MyComm))
1950 recv_msg.Recv(rank, size, MyComm);
1952 const NeighborRowMessage::RowInfo::List &rows = recv_msg.GetRows();
1953 for (
unsigned i = 0; i < rows.size(); i++)
1955 const NeighborRowMessage::RowInfo &ri = rows[i];
1956 int dof = PackDof(ri.entity, ri.index, ri.edof);
1957 pmatrix[dof] = ri.row;
1959 if (dof < ndofs && !finalized[dof]) { num_finalized++; }
1960 finalized[dof] =
true;
1962 if (ri.group >= 0 && dof_group[dof] != ri.group)
1965 ForwardRow(ri.row, dof, ri.group, dof_group[dof], send_msg.back());
1975 for (
int dof = 0; dof <
ndofs; dof++)
1977 if (finalized[dof]) {
continue; }
1979 bool owned = (dof_owner[dof] == 0);
1980 bool shared = (dof_group[dof] != 0);
1984 const int* dep_col = deps.GetRowColumns(dof);
1985 const double* dep_coef = deps.GetRowEntries(dof);
1986 int num_dep = deps.RowSize(dof);
1989 buffer.elems.clear();
1990 for (
int j = 0; j < num_dep; j++)
1992 buffer.AddRow(pmatrix[dep_col[j]], dep_coef[j]);
1995 pmatrix[dof] = buffer;
1997 finalized[dof] =
true;
2004 ScheduleSendRow(pmatrix[dof], dof, dof_group[dof],
2011 #ifdef MFEM_DEBUG_PMATRIX
2024 NeighborRowMessage::IsendAll(send_msg.back(), MyComm);
2029 *P = MakeVDimHypreMatrix(pmatrix, ndofs, num_true_dofs,
2030 dof_offs, tdof_offs);
2036 while (NeighborRowMessage::IProbe(rank, size, MyComm))
2038 recv_msg.RecvDrop(rank, size, MyComm);
2042 for (std::list<NeighborRowMessage::Map>::iterator
2043 it = send_msg.begin(); it != send_msg.end(); ++it)
2045 NeighborRowMessage::WaitAllSent(*it);
2048 return num_true_dofs*
vdim;
2052 HypreParMatrix* ParFiniteElementSpace
2053 ::MakeVDimHypreMatrix(
const std::vector<PMatrixRow> &rows,
2054 int local_rows,
int local_cols,
2055 Array<HYPRE_Int> &row_starts,
2056 Array<HYPRE_Int> &col_starts)
const
2058 bool assumed = HYPRE_AssumedPartitionCheck();
2061 HYPRE_Int first_col = col_starts[assumed ? 0 : MyRank];
2062 HYPRE_Int next_col = col_starts[assumed ? 1 : MyRank+1];
2065 HYPRE_Int nnz_diag = 0, nnz_offd = 0;
2066 std::map<HYPRE_Int, int> col_map;
2067 for (
int i = 0; i < local_rows; i++)
2069 for (
unsigned j = 0; j < rows[i].elems.size(); j++)
2071 const PMatrixElement &elem = rows[i].elems[j];
2072 HYPRE_Int col = elem.column;
2073 if (col >= first_col && col < next_col)
2080 for (
int vd = 0; vd <
vdim; vd++)
2090 HYPRE_Int *cmap =
new HYPRE_Int[col_map.size()];
2092 for (std::map<HYPRE_Int, int>::iterator
2093 it = col_map.begin(); it != col_map.end(); ++it)
2095 cmap[offd_col] = it->first;
2096 it->second = offd_col++;
2099 HYPRE_Int *I_diag =
new HYPRE_Int[vdim*local_rows + 1];
2100 HYPRE_Int *I_offd =
new HYPRE_Int[vdim*local_rows + 1];
2102 HYPRE_Int *J_diag =
new HYPRE_Int[nnz_diag];
2103 HYPRE_Int *J_offd =
new HYPRE_Int[nnz_offd];
2105 double *A_diag =
new double[nnz_diag];
2106 double *A_offd =
new double[nnz_offd];
2108 int vdim1 = bynodes ? vdim : 1;
2109 int vdim2 = bynodes ? 1 :
vdim;
2110 int vdim_offset = bynodes ? local_cols : 1;
2113 nnz_diag = nnz_offd = 0;
2115 for (
int vd1 = 0; vd1 < vdim1; vd1++)
2117 for (
int i = 0; i < local_rows; i++)
2119 for (
int vd2 = 0; vd2 < vdim2; vd2++)
2121 I_diag[vrow] = nnz_diag;
2122 I_offd[vrow++] = nnz_offd;
2124 int vd = bynodes ? vd1 : vd2;
2125 for (
unsigned j = 0; j < rows[i].elems.size(); j++)
2127 const PMatrixElement &elem = rows[i].elems[j];
2128 if (elem.column >= first_col && elem.column < next_col)
2130 J_diag[nnz_diag] = elem.column + vd*vdim_offset - first_col;
2131 A_diag[nnz_diag++] = elem.value;
2135 J_offd[nnz_offd] = col_map[elem.column + vd*elem.stride];
2136 A_offd[nnz_offd++] = elem.value;
2142 MFEM_ASSERT(vrow == vdim*local_rows,
"");
2143 I_diag[vrow] = nnz_diag;
2144 I_offd[vrow] = nnz_offd;
2146 return new HypreParMatrix(MyComm,
2147 row_starts.Last(), col_starts.Last(),
2148 row_starts.GetData(), col_starts.GetData(),
2149 I_diag, J_diag, A_diag,
2150 I_offd, J_offd, A_offd,
2151 col_map.size(), cmap);
2155 static HYPRE_Int* make_i_array(
int nrows)
2157 HYPRE_Int *I =
new HYPRE_Int[nrows+1];
2158 for (
int i = 0; i <= nrows; i++) { I[i] = -1; }
2162 static HYPRE_Int* make_j_array(HYPRE_Int* I,
int nrows)
2165 for (
int i = 0; i < nrows; i++)
2167 if (I[i] >= 0) { nnz++; }
2169 HYPRE_Int *J =
new HYPRE_Int[nnz];
2172 for (
int i = 0, k = 0; i <= nrows; i++)
2174 HYPRE_Int col = I[i];
2176 if (col >= 0) { J[k++] = col; }
2182 ParFiniteElementSpace::RebalanceMatrix(
int old_ndofs,
2183 const Table* old_elem_dof)
2185 MFEM_VERIFY(
Nonconforming(),
"Only supported for nonconforming meshes.");
2186 MFEM_VERIFY(old_dof_offsets.
Size(),
"ParFiniteElementSpace::Update needs to "
2187 "be called before ParFiniteElementSpace::RebalanceMatrix");
2189 HYPRE_Int old_offset = HYPRE_AssumedPartitionCheck()
2190 ? old_dof_offsets[0] : old_dof_offsets[MyRank];
2193 ParNCMesh* pncmesh = pmesh->
pncmesh;
2199 const Array<int> &old_index = pncmesh->GetRebalanceOldIndex();
2200 MFEM_VERIFY(old_index.Size() == pmesh->
GetNE(),
2201 "Mesh::Rebalance was not called before "
2202 "ParFiniteElementSpace::RebalanceMatrix");
2205 HYPRE_Int* i_diag = make_i_array(vsize);
2206 for (
int i = 0; i < pmesh->
GetNE(); i++)
2208 if (old_index[i] >= 0)
2210 const int* old_dofs = old_elem_dof->GetRow(old_index[i]);
2213 for (
int vd = 0; vd <
vdim; vd++)
2215 for (
int j = 0; j < dofs.Size(); j++)
2218 if (row < 0) { row = -1 - row; }
2220 int col =
DofToVDof(old_dofs[j], vd, old_ndofs);
2221 if (col < 0) { col = -1 - col; }
2228 HYPRE_Int* j_diag = make_j_array(i_diag, vsize);
2231 Array<int> new_elements;
2232 Array<long> old_remote_dofs;
2233 pncmesh->RecvRebalanceDofs(new_elements, old_remote_dofs);
2236 HYPRE_Int* i_offd = make_i_array(vsize);
2237 for (
int i = 0; i < new_elements.Size(); i++)
2240 const long* old_dofs = &old_remote_dofs[i * dofs.Size() *
vdim];
2242 for (
int vd = 0; vd <
vdim; vd++)
2244 for (
int j = 0; j < dofs.Size(); j++)
2247 if (row < 0) { row = -1 - row; }
2249 if (i_diag[row] == i_diag[row+1])
2251 i_offd[row] = old_dofs[j + vd * dofs.Size()];
2256 HYPRE_Int* j_offd = make_j_array(i_offd, vsize);
2259 int offd_cols = i_offd[vsize];
2260 Array<Pair<HYPRE_Int, int> > cmap_offd(offd_cols);
2261 for (
int i = 0; i < offd_cols; i++)
2263 cmap_offd[i].one = j_offd[i];
2264 cmap_offd[i].two = i;
2266 SortPairs<HYPRE_Int, int>(cmap_offd, offd_cols);
2268 HYPRE_Int* cmap =
new HYPRE_Int[offd_cols];
2269 for (
int i = 0; i < offd_cols; i++)
2271 cmap[i] = cmap_offd[i].one;
2272 j_offd[cmap_offd[i].two] = i;
2276 M =
new HypreParMatrix(MyComm, MyRank, NRanks, dof_offsets, old_dof_offsets,
2277 i_diag, j_diag, i_offd, j_offd, cmap, offd_cols);
2282 struct DerefDofMessage
2284 std::vector<HYPRE_Int> dofs;
2285 MPI_Request request;
2289 ParFiniteElementSpace::ParallelDerefinementMatrix(
int old_ndofs,
2290 const Table* old_elem_dof)
2292 int nrk = HYPRE_AssumedPartitionCheck() ? 2 : NRanks;
2294 MFEM_VERIFY(
Nonconforming(),
"Not implemented for conforming meshes.");
2295 MFEM_VERIFY(old_dof_offsets[nrk],
"Missing previous (finer) space.");
2296 MFEM_VERIFY(dof_offsets[nrk] <= old_dof_offsets[nrk],
2297 "Previous space is not finer.");
2304 Array<int> dofs, old_dofs, old_vdofs;
2307 ParNCMesh* pncmesh = pmesh->
pncmesh;
2311 const CoarseFineTransformations &dtrans = pncmesh->GetDerefinementTransforms();
2312 const Array<int> &old_ranks = pncmesh->GetDerefineOldRanks();
2314 std::map<int, DerefDofMessage> messages;
2316 HYPRE_Int old_offset = HYPRE_AssumedPartitionCheck()
2317 ? old_dof_offsets[0] : old_dof_offsets[MyRank];
2321 for (
int k = 0; k < dtrans.embeddings.Size(); k++)
2323 const Embedding &emb = dtrans.embeddings[k];
2325 int fine_rank = old_ranks[k];
2326 int coarse_rank = (emb.parent < 0) ? (-1 - emb.parent)
2327 : pncmesh->ElementRank(emb.parent);
2329 if (coarse_rank != MyRank && fine_rank == MyRank)
2331 old_elem_dof->GetRow(k, dofs);
2334 DerefDofMessage &msg = messages[k];
2335 msg.dofs.resize(dofs.Size());
2336 for (
int i = 0; i < dofs.Size(); i++)
2338 msg.dofs[i] = old_offset + dofs[i];
2341 MPI_Isend(&msg.dofs[0], msg.dofs.size(), HYPRE_MPI_INT,
2342 coarse_rank, 291, MyComm, &msg.request);
2344 else if (coarse_rank == MyRank && fine_rank != MyRank)
2346 DerefDofMessage &msg = messages[k];
2347 msg.dofs.resize(ldof*vdim);
2349 MPI_Irecv(&msg.dofs[0], ldof*vdim, HYPRE_MPI_INT,
2350 fine_rank, 291, MyComm, &msg.request);
2361 SparseMatrix *diag =
new SparseMatrix(ndofs*vdim, old_ndofs*vdim);
2363 Array<char> mark(diag->Height());
2365 for (
int k = 0; k < dtrans.embeddings.Size(); k++)
2367 const Embedding &emb = dtrans.embeddings[k];
2368 if (emb.parent < 0) {
continue; }
2370 int coarse_rank = pncmesh->ElementRank(emb.parent);
2371 int fine_rank = old_ranks[k];
2373 if (coarse_rank == MyRank && fine_rank == MyRank)
2375 DenseMatrix &lR = localR(emb.matrix);
2378 old_elem_dof->GetRow(k, old_dofs);
2380 for (
int vd = 0; vd <
vdim; vd++)
2382 old_dofs.Copy(old_vdofs);
2385 for (
int i = 0; i < lR.Height(); i++)
2387 if (lR(i, 0) ==
infinity()) {
continue; }
2390 int m = (r >= 0) ? r : (-1 - r);
2395 diag->SetRow(r, old_vdofs, row);
2405 for (std::map<int, DerefDofMessage>::iterator
2406 it = messages.begin(); it != messages.end(); ++it)
2408 MPI_Wait(&it->second.request, MPI_STATUS_IGNORE);
2412 SparseMatrix *offd =
new SparseMatrix(ndofs*vdim, 1);
2414 std::map<HYPRE_Int, int> col_map;
2415 for (
int k = 0; k < dtrans.embeddings.Size(); k++)
2417 const Embedding &emb = dtrans.embeddings[k];
2418 if (emb.parent < 0) {
continue; }
2420 int coarse_rank = pncmesh->ElementRank(emb.parent);
2421 int fine_rank = old_ranks[k];
2423 if (coarse_rank == MyRank && fine_rank != MyRank)
2425 DenseMatrix &lR = localR(emb.matrix);
2429 DerefDofMessage &msg = messages[k];
2430 MFEM_ASSERT(msg.dofs.size(),
"");
2432 for (
int vd = 0; vd <
vdim; vd++)
2434 HYPRE_Int* remote_dofs = &msg.dofs[vd*ldof];
2436 for (
int i = 0; i < lR.Height(); i++)
2438 if (lR(i, 0) ==
infinity()) {
continue; }
2441 int m = (r >= 0) ? r : (-1 - r);
2446 for (
int j = 0; j < ldof; j++)
2448 if (row[j] == 0.0) {
continue; }
2449 int &lcol = col_map[remote_dofs[j]];
2450 if (!lcol) { lcol = col_map.size(); }
2451 offd->_Set_(m, lcol-1, row[j]);
2461 offd->SetWidth(col_map.size());
2464 HYPRE_Int *cmap =
new HYPRE_Int[offd->Width()];
2465 for (std::map<HYPRE_Int, int>::iterator
2466 it = col_map.begin(); it != col_map.end(); ++it)
2468 cmap[it->second-1] = it->first;
2475 int width = offd->Width();
2476 Array<Pair<int, int> > reorder(width);
2477 for (
int i = 0; i < width; i++)
2479 reorder[i].one = cmap[i];
2484 Array<int> reindex(width);
2485 for (
int i = 0; i < width; i++)
2487 reindex[reorder[i].two] = i;
2488 cmap[i] = reorder[i].one;
2491 int *J = offd->GetJ();
2492 for (
int i = 0; i < offd->NumNonZeroElems(); i++)
2494 J[i] = reindex[J[i]];
2496 offd->SortColumnIndices();
2500 R =
new HypreParMatrix(MyComm, dof_offsets[nrk], old_dof_offsets[nrk],
2501 dof_offsets, old_dof_offsets, diag, offd, cmap);
2503 #ifndef HYPRE_BIGINT
2507 diag->SetDataOwner(
false);
2508 offd->SetDataOwner(
false);
2513 R->SetOwnerFlags(3, 3, 1);
2518 void ParFiniteElementSpace::Destroy()
2526 ldof_sign.DeleteAll();
2529 delete Pconf; Pconf = NULL;
2532 delete gcomm; gcomm = NULL;
2552 MFEM_ASSERT(c_pfes != NULL,
"coarse_fes must be a parallel space");
2563 false, Tgf.OwnsOperator(),
false));
2564 Tgf.SetOperatorOwner(
false);
2576 MFEM_ABORT(
"Error in update sequence. Space needs to be updated after "
2577 "each mesh modification.");
2587 Table* old_elem_dof = NULL;
2596 Swap(dof_offsets, old_dof_offsets);
2619 old_elem_dof = NULL;
2631 Th.
Reset(ParallelDerefinementMatrix(old_ndofs, old_elem_dof));
2636 false,
false,
true));
2643 Th.
Reset(RebalanceMatrix(old_ndofs, old_elem_dof));
2651 delete old_elem_dof;
2658 :
Operator(pfes.GetVSize(), pfes.GetTrueVSize()),
2660 gc(pfes.GroupComm())
2663 const Table &group_ldof = gc.GroupLDofTable();
2665 for (
int gr = 1; gr < group_ldof.Size(); gr++)
2667 if (!gc.GetGroupTopology().IAmMaster(gr))
2684 for ( ; j < end; j++)
2690 for ( ; j <
Height(); j++)
2704 const double *xdata = x.
GetData();
2708 const int in_layout = 2;
2709 gc.BcastBegin(const_cast<double*>(xdata), in_layout);
2712 for (
int i = 0; i < m; i++)
2715 std::copy(xdata+j-i, xdata+end-i, ydata+j);
2718 std::copy(xdata+j-m, xdata+
Width(), ydata+j);
2720 const int out_layout = 0;
2721 gc.BcastEnd(ydata, out_layout);
2730 const double *xdata = x.
GetData();
2734 gc.ReduceBegin(xdata);
2737 for (
int i = 0; i < m; i++)
2740 std::copy(xdata+j, xdata+end, ydata+j-i);
2743 std::copy(xdata+j, xdata+
Height(), ydata+j-m);
2745 const int out_layout = 2;
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 Reduce(T *ldata, void(*Op)(OpData< T >)) const
Reduce within each group where the master is the root.
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
virtual void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1)
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 is ndofs * vdim.
std::vector< int > CommGroup
int DofToVDof(int dof, int vd, int ndofs=-1) const
void Bcast(T *ldata, int layout) const
Broadcast within each group where the master is the root.
const CommGroup & GetGroup(GroupId id) const
Return a list of ranks contained in the group of the given ID.
void GetFaceInfos(int Face, int *Inf1, int *Inf2)
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 const Operator * GetProlongationMatrix() const
void GetFaceVerticesEdges(const MeshId &face_id, int vert_index[4], int edge_index[4], int edge_orientation[4]) const
Return Mesh vertex and edge indices of a face identified by 'face_id'.
SparseMatrix * RefinementMatrix(int old_ndofs, const Table *old_elem_dof)
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
void Create(const Array< int > &ldof_group)
Initialize the communicator from a local-dof to group map. Finalize() is called internally.
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).
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
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)
Pointer to an Operator of a specified type.
Operator::Type Type() const
Get the currently set operator type id.
int VDofToDof(int vdof) const
virtual void GetEssentialVDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_vdofs, int component=-1) const
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)
void GetEntityDofs(int entity, int index, Array< int > &dofs) const
Helper to get vertex, edge or face DOFs (entity=0,1,2 resp.).
void GetEdgeVertices(const MeshId &edge_id, int vert_index[2]) const
Return Mesh vertex indices of an edge identified by 'edge_id'.
virtual void GetTrueTransferOperator(const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
Construct and return an Operator that can be used to transfer true-dof data from coarse_fes, defined on a coarse mesh, to this FE space, defined on a refined mesh.
int GetNE() const
Returns number of elements.
void DivideByGroupSize(double *vec)
Scale a vector of true dofs.
Abstract parallel finite element space.
bool operator<(const Pair< A, B > &p, const Pair< A, B > &q)
Comparison operator for class Pair, based on the first element only.
void Synchronize(Array< int > &ldof_marker) const
void Lose_Dof_TrueDof_Matrix()
bool GroupContains(GroupId id, int rank) const
Return true if group 'id' contains the given rank.
int GetLocalTDofNumber(int ldof) const
HypreParMatrix * GetPartialConformingInterpolation()
For a non-conforming mesh, construct and return the interpolation matrix from the partially conformin...
double * GetData() const
Return a pointer to the beginning of the Vector data.
const FiniteElementCollection * fec
Associated FE collection (not owned).
OperatorHandle Th
Transformation to apply to GridFunctions after space Update().
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)
const NCList & GetSharedList(int entity)
Helper to get shared vertices/edges/faces ('entity' == 0/1/2 resp.).
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
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()
ID for class SparseMatrix.
Communicator performing operations within groups defined by a GroupTopology with arbitrary-size data ...
const FiniteElement * GetFaceNbrFE(int i) const
ID for the base class Operator, i.e. any type.
void GetSharedFaceDofs(int group, int fi, Array< int > &dofs) const
Array< int > face_nbr_elements_offset
void ExchangeFaceNbrData()
void write(std::ostream &os, T value)
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.
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
int GetNGhostEdges() const
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 const Operator * GetProlongationMatrix() const
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.
GroupId GetOwnerId(int entity, int index) const
Return vertex/edge/face ('entity' == 0/1/2, resp.) owner.
void Transpose(const Table &A, Table &At, int _ncols_A)
Transpose a Table.
void AugmentMasterGroups()
static void AddDependencies(SparseMatrix &deps, Array< int > &master_dofs, Array< int > &slave_dofs, DenseMatrix &I)
HypreParMatrix * Transpose() const
Returns the transpose of *this.
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 Size() const
Returns the number of TYPE I elements.
void GetEdgeDofs(int i, Array< int > &dofs) const
Operator * Ptr() const
Access the underlying Operator pointer.
int GetGroupMaster(int g) const
void GetTransferOperator(const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
Construct and return an Operator that can be used to transfer GridFunction data from coarse_fes...
int GetNGhostFaces() const
void Swap(Array< T > &, Array< T > &)
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
int GetDof() const
Returns the number of degrees of freedom in the finite element.
void AddAColumnInRow(int r)
void SetSize(int nsize)
Change logical size of the array, keep existing entries.
ParFiniteElementSpace(const ParFiniteElementSpace &orig, ParMesh *pmesh=NULL, const FiniteElementCollection *fec=NULL)
Copy constructor: deep copy all data from orig except the ParMesh, the FiniteElementCollection, and some derived data.
HYPRE_Int GetGlobalScalarTDofNumber(int sldof)
void GetLocalDerefinementMatrices(DenseTensor &localR) const
void SetLTDofTable(const Array< int > &ldof_ltdof)
Initialize the internal group_ltdof Table.
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 SetOperatorOwner(bool own=true)
Set the ownership flag for the held Operator.
Table face_nbr_element_dof
void GroupFace(int group, int i, int &face, int &o)
Mesh * mesh
The mesh that FE space lives on (not owned).
GridFunction interpolation operator applicable after mesh refinement.
GroupId GetGroupId(int entity, int index) const
Return the communication group ID for a vertex/edge/face.
const NCList & GetNCList(int entity)
Return vertex/edge/face list (entity = 0/1/2, respectively).
virtual const SparseMatrix * GetRestrictionMatrix() const
Get the R matrix which restricts a local dof vector to true dof vector.
General triple product operator x -> A*B*C*x, with ownership of the factors.
int GroupNFaces(int group)
bool IsGhost(int entity, int index) const
Return true if the specified vertex/edge/face is a ghost.
double infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
const FiniteElement * GetFaceNbrFaceFE(int i) const
HYPRE_Int * GetTrueDofOffsets() const
void GetFaceNbrFaceVDofs(int i, Array< int > &vdofs) const
void MakeRef(T *, int)
Make this Array a reference to a pointer.
void GroupEdge(int group, int i, int &edge, int &o)
int GetFaceBaseGeometry(int i) const
void GenerateOffsets(int N, HYPRE_Int loc_sizes[], Array< HYPRE_Int > *offsets[]) const
ID for class HypreParMatrix.
static bool DofFinalizable(int dof, const Array< bool > &finalized, const SparseMatrix &deps)
NURBSExtension * NURBSext
virtual int DofForGeometry(int GeomType) const =0
int GetNGhostVertices() const
Table send_face_nbr_elements
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Wrapper for hypre's ParCSR matrix class.
GroupCommunicator * ScalarGroupComm()
Return a new GroupCommunicator on Dofs.
BiLinear2DFiniteElement QuadrilateralFE
Class for parallel meshes.
Abstract data type element.
int GetFaceNbrRank(int fn) const
Linear1DFiniteElement SegmentFE
int GetBdrElementBaseGeometry(int i=0) const
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
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.
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Array< HYPRE_Int > face_nbr_glob_dof_map