/** High Order Finite Element Space for H(Curl) */ #include #include namespace ngcomp { using namespace ngcomp; HCurlHighOrderFESpace :: HCurlHighOrderFESpace (const MeshAccess & ama, const Flags & aflags) : FESpace (ama, aflags), flags(aflags) { gradientdomains.SetSize (ma.GetNDomains()); gradientdomains.Set(); fn=int(flags.GetNumFlag("face",1)); if (flags.NumListFlagDefined("gradientdomains")) { const ARRAY & graddomains = flags.GetNumListFlag ("gradientdomains"); // cout << " graddomains " << graddomains << endl; for (int i = 0; i < gradientdomains.Size(); i++) if (!graddomains[i]) gradientdomains.Clear(i); cout << endl << " ******* gradientdomains" << gradientdomains << endl; } if(flags.GetDefineFlag("nograds")) gradientdomains.Clear(); low_order_space = new NedelecFESpace (ma, 0, dimension, iscomplex); rel_order = int (flags.GetNumFlag ("relorder", 0)); smoother = int (flags.GetNumFlag("smoothing",8)); /* if (flags.GetDefineFlag ("optext")) { trig = new HCurlHighOrderTrig (order); tet = new HCurlHighOrderTet (order); prism = new HCurlHighOrderPrism (order); } else */ trig = new HCurlHighOrderTrig (order); tet = new HCurlHighOrderTet (order); prism = new HCurlHighOrderPrism (order); quad = new HCurlHighOrderQuad (order); hex = new HCurlHighOrderHex (order); segm = new HCurlHighOrderSegm (order); // Evaluator for shape tester static ConstantCoefficientFunction one(1); if (ma.GetDimension() == 2) { ARRAY coeffs(1); coeffs[0] = &one; evaluator = GetIntegrators().CreateBFI("massedge", 2, coeffs); } else if(ma.GetDimension() == 3) { ARRAY coeffs(1); coeffs[0] = &one; evaluator = GetIntegrators().CreateBFI("massedge",3,coeffs); boundary_evaluator = GetIntegrators().CreateBFI("robinedge",3,coeffs); } } HCurlHighOrderFESpace :: ~HCurlHighOrderFESpace () { ; } FESpace * HCurlHighOrderFESpace :: Create (const MeshAccess & ma, const Flags & flags) { /* int order = int(flags.GetNumFlag ("order", 0)); int dim = int(flags.GetNumFlag ("dim", 1)); bool iscomplex = flags.GetDefineFlag ("complex"); if (order <= 0) return new NedelecFESpace (ma,0, dim, iscomplex); // Space with MG else */ return new HCurlHighOrderFESpace (ma, flags); } void HCurlHighOrderFESpace :: Update() { int i, j; if (order < 0) throw Exception("HCurlHighOrderFESpace::Update() order < 0 !" ) ; low_order_space -> Update(); nv = ma.GetNV(); nel = ma.GetNE(); switch(ma.GetDimension()) { case 2: ned = ma.GetNEdges(); nfa = 0; break; case 3: ned = ma.GetNEdges(); nfa = ma.GetNFaces(); break; } order_edge.SetSize (ned); order_face.SetSize (nfa); order_inner.SetSize (nel); usegrad_edge.SetSize (ned); usegrad_face.SetSize (nfa); usegrad_cell.SetSize (nel); order_edge = order; order_face = order; order_inner = order; // order_inner = 0; usegrad_edge = 0; usegrad_face = 0; usegrad_cell = 0; ARRAY eledges, elfaces; for(i=0; i< nel; i++) if(gradientdomains[ma.GetElIndex(i)]) { ma.GetElEdges(i,eledges); for(j=0;j order_edge[eledges[j]]) order_edge[eledges[j]] = elorder; for (j = 0; j < elfaces.Size(); j++) if (elorder > order_face[elfaces[j]]) order_face[elfaces[j]] = elorder; if (elorder > order_inner[i]) order_inner[i] = elorder; } */ /* // skip dofs on Dirichlet boundary hack [JS] int nsel = ma.GetNE(); for (i = 0; i < nsel; i++) { ma.GetSElEdges (i, eledges); int face = ma.GetSElFace (i); for (j = 0; j < eledges.Size(); j++) order_edge[eledges[j]] = 0; order_face[face] = 0; } */ /* (*testout) << " order = " << order << endl; (*testout) << "order_edge = " << order_edge << endl; (*testout) << "order_face = " << order_face << endl; (*testout) << "order_inner = " << order_inner << endl; */ ARRAY pnums; ndof = ned; // Nedelec (order = 0) !! first_edge_dof.SetSize(ned+1); // last element = ndof; for (i = 0; i < ned; i++) { first_edge_dof[i] = ndof; ndof += usegrad_edge[i]*order_edge[i]; } first_edge_dof[ned] = ndof; first_face_dof.SetSize(nfa+1); int inci =0; for (i=0; i< nfa; i++) { if(order_face[i]>0) { ma.GetFacePNums(i,pnums); int p = order_face[i]; switch(pnums.Size()) { case 3: //Triangle inci = ((usegrad_face[i]+1)*p + 2)*(p-1)/2; break; case 4: //Quad // inci= 2*(p+1)*p; inci = ((usegrad_face[i]+1)*p + 2) * p; break; } } else inci = 0; first_face_dof[i] = ndof; ndof+= inci; } first_face_dof[nfa] = ndof; first_inner_dof.SetSize(nel+1); for (i=0; i< nel; i++) { int p = order_inner[i]; switch(ma.GetElType(i)) { case ET_TRIG: inci= ((usegrad_cell[i]+1)*p + 2) * (p-1) /2;; break; case ET_QUAD: inci= ((usegrad_cell[i]+1) * p + 2) * p; break; case ET_TET: inci = ((usegrad_cell[i] + 2) * p + 3) * (p-2) * (p-1) / 6; break; case ET_PRISM: inci = ((usegrad_cell[i]+2)* p + 3) * p * (p-1) / 2; break; case ET_HEX: inci = ((usegrad_cell[i] + 2 )* p + 3) * p * p; break; default: inci = 0; break; } if (inci < 0 || p <= 0) inci = 0; first_inner_dof[i] = ndof; ndof+= inci; } first_inner_dof[nel] = ndof; /* (*testout) << " HCURL " << endl; (*testout) << "usegrad_edge " << usegrad_edge << endl; (*testout) << "usegrad_face " << usegrad_face << endl; (*testout) << "usegrad_cell " << usegrad_cell << endl; (*testout) << "ndof = " << ndof << endl; (*testout) << "first_edge = " << first_edge_dof << endl; (*testout) << "first_face = " << first_face_dof << endl; (*testout) << "first_inner = " << first_inner_dof << endl; (*testout) << " order = " << order << endl; (*testout) << "order_edge HC = " << order_edge << endl; (*testout) << "order_face HC = " << order_face << endl; (*testout) << "order_inner HC = " << order_inner << endl; */ } const FiniteElement & HCurlHighOrderFESpace :: GetFE (int elnr, LocalHeap & lh) const { FiniteElement * fe = 0; switch (ma.GetElType(elnr)) { case ET_TET: fe = tet; break; case ET_PYRAMID: fe = pyramid; break; case ET_PRISM: fe = prism; break; case ET_TRIG: fe = trig; break; case ET_QUAD: fe = quad; break; case ET_HEX: fe = hex; break; default: fe = 0; } if (!fe) { stringstream str; str << "HCurlHighOrderFESpace " << GetClassName() << ", undefined eltype " << ElementTopology::GetElementName(ma.GetElType(elnr)) << ", order = " << order << endl; throw Exception (str.str()); } ArrayMem vnums; // calls GetElPNums -> max 12 for PRISM12 ma.GetElVertices(elnr, vnums); if(ma.GetDimension() == 2) { HCurlHighOrderFiniteElement<2> * hofe = dynamic_cast*> (fe); ArrayMem ednums, ord_edge, ug_edge; ma.GetElEdges(elnr, ednums); ord_edge.SetSize (ednums.Size()); ug_edge.SetSize (ednums.Size()); for (int j = 0; j < ednums.Size(); j++) { ord_edge[j] = order_edge[ednums[j]]; ug_edge[j] = usegrad_edge[ednums[j]]; } hofe -> SetVertexNumbers (vnums); hofe -> SetOrderEdge (ord_edge); hofe -> SetOrderInner (order_inner[elnr]); hofe -> SetUsegradEdge (ug_edge); hofe -> SetUsegradCell (usegrad_cell[elnr]); hofe -> ComputeNDof(); } else if (ma.GetDimension() == 3) { HCurlHighOrderFiniteElement<3> * hofe = dynamic_cast*> (fe); ArrayMem ednums, ord_edge, ug_edge; ArrayMem fanums, ord_face, ug_face; ma.GetElEdges(elnr, ednums); ma.GetElFaces(elnr, fanums); ord_edge.SetSize (ednums.Size()); ord_face.SetSize (fanums.Size()); ug_edge.SetSize (ednums.Size()); ug_face.SetSize (fanums.Size()); for (int j = 0; j < ednums.Size(); j++) { ord_edge[j] = order_edge[ednums[j]]; ug_edge[j] = usegrad_edge[ednums[j]]; } for (int j = 0; j < fanums.Size(); j++) { ord_face[j] = order_face[fanums[j]]; ug_face[j] = usegrad_face[fanums[j]]; } hofe -> SetVertexNumbers (vnums); hofe -> SetOrderEdge (ord_edge); hofe -> SetOrderFace (ord_face); hofe -> SetOrderInner (order_inner[elnr]); hofe -> SetUsegradEdge (ug_edge); hofe -> SetUsegradFace (ug_face); hofe -> SetUsegradCell (usegrad_cell[elnr]); hofe -> ComputeNDof(); } return *fe; } const FiniteElement & HCurlHighOrderFESpace :: GetSFE (int selnr, LocalHeap & lh) const { int i, j; FiniteElement * fe = 0; switch (ma.GetSElType(selnr)) { case ET_SEGM: fe = segm; break; case ET_TRIG: fe = trig; break; case ET_QUAD: fe = quad; break; default: fe = 0; } if (!fe) { stringstream str; str << "HCurlHighOrderFESpace " << GetClassName() << ", undefined eltype " << ElementTopology::GetElementName(ma.GetSElType(selnr)) << ", order = " << order << endl; throw Exception (str.str()); } ArrayMem vnums; ArrayMem ednums, ord_edge, ug_edge; int ord_face, ug_face; ma.GetSElVertices(selnr, vnums); if(fe == segm) { HCurlHighOrderFiniteElement<1> * hofe = dynamic_cast*> (fe); hofe -> SetVertexNumbers (vnums); ma.GetSElEdges(selnr, ednums); hofe -> SetOrderInner (order_edge[ednums[0]]); hofe -> SetUsegradCell (usegrad_edge[ednums[0]]); hofe -> ComputeNDof(); } else { HCurlHighOrderFiniteElement<2> * hofe = dynamic_cast*> (fe); ma.GetSElEdges(selnr, ednums); ord_face = order_face[ma.GetSElFace(selnr)]; ug_face = usegrad_face[ma.GetSElFace(selnr)]; ord_edge.SetSize (ednums.Size()); ug_edge.SetSize (ednums.Size()); for (j = 0; j < ednums.Size(); j++) { ord_edge[j] = order_edge[ednums[j]]; ug_edge[j] = usegrad_edge[ednums[j]]; } hofe -> SetVertexNumbers (vnums); hofe -> SetOrderEdge (ord_edge); hofe -> SetOrderInner (ord_face); hofe -> SetUsegradEdge(ug_edge); hofe -> SetUsegradCell(ug_face); hofe -> ComputeNDof(); } return *fe; } int HCurlHighOrderFESpace :: GetNDof () const { return ndof; } void HCurlHighOrderFESpace :: GetDofNrs (int elnr, ARRAY & dnums) const { // Save phase-functions the way // (1*e1),.. (1*e_ne) // (p_t)*tang_e1, ... p_t*tang_ne // p_n * el1, p_i * el1, ... , p_n * nel_n , p_i *el_nel ARRAY vnums, ednums, fnums; int i, j; int first,next; ma.GetElEdges (elnr, ednums); if(ma.GetDimension() == 3) ma.GetElFaces (elnr, fnums); else fnums.SetSize(0); dnums.SetSize(0); if(order < 0) throw Exception(" HCurlHighOrderFESpace :: GetDofNrs() order < 0 "); //Nedelec0 for (i = 0; i < ednums.Size(); i++) dnums.Append (ednums[i]); //edges_tang for (i = 0; i < ednums.Size(); i++) { first = first_edge_dof[ednums[i]]; next = first_edge_dof[ednums[i]+1]; for (j = first; j & dnums) const { if (!eliminate_internal) { GetDofNrs (elnr, dnums); return; } // Save phase-functions the way // (1*e1),.. (1*e_ne) // (p_t)*tang_e1, ... p_t*tang_ne // p_n * el1, p_i * el1, ... , p_n * nel_n , p_i *el_nel ARRAY vnums, ednums, fnums; int i, j; int first,next; ma.GetElEdges (elnr, ednums); if(ma.GetDimension() == 3) ma.GetElFaces (elnr, fnums); else fnums.SetSize(0); dnums.SetSize(0); if(order < 0) throw Exception(" HCurlHighOrderFESpace :: GetDofNrs() order < 0 "); //Nedelec0 for (i = 0; i < ednums.Size(); i++) dnums.Append (ednums[i]); //edges_tang for (i = 0; i < ednums.Size(); i++) { first = first_edge_dof[ednums[i]]; next = first_edge_dof[ednums[i]+1]; for (j = first; j & dnums) const { // Save shape-functions the way // (1*e1),.. (1*e_ne) // (p_t)*tang_e1, ... p_t*tang_ne // p_n * el1, p_i * el1, ... , p_n * nel_n , p_i *el_nel ARRAY vnums, ednums; int fnum; int i, j; int first,next; ma.GetSElEdges (selnr, ednums); fnum = ma.GetSElFace (selnr); dnums.SetSize(0); if(order <0) throw (" HCurlHighOrderFESpace :: GetSDofNrs() order < 0 "); //Nedelec for (i = 0; i < ednums.Size(); i++) dnums.Append (ednums[i]); //edges_tang for (i = 0; i < ednums.Size(); i++) { first = first_edge_dof[ednums[i]]; next = first_edge_dof[ednums[i]+1]; for (j = first; j 1) { // inner = normal + bubbles first = first_face_dof[fnum]; next = first_face_dof[fnum+1]; for(j=first; j vnums; ARRAY orient; ARRAY ednums, fanums, faorient; for(i=0; i< nel ; i++) ma.GetElVertices (i, vnums); for(i=0; i< nel; i++) ma.GetElEdges (i,vnums,orient); int pn1,pn2; for(i=0; i< ned; i++) ma.GetEdgePNums (i,pn1,pn2); switch(SmoothingType) { case 1: // 1 RT Block ncnt = 1 + first_edge_dof.Size() -1 + first_inner_dof.Size() -1; break; case 2: // ned RT Blocks ncnt = ned + first_edge_dof.Size() -1 + first_inner_dof.Size() -1; break; case 3: // ned RT+ edges_normal Blocks ncnt = ned + first_inner_dof.Size() -1; break; case 4: // no RT Block ncnt = first_edge_dof.Size() -1 + first_inner_dof.Size() -1; break; case 5: // RT in divergence blocks ncnt = nv + first_edge_dof.Size() -1 + first_inner_dof.Size() -1; break; case 6: ncnt = ned + nfa; break; case 7: ncnt = nv + ned + nfa + nel; break; case 8: ncnt = nv + ned + nfa + nel; break; case 9: ncnt = nv + ned + nfa + nel; break; case 10: ncnt = nv + ned + nfa + nel; default: cout << " Error in HCurlHOFESpace :: CreateSmoothingBlocks no SmoothingType " << endl; ncnt =0; } ARRAY cnt(ncnt); cnt = 0; cout << " ncnt " << ncnt << endl; switch (SmoothingType) { case 1: ii = 0; cnt[ii] = ned; //RT ii++; for(i=0; i< first_edge_dof.Size()-1;i++ ) cnt[ii++] = first_edge_dof[i+1] - first_edge_dof[i]; for(i=0; i< first_inner_dof.Size()-1;i++ ) cnt[ii++] = first_inner_dof[i+1] - first_inner_dof[i]; break; case 2: ii = 0; for(i=0; i< ned; i++) cnt[ii++] = 1; for(i=0; i< first_edge_dof.Size()-1;i++ ) cnt[ii++] = first_edge_dof[i+1] - first_edge_dof[i]; for(i=0; i< first_inner_dof.Size()-1;i++ ) cnt[ii++] = first_inner_dof[i+1] - first_inner_dof[i]; break; case 3: ii = 0; for(i=0; i< ned; i++) cnt[i] = 1; for(i=0; i< first_edge_dof.Size()-1;i++ ) cnt[i] += first_edge_dof[i+1] - first_edge_dof[i]; ii=ned; for(i=0; i< first_inner_dof.Size()-1;i++) cnt[ii++] = first_inner_dof[i+1] - first_inner_dof[i]; break; case 4: ii = 0; for(i=0; i< first_edge_dof.Size()-1;i++ ) cnt[ii++] = first_edge_dof[i+1] - first_edge_dof[i]; for(i=0; i< first_inner_dof.Size()-1;i++ ) cnt[ii++] = first_inner_dof[i+1] - first_inner_dof[i]; break; case 5: int v1, v2; for(i=0; i< nv; i++) cnt[i]=0; for(i=0; i< ned; i++) { ma.GetEdgePNums (i, v1, v2); cnt[v1]++; cnt[v2]++; } ii = nv; for(i=0; i< first_edge_dof.Size()-1;i++ ) cnt[ii++] = first_edge_dof[i+1] - first_edge_dof[i]; for(i=0; i< first_inner_dof.Size()-1;i++ ) cnt[ii++] = first_inner_dof[i+1] - first_inner_dof[i]; break; case 6: { for (i = 0; i < ned; i++) cnt[i] = first_edge_dof[i+1] - first_edge_dof[i]; for (i = 0; i < nfa; i++) cnt[ned+i] = first_face_dof[i+1] - first_face_dof[i]; for (i = 0; i < nel; i++) { if(ma.GetDimension() == 3) ma.GetElFaces (i, fanums, faorient); else fanums.SetSize(0); for (j = 0; j < fanums.Size(); j++) cnt[ned+fanums[j]] += first_inner_dof[i+1]-first_inner_dof[i]; } break; } case 7: { /* for (i = 0; i < ned; i++) cnt[i] = first_edge_dof[i+1] - first_edge_dof[i]; for (i = 0; i < nfa; i++) cnt[ned+i] = first_face_dof[i+1] - first_face_dof[i]; for (i = 0; i < nel; i++) cnt[ned+nfa+i] = first_inner_dof[i+1] - first_inner_dof[i]; break; */ for (i = 0; i < ned; i++) cnt[ma.GetClusterRepEdge(i)] += first_edge_dof[i+1] - first_edge_dof[i]; for (i = 0; i < nfa; i++) cnt[ma.GetClusterRepFace(i)] += first_face_dof[i+1] - first_face_dof[i]; if (!eliminate_internal) for (i = 0; i < nel; i++) cnt[ma.GetClusterRepElement(i)] += first_inner_dof[i+1] - first_inner_dof[i]; break; } case 8: { for (i = 0; i < ned; i++) { ma.GetEdgePNums (i,pn1,pn2); cnt[pn1] += 1 + first_edge_dof[i+1] - first_edge_dof[i]; cnt[pn2] += 1 + first_edge_dof[i+1] - first_edge_dof[i]; } for (i = 0; i < nfa; i++) { cnt[nv+ned+i] = first_face_dof[i+1] - first_face_dof[i]; } if (!eliminate_internal) for (i = 0; i < nel; i++) cnt[nv+ned+nfa+i] = first_inner_dof[i+1] - first_inner_dof[i]; else for (i = 0; i < nel; i++) cnt[nv+ned+nfa+i] = 0; break; } case 9: { for (i = 0; i < nv; i++) cnt[i] = 1; for (i = 0; i < ned; i++) cnt[nv+i] = first_edge_dof[i+1] - first_edge_dof[i]; for (i = 0; i < nfa; i++) cnt[nv+ned+i] = first_face_dof[i+1] - first_face_dof[i]; for (i = 0; i < nel; i++) { ma.GetElEdges (i,ednums,orient); for (k = 0; k < ednums.Size(); k++) cnt[nv+ednums[k]] += first_inner_dof[i+1] - first_inner_dof[i]; ma.GetElFaces (i,fanums,orient); for (k = 0; k < fanums.Size(); k++) cnt[nv+ned+fanums[k]] += first_inner_dof[i+1] - first_inner_dof[i]; } break; } } Table & table = *new Table (cnt); switch(SmoothingType) { case 1: ii=0; for(i=0; i dnums_h1l; ARRAY dnums_hcl; LocalHeap lh (1000000); // Matrix Graph for gradient matrix , start (end) position for assembling ARRAY cnts(ndof); // for(int i=0; i & grad = *new SparseMatrix(cnts); //cout << " grad cnts " << endl; // (*testout) << " grad cnts " << endl; // vertices - nedelec for (int i = 0; i < ned; i++) { int p1,p2; ma.GetEdgePNums(i,p1,p2); grad.CreatePosition(i,p1); grad.CreatePosition(i,p2); //if(p1 > p2) // A&C if (p1 < p2) // new { grad(i,p1) = -1.; grad(i,p2) = 1.; } else { grad(i,p1) = 1.; grad(i,p2) = -1.; } } for(int i=0; i