//--------------------------------------------------------- DMat& NDG3D::Lift3D() //--------------------------------------------------------- { // function [LIFT] = Lift3D(N, r, s, t) // Purpose : Compute 3D surface to volume lift operator used in DG formulation DMat Emat(Np, Nfaces*Nfp),VFace,massFace; DVec faceR,faceS; IVec idr; Index1D JJ; for (int face=1; face<=Nfaces; ++face) { // process face if (1==face) {faceR = r(Fmask(All,1)); faceS = s(Fmask(All,1));} else if (2==face) {faceR = r(Fmask(All,2)); faceS = t(Fmask(All,2));} else if (3==face) {faceR = s(Fmask(All,3)); faceS = t(Fmask(All,3));} else if (4==face) {faceR = s(Fmask(All,4)); faceS = t(Fmask(All,4));} VFace = Vandermonde2D(N, faceR, faceS); massFace = inv(VFace*trans(VFace)); idr = Fmask(All,face); //idc = (face-1)*Nfp+1: face*Nfp; JJ.reset((face-1)*Nfp+1, face*Nfp); //Emat(idr, JJ) = Emat(idr, JJ) + massFace; Emat(idr, JJ) = massFace; // TW: += -> = } // inv(mass matrix)*\I_n (L_i,L_j)_{edge_n} LIFT = V*(trans(V)*Emat); return LIFT; }
//--------------------------------------------------------- DMat& NDG2D::Lift2D() //--------------------------------------------------------- { // function [LIFT] = Lift2D() // Purpose : Compute surface to volume lift term for DG formulation DMat V1D,massEdge1,massEdge2,massEdge3; DVec faceR,faceS; Index1D J1(1,Nfp), J2(Nfp+1,2*Nfp), J3(2*Nfp+1,3*Nfp); DMat Emat(Np, Nfaces*Nfp); // face 1 faceR = r(Fmask(All,1)); V1D = Vandermonde1D(N, faceR); massEdge1 = inv(V1D*trans(V1D)); Emat(Fmask(All,1), J1) = massEdge1; // face 2 faceR = r(Fmask(All,2)); V1D = Vandermonde1D(N, faceR); massEdge2 = inv(V1D*trans(V1D)); Emat(Fmask(All,2), J2) = massEdge2; // face 3 faceS = s(Fmask(All,3)); V1D = Vandermonde1D(N, faceS); massEdge3 = inv(V1D*trans(V1D)); Emat(Fmask(All,3), J3) = massEdge3; // inv(mass matrix)*\I_n (L_i,L_j)_{edge_n} LIFT = V*(trans(V)*Emat); return LIFT; }
//--------------------------------------------------------- void CurvedINS2D::INSLiftDrag2D(double ra) //--------------------------------------------------------- { // function [Cd, Cl, dP, sw, stri] = INSLiftDrag2D(Ux, Uy, PR, ra, nu, time, tstep, Nsteps) // Purpose: compute coefficients of lift, drag and pressure drop at cylinder static FILE* fid; static DVec sw1, sw2; static int Nc=0, stri1=0, stri2=0; if (1 == tstep) { char buf[50]; sprintf(buf, "liftdraghistory%d.dat", N); fid = fopen(buf, "w"); fprintf(fid, "timeCdCldP = [...\n"); // Sample location and weights for pressure drop // Note: the VolkerCylinder test assumes the 2 // sample points (-ra, 0), (ra, 0), are vertices // located on the internal cylinder boundary Sample2D(-ra, 0.0, sw1, stri1); Sample2D( ra, 0.0, sw2, stri2); Nc = mapC.size()/Nfp; } bool bDo=false; if (1==tstep || tstep==Nsteps || !umMOD(tstep,10)) { bDo=true; } else if (time > 3.90 && time < 3.96) { bDo=true; } // catch C_d (3.9362) else if (time > 5.65 && time < 5.73) { bDo=true; } // catch C_l (5.6925) else if (time > 7.999) { bDo=true; } // catch dP (8.0) if (!bDo) return; DVec PRC, nxC, nyC, wv, tv; DMat dUxdx,dUxdy, dUydx,dUydy, MM1D, V1D; DMat dUxdxC,dUxdyC, dUydxC,dUydyC, hforce, vforce, sJC; double dP=0.0, Cd=0.0, Cl=0.0; dP = sw1.inner(PR(All,stri1)) - sw2.inner(PR(All,stri2)); // compute derivatives Grad2D(Ux, dUxdx,dUxdy); dUxdxC=dUxdx(vmapC); dUxdyC=dUxdy(vmapC); Grad2D(Uy, dUydx,dUydy); dUydxC=dUydx(vmapC); dUydyC=dUydy(vmapC); PRC=PR(vmapC); nxC=nx(mapC); nyC=ny(mapC); sJC=sJ(mapC); hforce = -PRC.dm(nxC) + nu*( nxC.dm( 2.0 *dUxdxC) + nyC.dm(dUydxC+dUxdyC) ); vforce = -PRC.dm(nyC) + nu*( nxC.dm(dUydxC+dUxdyC) + nyC.dm( 2.0 *dUydyC) ); hforce.reshape(Nfp, Nc); vforce.reshape(Nfp, Nc); sJC .reshape(Nfp, Nc); // compute weights for integrating (1,hforce) and (1,vforce) V1D = Vandermonde1D(N, r(Fmask(All,1))); MM1D = trans(inv(V1D)) / V1D; wv = MM1D.col_sums(); tv = wv*(sJC.dm(hforce)); Cd=tv.sum(); // Compute drag coefficient tv = wv*(sJC.dm(vforce)); Cl=tv.sum(); // Compute lift coefficient // Output answers for plotting fprintf(fid, "%15.14f %15.14f %15.14f %15.14f;...\n", time, Cd/ra, Cl/ra, dP); fflush(fid); // LOG report if (1==tstep || tstep==Nsteps || !umMOD(tstep,Nreport)) { umLOG(1, "%7d %6.3lf %9.5lf %10.6lf %9.5lf\n", tstep, time, Cd/ra, Cl/ra, dP); } if (tstep==Nsteps) { fprintf(fid, "];\n"); fclose(fid); fid=NULL; } }
//--------------------------------------------------------- void NDG2D::MakeCylinder2D ( const IMat& faces, double ra, double xo, double yo ) //--------------------------------------------------------- { // Function: MakeCylinder2D(faces, ra, xo, yo) // Purpose: Use Gordon-Hall blending with an isoparametric // map to modify a list of faces so they conform // to a cylinder of radius r centered at (xo,yo) int NCurveFaces = faces.num_rows(); IVec vflag(VX.size()); IMat VFlag(EToV.num_rows(),EToV.num_cols()); int n=0,k=0,f=0,v1=0,v2=0; double theta1=0.0,theta2=0.0,x1=0.0,x2=0.0,y1=0.0,y2=0.0; double newx1=0.0,newx2=0.0,newy1=0.0,newy2=0.0; DVec vr, fr, theta, fdx,fdy, vdx, vdy, blend,numer,denom; IVec va,vb,vc, ks, Fm_f, ids; DMat Vface, Vvol; for (n=1; n<=NCurveFaces; ++n) { // move vertices of faces to be curved onto circle k = faces(n,1); f = faces(n,2); v1 = EToV(k, f); v2 = EToV(k, umMOD(f,Nfaces)+1); theta1 = atan2(VY(v1),VX(v1)); theta2 = atan2(VY(v2),VX(v2)); newx1 = xo + ra*cos(theta1); newy1 = yo + ra*sin(theta1); newx2 = xo + ra*cos(theta2); newy2 = yo + ra*sin(theta2); // update mesh vertex locations VX(v1) = newx1; VX(v2) = newx2; VY(v1) = newy1; VY(v2) = newy2; // store modified vertex numbers vflag(v1) = 1; vflag(v2) = 1; } // map modified vertex flag to each element //vflag = vflag(EToV); VFlag.resize(EToV); VFlag.set_map(EToV, vflag); // (map, values) // locate elements with at least one modified vertex //ks = find(sum(vflag,2)>0); ks = find(VFlag.row_sums(), '>', 0); // build coordinates of all the corrected nodes IMat VA=EToV(ks,1), VB=EToV(ks,2), VC=EToV(ks,3); // FIXME: loading 2D mapped data into 1D vectors int Nr=VA.num_rows(); va.copy(Nr,VA.data()); vb.copy(Nr,VB.data()); vc.copy(Nr,VC.data()); // Note: outer products of (Vector,MappedRegion1D) x(All,ks) = 0.5*(-(r+s)*VX(va)+(1.0+r)*VX(vb)+(1.0+s)*VX(vc)); y(All,ks) = 0.5*(-(r+s)*VY(va)+(1.0+r)*VY(vb)+(1.0+s)*VY(vc)); // deform specified faces for (n=1; n<=NCurveFaces; ++n) { k = faces(n,1); f = faces(n,2); // find vertex locations for this face and tangential coordinate if (f==1) { v1=EToV(k,1); v2=EToV(k,2); vr=r; } else if (f==2) { v1=EToV(k,2); v2=EToV(k,3); vr=s; } else if (f==3) { v1=EToV(k,1); v2=EToV(k,3); vr=s; } fr = vr(Fmask(All,f)); x1 = VX(v1); y1 = VY(v1); x2 = VX(v2); y2 = VY(v2); // move vertices at end points of this face to the cylinder theta1 = atan2(y1-yo, x1-xo); theta2 = atan2(y2-yo, x2-xo); // check to make sure they are in the same quadrant if ((theta2 > 0.0) && (theta1 < 0.0)) { theta1 += 2*pi; } if ((theta1 > 0.0) && (theta2 < 0.0)) { theta2 += 2*pi; } // distribute N+1 nodes by arc-length along edge theta = 0.5*theta1*(1.0-fr) + 0.5*theta2*(1.0+fr); // evaluate deformation of coordinates fdx = xo + ra*apply(cos,theta) - x(Fmask(All,f),k); fdy = yo + ra*apply(sin,theta) - y(Fmask(All,f),k); // build 1D Vandermonde matrix for face nodes and volume nodes Vface = Vandermonde1D(N, fr); Vvol = Vandermonde1D(N, vr); // compute unblended volume deformations vdx = Vvol * (Vface|fdx); vdy = Vvol * (Vface|fdy); // blend deformation and increment node coordinates ids = find(abs(1.0-vr), '>', 1e-7); // warp and blend denom = 1.0-vr(ids); if (1==f) { numer = -(r(ids)+s(ids)); } else if (2==f) { numer = (r(ids)+1.0 ); } else if (3==f) { numer = -(r(ids)+s(ids)); } blend = numer.dd(denom); x(ids,k) += (blend.dm(vdx(ids))); y(ids,k) += (blend.dm(vdy(ids))); } // repair other coordinate dependent information Fx = x(Fmask, All); Fy = y(Fmask, All); ::GeometricFactors2D(x,y,Dr,Ds, rx,sx,ry,sy,J); Normals2D(); Fscale = sJ.dd(J(Fmask,All)); }
//--------------------------------------------------------- void NDG2D::BuildPeriodicMaps2D(double xperiod, double yperiod) //--------------------------------------------------------- { // function [] = BuildPeriodicMaps2D(xperiod, yperiod); // Purpose: Connectivity and boundary tables for with all // maps returned in Globals2D assuming periodicity // Find node to node connectivity vmapM.resize(Nfp*Nfaces*K); vmapP.resize(Nfp*Nfaces*K); DVec FxL,FyL,FxR,FyR; DMat x1,x2,y1,y2,D,xF1,yF1,xF2,yF2; IMat idLR; IVec idL,idR,vidL,vidR,fidL,fidR; int k1=0,f1=0, k2=0,f2=0; DVec onesNfp=ones(Nfp); double dx=0.0, dy=0.0, cx1=0.0,cx2=0.0,cy1=0.0,cy2=0.0; double dNfp=(double)Nfp; for (k1=1; k1<=K; ++k1) { for (f1=1; f1<=Nfaces; ++f1) { k2 = EToE(k1,f1); f2 = EToF(k1,f1); vidL = Fmask(All,f1); vidL += (k1-1)*Np; vidR = Fmask(All,f2); vidR += (k2-1)*Np; fidL = Range(1,Nfp) + (f1-1)*Nfp + (k1-1)*Nfp*Nfaces; fidR = Range(1,Nfp) + (f2-1)*Nfp + (k2-1)*Nfp*Nfaces; vmapM(fidL) = vidL; vmapP(fidL) = vidL; FxL=Fx(fidL); FyL=Fy(fidL); FxR=Fx(fidR); FyR=Fy(fidR); x1 = outer(FxL, onesNfp); y1 = outer(FyL, onesNfp); x2 = outer(FxR, onesNfp); y2 = outer(FyR, onesNfp); // Compute distance matrix D = sqr(x1-trans(x2)) + sqr(y1-trans(y2)); idLR = find2D(abs(D), '<', NODETOL); idL=idLR(All,1); idR=idLR(All,2); vmapP(fidL(idL)) = vidR(idR); } } for (k1=1; k1<=K; ++k1) { for (f1=1; f1<=Nfaces; ++f1) { //################################################### xF1=x(Fmask(All,f1), k1); cx1=xF1.sum()/dNfp; yF1=y(Fmask(All,f1), k1); cy1=yF1.sum()/dNfp; //################################################### k2 = EToE(k1,f1); f2 = EToF(k1,f1); if (k2==k1) { for (k2=1; k2<=K; ++k2) { if (k1!=k2) { for (f2=1; f2<=Nfaces; ++f2) { if (EToE(k2,f2)==k2) { //######################################### xF2=x(Fmask(All,f2), k2); cx2=xF2.sum()/dNfp; yF2=y(Fmask(All,f2), k2); cy2=yF2.sum()/dNfp; //######################################### dx = sqrt( SQ(abs(cx1-cx2)-xperiod) + SQ(cy1-cy2)); dy = sqrt( SQ(cx1-cx2) + SQ(abs(cy1-cy2)-yperiod)); if (dx<NODETOL || dy<NODETOL) { EToE(k1,f1) = k2; EToE(k2,f2) = k1; EToF(k1,f1) = f2; EToF(k2,f2) = f1; vidL = Fmask(All,f1); vidL += (k1-1)*Np; vidR = Fmask(All,f2); vidR += (k2-1)*Np; fidL = Range(1,Nfp) + (f1-1)*Nfp + (k1-1)*Nfp*Nfaces; fidR = Range(1,Nfp) + (f2-1)*Nfp + (k2-1)*Nfp*Nfaces; FxL=Fx(fidL); FyL=Fy(fidL); FxR=Fx(fidR); FyR=Fy(fidR); x1 = outer(FxL, onesNfp); y1 = outer(FyL, onesNfp); x2 = outer(FxR, onesNfp); y2 = outer(FyR, onesNfp); // Compute distance matrix if (dx<NODETOL) { D = sqr(abs(x1-trans(x2))-xperiod) + sqr(y1-trans(y2)); } else { D = sqr(x1-trans(x2)) + sqr(abs(y1-trans(y2))-yperiod); } idLR = find2D(abs(D), '<', NODETOL); idL=idLR(All,1); idR=idLR(All,2); //assert(idL.size() == Nfp); if (idL.size() != Nfp) { umERROR("NDG2D::BuildPeriodicMaps2D", "Nfp != idL.size() = %d", idL.size()); } vmapP(fidL(idL)) = vidR(idR); vmapP(fidR(idR)) = vidL(idL); } } } } } } } } // Create default list of boundary nodes mapB = find(vmapP, '=', vmapM); vmapB = vmapM(mapB); }
//--------------------------------------------------------- void NDG3D::PoissonIPDG3D(CSd& spOP, CSd& spMM) //--------------------------------------------------------- { // function [OP,MM] = PoissonIPDG3D() // // Purpose: Set up the discrete Poisson matrix directly // using LDG. The operator is set up in the weak form DVec faceR("faceR"), faceS("faceS"), faceT("faceT"); DMat V2D; IVec Fm("Fm"); IVec i1_Nfp = Range(1,Nfp); double opti1=0.0, opti2=0.0; int i=0; umLOG(1, "\n ==> {OP,MM} assembly: "); opti1 = timer.read(); // time assembly // build local face matrices DMat massEdge[5]; // = zeros(Np,Np,Nfaces); for (i=1; i<=Nfaces; ++i) { massEdge[i].resize(Np,Np); } // face mass matrix 1 Fm = Fmask(All,1); faceR=r(Fm); faceS=s(Fm); V2D = Vandermonde2D(N, faceR, faceS); massEdge[1](Fm,Fm) = inv(V2D*trans(V2D)); // face mass matrix 2 Fm = Fmask(All,2); faceR = r(Fm); faceT = t(Fm); V2D = Vandermonde2D(N, faceR, faceT); massEdge[2](Fm,Fm) = inv(V2D*trans(V2D)); // face mass matrix 3 Fm = Fmask(All,3); faceS = s(Fm); faceT = t(Fm); V2D = Vandermonde2D(N, faceS, faceT); massEdge[3](Fm,Fm) = inv(V2D*trans(V2D)); // face mass matrix 4 Fm = Fmask(All,4); faceS = s(Fm); faceT = t(Fm); V2D = Vandermonde2D(N, faceS, faceT); massEdge[4](Fm,Fm) = inv(V2D*trans(V2D)); // build local volume mass matrix MassMatrix = trans(invV)*invV; DMat Dx("Dx"),Dy("Dy"),Dz("Dz"), Dx2("Dx2"),Dy2("Dy2"),Dz2("Dz2"); DMat Dn1("Dn1"),Dn2("Dn2"), mmE("mmE"), OP11("OP11"), OP12("OP12"); DMat mmE_All_Fm1, mmE_Fm1_Fm1, Dn2_Fm2_All; IMat rows1,cols1,rows2,cols2; int k1=0,f1=0,k2=0,f2=0,id=0; Index1D entries, entriesMM, idsM; IVec fidM,vidM,Fm1,vidP,Fm2; double lnx=0.0,lny=0.0,lnz=0.0,lsJ=0.0,hinv=0.0,gtau=0.0; double N1N1 = double((N+1)*(N+1)); int NpNp = Np*Np; // build DG derivative matrices int max_OP = (K*Np*Np*(1+Nfaces)); int max_MM = (K*Np*Np); // "OP" triplets (i,j,x), extracted to {Ai,Aj,Ax} IVec OPi(max_OP), OPj(max_OP), Ai,Aj; DVec OPx(max_OP), Ax; // "MM" triplets (i,j,x) IVec MMi(max_MM), MMj(max_MM); DVec MMx(max_MM); IVec OnesNp = Ones(Np); // global node numbering entries.reset(1,NpNp); entriesMM.reset(1,NpNp); OP12.resize(Np,Np); for (k1=1; k1<=K; ++k1) { if (! (k1%250)) { umLOG(1, "%d, ",k1); } rows1 = outer( Range((k1-1)*Np+1,k1*Np), OnesNp ); cols1 = trans(rows1); // Build local operators Dx = rx(1,k1)*Dr + sx(1,k1)*Ds + tx(1,k1)*Dt; Dy = ry(1,k1)*Dr + sy(1,k1)*Ds + ty(1,k1)*Dt; Dz = rz(1,k1)*Dr + sz(1,k1)*Ds + tz(1,k1)*Dt; OP11 = J(1,k1)*(trans(Dx)*MassMatrix*Dx + trans(Dy)*MassMatrix*Dy + trans(Dz)*MassMatrix*Dz); // Build element-to-element parts of operator for (f1=1; f1<=Nfaces; ++f1) { k2 = EToE(k1,f1); f2 = EToF(k1,f1); rows2 = outer( Range((k2-1)*Np+1, k2*Np), OnesNp ); cols2 = trans(rows2); fidM = (k1-1)*Nfp*Nfaces + (f1-1)*Nfp + i1_Nfp; vidM = vmapM(fidM); Fm1 = mod(vidM-1,Np)+1; vidP = vmapP(fidM); Fm2 = mod(vidP-1,Np)+1; id = 1+(f1-1)*Nfp + (k1-1)*Nfp*Nfaces; lnx = nx(id); lny = ny(id); lnz = nz(id); lsJ = sJ(id); hinv = std::max(Fscale(id), Fscale(1+(f2-1)*Nfp, k2)); Dx2 = rx(1,k2)*Dr + sx(1,k2)*Ds + tx(1,k2)*Dt; Dy2 = ry(1,k2)*Dr + sy(1,k2)*Ds + ty(1,k2)*Dt; Dz2 = rz(1,k2)*Dr + sz(1,k2)*Ds + tz(1,k2)*Dt; Dn1 = lnx*Dx + lny*Dy + lnz*Dz; Dn2 = lnx*Dx2 + lny*Dy2 + lnz*Dz2; mmE = lsJ*massEdge[f1]; gtau = 2.0 * N1N1 * hinv; // set penalty scaling if (EToE(k1,f1)==k1) { OP11 += ( gtau*mmE - mmE*Dn1 - trans(Dn1)*mmE ); // ok } else { // interior face variational terms OP11 += 0.5*( gtau*mmE - mmE*Dn1 - trans(Dn1)*mmE ); // extract mapped regions: mmE_All_Fm1 = mmE(All,Fm1); mmE_Fm1_Fm1 = mmE(Fm1,Fm1); Dn2_Fm2_All = Dn2(Fm2,All); OP12 = 0.0; // reset to zero OP12(All,Fm2) = -0.5*( gtau*mmE_All_Fm1 ); OP12(Fm1,All) -= 0.5*( mmE_Fm1_Fm1*Dn2_Fm2_All ); //OP12(All,Fm2) -= 0.5*(-trans(Dn1)*mmE_All_Fm1 ); OP12(All,Fm2) += 0.5*( trans(Dn1)*mmE_All_Fm1 ); // load this set of triplets #if (1) OPi(entries)=rows1; OPj(entries)=cols2, OPx(entries)=OP12; entries += (NpNp); #else //########################################################### // load only the lower triangle (after droptol test?) sk=0; start=entries(1); for (int i=1; i<=NpNp; ++i) { eid = start+i; id=entries(eid); rid=rows1(i); cid=cols2(i); if (rows1(rid) >= cid) { // take lower triangle if ( fabs(OP12(id)) > 1e-15) { // drop small entries ++sk; OPi(id)=rid; OPj(id)=cid, OPx(id)=OP12(id); } } } entries += sk; //########################################################### #endif } } OPi(entries )=rows1; OPj(entries )=cols1, OPx(entries )=OP11; MMi(entriesMM)=rows1; MMj(entriesMM)=cols1; MMx(entriesMM)=J(1,k1)*MassMatrix; entries += (NpNp); entriesMM += (NpNp); } umLOG(1, "\n ==> {OP,MM} to sparse\n"); entries.reset(1, entries.hi()-Np*Np); // Extract triplets from the large buffers. Note: this // requires copying each array, and since these arrays // can be HUGE(!), we force immediate deallocation: Ai=OPi(entries); OPi.Free(); Aj=OPj(entries); OPj.Free(); Ax=OPx(entries); OPx.Free(); umLOG(1, " ==> triplets ready (OP) nnz = %10d\n", entries.hi()); // adjust triplet indices for 0-based sparse operators Ai -= 1; Aj -= 1; MMi -= 1; MMj -= 1; int npk=Np*K; #if defined(NDG_USE_CHOLMOD) || defined(NDG_New_CHOLINC) // load only the lower triangle tril(OP) free args? spOP.load(npk,npk, Ai,Aj,Ax, sp_LT, false,1e-15, true); // {LT, false} -> TriL #else // select {upper,lower,both} triangles //spOP.load(npk,npk, Ai,Aj,Ax, sp_LT, true,1e-15,true); // LT -> enforce symmetry //spOP.load(npk,npk, Ai,Aj,Ax, sp_All,true,1e-15,true); // All-> includes "noise" //spOP.load(npk,npk, Ai,Aj,Ax, sp_UT, false,1e-15,true); // UT -> triu(OP) only #endif Ai.Free(); Aj.Free(); Ax.Free(); umLOG(1, " ==> triplets ready (MM) nnz = %10d\n", entriesMM.hi()); //------------------------------------------------------- // The mass matrix operator will NOT be factorised, // Load ALL elements (both upper and lower triangles): //------------------------------------------------------- spMM.load(npk,npk, MMi,MMj,MMx, sp_All,false,1.00e-15,true); MMi.Free(); MMj.Free(); MMx.Free(); opti2 = timer.read(); // time assembly umLOG(1, " ==> {OP,MM} converted to csc. (%g secs)\n", opti2-opti1); }
//--------------------------------------------------------- DVec& NDG2D::PoissonIPDGbc2D (DVec& ubc, //[in] DVec& qbc //[in] ) //--------------------------------------------------------- { // function [OP] = PoissonIPDGbc2D() // Purpose: Set up the discrete Poisson matrix directly // using LDG. The operator is set up in the weak form // build DG derivative matrices int max_OP = (K*Np*Np*(1+Nfaces)); // initialize parameters DVec faceR("faceR"), faceS("faceS"); DMat V1D("V1D"), Dx("Dx"),Dy("Dy"), Dn1("Dn1"), mmE_Fm1("mmE(:,Fm1)"); IVec Fm("Fm"), Fm1("Fm1"), fidM("fidM"); double lnx=0.0,lny=0.0,lsJ=0.0,hinv=0.0,gtau=0.0; int i=0,k1=0,f1=0,id=0; IVec i1_Nfp = Range(1,Nfp); double N1N1 = double((N+1)*(N+1)); // build local face matrices DMat massEdge[4]; // = zeros(Np,Np,Nfaces); for (i=1; i<=Nfaces; ++i) { massEdge[i].resize(Np,Np); } // face mass matrix 1 Fm = Fmask(All,1); faceR = r(Fm); V1D = Vandermonde1D(N, faceR); massEdge[1](Fm,Fm) = inv(V1D*trans(V1D)); // face mass matrix 2 Fm = Fmask(All,2); faceR = r(Fm); V1D = Vandermonde1D(N, faceR); massEdge[2](Fm,Fm) = inv(V1D*trans(V1D)); // face mass matrix 3 Fm = Fmask(All,3); faceS = s(Fm); V1D = Vandermonde1D(N, faceS); massEdge[3](Fm,Fm) = inv(V1D*trans(V1D)); // build DG right hand side DVec* pBC = new DVec(Np*K, "bc", OBJ_temp); DVec& bc = (*pBC); // reference, for syntax //////////////////////////////////////////////////////////////// umMSG(1, "\n ==> {OP} assembly [bc]: "); for (k1=1; k1<=K; ++k1) { if (! (k1%100)) { umMSG(1, "%d, ",k1); } // rows1 = outer(Range((k1-1)*Np+1,k1*Np), Ones(NGauss)); // Build element-to-element parts of operator for (f1=1; f1<=Nfaces; ++f1) { if (BCType(k1,f1)) { ////////////////////////added by Kevin /////////////////////////////// Fm1 = Fmask(All,f1); fidM = (k1-1)*Nfp*Nfaces + (f1-1)*Nfp + i1_Nfp; id = 1+(f1-1)*Nfp + (k1-1)*Nfp*Nfaces; lnx = nx(id); lny = ny(id); lsJ = sJ(id); hinv = Fscale(id); Dx = rx(1,k1)*Dr + sx(1,k1)*Ds; Dy = ry(1,k1)*Dr + sy(1,k1)*Ds; Dn1 = lnx*Dx + lny*Dy; //mmE = lsJ*massEdge(:,:,f1); //bc(All,k1) += (gtau*mmE(All,Fm1) - Dn1'*mmE(All,Fm1))*ubc(fidM); mmE_Fm1 = massEdge[f1](All,Fm1); mmE_Fm1 *= lsJ; gtau = 10*N1N1*hinv; // set penalty scaling //bc(All,k1) += (gtau*mmE_Fm1 - trans(Dn1)*mmE_Fm1) * ubc(fidM); switch(BCType(k1,f1)){ case BC_Dirichlet: bc(Np*(k1-1)+Range(1,Np)) += (gtau*mmE_Fm1 - trans(Dn1)*mmE_Fm1)*ubc(fidM); break; case BC_Neuman: bc(Np*(k1-1)+Range(1,Np)) += mmE_Fm1*qbc(fidM); break; default: std::cout<<"warning: boundary condition is incorrect"<<std::endl; } } } } return bc; }
void NDG2D::PoissonIPDGbc2D( CSd& spOP //[out] sparse operator ) { // function [OP] = PoissonIPDGbc2D() // Purpose: Set up the discrete Poisson matrix directly // using LDG. The operator is set up in the weak form // build DG derivative matrices int max_OP = (K*Np*Np*(1+Nfaces)); //initialize parameters DVec faceR("faceR"), faceS("faceS"); IVec Fm("Fm"), Fm1("Fm1"), fidM("fidM"); DMat V1D("V1D"); int i=0; // build local face matrices DMat massEdge[4]; // = zeros(Np,Np,Nfaces); for (i=1; i<=Nfaces; ++i) { massEdge[i].resize(Np,Np); } // face mass matrix 1 Fm = Fmask(All,1); faceR = r(Fm); V1D = Vandermonde1D(N, faceR); massEdge[1](Fm,Fm) = inv(V1D*trans(V1D)); // face mass matrix 2 Fm = Fmask(All,2); faceR = r(Fm); V1D = Vandermonde1D(N, faceR); massEdge[2](Fm,Fm) = inv(V1D*trans(V1D)); // face mass matrix 3 Fm = Fmask(All,3); faceS = s(Fm); V1D = Vandermonde1D(N, faceS); massEdge[3](Fm,Fm) = inv(V1D*trans(V1D)); //continue initialize parameters DMat Dx("Dx"),Dy("Dy"), Dn1("Dn1"), mmE_Fm1("mmE(:,Fm1)"); double lnx=0.0,lny=0.0,lsJ=0.0,hinv=0.0,gtau=0.0; int k1=0,f1=0,id=0; IVec i1_Nfp = Range(1,Nfp); double N1N1 = double((N+1)*(N+1)); // "OP" triplets (i,j,x), extracted to {Ai,Aj,Ax} IVec OPi(max_OP),OPj(max_OP), Ai,Aj; DVec OPx(max_OP), Ax; IMat rows1, cols1; Index1D entries; DMat OP11(Np,Nfp, 0.0); // global node numbering entries.reset(1,Np*Nfp); cols1 = outer(Ones(Np), Range(1,Nfp)); umMSG(1, "\n ==> {OP} assembly [bc]: "); for (k1=1; k1<=K; ++k1) { if (! (k1%100)) { umMSG(1, "%d, ",k1); } rows1 = outer(Range((k1-1)*Np+1,k1*Np), Ones(Nfp)); // Build element-to-element parts of operator for (f1=1; f1<=Nfaces; ++f1) { if (BCType(k1,f1)) { ////////////////////////added by Kevin /////////////////////////////// Fm1 = Fmask(All,f1); fidM = (k1-1)*Nfp*Nfaces + (f1-1)*Nfp + i1_Nfp; id = 1+(f1-1)*Nfp + (k1-1)*Nfp*Nfaces; lnx = nx(id); lny = ny(id); lsJ = sJ(id); hinv = Fscale(id); Dx = rx(1,k1)*Dr + sx(1,k1)*Ds; Dy = ry(1,k1)*Dr + sy(1,k1)*Ds; Dn1 = lnx*Dx + lny*Dy; //mmE = lsJ*massEdge(:,:,f1); //bc(All,k1) += (gtau*mmE(All,Fm1) - Dn1'*mmE(All,Fm1))*ubc(fidM); mmE_Fm1 = massEdge[f1](All,Fm1); mmE_Fm1 *= lsJ; gtau = 10*N1N1*hinv; // set penalty scaling //bc(All,k1) += (gtau*mmE_Fm1 - trans(Dn1)*mmE_Fm1) * ubc(fidM); switch(BCType(k1,f1)){ case BC_Dirichlet: OP11 = gtau*mmE_Fm1 - trans(Dn1)*mmE_Fm1; break; case BC_Neuman: OP11 = mmE_Fm1; break; default: std::cout<<"warning: boundary condition is incorrect"<<std::endl; } OPi(entries)=rows1; OPj(entries)=cols1; OPx(entries)=OP11; entries += (Np*Nfp); } cols1 += Nfp; } } umMSG(1, "\n ==> {OPbc} to sparse\n"); entries.reset(1, entries.hi()-(Np*Nfp)); // extract triplets from large buffers Ai=OPi(entries); Aj=OPj(entries); Ax=OPx(entries); // These arrays can be HUGE, so force deallocation OPi.Free(); OPj.Free(); OPx.Free(); // return 0-based sparse result Ai -= 1; Aj -= 1; //------------------------------------------------------- // This operator is not symmetric, and will NOT be // factorised, only used to create reference RHS's: // // refrhsbcPR = spOP1 * bcPR; // refrhsbcUx = spOP2 * bcUx; // refrhsbcUy = spOP2 * bcUy; // // Load ALL elements (both upper and lower triangles): //------------------------------------------------------- spOP.load(Np*K, Nfp*Nfaces*K, Ai,Aj,Ax, sp_All,false, 1e-15,true); Ai.Free(); Aj.Free(); Ax.Free(); umMSG(1, " ==> {OPbc} ready.\n"); #if (1) // check on original estimates for nnx umMSG(1, " ==> max_OP: %12d\n", max_OP); umMSG(1, " ==> nnz_OP: %12d\n", entries.hi()); #endif }
startUp1d::startUp1d(int N,int K) { NODETOL=1e-10; r = JacobiGL(0,0,N); Np = N+1; Nfp = 1; Nfaces =2; V = Vandermonde1D(N,r); Dr = Dmatrix1D(N,r,V); invV = V.inverse(); MatrixXd Emat(Np,Nfaces*Nfp); Emat.setZero(Np,2); Emat(0,0)=1.0; Emat(Np-1,1)=1.0; LIFT = V*V.transpose()*Emat; EToV.setZero(K,2); VX.setZero(K+1); EToV = meshGen(0.0,1.0,K,Nv,VX); ArrayXi va,vb; va = EToV.col(0); vb=EToV.col(1); VectorXd v1(K),v2(K); { int temp=0; for(int i=0; i<K; i++) { temp = va(i); v1(i)= VX(temp-1); temp = vb(i); v2(i)= VX(temp-1); } } VectorXd temp1; temp1.setOnes(N+1,1); x =temp1*v1.transpose()+ 0.5*((r.array()+1).matrix())*(v2-v1).transpose(); J = Dr*x; rx = 1.0/J.array(); Fmask.setZero(2); Fmask(0)=0; Fmask(1)=Np-1; std::cout<<"Fx"<<Fmask<<"\n"; Fx.setZero(2,K); Fx.row(0)=x.row(0); Fx.row(1)=x.row(Np-1); std::cout<<"Fx"<<Fx<<"\n"; nx=Normals1D(Nfp,Nfaces,K); Fscale.setZero(2,K); Fscale.row(0)=J.row(0); Fscale.row(1)=J.row(Np-1); Fscale = 1.0/Fscale.array(); EToEF = Connect1DEToE(EToV); std::cout<<"Fscale "<<"\n"<<Fscale<<"\n"; std::cout<<"Fscale "<<"\n"<<EToEF<<"\n"; }