void mixtureKEpsilon<BasicTurbulenceModel>::correct() { const transportModel& gas = this->transport(); const twoPhaseSystem& fluid = gas.fluid(); // Only solve the mixture turbulence for the gas-phase if (&gas != &fluid.phase1()) { // This is the liquid phase but check the model for the gas-phase // is consistent this->liquidTurbulence(); return; } if (!this->turbulence_) { return; } // Initialise the mixture fields if they have not yet been constructed initMixtureFields(); // Local references to gas-phase properties const surfaceScalarField& phig = this->phi_; const volVectorField& Ug = this->U_; const volScalarField& alphag = this->alpha_; volScalarField& kg = this->k_; volScalarField& epsilong = this->epsilon_; volScalarField& nutg = this->nut_; // Local references to liquid-phase properties mixtureKEpsilon<BasicTurbulenceModel>& liquidTurbulence = this->liquidTurbulence(); const surfaceScalarField& phil = liquidTurbulence.phi_; const volVectorField& Ul = liquidTurbulence.U_; const volScalarField& alphal = liquidTurbulence.alpha_; volScalarField& kl = liquidTurbulence.k_; volScalarField& epsilonl = liquidTurbulence.epsilon_; volScalarField& nutl = liquidTurbulence.nut_; // Local references to mixture properties volScalarField& rhom = rhom_(); volScalarField& km = km_(); volScalarField& epsilonm = epsilonm_(); eddyViscosity<RASModel<BasicTurbulenceModel> >::correct(); // Update the effective mixture density rhom = this->rhom(); // Mixture flux surfaceScalarField phim("phim", mixFlux(phil, phig)); // Mixture velocity divergence volScalarField divUm ( mixU ( fvc::div(fvc::absolute(phil, Ul)), fvc::div(fvc::absolute(phig, Ug)) ) ); tmp<volScalarField> Gc; { tmp<volTensorField> tgradUl = fvc::grad(Ul); Gc = tmp<volScalarField> ( new volScalarField ( this->GName(), nutl*(tgradUl() && dev(twoSymm(tgradUl()))) ) ); tgradUl.clear(); // Update k, epsilon and G at the wall kl.boundaryField().updateCoeffs(); epsilonl.boundaryField().updateCoeffs(); Gc().checkOut(); } tmp<volScalarField> Gd; { tmp<volTensorField> tgradUg = fvc::grad(Ug); Gd = tmp<volScalarField> ( new volScalarField ( this->GName(), nutg*(tgradUg() && dev(twoSymm(tgradUg()))) ) ); tgradUg.clear(); // Update k, epsilon and G at the wall kg.boundaryField().updateCoeffs(); epsilong.boundaryField().updateCoeffs(); Gd().checkOut(); } // Mixture turbulence generation volScalarField Gm(mix(Gc, Gd)); // Mixture turbulence viscosity volScalarField nutm(mixU(nutl, nutg)); // Update the mixture k and epsilon boundary conditions km == mix(kl, kg); bound(km, this->kMin_); epsilonm == mix(epsilonl, epsilong); bound(epsilonm, this->epsilonMin_); // Dissipation equation tmp<fvScalarMatrix> epsEqn ( fvm::ddt(rhom, epsilonm) + fvm::div(phim, epsilonm) - fvm::Sp(fvc::ddt(rhom) + fvc::div(phim), epsilonm) - fvm::laplacian(DepsilonEff(rhom*nutm), epsilonm) == C1_*rhom*Gm*epsilonm/km - fvm::SuSp(((2.0/3.0)*C1_)*rhom*divUm, epsilonm) - fvm::Sp(C2_*rhom*epsilonm/km, epsilonm) + epsilonSource() ); epsEqn().relax(); epsEqn().boundaryManipulate(epsilonm.boundaryField()); solve(epsEqn); bound(epsilonm, this->epsilonMin_); // Turbulent kinetic energy equation tmp<fvScalarMatrix> kmEqn ( fvm::ddt(rhom, km) + fvm::div(phim, km) - fvm::Sp(fvc::ddt(rhom) + fvc::div(phim), km) - fvm::laplacian(DkEff(rhom*nutm), km) == rhom*Gm - fvm::SuSp((2.0/3.0)*rhom*divUm, km) - fvm::Sp(rhom*epsilonm/km, km) + kSource() ); kmEqn().relax(); solve(kmEqn); bound(km, this->kMin_); km.correctBoundaryConditions(); volScalarField Cc2(rhom/(alphal*rholEff() + alphag*rhogEff()*Ct2_())); kl = Cc2*km; kl.correctBoundaryConditions(); epsilonl = Cc2*epsilonm; epsilonl.correctBoundaryConditions(); liquidTurbulence.correctNut(); Ct2_() = Ct2(); kg = Ct2_()*kl; kg.correctBoundaryConditions(); epsilong = Ct2_()*epsilonl; epsilong.correctBoundaryConditions(); nutg = Ct2_()*(liquidTurbulence.nu()/this->nu())*nutl; }
void UZRectMollerup::tick (const GeometryRect& geo, const std::vector<size_t>& drain_cell, const double drain_water_level, const Soil& soil, SoilWater& soil_water, const SoilHeat& soil_heat, const Surface& surface, const Groundwater& groundwater, const double dt, Treelog& msg) { daisy_assert (K_average.get ()); const size_t edge_size = geo.edge_size (); // number of edges const size_t cell_size = geo.cell_size (); // number of cells // Insert magic here. ublas::vector<double> Theta (cell_size); // water content ublas::vector<double> Theta_previous (cell_size); // at start of small t-step ublas::vector<double> h (cell_size); // matrix pressure ublas::vector<double> h_previous (cell_size); // at start of small timestep ublas::vector<double> h_ice (cell_size); // ublas::vector<double> S (cell_size); // sink term ublas::vector<double> S_vol (cell_size); // sink term #ifdef TEST_OM_DEN_ER_BRUGT ublas::vector<double> S_macro (cell_size); // sink term std::vector<double> S_drain (cell_size, 0.0); // matrix-> macro -> drain flow std::vector<double> S_drain_sum (cell_size, 0.0); // For large timestep const std::vector<double> S_matrix (cell_size, 0.0); // matrix -> macro std::vector<double> S_matrix_sum (cell_size, 0.0); // for large timestep #endif ublas::vector<double> T (cell_size); // temperature ublas::vector<double> Kold (edge_size); // old hydraulic conductivity ublas::vector<double> Ksum (edge_size); // Hansen hydraulic conductivity ublas::vector<double> Kcell (cell_size); // hydraulic conductivity ublas::vector<double> Kold_cell (cell_size); // old hydraulic conductivity ublas::vector<double> Ksum_cell (cell_size); // Hansen hydraulic conductivity ublas::vector<double> h_lysimeter (cell_size); std::vector<bool> active_lysimeter (cell_size); const std::vector<size_t>& edge_above = geo.cell_edges (Geometry::cell_above); const size_t edge_above_size = edge_above.size (); ublas::vector<double> remaining_water (edge_above_size); std::vector<bool> drain_cell_on (drain_cell.size (),false); for (size_t i = 0; i < edge_above_size; i++) { const size_t edge = edge_above[i]; remaining_water (i) = surface.h_top (geo, edge); } ublas::vector<double> q; // Accumulated flux q = ublas::zero_vector<double> (edge_size); ublas::vector<double> dq (edge_size); // Flux in small timestep. dq = ublas::zero_vector<double> (edge_size); //Make Qmat area diagonal matrix //Note: This only needs to be calculated once... ublas::banded_matrix<double> Qmat (cell_size, cell_size, 0, 0); for (int c = 0; c < cell_size; c++) Qmat (c, c) = geo.cell_volume (c); // make vectors for (size_t cell = 0; cell != cell_size ; ++cell) { Theta (cell) = soil_water.Theta (cell); h (cell) = soil_water.h (cell); h_ice (cell) = soil_water.h_ice (cell); S (cell) = soil_water.S_sum (cell); S_vol (cell) = S (cell) * geo.cell_volume (cell); if (use_forced_T) T (cell) = forced_T; else T (cell) = soil_heat.T (cell); h_lysimeter (cell) = geo.zplus (cell) - geo.cell_z (cell); } // Remember old value. Theta_error = Theta; // Start time loop double time_left = dt; // How much of the large time step left. double ddt = dt; // We start with small == large time step. int number_of_time_step_reductions = 0; int iterations_with_this_time_step = 0; int n_small_time_steps = 0; while (time_left > 0.0) { if (ddt > time_left) ddt = time_left; std::ostringstream tmp_ddt; tmp_ddt << "Time t = " << (dt - time_left) << "; ddt = " << ddt << "; steps " << n_small_time_steps << "; time left = " << time_left; Treelog::Open nest (msg, tmp_ddt.str ()); if (n_small_time_steps > 0 && (n_small_time_steps%msg_number_of_small_time_steps) == 0) { msg.touch (); msg.flush (); } n_small_time_steps++; if (n_small_time_steps > max_number_of_small_time_steps) { msg.debug ("Too many small timesteps"); throw "Too many small timesteps"; } // Initialization for each small time step. if (debug > 0) { std::ostringstream tmp; tmp << "h = " << h << "\n"; tmp << "Theta = " << Theta; msg.message (tmp.str ()); } int iterations_used = 0; h_previous = h; Theta_previous = Theta; if (debug == 5) { std::ostringstream tmp; tmp << "Remaining water at start: " << remaining_water; msg.message (tmp.str ()); } ublas::vector<double> h_conv; for (size_t cell = 0; cell != cell_size ; ++cell) active_lysimeter[cell] = h (cell) > h_lysimeter (cell); for (size_t edge = 0; edge != edge_size ; ++edge) { Kold[edge] = find_K_edge (soil, geo, edge, h, h_ice, h_previous, T); Ksum [edge] = 0.0; } std::vector<top_state> state (edge_above.size (), top_undecided); // We try harder with smaller timesteps. const int max_loop_iter = max_iterations * (number_of_time_step_reductions * max_iterations_timestep_reduction_factor + 1); do // Start iteration loop { h_conv = h; iterations_used++; std::ostringstream tmp_conv; tmp_conv << "Convergence " << iterations_used; Treelog::Open nest (msg, tmp_conv.str ()); if (debug == 7) msg.touch (); // Calculate conductivity - The Hansen method for (size_t e = 0; e < edge_size; e++) { Ksum[e] += find_K_edge (soil, geo, e, h, h_ice, h_previous, T); Kedge[e] = (Ksum[e] / (iterations_used + 0.0)+ Kold[e]) / 2.0; } //Initialize diffusive matrix Solver::Matrix diff (cell_size); // diff = ublas::zero_matrix<double> (cell_size, cell_size); diffusion (geo, Kedge, diff); //Initialize gravitational matrix ublas::vector<double> grav (cell_size); //ublass compatibility grav = ublas::zero_vector<double> (cell_size); gravitation (geo, Kedge, grav); // Boundary matrices and vectors ublas::banded_matrix<double> Dm_mat (cell_size, cell_size, 0, 0); // Dir bc Dm_mat = ublas::zero_matrix<double> (cell_size, cell_size); ublas::vector<double> Dm_vec (cell_size); // Dir bc Dm_vec = ublas::zero_vector<double> (cell_size); ublas::vector<double> Gm (cell_size); // Dir bc Gm = ublas::zero_vector<double> (cell_size); ublas::vector<double> B (cell_size); // Neu bc B = ublas::zero_vector<double> (cell_size); lowerboundary (geo, groundwater, active_lysimeter, h, Kedge, dq, Dm_mat, Dm_vec, Gm, B, msg); upperboundary (geo, soil, T, surface, state, remaining_water, h, Kedge, dq, Dm_mat, Dm_vec, Gm, B, ddt, debug, msg, dt); Darcy (geo, Kedge, h, dq); //for calculating drain fluxes //Initialize water capacity matrix ublas::banded_matrix<double> Cw (cell_size, cell_size, 0, 0); for (size_t c = 0; c < cell_size; c++) Cw (c, c) = soil.Cw2 (c, h[c]); std::vector<double> h_std (cell_size); //ublas vector -> std vector std::copy(h.begin (), h.end (), h_std.begin ()); #ifdef TEST_OM_DEN_ER_BRUGT for (size_t cell = 0; cell != cell_size ; ++cell) { S_macro (cell) = (S_matrix[cell] + S_drain[cell]) * geo.cell_volume (cell); } #endif //Initialize sum matrix Solver::Matrix summat (cell_size); noalias (summat) = diff + Dm_mat; //Initialize sum vector ublas::vector<double> sumvec (cell_size); sumvec = grav + B + Gm + Dm_vec - S_vol #ifdef TEST_OM_DEN_ER_BRUGT - S_macro #endif ; // QCw is shorthand for Qmatrix * Cw Solver::Matrix Q_Cw (cell_size); noalias (Q_Cw) = prod (Qmat, Cw); //Initialize A-matrix Solver::Matrix A (cell_size); noalias (A) = (1.0 / ddt) * Q_Cw - summat; // Q_Cw_h is shorthand for Qmatrix * Cw * h const ublas::vector<double> Q_Cw_h = prod (Q_Cw, h); //Initialize b-vector ublas::vector<double> b (cell_size); //b = sumvec + (1.0 / ddt) * (Qmatrix * Cw * h + Qmatrix *(Wxx-Wyy)); b = sumvec + (1.0 / ddt) * (Q_Cw_h + prod (Qmat, Theta_previous-Theta)); // Force active drains to zero h. drain (geo, drain_cell, drain_water_level, h, Theta_previous, Theta, S_vol, #ifdef TEST_OM_DEN_ER_BRUGT S_macro, #endif dq, ddt, drain_cell_on, A, b, debug, msg); try { solver->solve (A, b, h); // Solve Ah=b with regard to h. } catch (const char *const error) { std::ostringstream tmp; tmp << "Could not solve equation system: " << error; msg.warning (tmp.str ()); // Try smaller timestep. iterations_used = max_loop_iter + 100; break; } for (int c=0; c < cell_size; c++) // update Theta Theta (c) = soil.Theta (c, h (c), h_ice (c)); if (debug > 1) { std::ostringstream tmp; tmp << "Time left = " << time_left << ", ddt = " << ddt << ", iteration = " << iterations_used << "\n"; tmp << "B = " << B << "\n"; tmp << "h = " << h << "\n"; tmp << "Theta = " << Theta; msg.message (tmp.str ()); } for (int c=0; c < cell_size; c++) { if (h (c) < min_pressure_potential || h (c) > max_pressure_potential) { std::ostringstream tmp; tmp << "Pressure potential out of realistic range, h[" << c << "] = " << h (c); msg.debug (tmp.str ()); iterations_used = max_loop_iter + 100; break; } } } while (!converges (h_conv, h) && iterations_used <= max_loop_iter); if (iterations_used > max_loop_iter) { number_of_time_step_reductions++; if (number_of_time_step_reductions > max_time_step_reductions) { msg.debug ("Could not find solution"); throw "Could not find solution"; } iterations_with_this_time_step = 0; ddt /= time_step_reduction; h = h_previous; Theta = Theta_previous; } else { // Update dq for new h. ublas::banded_matrix<double> Dm_mat (cell_size, cell_size, 0, 0); // Dir bc Dm_mat = ublas::zero_matrix<double> (cell_size, cell_size); ublas::vector<double> Dm_vec (cell_size); // Dir bc Dm_vec = ublas::zero_vector<double> (cell_size); ublas::vector<double> Gm (cell_size); // Dir bc Gm = ublas::zero_vector<double> (cell_size); ublas::vector<double> B (cell_size); // Neu bc B = ublas::zero_vector<double> (cell_size); lowerboundary (geo, groundwater, active_lysimeter, h, Kedge, dq, Dm_mat, Dm_vec, Gm, B, msg); upperboundary (geo, soil, T, surface, state, remaining_water, h, Kedge, dq, Dm_mat, Dm_vec, Gm, B, ddt, debug, msg, dt); Darcy (geo, Kedge, h, dq); #ifdef TEST_OM_DEN_ER_BRUGT // update macropore flow components for (int c = 0; c < cell_size; c++) { S_drain_sum[c] += S_drain[c] * ddt/dt; S_matrix_sum[c] += S_matrix[c] * ddt/dt; } #endif std::vector<double> h_std_new (cell_size); std::copy(h.begin (), h.end (), h_std_new.begin ()); // Update remaining_water. for (size_t i = 0; i < edge_above.size (); i++) { const int edge = edge_above[i]; const int cell = geo.edge_other (edge, Geometry::cell_above); const double out_sign = (cell == geo.edge_from (edge)) ? 1.0 : -1.0; remaining_water[i] += out_sign * dq (edge) * ddt; daisy_assert (std::isfinite (dq (edge))); } if (debug == 5) { std::ostringstream tmp; tmp << "Remaining water at end: " << remaining_water; msg.message (tmp.str ()); } // Contribution to large time step. daisy_assert (std::isnormal (dt)); daisy_assert (std::isnormal (ddt)); q += dq * ddt / dt; for (size_t e = 0; e < edge_size; e++) { daisy_assert (std::isfinite (dq (e))); daisy_assert (std::isfinite (q (e))); } for (size_t e = 0; e < edge_size; e++) { daisy_assert (std::isfinite (dq (e))); daisy_assert (std::isfinite (q (e))); } time_left -= ddt; iterations_with_this_time_step++; if (iterations_with_this_time_step > time_step_reduction) { number_of_time_step_reductions--; iterations_with_this_time_step = 0; ddt *= time_step_reduction; } } // End of small time step. } // Mass balance. // New = Old - S * dt + q_in * dt - q_out * dt + Error => // 0 = Old - New - S * dt + q_in * dt - q_out * dt + Error Theta_error -= Theta; // Old - New Theta_error -= S * dt; #ifdef TEST_OM_DEN_ER_BRUGT for (size_t c = 0; c < cell_size; c++) Theta_error (c) -= (S_matrix_sum[c] + S_drain_sum[c]) * dt; #endif for (size_t edge = 0; edge != edge_size; ++edge) { const int from = geo.edge_from (edge); const int to = geo.edge_to (edge); const double flux = q (edge) * geo.edge_area (edge) * dt; if (geo.cell_is_internal (from)) Theta_error (from) -= flux / geo.cell_volume (from); if (geo.cell_is_internal (to)) Theta_error (to) += flux / geo.cell_volume (to); } // Find drain sink from mass balance. #ifdef TEST_OM_DEN_ER_BRUGT std::fill(S_drain.begin (), S_drain.end (), 0.0); #else std::vector<double> S_drain (cell_size); #endif for (size_t i = 0; i < drain_cell.size (); i++) { const size_t cell = drain_cell[i]; S_drain[cell] = Theta_error (cell) / dt; Theta_error (cell) -= S_drain[cell] * dt; } if (debug == 2) { double total_error = 0.0; double total_abs_error = 0.0; double max_error = 0.0; int max_cell = -1; for (size_t cell = 0; cell != cell_size; ++cell) { const double volume = geo.cell_volume (cell); const double error = Theta_error (cell); total_error += volume * error; total_abs_error += std::fabs (volume * error); if (std::fabs (error) > std::fabs (max_error)) { max_error = error; max_cell = cell; } } std::ostringstream tmp; tmp << "Total error = " << total_error << " [cm^3], abs = " << total_abs_error << " [cm^3], max = " << max_error << " [] in cell " << max_cell; msg.message (tmp.str ()); } // Make it official. for (size_t cell = 0; cell != cell_size; ++cell) soil_water.set_content (cell, h (cell), Theta (cell)); #ifdef TEST_OM_DEN_ER_BRUGT soil_water.add_tertiary_sink (S_matrix_sum); soil_water.drain (S_drain_sum, msg); #endif for (size_t edge = 0; edge != edge_size; ++edge) { daisy_assert (std::isfinite (q[edge])); soil_water.set_flux (edge, q[edge]); } soil_water.drain (S_drain, msg); // End of large time step. }
// 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); } // --------------------------------------------------------- }