#include namespace ngfem { using namespace ngfem; #include "hdivhofe.hpp" //------------------------------------------------------------------------ // HDivHighOrderFiniteElement //------------------------------------------------------------------------ template HDivHighOrderFiniteElement :: HDivHighOrderFiniteElement (ELEMENT_TYPE aeltype) : HDivFiniteElement (aeltype, -1, -1) { for (int i = 0; i < 8; i++) vnums[i] = i; augmented = 0; } template void HDivHighOrderFiniteElement:: SetVertexNumbers (FlatArray & avnums) { for (int i = 0; i < avnums.Size(); i++) vnums[i] = avnums[i]; } template void HDivHighOrderFiniteElement:: SetOrderEdge (FlatArray & oe) { for (int i = 0; i < oe.Size(); i++) order_edge[i] = oe[i]; ComputeNDof(); } template void HDivHighOrderFiniteElement:: SetOrderFace (FlatArray & of) { for (int i = 0; i < of.Size(); i++) order_face[i] = of[i]; ComputeNDof(); } template void HDivHighOrderFiniteElement:: SetOrderInner (int oi) { order_inner = oi; ComputeNDof(); } //------------------------------------------------------------------------ // HDivHighOrderNormalFiniteElement //------------------------------------------------------------------------ template HDivHighOrderNormalFiniteElement :: HDivHighOrderNormalFiniteElement (ELEMENT_TYPE aeltype) : HDivNormalFiniteElement (aeltype, -1, -1) { for (int i = 0; i < 4; i++) vnums[i] = i; augmented = 0; } template void HDivHighOrderNormalFiniteElement:: SetVertexNumbers (FlatArray & avnums) { for (int i = 0; i < avnums.Size(); i++) vnums[i] = avnums[i]; } template void HDivHighOrderNormalFiniteElement:: SetOrderInner (int oi) { order_inner = oi; } //------------------------------------------------------------------------ // HDivHighOrderNormalSegm //------------------------------------------------------------------------ template HDivHighOrderNormalSegm :: HDivHighOrderNormalSegm (int aorder) : HDivHighOrderNormalFiniteElement<1>(ET_SEGM) { order_inner = aorder; ComputeNDof(); } template void HDivHighOrderNormalSegm :: ComputeNDof() { ndof = order_inner + 1; order = order_inner; } template void HDivHighOrderNormalSegm :: CalcShape (const IntegrationPoint & ip, FlatVector<> shape) const { double x = ip(0); int p = order_inner; int fac = 1; if (vnums[0] > vnums[1]) { fac *= -1; x=1-x; } ArrayMem rec_pol(p+1), leg(2); MatrixFixWidth<2> DExt(p); T_ORTHOPOL::CalcTrigExtDeriv(p+1, 1-2*x, 0, DExt); //IntegratedLegendrePolynomial (order_inner, 1-2*x, rec_pol); // LegendrePolynomial (order_inner, 2*x-1, rec_pol); //T_ORTHOPOL::CalcDeriv(order_inner+1, 1-2*x, rec_pol); shape(0) = -1.*fac; for(int j=1; j<=p;j++) shape(j) = 2.* fac * DExt(j-1,0); } template class HDivHighOrderNormalSegm; template class HDivHighOrderNormalSegm; //template class HDivHighOrderNormalSegm; //template class HDivHighOrderNormalSegm; //------------------------------------------------------------------------ // HDivHighOrderNormalQuad //------------------------------------------------------------------------ template HDivHighOrderNormalQuad :: HDivHighOrderNormalQuad (int aorder) : HDivHighOrderNormalFiniteElement<2>(ET_QUAD) { order_inner = aorder; ComputeNDof(); } template void HDivHighOrderNormalQuad :: ComputeNDof() { ndof = 1 + order_inner*order_inner + 2*order_inner; order = order_inner; order++; } template void HDivHighOrderNormalQuad :: CalcShape (const IntegrationPoint & ip, FlatVector<> shape) const { int i, j, k, l, m, ii; AutoDiff<2> x (ip(0), 0); AutoDiff<2> y (ip(1), 1); AutoDiff<2> lami[4] = {(1-x)*(1-y),x*(1-y),x*y,(1-x)*y}; AutoDiff<2> sigma[4] = {(1-x)+(1-y),x+(1-y),x+y,(1-x)+y}; shape = 0.0; ii = 1; int p = order_inner; ArrayMem,20> pol_xi(p+1), pol_eta(p+1); AutoDiff<2> polprod; int fmax = 0; for (int j = 1; j < 4; j++) if (vnums[j] > vnums[fmax]) fmax = j; int f1 = (fmax+3)%4; int f2 = (fmax+1)%4; int fac = 1; if(vnums[f2] > vnums[f1]) { swap(f1,f2); // fmax > f1 > f2; fac *= -1; } AutoDiff<2> xi = sigma[fmax]-sigma[f1]; AutoDiff<2> eta = sigma[fmax]-sigma[f2]; shape(0) = fac; T_ORTHOPOL::Calc(p+1, xi,pol_xi); T_ORTHOPOL::Calc(p+1,eta,pol_eta); // Typ 1 for (k = 0; k < p; k++) { for (l = 0; l < p; l++, ii++) { shape(ii) = 2.*(pol_eta[l].DValue(0)*pol_xi[k].DValue(1)-pol_eta[l].DValue(1)*pol_xi[k].DValue(0)); } } //Typ 2 for (k = 0; k < p; k++, ii+=2) { shape(ii) = -xi.DValue(0)*pol_eta[k].DValue(1) + xi.DValue(1)*pol_eta[k].DValue(0); shape(ii+1) = -eta.DValue(0)*pol_xi[k].DValue(1) + eta.DValue(1)*pol_xi[k].DValue(0); } return; } template class HDivHighOrderNormalQuad; template class HDivHighOrderNormalQuad; template class HDivHighOrderNormalQuad; template class HDivHighOrderNormalQuad; //------------------------------------------------------------------------ // HDivHighOrderNormalTrig //------------------------------------------------------------------------ template HDivHighOrderNormalTrig :: HDivHighOrderNormalTrig (int aorder) : HDivHighOrderNormalFiniteElement<2>(ET_TRIG) { order_inner = aorder; ComputeNDof(); } template void HDivHighOrderNormalTrig :: ComputeNDof() { ndof = 1 + (order_inner*order_inner+3*order_inner)/2; order = order_inner; order++; } template void HDivHighOrderNormalTrig :: CalcShape (const IntegrationPoint & ip, FlatVector<> shape) const { double x = ip(0); double y = ip(1); double lami[3]; lami[0] = x; lami[1] = y; lami[2] = 1-x-y; Mat<3,2> dlami(0); dlami(0,0) = 1.; dlami(1,1) = 1.; dlami(2,0) = -1.; dlami(2,1) = -1.; int ii, i, j, k, l, is, ie, iop; int p = order_inner; ii = 1; int fav[3]; for(i=0;i<3;i++) fav[i] = i; //Sort vertices first edge op minimal vertex int fswap = 1; if(vnums[fav[0]] > vnums[fav[1]]) { swap(fav[0],fav[1]); fswap *= -1; } if(vnums[fav[1]] > vnums[fav[2]]) { swap(fav[1],fav[2]); fswap *= -1; } if(vnums[fav[0]] > vnums[fav[1]]) { swap(fav[0],fav[1]); fswap *= -1; } is = fav[0]; ie = fav[1]; iop = fav[2]; AutoDiff<2> ls = lami[is]; AutoDiff<2> le = lami[ie]; AutoDiff<2> lo = lami[iop]; //AutoDiff<3> lsle = lami[is]*lami[ie]; for (j = 0; j < 2; j++) { ls.DValue(j) = dlami(is,j); le.DValue(j) = dlami(ie,j); lo.DValue(j) = dlami(iop,j); } Vec<2> nedelec; for (j = 0; j < 2; j++) nedelec(j) = ls.Value()*le.DValue(j) - le.Value()*ls.DValue(j); AutoDiff<2> lsle=ls*le; // RT_0-normal low order shapes shape(0) = fswap; Vec<2> grad1, grad2; ArrayMem, 100> ad_rec_pol1(100); ArrayMem, 100> ad_rec_pol2(100); ScaledLegendrePolynomial(p-1, le-ls, 1-lo, ad_rec_pol1); LegendrePolynomial(p-1, 2*lo-1, ad_rec_pol2); for (k = 0; k <= p-1; k++) { ad_rec_pol1[k] *= lsle; ad_rec_pol2[k] *= lo; } // Typ 1 for (k = 0; k <= p-1; k++) { for (l = 0; l <= p-1-k; l++, ii++) { for (j = 0; j < 2; j++) { grad1(j) = ad_rec_pol1[k].DValue(j); grad2(j) = ad_rec_pol2[l].DValue(j); } shape(ii) = 2. * (grad1(1)*grad2(0) - grad1(0)*grad2(1)); } } // Typ 2 double curlned; curlned = 2.* (ls.DValue(0)*le.DValue(1) - ls.DValue(1)*le.DValue(0)); for (k = 0; k <= p-1; k++, ii++) { for (j = 0; j < 2; j++) grad2(j) = ad_rec_pol2[k].DValue(j); shape(ii) = (grad2(0)*nedelec(1) - grad2(1)*nedelec(0)) + ad_rec_pol2[k].Value()*curlned; } } template class HDivHighOrderNormalTrig; template class HDivHighOrderNormalTrig; template class HDivHighOrderNormalTrig; template class HDivHighOrderNormalTrig; //------------------------------------------------------------------------ // HDivHighOrderTrig //------------------------------------------------------------------------ template HDivHighOrderTrig :: HDivHighOrderTrig (int aorder) : HDivHighOrderFiniteElement<2>(ET_TRIG) { order_inner = aorder; for (int i = 0; i < 3; i++) order_edge[i] = aorder; ComputeNDof(); } template void HDivHighOrderTrig :: ComputeNDof() { ndof_edge =0; ndof = 3; // Thomas-Raviart // if oder_edge < 1 --> Thomas Raviart int i; for (i = 0; i < 3; i++) { ndof += order_edge[i]; ndof_edge += order_edge[i]; } if (order_inner > 1) { ndof += order_inner*order_inner-1; //ndof += order_inner_curl*(order_inner_curl-1)/2; //ndof += order_inner*(order_inner-1)/2 + order_inner-1; } order = 0; // max(order_edges_normal,order_inner); for (i = 0; i < 3; i++) { if (order_edge[i] > order) order = order_edge[i]; } if (order_inner > order) // order_edge_tangential = order_inner; order = order_inner; order++; } template void HDivHighOrderTrig :: CalcShape (const IntegrationPoint & ip, FlatMatrixFixWidth<2> shape) const { double x = ip(0); double y = ip(1); double lami[3]; lami[0] = x; lami[1] = y; lami[2] = 1-x-y; Mat<3,2> dlami(0); dlami(0,0) = 1.; dlami(1,1) = 1.; dlami(2,0) = -1.; dlami(2,1) = -1.; Mat<3,2> clami(0); clami(0,1) = -1.; clami(1,0) = 1.; clami(2,1) = 1.; clami(2,0) = -1.; shape = 0.0; int p, p_curl; int i, j, k, l; int ii = 3; const EDGE * edges = ElementTopology::GetEdges (ET_TRIG); int is, ie, io; for (i = 0; i < 3; i++) { p = order_edge[i]; is = edges[i][0]; ie = edges[i][1]; io = 3-is-ie; if (vnums[is] > vnums[ie]) swap (is, ie); //RT low order edge shape function for(j=0; j<2; j++) shape(i,j) = lami[ie]*clami(is,j) - lami[is]*clami(ie,j); //Edge normal shapes if(p>0) { MatrixFixWidth<2> DExt(p+2); T_ORTHOPOL::CalcTrigExtDeriv(p+1, lami[ie]-lami[is], lami[io], DExt); for(j=0; j<= p-1;j++) { shape(ii,0) = (clami(ie,0) - clami(is,0)) * DExt(j,0) + clami(io,0) * DExt(j,1); shape(ii++,1) = (clami(ie,1) - clami(is,1)) * DExt(j,0) + clami(io,1) * DExt(j,1); } } } if(order_inner < 2) return; p = order_inner; p_curl = order_inner; //Inner shapes if(p>1) { ArrayMem rec_pol(order-1), drec_polx(order-1), drec_polt(order-1); ArrayMem rec_pol2(order-1), drec_pol2x(order-1), drec_pol2t(order-1); ArrayMem mem(3*order*sizeof(double)); ArrayMem mem2(3*order*sizeof(double)); FlatMatrixFixWidth<3> curl_recpol(order, &mem[0]); FlatMatrixFixWidth<3> curl_recpol2(order, &mem2[0]); int fav[3]; for(i=0;i<3;i++) fav[i] = i; //Sort vertices first edge op minimal vertex if(vnums[fav[0]] > vnums[fav[1]]) swap(fav[0],fav[1]); if(vnums[fav[1]] > vnums[fav[2]]) swap(fav[1],fav[2]); if(vnums[fav[0]] > vnums[fav[1]]) swap(fav[0],fav[1]); double ls = lami[fav[0]]; double le = lami[fav[1]]; double lo = lami[fav[2]]; ScaledLegendrePolynomialandDiff(p_curl-2, le-ls, 1-lo, rec_pol, drec_polx, drec_polt); LegendrePolynomialandDiff(p_curl-2, 2*lo-1,rec_pol2, drec_pol2x); // \curl (ls * le * rec_pol), and \curl (lo rec_pol2) for (j = 0; j <= p_curl-2; j++) { for (l = 0; l < 2; l++) { curl_recpol(j,l) = ls * le * (drec_polx[j] * (clami(fav[1],l) - clami(fav[0],l)) - drec_polt[j] * (clami(fav[2],l))) + (ls * clami(fav[1],l) + le * clami(fav[0],l)) * rec_pol[j]; curl_recpol2(j,l) = lo * (drec_pol2x[j] * 2*clami(fav[2],l)) + clami(fav[2],l) * rec_pol2[j]; } } // curls: for (j = 0; j <= p_curl-2; j++) for (k = 0; k <= p_curl-2-j; k++, ii++) for (l = 0; l < 2; l++) shape(ii, l) = ls*le*rec_pol[j]*curl_recpol2(k,l) + curl_recpol(j,l)*lo*rec_pol2[k]; // rotations of curls for (j = 0; j <= p-2; j++) for (k = 0; k <= p-2-j; k++, ii++) for (l = 0; l < 2; l++) shape(ii, l) = ls*le*rec_pol[j]*curl_recpol2(k,l) - curl_recpol(j,l) * lo * rec_pol2[k]; // rec_pol2 * RT_0 for (j = 0; j <= p-2; j++, ii++) for (l = 0; l < 2; l++) shape(ii,l) = lo*rec_pol2[j] * (ls*clami(fav[1],l)-le*clami(fav[0],l)); } } template void HDivHighOrderTrig :: CalcDivShape (const IntegrationPoint & ip, FlatVector<> shape) const { double lami[3]; lami[0] = ip(0); lami[1] = ip(1); lami[2] = 1-ip(0)-ip(1); Mat<3,2> dlami(0.); dlami(0,0) = 1.; dlami(1,1) = 1.; dlami(2,0) = -1.; dlami(2,1) = -1.; Mat<3,2> clami(0.); clami(0,1) = -1.; clami(1,0) = 1.; clami(2,1) = 1.; clami(2,0) = -1.; shape = 0.0; int p, p_curl; int i, j, k, l; int ii = 3; const EDGE * edges = ElementTopology::GetEdges (ET_TRIG); for (i = 0; i < 3; i++) { p = order_edge[i]; int is = edges[i][0]; int ie = edges[i][1]; if (vnums[is] > vnums[ie]) swap (is, ie); //RT low order edge shape function //shape(i) = 2*(dlami(ie,0)*clami(is,0) + dlami(ie,1)*clami(ie,1)); for(j=0; j<= 1; j++) shape(i) += dlami(ie,j)*clami(is,j) - dlami(is,j)*clami(ie,j); //Edge normal shapes (curls) if(p>0) { for(j=0; j<= p-1;j++) ii++; } } if(order_inner < 2) return; p = order_inner; p_curl = order_inner; //Inner shapes (Face) if(p>1) { ArrayMem rec_pol(order-1), drec_polx(order-1), drec_polt(order-1); ArrayMem rec_pol2(order-1), drec_pol2x(order-1), drec_pol2t(order-1); ArrayMem mem(3*order*sizeof(double)); ArrayMem mem2(3*order*sizeof(double)); FlatMatrixFixWidth<2> grad_recpol(order, &mem[0]); FlatMatrixFixWidth<2> grad_recpol2(order, &mem2[0]); int fav[3]; for(i=0;i<3;i++) fav[i] = i; //Sort vertices first edge op minimal vertex if(vnums[fav[0]] > vnums[fav[1]]) swap(fav[0],fav[1]); if(vnums[fav[1]] > vnums[fav[2]]) swap(fav[1],fav[2]); if(vnums[fav[0]] > vnums[fav[1]]) swap(fav[0],fav[1]); double ls = lami[fav[0]]; double le = lami[fav[1]]; double lo = lami[fav[2]]; ScaledLegendrePolynomialandDiff(p_curl-2, le-ls, 1-lo, rec_pol, drec_polx, drec_polt); LegendrePolynomialandDiff(p_curl-2, 2*lo-1,rec_pol2, drec_pol2x); // \curl (ls * le * rec_pol), and \curl (lo rec_pol2) for (j = 0; j <= p_curl-2; j++) { for (l = 0; l < 2; l++) { grad_recpol(j,l) = ls * le * (drec_polx[j] * (dlami(fav[1],l) - dlami(fav[0],l)) - drec_polt[j] * (dlami(fav[2],l))) + (ls * dlami(fav[1],l) + le * dlami(fav[0],l)) * rec_pol[j]; grad_recpol2(j,l) = lo * (drec_pol2x[j] * 2*dlami(fav[2],l)) + dlami(fav[2],l) * rec_pol2[j]; } } // curls: for (j = 0; j <= p_curl-2; j++) for (k = 0; k <= p_curl-2-j; k++) ii++; // rotations of curls for (j = 0; j <= p-2; j++) for (k = 0; k <= p-2-j; k++, ii++) for (l = 0; l < 2; l++) shape(ii) = 2 * (grad_recpol(j,0) * grad_recpol2(k,1) - grad_recpol(j,1) * grad_recpol2(k,0)); // shape (ii) = grad u . curl v = 2 (u_x v_y - u_y v_x) ; // div(rec_pol * RT_0) = double divrt0 = 2*(dlami(fav[0],0)*clami(fav[1],0) + dlami(fav[0],1)*clami(fav[1],1)); Vec<2> rt0; for (l = 0; l<2; l++) rt0(l) = lami[fav[0]]*clami(fav[1],l)-lami[fav[1]]*clami(fav[0],l); for (j = 0; j <= p-2; j++, ii++) shape(ii) = divrt0 * lo*rec_pol2[j] + rt0(0)*grad_recpol2(j,0) + rt0(1)*grad_recpol2(j,1); } } template class HDivHighOrderTrig; template class HDivHighOrderTrig; template class HDivHighOrderTrig; template class HDivHighOrderTrig; //------------------------------------------------------------------------ // HDivHighOrderQuad //------------------------------------------------------------------------ template HDivHighOrderQuad :: HDivHighOrderQuad (int aorder) : HDivHighOrderFiniteElement<2>(ET_QUAD) { order_inner = aorder; //order_inner = 0;//geändert for (int i = 0; i < 4; i++) order_edge[i] = aorder; ComputeNDof(); } template void HDivHighOrderQuad :: ComputeNDof() { int i; ndof = 4; for (i = 0; i < 4; i++) ndof += order_edge[i]; ndof += 2*(order_inner*order_inner+order_inner); order = 0; for (i = 0; i < 4; i++) if (order_edge[i] > order) order = order_edge[i]; if (order_inner > order) order = order_inner; order++; } template void HDivHighOrderQuad :: CalcShape (const IntegrationPoint & ip, FlatMatrixFixWidth<2> shape) const { AutoDiff<2> x (ip(0), 0); AutoDiff<2> y (ip(1), 1); AutoDiff<2> lami[4] = {(1-x)*(1-y),x*(1-y),x*y,(1-x)*y}; AutoDiff<2> sigma[4] = {(1-x)+(1-y),x+(1-y),x+y,(1-x)+y}; AutoDiff<2> ext[4] = {1-y, y, 1-x, x}; Mat<4,2> can(0); can(0,1) = -1.; can(1,1) = 1.; can(2,0) = -1.; can(3,0) = 1.; shape = 0.0; int p; int ii = 4; ArrayMem,20> rec_pol(order+2); const EDGE * edges = ElementTopology::GetEdges (ET_QUAD); int is, ie; for (int i = 0; i < 4; i++) { p = order_edge[i]; is = edges[i][0]; ie = edges[i][1]; //(*testout)<<"vnums[is]="< vnums[ie]) { swap (is, ie); fac *= -1;} // (*testout)<<"vnums[is]="<