// This is a user-supplied routine that sets the the boundary conditions // void SetBndValues_Unst(const mesh& Mesh, dTensor3* q, dTensor3* aux) { int meqn = q->getsize(2); int kmax = q->getsize(3); int maux = aux->getsize(2); int NumElems = Mesh.get_NumElems(); int NumPhysElems = Mesh.get_NumPhysElems(); int NumGhostElems = Mesh.get_NumGhostElems(); int NumNodes = Mesh.get_NumNodes(); int NumPhysNodes = Mesh.get_NumPhysNodes(); int NumEdges = Mesh.get_NumEdges(); // ---------------------------------------- // Loop over each ghost cell element and // place the correct information into // these elements // ---------------------------------------- for (int i=1; i<=NumGhostElems; i++) { int j = Mesh.get_ghost_link(i); for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { q->set(i+NumPhysElems,m,k, 0.0 ); } } }
void ConSoln_Unst(const mesh& Mesh, const dTensor3& aux, const dTensor3& q, double t, string outputdir) { const int NumElems = q.getsize(1); const int meqn = q.getsize(2); const int kmax = q.getsize(3); const int maux = aux.getsize(2); const string fname1 = outputdir+"/conservation.dat"; ofstream write_file1,write_file2; dTensor1 qsum(meqn); dTensor1 res_sum(meqn); const int NumPhysElems = Mesh.get_NumPhysElems(); if (t==0) { write_file1.open(fname1.c_str(), ofstream::out); } else { write_file1.open(fname1.c_str(), ofstream::app); } // ----------------- // CONSERVATION // ----------------- if (dogParams.get_mcapa()<1) // without capacity function { for (int m=1; m<=meqn; m++) { qsum.set(m,0.0); for (int i=1; i<=NumPhysElems; i++) { double dtmp = Mesh.get_area_prim(i); double qtmp = q.get(i,m,1); qsum.set(m, (qsum.get(m) + dtmp*qtmp) ); } } } write_file1 << setprecision(16); write_file1 << setw(24) << scientific << t << " "; for (int m=1; m<=meqn; m++) { if (fabs(qsum.get(m)) < 1.0e-99) {qsum.set(m, 0.0);} write_file1 << setw(24) << scientific << qsum.get(m) << " "; } write_file1 << endl; write_file1.close(); }
double GetCFL_Unst(double dt, const mesh& Mesh, const dTensor3& aux, const dTensor1& smax) { double cfl=-100.0; int NumPhysElems = Mesh.get_NumPhysElems(); int NumEdges = Mesh.get_NumEdges(); for (int i=1; i<=NumPhysElems; i++) { double Area = Mesh.get_area_prim(i); int edge1 = Mesh.get_tedge(i,1); int edge2 = Mesh.get_tedge(i,2); int edge3 = Mesh.get_tedge(i,3); double tmp = Max(Max(smax.get(edge1),smax.get(edge2)), smax.get(edge3)); cfl = Max(0.5*dt*tmp/Area, cfl); } return cfl; }
// This is a user-supplied routine that sets the the boundary conditions // // The default routine for the 4D Vlasov code is to apply zero boundary // conditions in configuration space. This routine is identical to the one // found in the unst branch of the 2D DoGPack code, and *should* be setting // periodic boundary conditions. // void SetBndValues_Unst(const mesh& Mesh, dTensor3* q, dTensor3* aux) { // problem information (If this were to be pulled from DogParams, these // numbers would NOT be correct! The reason is that each quadrature point // was actually saved as a separate "equation") const int meqn = q->getsize(2); const int kmax = q->getsize(3); const int maux = aux->getsize(2); // Mesh information const int NumElems = Mesh.get_NumElems(); const int NumPhysElems = Mesh.get_NumPhysElems(); const int NumGhostElems = Mesh.get_NumGhostElems(); const int NumNodes = Mesh.get_NumNodes(); const int NumPhysNodes = Mesh.get_NumPhysNodes(); const int NumEdges = Mesh.get_NumEdges(); // ---------------------------------------- // Loop over each ghost cell element and // place the correct information into // these elements // ---------------------------------------- for (int i=1; i<=NumGhostElems; i++) { int j = Mesh.get_ghost_link(i); for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { q->set(i+NumPhysElems, m, k, q->get(j, m, k) ); } } }
// // Output basic mesh information to screen // void ScreenOutput(const mesh& Mesh) { // Compute mesh quality parameters double totalarea = Mesh.get_area_prim(1); double maxarea = Mesh.get_area_prim(1); double minarea = Mesh.get_area_prim(1); for (int i=2; i<=Mesh.get_NumPhysElems(); i++) { double tmp = Mesh.get_area_prim(i); totalarea = totalarea + tmp; if (tmp < minarea) { minarea = tmp; } if (tmp > maxarea) { maxarea = tmp; } } double minAngle = 180.0; for (int i=1; i<=Mesh.get_NumPhysElems(); i++) { const int i1 = Mesh.get_tnode(i,1); const int i2 = Mesh.get_tnode(i,2); const int i3 = Mesh.get_tnode(i,3); point v12, v23, v31; v12.x = Mesh.get_node(i2,1) - Mesh.get_node(i1,1); v12.y = Mesh.get_node(i2,2) - Mesh.get_node(i1,2); v23.x = Mesh.get_node(i3,1) - Mesh.get_node(i2,1); v23.y = Mesh.get_node(i3,2) - Mesh.get_node(i2,2); v31.x = Mesh.get_node(i1,1) - Mesh.get_node(i3,1); v31.y = Mesh.get_node(i1,2) - Mesh.get_node(i3,2); double angle1 = acos((v12.x*-v31.x+v12.y*-v31.y) /(sqrt(v12.x*v12.x+v12.y*v12.y)*sqrt(v31.x*v31.x+v31.y*v31.y))); double angle2 = acos((v23.x*-v12.x+v23.y*-v12.y) /(sqrt(v23.x*v23.x+v23.y*v23.y)*sqrt(v12.x*v12.x+v12.y*v12.y))); double angle3 = acos((v31.x*-v23.x+v31.y*-v23.y) /(sqrt(v31.x*v31.x+v31.y*v31.y)*sqrt(v23.x*v23.x+v23.y*v23.y))); if ((angle1*180/pi) < minAngle) { minAngle = angle1*180/pi; } if ((angle2*180/pi) < minAngle) { minAngle = angle2*180/pi; } if ((angle3*180/pi) < minAngle) { minAngle = angle3*180/pi; } } // Output summary of results to screen printf("\n"); printf(" SUMMARY OF RESULTS:\n"); printf(" -------------------\n"); printf(" Number of Elements: %8i\n",Mesh.get_NumElems()); printf(" Number of Physical Elements: %8i\n",Mesh.get_NumPhysElems()); printf(" Number of Ghost Elements: %8i\n",Mesh.get_NumGhostElems()); printf(" Number of Nodes: %8i\n",Mesh.get_NumNodes()); printf(" Number of Physical Nodes: %8i\n",Mesh.get_NumPhysNodes()); printf(" Number of Boundary Nodes: %8i\n",Mesh.get_NumBndNodes()); printf(" Number of Edges: %8i\n",Mesh.get_NumEdges()); printf(" Number of Boundary Edges: %8i\n",Mesh.get_NumBndEdges()); printf("\n"); printf(" Total Area Covered: %24.16e\n",totalarea); printf(" Area Ratio: small/large: %24.16e\n",minarea/maxarea); printf(" Angle Ratio: minAngle/60: %24.16e\n",minAngle/60.0); printf("\n"); }
void ComputeError(const int space_order, const mesh& Mesh, const dTensor1& phi, const dTensor2& E1, const dTensor2& E2, void (*PhiFunc)(const dTensor2& xpts,dTensor2& phi_ex), void (*EfieldFunc)(const dTensor2& xpts,dTensor2& Efield_ex)) { // Potential const int NumPhysNodes = phi.getsize();//Mesh.get_NumPhysNodes(); dTensor2 xpts(NumPhysNodes,2); dTensor2 phi_ex(NumPhysNodes,1); double phi_err; double phi_rel; switch(space_order) { case 2: for (int i=1; i<=NumPhysNodes; i++) { xpts.set(i,1, Mesh.get_node(i,1) ); xpts.set(i,2, Mesh.get_node(i,2) ); } PhiFunc(xpts,phi_ex); phi_err = 0.0; phi_rel = 0.0; for (int i=1; i<=NumPhysNodes; i++) { phi_rel = phi_rel + pow(phi_ex.get(i,1),2); phi_err = phi_err + pow(phi_ex.get(i,1)-phi.get(i),2); } phi_err = sqrt(phi_err/phi_rel); break; case 3: for (int i=1; i<=NumPhysNodes; i++) { xpts.set(i,1, Mesh.get_sub_node(i,1) ); xpts.set(i,2, Mesh.get_sub_node(i,2) ); } PhiFunc(xpts,phi_ex); phi_err = 0.0; phi_rel = 0.0; for (int i=1; i<=NumPhysNodes; i++) { phi_rel = phi_rel + pow(phi_ex.get(i,1),2); phi_err = phi_err + pow(phi_ex.get(i,1)-phi.get(i),2); } phi_err = sqrt(phi_err/phi_rel); break; } // Electric field components void L2Project_Unst(const int istart, const int iend, const int QuadOrder, const int BasisOrder_fout, const mesh& Mesh, dTensor3* fout, void (*Func)(const dTensor2&,dTensor2&)); const int NumElems = Mesh.get_NumElems(); const int NumPhysElems = Mesh.get_NumPhysElems(); const int kmax = E1.getsize(2); dTensor3 Efield_ex(NumElems,2,kmax); L2Project_Unst(1,NumElems,space_order,space_order, Mesh,&Efield_ex,EfieldFunc); double E1_err = 0.0; double E1_rel = 0.0; double E2_err = 0.0; double E2_rel = 0.0; for (int i=1; i<=NumPhysElems; i++) { double Area = Mesh.get_area_prim(i); double tmp1 = 0.0; double tmp2 = 0.0; double tmp1_rel = 0.0; double tmp2_rel = 0.0; for (int k=1; k<=kmax; k++) { tmp1 = tmp1 + pow((E1.get(i,k)-Efield_ex.get(i,1,k)),2); tmp2 = tmp2 + pow((E2.get(i,k)-Efield_ex.get(i,2,k)),2); tmp1_rel = tmp1_rel + pow((Efield_ex.get(i,1,k)),2); tmp2_rel = tmp2_rel + pow((Efield_ex.get(i,2,k)),2); } E1_err = E1_err + Area*tmp1; E2_err = E2_err + Area*tmp2; E1_rel = E1_rel + Area*tmp1_rel; E2_rel = E2_rel + Area*tmp2_rel; } E1_err = sqrt(E1_err/E1_rel); E2_err = sqrt(E2_err/E2_rel); // Summary printf(" |----------------------------\n"); printf(" | Errors:\n"); printf(" |----------------------------\n"); printf(" | phi_err = %e\n",phi_err); printf(" | E1_err = %e\n",E1_err); printf(" | E2_err = %e\n",E2_err); printf(" |----------------------------\n"); printf("\n"); }
// Save the time, and print the L2-norm of the electric field // // TODO - is this the spot where we'd like to print moments? Do we need // moments after each time step or for each frame? // void PrintElectricField( const double t, const mesh& Mesh, const dTensorBC5& q, const dTensor2& E1, const dTensor2& E2 ) { const int mx = q.getsize(1); const int my = q.getsize(2); const int NumElems = q.getsize(3); const int meqn = q.getsize(4); const int kmax = q.getsize(5); const int mbc = q.getmbc(); const int NumPhysElems = Mesh.get_NumPhysElems(); string fname1 = string(dogParams.get_outputdir())+"/conservation.dat"; string fname2 = string(dogParams.get_outputdir())+"/Efield.dat"; ofstream write_file1,write_file2; if( fabs(t) < EPSILON ) { write_file1.open(fname1.c_str(), ofstream::out); write_file2.open(fname2.c_str(), ofstream::out); } else { write_file1.open(fname1.c_str(), ofstream::app); write_file2.open(fname2.c_str(), ofstream::app); } // ----------------- // CONSERVATION // ----------------- dTensor1 qsum(meqn); if (dogParams.get_mcapa()<1) // without capacity function { for (int m=1; m<=meqn; m++) { qsum.set(m,0.0); for (int i=1; i<=mx; i++) for (int j=1; j<=my; j++) for (int n=1; n<=NumPhysElems; n++) { qsum.set(m, qsum.get(m) + Mesh.get_area_prim(n)*dogParamsCart2.get_prim_vol()*q.get(i,j,n,m,1) ); } } } write_file1 << setprecision(16); write_file1 << setw(24) << scientific << t << " "; for (int m=1; m<=meqn; m++) { if (fabs(qsum.get(m)) < 1.0e-99) { qsum.set(m, 0.0); } write_file1 << setw(24) << scientific << qsum.get(m) << " "; } write_file1 << endl; write_file1.close(); /////////////////////////////////////////////////////////////////////////// // Conserved Vlasov-Poisson Quantities // // ||f||_1, ||f||_2, Energy, Entropy // /////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // Electric Field const int mcons = 4; // TODO - do we want to compute the extra moments here or later? ////dTensorBC4 ConsData2d(mx, my, mcons, kmax,mbc); ////const int space_order = dogParams.get_space_order(); ////L2Project(1, mx, 1, my, space_order, space_order, space_order, //// space_order, &q, &aux, &ConsData2d, &ConservedFunc ); // electric field, entropy and energy dTensor1 ConsData(mcons); ConsData.setall(0.); // Compute the integral of all the 2d quantities: // for (int m=1; m<=mcons; m++) // { // for (int i=1; i<=mx; i++) // for (int j=1; j<=my; j++) // { // ConsData.set(m, ConsData.get(m) + dx*dy*ConsData2d.get(i,j,m,1) ); // } // } // Compute the integral of all the 1d quanties: // \int E^2 \ dx double Esqd = 0.0; for(int n=1; n <= NumElems; n++ ) for(int k=1; k <= E1.getsize(2); k++ ) { Esqd += Mesh.get_area_prim(n) * ( pow( E1.get(n,k), 2 ) + pow(E2.get(n,k), 2 ) ); } //printf("Esqd = %f\n", Esqd ); //exit(1); // Add in E to the total Energy: // ConsData.set(3, ConsData.get(3) + 0.5 * E2 ); ConsData.set(3, 0. ); // print time: write_file2 << setprecision(16); write_file2 << setw(24) << scientific << t << " "; // print ||E||_2 first: write_file2 << setw(24) << scientific << sqrt( Esqd ) << " "; // print all the other conserved quantities: for (int m=1; m<=mcons; m++) { write_file2 << setw(24) << scientific << ConsData.get(m) << " "; } write_file2 << endl; write_file2.close(); }
// Right-hand side for hyperbolic PDE in divergence form // // q_t = -( f(q,x,y,t)_x + g(q,x,y,t)_y ) + Psi(q,x,y,t) // void LaxWendroff_Unst(double dt, const mesh& Mesh, const edge_data_Unst& EdgeData, dTensor3& aux, // SetBndValues modifies ghost cells dTensor3& q, // SetBndValues modifies ghost cells dTensor3& Lstar, dTensor1& smax) { const int NumElems = Mesh.get_NumElems(); const int NumPhysElems = Mesh.get_NumPhysElems(); const int NumEdges = Mesh.get_NumEdges(); const int meqn = q.getsize(2); const int kmax = q.getsize(3); const int maux = aux.getsize(2); const int space_order = dogParams.get_space_order(); dTensor3 EdgeFluxIntegral(NumElems,meqn,kmax); dTensor3 ElemFluxIntegral(NumElems,meqn,kmax); dTensor3 Psi(NumElems,meqn,kmax); // --------------------------------------------------------- // Boundary Conditions SetBndValues_Unst(Mesh, &q, &aux); // --------------------------------------------------------- // --------------------------------------------------------------------- // // Part 0: Compute the Lax-Wendroff "flux" function: // // Here, we include the extra information about time derivatives. // --------------------------------------------------------------------- // dTensor3 F(NumElems, meqn, kmax ); F.setall(0.); dTensor3 G(NumElems, meqn, kmax ); G.setall(0.); L2ProjectLxW_Unst( dogParams.get_time_order(), 1.0, 0.5*dt, dt*dt/6.0, 1, NumElems, space_order, space_order, space_order, space_order, Mesh, &q, &aux, &F, &G, &FluxFunc, &DFluxFunc, &D2FluxFunc ); // --------------------------------------------------------- // Part I: compute source term // --------------------------------------------------------- if ( dogParams.get_source_term()>0 ) { // eprintf("error: have not implemented source term for LxW solver."); printf("Source term has not been implemented for LxW solver. Terminating program."); exit(1); } Lstar.setall(0.); // --------------------------------------------------------- // --------------------------------------------------------- // Part II: compute flux integral on element edges // --------------------------------------------------------- // Loop over all interior edges EdgeFluxIntegral.setall(0.); ElemFluxIntegral.setall(0.); #pragma omp parallel for // Loop over all interior edges for (int i=1; i<=NumEdges; i++) { // Edge coordinates double x1 = Mesh.get_edge(i,1); double y1 = Mesh.get_edge(i,2); double x2 = Mesh.get_edge(i,3); double y2 = Mesh.get_edge(i,4); // Elements on either side of edge int ileft = Mesh.get_eelem(i,1); int iright = Mesh.get_eelem(i,2); double Areal = Mesh.get_area_prim(ileft); double Arear = Mesh.get_area_prim(iright); // Scaled normal to edge dTensor1 nhat(2); nhat.set(1, (y2-y1) ); nhat.set(2, (x1-x2) ); // Variables to store flux integrals along edge dTensor2 Fr_tmp(meqn,dogParams.get_space_order()); dTensor2 Fl_tmp(meqn,dogParams.get_space_order()); // Loop over number of quadrature points along each edge for (int ell=1; ell<=dogParams.get_space_order(); ell++) { dTensor1 Ql(meqn), Qr(meqn); dTensor1 ffl(meqn), ffr(meqn); // << -- NEW PART -- >> dTensor1 Auxl(maux), Auxr(maux); // Riemann data - q for (int m=1; m<=meqn; m++) { Ql.set(m, 0.0 ); Qr.set(m, 0.0 ); // << -- NEW PART, ffl and ffr -- >> // ffl.set(m, 0.0 ); ffr.set(m, 0.0 ); for (int k=1; k<=kmax; k++) { Ql.set(m, Ql.get(m) + EdgeData.phi_left->get(i,ell,k) *q.get(ileft, m,k) ); Qr.set(m, Qr.get(m) + EdgeData.phi_right->get(i,ell,k) *q.get(iright,m,k) ); // << -- NEW PART, ffl and ffr -- >> // // Is this the correct way to use the normal vector? ffl.set(m, ffl.get(m) + EdgeData.phi_left->get (i, ell, k) * ( nhat.get(1)*F.get( ileft, m, k) + nhat.get(2)*G.get( ileft, m, k) ) ); ffr.set(m, ffr.get(m) + EdgeData.phi_right->get(i, ell, k) * ( nhat.get(1)*F.get(iright, m, k) + nhat.get(2)*G.get(iright, m, k) ) ); } } // Riemann data - aux for (int m=1; m<=maux; m++) { Auxl.set(m, 0.0 ); Auxr.set(m, 0.0 ); for (int k=1; k<=kmax; k++) { Auxl.set(m, Auxl.get(m) + EdgeData.phi_left->get(i,ell,k) * aux.get(ileft, m,k) ); Auxr.set(m, Auxr.get(m) + EdgeData.phi_right->get(i,ell,k) * aux.get(iright,m,k) ); } } // Solve Riemann problem dTensor1 xedge(2); double s = EdgeData.xpts1d->get(ell); xedge.set(1, x1 + 0.5*(s+1.0)*(x2-x1) ); xedge.set(2, y1 + 0.5*(s+1.0)*(y2-y1) ); // Solve the Riemann problem for this edge dTensor1 Fl(meqn), Fr(meqn); // Use the time-averaged fluxes to define left and right values for // the Riemann solver. const double smax_edge = RiemannSolveLxW( nhat, xedge, Ql, Qr, Auxl, Auxr, ffl, ffr, Fl, Fr); smax.set(i, Max(smax_edge,smax.get(i)) ); // Construct fluxes for (int m=1; m<=meqn; m++) { Fr_tmp.set(m,ell, Fr.get(m) ); Fl_tmp.set(m,ell, Fl.get(m) ); } } // Add edge integral to line integral around the full element for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { double Fl_sum = 0.0; double Fr_sum = 0.0; for (int ell=1; ell<=dogParams.get_space_order(); ell++) { Fl_sum = Fl_sum + 0.5*EdgeData.wgts1d->get(ell) *EdgeData.phi_left->get(i,ell,k) *Fl_tmp.get(m,ell); Fr_sum = Fr_sum + 0.5*EdgeData.wgts1d->get(ell) *EdgeData.phi_right->get(i,ell,k)*Fr_tmp.get(m,ell); } EdgeFluxIntegral.set(ileft, m,k, EdgeFluxIntegral.get(ileft, m,k) + Fl_sum/Areal ); EdgeFluxIntegral.set(iright,m,k, EdgeFluxIntegral.get(iright,m,k) - Fr_sum/Arear ); } } // --------------------------------------------------------- // --------------------------------------------------------- // Part III: compute intra-element contributions // --------------------------------------------------------- if( dogParams.get_space_order() > 1 ) { L2ProjectGradAddLegendre_Unst(1, NumPhysElems, space_order, Mesh, &F, &G, &ElemFluxIntegral ); } // --------------------------------------------------------- // --------------------------------------------------------- // Part IV: construct Lstar // --------------------------------------------------------- if (dogParams.get_source_term()==0) // Without Source Term { #pragma omp parallel for for (int i=1; i<=NumPhysElems; i++) for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { double tmp = ElemFluxIntegral.get(i,m,k) - EdgeFluxIntegral.get(i,m,k); Lstar.set(i,m,k, tmp ); } } else // With Source Term { #pragma omp parallel for for (int i=1; i<=NumPhysElems; i++) for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { // double tmp = ElemFluxIntegral.get(i,m,k) // - EdgeFluxIntegral.get(i,m,k) // + Psi.get(i,m,k); // Lstar.set(i,m,k, tmp ); printf("Source term has not been implemented for LxW solver. Terminating program."); exit(1); } } // --------------------------------------------------------- // --------------------------------------------------------- // Part V: add extra contributions to Lstar // --------------------------------------------------------- // Call LstarExtra LstarExtra_Unst(Mesh, &q, &aux, &Lstar); // --------------------------------------------------------- // --------------------------------------------------------- // Part VI: artificial viscosity limiter // --------------------------------------------------------- // if (dogParams.get_space_order()>1 && // dogParams.using_viscosity_limiter()) // { ArtificialViscosity(&aux,&q,&Lstar); } // --------------------------------------------------------- }
void ConstructA_CG2(const mesh& Mesh, FullMatrix& A) { const int NumPhysElems = Mesh.get_NumPhysElems(); const int NumBndNodes = Mesh.get_SubNumBndNodes(); const int Asize = Mesh.get_SubNumPhysNodes(); assert_eq(Asize,A.get_NumRows()); assert_eq(Asize,A.get_NumCols()); dTensor1 A1(6); dTensor1 A2(6); dTensor1 A3(6); dTensor1 A4(6); dTensor1 A5(6); dTensor1 A6(6); A1.set(1, -oneninth ); A1.set(2, 4.0*oneninth ); A1.set(3, -oneninth ); A1.set(4, 4.0*oneninth ); A1.set(5, 4.0*oneninth ); A1.set(6, -oneninth ); A2.set(1, -onethird ); A2.set(2, 0.0 ); A2.set(3, onethird ); A2.set(4, -4.0*onethird ); A2.set(5, 4.0*onethird ); A2.set(6, 0.0 ); A3.set(1, -onethird ); A3.set(2, -4.0*onethird ); A3.set(3, 0.0 ); A3.set(4, 0.0 ); A3.set(5, 4.0*onethird ); A3.set(6, onethird ); A4.set(1, 4.0 ); A4.set(2, -4.0 ); A4.set(3, 0.0 ); A4.set(4, -4.0 ); A4.set(5, 4.0 ); A4.set(6, 0.0 ); A5.set(1, 2.0 ); A5.set(2, -4.0 ); A5.set(3, 2.0 ); A5.set(4, 0.0 ); A5.set(5, 0.0 ); A5.set(6, 0.0 ); A6.set(1, 2.0 ); A6.set(2, 0.0 ); A6.set(3, 0.0 ); A6.set(4, -4.0 ); A6.set(5, 0.0 ); A6.set(6, 2.0 ); dTensor2 spts(3,2); spts.set(1,1, 1.0/3.0 ); spts.set(1,2, -1.0/6.0 ); spts.set(2,1, -1.0/6.0 ); spts.set(2,2, -1.0/6.0 ); spts.set(3,1, -1.0/6.0 ); spts.set(3,2, 1.0/3.0 ); dTensor1 wgts(3); wgts.set(1, 1.0/6.0 ); wgts.set(2, 1.0/6.0 ); wgts.set(3, 1.0/6.0 ); // Loop over all elements in the mesh for (int i=1; i<=NumPhysElems; i++) { // Information for element i iTensor1 tt(6); for (int k=1; k<=6; k++) { tt.set(k, Mesh.get_node_subs(i,k) ); } // Evaluate gradients of the Lagrange polynomials on Gauss quadrature points dTensor2 gpx(6,3); dTensor2 gpy(6,3); for (int m=1; m<=3; m++) { double xi = spts.get(m,1); double eta = spts.get(m,2); for (int k=1; k<=6; k++) { double gp_xi = A2.get(k) + 2.0*A5.get(k)*xi + A4.get(k)*eta; double gp_eta = A3.get(k) + A4.get(k)*xi + 2.0*A6.get(k)*eta; gpx.set(k,m, Mesh.get_jmat(i,1,1)*gp_xi + Mesh.get_jmat(i,1,2)*gp_eta ); gpy.set(k,m, Mesh.get_jmat(i,2,1)*gp_xi + Mesh.get_jmat(i,2,2)*gp_eta ); } } // Entries of the stiffness matrix A double Area = Mesh.get_area_prim(i); for (int j=1; j<=6; j++) for (int k=1; k<=6; k++) { double tmp = A.get(tt.get(j),tt.get(k)); for (int m=1; m<=3; m++) { tmp = tmp + 2.0*Area*wgts.get(m)*(gpx.get(j,m)*gpx.get(k,m)+gpy.get(j,m)*gpy.get(k,m)); } A.set(tt.get(j),tt.get(k), tmp ); } } // Replace boundary node equations by Dirichlet boundary condition enforcement for (int i=1; i<=NumBndNodes; i++) { const int j=Mesh.get_sub_bnd_node(i); for (int k=1; k<=A.get_NumCols(); k++) { A.set(j,k, 0.0 ); } for (int k=1; k<=A.get_NumRows(); k++) { A.set(k,j, 0.0 ); } A.set(j,j, 1.0 ); } // Get sparse structure representation A.Sparsify(); }
// This is the positivity preserving limiter proposed in // "Maximum-Principle-Satisfying and Positivity-Preserving // High Order Discontinuous Galerkin Schemes // for Conservation Laws on Triangular Meshes", Zhang, Xia and Shu // J. Sci. Comput. (2012). // // THIS METHOD ASSUMES THAT EVERY COMPONENT OF CONSERVED VARIABLES SHOULD STAY // POSITIVE. // // In order to implement this for a different scheme, one should rewrite, or // redefine what components should remain positiive. This will require // reworking the control flow logic for how time step lengths are chosen. void ApplyPosLimiter_Unst(const mesh& Mesh, const dTensor3& aux, dTensor3& q) { const int NumElems = Mesh.get_NumElems(); const int NumPhysElems = Mesh.get_NumPhysElems(); const int NumEdges = Mesh.get_NumEdges(); const int meqn = q.getsize(2); const int kmax = q.getsize(3); const int maux = aux.getsize(2); const int space_order = dogParams.get_space_order(); // Do nothing in the case of piecewise constants if( space_order == 1 ) { return; } // ------------------------------------------------ // // number of points where we want to check solution // // ------------------------------------------------ // const int space_order_sq = space_order*space_order; const int mpts_vec[] = {0, 3*space_order_sq, 18, 3*space_order_sq, 3*space_order_sq }; // TODO - FILL IN 2ND-ORDER CASE const int mpoints = mpts_vec[space_order-1]; // ---------------------------------------------------------- // // sample basis at all points where we want to check solution // // ---------------------------------------------------------- // dTensor2 spts(mpoints, 2); void SetPositivePoints_Unst(const int& space_order, dTensor2& spts); SetPositivePoints_Unst(space_order, spts); void SamplePhiAtPositivePoints_Unst(const int& space_order, const dTensor2& spts, dTensor2& phi); dTensor2 phi(mpoints, kmax); SamplePhiAtPositivePoints_Unst(space_order, spts, phi); // -------------------------------------------------------------- // // q_limited = Q1 + \theta ( q(xi,eta) - Q1 ) // // where theta = min(1, |Q1| / |Q1-m|; m = min_{i} q(xi_i, eta_i) // // -------------------------------------------------------------- // #pragma omp parallel for for(int i=1; i <= NumPhysElems; i++) for(int me=1; me <= meqn; me++) { double m = 0.0; for(int mp=1; mp <= mpoints; mp++) { // evaluate q at spts(mp) // double qnow = 0.0; for( int k=1; k <= kmax; k++ ) { qnow += q.get(i,me,k) * phi.get(mp,k); } m = Min(m, qnow); } double theta = 0.0; double Q1 = q.get(i,me,1); assert_ge( Q1, -1e-13 ); if( fabs( Q1 - m ) < 1.0e-14 ){ theta = 1.0; } else{ theta = Min( 1.0, fabs( Q1 / (Q1 - m) ) ); } // limit q // for( int k=2; k <= kmax; k++ ) { q.set(i,me,k, q.get(i,me,k) * theta ); } } }
void ConstructL_Unst( const double t, const dTensor2* vel_vec, const mesh& Mesh, const edge_data_Unst& EdgeData, dTensor3& aux, // SetBndValues_Unst modifies ghost cells dTensor3& q, // SetBndValues_Unst modifies ghost cells dTensor3& Lstar, dTensor1& smax) { const int NumElems = Mesh.get_NumElems(); const int NumPhysElems = Mesh.get_NumPhysElems(); const int NumEdges = Mesh.get_NumEdges(); const int meqn = q.getsize(2); const int kmax = q.getsize(3); const int maux = aux.getsize(2); const int space_order = dogParams.get_space_order(); dTensor3 EdgeFluxIntegral(NumElems,meqn,kmax); dTensor3 ElemFluxIntegral(NumElems,meqn,kmax); dTensor3 Psi(NumElems,meqn,kmax); // --------------------------------------------------------- // Boundary Conditions SetBndValues_Unst(Mesh,&q,&aux); // Positivity limiter void ApplyPosLimiter_Unst(const mesh& Mesh, const dTensor3& aux, dTensor3& q); if( dogParams.using_moment_limiter() ) { ApplyPosLimiter_Unst(Mesh, aux, q); } // --------------------------------------------------------- // --------------------------------------------------------- // Part I: compute flux integral on element edges // --------------------------------------------------------- // Loop over all interior edges and solve Riemann problems // dTensor1 nvec(2); // Loop over all interior edges EdgeFluxIntegral.setall(0.); ElemFluxIntegral.setall(0.); // Loop over all interior edges #pragma omp parallel for for (int i=1; i<=NumEdges; i++) { // Edge coordinates double x1 = Mesh.get_edge(i,1); double y1 = Mesh.get_edge(i,2); double x2 = Mesh.get_edge(i,3); double y2 = Mesh.get_edge(i,4); // Elements on either side of edge int ileft = Mesh.get_eelem(i,1); int iright = Mesh.get_eelem(i,2); double Areal = Mesh.get_area_prim(ileft); double Arear = Mesh.get_area_prim(iright); // Scaled normal to edge dTensor1 nhat(2); nhat.set(1, (y2-y1) ); nhat.set(2, (x1-x2) ); // Variables to store flux integrals along edge dTensor2 Fr_tmp(meqn,dogParams.get_space_order()); dTensor2 Fl_tmp(meqn,dogParams.get_space_order()); // Loop over number of quadrature points along each edge for (int ell=1; ell<=dogParams.get_space_order(); ell++) { dTensor1 Ql(meqn),Qr(meqn); dTensor1 Auxl(maux),Auxr(maux); // Riemann data - q for (int m=1; m<=meqn; m++) { Ql.set(m, 0.0 ); Qr.set(m, 0.0 ); for (int k=1; k<=kmax; k++) { Ql.set(m, Ql.get(m) + EdgeData.phi_left->get(i,ell,k) *q.get(ileft, m,k) ); Qr.set(m, Qr.get(m) + EdgeData.phi_right->get(i,ell,k) *q.get(iright,m,k) ); } } // Riemann data - aux for (int m=1; m<=maux; m++) { Auxl.set(m, 0.0 ); Auxr.set(m, 0.0 ); for (int k=1; k<=kmax; k++) { Auxl.set(m, Auxl.get(m) + EdgeData.phi_left->get(i,ell,k) *aux.get(ileft, m,k) ); Auxr.set(m, Auxr.get(m) + EdgeData.phi_right->get(i,ell,k) *aux.get(iright,m,k) ); } } // Solve Riemann problem dTensor1 xedge(2); double s = EdgeData.xpts1d->get(ell); xedge.set(1, x1 + 0.5*(s+1.0)*(x2-x1) ); xedge.set(2, y1 + 0.5*(s+1.0)*(y2-y1) ); dTensor1 Fl(meqn),Fr(meqn); const double smax_edge = RiemannSolve(vel_vec, nhat, xedge, Ql, Qr, Auxl, Auxr, Fl, Fr); smax.set(i, Max(smax_edge,smax.get(i)) ); // Construct fluxes for (int m=1; m<=meqn; m++) { Fr_tmp.set(m,ell, Fr.get(m) ); Fl_tmp.set(m,ell, Fl.get(m) ); } } // Add edge integral to line integral around the full element for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { double Fl_sum = 0.0; double Fr_sum = 0.0; for (int ell=1; ell<=dogParams.get_space_order(); ell++) { Fl_sum = Fl_sum + 0.5*EdgeData.wgts1d->get(ell) *EdgeData.phi_left->get(i,ell,k) *Fl_tmp.get(m,ell); Fr_sum = Fr_sum + 0.5*EdgeData.wgts1d->get(ell) *EdgeData.phi_right->get(i,ell,k)*Fr_tmp.get(m,ell); } EdgeFluxIntegral.set(ileft, m,k, EdgeFluxIntegral.get(ileft, m,k) + Fl_sum/Areal ); EdgeFluxIntegral.set(iright,m,k, EdgeFluxIntegral.get(iright,m,k) - Fr_sum/Arear ); } } // --------------------------------------------------------- // --------------------------------------------------------- // Part II: compute intra-element contributions // --------------------------------------------------------- L2ProjectGrad_Unst(vel_vec, 1,NumPhysElems, space_order,space_order,space_order,space_order, Mesh,&q,&aux,&ElemFluxIntegral,&FluxFunc); // --------------------------------------------------------- // --------------------------------------------------------- // Part III: compute source term // --------------------------------------------------------- if ( dogParams.get_source_term()>0 ) { // Set source term on computational grid // Set values and apply L2-projection L2Project_Unst(t, vel_vec, 1,NumPhysElems, space_order,space_order,space_order,space_order, Mesh,&q,&aux,&Psi,&SourceTermFunc); } // --------------------------------------------------------- // --------------------------------------------------------- // Part IV: construct Lstar // --------------------------------------------------------- if (dogParams.get_source_term()==0) // Without Source Term { #pragma omp parallel for for (int i=1; i<=NumPhysElems; i++) for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { double tmp = ElemFluxIntegral.get(i,m,k) - EdgeFluxIntegral.get(i,m,k); Lstar.set(i,m,k, tmp ); } } else // With Source Term { #pragma omp parallel for for (int i=1; i<=NumPhysElems; i++) for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { double tmp = ElemFluxIntegral.get(i,m,k) - EdgeFluxIntegral.get(i,m,k) + Psi.get(i,m,k); Lstar.set(i,m,k, tmp ); } } // --------------------------------------------------------- // --------------------------------------------------------- // Part V: add extra contributions to Lstar // --------------------------------------------------------- // Call LstarExtra LstarExtra_Unst(Mesh,&q,&aux,&Lstar); // --------------------------------------------------------- }