From 593089b2a5de8f540c4c68efea42d2b6c6742403 Mon Sep 17 00:00:00 2001 From: dougshidong Date: Fri, 17 May 2019 21:13:33 -0400 Subject: [PATCH] Major commit taking out numerical flux Physics and numerical fluxes are now computed outside of the DG discretization. Partial implementation of vector-valued problems by adding the std::array structures Diffusive terms require a function that will evaluate the solution numerical flux and the viscous numerical flux. Current implementation of SIPG is working to recover optimal convergence orders of the solution but not of the output functional Suboptimal output error is perceived for diffusion (maybe, I get 2p) and convection-diffusion (definitely) TODO: Find the adjoint consistent boundary condition for the diffusion problem and convection-diffusion problem TODO: Find out why the linear solver is soooo much slower for the diffusion problems Start 1: 1D_ADVECTION_IMPLICIT_MANUFACTURED_SOLUTION 1/12 Test #1: 1D_ADVECTION_IMPLICIT_MANUFACTURED_SOLUTION .............. Passed 0.53 sec Start 2: 2D_ADVECTION_IMPLICIT_MANUFACTURED_SOLUTION 2/12 Test #2: 2D_ADVECTION_IMPLICIT_MANUFACTURED_SOLUTION .............. Passed 5.84 sec Start 3: 3D_ADVECTION_IMPLICIT_MANUFACTURED_SOLUTION 3/12 Test #3: 3D_ADVECTION_IMPLICIT_MANUFACTURED_SOLUTION .............. Passed 47.98 sec Start 4: 1D_DIFFUSION_IMPLICIT_MANUFACTURED_SOLUTION 4/12 Test #4: 1D_DIFFUSION_IMPLICIT_MANUFACTURED_SOLUTION .............. Passed 0.64 sec Start 5: 2D_DIFFUSION_IMPLICIT_MANUFACTURED_SOLUTION 5/12 Test #5: 2D_DIFFUSION_IMPLICIT_MANUFACTURED_SOLUTION .............. Passed 3.23 sec Start 6: 3D_DIFFUSION_IMPLICIT_MANUFACTURED_SOLUTION 6/12 Test #6: 3D_DIFFUSION_IMPLICIT_MANUFACTURED_SOLUTION .............. Passed 237.84 sec Start 7: 1D_CONVECTION_DIFFUSION_IMPLICIT_MANUFACTURED_SOLUTION 7/12 Test #7: 1D_CONVECTION_DIFFUSION_IMPLICIT_MANUFACTURED_SOLUTION ... Passed 0.75 sec Start 8: 2D_CONVECTION_DIFFUSION_IMPLICIT_MANUFACTURED_SOLUTION 8/12 Test #8: 2D_CONVECTION_DIFFUSION_IMPLICIT_MANUFACTURED_SOLUTION ... Passed 3.45 sec Start 9: 3D_CONVECTION_DIFFUSION_IMPLICIT_MANUFACTURED_SOLUTION 9/12 Test #9: 3D_CONVECTION_DIFFUSION_IMPLICIT_MANUFACTURED_SOLUTION ... Passed 266.84 sec Start 10: 1D_numerical_flux_conservation 10/12 Test #10: 1D_numerical_flux_conservation ........................... Passed 0.27 sec Start 11: 2D_numerical_flux_conservation 11/12 Test #11: 2D_numerical_flux_conservation ........................... Passed 0.25 sec Start 12: 3D_numerical_flux_conservation 12/12 Test #12: 3D_numerical_flux_conservation ........................... Passed 0.24 sec 100% tests passed, 0 tests failed out of 12 Total Test time (real) = 567.87 sec --- TODO | 10 +- input_file.prm | 43 +++ run_this_input.py | 28 ++ src/assemble_implicit.cpp | 219 ++++++------ src/dg.cpp | 41 +++ src/dg.h | 4 + src/grid_study.cpp | 4 +- src/linear_solver.cpp | 13 +- src/numerical_flux/CMakeLists.txt | 1 + src/numerical_flux/numerical_flux.cpp | 30 +- src/numerical_flux/numerical_flux.h | 51 +-- src/numerical_flux/viscous_numerical_flux.cpp | 157 +++++++++ src/numerical_flux/viscous_numerical_flux.h | 77 +++++ src/ode_solver.cpp | 22 +- src/parameters.cpp | 2 +- src/physics/CMakeLists.txt | 6 +- src/physics/physics.cpp | 312 ++++++++++++++++++ src/physics/physics.h | 33 +- .../1d_convection_diffusion_implicit.prm | 13 +- .../2d_convection_diffusion_implicit.prm | 6 +- .../3d_convection_diffusion_implicit.prm | 4 +- .../2d_diffusion_implicit.prm | 4 +- .../numerical_flux_conservation.cpp | 209 ++++++++---- 23 files changed, 1000 insertions(+), 289 deletions(-) create mode 100644 input_file.prm create mode 100755 run_this_input.py create mode 100644 src/numerical_flux/viscous_numerical_flux.cpp create mode 100644 src/numerical_flux/viscous_numerical_flux.h diff --git a/TODO b/TODO index fd51957e9..b78031f38 100644 --- a/TODO +++ b/TODO @@ -2,15 +2,11 @@ Look into member variable naming for fe_values This one just bit me. In face_boundary I used the member fe_values instead of passed fe_values_face by mistake. -Take physics out of the DiscontinuousGalerkin class. +Find the adjoint consistent boundary condition for the diffusion problem and convection-diffusion problem -Move boundary conditions to Physics class. - -Compute auxiliary variable $ \sigma = \nabla u $ independently. +Find out why the linear solver is soooo much slower for the diffusion problems. Maybe just need pre-conditioner. -Take numerical flux out of the DiscontinuousGalerkin class. - -Adjoint consistency, output integral 2p. +Move boundary conditions to Physics class. Vector-valued problems - Figure out global solution ordering diff --git a/input_file.prm b/input_file.prm new file mode 100644 index 000000000..4d98bf789 --- /dev/null +++ b/input_file.prm @@ -0,0 +1,43 @@ +# Listing of Parameters +# --------------------- +# Number of dimensions +set dimension = 1 + +# The kind of solver for the linear system. Choices are +# . +set pde_type = advection + + +subsection ODE solver + # Maximum nonlinear solver iterations + set nonlinear_max_iterations = 3 + + # Nonlinear solver residual tolerance + set nonlinear_steady_residual_tolerance = 1e-13 + + # Print every print_iteration_modulo iterations of the nonlinear solver + set print_iteration_modulo = 1 + + # Explicit or implicit solverChoices are . + set solver_type = implicit +end + + +subsection manufactured solution convergence study + # Last degree used for convergence study + set degree_end = 4 + + # Starting degree for convergence study + set degree_start = 1 + + # Initial grid of size (initial_grid_size)^dim + set initial_grid_size = 2 + + # Number of grids in grid study + set number_of_grids = 5 + + # Multiplier on grid size. nth-grid will be of size + # (initial_grid^grid_progression)^dim + set grid_progression = 1.5 +end + diff --git a/run_this_input.py b/run_this_input.py new file mode 100755 index 000000000..f46d9195f --- /dev/null +++ b/run_this_input.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +import os +import sys +import re + +fname = 'input_file.prm' + +f = open(fname) + +regexp = re.compile(r'set dimension.*?([1-3.-]+)') + +dim = -1 +with open(fname) as f: + for line in f: + match = regexp.match(line) + if match: + dim = int(match.group(1)) + break +if dim == -1: + sys.exit("No valid 'set dimension = [1-3]' line found") + + + +bin_path = './bin/PHiLiP_'+str(dim)+'D' + +command = bin_path + ' -p ' + fname +print("Running: " + command) +os.system(command) diff --git a/src/assemble_implicit.cpp b/src/assemble_implicit.cpp index 2e938b85c..10d09b33b 100644 --- a/src/assemble_implicit.cpp +++ b/src/assemble_implicit.cpp @@ -26,7 +26,7 @@ namespace PHiLiP { using ADtype = Sacado::Fad::DFad; using ADArray = std::array; - using ADArrayVector = std::array< Tensor<1,dim,ADtype>, nstate >; + using ADArrayTensor1 = std::array< Tensor<1,dim,ADtype>, nstate >; const unsigned int n_quad_pts = fe_values_vol->n_quadrature_points; const unsigned int n_dofs_cell = fe_values_vol->dofs_per_cell; @@ -45,10 +45,10 @@ namespace PHiLiP std::vector residual_derivatives(n_dofs_cell); std::vector< ADArray > soln_at_q(n_quad_pts); - std::vector< ADArrayVector > soln_grad_at_q(n_quad_pts); // Tensor initialize with zeros + std::vector< ADArrayTensor1 > soln_grad_at_q(n_quad_pts); // Tensor initialize with zeros - std::vector< ADArrayVector > conv_phys_flux_at_q(n_quad_pts); - std::vector< ADArrayVector > diss_phys_flux_at_q(n_quad_pts); + std::vector< ADArrayTensor1 > conv_phys_flux_at_q(n_quad_pts); + std::vector< ADArrayTensor1 > diss_phys_flux_at_q(n_quad_pts); std::vector< ADArray > source_at_q(n_quad_pts); for (unsigned int iquad=0; iquadshape_grad(itest,iquad) * JxW[iquad]; + rhs[istate] += fe_values_vol->shape_grad(itest,iquad) * conv_phys_flux_at_q[iquad][istate] * JxW[iquad]; // Diffusive // Note that for diffusion, the negative is defined in the physics - //rhs[istate] += diss_phys_flux_at_q[iquad][istate] * fe_values_vol->shape_grad(itest,iquad) * JxW[iquad]; + rhs[istate] += fe_values_vol->shape_grad(itest,iquad) * diss_phys_flux_at_q[iquad][istate] * JxW[iquad]; // Source - rhs[istate] += source_at_q[iquad][istate] * fe_values_vol->shape_value(itest,iquad) * JxW[iquad]; + rhs[istate] += fe_values_vol->shape_value(itest,iquad) * source_at_q[iquad][istate] * JxW[iquad]; } } @@ -119,7 +119,7 @@ namespace PHiLiP { using ADtype = Sacado::Fad::DFad; using ADArray = std::array; - using ADArrayVector = std::array< Tensor<1,dim,ADtype>, nstate >; + using ADArrayTensor1 = std::array< Tensor<1,dim,ADtype>, nstate >; const unsigned int n_dofs_cell = fe_values_boundary->dofs_per_cell; const unsigned int n_face_quad_pts = fe_values_boundary->n_quadrature_points; @@ -136,10 +136,12 @@ namespace PHiLiP //boundary_function.value_list (fe_values_boundary->get_quadrature_points(), boundary_values, dummy); std::vector boundary_values(n_face_quad_pts); + std::vector boundary_gradients(n_face_quad_pts); const std::vector< Point > quad_pts = fe_values_boundary->get_quadrature_points(); for (unsigned int iquad=0; iquad x_quad = quad_pts[iquad]; pde_physics->manufactured_solution(x_quad, boundary_values[iquad]); + pde_physics->manufactured_gradient(x_quad, boundary_gradients[iquad]); } // AD variable @@ -154,18 +156,22 @@ namespace PHiLiP std::vector soln_int(n_face_quad_pts); std::vector soln_ext(n_face_quad_pts); - std::vector soln_grad_int(n_face_quad_pts); - std::vector soln_grad_ext(n_face_quad_pts); + std::vector soln_grad_int(n_face_quad_pts); + std::vector soln_grad_ext(n_face_quad_pts); - std::vector diss_phys_flux_int(n_face_quad_pts); - std::vector diss_phys_flux_ext(n_face_quad_pts); + std::vector diss_phys_flux_int(n_face_quad_pts); + std::vector diss_phys_flux_ext(n_face_quad_pts); - std::vector convective_num_flux_dot_n(n_face_quad_pts); + std::vector conv_num_flux_dot_n(n_face_quad_pts); + std::vector diss_soln_num_flux(n_face_quad_pts); // u* + std::vector diss_flux_jump_int(n_face_quad_pts); // u*-u_int + std::vector diss_auxi_num_flux_dot_n(n_face_quad_pts); // sigma* for (unsigned int iquad=0; iquad normal_int = normals[iquad]; + const Tensor<1,dim,ADtype> normal_ext = -normal_int; ADArray characteristic_dot_n_at_q = pde_physics->convective_eigenvalues(boundary_values[iquad], normal_int); for (int istate=0; istatedissipative_flux (soln_int[iquad], soln_grad_int[iquad], diss_phys_flux_int[iquad]); - convective_num_flux_dot_n[iquad] = conv_num_flux->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int); + conv_num_flux_dot_n[iquad] = conv_num_flux->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int); + + diss_soln_num_flux[iquad] = diss_num_flux->evaluate_solution_flux(soln_int[iquad], soln_ext[iquad], normal_int); + + ADArrayTensor1 diss_soln_jump_int; + for (int s=0; sdissipative_flux (soln_int[iquad], diss_soln_jump_int, diss_flux_jump_int[iquad]); + + diss_auxi_num_flux_dot_n[iquad] = diss_num_flux->evaluate_auxiliary_flux( + soln_int[iquad], soln_ext[iquad], + soln_grad_int[iquad], soln_grad_ext[iquad], + normal_int, penalty); + + } // Applying convection boundary condition @@ -205,11 +235,18 @@ namespace PHiLiP for (unsigned int iquad=0; iquadshape_value(itest,iquad) * - JxW[iquad]; + // Convection + rhs[istate] -= fe_values_boundary->shape_value(itest,iquad) * conv_num_flux_dot_n[iquad][istate] * JxW[iquad]; + // Diffusive + rhs[istate] -= fe_values_boundary->shape_value(itest,iquad) * diss_auxi_num_flux_dot_n[iquad][istate] * JxW[iquad]; + rhs[istate] += fe_values_boundary->shape_grad(itest,iquad) * diss_flux_jump_int[iquad][istate] * JxW[iquad]; } + //for (int istate=0; istateshape_value(itest,iquad) * + // JxW[iquad]; + //} // // Diffusion // // ******************* @@ -219,7 +256,7 @@ namespace PHiLiP // // Weakly imposed boundary condition // //soln_ext = boundary_values[iquad]; - // const ADArrayVector soln_grad_ext = soln_grad_int[iquad]; + // const ADArrayTensor1 soln_grad_ext = soln_grad_int[iquad]; // // Note: The test function is piece-wise defined to be non-zero only on the associated cell // // and zero everywhere else. @@ -229,9 +266,9 @@ namespace PHiLiP // const Tensor<1,dim,real> test_grad_ext;// = 0; // //const Tensor<1,dim,ADtype> soln_jump = (soln_int[iquad] - soln_ext) * normal_int; - // const ADArrayVector soln_grad_avg = 0.5*(soln_grad_int[iquad] + soln_grad_ext); - // const ADArrayVector test_jump = (test_int - test_ext) * normal_int; - // const ADArrayVector test_grad_avg = 0.5*(test_grad_int + test_grad_ext); + // const ADArrayTensor1 soln_grad_avg = 0.5*(soln_grad_int[iquad] + soln_grad_ext); + // const ADArrayTensor1 test_jump = (test_int - test_ext) * normal_int; + // const ADArrayTensor1 test_grad_avg = 0.5*(test_grad_int + test_grad_ext); // //rhs += (soln_jump * test_grad_avg + soln_grad_avg * test_jump - penalty*soln_jump*test_jump) * JxW[iquad]; } @@ -265,7 +302,7 @@ namespace PHiLiP { using ADtype = Sacado::Fad::DFad; using ADArray = std::array; - using ADArrayVector = std::array< Tensor<1,dim,ADtype>, nstate >; + using ADArrayTensor1 = std::array< Tensor<1,dim,ADtype>, nstate >; // Use quadrature points of neighbor cell // Might want to use the maximum n_quad_pts1 and n_quad_pts2 @@ -304,18 +341,26 @@ namespace PHiLiP std::vector dR2_dW1(n_dofs_current_cell); std::vector dR2_dW2(n_dofs_neighbor_cell); - std::vector normal_int_numerical_flux(n_face_quad_pts); + std::vector conv_num_flux_dot_n(n_face_quad_pts); // Interpolate solution to the face quadrature points std::vector< ADArray > soln_int(n_face_quad_pts); std::vector< ADArray > soln_ext(n_face_quad_pts); - std::vector< ADArrayVector > soln_grad_int(n_face_quad_pts); // Tensor initialize with zeros - std::vector< ADArrayVector > soln_grad_ext(n_face_quad_pts); // Tensor initialize with zeros + std::vector< ADArrayTensor1 > soln_grad_int(n_face_quad_pts); // Tensor initialize with zeros + std::vector< ADArrayTensor1 > soln_grad_ext(n_face_quad_pts); // Tensor initialize with zeros + + std::vector diss_soln_num_flux(n_face_quad_pts); // u* + std::vector diss_auxi_num_flux_dot_n(n_face_quad_pts); // sigma* + + std::vector diss_flux_jump_int(n_face_quad_pts); // u*-u_int + std::vector diss_flux_jump_ext(n_face_quad_pts); // u*-u_ext for (unsigned int iquad=0; iquad normal_int = normals_int[iquad]; + const Tensor<1,dim,ADtype> normal_ext = -normal_int; + for (int istate=0; istateshape_grad(itrial, iquad); } } - normal_int_numerical_flux[iquad] = conv_num_flux->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int); + conv_num_flux_dot_n[iquad] = conv_num_flux->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int); + + diss_soln_num_flux[iquad] = diss_num_flux->evaluate_solution_flux(soln_int[iquad], soln_ext[iquad], normal_int); + + ADArrayTensor1 diss_soln_jump_int, diss_soln_jump_ext; + for (int s=0; sdissipative_flux (soln_int[iquad], diss_soln_jump_int, diss_flux_jump_int[iquad]); + pde_physics->dissipative_flux (soln_ext[iquad], diss_soln_jump_ext, diss_flux_jump_ext[iquad]); + + diss_auxi_num_flux_dot_n[iquad] = diss_num_flux->evaluate_auxiliary_flux( + soln_int[iquad], soln_ext[iquad], + soln_grad_int[iquad], soln_grad_ext[iquad], + normal_int, penalty); } - for (unsigned int itest_current=0; itest_currentshape_value(itest_current,iquad) * - normal_int_numerical_flux[iquad][istate] * - JxW_int[iquad]; + // Convection + rhs[istate] -= fe_values_int->shape_value(itest_int,iquad) * conv_num_flux_dot_n[iquad][istate] * JxW_int[iquad]; + // Diffusive + rhs[istate] -= fe_values_int->shape_value(itest_int,iquad) * diss_auxi_num_flux_dot_n[iquad][istate] * JxW_int[iquad]; + rhs[istate] += fe_values_int->shape_grad(itest_int,iquad) * diss_flux_jump_int[iquad][istate] * JxW_int[iquad]; } - - // // Diffusion - - - // //// Note: The test function is piece-wise defined to be non-zero only on the associated cell - // //// and zero everywhere else. - // //const Tensor< 1, dim, real > test_grad_int = fe_values_int->shape_grad(itest_current, iquad); - // //const Tensor< 1, dim, real > test_grad_ext; // Constructor initializes with zeros - - // //const Tensor< 1, dim, real > normal1 = normals_int[iquad]; - // //const Tensor< 1, dim, ADtype > soln_jump = (soln_int[iquad] - soln_ext[iquad]) * normal1; - // //const Tensor< 1, dim, ADtype > soln_grad_avg = 0.5*(soln_grad_ext[iquad] + soln_grad_int[iquad]); - - // //const Tensor< 1, dim, real > test_jump = (test_int - test_ext) * normal1; - // //const Tensor< 1, dim, real > test_grad_avg = 0.5*(test_grad_int + test_grad_ext); - - // //rhs += (soln_jump * test_grad_avg + soln_grad_avg * test_jump - penalty*soln_jump*test_jump) * JxW_int[iquad]; - - // // Note: The test function is piece-wise defined to be non-zero only on the associated cell - // // and zero everywhere else. - // const real test_int = fe_values_int->shape_value(itest_current, iquad); - // const real test_ext = 0; - - // for (unsigned int idim=0; idimshape_grad(itest_current, iquad)[idim]; - // const real test_grad_ext = 0; - - // // Using normals from interior point of view - // const real normal1 = normals_int[iquad][idim]; - // const ADtype soln_jump = (soln_int[iquad] - soln_ext[iquad]) * normal1; - // const ADtype soln_grad_avg = 0.5*(soln_grad_int[iquad][idim] + soln_grad_ext[iquad][idim]); - // const real test_jump = (test_int - test_ext) * normal1; - // const real test_grad_avg = 0.5*(test_grad_int + test_grad_ext); - // - // //rhs += (soln_jump * test_grad_avg + soln_grad_avg * test_jump - penalty*soln_jump*test_jump) * JxW_int[iquad]; - // } } // ******************* const int ISTATE = 0; - current_cell_rhs(itest_current) += rhs[ISTATE].val(); + current_cell_rhs(itest_int) += rhs[ISTATE].val(); for (unsigned int itrial = 0; itrial < n_dofs_current_cell; ++itrial) { dR1_dW1[itrial] = rhs[ISTATE].dx(itrial); } for (unsigned int itrial = 0; itrial < n_dofs_neighbor_cell; ++itrial) { dR1_dW2[itrial] = rhs[ISTATE].dx(n_dofs_current_cell+itrial); } - system_matrix.add(current_dofs_indices[itest_current], current_dofs_indices, dR1_dW1); - system_matrix.add(current_dofs_indices[itest_current], neighbor_dofs_indices, dR1_dW2); + system_matrix.add(current_dofs_indices[itest_int], current_dofs_indices, dR1_dW1); + system_matrix.add(current_dofs_indices[itest_int], neighbor_dofs_indices, dR1_dW2); } - for (unsigned int itest_neighbor=0; itest_neighborshape_value(itest_neighbor,iquad) * - (-normal_int_numerical_flux[iquad][istate]) * - JxW_int[iquad]; + // Convection + rhs[istate] -= fe_values_ext->shape_value(itest_ext,iquad) * (-conv_num_flux_dot_n[iquad][istate]) * JxW_int[iquad]; + // Diffusive + rhs[istate] -= fe_values_ext->shape_value(itest_ext,iquad) * (-diss_auxi_num_flux_dot_n[iquad][istate]) * JxW_int[iquad]; + rhs[istate] += fe_values_ext->shape_grad(itest_ext,iquad) * diss_flux_jump_ext[iquad][istate] * JxW_int[iquad]; } - - // // Diffusion - - // // Note: The test function is piece-wise defined to be non-zero only on the associated cell - // // and zero everywhere else. - // const real test_int = fe_values_ext->shape_value(itest_neighbor, iquad); - // const real test_ext = 0; - - // for (unsigned int idim=0; idimshape_grad(itest_neighbor, iquad)[idim]; - // const real test_grad_ext = 0; - - // // Using normals from other side - // // So opposite and equal value - // const real flipped_normal1 = -normals_int[iquad][idim]; - // // Flipped soln_ext and soln_int - // const ADtype soln_jump = (soln_ext[iquad] - soln_int[iquad]) * flipped_normal1; - // const ADtype soln_grad_avg = 0.5*(soln_grad_int[iquad][idim] + soln_grad_ext[iquad][idim]); - // const real test_jump = (test_int - test_ext) * flipped_normal1; - // const real test_grad_avg = 0.5*(test_grad_int + test_grad_ext); - // - // //rhs += (soln_jump * test_grad_avg + soln_grad_avg * test_jump - penalty*soln_jump*test_jump) * JxW_int[iquad]; - // } } // ******************* const int ISTATE = 0; - neighbor_cell_rhs(itest_neighbor) += rhs[ISTATE].val(); + neighbor_cell_rhs(itest_ext) += rhs[ISTATE].val(); for (unsigned int itrial = 0; itrial < n_dofs_current_cell; ++itrial) { dR2_dW1[itrial] = rhs[ISTATE].dx(itrial); } for (unsigned int itrial = 0; itrial < n_dofs_neighbor_cell; ++itrial) { dR2_dW2[itrial] = rhs[ISTATE].dx(n_dofs_current_cell+itrial); } - system_matrix.add(neighbor_dofs_indices[itest_neighbor], current_dofs_indices, dR2_dW1); - system_matrix.add(neighbor_dofs_indices[itest_neighbor], neighbor_dofs_indices, dR2_dW2); + system_matrix.add(neighbor_dofs_indices[itest_ext], current_dofs_indices, dR2_dW1); + system_matrix.add(neighbor_dofs_indices[itest_ext], neighbor_dofs_indices, dR2_dW2); } } template void DiscontinuousGalerkin::assemble_face_term_implicit( diff --git a/src/dg.cpp b/src/dg.cpp index 503dfd85c..66752656a 100644 --- a/src/dg.cpp +++ b/src/dg.cpp @@ -70,6 +70,8 @@ namespace PHiLiP pde_physics = PhysicsFactory::create_Physics(parameters->pde_type); conv_num_flux = NumericalFluxFactory::create_convective_numerical_flux (parameters->conv_num_flux_type, pde_physics); + diss_num_flux = NumericalFluxFactory::create_dissipative_numerical_flux + (parameters->diss_num_flux_type, pde_physics); } // Destructor template @@ -99,6 +101,7 @@ namespace PHiLiP void DiscontinuousGalerkin::delete_fe_values () { delete conv_num_flux; + delete diss_num_flux; delete pde_physics; if (fe_values_cell != NULL) delete fe_values_cell; @@ -538,6 +541,44 @@ namespace PHiLiP data_out.write_gnuplot(gnuplot_output); } + template + void DiscontinuousGalerkin::evaluate_inverse_mass_matrices () + { + // Invert and store mass matrix + // Using Gauss-Jordan since it's deal.II's default invert function + // Could store Cholesky decomposition for more efficient pre-processing + const int n_quad_pts = quadrature.size(); + const int n_dofs_per_cell = fe.dofs_per_cell; + + typename DoFHandler::active_cell_iterator + cell = dof_handler.begin_active(), + endc = dof_handler.end(); + + inv_mass_matrix.resize(triangulation->n_active_cells(), + FullMatrix(n_dofs_per_cell)); + FullMatrix mass_matrix(n_dofs_per_cell); + for (; cell!=endc; ++cell) { + + int cell_index = cell->index(); + fe_values_cell->reinit(cell); + + for (int itest=0; itestshape_value(itest,iquad) + * fe_values_cell->shape_value(itrial,iquad) + * fe_values_cell->JxW(iquad); + } + mass_matrix[itrial][itest] = mass_matrix[itest][itrial]; + } + } + inv_mass_matrix[cell_index].invert(mass_matrix); + } + } + + template class DiscontinuousGalerkin ; diff --git a/src/dg.h b/src/dg.h index c056508a9..4b4411dc5 100644 --- a/src/dg.h +++ b/src/dg.h @@ -44,6 +44,7 @@ namespace PHiLiP void allocate_system (); void assemble_system (); + void evaluate_inverse_mass_matrices (); double get_residual_l2norm (); void delete_fe_values (); @@ -84,6 +85,7 @@ namespace PHiLiP /// Contains the physics of the PDE Physics > *pde_physics; NumericalFluxConvective > *conv_num_flux; + NumericalFluxDissipative > *diss_num_flux; void allocate_system_explicit (); @@ -141,6 +143,8 @@ namespace PHiLiP Vector ¤t_cell_rhs, Vector &neighbor_cell_rhs); + std::vector> inv_mass_matrix; + // QGauss is Gauss-Legendre quadrature nodes const QGauss quadrature; const QGauss face_quadrature; diff --git a/src/grid_study.cpp b/src/grid_study.cpp index bfcd819f5..35f69319e 100644 --- a/src/grid_study.cpp +++ b/src/grid_study.cpp @@ -90,7 +90,7 @@ namespace PHiLiP // p0 tends to require a finer grid to reach asymptotic region unsigned int n_grids = n_grids_input; - if (poly_degree == 0) n_grids = n_grids_input + 2; + if (poly_degree <= 1) n_grids = n_grids_input + 1; std::vector n_1d_cells(n_grids); n_1d_cells[0] = initial_grid_size; @@ -168,6 +168,8 @@ namespace PHiLiP //dg.set_physics(physics); dg.allocate_system (); + dg.evaluate_inverse_mass_matrices(); + //ODESolver *ode_solver = ODESolverFactory::create_ODESolver(parameters.solver_type); ODESolver *ode_solver = ODESolverFactory::create_ODESolver(&dg); diff --git a/src/linear_solver.cpp b/src/linear_solver.cpp index fc45a14cc..c61d96c09 100644 --- a/src/linear_solver.cpp +++ b/src/linear_solver.cpp @@ -20,15 +20,18 @@ namespace PHiLiP //system_matrix.print(std::cout, true); //solution.print(std::cout); - //right_hand_side.print(std::cout); - //FullMatrix fullA(system_matrix.m()); - //fullA.copy_from(system_matrix); - //std::cout<<"Dense matrix:"<linear_solver_type == LinSolvParam::LinearSolverType::direct) { + if (param->linear_solver_output == Parameters::OutputType::verbose) { + right_hand_side.print(std::cout); + FullMatrix fullA(system_matrix.m()); + fullA.copy_from(system_matrix); + std::cout<<"Dense matrix:"< #include #include "numerical_flux.h" +#include "viscous_numerical_flux.h" namespace PHiLiP { @@ -87,30 +88,6 @@ namespace PHiLiP return numerical_flux_dot_n; } - template - NumericalFluxDissipative::~NumericalFluxDissipative() {} - - template - void SymmetricInternalPenalty - ::evaluate_flux ( - const std::array &soln_int, - const std::array &soln_ext, - const std::array, nstate> &soln_grad_int, - const std::array, nstate> &soln_grad_ext, - const Tensor<1,dim,real> &normal1, - std::array &soln_flux, - std::array, nstate> &grad_flux) const - { - std::array soln_avg = array_average(soln_int, soln_ext); - - //std::array,nstate> diffusion_matrix_int = - // pde_physics->diffusion_matrix(soln_int); - - //std::array,nstate> diffusion_matrix_ext = - // pde_physics->diffusion_matrix(soln_ext); - } - - // Instantiation template class NumericalFluxConvective; template class NumericalFluxConvective >; @@ -118,11 +95,6 @@ namespace PHiLiP template class LaxFriedrichs; template class LaxFriedrichs >; - template class NumericalFluxDissipative; - template class NumericalFluxDissipative >; - - template class SymmetricInternalPenalty; - template class SymmetricInternalPenalty >; template class NumericalFluxFactory; template class NumericalFluxFactory >; diff --git a/src/numerical_flux/numerical_flux.h b/src/numerical_flux/numerical_flux.h index c797c59fb..08d85456b 100644 --- a/src/numerical_flux/numerical_flux.h +++ b/src/numerical_flux/numerical_flux.h @@ -3,6 +3,7 @@ #include #include "physics/physics.h" +#include "numerical_flux/viscous_numerical_flux.h" namespace PHiLiP { using namespace dealii; @@ -46,56 +47,6 @@ namespace PHiLiP }; - /// Numerical flux associated with dissipation - template - class NumericalFluxDissipative - { - public: - /// Base class destructor. - /// Abstract classes required virtual destructors. - /// Even if it is a pure function, its definition is still required. - virtual ~NumericalFluxDissipative() = 0; - - virtual void evaluate_flux ( - const std::array &soln_int, - const std::array &soln_ext, - const std::array, nstate> &soln_grad_int, - const std::array, nstate> &soln_grad_ext, - const Tensor<1,dim,real> &normal1, - std::array &soln_flux, - std::array, nstate> &grad_flux) const = 0; - - }; - - template - class SymmetricInternalPenalty: public NumericalFluxDissipative - { - public: - /// Constructor - SymmetricInternalPenalty(Physics *physics_input) - : - pde_physics(physics_input) - {}; - /// Destructor - ~SymmetricInternalPenalty() {}; - - /// Evaluate solution and gradient flux - /* $\hat{u} = {u_h}$, - * $ \hat{A} = {{ A \nabla u_h }} - \mu {{ A }} [[ u_h ]] $ - */ - void evaluate_flux ( - const std::array &soln_int, - const std::array &soln_ext, - const std::array, nstate> &soln_grad_int, - const std::array, nstate> &soln_grad_ext, - const Tensor<1,dim,real> &normal1, - std::array &soln_flux, - std::array, nstate> &grad_flux) const; - protected: - const Physics *pde_physics; - - }; - template class NumericalFluxFactory diff --git a/src/numerical_flux/viscous_numerical_flux.cpp b/src/numerical_flux/viscous_numerical_flux.cpp new file mode 100644 index 000000000..7f1ac5b64 --- /dev/null +++ b/src/numerical_flux/viscous_numerical_flux.cpp @@ -0,0 +1,157 @@ +#include +#include +#include "viscous_numerical_flux.h" + +namespace PHiLiP +{ + using namespace dealii; + using AllParam = Parameters::AllParameters; + + // Protyping low level functions + template + std::array array_average( + const std::array &array1, + const std::array &array2) + { + std::array array_average; + for (int s=0; s + std::array,nstate> array_jump( + const std::array &array1, + const std::array &array2, + const Tensor<1,dim,real> &normal1) + { + std::array,nstate> array_jump; + for (int s=0; s + NumericalFluxDissipative::~NumericalFluxDissipative() {} + + + //template + //void NumericalFluxDissipative + //::evaluate_auxiliary ( + // const std::vector> &soln_nodal_face_int, + // const std::vector> &soln_nodal_face_ext, + // const std::vector> &soln_nodal_face_flux, + // const std::vector> &soln_grad_nodal_volume_int, + // const std::vector> &soln_grad_nodal_volume_ext, + // const std::vector> &normal_int, + // std::vector> &auxiliary_modal_int, + // std::vector> &auxiliary_modal_ext) const + //{ + // // Need some kind of assert to confirm that A and A_transpose correspond + // // to the current interior and exterior cell + + // // Interpolate solution to the face quadrature points + // std::vector< ADArray > soln_int(n_face_quad_pts); + // std::vector< ADArray > soln_ext(n_face_quad_pts); + + // std::vector< ADArrayVector > soln_grad_int(n_face_quad_pts); // Tensor initialize with zeros + // std::vector< ADArrayVector > soln_grad_ext(n_face_quad_pts); // Tensor initialize with zeros + // for (unsigned int iquad=0; iquad normal_int = normals_int[iquad]; + + // for (int istate=0; istateshape_value(itrial, iquad); + // soln_grad_int[iquad][istate] += current_solution_ad[itrial][istate] * fe_values_int->shape_grad(itrial, iquad); + // } + // for (unsigned int itrial=0; itrialshape_value(itrial, iquad); + // soln_grad_ext[iquad][istate] += neighbor_solution_ad[itrial][istate] * fe_values_ext->shape_grad(itrial, iquad); + // } + // } + // normal_int_numerical_flux[iquad] = conv_num_flux->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int); + + // } + //} + + + //template + //void NumericalFluxDissipative + //::assemble_auxiliary_cell ( + // const std::array, nstate> &soln_grad_int) const + //{ + //} + + template + std::array SymmetricInternalPenalty + ::evaluate_solution_flux ( + const std::array &soln_int, + const std::array &soln_ext, + const Tensor<1,dim,real> &normal_int) const + { + std::array soln_avg = array_average(soln_int, soln_ext); + + //std::array,nstate> diffusion_matrix_int = + // pde_physics->diffusion_matrix(soln_int); + + //std::array,nstate> diffusion_matrix_ext = + // pde_physics->diffusion_matrix(soln_ext); + + return soln_avg; + } + + template + std::array SymmetricInternalPenalty + ::evaluate_auxiliary_flux ( + const std::array &soln_int, + const std::array &soln_ext, + const std::array, nstate> &soln_grad_int, + const std::array, nstate> &soln_grad_ext, + const Tensor<1,dim,real> &normal_int, + const real &penalty) const + { + using ArrayTensor1 = std::array, nstate>; + ArrayTensor1 phys_flux_int, phys_flux_ext; + + // {{A*grad_u}} + pde_physics->dissipative_flux (soln_int, soln_grad_int, phys_flux_int); + pde_physics->dissipative_flux (soln_ext, soln_grad_ext, phys_flux_ext); + ArrayTensor1 phys_flux_avg = array_average>(phys_flux_int, phys_flux_ext); + + // {{A}}*[[u]] + ArrayTensor1 soln_jump = array_jump(soln_int, soln_ext, normal_int); + ArrayTensor1 A_jumpu_int, A_jumpu_ext; + pde_physics->dissipative_flux (soln_int, soln_jump, A_jumpu_int); + pde_physics->dissipative_flux (soln_ext, soln_jump, A_jumpu_ext); + const ArrayTensor1 A_jumpu_avg = array_average>(A_jumpu_int, A_jumpu_ext); + + + std::array auxiliary_flux_dot_n; + for (int s=0; s; + template class NumericalFluxDissipative >; + + template class SymmetricInternalPenalty; + template class SymmetricInternalPenalty >; + +} diff --git a/src/numerical_flux/viscous_numerical_flux.h b/src/numerical_flux/viscous_numerical_flux.h new file mode 100644 index 000000000..8e27dd606 --- /dev/null +++ b/src/numerical_flux/viscous_numerical_flux.h @@ -0,0 +1,77 @@ +#ifndef __VISCOUS_NUMERICAL_FLUX__ +#define __VISCOUS_NUMERICAL_FLUX__ + +#include +#include "physics/physics.h" +namespace PHiLiP +{ + using namespace dealii; + using AllParam = Parameters::AllParameters; + + /// Numerical flux associated with dissipation + template + class NumericalFluxDissipative + { + public: + /// Base class destructor. + /// Abstract classes required virtual destructors. + /// Even if it is a pure function, its definition is still required. + virtual ~NumericalFluxDissipative() = 0; + + virtual std::array evaluate_solution_flux ( + const std::array &soln_int, + const std::array &soln_ext, + const Tensor<1,dim,real> &normal_int) const = 0; + + virtual std::array evaluate_auxiliary_flux ( + const std::array &soln_int, + const std::array &soln_ext, + const std::array, nstate> &soln_grad_int, + const std::array, nstate> &soln_grad_ext, + const Tensor<1,dim,real> &normal_int, + const real &penalty) const = 0; + + Tensor<1,dim, Tensor<1,nstate,real>> diffusion_matrix_int; + Tensor<1,dim, Tensor<1,nstate,real>> diffusion_matrix_int_transpose; + Tensor<1,dim, Tensor<1,nstate,real>> diffusion_matrix_ext; + Tensor<1,dim, Tensor<1,nstate,real>> diffusion_matrix_ext_transpose; + + }; + + template + class SymmetricInternalPenalty: public NumericalFluxDissipative + { + public: + /// Constructor + SymmetricInternalPenalty(Physics *physics_input) + : + pde_physics(physics_input) + {}; + /// Destructor + ~SymmetricInternalPenalty() {}; + + /// Evaluate solution and gradient flux + /* $\hat{u} = {u_h}$, + * $ \hat{A} = {{ A \nabla u_h }} - \mu {{ A }} [[ u_h ]] $ + */ + std::array evaluate_solution_flux ( + const std::array &soln_int, + const std::array &soln_ext, + const Tensor<1,dim,real> &normal_int) const; + + std::array evaluate_auxiliary_flux ( + const std::array &soln_int, + const std::array &soln_ext, + const std::array, nstate> &soln_grad_int, + const std::array, nstate> &soln_grad_ext, + const Tensor<1,dim,real> &normal_int, + const real &penalty) const; + + protected: + const Physics *pde_physics; + + }; + +} + +#endif diff --git a/src/ode_solver.cpp b/src/ode_solver.cpp index 62874883b..3a8ef7caa 100644 --- a/src/ode_solver.cpp +++ b/src/ode_solver.cpp @@ -16,25 +16,39 @@ namespace PHiLiP dg->assemble_system (); this->residual_norm = dg->get_residual_l2norm(); this->residual_norm = 1; // Always do at least 1 iteration + double update_norm = 1; // Always do at least 1 iteration this->current_iteration = 0; - while ( this->residual_norm > parameters->nonlinear_steady_residual_tolerance + while ( + this->residual_norm > parameters->nonlinear_steady_residual_tolerance + && update_norm > parameters->nonlinear_steady_residual_tolerance && this->current_iteration < parameters->nonlinear_max_iterations ) { - ++this->current_iteration; - if ((this->parameters->ode_output) == Parameters::OutputType::verbose && (this->current_iteration%parameters->print_iteration_modulo) == 0 ) std::cout << " Iteration: " << this->current_iteration << " Residual norm: " << this->residual_norm << std::endl; + if ((this->parameters->ode_output) == Parameters::OutputType::verbose && + (this->current_iteration%parameters->print_iteration_modulo) == 0 ) + std::cout << " Assembling system... "; + dg->assemble_system (); + + if ((this->parameters->ode_output) == Parameters::OutputType::verbose && + (this->current_iteration%parameters->print_iteration_modulo) == 0 ) + std::cout << " Evaluating system update... "; evaluate_solution_update (); + + //this->solution_update *= 0.1; + update_norm = this->solution_update.l2_norm(); dg->solution += this->solution_update; - dg->assemble_system (); this->residual_norm = dg->get_residual_l2norm(); + + ++(this->current_iteration); + } return 1; } diff --git a/src/parameters.cpp b/src/parameters.cpp index 255f4e38a..f1106fb54 100644 --- a/src/parameters.cpp +++ b/src/parameters.cpp @@ -74,7 +74,7 @@ namespace Parameters { prm.enter_subsection("ODE solver"); { - prm.declare_entry("ode_output", "quiet", + prm.declare_entry("ode_output", "verbose", Patterns::Selection("quiet|verbose"), "State whether output from ODE solver should be printed. " "Choices are ."); diff --git a/src/physics/CMakeLists.txt b/src/physics/CMakeLists.txt index ef3875755..b828b426c 100644 --- a/src/physics/CMakeLists.txt +++ b/src/physics/CMakeLists.txt @@ -1,7 +1,7 @@ set(SOURCE - linear_advection.cpp - diffusion.cpp - convection_diffusion.cpp + #linear_advection.cpp + #diffusion.cpp + #convection_diffusion.cpp physics.cpp ) diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index 21097a6df..b8eb94878 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -35,6 +35,20 @@ namespace PHiLiP template Physics::~Physics() {} + template + void Physics + ::dissipative_flux_A_gradu ( + const real scaling, + const std::array &solution, + const std::array,nstate> &solution_gradient, + std::array,nstate> &dissipative_flux) const + { + const std::array,nstate> dissipation = apply_diffusion_matrix(solution, solution_gradient); + for (int s=0; s void Physics @@ -51,6 +65,27 @@ namespace PHiLiP if (dim==3) uexact[ISTATE] = sin(a*pos[0]+d)*sin(b*pos[1]+e)*sin(c*pos[2]+f); solution = uexact; } + template + void Physics + ::manufactured_gradient (const Point &pos, std::array,nstate> &solution_gradient) const + { + std::array uexact; + + using phys = Physics; + const double a = phys::freq_x, b = phys::freq_y, c = phys::freq_z; + const double d = phys::offs_x, e = phys::offs_y, f = phys::offs_z; + const int ISTATE = 0; + if (dim==1) { + solution_gradient[ISTATE][0] = a*cos(a*pos[0]+d); + } else if (dim==2) { + solution_gradient[ISTATE][0] = a*cos(a*pos[0]+d)*sin(b*pos[1]+e); + solution_gradient[ISTATE][1] = b*sin(a*pos[0]+d)*cos(b*pos[1]+e); + } else if (dim==3) { + solution_gradient[ISTATE][0] = a*cos(a*pos[0]+d)*sin(b*pos[1]+e)*sin(c*pos[2]+f); + solution_gradient[ISTATE][1] = b*sin(a*pos[0]+d)*cos(b*pos[1]+e)*sin(c*pos[2]+f); + solution_gradient[ISTATE][2] = c*sin(a*pos[0]+d)*sin(b*pos[1]+e)*cos(c*pos[2]+f); + } + } template double Physics @@ -126,5 +161,282 @@ namespace PHiLiP template class PhysicsFactory >; template class PhysicsFactory; + // Linear advection functions + template + Tensor<1,dim,real> LinearAdvection + ::advection_speed () const + { + Tensor<1,dim,real> advection_speed; + + if(dim >= 1) advection_speed[0] = this->velo_x; + if(dim >= 2) advection_speed[1] = this->velo_y; + if(dim >= 3) advection_speed[2] = this->velo_z; + + return advection_speed; + } + + template + std::array LinearAdvection + ::convective_eigenvalues ( + const std::array &/*solution*/, + const Tensor<1,dim,real> &normal) const + { + std::array eig; + const Tensor<1,dim,real> advection_speed = this->advection_speed(); + for (int i=0; i + void LinearAdvection + ::convective_flux ( + const std::array &solution, + std::array,nstate> &conv_flux) const + { + // Assert conv_flux dimensions + const Tensor<1,dim,real> velocity_field = this->advection_speed(); + for (int i=0; i + std::array,nstate> LinearAdvection + ::apply_diffusion_matrix( + const std::array &solution, + const std::array,nstate> &solution_grad) const + { + std::array,nstate> zero; // deal.II tensors are initialized with zeros + return zero; + } + + template + void LinearAdvection + ::dissipative_flux ( + const std::array &solution, + const std::array,nstate> &solution_gradient, + std::array,nstate> &diss_flux) const + { + // No dissipation + const double diff_coeff = this->diff_coeff; + for (int i=0; i + void LinearAdvection + ::source_term ( + const Point &pos, + const std::array &/*solution*/, + std::array &source) const + { + const Tensor<1,dim,real> vel = this->advection_speed(); + using phys = Physics; + const double a = phys::freq_x, b = phys::freq_y, c = phys::freq_z; + const double d = phys::offs_x, e = phys::offs_y, f = phys::offs_z; + const int ISTATE = 0; + if (dim==1) { + const real x = pos[0]; + source[ISTATE] = vel[0]*a*cos(a*x+d); + } else if (dim==2) { + const real x = pos[0], y = pos[1]; + source[ISTATE] = vel[0]*a*cos(a*x+d)*sin(b*y+e) + + vel[1]*b*sin(a*x+d)*cos(b*y+e); + } else if (dim==3) { + const real x = pos[0], y = pos[1], z = pos[2]; + source[ISTATE] = vel[0]*a*cos(a*x+d)*sin(b*y+e)*sin(c*z+f) + + vel[1]*b*sin(a*x+d)*cos(b*y+e)*sin(c*z+f) + + vel[2]*c*sin(a*x+d)*sin(b*y+e)*cos(c*z+f); + } + } + + template class LinearAdvection < PHILIP_DIM, 1, Sacado::Fad::DFad >; + template class LinearAdvection < PHILIP_DIM, 1, double >; + + template + void Diffusion + ::convective_flux ( + const std::array &/*solution*/, + std::array,nstate> &/*conv_flux*/) const + { } + + template + std::array Diffusion + ::convective_eigenvalues( + const std::array &/*solution*/, + const Tensor<1,dim,real> &/*normal*/) const + { + std::array eig; + for (int i=0; i + std::array,nstate> Diffusion + ::apply_diffusion_matrix( + const std::array &solution, + const std::array,nstate> &solution_grad) const + { + // deal.II tensors are initialized with zeros + std::array,nstate> diffusion; + for (int d=0; d + void Diffusion + ::dissipative_flux ( + const std::array &solution, + const std::array,nstate> &solution_gradient, + std::array,nstate> &diss_flux) const + { + const double diff_coeff = this->diff_coeff; + for (int i=0; i + void Diffusion + ::source_term ( + const Point &pos, + const std::array &/*solution*/, + std::array &source) const + { + using phys = Physics; + const double a = phys::freq_x, b = phys::freq_y, c = phys::freq_z; + const double d = phys::offs_x, e = phys::offs_y, f = phys::offs_z; + const double diff_coeff = this->diff_coeff; + const int ISTATE = 0; + if (dim==1) { + const real x = pos[0]; + source[ISTATE] = diff_coeff*a*a*sin(a*x+d); + } else if (dim==2) { + const real x = pos[0], y = pos[1]; + source[ISTATE] = diff_coeff*a*a*sin(a*x+d)*sin(b*y+e) + + diff_coeff*b*b*sin(a*x+d)*sin(b*y+e); + } else if (dim==3) { + const real x = pos[0], y = pos[1], z = pos[2]; + + source[ISTATE] = diff_coeff*a*a*sin(a*x+d)*sin(b*y+e)*sin(c*z+f) + + diff_coeff*b*b*sin(a*x+d)*sin(b*y+e)*sin(c*z+f) + + diff_coeff*c*c*sin(a*x+d)*sin(b*y+e)*sin(c*z+f); + } + } + + template class Diffusion < PHILIP_DIM, 1, Sacado::Fad::DFad >; + template class Diffusion < PHILIP_DIM, 1, double >; + + template + void ConvectionDiffusion + ::convective_flux ( + const std::array &solution, + std::array,nstate> &conv_flux) const + { + const Tensor<1,dim,real> velocity_field = this->advection_speed(); + for (int i=0; i + Tensor<1,dim,real> ConvectionDiffusion + ::advection_speed () const + { + Tensor<1,dim,real> advection_speed; + + if(dim >= 1) advection_speed[0] = this->velo_x; + if(dim >= 2) advection_speed[1] = this->velo_y; + if(dim >= 3) advection_speed[2] = this->velo_z; + return advection_speed; + } + + template + std::array ConvectionDiffusion + ::convective_eigenvalues ( + const std::array &/*solution*/, + const Tensor<1,dim,real> &normal) const + { + std::array eig; + const Tensor<1,dim,real> advection_speed = this->advection_speed(); + for (int i=0; i + std::array,nstate> ConvectionDiffusion + ::apply_diffusion_matrix( + const std::array &solution, + const std::array,nstate> &solution_grad) const + { + // deal.II tensors are initialized with zeros + std::array,nstate> diffusion; + for (int d=0; d + void ConvectionDiffusion + ::dissipative_flux ( + const std::array &solution, + const std::array,nstate> &solution_gradient, + std::array,nstate> &diss_flux) const + { + const double diff_coeff = this->diff_coeff; + for (int i=0; i + void ConvectionDiffusion + ::source_term ( + const Point &pos, + const std::array &/*solution*/, + std::array &source) const + { + const Tensor<1,dim,real> velocity_field = this->advection_speed(); + using phys = Physics; + const double a = phys::freq_x, b = phys::freq_y, c = phys::freq_z; + const double d = phys::offs_x, e = phys::offs_y, f = phys::offs_z; + + const double diff_coeff = this->diff_coeff; + const int ISTATE = 0; + if (dim==1) { + const real x = pos[0]; + source[ISTATE] = velocity_field[0]*a*cos(a*x+d) + + diff_coeff*a*a*sin(a*x+d); + } else if (dim==2) { + const real x = pos[0], y = pos[1]; + source[ISTATE] = velocity_field[0]*a*cos(a*x+d)*sin(b*y+e) + + velocity_field[1]*b*sin(a*x+d)*cos(b*y+e) + + diff_coeff*a*a*sin(a*x+d)*sin(b*y+e) + + diff_coeff*b*b*sin(a*x+d)*sin(b*y+e); + } else if (dim==3) { + const real x = pos[0], y = pos[1], z = pos[2]; + source[ISTATE] = velocity_field[0]*a*cos(a*x+d)*sin(b*y+e)*sin(c*z+f) + + velocity_field[1]*b*sin(a*x+d)*cos(b*y+e)*sin(c*z+f) + + velocity_field[2]*c*sin(a*x+d)*sin(b*y+e)*cos(c*z+f) + + diff_coeff*a*a*sin(a*x+d)*sin(b*y+e)*sin(c*z+f) + + diff_coeff*b*b*sin(a*x+d)*sin(b*y+e)*sin(c*z+f) + + diff_coeff*c*c*sin(a*x+d)*sin(b*y+e)*sin(c*z+f); + } + } + // Instantiate + template class ConvectionDiffusion < PHILIP_DIM, 1, double >; + template class ConvectionDiffusion < PHILIP_DIM, 1, Sacado::Fad::DFad >; + + } // end of PHiLiP namespace diff --git a/src/physics/physics.h b/src/physics/physics.h index 1d7ff2bd0..ab0755cc4 100644 --- a/src/physics/physics.h +++ b/src/physics/physics.h @@ -32,6 +32,9 @@ namespace PHiLiP virtual void manufactured_solution ( const Point &pos, std::array &solution) const; + virtual void manufactured_gradient ( + const Point &pos, + std::array,nstate> &solution_gradient) const; /// Returns the integral of the manufactured solution over the hypercube [0,1] /// @@ -51,8 +54,17 @@ namespace PHiLiP const Tensor<1,dim,real> &/*normal*/) const = 0; // Evaluate the diffusion matrix $ A $ such that $F_v = A \nabla u$ - virtual std::array,nstate> diffusion_matrix ( - const std::array &solution) const = 0; + virtual std::array,nstate> apply_diffusion_matrix ( + const std::array &solution, + const std::array,nstate> &solution_grad) const = 0; + + // Dissipative fluxes that will be differentiated once in space + // Evaluates the dissipative flux through the linearization F = A(u)*grad(u) + void dissipative_flux_A_gradu ( + const real scaling, + const std::array &solution, + const std::array,nstate> &solution_gradient, + std::array,nstate> &diss_flux) const; // Dissipative fluxes that will be differentiated once in space virtual void dissipative_flux ( @@ -92,7 +104,7 @@ namespace PHiLiP //const double offs_x = 1, offs_y = 1.2, offs_z = 1.5; const double pi = atan(1)*4.0; - const double freq_x = 1.59/dim, freq_y = 2*1.81/dim, freq_z = 3*1.76/dim; + const double freq_x = 0.59/dim, freq_y = 2*0.81/dim, freq_z = 3*0.76/dim; const double offs_x = 1, offs_y = 1.2, offs_z = 1.5; const double velo_x = exp(1)/2, velo_y =-pi/4.0, velo_z = sqrt(2); //const double velo_x = 1.0, velo_y =-pi/4.0, velo_z = sqrt(2); @@ -129,8 +141,9 @@ namespace PHiLiP const Tensor<1,dim,real> &normal) const; // Diffusion matrix: 0 - std::array,nstate> diffusion_matrix ( - const std::array &solution) const; + std::array,nstate> apply_diffusion_matrix ( + const std::array &solution, + const std::array,nstate> &solution_grad) const; // Dissipative flux: 0 void dissipative_flux ( @@ -171,8 +184,9 @@ namespace PHiLiP const Tensor<1,dim,real> &/*normal*/) const; // Diffusion matrix is identity - std::array,nstate> diffusion_matrix ( - const std::array &solution) const; + std::array,nstate> apply_diffusion_matrix ( + const std::array &solution, + const std::array,nstate> &solution_grad) const; // Dissipative flux: u void dissipative_flux ( @@ -208,8 +222,9 @@ namespace PHiLiP const Tensor<1,dim,real> &/*normal*/) const; // Diffusion matrix is identity - std::array,nstate> diffusion_matrix ( - const std::array &solution) const; + std::array,nstate> apply_diffusion_matrix ( + const std::array &solution, + const std::array,nstate> &solution_grad) const; // Dissipative flux: u void dissipative_flux ( diff --git a/tests/convection_diffusion_implicit/1d_convection_diffusion_implicit.prm b/tests/convection_diffusion_implicit/1d_convection_diffusion_implicit.prm index 4a761af40..45df15016 100644 --- a/tests/convection_diffusion_implicit/1d_convection_diffusion_implicit.prm +++ b/tests/convection_diffusion_implicit/1d_convection_diffusion_implicit.prm @@ -4,15 +4,18 @@ set dimension = 1 # The PDE we want to solve. Choices are -# . +# . set pde_type = convection_diffusion subsection ODE solver + + set ode_output = verbose + # Maximum nonlinear solver iterations set nonlinear_max_iterations = 500000 # Nonlinear solver residual tolerance - set nonlinear_steady_residual_tolerance = 1e-13 + set nonlinear_steady_residual_tolerance = 1e-12 # Print every print_iteration_modulo iterations of the nonlinear solver set print_iteration_modulo = 1 @@ -26,15 +29,15 @@ subsection manufactured solution convergence study set degree_end = 3 # Starting degree for convergence study - set degree_start = 0 + set degree_start = 1 # Multiplier on grid size. nth-grid will be of size # (initial_grid^grid_progression)^dim set grid_progression = 1.5 # Initial grid of size (initial_grid_size)^dim - set initial_grid_size = 2 + set initial_grid_size = 3 # Number of grids in grid study - set number_of_grids = 4 + set number_of_grids = 6 end diff --git a/tests/convection_diffusion_implicit/2d_convection_diffusion_implicit.prm b/tests/convection_diffusion_implicit/2d_convection_diffusion_implicit.prm index 4f6370bec..7a926b2ac 100644 --- a/tests/convection_diffusion_implicit/2d_convection_diffusion_implicit.prm +++ b/tests/convection_diffusion_implicit/2d_convection_diffusion_implicit.prm @@ -5,7 +5,7 @@ set dimension = 2 # The PDE we want to solve. Choices are # . -set pde_type = advection +set pde_type = convection_diffusion subsection ODE solver # Maximum nonlinear solver iterations @@ -26,7 +26,7 @@ subsection manufactured solution convergence study set degree_end = 3 # Starting degree for convergence study - set degree_start = 0 + set degree_start = 1 # Multiplier on grid size. nth-grid will be of size # (initial_grid^grid_progression)^dim @@ -36,6 +36,6 @@ subsection manufactured solution convergence study set initial_grid_size = 2 # Number of grids in grid study - set number_of_grids = 4 + set number_of_grids = 5 end diff --git a/tests/convection_diffusion_implicit/3d_convection_diffusion_implicit.prm b/tests/convection_diffusion_implicit/3d_convection_diffusion_implicit.prm index 95026a42f..46a117c34 100644 --- a/tests/convection_diffusion_implicit/3d_convection_diffusion_implicit.prm +++ b/tests/convection_diffusion_implicit/3d_convection_diffusion_implicit.prm @@ -5,7 +5,7 @@ set dimension = 3 # The PDE we want to solve. Choices are # . -set pde_type = advection +set pde_type = convection_diffusion subsection ODE solver # Maximum nonlinear solver iterations @@ -26,7 +26,7 @@ subsection manufactured solution convergence study set degree_end = 3 # Starting degree for convergence study - set degree_start = 0 + set degree_start = 1 # Multiplier on grid size. nth-grid will be of size # (initial_grid^grid_progression)^dim diff --git a/tests/diffusion_implicit/2d_diffusion_implicit.prm b/tests/diffusion_implicit/2d_diffusion_implicit.prm index 68c515662..b11f2ca19 100644 --- a/tests/diffusion_implicit/2d_diffusion_implicit.prm +++ b/tests/diffusion_implicit/2d_diffusion_implicit.prm @@ -26,7 +26,7 @@ subsection manufactured solution convergence study set degree_end = 3 # Starting degree for convergence study - set degree_start = 2 + set degree_start = 1 # Multiplier on grid size. nth-grid will be of size # (initial_grid^grid_progression)^dim @@ -36,6 +36,6 @@ subsection manufactured solution convergence study set initial_grid_size = 2 # Number of grids in grid study - set number_of_grids = 4 + set number_of_grids = 5 end diff --git a/tests/numerical_flux/numerical_flux_conservation.cpp b/tests/numerical_flux/numerical_flux_conservation.cpp index b54aa94d6..5de493ac0 100644 --- a/tests/numerical_flux/numerical_flux_conservation.cpp +++ b/tests/numerical_flux/numerical_flux_conservation.cpp @@ -1,3 +1,6 @@ +#include + +#include "parameters.h" #include "parameters.h" #include "physics/physics.h" #include "numerical_flux/numerical_flux.h" @@ -6,65 +9,148 @@ using PDEType = Parameters::AllParameters::PartialDifferentialEquation; using ConvType = Parameters::AllParameters::ConvectiveNumericalFlux; using DissType = Parameters::AllParameters::DissipativeNumericalFlux; +const double TOLERANCE = 1E-12; + template -int test_numerical_flux_conservation (const PDEType pde_type, const ConvType conv_type) +void set_solution ( + std::array &soln_int, + std::array &soln_ext, + std::array, nstate> &soln_grad_int, + std::array, nstate> &soln_grad_ext, + dealii::Tensor<1,dim,double> &normal_int) { - const double TOLERANCE = 1E-12; - std::cout << std::setprecision(std::numeric_limits::digits10 + 1); - std::cout << std::scientific; - - - using namespace PHiLiP; - Physics *pde_physics = PhysicsFactory::create_Physics(pde_type); - - NumericalFluxConvective *conv_num_flux = - NumericalFluxFactory - ::create_convective_numerical_flux (conv_type, pde_physics); - - Tensor<1,dim,double> normal_int; for (int d=0; d soln_int, soln_ext; for (int s=0; s conv_num_flux_dot_n_1 = conv_num_flux->evaluate_flux(soln_int, soln_ext, normal_int); - std::array conv_num_flux_dot_n_2 = conv_num_flux->evaluate_flux(soln_ext, soln_int, -normal_int); + for (int d=0; d +void compare_array ( const std::array &array1, const std::array &array2, double scale2) +{ for (int s=0; s (diss_num_flux_dot_n_1, diss_num_flux_dot_n_2, 1.0); + + std::cout << "Dissipative auxiliary flux conservation (should be equal and opposite since it is dotted with normal)" << std::endl; + compare_array (diss_auxi_num_flux_dot_n_1, diss_auxi_num_flux_dot_n_2, -1.0); + + delete diss_num_flux; delete pde_physics; return 0; } template -int test_numerical_flux_consistency (const PDEType pde_type, const ConvType conv_type) +int test_dissipative_numerical_flux_consistency (const PDEType pde_type, const DissType diss_type) { - const double TOLERANCE = 1E-12; - std::cout << std::setprecision(std::numeric_limits::digits10 + 1); - std::cout << std::scientific; + using namespace PHiLiP; + Physics *pde_physics = PhysicsFactory::create_Physics(pde_type); + + NumericalFluxDissipative *diss_num_flux = + NumericalFluxFactory + ::create_dissipative_numerical_flux (diss_type, pde_physics); + + Tensor<1,dim,double> normal_int; + std::array soln_int, soln_ext; + std::array, nstate> soln_grad_int, soln_grad_ext; + set_solution (soln_int, soln_ext, soln_grad_int, soln_grad_ext, normal_int); + + // Copy state to ext cell + soln_int = soln_ext; + soln_grad_int = soln_grad_ext; + // Evaluate numerical fluxes + std::array diss_soln_num_flux_dot_n = diss_num_flux->evaluate_flux(soln_int, soln_ext, normal_int); + double penalty = 100; + std::array diss_auxi_num_flux_dot_n = diss_num_flux->evaluate_auxiliary_flux( + soln_int, soln_ext, + soln_grad_int, soln_grad_ext, + normal_int, penalty); + + std::array, nstate> diss_phys_flux_int; + pde_physics->dissipative_flux (soln_int, diss_phys_flux_int); + + std::array diss_phys_flux_dot_n; + for (int s=0; s (diss_soln_num_flux_dot_n, soln_int, 1.0); + + std::cout << "Dissipative auxiliary flux should be consistent (equal) with gradient, when same values on each side of boundary" << std::endl; + compare_array (diss_auxi_num_flux_dot_n, diss_phys_flux_int, 1.0); + + delete diss_num_flux; + delete pde_physics; + + return 0; +} + +template +int test_convective_numerical_flux_conservation (const PDEType pde_type, const ConvType conv_type) +{ using namespace PHiLiP; Physics *pde_physics = PhysicsFactory::create_Physics(pde_type); @@ -73,16 +159,40 @@ int test_numerical_flux_consistency (const PDEType pde_type, const ConvType conv ::create_convective_numerical_flux (conv_type, pde_physics); Tensor<1,dim,double> normal_int; - for (int d=0; d soln_int, soln_ext; + std::array, nstate> soln_grad_int, soln_grad_ext; + set_solution (soln_int, soln_ext, soln_grad_int, soln_grad_ext, normal_int); + + std::array conv_num_flux_dot_n_1 = conv_num_flux->evaluate_flux(soln_int, soln_ext, normal_int); + std::array conv_num_flux_dot_n_2 = conv_num_flux->evaluate_flux(soln_ext, soln_int, -normal_int); + + std::cout << "Convective numerical flux conservation (should be equal and opposite)" << std::endl; + compare_array (conv_num_flux_dot_n_1, conv_num_flux_dot_n_2, -1.0); + + delete conv_num_flux; + delete pde_physics; + + return 0; +} +template +int test_convective_numerical_flux_consistency (const PDEType pde_type, const ConvType conv_type) +{ + using namespace PHiLiP; + Physics *pde_physics = PhysicsFactory::create_Physics(pde_type); + + NumericalFluxConvective *conv_num_flux = + NumericalFluxFactory + ::create_convective_numerical_flux (conv_type, pde_physics); + + Tensor<1,dim,double> normal_int; std::array soln_int, soln_ext; - for (int s=0; s, nstate> soln_grad_int, soln_grad_ext; + set_solution (soln_int, soln_ext, soln_grad_int, soln_grad_ext, normal_int); + // Consistent numerical flux should be equal to physical flux when both states are equal + // Therefore, f1 - f2 = 0 + soln_int = soln_ext; std::array conv_num_flux_dot_n = conv_num_flux->evaluate_flux(soln_int, soln_ext, normal_int); std::array, nstate> conv_phys_flux_int; @@ -93,26 +203,8 @@ int test_numerical_flux_consistency (const PDEType pde_type, const ConvType conv conv_phys_flux_dot_n[s] = conv_phys_flux_int[s]*normal_int; } - - std::cout << "PDE type " << pde_type << std::endl; - for (int s=0; s (conv_num_flux_dot_n, conv_phys_flux_dot_n, 1.0); delete conv_num_flux; delete pde_physics; @@ -129,6 +221,7 @@ int main (int argc, char *argv[]) PDEType::diffusion, PDEType::convection_diffusion }; + std::vector conv_type { ConvType::lax_friedrichs }; @@ -139,8 +232,10 @@ int main (int argc, char *argv[]) int success = 0; for (auto pde = pde_type.begin(); pde != pde_type.end() && success == 0; pde++) { for (auto conv = conv_type.begin(); conv != conv_type.end() && success == 0; conv++) { - success = test_numerical_flux_conservation (*pde, *conv); - success = test_numerical_flux_consistency (*pde, *conv); + success = test_convective_numerical_flux_conservation (*pde, *conv); + } + for (auto diss = diss_type.begin(); diss != diss_type.end() && success == 0; diss++) { + success = test_dissipative_numerical_flux_conservation (*pde, *diss); } } return success;