12 #include "../config/config.hpp"
19 #include "../general/forall.hpp"
38 const int *partitioning)
54 int element_counter = 0;
56 const int glob_ne = glob_fes->
GetNE();
57 for (
int i = 0; i < glob_ne; i++)
59 if (partitioning[i] == MyRank)
92 MFEM_ASSERT(
pfes != NULL,
"not a ParFiniteElementSpace");
107 MFEM_ASSERT(
pfes != NULL,
"not a ParFiniteElementSpace");
122 MFEM_ASSERT(
pfes != NULL,
"not a ParFiniteElementSpace");
135 prolong->
Mult(*tv, *
this);
226 MPI_Request *requests =
new MPI_Request[2*num_face_nbrs];
227 MPI_Request *send_requests = requests;
228 MPI_Request *recv_requests = requests + num_face_nbrs;
229 MPI_Status *statuses =
new MPI_Status[num_face_nbrs];
231 auto d_data = this->
Read();
235 const int ldof = d_send_ldof[i];
236 d_send_data[i] = d_data[ldof >= 0 ? ldof : -1-ldof];
243 for (
int fn = 0; fn < num_face_nbrs; fn++)
248 MPI_Isend(&send_data_ptr[send_offset[fn]],
249 send_offset[fn+1] - send_offset[fn],
250 MPI_DOUBLE, nbr_rank, tag, MyComm, &send_requests[fn]);
252 MPI_Irecv(&face_nbr_data_ptr[recv_offset[fn]],
253 recv_offset[fn+1] - recv_offset[fn],
254 MPI_DOUBLE, nbr_rank, tag, MyComm, &recv_requests[fn]);
257 MPI_Waitall(num_face_nbrs, send_requests, statuses);
258 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
277 int s = dofs.
Size()/fes_vdim;
318 return (DofVal * LocVec);
332 int dof = FElem->
GetDof();
349 for (
int k = 0; k < vdim; k++)
351 val(k) = shape * ((
const double *)loc_data + dof * k);
374 int comp,
Vector *tr)
const
412 return (DofVal * LocVec);
459 for (
int k = 0; k < vdim; k++)
461 val(k) = shape * ((
const double *)loc_data + dof * k);
480 "ParGridFunction::GetElementDofValues: ExchangeFaceNbrData "
481 "must be called before accessing face neighbor elements.");
503 double loc_integral, glob_integral;
507 MPI_Allreduce(&loc_integral, &glob_integral, 1, MPI_DOUBLE, MPI_SUM,
510 (*this) *= (delta_c->
Scale() / glob_integral);
524 ldof_attr.
Copy(gdof_attr);
527 gcomm.
Bcast(gdof_attr);
533 if (gdof_attr[i] > ldof_attr[i])
547 gcomm.
Bcast(gdof_attr);
550 (*this)(i) /= gdof_attr[i];
570 gcomm.
Bcast(zones_per_vdof);
592 gcomm.
Bcast(zones_per_vdof);
608 for (
int i = 0; i < values.
Size(); i++)
610 values(i) = values_counter[i] ? (*this)(i) : 0.0;
619 for (
int i = 0; i < values.Size(); i++)
621 if (values_counter[i])
623 (*this)(i) = values(i)/values_counter[i];
630 for (
int i = 0; i < values_counter.Size(); i++)
633 bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
646 for (
int i = 0; i < values.
Size(); i++)
648 values(i) = values_counter[i] ? (*this)(i) : 0.0;
657 for (
int i = 0; i < values.Size(); i++)
659 if (values_counter[i])
661 (*this)(i) = values(i)/values_counter[i];
668 for (
int i = 0; i < values_counter.Size(); i++)
671 bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
684 int fdof, intorder, k;
686 Vector shape, el_dofs, err_val, ell_coeff_val;
693 std::map<int,int> local_to_shared;
697 local_to_shared[i_local] = i;
702 double shared_face_factor = 1.0;
703 bool shared_face =
false;
704 int iel1, iel2, info1, info2;
713 if (info2 >= 0 && iel2 < 0)
715 int ishared = local_to_shared[i];
719 if ( (k = fe2->
GetOrder()) > intorder )
724 shared_face_factor = 0.5;
732 if ( (k = fe2->
GetOrder()) > intorder )
746 intorder = 2 * intorder;
759 transf = face_elem_transf->
Elem1;
765 for (k = 0; k < fdof; k++)
768 el_dofs(k) = (*this)(vdofs[k]);
772 el_dofs(k) = - (*this)(-1-vdofs[k]);
779 ell_coeff_val(j) = ell_coeff->
Eval(*transf, eip);
780 err_val(j) = exsol->
Eval(*transf, eip) - (shape * el_dofs);
785 transf = face_elem_transf->
Elem2;
792 for (k = 0; k < fdof; k++)
805 for (k = 0; k < fdof; k++)
808 el_dofs(k) = (*this)(vdofs[k]);
812 el_dofs(k) = - (*this)(-1 - vdofs[k]);
820 ell_coeff_val(j) += ell_coeff->
Eval(*transf, eip);
821 ell_coeff_val(j) *= 0.5;
822 err_val(j) -= (exsol->
Eval(*transf, eip) - (shape * el_dofs));
825 transf = face_elem_transf;
830 double nu = jump_scaling.
Eval(h, p);
831 error += shared_face_factor*(ip.
weight * nu * ell_coeff_val(j) *
833 err_val(j) * err_val(j));
837 error = (error < 0.0) ? -sqrt(-error) : sqrt(error);
843 double *data_ =
const_cast<double*
>(
HostRead());
844 for (
int i = 0; i <
size; i++)
851 for (
int i = 0; i <
size; i++)
860 ostringstream fname_with_suffix;
861 fname_with_suffix << fname <<
"." << setfill(
'0') << setw(6) << rank;
862 ofstream ofs(fname_with_suffix.str().c_str());
863 ofs.precision(precision);
874 ofs.precision(precision);
879 #ifdef MFEM_USE_ADIOS2
881 const std::string& variable_name,
884 double *data_ =
const_cast<double*
>(
HostRead());
885 for (
int i = 0; i <
size; i++)
892 for (
int i = 0; i <
size; i++)
907 MyComm =
pfes -> GetComm();
909 MPI_Comm_size(MyComm, &NRanks);
910 MPI_Comm_rank(MyComm, &MyRank);
912 double **values =
new double*[NRanks];
913 int *nv =
new int[NRanks];
914 int *nvdofs =
new int[NRanks];
915 int *nedofs =
new int[NRanks];
916 int *nfdofs =
new int[NRanks];
917 int *nrdofs =
new int[NRanks];
919 double * h_data =
const_cast<double *
>(this->
HostRead());
922 nv[0] =
pfes -> GetVSize();
923 nvdofs[0] =
pfes -> GetNVDofs();
924 nedofs[0] =
pfes -> GetNEDofs();
925 nfdofs[0] =
pfes -> GetNFDofs();
932 for (p = 1; p < NRanks; p++)
934 MPI_Recv(&nv[p], 1, MPI_INT, p, 455, MyComm, &status);
935 MPI_Recv(&nvdofs[p], 1, MPI_INT, p, 456, MyComm, &status);
936 MPI_Recv(&nedofs[p], 1, MPI_INT, p, 457, MyComm, &status);
937 MPI_Recv(&nfdofs[p], 1, MPI_INT, p, 458, MyComm, &status);
938 values[
p] =
new double[nv[
p]];
939 MPI_Recv(values[p], nv[p], MPI_DOUBLE, p, 460, MyComm, &status);
942 int vdim =
pfes -> GetVDim();
944 for (p = 0; p < NRanks; p++)
946 nrdofs[
p] = nv[
p]/vdim - nvdofs[
p] - nedofs[
p] - nfdofs[
p];
951 for (
int d = 0; d < vdim; d++)
953 for (p = 0; p < NRanks; p++)
954 for (i = 0; i < nvdofs[
p]; i++)
956 out << *values[
p]++ <<
'\n';
959 for (p = 0; p < NRanks; p++)
960 for (i = 0; i < nedofs[
p]; i++)
962 out << *values[
p]++ <<
'\n';
965 for (p = 0; p < NRanks; p++)
966 for (i = 0; i < nfdofs[
p]; i++)
968 out << *values[
p]++ <<
'\n';
971 for (p = 0; p < NRanks; p++)
972 for (i = 0; i < nrdofs[
p]; i++)
974 out << *values[
p]++ <<
'\n';
980 for (p = 0; p < NRanks; p++)
981 for (i = 0; i < nvdofs[
p]; i++)
982 for (
int d = 0; d < vdim; d++)
984 out << *values[
p]++ <<
'\n';
987 for (p = 0; p < NRanks; p++)
988 for (i = 0; i < nedofs[
p]; i++)
989 for (
int d = 0; d < vdim; d++)
991 out << *values[
p]++ <<
'\n';
994 for (p = 0; p < NRanks; p++)
995 for (i = 0; i < nfdofs[
p]; i++)
996 for (
int d = 0; d < vdim; d++)
998 out << *values[
p]++ <<
'\n';
1001 for (p = 0; p < NRanks; p++)
1002 for (i = 0; i < nrdofs[
p]; i++)
1003 for (
int d = 0; d < vdim; d++)
1005 out << *values[
p]++ <<
'\n';
1009 for (p = 1; p < NRanks; p++)
1012 delete [] values[
p];
1018 MPI_Send(&nv[0], 1, MPI_INT, 0, 455, MyComm);
1019 MPI_Send(&nvdofs[0], 1, MPI_INT, 0, 456, MyComm);
1020 MPI_Send(&nedofs[0], 1, MPI_INT, 0, 457, MyComm);
1021 MPI_Send(&nfdofs[0], 1, MPI_INT, 0, 458, MyComm);
1022 MPI_Send(h_data, nv[0], MPI_DOUBLE, 0, 460, MyComm);
1042 loc_norm = -pow(-loc_norm, p);
1046 loc_norm = pow(loc_norm, p);
1049 MPI_Allreduce(&loc_norm, &glob_norm, 1, MPI_DOUBLE, MPI_SUM, comm);
1051 if (glob_norm < 0.0)
1053 glob_norm = -pow(-glob_norm, 1.0/p);
1057 glob_norm = pow(glob_norm, 1.0/p);
1062 MPI_Allreduce(&loc_norm, &glob_norm, 1, MPI_DOUBLE, MPI_MAX, comm);
1074 MFEM_VERIFY(ffes,
"the flux FE space must be ParFiniteElementSpace");
1087 for (
int i = 0; i < count.Size(); i++)
1089 if (count[i] != 0) { flux(i) /= count[i]; }
1110 int norm_p,
double solver_tol,
int solver_max_it)
1120 for (
int i = 0; i < xfes->
GetNE(); i++)
1127 *flux_fes.
GetFE(i), el_f,
false);
1140 MFEM_VERIFY(smooth_flux_fes.
GetFE(0) != NULL,
1141 "Could not obtain FE of smooth flux space.");
1196 double total_error = 0.0;
1198 for (
int i = 0; i < xfes->
GetNE(); i++)
1201 total_error += pow(errors(i), norm_p);
1205 MPI_Allreduce(&total_error, &glob_error, 1, MPI_DOUBLE, MPI_SUM,
1208 return pow(glob_error, 1.0/norm_p);
1213 #endif // MFEM_USE_MPI
int GetNPoints() const
Returns the number of the points in the integration rule.
Abstract class for all finite elements.
int GetNFaceNeighbors() const
Ordering::Type GetOrdering() const
Return the ordering method.
int Size() const
Return the logical size of the array.
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
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().
Class for an integration rule - an Array of IntegrationPoint.
HypreParVector * NewTrueDofVector()
Class for grid function - Vector with associated FE space.
void Bcast(T *ldata, int layout) const
Broadcast within each group where the master is the root.
virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const
Evaluate the values of all shape functions of a vector finite element in reference space at the given...
void ExchangeFaceNbrData()
void SumFluxAndCount(BilinearFormIntegrator &blfi, GridFunction &flux, Array< int > &counts, bool wcoef, int subdomain)
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
ParMesh * GetParMesh() const
HypreParVector * ParallelAssemble() const
Returns a new vector assembled on the true dofs.
Base class for vector Coefficients that optionally depend on time and space.
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 ProjectDeltaCoefficient(DeltaCoefficient &delta_coeff, double &integral)
HypreParVector * ParallelProject() const
Returns a new vector restricted to the true dofs.
virtual void GetElementDofValues(int el, Vector &dof_vals) const
virtual void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const
virtual const Operator * GetProlongationMatrix() const
The returned Operator is owned by the FiniteElementSpace.
void SetSize(int s)
Resize the vector to size s.
void GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i'th element.
double Scale()
Return the scale factor times the optional time dependent function. Returns with when not set by th...
void ProjectDiscCoefficient(VectorCoefficient &coeff, Array< int > &dof_attr)
int GetNSharedFaces() const
Return the number of shared faces (3D), edges (2D), vertices (1D)
ParFiniteElementSpace * pfes
Points to the same object as fes.
void Copy(Array ©) const
Create a copy of the internal array to the provided copy.
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Data type dense matrix using column-major storage.
virtual double * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Delta function coefficient optionally multiplied by a weight coefficient and a scaled time dependent ...
int Size() const
Returns the size of the vector.
int GetNE() const
Returns number of elements.
virtual double GetValue(int i, const IntegrationPoint &ip, int vdim=1) const
virtual void Save(std::ostream &out) const
void DivideByGroupSize(double *vec)
Scale a vector of true dofs.
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
virtual void ProjectDiscCoefficient(VectorCoefficient &coeff)
Project a discontinuous vector coefficient as a grid function on a continuous finite element space...
virtual void SetSpace(FiniteElementSpace *f)
Associate a new FiniteElementSpace with the ParGridFunction.
void AccumulateAndCountBdrTangentValues(VectorCoefficient &vcoeff, Array< int > &bdr_attr, Array< int > &values_counter)
Abstract parallel finite element space.
int GetMapType() const
Returns the FiniteElement::MapType of the element describing how reference functions are mapped to ph...
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
virtual void GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element 'elem'.
Vector send_data
Vector used as an MPI buffer to send face-neighbor data in ExchangeFaceNbrData() to neighboring proce...
int GetLocalTDofNumber(int ldof) const
void ComputeMeans(AvgType type, Array< int > &zones_per_vdof)
double * GetData() const
Return a pointer to the beginning of the Vector data.
FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31)
int Size_of_connections() const
void SetPrintLevel(int print_lvl)
virtual void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
void GetFaceNbrElementVDofs(int i, Array< int > &vdofs) const
virtual void MakeRef(FiniteElementSpace *f, double *v)
Make the ParGridFunction reference external data on a new FiniteElementSpace.
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
virtual void GetElementDofValues(int el, Vector &dof_vals) const
int GetNE() const
Returns number of elements in the mesh.
The BoomerAMG solver in hypre.
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
void MultTranspose(const double *x, double *y) const
Multiply a vector with the transpose matrix.
Communicator performing operations within groups defined by a GroupTopology with arbitrary-size data ...
const FiniteElement * GetFaceNbrFE(int i) const
void ExchangeFaceNbrData()
double f(const Vector &xvec)
double GetElementSize(ElementTransformation *T, int type=0)
virtual const FiniteElement * GetFE(int i) const
static void Sum(OpData< T >)
Reduce operation Sum, instantiated for int and double.
ElementTransformation * GetFaceNbrElementTransformation(int i) const
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Mesh * GetMesh() const
Returns the mesh.
virtual double * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
int GetSharedFace(int sface) const
Return the local face index for the given shared face.
Memory< int > & GetJMemory()
void SetPrintLevel(int print_level)
FaceElementTransformations * GetSharedFaceTransformations(int sf, bool fill2=true)
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const =0
Evaluate the values of all shape functions of a scalar finite element in reference space at the given...
HypreParMatrix * Dof_TrueDof_Matrix() const
The true dof-to-dof interpolation matrix.
virtual double ComputeDGFaceJumpError(Coefficient *exsol, Coefficient *ell_coeff, JumpScaling jump_scaling, const IntegrationRule *irs[]=NULL) const
Returns the Face Jumps error for L2 elements.
void AccumulateAndCountZones(Coefficient &coeff, AvgType type, Array< int > &zones_per_vdof)
Accumulates (depending on type) the values of coeff at all shared vdofs and counts in how many zones ...
virtual void MakeRef(FiniteElementSpace *f, double *v)
Make the GridFunction reference external data on a new FiniteElementSpace.
int GetVDim() const
Returns vector dimension.
FiniteElementSpace * FESpace()
const T * Read(const Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for read access to mem with the mfem::Device's DeviceMemoryClass, if on_dev = true...
void AddElementVector(const Array< int > &dofs, const Vector &elemvect)
Add elements of the elemvect Vector to the entries listed in dofs. Negative dof values cause the -dof...
virtual const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
void SetMaxIter(int max_iter)
virtual void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const
int SpaceDimension() const
Wrapper for hypre's parallel vector class.
ElementTransformation * GetElementTransformation(int i) const
Returns ElementTransformation for the i-th element.
double GlobalLpNorm(const double p, double loc_norm, MPI_Comm comm)
Compute a global Lp norm from the local Lp norms computed by each processor.
void GetFaceElements(int Face, int *Elem1, int *Elem2) const
double p(const Vector &x, double t)
void GetFaceInfos(int Face, int *Inf1, int *Inf2) const
void ProjectBdrCoefficient(Coefficient *coeff[], VectorCoefficient *vcoeff, Array< int > &attr)
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.
virtual void Mult(const Vector &x, Vector &y) const
Matrix vector multiplication.
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
FiniteElementSpace * fes
FE space on which the grid function lives. Owned if fec is not NULL.
virtual void ComputeFlux(BilinearFormIntegrator &blfi, GridFunction &flux, bool wcoef=true, int subdomain=-1)
static void Max(OpData< T >)
Reduce operation Max, instantiated for int and double.
void CalcPhysShape(ElementTransformation &Trans, Vector &shape) const
Evaluate the values of all shape functions of a scalar finite element in physical space at the point ...
GroupCommunicator & GroupComm()
Return a reference to the internal GroupCommunicator (on VDofs)
static bool GetGPUAwareMPI()
FiniteElementCollection * fec
Used when the grid function is read from a file. It can also be set explicitly, see MakeOwner()...
double L2ZZErrorEstimator(BilinearFormIntegrator &flux_integrator, const ParGridFunction &x, ParFiniteElementSpace &smooth_flux_fes, ParFiniteElementSpace &flux_fes, Vector &errors, int norm_p, double solver_tol, int solver_max_it)
void Distribute(const Vector *tv)
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
double ComputeElementLpDistance(double p, int i, GridFunction &gf1, GridFunction &gf2)
Compute the Lp distance between two grid functions on the given element.
bool Nonconforming() const
void SaveAsOne(const char *fname, int precision=16) const
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name...
void GetFaceNbrElementTransformation(int i, IsoparametricTransformation *ElTr)
Vector face_nbr_data
Vector used to store data from face-neighbor processors, initialized by ExchangeFaceNbrData().
virtual const char * Name() const
Class for integration point with weight.
virtual const SparseMatrix * GetRestrictionMatrix() const
Get the R matrix which restricts a local dof vector to true dof vector.
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff, Array< int > &bdr_attr)
Project the tangential components of the given VectorCoefficient on the boundary. Only boundary attri...
double GetFaceNbrElementSize(int i, int type=0)
HypreParVector * ParallelAverage() const
Returns a new vector averaged on the true dofs.
void SetPreconditioner(HypreSolver &precond)
Set the hypre solver to be used as a preconditioner.
void Destroy()
Destroy a vector.
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
HypreParVector * GetTrueDofs() const
Returns the true dofs in a new HypreParVector.
void AddDistribute(double a, const Vector *tv)
double infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
virtual void SetSpace(FiniteElementSpace *f)
Associate a new FiniteElementSpace with the GridFunction.
int GetFaceNbrVSize() const
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip)=0
Evaluate the coefficient in the element described by T at the point ip.
for VectorFiniteElements (Nedelec, Raviart-Thomas)
const FiniteElementCollection * FEColl() const
Vector coefficient defined by a vector GridFunction.
HYPRE_Int Mult(HypreParVector &x, HypreParVector &y, double alpha=1.0, double beta=0.0) const
Computes y = alpha * A * x + beta * y.
Class for parallel grid function.
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.
double Eval(double h, int p) const
virtual void Mult(const HypreParVector &b, HypreParVector &x) const
Solve Ax=b with hypre's PCG.
int GetRangeType() const
Returns the FiniteElement::RangeType of the element, one of {SCALAR, VECTOR}.
Class for parallel meshes.
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
int GetFaceNbrRank(int fn) const
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
void AccumulateAndCountBdrValues(Coefficient *coeff[], VectorCoefficient *vcoeff, Array< int > &attr, Array< int > &values_counter)
virtual double GetValue(int i, const IntegrationPoint &ip, int vdim=1) const
void ParallelProject(Vector &tv) const
Returns the vector restricted to the true dofs.
ParFiniteElementSpace * ParFESpace() const
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const