///Basic test for FastForwardRead class. TEST ( iszfstream, fastforwardread ) { //Do not delete! std::stringstream *ss = new std::stringstream; *ss << "one" << std::endl; *ss << "two" << std::endl; *ss << "three" << std::endl; *ss << "four" << std::endl; *ss << "five" ; { uu::FastForwardRead<> ffr ( ss ); std::string line; bool finished; finished = ffr ( 2, &line ); EXPECT_EQ ( line, "two" ); EXPECT_EQ ( finished, false ); finished = ffr ( 4, &line ); EXPECT_EQ ( line, "four" ); EXPECT_EQ ( finished, false ); finished = ffr ( 5, &line ); EXPECT_EQ ( line, "five" ); EXPECT_EQ ( finished, false ); finished = ffr ( 6, &line ); //No more readings EXPECT_EQ ( line, "" ); EXPECT_EQ ( finished, true ); // Cannot read backwards user_check_ok = true; finished = ffr ( 1, &line ); EXPECT_EQ ( line, "" ); EXPECT_EQ ( user_check_ok, false ); user_check_ok = true; } ss = new std::stringstream; *ss << "one" << std::endl; { std::string line; bool finished; uu::FastForwardRead<> ffr ( ss ); finished = ffr ( 1, &line ); EXPECT_EQ (finished, false); EXPECT_EQ (line, "one"); finished = ffr ( 2, &line ); EXPECT_EQ (finished, true); EXPECT_EQ (line, ""); } };
// Right-hand side of the Lax-Wendroff discretization: // // ( q(t+dt) - q(t) )/dt = -F_{x} - G_{y}. // // This routine constructs the 'time-integrated' flux functions F and G using the // Cauchy-Kowalewski procedure. // // First, consider time derivatives of q // // q^{n+1} = q^n + dt * (q^n_t + dt/2 * q^n_tt + dt^3/6 q^n_ttt ). // // Formally, these are given by // // q_{t} = ( -f(q) )_x + ( -g(q) )_y, // q_{tt} = ( f'(q) * ( f_x + g_y )_x + ( g'(q) * ( f_x + g_y )_y // q_{ttt} = ... // // Now, considering Taylor expansions of f and g, centered about t = t^n // // F = f^n + (t-t^n) \dot{f^n} + \cdots // G = g^n + (t-t^n) \dot{g^n} + \cdots // // We have the following form, after integrating in time // // F: = ( f - dt/2 * ( f'(q)*( f_x+g_y ) // + dt^2/6 ( \pd2{f}{q} \cdot (f_x+g_y,f_x+g_y) + // \pd{f}{q} ( f_x + g_y )_t ) + \cdots // // G: = ( g - dt/2 * ( g'(q)*( f_x+g_y ) // + dt^2/6 ( \pd2{g}{q} \cdot (f_x+g_y,f_x+g_y) + // \pd{g}{q} ( f_x + g_y )_t ) + \cdots // // where the final ingredient is // // (f_x+g_y)_t = \pd2{f}{q} \cdot (q_x, f_x+g_y ) + \pd{f}{q} ( f_xx + g_xy ) + // \pd2{g}{q} \cdot (q_y, f_x+g_y ) + \pd{g}{q} ( f_xy + g_yy ). // // At the end of the day, we set // // L(q) := -F_x - G_y. // // See also: ConstructL. void LaxWendroff(double dt, const dTensorBC4& aux, const dTensorBC4& q, // set bndy values modifies these dTensorBC4& Lstar, dTensorBC3& smax) { printf("This call hasn't been tested \n"); if ( !dogParams.get_flux_term() ) { return; } const edge_data& edgeData = Legendre2d::get_edgeData(); const int space_order = dogParams.get_space_order(); const int mx = q.getsize(1); const int my = q.getsize(2); const int meqn = q.getsize(3); const int kmax = q.getsize(4); const int mbc = q.getmbc(); const int maux = aux.getsize(3); // Flux values // // Space-order = number of quadrature points needed for 1D integration // along cell edges. // dTensorBC4 Fm(mx, my, meqn, space_order, mbc); dTensorBC4 Fp(mx, my, meqn, space_order, mbc); dTensorBC4 Gm(mx, my, meqn, space_order, mbc); dTensorBC4 Gp(mx, my, meqn, space_order, mbc); // Flux function void FluxFunc(const dTensor2& xpts, const dTensor2& Q, const dTensor2& Aux, dTensor3& flux); // Jacobian of the flux function: void DFluxFunc(const dTensor2& xpts, const dTensor2& Q, const dTensor2& Aux, dTensor4& Dflux ); // Hessian of the flux function: void D2FluxFunc(const dTensor2& xpts, const dTensor2& Q, const dTensor2& Aux, dTensor5& D2flux ); // Riemann solver that relies on the fact that we already have // f(ql) and f(qr) already computed: double RiemannSolveLxW(const dTensor1& nvec, const dTensor1& xedge, const dTensor1& Ql, const dTensor1& Qr, const dTensor1& Auxl, const dTensor1& Auxr, const dTensor1& ffl, const dTensor1& ffr, dTensor1& Fl, dTensor1& Fr); void LstarExtra(const dTensorBC4*, const dTensorBC4*, dTensorBC4*); void ArtificialViscosity(const dTensorBC4* aux, const dTensorBC4* q, dTensorBC4* Lstar); // Grid information const double xlower = dogParamsCart2.get_xlow(); const double ylower = dogParamsCart2.get_ylow(); const double dx = dogParamsCart2.get_dx(); const double dy = dogParamsCart2.get_dy(); // --------------------------------------------------------------------- // // Boundary data: // --------------------------------------------------------------------- // // TODO - call this routine before calling this function. // void SetBndValues(dTensorBC4& q, dTensorBC4& aux); // SetBndValues(q, aux); // --------------------------------------------------------- // --------------------------------------------------------------------- // // Part 0: Compute the Lax-Wendroff "flux" function: // // Here, we include the extra information about time derivatives. // --------------------------------------------------------------------- // dTensorBC4 F(mx, my, meqn, kmax, mbc); F.setall(0.); dTensorBC4 G(mx, my, meqn, kmax, mbc); G.setall(0.); void L2ProjectLxW( const int mterms, const double alpha, const double beta_dt, const double charlie_dt, const int istart, const int iend, const int jstart, const int jend, const int QuadOrder, const int BasisOrder_auxin, const int BasisOrder_fout, const dTensorBC4* qin, const dTensorBC4* auxin, dTensorBC4* F, dTensorBC4* G, void FluxFunc (const dTensor2& xpts, const dTensor2& Q, const dTensor2& Aux, dTensor3& flux), void DFluxFunc (const dTensor2& xpts, const dTensor2& Q, const dTensor2& aux, dTensor4& Dflux), void D2FluxFunc (const dTensor2& xpts, const dTensor2& Q, const dTensor2& aux, dTensor5& D2flux) ); printf("hello\n"); L2ProjectLxW( 3, 1.0, 0.5*dt, dt*dt/6.0, 1-mbc, mx+mbc, 1-mbc, my+mbc, space_order, space_order, space_order, &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 inter-element interaction fluxes // // N = int( F(q,x,t) * phi_x, x ) / dA // // --------------------------------------------------------- // 1-direction: loop over interior edges and solve Riemann problems dTensor1 nvec(2); nvec.set(1, 1.0e0 ); nvec.set(2, 0.0e0 ); #pragma omp parallel for for (int i=(2-mbc); i<=(mx+mbc); i++) { dTensor1 Ql(meqn), Qr(meqn); dTensor1 ffl(meqn), ffr(meqn); dTensor1 Fl(meqn), Fr(meqn); dTensor1 DFl(meqn), DFr(meqn); dTensor1 Auxl(maux), Auxr(maux); dTensor1 xedge(2); for (int j=(2-mbc); j<=(my+mbc-1); j++) { // ell indexes Riemann point along the edge for (int ell=1; ell<=space_order; ell++) { // Riemann data - q and f (from basis functions/q) for (int m=1; m<=meqn; m++) { Ql.set (m, 0.0 ); Qr.set (m, 0.0 ); ffl.set(m, 0.0 ); ffr.set(m, 0.0 ); for (int k=1; k<=kmax; k++) { // phi_xl( xi=1.0, eta ), phi_xr( xi=-1.0, eta ) Ql.fetch(m) += edgeData.phi_xl->get(ell,k)*q.get(i-1, j, m, k ); Qr.fetch(m) += edgeData.phi_xr->get(ell,k)*q.get(i, j, m, k ); ffl.fetch(m) += edgeData.phi_xl->get(ell,k)*F.get(i-1, j, m, k ); ffr.fetch(m) += edgeData.phi_xr->get(ell,k)*F.get(i, j, 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.fetch(m) += edgeData.phi_xl->get(ell,k)*aux.get(i-1, j, m, k); Auxr.fetch(m) += edgeData.phi_xr->get(ell,k)*aux.get(i, j, m, k); } } // Solve Riemann problem xedge.set(1, xlower + (double(i)-1.0)*dx ); xedge.set(2, ylower + (double(j)-0.5)*dy ); const double smax_edge = RiemannSolveLxW( nvec, xedge, Ql, Qr, Auxl, Auxr, ffl, ffr, Fl, Fr); smax.set(i-1, j, 1, Max(dy*smax_edge,smax.get(i-1, j, 1)) ); smax.set(i, j, 1, Max(dy*smax_edge,smax.get(i, j, 1)) ); // Construct fluxes for (int m=1; m<=meqn; m++) { Fm.set(i , j, m, ell, Fr.get(m) ); Fp.set(i-1, j, m, ell, Fl.get(m) ); } } } } // 2-direction: loop over interior edges and solve Riemann problems nvec.set(1, 0.0e0 ); nvec.set(2, 1.0e0 ); #pragma omp parallel for for (int i=(2-mbc); i<=(mx+mbc-1); i++) { dTensor1 Ql(meqn), Qr(meqn); dTensor1 Fl(meqn), Fr(meqn); dTensor1 ffl(meqn), ffr(meqn); dTensor1 Auxl(maux),Auxr(maux); dTensor1 xedge(2); for (int j=(2-mbc); j<=(my+mbc); j++) for (int ell=1; ell<=space_order; ell++) { // Riemann data - q for (int m=1; m<=meqn; m++) { Ql.set (m, 0.0 ); Qr.set (m, 0.0 ); ffl.set (m, 0.0 ); ffr.set (m, 0.0 ); for (int k=1; k<=kmax; k++) { Ql.fetch(m) += edgeData.phi_yl->get(ell, k)*q.get(i, j-1, m, k ); Qr.fetch(m) += edgeData.phi_yr->get(ell, k)*q.get(i, j, m, k ); ffl.fetch(m) += edgeData.phi_yl->get(ell, k)*G.get(i, j-1, m, k ); ffr.fetch(m) += edgeData.phi_yr->get(ell, k)*G.get(i, j, 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.fetch(m) += edgeData.phi_yl->get(ell,k)*aux.get(i,j-1,m,k); Auxr.fetch(m) += edgeData.phi_yr->get(ell,k)*aux.get(i,j,m,k); } } // Solve Riemann problem xedge.set(1, xlower + (double(i)-0.5)*dx ); xedge.set(2, ylower + (double(j)-1.0)*dy ); const double smax_edge = RiemannSolveLxW( nvec, xedge, Ql, Qr, Auxl, Auxr, ffl, ffr, Fl, Fr); smax.set(i, j-1, 2, Max(dx*smax_edge, smax.get(i, j-1, 2)) ); smax.set(i, j, 2, Max(dx*smax_edge, smax.get(i, j, 2)) ); // Construct fluxes for (int m=1; m<=meqn; m++) { Gm.set(i, j, m, ell, Fr.get(m) ); Gp.set(i, j-1, m, ell, Fl.get(m) ); } } } // Compute ``flux differences'' dF and dG const double half_dx_inv = 0.5/dx; const double half_dy_inv = 0.5/dy; const int mlength = Lstar.getsize(3); assert_eq( meqn, mlength ); // Use the four values, Gm, Gp, Fm, Fp to construct the boundary integral: #pragma omp parallel for for (int i=(2-mbc); i<=(mx+mbc-1); i++) for (int j=(2-mbc); j<=(my+mbc-1); j++) for (int m=1; m<=mlength; m++) for (int k=1; k<=kmax; k++) { // 1-direction: dF double F1 = 0.0; double F2 = 0.0; for (int ell=1; ell<=space_order; ell++) { F1 = F1 + edgeData.wght_phi_xr->get(ell,k)*Fm.get(i,j,m,ell); F2 = F2 + edgeData.wght_phi_xl->get(ell,k)*Fp.get(i,j,m,ell); } // 2-direction: dG double G1 = 0.0; double G2 = 0.0; for (int ell=1; ell<=space_order; ell++) { G1 = G1 + edgeData.wght_phi_yr->get(ell,k)*Gm.get(i,j,m,ell); G2 = G2 + edgeData.wght_phi_yl->get(ell,k)*Gp.get(i,j,m,ell); } Lstar.fetch(i,j,m,k) -= (half_dx_inv*(F2-F1) + half_dy_inv*(G2-G1)); } // --------------------------------------------------------- // --------------------------------------------------------- // Part III: compute intra-element contributions // --------------------------------------------------------- // No need to call this if first-order in space if(dogParams.get_space_order()>1) { dTensorBC4 Ltmp( mx, my, meqn, kmax, mbc ); void L2ProjectGradAddLegendre(const int istart, const int iend, const int jstart, const int jend, const int QuadOrder, const dTensorBC4* F, const dTensorBC4* G, dTensorBC4* fout ); L2ProjectGradAddLegendre( 1-mbc, mx+mbc, 1-mbc, my+mbc, space_order, &F, &G, &Lstar ); } // --------------------------------------------------------- // --------------------------------------------------------- // Part IV: add extra contributions to Lstar // --------------------------------------------------------- // Call LstarExtra LstarExtra(&q,&aux,&Lstar); // --------------------------------------------------------- // --------------------------------------------------------- // Part V: artificial viscosity limiter // --------------------------------------------------------- if (dogParams.get_space_order()>1 && dogParams.using_viscosity_limiter()) { ArtificialViscosity(&aux,&q,&Lstar); } // --------------------------------------------------------- }
// 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); } // --------------------------------------------------------- }