12 #include "../config/config.hpp"
17 #include "../general/sort_pairs.hpp"
22 ParFiniteElementSpace::ParFiniteElementSpace(ParFiniteElementSpace &pf)
23 : FiniteElementSpace(pf)
31 ltdof_size = pf.ltdof_size;
32 Swap(ldof_group, pf.ldof_group);
33 Swap(ldof_ltdof, pf.ldof_ltdof);
34 Swap(dof_offsets, pf.dof_offsets);
35 Swap(tdof_offsets, pf.tdof_offsets);
36 Swap(tdof_nb_offsets, pf.tdof_nb_offsets);
37 Swap(ldof_sign, pf.ldof_sign);
40 num_face_nbr_dofs = pf.num_face_nbr_dofs;
41 pf.num_face_nbr_dofs = -1;
42 Swap<Table>(face_nbr_element_dof, pf.face_nbr_element_dof);
43 Swap<Table>(face_nbr_gdof, pf.face_nbr_gdof);
44 Swap<Table>(send_face_nbr_ldof, pf.send_face_nbr_ldof);
47 ParFiniteElementSpace::ParFiniteElementSpace(
54 MPI_Comm_size(MyComm, &NRanks);
55 MPI_Comm_rank(MyComm, &MyRank);
73 ConstructTrueNURBSDofs();
80 GenerateGlobalOffsets();
85 void ParFiniteElementSpace::GetGroupComm(
93 int group_ldof_counter;
107 group_ldof_counter = 0;
108 for (gr = 1; gr < ng; gr++)
111 group_ldof_counter += ned * pmesh->
GroupNEdges(gr);
112 group_ldof_counter += nfd * pmesh->
GroupNFaces(gr);
115 group_ldof_counter *=
vdim;
117 group_ldof.
SetDims(ng, group_ldof_counter);
120 group_ldof_counter = 0;
121 group_ldof.
GetI()[0] = group_ldof.
GetI()[1] = 0;
122 for (gr = 1; gr < ng; gr++)
124 int j, k, l, m, o, nv, ne, nf;
133 for (j = 0; j < nv; j++)
139 for (l = 0; l < nvd; l++, m++)
145 for (l = 0; l < dofs.
Size(); l++)
146 group_ldof.
GetJ()[group_ldof_counter++] = dofs[l];
151 for (j = 0; j < ne; j++)
158 for (l = 0; l < ned; l++)
161 dofs[l] = m + (-1-ind[l]);
163 (*ldof_sign)[dofs[l]] = -1;
166 dofs[l] = m + ind[l];
171 for (l = 0; l < dofs.
Size(); l++)
172 group_ldof.
GetJ()[group_ldof_counter++] = dofs[l];
177 for (j = 0; j < nf; j++)
185 for (l = 0; l < nfd; l++)
188 dofs[l] = m + (-1-ind[l]);
190 (*ldof_sign)[dofs[l]] = -1;
193 dofs[l] = m + ind[l];
198 for (l = 0; l < dofs.
Size(); l++)
199 group_ldof.
GetJ()[group_ldof_counter++] = dofs[l];
202 group_ldof.
GetI()[gr+1] = group_ldof_counter;
208 void ParFiniteElementSpace::ApplyLDofSigns(Array<int> &dofs)
const
210 for (
int i = 0; i < dofs.Size(); i++)
213 if (ldof_sign[-1-dofs[i]] < 0)
214 dofs[i] = -1-dofs[i];
218 if (ldof_sign[dofs[i]] < 0)
219 dofs[i] = -1-dofs[i];
231 ApplyLDofSigns(dofs);
242 ApplyLDofSigns(dofs);
248 ApplyLDofSigns(dofs);
251 void ParFiniteElementSpace::GenerateGlobalOffsets()
253 if (HYPRE_AssumedPartitionCheck())
263 MPI_Scan(ldof, &dof_offsets[0], 2, MPI_INT, MPI_SUM, MyComm);
265 tdof_offsets[1] = dof_offsets[1];
266 tdof_offsets[0] = tdof_offsets[1] - ldof[1];
268 dof_offsets[1] = dof_offsets[0];
269 dof_offsets[0] = dof_offsets[1] - ldof[0];
272 if (MyRank == NRanks-1)
274 ldof[0] = dof_offsets[1];
275 ldof[1] = tdof_offsets[1];
278 MPI_Bcast(ldof, 2, MPI_INT, NRanks-1, MyComm);
279 dof_offsets[2] = ldof[0];
280 tdof_offsets[2] = ldof[1];
288 dof_offsets.
SetSize (NRanks+1);
289 tdof_offsets.
SetSize(NRanks+1);
291 MPI_Allgather(&ldof, 1, MPI_INT, &dof_offsets[1], 1, MPI_INT, MyComm);
292 MPI_Allgather(<dof, 1, MPI_INT, &tdof_offsets[1], 1, MPI_INT, MyComm);
294 dof_offsets[0] = tdof_offsets[0] = 0;
295 for (i = 1; i < NRanks; i++)
297 dof_offsets [i+1] += dof_offsets [i];
298 tdof_offsets[i+1] += tdof_offsets[i];
330 i_diag = hypre_TAlloc(HYPRE_Int, ldof+1);
331 j_diag = hypre_TAlloc(HYPRE_Int, ltdof);
333 i_offd = hypre_TAlloc(HYPRE_Int, ldof+1);
334 j_offd = hypre_TAlloc(HYPRE_Int, ldof-ltdof);
336 cmap = hypre_TAlloc(HYPRE_Int, ldof-ltdof);
340 if (HYPRE_AssumedPartitionCheck())
343 MPI_Request *requests =
new MPI_Request[2*nsize];
344 MPI_Status *statuses =
new MPI_Status[2*nsize];
345 tdof_nb_offsets.
SetSize(nsize+1);
346 tdof_nb_offsets[0] = col_starts[0];
348 int request_counter = 0;
350 for (i = 1; i <= nsize; i++)
351 MPI_Irecv(&tdof_nb_offsets[i], 1, MPI_INT, gt.
GetNeighborRank(i), 5365,
352 MyComm, &requests[request_counter++]);
354 for (i = 1; i <= nsize; i++)
355 MPI_Isend(&tdof_nb_offsets[0], 1, MPI_INT, gt.
GetNeighborRank(i), 5365,
356 MyComm, &requests[request_counter++]);
358 MPI_Waitall(request_counter, requests, statuses);
364 i_diag[0] = i_offd[0] = 0;
365 diag_counter = offd_counter = 0;
366 for (i = 0; i < ldof; i++)
371 j_diag[diag_counter++] = ldof_ltdof[i];
375 if (HYPRE_AssumedPartitionCheck())
376 cmap_j_offd[offd_counter].one =
377 tdof_nb_offsets[gt.
GetGroupMaster(ldof_group[i])] + ldof_ltdof[i];
379 cmap_j_offd[offd_counter].one = col_starts[proc] + ldof_ltdof[i];
380 cmap_j_offd[offd_counter].two = offd_counter;
383 i_diag[i+1] = diag_counter;
384 i_offd[i+1] = offd_counter;
389 for (i = 0; i < offd_counter; i++)
391 cmap[i] = cmap_j_offd[i].one;
392 j_offd[cmap_j_offd[i].two] = i;
395 P =
new HypreParMatrix(MyComm, MyRank, NRanks, row_starts, col_starts,
396 i_diag, j_diag, i_offd, j_offd, cmap, offd_counter);
405 for (
int i = 0; i < ldof_group.
Size(); i++)
414 gc->
Create(pNURBSext()->ldof_group);
416 GetGroupComm(*gc, 0);
423 mfem_error(
"ParFiniteElementSpace::Synchronize");
427 gcomm->
Bcast(ldof_marker);
442 if (GetGroupTopo().IAmMaster(ldof_group[ldof]))
443 return ldof_ltdof[ldof];
450 if (HYPRE_AssumedPartitionCheck())
454 return ldof_ltdof[ldof] +
458 return ldof_ltdof[ldof] +
464 if (HYPRE_AssumedPartitionCheck())
469 return ldof_ltdof[sldof] +
471 ldof_group[sldof])] /
vdim;
473 return (ldof_ltdof[sldof*
vdim] +
474 tdof_nb_offsets[GetGroupTopo().GetGroupMaster(
479 return ldof_ltdof[sldof] +
481 ldof_group[sldof])] /
vdim;
483 return (ldof_ltdof[sldof*
vdim] +
484 tdof_offsets[GetGroupTopo().GetGroupMasterRank(
490 if (HYPRE_AssumedPartitionCheck())
491 return dof_offsets[0];
493 return dof_offsets[MyRank];
505 if (num_face_nbrs == 0)
511 MPI_Request *requests =
new MPI_Request[2*num_face_nbrs];
512 MPI_Request *send_requests = requests;
513 MPI_Request *recv_requests = requests + num_face_nbrs;
514 MPI_Status *statuses =
new MPI_Status[num_face_nbrs];
520 Table send_nbr_elem_dof;
527 for (
int fn = 0; fn < num_face_nbrs; fn++)
532 for (
int i = 0; i < num_my_elems; i++)
535 for (
int j = 0; j < ldofs.
Size(); j++)
536 if (ldof_marker[ldofs[j]] != fn)
538 ldof_marker[ldofs[j]] = fn;
547 MyComm, &send_requests[fn]);
550 MyComm, &recv_requests[fn]);
553 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
558 MPI_Waitall(num_face_nbrs, send_requests, statuses);
566 int *send_I = send_nbr_elem_dof.
GetI();
568 for (
int fn = 0; fn < num_face_nbrs; fn++)
572 MPI_Isend(send_I + send_el_off[fn], send_el_off[fn+1] - send_el_off[fn],
573 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
575 MPI_Irecv(recv_I + recv_el_off[fn], recv_el_off[fn+1] - recv_el_off[fn],
576 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
579 MPI_Waitall(num_face_nbrs, send_requests, statuses);
580 send_nbr_elem_dof.
MakeJ();
584 for (
int fn = 0; fn < num_face_nbrs; fn++)
589 for (
int i = 0; i < num_my_elems; i++)
592 for (
int j = 0; j < ldofs.
Size(); j++)
593 if (ldof_marker[ldofs[j]] != fn)
595 ldof_marker[ldofs[j]] = fn;
599 send_el_off[fn] + i, ldofs, ldofs.
Size());
606 int *send_J = send_nbr_elem_dof.
GetJ();
607 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
611 int j_end = send_I[send_el_off[fn+1]];
613 for (
int i = 0; i < num_ldofs; i++)
614 ldof_marker[ldofs[i]] = i;
616 for ( ; j < j_end; j++)
617 send_J[j] = ldof_marker[send_J[j]];
620 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
627 for (
int fn = 0; fn < num_face_nbrs; fn++)
632 MPI_Isend(send_J + send_I[send_el_off[fn]],
633 send_I[send_el_off[fn+1]] - send_I[send_el_off[fn]],
634 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
636 MPI_Irecv(recv_J + recv_I[recv_el_off[fn]],
637 recv_I[recv_el_off[fn+1]] - recv_I[recv_el_off[fn]],
638 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
641 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
644 for (
int fn = 0, j = 0; fn < num_face_nbrs; fn++)
647 int j_end = recv_I[recv_el_off[fn+1]];
649 for ( ; j < j_end; j++)
653 MPI_Waitall(num_face_nbrs, send_requests, statuses);
661 for (
int i = 0; i < tot_send_dofs; i++)
662 send_J[i] += my_dof_offset;
663 for (
int fn = 0; fn < num_face_nbrs; fn++)
670 MPI_INT, nbr_rank, tag, MyComm, &send_requests[fn]);
674 MPI_INT, nbr_rank, tag, MyComm, &recv_requests[fn]);
677 MPI_Waitall(num_face_nbrs, send_requests, statuses);
680 for (
int i = 0; i < tot_send_dofs; i++)
681 send_J[i] -= my_dof_offset;
683 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
702 mfem_error(
"ParFiniteElementSpace::GetFaceNbrFE"
703 " does not support NURBS!");
710 hypre_ParCSRMatrix *csrP = (hypre_ParCSRMatrix*)(*P);
711 hypre_ParCSRMatrixOwnsRowStarts(csrP) = 1;
712 hypre_ParCSRMatrixOwnsColStarts(csrP) = 1;
718 void ParFiniteElementSpace::ConstructTrueDofs()
725 GetGroupComm(*gcomm, 1, &ldof_sign);
735 for (gr = 1; gr < group_ldof.
Size(); gr++)
737 const int *ldofs = group_ldof.
GetRow(gr);
738 const int nldofs = group_ldof.
RowSize(gr);
739 for (i = 0; i < nldofs; i++)
740 ldof_group[ldofs[i]] = gr;
743 for (i = 0; i < nldofs; i++)
744 ldof_ltdof[ldofs[i]] = -2;
749 for (i = 0; i < n; i++)
750 if (ldof_ltdof[i] == -1)
751 ldof_ltdof[i] = ltdof_size++;
754 gcomm->
Bcast(ldof_ltdof);
757 void ParFiniteElementSpace::ConstructTrueNURBSDofs()
760 GroupTopology > = pNURBSext()->
gtopo;
761 gcomm =
new GroupCommunicator(gt);
766 ldof_group.
MakeRef(pNURBSext()->ldof_group);
770 const int *scalar_ldof_group = pNURBSext()->
ldof_group;
772 for (
int i = 0; i < n; i++)
773 ldof_group[i] = scalar_ldof_group[
VDofToDof(i)];
776 gcomm->
Create(ldof_group);
784 for (
int i = 0; i < n; i++)
786 if (gt.IAmMaster(ldof_group[i]))
788 ldof_ltdof[i] = ltdof_size;
798 gcomm->
Bcast(ldof_ltdof);
820 GenerateGlobalOffsets();
828 GenerateGlobalOffsets();
Abstract class for Finite Elements.
int GetNFaceNeighbors() const
int GetGroupMasterRank(int g) const
int Size() const
Logical size of the array.
int GetNDofs() const
Returns number of degrees of freedom.
void AddColumnsInRow(int r, int ncol)
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Array< Element * > face_nbr_elements
int GetGroupSize(int g) const
void SetDims(int rows, int nnz)
int VDofToDof(int vdof) const
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
void Lose_Dof_TrueDof_Matrix()
const FiniteElementCollection * fec
int Size_of_connections() const
void DeleteAll()
Delete whole array.
void AddConnections(int r, const int *c, int nc)
bool IAmMaster(int g) const
virtual void GetFaceDofs(int i, Array< int > &dofs) const
template void SortPairs< int, int >(Pair< int, int > *, int)
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()
int GetGlobalTDofNumber(int ldof)
Returns the global tdof number of the given local degree of freedom.
const FiniteElement * GetFaceNbrFE(int i) const
Array< int > face_nbr_elements_offset
void ExchangeFaceNbrData()
int GetNumNeighbors() const
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.
int GetLocalTDofNumber(int ldof)
int GetGlobalScalarTDofNumber(int sldof)
int GroupNVertices(int group)
virtual void GetFaceDofs(int i, Array< int > &dofs) const
int Size() const
Returns the number of TYPE I elements.
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.
int GetNeighborRank(int i) const
void AddAColumnInRow(int r)
void mfem_error(const char *msg)
void SetSize(int nsize)
Change logical size of the array, keep existing entries.
void GetElementVDofs(int i, Array< int > &dofs) const
Returns indexes of degrees of freedom in array dofs for i'th element.
virtual void GetEssentialVDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_dofs) const
Determine the boundary degrees of freedom.
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 >))
int * GetTrueDofOffsets()
void Create(Array< int > &ldof_group)
void MakeRef(T *, int)
Make this Array a reference to a poiter.
void GroupEdge(int group, int i, int &edge, int &o)
void DofsToVDofs(Array< int > &dofs) const
int GetFaceBaseGeometry(int i) const
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
Table send_face_nbr_elements
Wrapper for hypre's ParCSR matrix class.
GroupCommunicator * ScalarGroupComm()
Return a new GroupCommunicator on Dofs.
Class for parallel meshes.
virtual FiniteElementSpace * SaveUpdate()
Return a copy of the current FE space and update.
int GetFaceNbrRank(int fn) const
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.