From ee3bdb4aa889a0af916964c06a6e57aef35b35d1 Mon Sep 17 00:00:00 2001 From: "A. Cicchino" <39313421+AlexanderCicchino@users.noreply.github.com> Date: Fri, 10 Feb 2023 21:45:47 -0500 Subject: [PATCH] ESFR Split Formulation (#111) * ESFR Split forms. Contains all unsteady unit and integration tests. Makes use of operators in DG strong. Provides weight-adjusted curvilinear Mass matrices. Includes free-stream preserving metric terms. * Removed the accidentally pushed mesh file. Will rebase last 4 commits into 1. * Cleaning up the accidental added line at end of some files and removed #if 0 #endif commented blocks. * And this file deleted last line. * Finished removing #if 0 #endif blocks, added some comments and included new numerical fluxes in the numerical_flux_conservation test. * Apply suggestions from code review dg.cpp minor edits * Implemented sum factorization in operators class. All operations can be written as a combination of matrix-vector products and inner products. A unit test verifies by testing the cputime for A*u and also M*u where M is a mass matrix--uses both matrix-vector product and inner product forms. All that is left is to clean up the unit test a bit to fail at wrong orders. * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review * Update src/parameters/all_parameters.cpp * Update with all changes requested from pull request. Only missing merge conflict with ode solver base then pull request changes complete. * Small cleanup changes before I merge upstream master in my branch. * Made corrections to explicit ode solver with Butcher tableau c values. Updated unsteady tests. Continued to clean up and removed deprecated Burgers Rewienski lines. * Cleaned up last few comments on pull request wrt Flux reconstruction operators and flags. * Removed old references to Runge-Kutta order. * Cleaned up re-used code in operators, and other comments from PR. * Removed collection tuple from dg. Removed finite element and quadrature collections from DG. Made consistent throughout the code to call operators finite element and quadrature collections from the operators collection tuple. * Fixed typos in error messages. * Created initial condition base class with interpolate and projection capabilities for different initial condition functions. This generalizes the initial condition class. * Turned axuiliary mass matrix into a single rather than array of dim because we use the same mass matrix for each dim direction. This reduces memory consumption. * Templated initial condition base by nstate and the functions therein. * Added a strong form Navier-Stokes integration test. * Made mapping support points arrays instead of vectors. Added flag in dg allocate system for the implicit matrix/vectors to allocate to reduce memory costs. * Fix minor changes from Pranshul. * Small update. Switching branch for other work. * Auxiliary variable correctly computed for NAvier-Stokes equation now. Verified through viscous TGV test strong. * Fixed small compiling error. * Fix TGV viscous strong control file * Strong viscous TGV energy check test confirmed pass. * Added definitions for projection. * Changed initial condition base to just initial condition since nothing is derived from it. * Current status of new operators backup * Made entropy conserving flux work for all physics types. Will return to my other branch with restructuring operators class for efficiency now. * Recent version, new operators quarter done. * For energy tests, only initializes ode solver on first iteration now. * For Julien to debug his flow solver case. I will revert these changes after so that the test case is mroe reasonable when using ctests. * Fixed the Burgers' energy inviscid initial condition. * Fixed stash error * Apply suggestions from code review * cleaning up InitialCondition; changed to SetInitialCondition * removing commented lines from previous commit * fixing bug that would run two tgv energy check quick tests * cleaning up src/parameter/ files; fixing comments marked as fixed that were not actually fixed * minor editorial changes * correcting all_parameters.cpp from last commit; indentation and doxygen fixes * indentation clean up in unit tests and euler split tgv * cleaning up src/testing/ files * removing unused CurvManifold class declaration in advection_explicit_periodic.h * changing tabs to spaces in burgers_stability.cpp * cleaning up ConvectionDiffusionPeriodic class files in src/testing/ * reducing code repetition in CMakeList for flow_variable_tests * reviewing src/dg, src/numerical_flux, and src/ode_solver/ files; moving all convective num fluxes to convective_numerical_flux.; converting tabs to spaces in convective_numerical_flux.cpp; general clean up in numerical flux directory; indentation fixes * New operators class completed with passing unit tests. Only unit tests to change atm are sum factorization, metric splitting and weight adjusted inverse. Next step is to deprecate the previous operators class and make respective changes throughout dg, tests etc. * reviewing src/mesh/grids files * making repeated constants class members in NonsymmetricCurvedGridManifold * correcting "set test_type = flow_solver" to "set run_type = flow_simulation" in prm files * The sum factorization test. * Changed mapping shape functions class so metric operators less variables pass to construct. * fixing time refinement study parameter file * New operators class complete with top-nothc efficiency :) * adding print statements for operators allocation status * adding forgotten print statements * comment fix * resolving a PR comment * Implemented new operators class throughout DG/DG strong. All that is left is having it pass the tests. It currently compiles. * I have DG strong conservative working, now need to tweak split forms and pass all tests. * Conservative DG works 2D curvilinear. Now need cuvilinear split form to work properly, then will do auxtesting/tgv and finito. * Got curvilinear stability and weight-adjusted curvilinear working perfectly. Now only needs to pass auxiliary/conv_diff explicit and it's all done! * 3D TGV works. Now just auxiliary. * bug fix for writing pvtu files in subdirectory * setting default value for WALE model constant to that recommended by literature * Auxiliary and conv diffusion passes. * Inverse mass on the fly and mass evaluated on the fly in application per cell done. Only doesnt work for curvilinear at the moment. Has flag to use. For curvilinear, do not use inverse on the fly yet. Works perfectly for linear grids. * 2pt flux Hadamard sum after the Hadamard product now O n^d+1. All is finished. * Made mass matrix computation more efficient. FINALLY PASSES NACA 0012 OPTIMIZATION I'm so happy! * compiles. Have not yet tested since the merge. * Fixed TGV Euler split form test that got stuff deleted during the merge. Also, in mass matrix DG, changed condition of factoring out det of Jac by Cartesian element rather than linear. This is because unstructured linear meshes do NOT have a constant metric Jacobian determinant, only Cartesian meshes do. Will run ctest and clean up documentation now. * Moved the entropy consevring, entropy stable split, and central numerical fluxes into convective numerical flux. * Changed tabs to spaces in burgers epxlicit test. * Added documentation equations to DG strong. * Modified TGV split test to use initial condition TGV function. * Fixed Polynomial degree ramping issue. * Run curvilinear mesh on Narval. Also, made 3D periodic nonsymm curv grid. * Added energy file declaration from control file. Also increased warping of grid. * small clean up * fixing pde_type flag in strong dg * correcting initial condition setting in split tgv * Finished with curv TGV work for conference * 1D_BURGERS_STABILITY_ORDERS_OF_ACCURACY_LONG passing * 1D_TIME_REFINEMENT_STUDY_ADVECTION_EXPLICIT now passes and behaves as supposed to. * 1D periodic now CONFIRMED to work with dealii matched faces. Thus, the hardcoded 1D periodic was removed. All tests that are affected by this pass. * Viscous TGV energy check quick STRONG passing. * Smoothed out auxiliary test to reach asymptotic convergence in L infinity norm in a reasonable time/grid level. * Unit test verifying DG Strong Auxiliary equations' right-hand-side for d\in[1,3], for Navier-Stokes equations. * Fixed CMake files and cleaned up the include header files in unit test. * Resolved conflicts from merge that caused the tests to fail. Tests are passing now. * Removed use_strong_form flag in dg.cpp. Instead uses polymorphism to build operators needed for strong or fevalues needed for weak and assembles the residual functions therein. Also, corrected parameter files for advection unsteady weight adjusted curvilinear tests. * Made a few small minor changes to operators. * Small bug fix I saw. * fixing Gaussian bump flow case merge commit; related tests now passing * adding physics_model to use_aux_equation flag * Refactoring NumericalFluxConvective * introducing has_nonzero_diffusion bool in physics * assigning has_nonzero_diffusion to use_auxiliary_eqn * bug fix * Added viscous pseudotime to converge the diffusion with explicit steady state (both weak and strong needed this). Added the max_dt_cell for strong form calculation. Verified the boundary integrals in strong form. Fully verified viscous strong form, with energy tests recovering the exact provable stability bound to machine precision. Added a central viscous flux to achieve the exact provable stability condition. * Fixed 3D periodic nonsymmetric grid. Setup TGV for curvilinear grid. Fixed bug in weight-adjusted on-the-fly for curvilinear and now passes both 2D and 3D tests. Added condition for sum-factorization tests for cpu orders of convergence. * improving MPI_VISCOUS_TAYLOR_GREEN_VORTEX_RESTART_FROM_PARAMETER_FILE_CHECK * Update. Switching branches. * Added check for convergence in Hadamard product sum-factorized test. The test is still the same but it checks if the computed error was off because it didn't consider enough polynomial points. * This always passes. * Speed up TGV run. * Fixed bug with diffusion implicit convergence times. * Cleaned up TGV test for curvilinear grid. * Fix nonsymmetric grid for 2D advection, the 1/5 was too much warping, changed back to 1/10. * Adding Ismail-Roe split form convective numerical flux; introducing parameter 'two_point_num_flux_type'. * FlowSolver using set_initial_condition; can be used for curvilinear grids now * adding safeguard for parameter: number_of_grid_elements_per_dimension * Fixed projection IC for multi-state. * The test parameter file for multi-state curvilinear projection. * renaming "entropy_conserving_flux" to "two_point_flux" * using pcout in ODE factory * adding output_high_order_grid parameter * adding constant_time_step parameter for TGV DNS verification * minor merge fix * bug fix in parameters for constant_time_step * updating ode_solver_type in missed prm files from explicit to runge_kutta; all tests expected to pass are passing * allowing for negative grid bounds; needed for verifying viscous TGV * Fixing bug which adds dissipation to Euler * Test to confirm conservation of entropy * PR comments re: entropy check test * Changing physics per PR comments; using isothermal TGV initialization * Adding comment re: MPI behaviour of dot product. * Move entropy calculation into physics * Fixing an accidental change * Addressing final PR comments * fixing ctest command for TGV restart tests when MPIMAX is not a power of 2 * setting output_high_order_grid to false by default * removing commented code in tgv shell script * Bug fixed for auxiliary rhs test to work with general processors. * Small fix from last commit. * Sum-factorized Hadamard product works with general diagonal weights for other tensor directions. This enables the use of general matrices for 2pt fluxes (stiffness operator rather than derivative). * Setup volume skew-symmetric form for DG solver. Setup surface Hadamard products using sum-factorization type algorithms with corresponding unit tests. Hadamard products handle basis of variable sizes with arbitrary diagonal products. * Put surface two point flux in dg strong. Uncollocated updated version works perfectly for Burgers' and curvilinear. Exploring why not yet machine precision entropy conservation for Euler TGV uncollocated IR. * PeriodicTurbulence Adaptive Time Step MPI Bug Fix (#3) * flipping sign on viscous flux * reverting sign flip on viscous flux * renaming mean_specific_energy and trying equivalent pressure gradient method * unused var fix * removing misleading compute_dimensional_temperature * const member initialization for sutherlands law temperatures * bug fix for adaptive time step; using MPI max * making temperature_inf an input parameter that must be consistent with the Prandtl number * removing commented code in header * doxygen fix * Added Chandrashekar flux. General uncollocated two-point fluxes works perfectly. Verified with 3D TGV curvilinear FR c+ uncollocated entropy conservation. Found a bug with weight-adjusted curvilinear mass inverse with uncollocated and overintegration. To be fixed in future only overintegration doesn't work as expected with uncollocated curvilinear weight-adjusted. * Clean up. Giong to merge. * Deleted commented out debugging code. * Cleaned up euler/physics_model as per comments. Added in strong DG to interpolate the conservative variables to the face for the numerical flux if conservative to pass the TGV quick tets. In the future, I think that it should be the interpolation of the entropy variables to the face even for conservative DG. * Added Ranocha entropy conserving, KEP and PEP numerical flux. Added mapping support points extraction that scales on order (grid_degre+1)^dim to alleviate previous bottleneck of computing the mapping support nodes that prevnted total scaling from (p+1)^dim. * Added test verifying that the global inverse mass matrix and global mass matrix on the fly recover same vector for multi state and any FR scheme fully veryfing the mass matrix application. * Integrated quantities for periodic turbulence now uses sum-factorization algorithms to reduce round-off error build up and provide scaling speed-up. * improvements and addressing PR comments * using constexpr where possible in operators.cpp * editorial changes * adding abort condition for aux equation * Replacing exit(1) by std::abort(), editorial changes to weak_dg.hpp * correcting abort for non-diffusive problems * cleaning up added polymorphism to DGBase (functions that are not called in DGBase and only in the derived DGStrong class); 1D, 2D, 3D_AUXILIARY_RHS_TEST are passing * Unifying the two versions of compute_entropy_variables in Euler physics * moving allocate_auxiliary_equation() definition to DGBase * Changing auxiliary explicit timestepping check to NOT-implicit. This will allow ODE solvers such as rrk_explicit to solve diffusive terms. --------- Co-authored-by: Alexander Co-authored-by: Julien Brillon <43619715+jbrillon@users.noreply.github.com> Co-authored-by: Carolyn --- generate_job_parameters_file_PHiLiP.sh | 2 +- src/deprecated/ode_solver.cpp | 6 +- src/dg/CMakeLists.txt | 6 +- src/dg/dg.cpp | 1491 +++++-- src/dg/dg.h | 276 +- src/dg/residual_sparsity_patterns.cpp | 4 +- src/dg/strong_dg.cpp | 3201 ++++++++++---- src/dg/strong_dg.hpp | 272 +- src/dg/weak_dg.cpp | 319 +- src/dg/weak_dg.hpp | 137 +- src/flow_solver/flow_solver.cpp | 10 +- src/flow_solver/flow_solver.h | 1 - .../1D_burgers_rewienski_snapshot.h | 2 +- .../1d_burgers_viscous_snapshot.h | 2 +- .../flow_solver_case_base.cpp | 9 +- .../flow_solver_cases/flow_solver_case_base.h | 2 +- src/flow_solver/flow_solver_cases/naca0012.h | 4 +- .../flow_solver_cases/periodic_turbulence.cpp | 236 +- .../flow_solver_cases/periodic_turbulence.h | 6 +- src/mesh/grids/CMakeLists.txt | 3 + .../nonsymmetric_curved_nonperiodic_grid.cpp | 244 ++ .../nonsymmetric_curved_nonperiodic_grid.hpp | 44 + .../nonsymmetric_curved_periodic_grid.cpp | 245 ++ .../nonsymmetric_curved_periodic_grid.hpp | 45 + .../grids/skew_symmetric_periodic_grid.cpp | 199 + .../grids/skew_symmetric_periodic_grid.hpp | 45 + src/mesh/grids/straight_periodic_cube.cpp | 14 + src/mesh/high_order_grid.cpp | 9 +- src/mesh/high_order_grid.h | 22 +- src/numerical_flux/CMakeLists.txt | 6 +- .../convective_numerical_flux.cpp | 454 +- .../convective_numerical_flux.hpp | 435 +- src/numerical_flux/numerical_flux_factory.cpp | 46 +- src/numerical_flux/numerical_flux_factory.hpp | 9 +- .../split_form_numerical_flux.cpp | 69 - .../split_form_numerical_flux.hpp | 40 - src/numerical_flux/viscous_numerical_flux.cpp | 121 +- src/numerical_flux/viscous_numerical_flux.hpp | 42 + src/ode_solver/explicit_ode_solver.cpp | 18 +- src/ode_solver/explicit_ode_solver.h | 1 + src/ode_solver/ode_solver_base.cpp | 17 +- src/operators/CMakeLists.txt | 7 +- src/operators/operators.cpp | 3758 +++++++++++------ src/operators/operators.h | 1644 +++++-- src/operators/operators_factory.cpp | 60 + src/operators/operators_factory.hpp | 34 + src/parameters/all_parameters.cpp | 137 +- src/parameters/all_parameters.h | 48 +- src/parameters/parameters_flow_solver.cpp | 44 +- src/parameters/parameters_flow_solver.h | 10 +- .../parameters_manufactured_solution.cpp | 36 +- .../parameters_manufactured_solution.h | 2 + src/parameters/parameters_navier_stokes.cpp | 8 +- src/parameters/parameters_navier_stokes.h | 1 + src/parameters/parameters_physics_model.cpp | 8 +- src/physics/burgers.cpp | 63 +- src/physics/burgers.h | 35 +- src/physics/burgers_rewienski.cpp | 3 +- src/physics/burgers_rewienski.h | 3 +- src/physics/convection_diffusion.cpp | 139 +- src/physics/convection_diffusion.h | 31 +- src/physics/euler.cpp | 348 +- src/physics/euler.h | 74 +- src/physics/initial_conditions/CMakeLists.txt | 16 +- ...ion.cpp => initial_condition_function.cpp} | 264 +- ...ndition.h => initial_condition_function.h} | 136 +- .../set_initial_condition.cpp | 92 + .../set_initial_condition.h | 42 + src/physics/large_eddy_simulation.cpp | 35 +- src/physics/large_eddy_simulation.h | 21 +- src/physics/manufactured_solution.cpp | 49 +- src/physics/manufactured_solution.h | 29 + src/physics/mhd.cpp | 42 +- src/physics/mhd.h | 25 +- src/physics/model.h | 1 + src/physics/model_factory.cpp | 12 +- src/physics/navier_stokes.cpp | 30 +- src/physics/navier_stokes.h | 31 +- src/physics/physics.cpp | 14 +- src/physics/physics.h | 30 +- src/physics/physics_factory.cpp | 25 +- src/physics/physics_model.cpp | 74 +- src/physics/physics_model.h | 23 +- src/reduced_order/CMakeLists.txt | 2 +- src/testing/CMakeLists.txt | 4 +- src/testing/advection_explicit_periodic.cpp | 471 ++- src/testing/advection_explicit_periodic.h | 20 +- src/testing/burgers_stability.cpp | 385 +- src/testing/burgers_stability.h | 26 +- ...convection_diffusion_explicit_periodic.cpp | 368 ++ .../convection_diffusion_explicit_periodic.h | 41 + src/testing/diffusion_exact_adjoint.cpp | 2 + src/testing/diffusion_exact_adjoint.h | 6 +- src/testing/euler_bump_optimization.cpp | 2 +- src/testing/euler_cylinder.cpp | 2 +- src/testing/euler_cylinder_adjoint.cpp | 2 +- src/testing/euler_gaussian_bump.cpp | 1 + .../euler_ismail_roe_entropy_check.cpp | 45 + src/testing/euler_ismail_roe_entropy_check.h | 32 + src/testing/euler_naca0012_optimization.cpp | 2 +- ...ler_split_inviscid_taylor_green_vortex.cpp | 565 ++- ...euler_split_inviscid_taylor_green_vortex.h | 38 +- src/testing/grid_refinement_study.cpp | 2 +- src/testing/grid_study.cpp | 12 +- src/testing/tests.cpp | 24 +- src/testing/time_refinement_study.cpp | 3 +- .../CMakeLists.txt | 2 + .../2D_advection_explicit_periodic.prm | 31 - .../2D_advection_explicit_periodic_OOA.prm | 58 + .../2D_advection_explicit_periodic_energy.prm | 59 + ...plicit_periodic_energy_weight_adjusted.prm | 59 + ...odic_energy_weight_adjusted_on_the_fly.prm | 59 + ...plicit_periodic_energy_weight_adjusted.prm | 59 + .../CMakeLists.txt | 37 +- .../1d_advection_explicit_strong.prm | 48 + .../2d_advection_explicit_strong.prm | 47 + .../3d_advection_explicit_strong.prm | 53 + .../advection_implicit/CMakeLists.txt | 21 + .../1D_burgers_energy_conservation_rrk.prm | 2 +- .../1D_burgers_stability.prm | 27 - .../1D_burgers_stability_OOA.prm | 56 + .../1D_burgers_stability_energy.prm | 53 + .../burgers_split_stability/CMakeLists.txt | 13 +- .../1D_conv_diff_explicit_periodic_energy.prm | 65 + .../2D_conv_diff_explicit_periodic_OOA.prm | 63 + .../2D_conv_diff_explicit_periodic_energy.prm | 64 + .../CMakeLists.txt | 21 + .../1d_diffusion_sipg_explicit_strong.prm | 52 + .../diffusion_implicit/CMakeLists.txt | 7 + .../euler_entropy_conservation/CMakeLists.txt | 16 + .../euler_ismail_roe_entropy_check.prm | 54 + ...ler_split_inviscid_taylor_green_vortex.prm | 43 +- .../reduced_order/CMakeLists.txt | 2 +- .../CMakeLists.txt | 42 +- ...green_vortex_energy_check_strong_quick.prm | 65 + ...r_green_vortex_energy_check_weak_long.prm} | 0 ..._green_vortex_energy_check_weak_quick.prm} | 6 +- ...cous_taylor_green_vortex_restart_check.prm | 4 +- ...ortex_restart_from_parameter_file_check.sh | 1 - ...time_refinement_study_burgers_explicit.prm | 2 +- tests/unit_tests/CMakeLists.txt | 2 + .../euler_manufactured_solution_source.cpp | 3 +- .../freestream_preservation.cpp | 2 +- .../flow_variable_tests/CMakeLists.txt | 81 + .../auxiliary_equations_int_by_parts.cpp | 473 +++ .../auxiliary_variable_test.cpp | 339 ++ ...er_stokes_manufactured_solution_source.cpp | 3 +- .../numerical_flux_conservation.cpp | 23 +- .../explicit_ode_solver.cpp | 3 +- .../operator_tests/4_point_flux.cpp | 147 + .../unit_tests/operator_tests/CMakeLists.txt | 630 ++- .../operator_tests/GCL_Collocated_test.cpp | 407 +- tests/unit_tests/operator_tests/GCL_test.cpp | 349 +- .../GCL_test_invariant_curl.cpp | 375 ++ .../Surface_GCL_Superparametric_test.cpp | 545 --- .../operator_tests/Surface_GCL_test.cpp | 545 --- .../operator_tests/Volume_operators_test.cpp | 292 -- .../operator_tests/chain_rule_test.cpp | 191 + .../consistent_Hadamard_test.cpp | 186 + .../consistent_surface_Hadamard_test.cpp | 264 ++ ...rface_oper_test.cpp => flux_oper_test.cpp} | 103 +- .../global_mass_matrix_test.cpp | 158 + .../mapping_basis_collocation_test.cpp | 145 + .../operator_tests/metric_Jacobian_test.cpp | 364 ++ .../metric_split_form_gradient.cpp | 498 +++ .../sum_factorization_Hadamard_test.cpp | 374 ++ .../operator_tests/sum_factorization_test.cpp | 332 ++ .../surface_GCL_Superparametric_test.cpp | 360 ++ .../operator_tests/surface_GCL_test.cpp | 363 ++ .../surface_conforming_test.cpp | 380 ++ .../operator_tests/surface_oper_test.cpp | 233 + .../operator_tests/tensor_product_test.cpp | 172 + .../operator_tests/volume_operators_test.cpp | 154 + .../weight_adjusted_mass_inverse_test.cpp | 478 +++ ...per_test.cpp => weighted_int_by_parts.cpp} | 149 +- .../optimization/flow_constraints_check.cpp | 2 +- .../optimization/objective_check.cpp | 2 +- 177 files changed, 21932 insertions(+), 6039 deletions(-) create mode 100644 src/mesh/grids/nonsymmetric_curved_nonperiodic_grid.cpp create mode 100644 src/mesh/grids/nonsymmetric_curved_nonperiodic_grid.hpp create mode 100644 src/mesh/grids/nonsymmetric_curved_periodic_grid.cpp create mode 100644 src/mesh/grids/nonsymmetric_curved_periodic_grid.hpp create mode 100644 src/mesh/grids/skew_symmetric_periodic_grid.cpp create mode 100644 src/mesh/grids/skew_symmetric_periodic_grid.hpp delete mode 100644 src/numerical_flux/split_form_numerical_flux.cpp delete mode 100644 src/numerical_flux/split_form_numerical_flux.hpp create mode 100644 src/operators/operators_factory.cpp create mode 100644 src/operators/operators_factory.hpp rename src/physics/initial_conditions/{initial_condition.cpp => initial_condition_function.cpp} (50%) rename src/physics/initial_conditions/{initial_condition.h => initial_condition_function.h} (67%) create mode 100644 src/physics/initial_conditions/set_initial_condition.cpp create mode 100644 src/physics/initial_conditions/set_initial_condition.h create mode 100644 src/testing/convection_diffusion_explicit_periodic.cpp create mode 100644 src/testing/convection_diffusion_explicit_periodic.h create mode 100644 src/testing/euler_ismail_roe_entropy_check.cpp create mode 100644 src/testing/euler_ismail_roe_entropy_check.h delete mode 100644 tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic.prm create mode 100644 tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_OOA.prm create mode 100644 tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_energy.prm create mode 100644 tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_energy_weight_adjusted.prm create mode 100644 tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_energy_weight_adjusted_on_the_fly.prm create mode 100644 tests/integration_tests_control_files/advection_explicit_periodic/3D_advection_explicit_periodic_energy_weight_adjusted.prm create mode 100644 tests/integration_tests_control_files/advection_implicit/1d_advection_explicit_strong.prm create mode 100644 tests/integration_tests_control_files/advection_implicit/2d_advection_explicit_strong.prm create mode 100644 tests/integration_tests_control_files/advection_implicit/3d_advection_explicit_strong.prm delete mode 100644 tests/integration_tests_control_files/burgers_split_stability/1D_burgers_stability.prm create mode 100644 tests/integration_tests_control_files/burgers_split_stability/1D_burgers_stability_OOA.prm create mode 100644 tests/integration_tests_control_files/burgers_split_stability/1D_burgers_stability_energy.prm create mode 100644 tests/integration_tests_control_files/convection_diffusion_explicit_periodic/1D_conv_diff_explicit_periodic_energy.prm create mode 100644 tests/integration_tests_control_files/convection_diffusion_explicit_periodic/2D_conv_diff_explicit_periodic_OOA.prm create mode 100644 tests/integration_tests_control_files/convection_diffusion_explicit_periodic/2D_conv_diff_explicit_periodic_energy.prm create mode 100644 tests/integration_tests_control_files/convection_diffusion_explicit_periodic/CMakeLists.txt create mode 100644 tests/integration_tests_control_files/diffusion_implicit/1d_diffusion_sipg_explicit_strong.prm create mode 100644 tests/integration_tests_control_files/euler_entropy_conservation/CMakeLists.txt create mode 100644 tests/integration_tests_control_files/euler_entropy_conservation/euler_ismail_roe_entropy_check.prm create mode 100644 tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_strong_quick.prm rename tests/integration_tests_control_files/taylor_green_vortex_integration/{viscous_taylor_green_vortex_energy_check_long.prm => viscous_taylor_green_vortex_energy_check_weak_long.prm} (100%) rename tests/integration_tests_control_files/taylor_green_vortex_integration/{viscous_taylor_green_vortex_energy_check_quick.prm => viscous_taylor_green_vortex_energy_check_weak_quick.prm} (93%) create mode 100644 tests/unit_tests/flow_variable_tests/CMakeLists.txt create mode 100644 tests/unit_tests/flow_variable_tests/auxiliary_equations_int_by_parts.cpp create mode 100644 tests/unit_tests/flow_variable_tests/auxiliary_variable_test.cpp create mode 100644 tests/unit_tests/operator_tests/4_point_flux.cpp create mode 100644 tests/unit_tests/operator_tests/GCL_test_invariant_curl.cpp delete mode 100644 tests/unit_tests/operator_tests/Surface_GCL_Superparametric_test.cpp delete mode 100644 tests/unit_tests/operator_tests/Surface_GCL_test.cpp delete mode 100644 tests/unit_tests/operator_tests/Volume_operators_test.cpp create mode 100644 tests/unit_tests/operator_tests/chain_rule_test.cpp create mode 100644 tests/unit_tests/operator_tests/consistent_Hadamard_test.cpp create mode 100644 tests/unit_tests/operator_tests/consistent_surface_Hadamard_test.cpp rename tests/unit_tests/operator_tests/{Surface_oper_test.cpp => flux_oper_test.cpp} (55%) create mode 100644 tests/unit_tests/operator_tests/global_mass_matrix_test.cpp create mode 100644 tests/unit_tests/operator_tests/mapping_basis_collocation_test.cpp create mode 100644 tests/unit_tests/operator_tests/metric_Jacobian_test.cpp create mode 100644 tests/unit_tests/operator_tests/metric_split_form_gradient.cpp create mode 100644 tests/unit_tests/operator_tests/sum_factorization_Hadamard_test.cpp create mode 100644 tests/unit_tests/operator_tests/sum_factorization_test.cpp create mode 100644 tests/unit_tests/operator_tests/surface_GCL_Superparametric_test.cpp create mode 100644 tests/unit_tests/operator_tests/surface_GCL_test.cpp create mode 100644 tests/unit_tests/operator_tests/surface_conforming_test.cpp create mode 100644 tests/unit_tests/operator_tests/surface_oper_test.cpp create mode 100644 tests/unit_tests/operator_tests/tensor_product_test.cpp create mode 100644 tests/unit_tests/operator_tests/volume_operators_test.cpp create mode 100644 tests/unit_tests/operator_tests/weight_adjusted_mass_inverse_test.cpp rename tests/unit_tests/operator_tests/{Flux_oper_test.cpp => weighted_int_by_parts.cpp} (51%) diff --git a/generate_job_parameters_file_PHiLiP.sh b/generate_job_parameters_file_PHiLiP.sh index 1448ef040..00bb514fa 100755 --- a/generate_job_parameters_file_PHiLiP.sh +++ b/generate_job_parameters_file_PHiLiP.sh @@ -1,4 +1,4 @@ -# This file quickly generates the job paramters file +# This file quickly generates the job parameters file filename="my_job_parameters_file.sh" walltime="2:00:00" # wall time diff --git a/src/deprecated/ode_solver.cpp b/src/deprecated/ode_solver.cpp index 7f2667382..bf18bc8b9 100644 --- a/src/deprecated/ode_solver.cpp +++ b/src/deprecated/ode_solver.cpp @@ -513,7 +513,7 @@ void Implicit_ODESolver::allocate_ode_system () //std::shared_ptr> ODESolverFactory::create_ODESolver(Parameters::ODESolverParam::ODESolverEnum ode_solver_type) //{ // using ODEEnum = Parameters::ODESolverParam::ODESolverEnum; -// if(ode_solver_type == ODEEnum::explicit_solver) return std::make_shared>(); +// if(ode_solver_type == ODEEnum::runge_kutta_solver) return std::make_shared>(); // if(ode_solver_type == ODEEnum::implicit_solver) return std::make_shared>(); // else { // pcout << "Can't create ODE solver since explicit/implicit solver is not clear." << std::endl; @@ -525,7 +525,7 @@ std::shared_ptr> ODESolverFactoryall_parameters->ode_solver_param.ode_solver_type; - if(ode_solver_type == ODEEnum::explicit_solver) return std::make_shared>(dg_input); + if(ode_solver_type == ODEEnum::runge_kutta_solver) return std::make_shared>(dg_input); if(ode_solver_type == ODEEnum::implicit_solver) return std::make_shared>(dg_input); else { dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); @@ -533,7 +533,7 @@ std::shared_ptr> ODESolverFactory::DGBase( , nstate(nstate_input) , initial_degree(degree) , max_degree(max_degree_input) + , max_grid_degree(grid_degree_input) , triangulation(triangulation_input) , fe_collection(std::get<0>(collection_tuple)) , volume_quadrature_collection(std::get<1>(collection_tuple)) , face_quadrature_collection(std::get<2>(collection_tuple)) - , oned_quadrature_collection(std::get<3>(collection_tuple)) - , fe_collection_lagrange(std::get<4>(collection_tuple)) + , fe_collection_lagrange(std::get<3>(collection_tuple)) + , oneD_fe_collection(std::get<4>(collection_tuple)) + , oneD_fe_collection_1state(std::get<5>(collection_tuple)) + , oneD_fe_collection_flux(std::get<6>(collection_tuple)) + , oneD_quadrature_collection(std::get<7>(collection_tuple)) + , oneD_face_quadrature(max_degree) , dof_handler(*triangulation, true) - , high_order_grid(std::make_shared>(grid_degree_input, triangulation)) + , high_order_grid(std::make_shared>(grid_degree_input, triangulation, all_parameters->output_high_order_grid)) , fe_q_artificial_dissipation(1) , dof_handler_artificial_dissipation(*triangulation, false) , mpi_communicator(MPI_COMM_WORLD) @@ -129,25 +134,32 @@ void DGBase::set_high_order_grid(std::shared_ptr std::tuple< //dealii::hp::MappingCollection, // Mapping dealii::hp::FECollection, // Solution FE dealii::hp::QCollection, // Volume quadrature dealii::hp::QCollection, // Face quadrature - dealii::hp::QCollection<1>, // 1D quadrature for strong form - dealii::hp::FECollection > // Lagrange polynomials for strong form + dealii::hp::FECollection, // Lagrange polynomials for strong form + dealii::hp::FECollection<1>, // Solution FE 1D + dealii::hp::FECollection<1>, // Solution FE 1D for a single state + dealii::hp::FECollection<1>, // Collocated flux basis 1D for Strong + dealii::hp::QCollection<1> >// 1D quadrature for strong form DGBase::create_collection_tuple( const unsigned int max_degree, const int nstate, const Parameters::AllParameters *const parameters_input) const { dealii::hp::FECollection fe_coll; + dealii::hp::FECollection<1> fe_coll_1D; + dealii::hp::FECollection<1> fe_coll_1D_1state; dealii::hp::QCollection volume_quad_coll; dealii::hp::QCollection face_quad_coll; - dealii::hp::QCollection<1> oned_quad_coll; + dealii::hp::QCollection<1> oneD_quad_coll; dealii::hp::FECollection fe_coll_lagr; + dealii::hp::FECollection<1> fe_coll_lagr_1D; // for p=0, we use a p=1 FE for collocation, since there's no p=0 quadrature for Gauss Lobatto if (parameters_input->use_collocated_nodes==true) @@ -158,15 +170,21 @@ DGBase::create_collection_tuple( const dealii::FESystem fe_system(fe_dg, nstate); fe_coll.push_back (fe_system); - dealii::Quadrature<1> oned_quad(degree+1); + const dealii::FE_DGQ<1> fe_dg_1D(degree); + const dealii::FESystem<1,1> fe_system_1D(fe_dg_1D, nstate); + fe_coll_1D.push_back (fe_system_1D); + const dealii::FESystem<1,1> fe_system_1D_1state(fe_dg_1D, 1); + fe_coll_1D_1state.push_back (fe_system_1D_1state); + + dealii::Quadrature<1> oneD_quad(degree+1); dealii::Quadrature volume_quad(degree+1); dealii::Quadrature face_quad(degree+1); //removed const if (parameters_input->use_collocated_nodes) { - dealii::QGaussLobatto<1> oned_quad_Gauss_Lobatto (degree+1); + dealii::QGaussLobatto<1> oneD_quad_Gauss_Lobatto (degree+1); dealii::QGaussLobatto vol_quad_Gauss_Lobatto (degree+1); - oned_quad = oned_quad_Gauss_Lobatto; + oneD_quad = oneD_quad_Gauss_Lobatto; volume_quad = vol_quad_Gauss_Lobatto; if(dim == 1) { @@ -177,20 +195,23 @@ DGBase::create_collection_tuple( face_quad = face_quad_Gauss_Lobatto; } } else { - dealii::QGauss<1> oned_quad_Gauss_Legendre (degree+1); + dealii::QGauss<1> oneD_quad_Gauss_Legendre (degree+1); dealii::QGauss vol_quad_Gauss_Legendre (degree+1); dealii::QGauss face_quad_Gauss_Legendre (degree+1); - oned_quad = oned_quad_Gauss_Legendre; + oneD_quad = oneD_quad_Gauss_Legendre; volume_quad = vol_quad_Gauss_Legendre; face_quad = face_quad_Gauss_Legendre; } volume_quad_coll.push_back (volume_quad); face_quad_coll.push_back (face_quad); - oned_quad_coll.push_back (oned_quad); + oneD_quad_coll.push_back (oneD_quad); - dealii::FE_DGQArbitraryNodes lagrange_poly(oned_quad); + dealii::FE_DGQArbitraryNodes lagrange_poly(oneD_quad); fe_coll_lagr.push_back (lagrange_poly); + + dealii::FE_DGQArbitraryNodes<1,1> lagrange_poly_1D(oneD_quad); + fe_coll_lagr_1D.push_back (lagrange_poly_1D); } int minimum_degree = (parameters_input->use_collocated_nodes==true) ? 1 : 0; @@ -203,14 +224,22 @@ DGBase::create_collection_tuple( const dealii::FESystem fe_system(fe_dg, nstate); fe_coll.push_back (fe_system); - dealii::Quadrature<1> oned_quad(degree+1); + const dealii::FE_DGQ<1> fe_dg_1D(degree); + //const dealii::FE_DGQArbitraryNodes fe_dg(dealii::QGauss<1>(degree+1)); + //std::cout << degree << " fe_dg.tensor_degree " << fe_dg.tensor_degree() << " fe_dg.n_dofs_per_cell " << fe_dg.n_dofs_per_cell() << std::endl; + const dealii::FESystem<1,1> fe_system_1D(fe_dg_1D, nstate); + fe_coll_1D.push_back (fe_system_1D); + const dealii::FESystem<1,1> fe_system_1D_1state(fe_dg_1D, 1); + fe_coll_1D_1state.push_back (fe_system_1D_1state); + + dealii::Quadrature<1> oneD_quad(degree+1); dealii::Quadrature volume_quad(degree+1); dealii::Quadrature face_quad(degree+1); //removed const if (parameters_input->use_collocated_nodes) { - dealii::QGaussLobatto<1> oned_quad_Gauss_Lobatto (degree+1); + dealii::QGaussLobatto<1> oneD_quad_Gauss_Lobatto (degree+1); dealii::QGaussLobatto vol_quad_Gauss_Lobatto (degree+1); - oned_quad = oned_quad_Gauss_Lobatto; + oneD_quad = oneD_quad_Gauss_Lobatto; volume_quad = vol_quad_Gauss_Lobatto; if(dim == 1) @@ -225,22 +254,25 @@ DGBase::create_collection_tuple( } } else { const unsigned int overintegration = parameters_input->overintegration; - dealii::QGauss<1> oned_quad_Gauss_Legendre (degree+1+overintegration); + dealii::QGauss<1> oneD_quad_Gauss_Legendre (degree+1+overintegration); dealii::QGauss vol_quad_Gauss_Legendre (degree+1+overintegration); dealii::QGauss face_quad_Gauss_Legendre (degree+1+overintegration); - oned_quad = oned_quad_Gauss_Legendre; + oneD_quad = oneD_quad_Gauss_Legendre; volume_quad = vol_quad_Gauss_Legendre; face_quad = face_quad_Gauss_Legendre; } volume_quad_coll.push_back (volume_quad); face_quad_coll.push_back (face_quad); - oned_quad_coll.push_back (oned_quad); + oneD_quad_coll.push_back (oneD_quad); - dealii::FE_DGQArbitraryNodes lagrange_poly(oned_quad); + dealii::FE_DGQArbitraryNodes lagrange_poly(oneD_quad); fe_coll_lagr.push_back (lagrange_poly); + + dealii::FE_DGQArbitraryNodes<1,1> lagrange_poly_1d(oneD_quad); + fe_coll_lagr_1D.push_back (lagrange_poly_1d); } - return std::make_tuple(fe_coll, volume_quad_coll, face_quad_coll, oned_quad_coll, fe_coll_lagr); + return std::make_tuple(fe_coll, volume_quad_coll, face_quad_coll, fe_coll_lagr, fe_coll_1D, fe_coll_1D_1state, fe_coll_lagr_1D, oneD_quad_coll); } template @@ -402,6 +434,12 @@ void DGBaseState::update_model_variables() pde_model_rad_fad->cellwise_volume.update_ghost_values(); } +template +void DGBaseState::set_use_auxiliary_eq() +{ + this->use_auxiliary_eq = pde_physics_double->has_nonzero_diffusion; +} + template real DGBaseState::evaluate_CFL ( std::vector< std::array > soln_at_q, @@ -412,11 +450,13 @@ real DGBaseState::evaluate_CFL ( { const unsigned int n_pts = soln_at_q.size(); std::vector< real > convective_eigenvalues(n_pts); + std::vector< real > viscosities(n_pts); for (unsigned int isol = 0; isol < n_pts; ++isol) { convective_eigenvalues[isol] = pde_physics_double->max_convective_eigenvalue (soln_at_q[isol]); - //viscosities[isol] = pde_physics_double->compute_diffusion_coefficient (soln_at_q[isol]); + viscosities[isol] = pde_physics_double->max_viscous_eigenvalue (soln_at_q[isol]); } const real max_eig = *(std::max_element(convective_eigenvalues.begin(), convective_eigenvalues.end())); + const real max_diffusive = *(std::max_element(viscosities.begin(), viscosities.end())); //const real cfl_convective = cell_diameter / max_eig; //const real cfl_diffusive = artificial_dissipation != 0.0 ? 0.5*cell_diameter*cell_diameter / artificial_dissipation : 1e200; @@ -426,7 +466,9 @@ real DGBaseState::evaluate_CFL ( const real cfl_convective = (cell_diameter / max_eig) / (2*p+1);//(p * p); const real cfl_diffusive = artificial_dissipation != 0.0 ? (0.5*cell_diameter*cell_diameter / artificial_dissipation) / (p*p*p*p) - : 1e200; + : ( (this->all_parameters->ode_solver_param.ode_solver_type != Parameters::ODESolverParam::ODESolverEnum::implicit_solver ) ?//if explicit use pseudotime stepping CFL + (0.5*cell_diameter * cell_diameter / max_diffusive) / (2*p+1) + : 1e200 ); real min_cfl = std::min(cfl_convective, cfl_diffusive); if (min_cfl >= 1e190) min_cfl = cell_diameter / 1; @@ -633,33 +675,36 @@ void DGBase::assemble_cell_residual ( dealii::hp::FEFaceValues &fe_values_collection_face_ext, dealii::hp::FESubfaceValues &fe_values_collection_subface, dealii::hp::FEValues &fe_values_collection_volume_lagrange, - dealii::LinearAlgebra::distributed::Vector &rhs) + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::basis_functions &flux_basis_int, + OPERATOR::basis_functions &flux_basis_ext, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::mapping_shape_functions &mapping_basis, + const bool compute_auxiliary_right_hand_side, + dealii::LinearAlgebra::distributed::Vector &rhs, + std::array,dim> &rhs_aux) { std::vector current_dofs_indices; std::vector neighbor_dofs_indices; // Current reference element related to this physical cell const int i_fele = current_cell->active_fe_index(); - const int i_quad = i_fele; - const int i_mapp = 0; const dealii::FESystem ¤t_fe_ref = fe_collection[i_fele]; const unsigned int n_dofs_curr_cell = current_fe_ref.n_dofs_per_cell(); // Local vector contribution from each cell dealii::Vector current_cell_rhs (n_dofs_curr_cell); // Defaults to 0.0 initialization + // Local vector contribution from each cell for Auxiliary equations + std::vector> current_cell_rhs_aux (n_dofs_curr_cell);// Defaults to 0.0 initialization // Obtain the mapping from local dof indices to global dof indices current_dofs_indices.resize(n_dofs_curr_cell); current_cell->get_dof_indices (current_dofs_indices); - fe_values_collection_volume.reinit (current_cell, i_quad, i_mapp, i_fele); - const dealii::FEValues &fe_values_volume = fe_values_collection_volume.get_present_fe_values(); - - dealii::TriaIterator> cell_iterator = static_cast> > (current_cell); - //if (!(all_parameters->use_weak_form)) fe_values_collection_volume_lagrange.reinit (current_cell, i_quad, i_mapp, i_fele); - fe_values_collection_volume_lagrange.reinit (cell_iterator, i_quad, i_mapp, i_fele); - const dealii::FEValues &fe_values_lagrange = fe_values_collection_volume_lagrange.get_present_fe_values(); + const unsigned int grid_degree = this->high_order_grid->fe_system.tensor_degree(); + const unsigned int poly_degree = i_fele; const unsigned int n_metric_dofs_cell = high_order_grid->fe_system.dofs_per_cell; std::vector current_metric_dofs_indices(n_metric_dofs_cell); @@ -679,35 +724,46 @@ void DGBase::assemble_cell_residual ( const dealii::types::global_dof_index current_cell_index = current_cell->active_cell_index(); - assemble_volume_term_explicit ( + std::array,dim> mapping_support_points; + //if have source term need to store vol flux nodes. + const bool store_vol_flux_nodes = all_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term; + //for boundary conditions not periodic we need surface flux nodes + //should change this flag to something like if have face on boundary not periodic in the future + const bool store_surf_flux_nodes = (all_parameters->use_periodic_bc) ? false : true; + OPERATOR::metric_operators metric_oper_int(nstate, poly_degree, grid_degree, + store_vol_flux_nodes, + store_surf_flux_nodes); + + //flag to terminate if strong form and implicit + if((this->all_parameters->use_weak_form==false) + && (this->all_parameters->ode_solver_param.ode_solver_type + == Parameters::ODESolverParam::ODESolverEnum::implicit_solver)) + { + pcout<<"ERROR: Implicit does not currently work for strong form. Aborting..."<::assemble_cell_residual ( auto current_face = current_cell->face(iface); // CASE 1: FACE AT BOUNDARY - if (current_face->at_boundary() && !current_cell->has_periodic_neighbor(iface) ) { - - fe_values_collection_face_int.reinit(current_cell, iface, i_quad, i_mapp, i_fele); - - const dealii::FEFaceValues &fe_values_face_int = fe_values_collection_face_int.get_present_fe_values(); - + if ((current_face->at_boundary() && !current_cell->has_periodic_neighbor(iface))) + { const real penalty = evaluate_penalty_scaling (current_cell, iface, fe_collection); const unsigned int boundary_id = current_face->boundary_id(); - //if (compute_dRdW || compute_dRdX || compute_d2R) { - const dealii::Quadrature face_quadrature = face_quadrature_collection[i_quad]; - assemble_boundary_term_derivatives ( - current_cell, - current_cell_index, - iface, boundary_id, fe_values_face_int, penalty, - current_fe_ref, face_quadrature, - current_metric_dofs_indices, current_dofs_indices, current_cell_rhs, - compute_dRdW, compute_dRdX, compute_d2R); - //} else { - // assemble_boundary_term_explicit ( - // current_cell, - // current_cell_index, - // boundary_id, fe_values_face_int, penalty, current_dofs_indices, current_cell_rhs); - //} + assemble_boundary_term_and_build_operators( + current_cell, + current_cell_index, + iface, + boundary_id, + penalty, + current_dofs_indices, + current_metric_dofs_indices, + poly_degree, + grid_degree, + soln_basis_int, + flux_basis_int, + flux_basis_stiffness, + metric_oper_int, + mapping_basis, + mapping_support_points, + fe_values_collection_face_int, + current_fe_ref, + current_cell_rhs, + current_cell_rhs_aux, + compute_auxiliary_right_hand_side, + compute_dRdW, compute_dRdX, compute_d2R); - //CASE 2: PERIODIC BOUNDARY CONDITIONS - //note that periodicity is not adapted for hp adaptivity yet. this needs to be figured out in the future - } else if (current_face->at_boundary() && current_cell->has_periodic_neighbor(iface)){ + } + // CASE 2: PERIODIC BOUNDARY CONDITIONS + // NOTE: Periodicity is not adapted for hp adaptivity yet. this needs to be figured out in the future + else if (current_face->at_boundary() && current_cell->has_periodic_neighbor(iface)) + { const auto neighbor_cell = current_cell->periodic_neighbor(iface); - //std::cout << "cell " << current_cell->index() << " at boundary" <index() << std::endl; - - - if (!current_cell->periodic_neighbor_is_coarser(iface) && current_cell_should_do_the_work(current_cell, neighbor_cell)) { + if (!current_cell->periodic_neighbor_is_coarser(iface) && current_cell_should_do_the_work(current_cell, neighbor_cell)) + { Assert (current_cell->periodic_neighbor(iface).state() == dealii::IteratorState::valid, dealii::ExcInternalError()); const unsigned int n_dofs_neigh_cell = fe_collection[neighbor_cell->active_fe_index()].n_dofs_per_cell(); @@ -763,87 +821,74 @@ void DGBase::assemble_cell_residual ( neighbor_dofs_indices.resize(n_dofs_neigh_cell); neighbor_cell->get_dof_indices (neighbor_dofs_indices); - fe_values_collection_face_int.reinit (current_cell, iface, i_quad, i_mapp, i_fele); - const dealii::FEFaceValues &fe_values_face_int = fe_values_collection_face_int.get_present_fe_values(); - // Corresponding face of the neighbor. const unsigned int neighbor_iface = current_cell->periodic_neighbor_of_periodic_neighbor(iface); - const int i_fele_n = neighbor_cell->active_fe_index(), i_quad_n = i_fele_n, i_mapp_n = 0; - fe_values_collection_face_ext.reinit (neighbor_cell, neighbor_iface, i_quad_n, i_mapp_n, i_fele_n); - const dealii::FEFaceValues &fe_values_face_ext = fe_values_collection_face_ext.get_present_fe_values(); + const int i_fele_n = neighbor_cell->active_fe_index(); + // Compute penalty. const real penalty1 = evaluate_penalty_scaling (current_cell, iface, fe_collection); const real penalty2 = evaluate_penalty_scaling (neighbor_cell, neighbor_iface, fe_collection); const real penalty = 0.5 * (penalty1 + penalty2); const dealii::types::global_dof_index neighbor_cell_index = neighbor_cell->active_cell_index(); - //if ( compute_dRdW || compute_dRdX || compute_d2R ) { - const auto metric_neighbor_cell = current_metric_cell->periodic_neighbor(iface); - metric_neighbor_cell->get_dof_indices(neighbor_metric_dofs_indices); - const dealii::Quadrature &used_face_quadrature = face_quadrature_collection[(i_quad_n > i_quad) ? i_quad_n : i_quad]; // Use larger quadrature order on the face - - std::pair face_subface_int = std::make_pair(iface, -1); - std::pair face_subface_ext = std::make_pair(neighbor_iface, -1); - const auto face_data_set_int = dealii::QProjector::DataSetDescriptor::face ( - dealii::ReferenceCell::get_hypercube(dim), - iface, - current_cell->face_orientation(iface), - current_cell->face_flip(iface), - current_cell->face_rotation(iface), - used_face_quadrature.size()); - const auto face_data_set_ext = dealii::QProjector::DataSetDescriptor::face ( - dealii::ReferenceCell::get_hypercube(dim), - neighbor_iface, - neighbor_cell->face_orientation(neighbor_iface), - neighbor_cell->face_flip(neighbor_iface), - neighbor_cell->face_rotation(neighbor_iface), - used_face_quadrature.size()); - assemble_face_term_derivatives ( - current_cell, - current_cell_index, - neighbor_cell_index, - face_subface_int, face_subface_ext, - face_data_set_int, - face_data_set_ext, - fe_values_face_int, fe_values_face_ext, - penalty, - fe_collection[i_fele], fe_collection[i_fele_n], - used_face_quadrature, - current_metric_dofs_indices, neighbor_metric_dofs_indices, - current_dofs_indices, neighbor_dofs_indices, - current_cell_rhs, neighbor_cell_rhs, - compute_dRdW, compute_dRdX, compute_d2R); - //} else { - // assemble_face_term_explicit ( - // current_cell, - // current_cell_index, - // neighbor_cell_index, - // fe_values_face_int, fe_values_face_ext, - // penalty, - // current_dofs_indices, neighbor_dofs_indices, - // current_cell_rhs, neighbor_cell_rhs); - //} - - // Add local contribution from neighbor cell to global vector - for (unsigned int i=0; iperiodic_neighbor(iface); + metric_neighbor_cell->get_dof_indices(neighbor_metric_dofs_indices); + const unsigned int poly_degree_ext = i_fele_n; + const unsigned int grid_degree_ext = this->high_order_grid->fe_system.tensor_degree(); + //constructor doesn't build anything + OPERATOR::metric_operators metric_oper_ext(nstate, poly_degree_ext, grid_degree_ext, + store_vol_flux_nodes, + store_surf_flux_nodes); + assemble_face_term_and_build_operators( + current_cell, + neighbor_cell, + current_cell_index, + neighbor_cell_index, + iface, + neighbor_iface, + penalty, + current_dofs_indices, + neighbor_dofs_indices, + current_metric_dofs_indices, + neighbor_metric_dofs_indices, + poly_degree, + poly_degree_ext, + grid_degree, + grid_degree_ext, + soln_basis_int, + soln_basis_ext, + flux_basis_int, + flux_basis_ext, + flux_basis_stiffness, + metric_oper_int, + metric_oper_ext, + mapping_basis, + mapping_support_points, + fe_values_collection_face_int, + fe_values_collection_face_ext, + current_cell_rhs, + neighbor_cell_rhs, + current_cell_rhs_aux, + rhs, + rhs_aux, + compute_auxiliary_right_hand_side, + compute_dRdW, compute_dRdX, compute_d2R); + } + } // CASE 3: NEIGHBOUR IS FINER // Occurs if the face has children - // Do nothing. - // The face contribution from the current cell will appear then the finer neighbor cell is assembled. - } else if (current_cell->face(iface)->has_children()) { - + else if (current_cell->face(iface)->has_children()) + { + // Do nothing. + // The face contribution from the current cell will appear then the finer neighbor cell is assembled. + } // CASE 4: NEIGHBOR IS COARSER // Assemble face residual. - } else if (current_cell->neighbor(iface)->face(current_cell->neighbor_face_no(iface))->has_children()) { - + else if (current_cell->neighbor(iface)->face(current_cell->neighbor_face_no(iface))->has_children()) + { Assert (current_cell->neighbor(iface).state() == dealii::IteratorState::valid, dealii::ExcInternalError()); Assert (!(current_cell->neighbor(iface)->has_children()), dealii::ExcInternalError()); @@ -862,7 +907,7 @@ void DGBase::assemble_cell_residual ( } Assert(neighbor_i_subface != n_subface, dealii::ExcInternalError()); - const int i_fele_n = neighbor_cell->active_fe_index(), i_quad_n = i_fele_n, i_mapp_n = 0; + const int i_fele_n = neighbor_cell->active_fe_index();//, i_quad_n = i_fele_n, i_mapp_n = 0; const unsigned int n_dofs_neigh_cell = fe_collection[i_fele_n].n_dofs_per_cell(); dealii::Vector neighbor_cell_rhs (n_dofs_neigh_cell); // Defaults to 0.0 initialization @@ -871,73 +916,61 @@ void DGBase::assemble_cell_residual ( neighbor_dofs_indices.resize(n_dofs_neigh_cell); neighbor_cell->get_dof_indices (neighbor_dofs_indices); - fe_values_collection_face_int.reinit (current_cell, iface, i_quad, i_mapp, i_fele); - const dealii::FEFaceValues &fe_values_face_int = fe_values_collection_face_int.get_present_fe_values(); - - fe_values_collection_subface.reinit (neighbor_cell, neighbor_iface, neighbor_i_subface, i_quad_n, i_mapp_n, i_fele_n); - const dealii::FESubfaceValues &fe_values_face_ext = fe_values_collection_subface.get_present_fe_values(); - const real penalty1 = evaluate_penalty_scaling (current_cell, iface, fe_collection); const real penalty2 = evaluate_penalty_scaling (neighbor_cell, neighbor_iface, fe_collection); const real penalty = 0.5 * (penalty1 + penalty2); const dealii::types::global_dof_index neighbor_cell_index = neighbor_cell->active_cell_index(); - //if ( compute_dRdW || compute_dRdX || compute_d2R ) { - const auto metric_neighbor_cell = current_metric_cell->neighbor(iface); - metric_neighbor_cell->get_dof_indices(neighbor_metric_dofs_indices); - - const dealii::Quadrature &used_face_quadrature = face_quadrature_collection[(i_quad_n > i_quad) ? i_quad_n : i_quad]; // Use larger quadrature order on the face - std::pair face_subface_int = std::make_pair(iface, -1); - std::pair face_subface_ext = std::make_pair(neighbor_iface, (int)neighbor_i_subface); - - const auto face_data_set_int = dealii::QProjector::DataSetDescriptor::face( - dealii::ReferenceCell::get_hypercube(dim), - iface, - current_cell->face_orientation(iface), - current_cell->face_flip(iface), - current_cell->face_rotation(iface), - used_face_quadrature.size()); - const auto face_data_set_ext = dealii::QProjector::DataSetDescriptor::subface ( - dealii::ReferenceCell::get_hypercube(dim), - neighbor_iface, - neighbor_i_subface, - neighbor_cell->face_orientation(neighbor_iface), - neighbor_cell->face_flip(neighbor_iface), - neighbor_cell->face_rotation(neighbor_iface), - used_face_quadrature.size(), - neighbor_cell->subface_case(neighbor_iface)); - assemble_face_term_derivatives ( - current_cell, - current_cell_index, - neighbor_cell_index, - face_subface_int, face_subface_ext, - face_data_set_int, - face_data_set_ext, - fe_values_face_int, fe_values_face_ext, - penalty, - fe_collection[i_fele], fe_collection[i_fele_n], - used_face_quadrature, - current_metric_dofs_indices, neighbor_metric_dofs_indices, - current_dofs_indices, neighbor_dofs_indices, - current_cell_rhs, neighbor_cell_rhs, - compute_dRdW, compute_dRdX, compute_d2R); - //} else { - // assemble_face_term_explicit ( - // current_cell, - // current_cell_index, - // neighbor_cell_index, - // fe_values_face_int, fe_values_face_ext, - // penalty, - // current_dofs_indices, neighbor_dofs_indices, - // current_cell_rhs, neighbor_cell_rhs); - //} - // Add local contribution from neighbor cell to global vector - for (unsigned int i=0; ineighbor(iface); + metric_neighbor_cell->get_dof_indices(neighbor_metric_dofs_indices); + + const unsigned int poly_degree_ext = i_fele_n; + const unsigned int grid_degree_ext = this->high_order_grid->fe_system.tensor_degree(); + //Check if the poly degree or mapping changed order, in which case, then we re-compute the corresponding basis + OPERATOR::metric_operators metric_oper_ext(nstate, poly_degree_ext, grid_degree_ext, + store_vol_flux_nodes, + store_surf_flux_nodes); + + assemble_subface_term_and_build_operators( + current_cell, + neighbor_cell, + current_cell_index, + neighbor_cell_index, + iface, + neighbor_iface, + neighbor_i_subface, + penalty, + current_dofs_indices, + neighbor_dofs_indices, + current_metric_dofs_indices, + neighbor_metric_dofs_indices, + poly_degree, + poly_degree_ext, + grid_degree, + grid_degree_ext, + soln_basis_int, + soln_basis_ext, + flux_basis_int, + flux_basis_ext, + flux_basis_stiffness, + metric_oper_int, + metric_oper_ext, + mapping_basis, + mapping_support_points, + fe_values_collection_face_int, + fe_values_collection_subface, + current_cell_rhs, + neighbor_cell_rhs, + current_cell_rhs_aux, + rhs, + rhs_aux, + compute_auxiliary_right_hand_side, + compute_dRdW, compute_dRdX, compute_d2R); + } // CASE 5: NEIGHBOR CELL HAS SAME COARSENESS // Therefore, we need to choose one of them to do the work - } else if ( current_cell_should_do_the_work(current_cell, current_cell->neighbor(iface)) ) { + else if (current_cell_should_do_the_work(current_cell, current_cell->neighbor(iface))) + { Assert (current_cell->neighbor(iface).state() == dealii::IteratorState::valid, dealii::ExcInternalError()); const auto neighbor_cell = current_cell->neighbor_or_periodic_neighbor(iface); @@ -955,80 +988,80 @@ void DGBase::assemble_cell_residual ( neighbor_dofs_indices.resize(n_dofs_neigh_cell); neighbor_cell->get_dof_indices (neighbor_dofs_indices); - fe_values_collection_face_int.reinit (current_cell, iface, i_quad, i_mapp, i_fele); - const dealii::FEFaceValues &fe_values_face_int = fe_values_collection_face_int.get_present_fe_values(); - - const int i_fele_n = neighbor_cell->active_fe_index(), i_quad_n = i_fele_n, i_mapp_n = 0; - fe_values_collection_face_ext.reinit (neighbor_cell, neighbor_iface, i_quad_n, i_mapp_n, i_fele_n); - const dealii::FEFaceValues &fe_values_face_ext = fe_values_collection_face_ext.get_present_fe_values(); + const int i_fele_n = neighbor_cell->active_fe_index(); + // Compute penalty. const real penalty1 = evaluate_penalty_scaling (current_cell, iface, fe_collection); const real penalty2 = evaluate_penalty_scaling (neighbor_cell, neighbor_iface, fe_collection); const real penalty = 0.5 * (penalty1 + penalty2); const dealii::types::global_dof_index neighbor_cell_index = neighbor_cell->active_cell_index(); - //if ( compute_dRdW || compute_dRdX || compute_d2R ) { - const auto metric_neighbor_cell = current_metric_cell->neighbor_or_periodic_neighbor(iface); - metric_neighbor_cell->get_dof_indices(neighbor_metric_dofs_indices); - const dealii::Quadrature &used_face_quadrature = face_quadrature_collection[(i_quad_n > i_quad) ? i_quad_n : i_quad]; // Use larger quadrature order on the face - - std::pair face_subface_int = std::make_pair(iface, -1); - std::pair face_subface_ext = std::make_pair(neighbor_iface, -1); - const auto face_data_set_int = dealii::QProjector::DataSetDescriptor::face ( - dealii::ReferenceCell::get_hypercube(dim), - iface, - current_cell->face_orientation(iface), - current_cell->face_flip(iface), - current_cell->face_rotation(iface), - used_face_quadrature.size()); - const auto face_data_set_ext = dealii::QProjector::DataSetDescriptor::face ( - dealii::ReferenceCell::get_hypercube(dim), - neighbor_iface, - neighbor_cell->face_orientation(neighbor_iface), - neighbor_cell->face_flip(neighbor_iface), - neighbor_cell->face_rotation(neighbor_iface), - used_face_quadrature.size()); - assemble_face_term_derivatives ( - current_cell, - current_cell_index, - neighbor_cell_index, - face_subface_int, face_subface_ext, - face_data_set_int, - face_data_set_ext, - fe_values_face_int, fe_values_face_ext, - penalty, - fe_collection[i_fele], fe_collection[i_fele_n], - used_face_quadrature, - current_metric_dofs_indices, neighbor_metric_dofs_indices, - current_dofs_indices, neighbor_dofs_indices, - current_cell_rhs, neighbor_cell_rhs, - compute_dRdW, compute_dRdX, compute_d2R); - //} else { - // assemble_face_term_explicit ( - // current_cell, - // current_cell_index, - // neighbor_cell_index, - // fe_values_face_int, fe_values_face_ext, - // penalty, - // current_dofs_indices, neighbor_dofs_indices, - // current_cell_rhs, neighbor_cell_rhs); - //} - - // Add local contribution from neighbor cell to global vector - for (unsigned int i=0; ineighbor_or_periodic_neighbor(iface); + metric_neighbor_cell->get_dof_indices(neighbor_metric_dofs_indices); + + const unsigned int poly_degree_ext = i_fele_n; + // In future high_order_grids dof object/metric_cell should store the cell's fe degree. + // For now high_order_grid only handles all cells of same grid degree. + const unsigned int grid_degree_ext = this->high_order_grid->fe_system.tensor_degree(); + //Check if the poly degree or mapping changed order, in which case, then we re-compute the corresponding basis + OPERATOR::metric_operators metric_oper_ext(nstate, poly_degree_ext, grid_degree_ext, + store_vol_flux_nodes, + store_surf_flux_nodes); + + assemble_face_term_and_build_operators( + current_cell, + neighbor_cell, + current_cell_index, + neighbor_cell_index, + iface, + neighbor_iface, + penalty, + current_dofs_indices, + neighbor_dofs_indices, + current_metric_dofs_indices, + neighbor_metric_dofs_indices, + poly_degree, + poly_degree_ext, + grid_degree, + grid_degree_ext, + soln_basis_int, + soln_basis_ext, + flux_basis_int, + flux_basis_ext, + flux_basis_stiffness, + metric_oper_int, + metric_oper_ext, + mapping_basis, + mapping_support_points, + fe_values_collection_face_int, + fe_values_collection_face_ext, + current_cell_rhs, + neighbor_cell_rhs, + current_cell_rhs_aux, + rhs, + rhs_aux, + compute_auxiliary_right_hand_side, + compute_dRdW, compute_dRdX, compute_d2R); + } + else { // Should be faces where the neighbor cell has the same coarseness // but will be evaluated when we visit the other cell. } - - } // end of face loop - // Add local contribution from current cell to global vector - for (unsigned int i=0; i::update_artificial_dissipation_discontinuity_sens artificial_dissipation_c0.update_ghost_values(); } +template +void DGBase::reinit_operators_for_cell_residual_loop( + const unsigned int poly_degree_int, + const unsigned int poly_degree_ext, + const unsigned int /*grid_degree*/, + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::basis_functions &flux_basis_int, + OPERATOR::basis_functions &flux_basis_ext, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::mapping_shape_functions &mapping_basis) +{ + soln_basis_int.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree_int], oneD_quadrature_collection[poly_degree_int]); + soln_basis_int.build_1D_gradient_operator(oneD_fe_collection_1state[poly_degree_int], oneD_quadrature_collection[poly_degree_int]); + soln_basis_int.build_1D_surface_operator(oneD_fe_collection_1state[poly_degree_int], oneD_face_quadrature); + soln_basis_int.build_1D_surface_gradient_operator(oneD_fe_collection_1state[poly_degree_int], oneD_face_quadrature); + + soln_basis_ext.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree_ext], oneD_quadrature_collection[poly_degree_ext]); + soln_basis_ext.build_1D_gradient_operator(oneD_fe_collection_1state[poly_degree_ext], oneD_quadrature_collection[poly_degree_ext]); + soln_basis_ext.build_1D_surface_operator(oneD_fe_collection_1state[poly_degree_ext], oneD_face_quadrature); + soln_basis_ext.build_1D_surface_gradient_operator(oneD_fe_collection_1state[poly_degree_ext], oneD_face_quadrature); + + flux_basis_int.build_1D_volume_operator(oneD_fe_collection_flux[poly_degree_int], oneD_quadrature_collection[poly_degree_int]); + flux_basis_int.build_1D_gradient_operator(oneD_fe_collection_flux[poly_degree_int], oneD_quadrature_collection[poly_degree_int]); + flux_basis_int.build_1D_surface_operator(oneD_fe_collection_flux[poly_degree_int], oneD_face_quadrature); + flux_basis_int.build_1D_surface_gradient_operator(oneD_fe_collection_flux[poly_degree_int], oneD_face_quadrature); + + flux_basis_ext.build_1D_volume_operator(oneD_fe_collection_flux[poly_degree_ext], oneD_quadrature_collection[poly_degree_ext]); + flux_basis_ext.build_1D_gradient_operator(oneD_fe_collection_flux[poly_degree_ext], oneD_quadrature_collection[poly_degree_ext]); + flux_basis_ext.build_1D_surface_operator(oneD_fe_collection_flux[poly_degree_ext], oneD_face_quadrature); + flux_basis_ext.build_1D_surface_gradient_operator(oneD_fe_collection_flux[poly_degree_ext], oneD_face_quadrature); + + //flux basis stiffness operator for skew-symmetric form + flux_basis_stiffness.build_1D_volume_operator(oneD_fe_collection_flux[poly_degree_int], oneD_quadrature_collection[poly_degree_int]); + + //We only need to compute the most recent mapping basis since we compute interior before looping faces + mapping_basis.build_1D_shape_functions_at_grid_nodes(high_order_grid->oneD_fe_system, high_order_grid->oneD_grid_nodes); + mapping_basis.build_1D_shape_functions_at_flux_nodes(high_order_grid->oneD_fe_system, oneD_quadrature_collection[poly_degree_ext], oneD_face_quadrature); +} + template void DGBase::assemble_residual (const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R, const double CFL_mass) { @@ -1349,6 +1422,17 @@ void DGBase::assemble_residual (const bool compute_dRdW, cons dealii::hp::FEValues fe_values_collection_volume_lagrange (mapping_collection, fe_collection_lagrange, volume_quadrature_collection, this->volume_update_flags); + const unsigned int init_grid_degree = high_order_grid->fe_system.tensor_degree(); + OPERATOR::basis_functions soln_basis_int(1, max_degree, init_grid_degree); + OPERATOR::basis_functions soln_basis_ext(1, max_degree, init_grid_degree); + OPERATOR::basis_functions flux_basis_int(1, max_degree, init_grid_degree); + OPERATOR::basis_functions flux_basis_ext(1, max_degree, init_grid_degree); + OPERATOR::local_basis_stiffness flux_basis_stiffness(1, max_degree, init_grid_degree, true); + OPERATOR::mapping_shape_functions mapping_basis(1, max_degree, init_grid_degree); + + reinit_operators_for_cell_residual_loop( + max_degree, max_degree, init_grid_degree, soln_basis_int, soln_basis_ext, flux_basis_int, flux_basis_ext, flux_basis_stiffness, mapping_basis); + solution.update_ghost_values(); int assembly_error = 0; @@ -1360,6 +1444,9 @@ void DGBase::assemble_residual (const bool compute_dRdW, cons // updates model variables only if there is a model if(all_parameters->pde_type == Parameters::AllParameters::PartialDifferentialEquation::physics_model) update_model_variables(); + // assembles and solves for auxiliary variable if necessary. + assemble_auxiliary_residual(); + auto metric_cell = high_order_grid->dof_handler_grid.begin_active(); for (auto soln_cell = dof_handler.begin_active(); soln_cell != dof_handler.end(); ++soln_cell, ++metric_cell) { //for (auto cell = triangulation->begin_active(); cell != triangulation->end(); ++cell) { @@ -1386,7 +1473,15 @@ void DGBase::assemble_residual (const bool compute_dRdW, cons fe_values_collection_face_ext, fe_values_collection_subface, fe_values_collection_volume_lagrange, - right_hand_side); + soln_basis_int, + soln_basis_ext, + flux_basis_int, + flux_basis_ext, + flux_basis_stiffness, + mapping_basis, + false, + right_hand_side, + auxiliary_right_hand_side); } // end of cell loop } catch(...) { assembly_error = 1; @@ -1852,7 +1947,7 @@ void DGBase::output_face_results_vtk (const unsigned int cycl if (iproc == 0) { std::vector filenames; for (unsigned int iproc = 0; iproc < dealii::Utilities::MPI::n_mpi_processes(mpi_communicator); ++iproc) { - std::string fn = this->all_parameters->solution_vtk_files_directory_name + "/" + "surface_solution-" + dealii::Utilities::int_to_string(dim, 1) +"D_maxpoly"+dealii::Utilities::int_to_string(max_degree, 2)+"-"; + std::string fn = "surface_solution-" + dealii::Utilities::int_to_string(dim, 1) +"D_maxpoly"+dealii::Utilities::int_to_string(max_degree, 2)+"-"; fn += dealii::Utilities::int_to_string(cycle, 4) + "."; fn += dealii::Utilities::int_to_string(iproc, 4); fn += ".vtu"; @@ -1968,7 +2063,7 @@ void DGBase::output_results_vtk (const unsigned int cycle, co if (iproc == 0) { std::vector filenames; for (unsigned int iproc = 0; iproc < dealii::Utilities::MPI::n_mpi_processes(mpi_communicator); ++iproc) { - std::string fn = this->all_parameters->solution_vtk_files_directory_name + "/" + "solution-" + dealii::Utilities::int_to_string(dim, 1) +"D_maxpoly"+dealii::Utilities::int_to_string(max_degree, 2)+"-"; + std::string fn = "solution-" + dealii::Utilities::int_to_string(dim, 1) +"D_maxpoly"+dealii::Utilities::int_to_string(max_degree, 2)+"-"; fn += dealii::Utilities::int_to_string(cycle, 4) + "."; fn += dealii::Utilities::int_to_string(iproc, 4); fn += ".vtu"; @@ -1983,13 +2078,27 @@ void DGBase::output_results_vtk (const unsigned int cycle, co } template -void DGBase::allocate_system () +void DGBase::allocate_auxiliary_equation() +{ + for (int idim=0; idim +void DGBase::allocate_system ( + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R) { pcout << "Allocating DG system and initializing FEValues" << std::endl; // This function allocates all the necessary memory to the // system matrices and vectors. dof_handler.distribute_dofs(fe_collection); + //This Cuthill_McKee renumbering for dof_handlr uses a lot of memory in 3D, is there another way? dealii::DoFRenumbering::Cuthill_McKee(dof_handler,true); //const bool reversed_numbering = true; //dealii::DoFRenumbering::Cuthill_McKee(dof_handler, reversed_numbering); @@ -2039,6 +2148,12 @@ void DGBase::allocate_system () right_hand_side.add(1.0); // Avoid 0 initial residual for output and logarithmic visualization. dual.reinit(locally_owned_dofs, ghost_dofs, mpi_communicator); + // Set use_auxiliary_eq flag + set_use_auxiliary_eq(); + + // Allocate for auxiliary equation only. + allocate_auxiliary_equation (); + // System matrix allocation dealii::DynamicSparsityPattern dsp(locally_relevant_dofs); dealii::DoFTools::make_flux_sparsity_pattern(dof_handler, dsp); @@ -2046,7 +2161,9 @@ void DGBase::allocate_system () sparsity_pattern.copy_from(dsp); - system_matrix.reinit(locally_owned_dofs, sparsity_pattern, mpi_communicator); + if (compute_dRdW || compute_dRdX || compute_d2R) { + system_matrix.reinit(locally_owned_dofs, sparsity_pattern, mpi_communicator); + } // system_matrix_transpose.reinit(system_matrix); // Epetra_CrsMatrix *input_matrix = const_cast(&(system_matrix.trilinos_matrix())); @@ -2093,24 +2210,30 @@ void DGBase::allocate_system () d2RdWdW.clear(); d2RdXdX.clear(); - solution_dRdW.reinit(solution); - solution_dRdW *= 0.0; - volume_nodes_dRdW.reinit(high_order_grid->volume_nodes); - volume_nodes_dRdW *= 0.0; + if (compute_dRdW) { + solution_dRdW.reinit(solution); + solution_dRdW *= 0.0; + volume_nodes_dRdW.reinit(high_order_grid->volume_nodes); + volume_nodes_dRdW *= 0.0; + } CFL_mass_dRdW = 0.0; - solution_dRdX.reinit(solution); - solution_dRdX *= 0.0; - volume_nodes_dRdX.reinit(high_order_grid->volume_nodes); - volume_nodes_dRdX *= 0.0; - - solution_d2R.reinit(solution); - solution_d2R *= 0.0; - volume_nodes_d2R.reinit(high_order_grid->volume_nodes); - volume_nodes_d2R *= 0.0; - dual_d2R.reinit(dual); - dual_d2R *= 0.0; + if (compute_dRdX) { + solution_dRdX.reinit(solution); + solution_dRdX *= 0.0; + volume_nodes_dRdX.reinit(high_order_grid->volume_nodes); + volume_nodes_dRdX *= 0.0; + } + + if (compute_d2R) { + solution_d2R.reinit(solution); + solution_d2R *= 0.0; + volume_nodes_d2R.reinit(high_order_grid->volume_nodes); + volume_nodes_d2R *= 0.0; + dual_d2R.reinit(dual); + dual_d2R *= 0.0; + } } template @@ -2168,9 +2291,56 @@ void DGBase::allocate_dRdX () dRdXv.reinit(row_parallel_partitioning, col_parallel_partitioning, dRdXv_sparsity_pattern, MPI_COMM_WORLD); } +template +void DGBase::reinit_operators_for_mass_matrix( + const bool Cartesian_element, + const unsigned int poly_degree, const unsigned int grid_degree, + OPERATOR::mapping_shape_functions &mapping_basis, + OPERATOR::basis_functions &basis, + OPERATOR::local_mass &reference_mass_matrix, + OPERATOR::local_Flux_Reconstruction_operator &reference_FR, + OPERATOR::local_Flux_Reconstruction_operator_aux &reference_FR_aux, + OPERATOR::derivative_p &deriv_p) +{ + using FR_enum = Parameters::AllParameters::Flux_Reconstruction; + const FR_enum FR_Type = this->all_parameters->flux_reconstruction_type; + + using FR_Aux_enum = Parameters::AllParameters::Flux_Reconstruction_Aux; + const FR_Aux_enum FR_Type_Aux = this->all_parameters->flux_reconstruction_aux_type; + + // Note the fe_collection passed for metric mapping operators has to be COLLOCATED ON GRID NODES + mapping_basis.build_1D_shape_functions_at_volume_flux_nodes(high_order_grid->oneD_fe_system, oneD_quadrature_collection[poly_degree]); + + if(Cartesian_element || this->all_parameters->use_weight_adjusted_mass){//then we can factor out det of Jac and rapidly simplify + reference_mass_matrix.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); + } + if(grid_degree > 1 || !Cartesian_element){//then we need to construct dim matrices on the fly + basis.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); + } + if((FR_Type != FR_enum::cDG && Cartesian_element) || (FR_Type != FR_enum::cDG && this->all_parameters->use_weight_adjusted_mass)){ + reference_FR.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); + } + if((use_auxiliary_eq && FR_Type_Aux != FR_Aux_enum::kDG && Cartesian_element) || (FR_Type_Aux != FR_Aux_enum::kDG && this->all_parameters->use_weight_adjusted_mass)){ + reference_FR_aux.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); + } + if(((FR_Type != FR_enum::cDG) || + (use_auxiliary_eq && FR_Type_Aux != FR_Aux_enum::kDG) ) && (grid_degree > 1 || !Cartesian_element)){ + deriv_p.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); + } +} + template void DGBase::evaluate_mass_matrices (bool do_inverse_mass_matrix) -{ +{ + using FR_enum = Parameters::AllParameters::Flux_Reconstruction; + const FR_enum FR_Type = this->all_parameters->flux_reconstruction_type; + + using FR_Aux_enum = Parameters::AllParameters::Flux_Reconstruction_Aux; + const FR_Aux_enum FR_Type_Aux = this->all_parameters->flux_reconstruction_aux_type; + + // flag for energy tests + const bool use_energy = this->all_parameters->use_energy; + // Mass matrix sparsity pattern //dealii::SparsityPattern dsp(dof_handler.n_dofs(), dof_handler.n_dofs(), dof_handler.get_fe_collection().max_dofs_per_cell()); //dealii::SparsityPattern dsp(dof_handler.n_dofs(), dof_handler.n_dofs(), dof_handler.get_fe_collection().max_dofs_per_cell()); @@ -2195,101 +2365,695 @@ void DGBase::evaluate_mass_matrices (bool do_inverse_mass_mat } } } + // Initialize global matrices to 0. dealii::SparsityTools::distribute_sparsity_pattern(dsp, dof_handler.locally_owned_dofs(), mpi_communicator, locally_owned_dofs); mass_sparsity_pattern.copy_from(dsp); - if (do_inverse_mass_matrix == true) { + if (do_inverse_mass_matrix) { global_inverse_mass_matrix.reinit(locally_owned_dofs, mass_sparsity_pattern); + if (use_auxiliary_eq){ + global_inverse_mass_matrix_auxiliary.reinit(locally_owned_dofs, mass_sparsity_pattern); + } + if (use_energy){//for split form get energy + global_mass_matrix.reinit(locally_owned_dofs, mass_sparsity_pattern); + if (use_auxiliary_eq){ + global_mass_matrix_auxiliary.reinit(locally_owned_dofs, mass_sparsity_pattern); + } + } } else { global_mass_matrix.reinit(locally_owned_dofs, mass_sparsity_pattern); + if (use_auxiliary_eq){ + global_mass_matrix_auxiliary.reinit(locally_owned_dofs, mass_sparsity_pattern); + } } - //dealii::TrilinosWrappers::SparseMatrix - // matrix_with_correct_size(locally_owned_dofs, - // mpi_communicator, - // dof_handler.get_fe_collection().max_dofs_per_cell()); - //pcout << "Before compress" << std::endl; - //matrix_with_correct_size.compress(dealii::VectorOperation::unknown); - //if (do_inverse_mass_matrix == true) { - // global_inverse_mass_matrix.reinit(matrix_with_correct_size); - //} else { - // global_mass_matrix.reinit(matrix_with_correct_size); - //} - //pcout << "AFter reinit" << std::endl; + // setup 1D operators for ONE STATE. We loop over states in assembly for speedup. + const unsigned int init_grid_degree = high_order_grid->fe_system.tensor_degree(); + OPERATOR::mapping_shape_functions mapping_basis(1, max_degree, init_grid_degree);//first set at max degree + OPERATOR::basis_functions basis(1, max_degree, init_grid_degree); + OPERATOR::local_mass reference_mass_matrix(1, max_degree, init_grid_degree);//first set at max degree + OPERATOR::local_Flux_Reconstruction_operator reference_FR(1, max_degree, init_grid_degree, FR_Type); + OPERATOR::local_Flux_Reconstruction_operator_aux reference_FR_aux(1, max_degree, init_grid_degree, FR_Type_Aux); + OPERATOR::derivative_p deriv_p(1, max_degree, init_grid_degree); - //const dealii::MappingManifold mapping; - //const dealii::MappingQ mapping(max_degree+1); - //const dealii::MappingQ mapping(high_order_grid->max_degree); - // std::cout << "Grid degree: " << high_order_grid->max_degree << std::endl; - //const dealii::MappingQGeneric mapping(high_order_grid->max_degree); - const auto mapping = (*(high_order_grid->mapping_fe_field)); + auto first_cell = dof_handler.begin_active(); + const bool Cartesian_first_element = (first_cell->manifold_id() == dealii::numbers::flat_manifold_id); - dealii::hp::MappingCollection mapping_collection(mapping); + reinit_operators_for_mass_matrix(Cartesian_first_element, max_degree, init_grid_degree, mapping_basis, basis, reference_mass_matrix, reference_FR, reference_FR_aux, deriv_p); - dealii::hp::FEValues fe_values_collection_volume (mapping_collection, fe_collection, volume_quadrature_collection, this->volume_update_flags); ///< FEValues of volume. - for (auto cell = dof_handler.begin_active(); cell!=dof_handler.end(); ++cell) { + //Loop over cells and set the matrices. + auto metric_cell = high_order_grid->dof_handler_grid.begin_active(); + for (auto cell = dof_handler.begin_active(); cell!=dof_handler.end(); ++cell, ++metric_cell) { if (!cell->is_locally_owned()) continue; - const unsigned int mapping_index = 0; + const bool Cartesian_element = (cell->manifold_id() == dealii::numbers::flat_manifold_id); + const unsigned int fe_index_curr_cell = cell->active_fe_index(); - const unsigned int quad_index = fe_index_curr_cell; + const unsigned int curr_grid_degree = high_order_grid->fe_system.tensor_degree();//in the future the metric cell's should store a local grid degree. currently high_order_grid dof_handler_grid doesn't have that capability + + //Check if need to recompute the 1D basis for the current degree (if different than previous cell) + //That is, if the poly_degree, manifold type, or grid degree is different than previous reference operator + if((fe_index_curr_cell != mapping_basis.current_degree) || + (curr_grid_degree != mapping_basis.current_grid_degree)) + { + reinit_operators_for_mass_matrix(Cartesian_element, fe_index_curr_cell, curr_grid_degree, mapping_basis, basis, reference_mass_matrix, reference_FR, reference_FR_aux, deriv_p); + + mapping_basis.current_degree = fe_index_curr_cell; + basis.current_degree = fe_index_curr_cell; + reference_mass_matrix.current_degree = fe_index_curr_cell; + reference_FR.current_degree = fe_index_curr_cell; + reference_FR_aux.current_degree = fe_index_curr_cell; + deriv_p.current_degree = fe_index_curr_cell; + } // Current reference element related to this physical cell - const dealii::FESystem ¤t_fe_ref = fe_collection[fe_index_curr_cell]; - const unsigned int n_dofs_cell = current_fe_ref.n_dofs_per_cell(); - const unsigned int n_quad_pts = volume_quadrature_collection[fe_index_curr_cell].size(); + const unsigned int n_dofs_cell = fe_collection[fe_index_curr_cell].n_dofs_per_cell(); + const unsigned int n_quad_pts = volume_quadrature_collection[fe_index_curr_cell].size(); + + //setup metric cell + const dealii::FESystem &fe_metric = high_order_grid->fe_system; + const unsigned int n_metric_dofs = high_order_grid->fe_system.dofs_per_cell; + const unsigned int n_grid_nodes = n_metric_dofs/dim; + std::vector metric_dof_indices(n_metric_dofs); + metric_cell->get_dof_indices (metric_dof_indices); + // get mapping_support points + std::array,dim> mapping_support_points; + for(int idim=0; idim &index_renumbering = dealii::FETools::hierarchic_to_lexicographic_numbering(curr_grid_degree); + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (high_order_grid->volume_nodes[metric_dof_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + const unsigned int ishape = fe_metric.system_to_component_index(idof).second; + const unsigned int igrid_node = index_renumbering[ishape]; + mapping_support_points[istate][igrid_node] = val; + } - dealii::FullMatrix local_mass_matrix(n_dofs_cell); + //get determinant of Jacobian + OPERATOR::metric_operators metric_oper(nstate, fe_index_curr_cell, curr_grid_degree); + metric_oper.build_determinant_volume_metric_Jacobian( + n_quad_pts, n_grid_nodes, + mapping_support_points, + mapping_basis); - fe_values_collection_volume.reinit (cell, quad_index, mapping_index, fe_index_curr_cell); - const dealii::FEValues &fe_values_volume = fe_values_collection_volume.get_present_fe_values(); + //Get dofs indices to set local matrices in global. + dofs_indices.resize(n_dofs_cell); + cell->get_dof_indices (dofs_indices); + //Compute local matrices and set them in the global system. + evaluate_local_metric_dependent_mass_matrix_and_set_in_global_mass_matrix( + Cartesian_element, + do_inverse_mass_matrix, + fe_index_curr_cell, + curr_grid_degree, + n_quad_pts, + n_dofs_cell, + dofs_indices, + metric_oper, + basis, + reference_mass_matrix, + reference_FR, + reference_FR_aux, + deriv_p); + }//end of cell loop + + //Compress global matrices. + if (do_inverse_mass_matrix) { + global_inverse_mass_matrix.compress(dealii::VectorOperation::insert); + if (use_auxiliary_eq){ + global_inverse_mass_matrix_auxiliary.compress(dealii::VectorOperation::insert); + } + if (use_energy){//for split form energy + global_mass_matrix.compress(dealii::VectorOperation::insert); + if (use_auxiliary_eq){ + global_mass_matrix_auxiliary.compress(dealii::VectorOperation::insert); + } + } + } else { + global_mass_matrix.compress(dealii::VectorOperation::insert); + if (use_auxiliary_eq){ + global_mass_matrix_auxiliary.compress(dealii::VectorOperation::insert); + } + } +} - for (unsigned int itest=0; itest +void DGBase::evaluate_local_metric_dependent_mass_matrix_and_set_in_global_mass_matrix( + const bool Cartesian_element, + const bool do_inverse_mass_matrix, + const unsigned int poly_degree, + const unsigned int /*curr_grid_degree*/, + const unsigned int n_quad_pts, + const unsigned int n_dofs_cell, + const std::vector dofs_indices, + OPERATOR::metric_operators &metric_oper, + OPERATOR::basis_functions &basis, + OPERATOR::local_mass &reference_mass_matrix, + OPERATOR::local_Flux_Reconstruction_operator &reference_FR, + OPERATOR::local_Flux_Reconstruction_operator_aux &reference_FR_aux, + OPERATOR::derivative_p &deriv_p) +{ + using FR_enum = Parameters::AllParameters::Flux_Reconstruction; + const FR_enum FR_Type = this->all_parameters->flux_reconstruction_type; + + using FR_Aux_enum = Parameters::AllParameters::Flux_Reconstruction_Aux; + const FR_Aux_enum FR_Type_Aux = this->all_parameters->flux_reconstruction_aux_type; + + dealii::FullMatrix local_mass_matrix(n_dofs_cell); + dealii::FullMatrix local_mass_matrix_inv(n_dofs_cell); + dealii::FullMatrix local_mass_matrix_aux(n_dofs_cell); + dealii::FullMatrix local_mass_matrix_aux_inv(n_dofs_cell); + + for(int istate=0; istate local_mass_matrix_state(n_shape_fns); + dealii::FullMatrix local_mass_matrix_inv_state(n_shape_fns); + dealii::FullMatrix local_mass_matrix_aux_state(n_shape_fns); + dealii::FullMatrix local_mass_matrix_aux_inv_state(n_shape_fns); + // compute mass matrix and inverse the standard way + if(this->all_parameters->use_weight_adjusted_mass == false){ + //check if Cartesian grid because we can factor out determinant of Jacobian + if(Cartesian_element){ + local_mass_matrix_state.add(metric_oper.det_Jac_vol[0], + reference_mass_matrix.tensor_product_state( + 1, + reference_mass_matrix.oneD_vol_operator, + reference_mass_matrix.oneD_vol_operator, + reference_mass_matrix.oneD_vol_operator)); + if(use_auxiliary_eq){ + local_mass_matrix_aux_state.add(1.0, local_mass_matrix_state); + } + if(FR_Type != FR_enum::cDG){ + local_mass_matrix_state.add(metric_oper.det_Jac_vol[0], + reference_FR.build_dim_Flux_Reconstruction_operator( + reference_mass_matrix.oneD_vol_operator, + 1, + n_shape_fns)); + } + if(use_auxiliary_eq){ + if(FR_Type_Aux != FR_Aux_enum::kDG){ + local_mass_matrix_aux_state.add(metric_oper.det_Jac_vol[0], + reference_FR_aux.build_dim_Flux_Reconstruction_operator( + reference_mass_matrix.oneD_vol_operator, + 1, + n_shape_fns)); + } + } + if(do_inverse_mass_matrix){ + local_mass_matrix_inv_state.invert(local_mass_matrix_state); + if(use_auxiliary_eq) + local_mass_matrix_aux_inv_state.invert(local_mass_matrix_aux_state); + } + } + //if not a linear grid, we have to build the dim matrices on the fly + else{ + //quadrature weights + const std::vector &quad_weights = volume_quadrature_collection[poly_degree].get_weights(); + local_mass_matrix_state = reference_mass_matrix.build_dim_mass_matrix( + 1, + n_shape_fns, n_quad_pts, + basis, + metric_oper.det_Jac_vol, + quad_weights); + + if(use_auxiliary_eq) local_mass_matrix_aux_state.add(1.0, local_mass_matrix_state); + + if(FR_Type != FR_enum::cDG){ + dealii::FullMatrix local_FR(n_shape_fns); + local_FR = reference_FR.build_dim_Flux_Reconstruction_operator_directly( + 1, + n_shape_fns, + deriv_p.oneD_vol_operator, + local_mass_matrix_state); + local_mass_matrix_state.add(1.0, local_FR); + } + if(use_auxiliary_eq){ + if(FR_Type_Aux != FR_Aux_enum::kDG){ + dealii::FullMatrix local_FR_aux(n_shape_fns); + local_FR_aux = reference_FR_aux.build_dim_Flux_Reconstruction_operator_directly( + 1, + n_shape_fns, + deriv_p.oneD_vol_operator, + local_mass_matrix_aux_state); + local_mass_matrix_aux_state.add(1.0, local_FR_aux); + } + } + } + if(do_inverse_mass_matrix){ + local_mass_matrix_inv_state.invert(local_mass_matrix_state); + if(use_auxiliary_eq) + local_mass_matrix_aux_inv_state.invert(local_mass_matrix_aux_state); + } + } + else{//do weight adjusted inverse + //Weight-adjusted framework based off Cicchino, Alexander, and Sivakumaran Nadarajah. "Nonlinearly Stable Split Forms for the Weight-Adjusted Flux Reconstruction High-Order Method: Curvilinear Numerical Validation." AIAA SCITECH 2022 Forum. 2022 for FR. For a DG background please refer to Chan, Jesse, and Lucas C. Wilcox. "On discretely entropy stable weight-adjusted discontinuous Galerkin methods: curvilinear meshes." Journal of Computational Physics 378 (2019): 366-393. Section 4.1. + //quadrature weights + const std::vector &quad_weights = volume_quadrature_collection[poly_degree].get_weights(); + std::vector J_inv(n_quad_pts); + for(unsigned int iquad=0; iquad local_weighted_mass_matrix(n_shape_fns); + dealii::FullMatrix local_weighted_mass_matrix_aux(n_shape_fns); + local_weighted_mass_matrix = reference_mass_matrix.build_dim_mass_matrix( + 1, + n_shape_fns, n_quad_pts, + basis, + J_inv, + quad_weights); + if(use_auxiliary_eq) + local_weighted_mass_matrix_aux.add(1.0, local_weighted_mass_matrix); + + if(FR_Type != FR_enum::cDG){ + dealii::FullMatrix local_FR(n_shape_fns); + local_FR = reference_FR.build_dim_Flux_Reconstruction_operator_directly( + 1, + n_shape_fns, + deriv_p.oneD_vol_operator, + local_weighted_mass_matrix); + local_weighted_mass_matrix.add(1.0, local_FR); + } + //auxiliary weighted not correct and not yet implemented properly... + if(use_auxiliary_eq){ + if(FR_Type_Aux != FR_Aux_enum::kDG){ + dealii::FullMatrix local_FR_aux(n_shape_fns); + local_FR_aux = reference_FR_aux.build_dim_Flux_Reconstruction_operator_directly( + 1, + n_shape_fns, + deriv_p.oneD_vol_operator, + local_mass_matrix); + local_weighted_mass_matrix_aux.add(1.0, local_FR_aux); + } + } + dealii::FullMatrix ref_mass_dim(n_shape_fns); + ref_mass_dim = reference_mass_matrix.tensor_product_state( + 1, + reference_mass_matrix.oneD_vol_operator, + reference_mass_matrix.oneD_vol_operator, + reference_mass_matrix.oneD_vol_operator); + if(FR_Type != FR_enum::cDG){ + dealii::FullMatrix local_FR(n_shape_fns); + local_FR = reference_FR.build_dim_Flux_Reconstruction_operator( + reference_mass_matrix.oneD_vol_operator, + 1, + n_shape_fns); + ref_mass_dim.add(1.0, local_FR); + } + dealii::FullMatrix ref_mass_dim_inv(n_shape_fns); + ref_mass_dim_inv.invert(ref_mass_dim); + dealii::FullMatrix temp(n_shape_fns); + ref_mass_dim_inv.mmult(temp, local_weighted_mass_matrix); + temp.mmult(local_mass_matrix_inv_state, ref_mass_dim_inv); + local_mass_matrix_state.invert(local_mass_matrix_inv_state); + if(use_auxiliary_eq){ + dealii::FullMatrix temp2(n_shape_fns); + ref_mass_dim_inv.mmult(temp2, local_weighted_mass_matrix_aux); + temp2.mmult(local_mass_matrix_aux_inv_state, ref_mass_dim_inv); + local_mass_matrix_aux_state.invert(local_mass_matrix_aux_inv_state); + } + } + //write the ONE state, dim sized mass matrices using symmetry into nstate, dim sized mass matrices. + for(unsigned int test_shape=0; test_shapeall_parameters->use_energy){//for split form energy + global_mass_matrix.set(dofs_indices, local_mass_matrix); + if(use_auxiliary_eq){ + global_mass_matrix_auxiliary.set(dofs_indices, local_mass_matrix_aux); + } + } + } else { + //only store global mass matrix + global_mass_matrix.set(dofs_indices, local_mass_matrix); + if(use_auxiliary_eq){ + global_mass_matrix_auxiliary.set(dofs_indices, local_mass_matrix_aux); + } + } +} + +template +void DGBase::apply_inverse_global_mass_matrix( + dealii::LinearAlgebra::distributed::Vector &input_vector, + dealii::LinearAlgebra::distributed::Vector &output_vector, + const bool use_auxiliary_eq) +{ + using FR_enum = Parameters::AllParameters::Flux_Reconstruction; + using FR_Aux_enum = Parameters::AllParameters::Flux_Reconstruction_Aux; + const FR_enum FR_Type = this->all_parameters->flux_reconstruction_type; + const FR_Aux_enum FR_Type_Aux = this->all_parameters->flux_reconstruction_aux_type; + + const unsigned int init_grid_degree = high_order_grid->fe_system.tensor_degree(); + OPERATOR::mapping_shape_functions mapping_basis(1, max_degree, init_grid_degree); + + OPERATOR::FR_mass_inv mass_inv(1, max_degree, init_grid_degree, FR_Type); + OPERATOR::FR_mass_inv_aux mass_inv_aux(1, max_degree, init_grid_degree, FR_Type_Aux); + + OPERATOR::vol_projection_operator_FR projection_oper(1, max_degree, init_grid_degree, FR_Type, true); + OPERATOR::vol_projection_operator_FR_aux projection_oper_aux(1, max_degree, init_grid_degree, FR_Type_Aux, true); + + mapping_basis.build_1D_shape_functions_at_volume_flux_nodes(high_order_grid->oneD_fe_system, oneD_quadrature_collection[max_degree]); + + const unsigned int grid_degree = this->high_order_grid->fe_system.tensor_degree(); + const dealii::FESystem &fe_metric = high_order_grid->fe_system; + const unsigned int n_metric_dofs = high_order_grid->fe_system.dofs_per_cell; + auto metric_cell = high_order_grid->dof_handler_grid.begin_active(); - const unsigned int istate_trial = fe_values_volume.get_fe().system_to_component_index(itrial).first; + auto first_cell = dof_handler.begin_active(); + const bool Cartesian_first_element = (first_cell->manifold_id() == dealii::numbers::flat_manifold_id) ? true : false; - real value = 0.0; - for (unsigned int iquad=0; iquadis_locally_owned()) continue; + + const unsigned int poly_degree = soln_cell->active_fe_index(); + const unsigned int n_dofs_cell = fe_collection[poly_degree].n_dofs_per_cell(); + std::vector current_dofs_indices; + current_dofs_indices.resize(n_dofs_cell); + soln_cell->get_dof_indices (current_dofs_indices); + + const bool Cartesian_element = (soln_cell->manifold_id() == dealii::numbers::flat_manifold_id); + + // if poly degree, the element manifold type, or grid degree changed for this cell, reinitialize the reference operator + if((poly_degree != mass_inv.current_degree && Cartesian_element && !use_auxiliary_eq) || + (poly_degree != projection_oper.current_degree && (grid_degree > 1 || Cartesian_element) && !use_auxiliary_eq)) + { + mapping_basis.build_1D_shape_functions_at_volume_flux_nodes(high_order_grid->oneD_fe_system, oneD_quadrature_collection[poly_degree]); + if(Cartesian_element){//then we can factor out det of Jac and rapidly simplify + mass_inv.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); + if(use_auxiliary_eq){ + mass_inv_aux.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); } - local_mass_matrix[itrial][itest] = 0.0; - local_mass_matrix[itest][itrial] = 0.0; - if(istate_test==istate_trial) { - local_mass_matrix[itrial][itest] = value; - local_mass_matrix[itest][itrial] = value; + } + else{//we always use weight-adjusted for curvilinear based off the projection operator + projection_oper.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); + if(use_auxiliary_eq){ + projection_oper_aux.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); } } } - dofs_indices.resize(n_dofs_cell); - cell->get_dof_indices (dofs_indices); - if (do_inverse_mass_matrix == true) { - dealii::FullMatrix local_inverse_mass_matrix(n_dofs_cell); - local_inverse_mass_matrix.invert(local_mass_matrix); - global_inverse_mass_matrix.set (dofs_indices, local_inverse_mass_matrix); - } else { - global_mass_matrix.set (dofs_indices, local_mass_matrix); + // get mapping support points and determinant of Jacobian + // setup metric cell + std::vector metric_dof_indices(n_metric_dofs); + metric_cell->get_dof_indices (metric_dof_indices); + // get mapping_support points + std::array,dim> mapping_support_points; + for(int idim=0; idim &index_renumbering = dealii::FETools::hierarchic_to_lexicographic_numbering(grid_degree); + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (high_order_grid->volume_nodes[metric_dof_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + const unsigned int ishape = fe_metric.system_to_component_index(idof).second; + const unsigned int igrid_node = index_renumbering[ishape]; + mapping_support_points[istate][igrid_node] = val; + } + //get determinant of Jacobian + const unsigned int n_quad_pts = volume_quadrature_collection[poly_degree].size(); + const unsigned int n_grid_nodes = n_metric_dofs / dim; + //get determinant of Jacobian + OPERATOR::metric_operators metric_oper(1, poly_degree, grid_degree); + metric_oper.build_determinant_volume_metric_Jacobian( + n_quad_pts, n_grid_nodes, + mapping_support_points, + mapping_basis); + //solve mass inverse times input vector for each state independently + for(int istate=0; istate local_input_vector(n_shape_fns); + std::vector local_output_vector(n_shape_fns); + + for(unsigned int ishape=0; ishape::digits10 + 1); - //global_mass_matrix.print(std::cout); - ////std::abort(); + if(Cartesian_element){ + if(use_auxiliary_eq){ + mass_inv_aux.matrix_vector_mult_1D(local_input_vector, local_output_vector, + mass_inv_aux.oneD_vol_operator, + false, 1.0 / metric_oper.det_Jac_vol[0]); + } + else{ + mass_inv.matrix_vector_mult_1D(local_input_vector, local_output_vector, + mass_inv.oneD_vol_operator, + false, 1.0 / metric_oper.det_Jac_vol[0]); + } + } + else{ + if(use_auxiliary_eq){ + std::vector projection_of_input(n_quad_pts); + projection_oper_aux.matrix_vector_mult_1D(local_input_vector, projection_of_input, + projection_oper_aux.oneD_transpose_vol_operator); + const std::vector &quad_weights = volume_quadrature_collection[poly_degree].get_weights(); + std::vector JxW_inv(n_quad_pts); + for(unsigned int iquad=0; iquad projection_of_input(n_quad_pts); + projection_oper.matrix_vector_mult_1D(local_input_vector, projection_of_input, + projection_oper.oneD_transpose_vol_operator); + const std::vector &quad_weights = volume_quadrature_collection[poly_degree].get_weights(); + std::vector JxW_inv(n_quad_pts); + for(unsigned int iquad=0; iquad +void DGBase::apply_global_mass_matrix( + dealii::LinearAlgebra::distributed::Vector &input_vector, + dealii::LinearAlgebra::distributed::Vector &output_vector, + const bool use_auxiliary_eq) +{ + using FR_enum = Parameters::AllParameters::Flux_Reconstruction; + using FR_Aux_enum = Parameters::AllParameters::Flux_Reconstruction_Aux; + const FR_enum FR_Type = this->all_parameters->flux_reconstruction_type; + const FR_Aux_enum FR_Type_Aux = this->all_parameters->flux_reconstruction_aux_type; + + const unsigned int init_grid_degree = high_order_grid->fe_system.tensor_degree(); + OPERATOR::mapping_shape_functions mapping_basis(1, max_degree, init_grid_degree); + + OPERATOR::FR_mass mass(1, max_degree, init_grid_degree, FR_Type); + OPERATOR::FR_mass_aux mass_aux(1, max_degree, init_grid_degree, FR_Type_Aux); + + OPERATOR::vol_projection_operator projection_oper(1, max_degree, init_grid_degree); + + mapping_basis.build_1D_shape_functions_at_volume_flux_nodes(high_order_grid->oneD_fe_system, oneD_quadrature_collection[max_degree]); + + const unsigned int grid_degree = this->high_order_grid->fe_system.tensor_degree(); + const dealii::FESystem &fe_metric = high_order_grid->fe_system; + const unsigned int n_metric_dofs = high_order_grid->fe_system.dofs_per_cell; + auto metric_cell = high_order_grid->dof_handler_grid.begin_active(); + + auto first_cell = dof_handler.begin_active(); + const bool Cartesian_first_element = (first_cell->manifold_id() == dealii::numbers::flat_manifold_id); + + if(use_auxiliary_eq){ + mass_aux.build_1D_volume_operator(oneD_fe_collection_1state[max_degree], oneD_quadrature_collection[max_degree]); + if(grid_degree>1 || !Cartesian_first_element){ + projection_oper.build_1D_volume_operator(oneD_fe_collection_1state[max_degree], oneD_quadrature_collection[max_degree]); + } } + else{ + mass.build_1D_volume_operator(oneD_fe_collection_1state[max_degree], oneD_quadrature_collection[max_degree]); + if(grid_degree>1 || !Cartesian_first_element){ + projection_oper.build_1D_volume_operator(oneD_fe_collection_1state[max_degree], oneD_quadrature_collection[max_degree]); + } + } + + for (auto soln_cell = dof_handler.begin_active(); soln_cell != dof_handler.end(); ++soln_cell, ++metric_cell) { + if (!soln_cell->is_locally_owned()) continue; + + const unsigned int poly_degree = soln_cell->active_fe_index(); + const unsigned int n_dofs_cell = fe_collection[poly_degree].n_dofs_per_cell(); + std::vector current_dofs_indices; + current_dofs_indices.resize(n_dofs_cell); + soln_cell->get_dof_indices (current_dofs_indices); + + const bool Cartesian_element = (soln_cell->manifold_id() == dealii::numbers::flat_manifold_id) ? true : false; + + //if poly degree changed for this cell, rinitialize + if((poly_degree != mass.current_degree && (grid_degree == 1 || Cartesian_element) && !use_auxiliary_eq) || + (poly_degree != projection_oper.current_degree && (grid_degree > 1 || !Cartesian_element) && !use_auxiliary_eq)){ + mapping_basis.build_1D_shape_functions_at_volume_flux_nodes(high_order_grid->oneD_fe_system, oneD_quadrature_collection[poly_degree]); + if(use_auxiliary_eq){ + mass_aux.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); + if(grid_degree>1 || !Cartesian_element){ + projection_oper.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); + } + } + else{ + mass.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); + if(grid_degree>1 || !Cartesian_element){ + projection_oper.build_1D_volume_operator(oneD_fe_collection_1state[poly_degree], oneD_quadrature_collection[poly_degree]); + } + } + } - return; + //get mapping support points and determinant of Jacobian + //setup metric cell + std::vector metric_dof_indices(n_metric_dofs); + metric_cell->get_dof_indices (metric_dof_indices); + // get mapping_support points + std::array,dim> mapping_support_points; + for(int idim=0; idim &index_renumbering = dealii::FETools::hierarchic_to_lexicographic_numbering(grid_degree); + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (high_order_grid->volume_nodes[metric_dof_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + const unsigned int ishape = fe_metric.system_to_component_index(idof).second; + const unsigned int igrid_node = index_renumbering[ishape]; + mapping_support_points[istate][igrid_node] = val; + } + //get determinant of Jacobian + const unsigned int n_quad_pts = volume_quadrature_collection[poly_degree].size(); + const unsigned int n_grid_nodes = n_metric_dofs / dim; + //get determinant of Jacobian + OPERATOR::metric_operators metric_oper(1, poly_degree, grid_degree); + metric_oper.build_determinant_volume_metric_Jacobian( + n_quad_pts, n_grid_nodes, + mapping_support_points, + mapping_basis); + + //solve mass inverse times input vector for each state independently + for(int istate=0; istate local_input_vector(n_shape_fns); + std::vector local_output_vector(n_shape_fns); + + for(unsigned int ishape=0; ishape &quad_weights = volume_quadrature_collection[poly_degree].get_weights(); + dealii::FullMatrix proj_mass(n_quad_pts_1D, n_dofs_1D); + projection_oper.oneD_vol_operator.Tmmult(proj_mass, mass_aux.oneD_vol_operator); + + std::vector projection_of_input(n_quad_pts); + projection_oper.matrix_vector_mult_1D(local_input_vector, projection_of_input, + proj_mass); + std::vector JxW(n_quad_pts); + for(unsigned int iquad=0; iquad &quad_weights = volume_quadrature_collection[poly_degree].get_weights(); + + std::vector proj_mass(n_shape_fns); + mass.matrix_vector_mult_1D(local_input_vector, proj_mass, + mass.oneD_vol_operator); + std::vector projection_of_input(n_quad_pts); + std::vector ones(n_shape_fns, 1.0); + projection_oper.inner_product_1D(proj_mass, ones, projection_of_input, + projection_oper.oneD_vol_operator); + std::vector JxW(n_quad_pts); + for(unsigned int iquad=0; iquad temp(n_shape_fns); + projection_oper.matrix_vector_mult_1D(JxW, + temp, + projection_oper.oneD_vol_operator); + mass.inner_product_1D(temp, ones, + local_output_vector, + mass.oneD_vol_operator); + + } + } + + for(unsigned int ishape=0; ishape @@ -2514,6 +3278,11 @@ real2 DGBase::discontinuity_sensor( return eps; } +template +void DGBase::set_current_time(const real current_time_input) +{ + this->current_time = current_time_input; +} // No support for anisotropic mesh refinement with parallel::distributed::Triangulation // template // void DGBase::set_anisotropic_flags() diff --git a/src/dg/dg.h b/src/dg/dg.h index c940fb7dc..41ce18342 100644 --- a/src/dg/dg.h +++ b/src/dg/dg.h @@ -39,6 +39,7 @@ #include "numerical_flux/convective_numerical_flux.hpp" #include "numerical_flux/viscous_numerical_flux.hpp" #include "parameters/all_parameters.h" +#include "operators/operators.h" #include "artificial_dissipation_factory.h" // Template specialization of MappingFEField @@ -99,6 +100,10 @@ class DGBase * DGBase cannot use nstate as a compile-time known. */ const unsigned int max_degree; + /// Maximum grid degree used for hp-refi1nement. + /** This is known through the constructor parameters. + * DGBase cannot use nstate as a compile-time known. */ + const unsigned int max_grid_degree; /// Principal constructor that will call delegated constructor. /** Will initialize mapping, fe_dg, all_parameters, volume_quadrature, and face_quadrature @@ -127,8 +132,11 @@ class DGBase dealii::hp::FECollection, // Solution FE dealii::hp::QCollection, // Volume quadrature dealii::hp::QCollection, // Face quadrature - dealii::hp::QCollection<1>, // 1D quadrature for strong form - dealii::hp::FECollection >; // Lagrange polynomials for strong form + dealii::hp::FECollection, // Lagrange polynomials for strong form + dealii::hp::FECollection<1>, // Solution FE 1D + dealii::hp::FECollection<1>, // Solution FE 1D for a single state + dealii::hp::FECollection<1>, // Collocated flux basis 1D for strong form + dealii::hp::QCollection<1> >; // 1D quadrature for strong form /// Delegated constructor that initializes collections. /** Since a function is used to generate multiple different objects, a delegated @@ -167,7 +175,9 @@ class DGBase /// Allocates the system. /** Must be done after setting the mesh and before assembling the system. */ - virtual void allocate_system (); + virtual void allocate_system (const bool compute_dRdW = true, + const bool compute_dRdX = true, + const bool compute_d2R = true); private: /// Allocates the second derivatives. @@ -199,12 +209,66 @@ class DGBase /// cell-wise is taken into account. void time_scaled_mass_matrices(const real scale); + /// Builds needed operators for cell residual loop. + void reinit_operators_for_cell_residual_loop( + const unsigned int poly_degree_int, + const unsigned int poly_degree_ext, + const unsigned int grid_degree, + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::basis_functions &flux_basis_int, + OPERATOR::basis_functions &flux_basis_ext, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::mapping_shape_functions &mapping_basis); + + /// Builds needed operators to compute mass matrices/inverses efficiently. + void reinit_operators_for_mass_matrix( + const bool Cartesian_element, + const unsigned int poly_degree, const unsigned int grid_degree, + OPERATOR::mapping_shape_functions &mapping_basis, + OPERATOR::basis_functions &basis, + OPERATOR::local_mass &reference_mass_matrix, + OPERATOR::local_Flux_Reconstruction_operator &reference_FR, + OPERATOR::local_Flux_Reconstruction_operator_aux &reference_FR_aux, + OPERATOR::derivative_p &deriv_p); + /// Allocates and evaluates the mass matrices for the entire grid - /** Although straightforward, this has not been tested yet. - * Will be required for accurate time-stepping or nonlinear problems - */ void evaluate_mass_matrices (bool do_inverse_mass_matrix = false); + /// Evaluates the metric dependent local mass matrices and inverses, then sets them in the global matrices. + void evaluate_local_metric_dependent_mass_matrix_and_set_in_global_mass_matrix( + const bool Cartesian_element,//Flag if cell is Cartesian + const bool do_inverse_mass_matrix, + const unsigned int poly_degree, + const unsigned int curr_grid_degree, + const unsigned int n_quad_pts, + const unsigned int n_dofs_cell, + const std::vector dofs_indices, + OPERATOR::metric_operators &metric_oper, + OPERATOR::basis_functions &basis, + OPERATOR::local_mass &reference_mass_matrix, + OPERATOR::local_Flux_Reconstruction_operator &reference_FR, + OPERATOR::local_Flux_Reconstruction_operator_aux &reference_FR_aux, + OPERATOR::derivative_p &deriv_p); + + /// Applies the inverse of the local metric dependent mass matrices when the global is not stored. + /** We use matrix-free methods to apply the inverse of the local mass matrix on-the-fly + * in each cell using sum-factorization techniques. + */ + void apply_inverse_global_mass_matrix( + dealii::LinearAlgebra::distributed::Vector &input_vector, + dealii::LinearAlgebra::distributed::Vector &output_vector, + const bool use_auxiliary_eq = false); + + /// Applies the local metric dependent mass matrices when the global is not stored. + /** We use matrix-free methods to apply the local mass matrix on-the-fly + * in each cell using sum-factorization techniques. + */ + void apply_global_mass_matrix( + dealii::LinearAlgebra::distributed::Vector &input_vector, + dealii::LinearAlgebra::distributed::Vector &output_vector, + const bool use_auxiliary_eq = false); + /// Evaluates the maximum stable time step /** If exact_time_stepping = true, use the same time step for the entire solution * NOT YET IMPLEMENTED @@ -251,6 +315,14 @@ class DGBase /// Global inverser mass matrix /** Should be block diagonal where each block contains the inverse mass matrix of each cell. */ dealii::TrilinosWrappers::SparseMatrix global_inverse_mass_matrix; + + /// Global auxiliary mass matrix. + /** Note that it has a mass matrix in each dimension since the auxiliary variable is a tensor of size dim. We use the same matrix in each dim.*/ + dealii::TrilinosWrappers::SparseMatrix global_mass_matrix_auxiliary; + + /// Global inverse of the auxiliary mass matrix + dealii::TrilinosWrappers::SparseMatrix global_inverse_mass_matrix_auxiliary; + /// System matrix corresponding to the derivative of the right_hand_side with /// respect to the solution dealii::TrilinosWrappers::SparseMatrix system_matrix; @@ -320,6 +392,12 @@ class DGBase * and has write-access to all locally_owned_dofs */ dealii::LinearAlgebra::distributed::Vector solution; + + ///The auxiliary equations' right hand sides. + std::array,dim> auxiliary_right_hand_side; + + ///The auxiliary equations' solution. + std::array,dim> auxiliary_solution; private: /// Modal coefficients of the solution used to compute dRdW last /// Will be used to avoid recomputing dRdW. @@ -485,7 +563,15 @@ class DGBase dealii::hp::FEFaceValues &fe_values_collection_face_ext, dealii::hp::FESubfaceValues &fe_values_collection_subface, dealii::hp::FEValues &fe_values_collection_volume_lagrange, - dealii::LinearAlgebra::distributed::Vector &rhs); + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::basis_functions &flux_basis_int, + OPERATOR::basis_functions &flux_basis_ext, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::mapping_shape_functions &mapping_basis, + const bool compute_auxiliary_right_hand_side,//flag on whether computing the Auxiliary variable's equations' residuals + dealii::LinearAlgebra::distributed::Vector &rhs, + std::array,dim> &rhs_aux); /// Finite Element Collection for p-finite-element to represent the solution /** This is a collection of FESystems */ @@ -503,8 +589,6 @@ class DGBase dealii::hp::QCollection volume_quadrature_collection; /// Quadrature used to evaluate face integrals. dealii::hp::QCollection face_quadrature_collection; - /// 1D quadrature to generate Lagrange polynomials for the sake of flux interpolation. - dealii::hp::QCollection<1> oned_quadrature_collection; protected: /// Lagrange basis used in strong form @@ -512,6 +596,33 @@ class DGBase const dealii::hp::FECollection fe_collection_lagrange; public: + + /// 1D Finite Element Collection for p-finite-element to represent the solution + /** This is a collection of FESystems for 1D. */ + const dealii::hp::FECollection<1> oneD_fe_collection; + + /// 1D Finite Element Collection for p-finite-element to represent the solution for a single state. + /** This is a collection of FESystems for 1D. + * Since each state is represented by the same polynomial degree, for the RHS, + * we only need to store the 1D basis functions for a single state. + */ + const dealii::hp::FECollection<1> oneD_fe_collection_1state; + /// 1D collocated flux basis used in strong form + /** This is a collection of collocated Lagrange bases for 1D.*/ + const dealii::hp::FECollection<1> oneD_fe_collection_flux; + /// 1D quadrature to generate Lagrange polynomials for the sake of flux interpolation. + dealii::hp::QCollection<1> oneD_quadrature_collection; + /// 1D surface quadrature is always one single point for all poly degrees. + dealii::QGauss<0> oneD_face_quadrature; + + /// Finite Element Collection to represent the high-order grid + /** This is a collection of FESystems. + * Unfortunately, deal.II doesn't have a working hp Mapping FE field. + * Therefore, every grid/cell will use the maximal polynomial mapping regardless of the solution order. + */ + //const dealii::hp::FECollection fe_collection_grid; + //const dealii::FESystem fe_grid; + /// Degrees of freedom handler /* Allows us to iterate over the finite elements' degrees of freedom. * Note that since we are not using FESystem, we need to multiply @@ -525,7 +636,12 @@ class DGBase /// High order grid that will provide the MappingFEField std::shared_ptr> high_order_grid; + /// Sets the current time within DG to be used for unsteady source terms. + void set_current_time(const real current_time_input); + protected: + /// The current time set in set_current_time() + real current_time; /// Continuous distribution of artificial dissipation. const dealii::FE_Q fe_q_artificial_dissipation; @@ -535,8 +651,126 @@ class DGBase /// Artificial dissipation coefficients dealii::LinearAlgebra::distributed::Vector artificial_dissipation_c0; -protected: + /// Builds the necessary operators/fe values and assembles volume residual. + virtual void assemble_volume_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + const dealii::types::global_dof_index current_cell_index, + const std::vector &cell_dofs_indices, + const std::vector &metric_dof_indices, + const unsigned int poly_degree, + const unsigned int grid_degree, + OPERATOR::basis_functions &soln_basis, + OPERATOR::basis_functions &flux_basis, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper, + OPERATOR::mapping_shape_functions &mapping_basis, + std::array,dim> &mapping_support_points, + dealii::hp::FEValues &fe_values_collection_volume, + dealii::hp::FEValues &fe_values_collection_volume_lagrange, + const dealii::FESystem ¤t_fe_ref, + dealii::Vector &local_rhs_int_cell, + std::vector> &local_auxiliary_RHS, + const bool compute_auxiliary_right_hand_side, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R) = 0; + + /// Builds the necessary operators/fe values and assembles boundary residual. + virtual void assemble_boundary_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + const dealii::types::global_dof_index current_cell_index, + const unsigned int iface, + const unsigned int boundary_id, + const real penalty, + const std::vector &cell_dofs_indices, + const std::vector &metric_dof_indices, + const unsigned int poly_degree, + const unsigned int grid_degree, + OPERATOR::basis_functions &soln_basis, + OPERATOR::basis_functions &flux_basis, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper, + OPERATOR::mapping_shape_functions &mapping_basis, + std::array,dim> &mapping_support_points, + dealii::hp::FEFaceValues &fe_values_collection_face_int, + const dealii::FESystem ¤t_fe_ref, + dealii::Vector &local_rhs_int_cell, + std::vector> &local_auxiliary_RHS, + const bool compute_auxiliary_right_hand_side, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R) = 0; + + /// Builds the necessary operators/fe values and assembles face residual. + virtual void assemble_face_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + typename dealii::DoFHandler::active_cell_iterator neighbor_cell, + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int iface, + const unsigned int neighbor_iface, + const real penalty, + const std::vector ¤t_dofs_indices, + const std::vector &neighbor_dofs_indices, + const std::vector ¤t_metric_dofs_indices, + const std::vector &neighbor_metric_dofs_indices, + const unsigned int poly_degree_int, + const unsigned int poly_degree_ext, + const unsigned int grid_degree_int, + const unsigned int grid_degree_ext, + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::basis_functions &flux_basis_int, + OPERATOR::basis_functions &flux_basis_ext, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper_int, + OPERATOR::metric_operators &metric_oper_ext, + OPERATOR::mapping_shape_functions &mapping_basis, + std::array,dim> &mapping_support_points, + dealii::hp::FEFaceValues &fe_values_collection_face_int, + dealii::hp::FEFaceValues &fe_values_collection_face_ext, + dealii::Vector ¤t_cell_rhs, + dealii::Vector &neighbor_cell_rhs, + std::vector> ¤t_cell_rhs_aux, + dealii::LinearAlgebra::distributed::Vector &rhs, + std::array,dim> &rhs_aux, + const bool compute_auxiliary_right_hand_side, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R) = 0; + /// Builds the necessary operators/fe values and assembles subface residual. + virtual void assemble_subface_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + typename dealii::DoFHandler::active_cell_iterator neighbor_cell, + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int iface, + const unsigned int neighbor_iface, + const unsigned int neighbor_i_subface, + const real penalty, + const std::vector ¤t_dofs_indices, + const std::vector &neighbor_dofs_indices, + const std::vector ¤t_metric_dofs_indices, + const std::vector &neighbor_metric_dofs_indices, + const unsigned int poly_degree_int, + const unsigned int poly_degree_ext, + const unsigned int grid_degree_int, + const unsigned int grid_degree_ext, + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::basis_functions &flux_basis_int, + OPERATOR::basis_functions &flux_basis_ext, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper_int, + OPERATOR::metric_operators &metric_oper_ext, + OPERATOR::mapping_shape_functions &mapping_basis, + std::array,dim> &mapping_support_points, + dealii::hp::FEFaceValues &fe_values_collection_face_int, + dealii::hp::FESubfaceValues &fe_values_collection_subface, + dealii::Vector ¤t_cell_rhs, + dealii::Vector &neighbor_cell_rhs, + std::vector> ¤t_cell_rhs_aux, + dealii::LinearAlgebra::distributed::Vector &rhs, + std::array,dim> &rhs_aux, + const bool compute_auxiliary_right_hand_side, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R) = 0; + +protected: /// Evaluate the integral over the cell volume and the specified derivatives. /** Compute both the right-hand side and the corresponding block of dRdW, dRdX, and/or d2R. */ virtual void assemble_volume_term_derivatives( @@ -597,6 +831,9 @@ class DGBase const dealii::types::global_dof_index current_cell_index, const dealii::FEValues &fe_values_volume, const std::vector ¤t_dofs_indices, + const std::vector &metric_dof_indices, + const unsigned int poly_degree, + const unsigned int grid_degree, dealii::Vector ¤t_cell_rhs, const dealii::FEValues &fe_values_lagrange) = 0; /// Evaluate the integral over the cell edges that are on domain boundaries @@ -610,14 +847,20 @@ class DGBase dealii::Vector ¤t_cell_rhs) = 0; /// Evaluate the integral over the internal cell edges virtual void assemble_face_term_explicit( + const unsigned int iface, + const unsigned int neighbor_iface, typename dealii::DoFHandler::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int poly_degree, + const unsigned int grid_degree, const dealii::FEFaceValuesBase &fe_values_face_int, const dealii::FEFaceValuesBase &fe_values_face_ext, const real penalty, const std::vector ¤t_dofs_indices, const std::vector &neighbor_dofs_indices, + const std::vector &metric_dof_indices_int, + const std::vector &metric_dof_indices_ext, dealii::Vector ¤t_cell_rhs, dealii::Vector &neighbor_cell_rhs) = 0; @@ -632,6 +875,12 @@ class DGBase const dealii::UpdateFlags neighbor_face_update_flags = dealii::update_values | dealii::update_gradients | dealii::update_quadrature_points | dealii::update_JxW_values; +public: + /// Allocates the auxiliary equations' variables and right hand side (primarily for Strong form diffusive) + void allocate_auxiliary_equation (); + + /// Asembles the auxiliary equations' residuals and solves. + virtual void assemble_auxiliary_residual () = 0; protected: MPI_Comm mpi_communicator; ///< MPI communicator @@ -678,6 +927,10 @@ class DGBase virtual void allocate_model_variables() = 0; /// Update the necessary variables declared in src/physics/model.h virtual void update_model_variables() = 0; + /// Flag for using the auxiliary equation + bool use_auxiliary_eq; + /// Set use_auxiliary_eq flag + virtual void set_use_auxiliary_eq() = 0; }; // end of DGBase class /// Abstract class templated on the number of state variables @@ -768,6 +1021,9 @@ class DGBaseState : public DGBase /// Update the necessary variables declared in src/physics/model.h void update_model_variables(); + /// Set use_auxiliary_eq flag + void set_use_auxiliary_eq(); + protected: /// Evaluate the time it takes for the maximum wavespeed to cross the cell domain. /** Currently only uses the convective eigenvalues. Future changes would take in account diff --git a/src/dg/residual_sparsity_patterns.cpp b/src/dg/residual_sparsity_patterns.cpp index cfaff76f3..42f9e24c3 100644 --- a/src/dg/residual_sparsity_patterns.cpp +++ b/src/dg/residual_sparsity_patterns.cpp @@ -61,7 +61,7 @@ dealii::SparsityPattern DGBase::get_dRdX_sparsity_pattern () for (; cell != dof_handler.end(); ++cell, ++metric_cell) { if (!cell->is_locally_owned()) continue; - const unsigned int n_resi_cell = fe_collection[cell->active_fe_index()].n_dofs_per_cell(); + const unsigned int n_resi_cell = this->fe_collection[cell->active_fe_index()].n_dofs_per_cell(); resi_indices.resize(n_resi_cell); cell->get_dof_indices (resi_indices); @@ -173,7 +173,7 @@ dealii::SparsityPattern DGBase::get_dRdXs_sparsity_pattern () for (; cell != dof_handler.end(); ++cell) { if (!cell->is_locally_owned()) continue; - const unsigned int n_resi_cell = fe_collection[cell->active_fe_index()].n_dofs_per_cell(); + const unsigned int n_resi_cell = this->fe_collection[cell->active_fe_index()].n_dofs_per_cell(); resi_indices.resize(n_resi_cell); cell->get_dof_indices (resi_indices); diff --git a/src/dg/strong_dg.cpp b/src/dg/strong_dg.cpp index e1e838ef2..22bb6ea13 100644 --- a/src/dg/strong_dg.cpp +++ b/src/dg/strong_dg.cpp @@ -5,6 +5,10 @@ #include #include +#include + +#include + #include #include "ADTypes.hpp" @@ -24,942 +28,2668 @@ DGStrong::DGStrong( const std::shared_ptr triangulation_input) : DGBaseState::DGBaseState(parameters_input, degree, max_degree_input, grid_degree_input, triangulation_input) { } + // Destructor template -DGStrong::~DGStrong () +DGStrong::~DGStrong() { pcout << "Destructing DGStrong..." << std::endl; } +/*********************************************************** +* +* Build operators and solve for RHS +* +***********************************************************/ template -void DGStrong::assemble_boundary_term_derivatives( - typename dealii::DoFHandler::active_cell_iterator /*cell*/, - const dealii::types::global_dof_index current_cell_index, - const unsigned int ,//face_number, - const unsigned int boundary_id, - const dealii::FEFaceValuesBase &fe_values_boundary, - const real penalty, - const dealii::FESystem &,//fe, - const dealii::Quadrature &,//quadrature, - const std::vector &,//metric_dof_indices, - const std::vector &soln_dof_indices, - dealii::Vector &local_rhs_int_cell, - const bool compute_dRdW, - const bool compute_dRdX, - const bool compute_d2R) -{ - (void) current_cell_index; - assert(compute_dRdW); assert(!compute_dRdX); assert(!compute_d2R); - (void) compute_dRdW; (void) compute_dRdX; (void) compute_d2R; - using ADArray = std::array; - using ADArrayTensor1 = std::array< dealii::Tensor<1,dim,FadType>, 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; - - AssertDimension (n_dofs_cell, soln_dof_indices.size()); - - const std::vector &JxW = fe_values_boundary.get_JxW_values (); - const std::vector> &normals = fe_values_boundary.get_normal_vectors (); - - std::vector residual_derivatives(n_dofs_cell); - - 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 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* - - std::vector conv_phys_flux(n_face_quad_pts); - - // AD variable - std::vector< FadType > soln_coeff_int(n_dofs_cell); - const unsigned int n_total_indep = n_dofs_cell; - for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { - soln_coeff_int[idof] = DGBase::solution(soln_dof_indices[idof]); - soln_coeff_int[idof].diff(idof, n_total_indep); +void DGStrong::assemble_volume_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + const dealii::types::global_dof_index current_cell_index, + const std::vector &cell_dofs_indices, + const std::vector &metric_dof_indices, + const unsigned int poly_degree, + const unsigned int grid_degree, + OPERATOR::basis_functions &soln_basis, + OPERATOR::basis_functions &flux_basis, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper, + OPERATOR::mapping_shape_functions &mapping_basis, + std::array,dim> &mapping_support_points, + dealii::hp::FEValues &/*fe_values_collection_volume*/, + dealii::hp::FEValues &/*fe_values_collection_volume_lagrange*/, + const dealii::FESystem &/*current_fe_ref*/, + dealii::Vector &local_rhs_int_cell, + std::vector> &local_auxiliary_RHS, + const bool compute_auxiliary_right_hand_side, + const bool /*compute_dRdW*/, const bool /*compute_dRdX*/, const bool /*compute_d2R*/) +{ + // Check if the current cell's poly degree etc is different then previous cell's. + // If the current cell's poly degree is different, then we recompute the 1D + // polynomial basis functions. Otherwise, we use the previous values in reference space. + if(poly_degree != soln_basis.current_degree){ + soln_basis.current_degree = poly_degree; + flux_basis.current_degree = poly_degree; + mapping_basis.current_degree = poly_degree; + this->reinit_operators_for_cell_residual_loop(poly_degree, poly_degree, grid_degree, soln_basis, soln_basis, flux_basis, flux_basis, flux_basis_stiffness, mapping_basis); } - - for (unsigned int iquad=0; iquad &fe_metric = this->high_order_grid->fe_system; + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + const unsigned int n_grid_nodes = n_metric_dofs / dim; + //Rewrite the high_order_grid->volume_nodes in a way we can use sum-factorization on. + //That is, splitting up the vector by the dimension. + for(int idim=0; idim > quad_pts = fe_values_boundary.get_quadrature_points(); - for (unsigned int iquad=0; iquad normal_int = normals[iquad]; - const dealii::Tensor<1,dim,FadType> normal_ext = -normal_int; - - for (unsigned int idof=0; idof real_quad_point = quad_pts[iquad]; - dealii::Point ad_point; - for (int d=0;dpde_physics_fad->boundary_face_values (boundary_id, ad_point, normal_int, soln_int[iquad], soln_grad_int[iquad], soln_ext[iquad], soln_grad_ext[iquad]); - - // - // Evaluate physical convective flux, physical dissipative flux - // Following the the boundary treatment given by - // Hartmann, R., Numerical Analysis of Higher Order Discontinuous Galerkin Finite Element Methods, - // Institute of Aerodynamics and Flow Technology, DLR (German Aerospace Center), 2008. - // Details given on page 93 - //conv_num_flux_dot_n[iquad] = DGBaseState::conv_num_flux_fad->evaluate_flux(soln_ext[iquad], soln_ext[iquad], normal_int); - - // So, I wasn't able to get Euler manufactured solutions to converge when F* = F*(Ubc, Ubc) - // Changing it back to the standdard F* = F*(Uin, Ubc) - // This is known not be adjoint consistent as per the paper above. Page 85, second to last paragraph. - // Losing 2p+1 OOA on functionals for all PDEs. - conv_num_flux_dot_n[iquad] = DGBaseState::conv_num_flux_fad->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int); - - // Used for strong form - // Which physical convective flux to use? - conv_phys_flux[iquad] = this->pde_physics_fad->convective_flux (soln_int[iquad]); - - // Notice that the flux uses the solution given by the Dirichlet or Neumann boundary condition - diss_soln_num_flux[iquad] = DGBaseState::diss_num_flux_fad->evaluate_solution_flux(soln_ext[iquad], soln_ext[iquad], normal_int); - - ADArrayTensor1 diss_soln_jump_int; - for (int s=0; spde_physics_fad->dissipative_flux (soln_int[iquad], diss_soln_jump_int, current_cell_index); - - diss_auxi_num_flux_dot_n[iquad] = DGBaseState::diss_num_flux_fad->evaluate_auxiliary_flux( - current_cell_index, current_cell_index, - 0.0, 0.0, - soln_int[iquad], soln_ext[iquad], - soln_grad_int[iquad], soln_grad_ext[iquad], - normal_int, penalty, true); - } - - // Boundary integral - for (unsigned int itest=0; itestall_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) { - for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { - //residual_derivatives[idof] = rhs.fastAccessDx(idof); - residual_derivatives[idof] = rhs.fastAccessDx(idof); - } - this->system_matrix.add(soln_dof_indices[itest], soln_dof_indices, residual_derivatives); - } + const std::vector &index_renumbering = dealii::FETools::hierarchic_to_lexicographic_numbering(grid_degree); + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (this->high_order_grid->volume_nodes[metric_dof_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + const unsigned int ishape = fe_metric.system_to_component_index(idof).second; + const unsigned int igrid_node = index_renumbering[ishape]; + mapping_support_points[istate][igrid_node] = val; + } + + //build the volume metric cofactor matrix and the determinant of the volume metric Jacobian + //Also, computes the physical volume flux nodes if needed from flag passed to constructor in dg.cpp + metric_oper.build_volume_metric_operators( + this->volume_quadrature_collection[poly_degree].size(), n_grid_nodes, + mapping_support_points, + mapping_basis, + this->all_parameters->use_invariant_curl_form); + + if(compute_auxiliary_right_hand_side){ + assemble_volume_term_auxiliary_equation ( + cell_dofs_indices, + poly_degree, + soln_basis, + flux_basis, + metric_oper, + local_auxiliary_RHS); + } + else{ + assemble_volume_term_strong( + cell, + current_cell_index, + cell_dofs_indices, + poly_degree, + soln_basis, + flux_basis, + flux_basis_stiffness, + metric_oper, + local_rhs_int_cell); } } template -void DGStrong::assemble_volume_term_derivatives( +void DGStrong::assemble_boundary_term_and_build_operators( typename dealii::DoFHandler::active_cell_iterator /*cell*/, - const dealii::types::global_dof_index current_cell_index, - const dealii::FEValues &fe_values_vol, - const dealii::FESystem &,//fe, - const dealii::Quadrature &,//quadrature, - const std::vector &,//metric_dof_indices, - const std::vector &cell_dofs_indices, - dealii::Vector &local_rhs_int_cell, - const dealii::FEValues &fe_values_lagrange, - const bool compute_dRdW, - const bool compute_dRdX, - const bool compute_d2R) + const dealii::types::global_dof_index current_cell_index, + const unsigned int iface, + const unsigned int boundary_id, + const real penalty, + const std::vector &cell_dofs_indices, + const std::vector &/*metric_dof_indices*/, + const unsigned int poly_degree, + const unsigned int /*grid_degree*/, + OPERATOR::basis_functions &soln_basis, + OPERATOR::basis_functions &flux_basis, + OPERATOR::local_basis_stiffness &/*flux_basis_stiffness*/, + OPERATOR::metric_operators &metric_oper, + OPERATOR::mapping_shape_functions &mapping_basis, + std::array,dim> &mapping_support_points, + dealii::hp::FEFaceValues &/*fe_values_collection_face_int*/, + const dealii::FESystem &/*current_fe_ref*/, + dealii::Vector &local_rhs_int_cell, + std::vector> &local_auxiliary_RHS, + const bool compute_auxiliary_right_hand_side, + const bool /*compute_dRdW*/, const bool /*compute_dRdX*/, const bool /*compute_d2R*/) { - (void) current_cell_index; - assert(compute_dRdW); assert(!compute_dRdX); assert(!compute_d2R); - (void) compute_dRdW; (void) compute_dRdX; (void) compute_d2R; - using ADArray = std::array; - using ADArrayTensor1 = std::array< dealii::Tensor<1,dim,FadType>, 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; - - AssertDimension (n_dofs_cell, cell_dofs_indices.size()); - - const std::vector &JxW = fe_values_vol.get_JxW_values (); - std::vector residual_derivatives(n_dofs_cell); + const dealii::FESystem &fe_metric = this->high_order_grid->fe_system; + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + const unsigned int n_grid_nodes = n_metric_dofs / dim; + //build the surface metric operators for interior + metric_oper.build_facet_metric_operators( + iface, + this->face_quadrature_collection[poly_degree].size(), + n_grid_nodes, + mapping_support_points, + mapping_basis, + this->all_parameters->use_invariant_curl_form); + + if(compute_auxiliary_right_hand_side){ + assemble_boundary_term_auxiliary_equation ( + iface, current_cell_index, poly_degree, + boundary_id, cell_dofs_indices, + soln_basis, metric_oper, + local_auxiliary_RHS); + } + else{ + assemble_boundary_term_strong ( + iface, + current_cell_index, + boundary_id, poly_degree, penalty, + cell_dofs_indices, + soln_basis, + flux_basis, + metric_oper, + local_rhs_int_cell); + } - std::vector< ADArray > soln_at_q(n_quad_pts); - std::vector< ADArrayTensor1 > soln_grad_at_q(n_quad_pts); // Tensor initialize with zeros +} - 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); +template +void DGStrong::assemble_face_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator /*cell*/, + typename dealii::DoFHandler::active_cell_iterator neighbor_cell, + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int iface, + const unsigned int neighbor_iface, + const real penalty, + const std::vector ¤t_dofs_indices, + const std::vector &neighbor_dofs_indices, + const std::vector &/*current_metric_dofs_indices*/, + const std::vector &neighbor_metric_dofs_indices, + const unsigned int poly_degree_int, + const unsigned int poly_degree_ext, + const unsigned int /*grid_degree_int*/, + const unsigned int grid_degree_ext, + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::basis_functions &flux_basis_int, + OPERATOR::basis_functions &flux_basis_ext, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper_int, + OPERATOR::metric_operators &metric_oper_ext, + OPERATOR::mapping_shape_functions &mapping_basis, + std::array,dim> &mapping_support_points, + dealii::hp::FEFaceValues &/*fe_values_collection_face_int*/, + dealii::hp::FEFaceValues &/*fe_values_collection_face_ext*/, + dealii::Vector ¤t_cell_rhs, + dealii::Vector &neighbor_cell_rhs, + std::vector> ¤t_cell_rhs_aux, + dealii::LinearAlgebra::distributed::Vector &rhs, + std::array,dim> &rhs_aux, + const bool compute_auxiliary_right_hand_side, + const bool /*compute_dRdW*/, const bool /*compute_dRdX*/, const bool /*compute_d2R*/) +{ - // AD variable - std::vector< FadType > soln_coeff(n_dofs_cell); - for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { - soln_coeff[idof] = DGBase::solution(cell_dofs_indices[idof]); - soln_coeff[idof].diff(idof, n_dofs_cell); + const dealii::FESystem &fe_metric = this->high_order_grid->fe_system; + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + const unsigned int n_grid_nodes = n_metric_dofs / dim; + //build the surface metric operators for interior + metric_oper_int.build_facet_metric_operators( + iface, + this->face_quadrature_collection[poly_degree_int].size(), + n_grid_nodes, + mapping_support_points, + mapping_basis, + this->all_parameters->use_invariant_curl_form); + + if(poly_degree_ext != soln_basis_ext.current_degree){ + soln_basis_ext.current_degree = poly_degree_ext; + flux_basis_ext.current_degree = poly_degree_ext; + mapping_basis.current_degree = poly_degree_ext; + this->reinit_operators_for_cell_residual_loop(poly_degree_int, poly_degree_ext, grid_degree_ext, soln_basis_int, soln_basis_ext, flux_basis_int, flux_basis_ext, flux_basis_stiffness, mapping_basis); } - for (unsigned int iquad=0; iquadvolume_nodes in a way we can use sum-factorization on. + //that is, splitting up the vector by the dimension. + std::array,dim> mapping_support_points_neigh; + for(int idim=0; idim &index_renumbering = dealii::FETools::hierarchic_to_lexicographic_numbering(grid_degree_ext); + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (this->high_order_grid->volume_nodes[neighbor_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + const unsigned int ishape = fe_metric.system_to_component_index(idof).second; + const unsigned int igrid_node = index_renumbering[ishape]; + mapping_support_points_neigh[istate][igrid_node] = val; + } + //build the metric operators for strong form + metric_oper_ext.build_volume_metric_operators( + this->volume_quadrature_collection[poly_degree_ext].size(), n_grid_nodes, + mapping_support_points_neigh, + mapping_basis, + this->all_parameters->use_invariant_curl_form); } - // Interpolate solution to face - for (unsigned int iquad=0; iquad1) std::cout << "Momentum " << soln_at_q[iquad][1] << std::endl; - //std::cout << "Energy " << soln_at_q[iquad][nstate-1] << std::endl; - // Evaluate physical convective flux and source term - conv_phys_flux_at_q[iquad] = this->pde_physics_fad->convective_flux (soln_at_q[iquad]); - diss_phys_flux_at_q[iquad] = this->pde_physics_fad->dissipative_flux (soln_at_q[iquad], soln_grad_at_q[iquad], current_cell_index); - if(this->all_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term) { - const dealii::Point real_quad_point = fe_values_vol.quadrature_point(iquad); - dealii::Point ad_point; - for (int d=0;dpde_physics_fad->source_term (ad_point, soln_at_q[iquad], current_cell_index); + if(compute_auxiliary_right_hand_side){ + const unsigned int n_dofs_neigh_cell = this->fe_collection[neighbor_cell->active_fe_index()].n_dofs_per_cell(); + std::vector> neighbor_cell_rhs_aux (n_dofs_neigh_cell ); // defaults to 0.0 initialization + assemble_face_term_auxiliary_equation ( + iface, neighbor_iface, + current_cell_index, neighbor_cell_index, + poly_degree_int, poly_degree_ext, + current_dofs_indices, neighbor_dofs_indices, + soln_basis_int, soln_basis_ext, + metric_oper_int, + current_cell_rhs_aux, neighbor_cell_rhs_aux); + // add local contribution from neighbor cell to global vector + for (unsigned int i=0; ife_collection[neighbor_cell->active_fe_index()].n_dofs_per_cell(); + for (unsigned int i=0; i &fe_values_lagrange = this->fe_values_collection_volume_lagrange.get_present_fe_values(); - std::vector flux_divergence(n_quad_pts); +template +void DGStrong::assemble_subface_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + typename dealii::DoFHandler::active_cell_iterator neighbor_cell, + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int iface, + const unsigned int neighbor_iface, + const unsigned int /*neighbor_i_subface*/, + const real penalty, + const std::vector ¤t_dofs_indices, + const std::vector &neighbor_dofs_indices, + const std::vector ¤t_metric_dofs_indices, + const std::vector &neighbor_metric_dofs_indices, + const unsigned int poly_degree_int, + const unsigned int poly_degree_ext, + const unsigned int grid_degree_int, + const unsigned int grid_degree_ext, + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::basis_functions &flux_basis_int, + OPERATOR::basis_functions &flux_basis_ext, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper_int, + OPERATOR::metric_operators &metric_oper_ext, + OPERATOR::mapping_shape_functions &mapping_basis, + std::array,dim> &mapping_support_points, + dealii::hp::FEFaceValues &fe_values_collection_face_int, + dealii::hp::FESubfaceValues &/*fe_values_collection_subface*/, + dealii::Vector ¤t_cell_rhs, + dealii::Vector &neighbor_cell_rhs, + std::vector> ¤t_cell_rhs_aux, + dealii::LinearAlgebra::distributed::Vector &rhs, + std::array,dim> &rhs_aux, + const bool compute_auxiliary_right_hand_side, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R) +{ + assemble_face_term_and_build_operators( + cell, + neighbor_cell, + current_cell_index, + neighbor_cell_index, + iface, + neighbor_iface, + penalty, + current_dofs_indices, + neighbor_dofs_indices, + current_metric_dofs_indices, + neighbor_metric_dofs_indices, + poly_degree_int, + poly_degree_ext, + grid_degree_int, + grid_degree_ext, + soln_basis_int, + soln_basis_ext, + flux_basis_int, + flux_basis_ext, + flux_basis_stiffness, + metric_oper_int, + metric_oper_ext, + mapping_basis, + mapping_support_points, + fe_values_collection_face_int, + fe_values_collection_face_int, + current_cell_rhs, + neighbor_cell_rhs, + current_cell_rhs_aux, + rhs, + rhs_aux, + compute_auxiliary_right_hand_side, + compute_dRdW, compute_dRdX, compute_d2R); - std::array,nstate>,dim> f; - std::array,nstate>,dim> g; +} +/******************************************************************* + * + * + * AUXILIARY EQUATIONS + * + * + *******************************************************************/ - for (int istate = 0; istate +void DGStrong::assemble_auxiliary_residual() +{ + using PDE_enum = Parameters::AllParameters::PartialDifferentialEquation; + using ODE_enum = Parameters::ODESolverParam::ODESolverEnum; + const PDE_enum pde_type = this->all_parameters->pde_type; + if(pde_type == PDE_enum::burgers_viscous){ + pcout << "DG Strong not yet verified for Burgers' viscous. Aborting..." << std::endl; + std::abort(); + } + // NOTE: auxiliary currently only works explicit time advancement - not implicit + if (this->use_auxiliary_eq && !(this->all_parameters->ode_solver_param.ode_solver_type == ODE_enum::implicit_solver)) { + //set auxiliary rhs to 0 + for(int idim=0; idimauxiliary_right_hand_side[idim] = 0; } + //initialize this to use DG cell residual loop. Note, FEValues to be deprecated in future. + const auto mapping = (*(this->high_order_grid->mapping_fe_field)); + + dealii::hp::MappingCollection mapping_collection(mapping); + + dealii::hp::FEValues fe_values_collection_volume (mapping_collection, this->fe_collection, this->volume_quadrature_collection, this->volume_update_flags); ///< FEValues of volume. + dealii::hp::FEFaceValues fe_values_collection_face_int (mapping_collection, this->fe_collection, this->face_quadrature_collection, this->face_update_flags); ///< FEValues of interior face. + dealii::hp::FEFaceValues fe_values_collection_face_ext (mapping_collection, this->fe_collection, this->face_quadrature_collection, this->neighbor_face_update_flags); ///< FEValues of exterior face. + dealii::hp::FESubfaceValues fe_values_collection_subface (mapping_collection, this->fe_collection, this->face_quadrature_collection, this->face_update_flags); ///< FEValues of subface. + + dealii::hp::FEValues fe_values_collection_volume_lagrange (mapping_collection, this->fe_collection_lagrange, this->volume_quadrature_collection, this->volume_update_flags); + + OPERATOR::basis_functions soln_basis_int(nstate, this->max_degree, this->max_grid_degree); + OPERATOR::basis_functions soln_basis_ext(nstate, this->max_degree, this->max_grid_degree); + OPERATOR::basis_functions flux_basis_int(nstate, this->max_degree, this->max_grid_degree); + OPERATOR::basis_functions flux_basis_ext(nstate, this->max_degree, this->max_grid_degree); + OPERATOR::local_basis_stiffness flux_basis_stiffness(nstate, this->max_degree, this->max_grid_degree); + OPERATOR::mapping_shape_functions mapping_basis(nstate, this->max_degree, this->max_grid_degree); + + this->reinit_operators_for_cell_residual_loop( + this->max_degree, this->max_degree, this->max_grid_degree, soln_basis_int, soln_basis_ext, flux_basis_int, flux_basis_ext, flux_basis_stiffness, mapping_basis); + + //loop over cells solving for auxiliary rhs + auto metric_cell = this->high_order_grid->dof_handler_grid.begin_active(); + for (auto soln_cell = this->dof_handler.begin_active(); soln_cell != this->dof_handler.end(); ++soln_cell, ++metric_cell) { + if (!soln_cell->is_locally_owned()) continue; + + this->assemble_cell_residual ( + soln_cell, + metric_cell, + false, false, false, + fe_values_collection_volume, + fe_values_collection_face_int, + fe_values_collection_face_ext, + fe_values_collection_subface, + fe_values_collection_volume_lagrange, + soln_basis_int, + soln_basis_ext, + flux_basis_int, + flux_basis_ext, + flux_basis_stiffness, + mapping_basis, + true, + this->right_hand_side, + this->auxiliary_right_hand_side); + } // end of cell loop + + for(int idim=0; idimauxiliary_right_hand_side[idim].compress(dealii::VectorOperation::add); + //update ghost values + this->auxiliary_right_hand_side[idim].update_ghost_values(); + + //solve for auxiliary solution for each dimension + if(this->all_parameters->use_inverse_mass_on_the_fly) + this->apply_inverse_global_mass_matrix(this->auxiliary_right_hand_side[idim], this->auxiliary_solution[idim], true); + else + this->global_inverse_mass_matrix_auxiliary.vmult(this->auxiliary_solution[idim], this->auxiliary_right_hand_side[idim]); + + //update ghost values of auxiliary solution + this->auxiliary_solution[idim].update_ghost_values(); + } + }//end of if statement for diffusive + else if (this->use_auxiliary_eq && (this->all_parameters->ode_solver_param.ode_solver_type == ODE_enum::implicit_solver)) { + pcout << "ERROR: " << "auxiliary currently only works for explicit time advancement. Aborting..." << std::endl; + std::abort(); + } else { + // Do nothing } +} - // Strong form - // The right-hand side sends all the term to the side of the source term - // Therefore, - // \divergence ( Fconv + Fdiss ) = source - // has the right-hand side - // rhs = - \divergence( Fconv + Fdiss ) + source - // Since we have done an integration by parts, the volume term resulting from the divergence of Fconv and Fdiss - // is negative. Therefore, negative of negative means we add that volume term to the right-hand-side - for (unsigned int itest=0; itest +void DGStrong::assemble_volume_term_auxiliary_equation( + const std::vector ¤t_dofs_indices, + const unsigned int poly_degree, + OPERATOR::basis_functions &soln_basis, + OPERATOR::basis_functions &flux_basis, + OPERATOR::metric_operators &metric_oper, + std::vector> &local_auxiliary_RHS) +{ + //Please see header file for exact formula we are solving. + const unsigned int n_quad_pts = this->volume_quadrature_collection[poly_degree].size(); + const unsigned int n_dofs_cell = this->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_shape_fns = n_dofs_cell / nstate; + const std::vector &quad_weights = this->volume_quadrature_collection[poly_degree].get_weights(); + + //Fetch the modal soln coefficients and the modal auxiliary soln coefficients + //We immediately separate them by state as to be able to use sum-factorization + //in the interpolation operator. If we left it by n_dofs_cell, then the matrix-vector + //mult would sum the states at the quadrature point. + //That is why the basis functions are of derived class state rather than base. + std::array,nstate> soln_coeff; + for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { + const unsigned int istate = this->fe_collection[poly_degree].system_to_component_index(idof).first; + const unsigned int ishape = this->fe_collection[poly_degree].system_to_component_index(idof).second; + if(ishape == 0) + soln_coeff[istate].resize(n_shape_fns); + soln_coeff[istate][ishape] = DGBase::solution(current_dofs_indices[idof]); + } + //Interpolate each state to the quadrature points using sum-factorization + //with the basis functions in each reference direction. + for(int istate=0; istate soln_at_q(n_quad_pts); + //interpolate soln coeff to volume cubature nodes + soln_basis.matrix_vector_mult_1D(soln_coeff[istate], soln_at_q, + soln_basis.oneD_vol_operator); + //the volume integral for the auxiliary equation is the physical integral of the physical gradient of the solution. + //That is, we need to physically integrate (we have determinant of Jacobian cancel) the Eq. (12) (with u for chi) in + //Cicchino, Alexander, et al. "Provably stable flux reconstruction high-order methods on curvilinear elements." Journal of Computational Physics 463 (2022): 111259. + + //apply gradient of reference basis functions on the solution at volume cubature nodes + dealii::Tensor<1,dim,std::vector> ref_gradient_basis_fns_times_soln; + for(int idim=0; idim phys_gradient_u(n_quad_pts); + for(unsigned int iquad=0; iquad rhs(n_shape_fns); + soln_basis.inner_product_1D(phys_gradient_u, quad_weights, + rhs, + soln_basis.oneD_vol_operator, + false, 1.0);//it's added since auxiliary is EQUAL to the gradient of the soln + + //write the the auxiliary rhs for the test function. + for(unsigned int ishape=0; ishape +void DGStrong::assemble_boundary_term_auxiliary_equation( + const unsigned int iface, + const dealii::types::global_dof_index current_cell_index, + const unsigned int poly_degree, + const unsigned int boundary_id, + const std::vector &dofs_indices, + OPERATOR::basis_functions &soln_basis, + OPERATOR::metric_operators &metric_oper, + std::vector> &local_auxiliary_RHS) +{ + (void) current_cell_index; - for (unsigned int iquad=0; iquadface_quadrature_collection[poly_degree].size(); + const unsigned int n_quad_pts_vol = this->volume_quadrature_collection[poly_degree].size(); + const unsigned int n_dofs = this->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_shape_fns = n_dofs / nstate; + AssertDimension (n_dofs, dofs_indices.size()); + + //Extract interior modal coefficients of solution + std::array,nstate> soln_coeff; + for (unsigned int idof = 0; idof < n_dofs; ++idof) { + const unsigned int istate = this->fe_collection[poly_degree].system_to_component_index(idof).first; + const unsigned int ishape = this->fe_collection[poly_degree].system_to_component_index(idof).second; + //allocate + if(ishape == 0) + soln_coeff[istate].resize(n_shape_fns); + + //solve + soln_coeff[istate][ishape] = DGBase::solution(dofs_indices[idof]); + } - // Convective - // Now minus such 2 integrations by parts - assert(JxW[iquad] - fe_values_lagrange.JxW(iquad) < 1e-14); + //Interpolate soln to facet, and gradient to facet. + std::array,nstate> soln_at_surf_q; + std::array>,nstate> ref_grad_soln_at_vol_q; + for(int istate=0; istate>,nstate> phys_grad_soln_at_surf_q; + for(int istate=0; istate phys_gradient_u(n_quad_pts_vol); + for(unsigned int iquad=0; iquadall_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term) { - rhs = rhs + fe_values_vol.shape_value_component(itest,iquad,istate) * source_at_q[iquad][istate] * JxW[iquad]; + //evaluate physical facet fluxes dot product with physical unit normal scaled by determinant of metric facet Jacobian + //the outward reference normal dircetion. + const dealii::Tensor<1,dim,double> unit_ref_normal_int = dealii::GeometryInfo::unit_normal_vector[iface]; + std::array>,nstate> surf_num_flux_minus_surf_soln_dot_normal; + for(unsigned int iquad=0; iquad metric_cofactor_surf; + for(int idim=0; idim soln_state; + std::array,nstate> phys_grad_soln_state; + for(int istate=0; istate unit_phys_normal_int; + metric_oper.transform_reference_to_physical(unit_ref_normal_int, + metric_cofactor_surf, + unit_phys_normal_int); + const double face_Jac_norm_scaled = unit_phys_normal_int.norm(); + unit_phys_normal_int /= face_Jac_norm_scaled;//normalize it. + + std::array soln_boundary; + std::array,nstate> grad_soln_boundary; + dealii::Point surf_flux_node; + for(int idim=0; idimpde_physics_double->boundary_face_values (boundary_id, surf_flux_node, unit_phys_normal_int, soln_state, phys_grad_soln_state, soln_boundary, grad_soln_boundary); - local_rhs_int_cell(itest) += rhs.val(); + std::array diss_soln_num_flux; + diss_soln_num_flux = this->diss_num_flux_double->evaluate_solution_flux(soln_state, soln_boundary, unit_phys_normal_int); - if (this->all_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) { - for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { - //residual_derivatives[idof] = rhs.fastAccessDx(idof); - residual_derivatives[idof] = rhs.fastAccessDx(idof); + for(int istate=0; istate &surf_quad_weights = this->face_quadrature_collection[poly_degree].get_weights(); + for(int istate=0; istate rhs(n_shape_fns); + + soln_basis.inner_product_surface_1D(iface, + surf_num_flux_minus_surf_soln_dot_normal[istate][idim], + surf_quad_weights, rhs, + soln_basis.oneD_surf_operator, + soln_basis.oneD_vol_operator, + false, 1.0);//it's added since auxiliary is EQUAL to the gradient of the soln + for(unsigned int ishape=0; ishapesystem_matrix.add(cell_dofs_indices[itest], cell_dofs_indices, residual_derivatives); } } } +/*********************************************************************************/ template -void DGStrong::assemble_face_term_derivatives( - typename dealii::DoFHandler::active_cell_iterator /*cell*/, +void DGStrong::assemble_face_term_auxiliary_equation( + const unsigned int iface, const unsigned int neighbor_iface, const dealii::types::global_dof_index current_cell_index, const dealii::types::global_dof_index neighbor_cell_index, - const std::pair /*face_subface_int*/, - const std::pair /*face_subface_ext*/, - const typename dealii::QProjector::DataSetDescriptor /*face_data_set_int*/, - const typename dealii::QProjector::DataSetDescriptor /*face_data_set_ext*/, - const dealii::FEFaceValuesBase &fe_values_int, - const dealii::FEFaceValuesBase &fe_values_ext, - const real penalty, - const dealii::FESystem &,//fe_int, - const dealii::FESystem &,//fe_ext, - const dealii::Quadrature &,//face_quadrature_int, - const std::vector &,//metric_dof_indices_int, - const std::vector &,//metric_dof_indices_ext, - const std::vector &soln_dof_indices_int, - const std::vector &soln_dof_indices_ext, - dealii::Vector &local_rhs_int_cell, - dealii::Vector &local_rhs_ext_cell, - const bool compute_dRdW, - const bool compute_dRdX, - const bool compute_d2R) + const unsigned int poly_degree_int, + const unsigned int poly_degree_ext, + const std::vector &dof_indices_int, + const std::vector &dof_indices_ext, + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::metric_operators &metric_oper_int, + std::vector> &local_auxiliary_RHS_int, + std::vector> &local_auxiliary_RHS_ext) { (void) current_cell_index; (void) neighbor_cell_index; - assert(compute_dRdW); assert(!compute_dRdX); assert(!compute_d2R); - (void) compute_dRdW; (void) compute_dRdX; (void) compute_d2R; - using ADArray = std::array; - using ADArrayTensor1 = std::array< dealii::Tensor<1,dim,FadType>, nstate >; - - // Use quadrature points of neighbor cell - // Might want to use the maximum n_quad_pts1 and n_quad_pts2 - const unsigned int n_face_quad_pts = fe_values_ext.n_quadrature_points; - - const unsigned int n_dofs_int = fe_values_int.dofs_per_cell; - const unsigned int n_dofs_ext = fe_values_ext.dofs_per_cell; - AssertDimension (n_dofs_int, soln_dof_indices_int.size()); - AssertDimension (n_dofs_ext, soln_dof_indices_ext.size()); + const unsigned int n_face_quad_pts = this->face_quadrature_collection[poly_degree_int].size();//assume interior cell does the work - // Jacobian and normal should always be consistent between two elements - // even for non-conforming meshes? - const std::vector &JxW_int = fe_values_int.get_JxW_values (); - const std::vector > &normals_int = fe_values_int.get_normal_vectors (); + const unsigned int n_dofs_int = this->fe_collection[poly_degree_int].dofs_per_cell; + const unsigned int n_dofs_ext = this->fe_collection[poly_degree_ext].dofs_per_cell; - // AD variable - std::vector soln_coeff_int_ad(n_dofs_int); - std::vector soln_coeff_ext_ad(n_dofs_ext); + const unsigned int n_shape_fns_int = n_dofs_int / nstate; + const unsigned int n_shape_fns_ext = n_dofs_ext / nstate; + AssertDimension (n_dofs_int, dof_indices_int.size()); + AssertDimension (n_dofs_ext, dof_indices_ext.size()); - // Jacobian blocks - std::vector dR1_dW1(n_dofs_int); - std::vector dR1_dW2(n_dofs_ext); - std::vector dR2_dW1(n_dofs_int); - std::vector dR2_dW2(n_dofs_ext); - - std::vector conv_num_flux_dot_n(n_face_quad_pts); - std::vector conv_phys_flux_int(n_face_quad_pts); - std::vector conv_phys_flux_ext(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< 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 - // AD variable - const unsigned int n_total_indep = n_dofs_int + n_dofs_ext; + //Extract interior modal coefficients of solution + std::array,nstate> soln_coeff_int; for (unsigned int idof = 0; idof < n_dofs_int; ++idof) { - soln_coeff_int_ad[idof] = DGBase::solution(soln_dof_indices_int[idof]); - soln_coeff_int_ad[idof].diff(idof, n_total_indep); - } - for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) { - soln_coeff_ext_ad[idof] = DGBase::solution(soln_dof_indices_ext[idof]); - soln_coeff_ext_ad[idof].diff(idof+n_dofs_int, n_total_indep); - } - for (unsigned int iquad=0; iquad normal_int = normals_int[iquad]; - const dealii::Tensor<1,dim,FadType> normal_ext = -normal_int; + const unsigned int istate = this->fe_collection[poly_degree_int].system_to_component_index(idof).first; + const unsigned int ishape = this->fe_collection[poly_degree_int].system_to_component_index(idof).second; + //allocate + if(ishape == 0) soln_coeff_int[istate].resize(n_shape_fns_int); - // Interpolate solution to face - for (unsigned int idof=0; idof1) std::cout << "Momentum int" << soln_int[iquad][1] << std::endl; - //std::cout << "Energy int" << soln_int[iquad][nstate-1] << std::endl; - //std::cout << "Density ext" << soln_ext[iquad][0] << std::endl; - //if(nstate>1) std::cout << "Momentum ext" << soln_ext[iquad][1] << std::endl; - //std::cout << "Energy ext" << soln_ext[iquad][nstate-1] << std::endl; + //solve + soln_coeff_int[istate][ishape] = DGBase::solution(dof_indices_int[idof]); + } - // Evaluate physical convective flux, physical dissipative flux, and source term - conv_num_flux_dot_n[iquad] = DGBaseState::conv_num_flux_fad->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int); + //Extract exterior modal coefficients of solution + std::array,nstate> soln_coeff_ext; + for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) { + const unsigned int istate = this->fe_collection[poly_degree_ext].system_to_component_index(idof).first; + const unsigned int ishape = this->fe_collection[poly_degree_ext].system_to_component_index(idof).second; + //allocate + if(ishape == 0) soln_coeff_ext[istate].resize(n_shape_fns_ext); - conv_phys_flux_int[iquad] = this->pde_physics_fad->convective_flux (soln_int[iquad]); - conv_phys_flux_ext[iquad] = this->pde_physics_fad->convective_flux (soln_ext[iquad]); + //solve + soln_coeff_ext[istate][ishape] = DGBase::solution(dof_indices_ext[idof]); + } - diss_soln_num_flux[iquad] = DGBaseState::diss_num_flux_fad->evaluate_solution_flux(soln_int[iquad], soln_ext[iquad], normal_int); + //Interpolate soln modal coefficients to the facet + std::array,nstate> soln_at_surf_q_int; + std::array,nstate> soln_at_surf_q_ext; + for(int istate=0; istate unit_ref_normal_int = dealii::GeometryInfo::unit_normal_vector[iface]; + std::array>,nstate> surf_num_flux_minus_surf_soln_int_dot_normal; + std::array>,nstate> surf_num_flux_minus_surf_soln_ext_dot_normal; + for (unsigned int iquad=0; iquad metric_cofactor_surf; + for(int idim=0; idimpde_physics_fad->dissipative_flux (soln_int[iquad], diss_soln_jump_int, current_cell_index); - diss_flux_jump_ext[iquad] = this->pde_physics_fad->dissipative_flux (soln_ext[iquad], diss_soln_jump_ext, neighbor_cell_index); - - diss_auxi_num_flux_dot_n[iquad] = DGBaseState::diss_num_flux_fad->evaluate_auxiliary_flux( - current_cell_index, neighbor_cell_index, - 0.0, 0.0, - soln_int[iquad], soln_ext[iquad], - soln_grad_int[iquad], soln_grad_ext[iquad], - normal_int, penalty); - } - - // From test functions associated with interior cell point of view - for (unsigned int itest_int=0; itest_int unit_phys_normal_int; + metric_oper_int.transform_reference_to_physical(unit_ref_normal_int, + metric_cofactor_surf, + unit_phys_normal_int); + const double face_Jac_norm_scaled = unit_phys_normal_int.norm(); + unit_phys_normal_int /= face_Jac_norm_scaled;//normalize it. + + std::array diss_soln_num_flux; + std::array soln_state_int; + std::array soln_state_ext; + for(int istate=0; istatediss_num_flux_double->evaluate_solution_flux(soln_state_int, soln_state_ext, unit_phys_normal_int); + + for(int istate=0; istateall_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) { - for (unsigned int idof = 0; idof < n_dofs_int; ++idof) { - dR1_dW1[idof] = rhs.fastAccessDx(idof); - } - for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) { - dR1_dW2[idof] = rhs.fastAccessDx(n_dofs_int+idof); + surf_num_flux_minus_surf_soln_ext_dot_normal[istate][idim][iquad] + = (diss_soln_num_flux[istate] - soln_at_surf_q_ext[istate][iquad]) * (- unit_phys_normal_int[idim]) * face_Jac_norm_scaled; } - this->system_matrix.add(soln_dof_indices_int[itest_int], soln_dof_indices_int, dR1_dW1); - this->system_matrix.add(soln_dof_indices_int[itest_int], soln_dof_indices_ext, dR1_dW2); } } + //solve residual and set + const std::vector &surf_quad_weights = this->face_quadrature_collection[poly_degree_int].get_weights(); + for(int istate=0; istate rhs_int(n_shape_fns_int); + + soln_basis_int.inner_product_surface_1D(iface, + surf_num_flux_minus_surf_soln_int_dot_normal[istate][idim], + surf_quad_weights, rhs_int, + soln_basis_int.oneD_surf_operator, + soln_basis_int.oneD_vol_operator, + false, 1.0);//it's added since auxiliary is EQUAL to the gradient of the soln + + for(unsigned int ishape=0; ishape rhs_ext(n_shape_fns_ext); - // From test functions associated with neighbour cell point of view - for (unsigned int itest_ext=0; itest_extall_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) { - for (unsigned int idof = 0; idof < n_dofs_int; ++idof) { - dR2_dW1[idof] = rhs.fastAccessDx(idof); + for(unsigned int ishape=0; ishapesystem_matrix.add(soln_dof_indices_ext[itest_ext], soln_dof_indices_int, dR2_dW1); - this->system_matrix.add(soln_dof_indices_ext[itest_ext], soln_dof_indices_ext, dR2_dW2); } } } - +/**************************************************** +* +* PRIMARY EQUATIONS STRONG FORM +* +****************************************************/ template -void DGStrong::assemble_volume_term_explicit( - typename dealii::DoFHandler::active_cell_iterator /*cell*/, - const dealii::types::global_dof_index current_cell_index, - const dealii::FEValues &fe_values_vol, - const std::vector &cell_dofs_indices, - dealii::Vector &local_rhs_int_cell, - const dealii::FEValues &fe_values_lagrange) +void DGStrong::assemble_volume_term_strong( + typename dealii::DoFHandler::active_cell_iterator cell, + const dealii::types::global_dof_index current_cell_index, + const std::vector &cell_dofs_indices, + const unsigned int poly_degree, + OPERATOR::basis_functions &soln_basis, + OPERATOR::basis_functions &flux_basis, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper, + dealii::Vector &local_rhs_int_cell) { (void) current_cell_index; - //std::cout << "assembling cell terms" << std::endl; - using realtype = real; - using realArray = std::array; - using realArrayTensor1 = std::array< dealii::Tensor<1,dim,realtype>, 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; + const unsigned int n_quad_pts = this->volume_quadrature_collection[poly_degree].size(); + const unsigned int n_dofs_cell = this->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_shape_fns = n_dofs_cell / nstate; + const std::vector &vol_quad_weights = this->volume_quadrature_collection[poly_degree].get_weights(); + const std::vector &oneD_vol_quad_weights = this->oneD_quadrature_collection[poly_degree].get_weights(); AssertDimension (n_dofs_cell, cell_dofs_indices.size()); - const std::vector &JxW = fe_values_vol.get_JxW_values (); - + // Fetch the modal soln coefficients and the modal auxiliary soln coefficients + // We immediately separate them by state as to be able to use sum-factorization + // in the interpolation operator. If we left it by n_dofs_cell, then the matrix-vector + // mult would sum the states at the quadrature point. + std::array,nstate> soln_coeff; + std::array>,nstate> aux_soln_coeff; + for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { + const unsigned int istate = this->fe_collection[poly_degree].system_to_component_index(idof).first; + const unsigned int ishape = this->fe_collection[poly_degree].system_to_component_index(idof).second; + if(ishape == 0) + soln_coeff[istate].resize(n_shape_fns); + soln_coeff[istate][ishape] = DGBase::solution(cell_dofs_indices[idof]); + for(int idim=0; idim::auxiliary_solution[idim](cell_dofs_indices[idof]); + } + } + std::array,nstate> soln_at_q; + std::array>,nstate> aux_soln_at_q; //auxiliary sol at flux nodes + std::vector> soln_at_q_for_max_CFL(n_quad_pts);//Need soln written in a different for to use pre-existing max CFL function + // Interpolate each state to the quadrature points using sum-factorization + // with the basis functions in each reference direction. + for(int istate=0; istate residual_derivatives(n_dofs_cell); + // For pseudotime, we need to compute the time_scaled_solution. + // Thus, we need to evaluate the max_dt_cell (as previously done in dg/weak_dg.cpp -> assemble_volume_term_explicit) + // Get max artificial dissipation + real max_artificial_diss = 0.0; + const unsigned int n_dofs_arti_diss = this->fe_q_artificial_dissipation.dofs_per_cell; + typename dealii::DoFHandler::active_cell_iterator artificial_dissipation_cell( + this->triangulation.get(), cell->level(), cell->index(), &(this->dof_handler_artificial_dissipation)); + std::vector dof_indices_artificial_dissipation(n_dofs_arti_diss); + artificial_dissipation_cell->get_dof_indices (dof_indices_artificial_dissipation); + for (unsigned int iquad=0; iquadall_parameters->artificial_dissipation_param.add_artificial_dissipation ) { + const dealii::Point point = this->volume_quadrature_collection[poly_degree].point(iquad); + for (unsigned int idof=0; idofartificial_dissipation_c0[index] * this->fe_q_artificial_dissipation.shape_value(idof, point); + } + max_artificial_diss = std::max(artificial_diss_coeff_at_q, max_artificial_diss); + } + } + // Get max_dt_cell for time_scaled_solution with pseudotime + real cell_volume_estimate = 0.0; + for (unsigned int iquad=0; iquaddiameter(); + const real cell_diameter = cell_volume / std::pow(diameter,dim-1); + const real cell_radius = 0.5 * cell_diameter; + this->cell_volume[current_cell_index] = cell_volume; + this->max_dt_cell[current_cell_index] = this->evaluate_CFL ( soln_at_q_for_max_CFL, max_artificial_diss, cell_radius, poly_degree); - std::vector< realArray > soln_at_q(n_quad_pts); - std::vector< realArrayTensor1 > soln_grad_at_q(n_quad_pts); // Tensor initialize with zeros - std::vector< realArrayTensor1 > conv_phys_flux_at_q(n_quad_pts); - std::vector< realArrayTensor1 > diss_phys_flux_at_q(n_quad_pts); - std::vector< realArray > source_at_q(n_quad_pts); + //Compute the physical fluxes, then convert them into reference fluxes. + //From the paper: Cicchino, Alexander, et al. "Provably stable flux reconstruction high-order methods on curvilinear elements." Journal of Computational Physics 463 (2022): 111259. + //For conservative DG, we compute the reference flux as per Eq. (9), to then recover the second volume integral in Eq. (17). + //For curvilinear split-form in Eq. (22), we apply a two-pt flux of the metric-cofactor matrix on the matrix operator constructed by the entropy stable/conservtive 2pt flux. + std::array>,nstate> conv_ref_flux_at_q; + std::array>,nstate> diffusive_ref_flux_at_q; + std::array,nstate> source_at_q; + // The matrix of two-pt fluxes for Hadamard products + std::array>,nstate> conv_ref_2pt_flux_at_q; - // AD variable - std::vector< realtype > soln_coeff(n_dofs_cell); - for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { - soln_coeff[idof] = DGBase::solution(cell_dofs_indices[idof]); - } for (unsigned int iquad=0; iquad soln_state; + std::array,nstate> aux_soln_state; + for(int istate=0; istate1) std::cout << "Momentum " << soln_at_q[iquad][1] << std::endl; - //std::cout << "Energy " << soln_at_q[iquad][nstate-1] << std::endl; - // Evaluate physical convective flux and source term - conv_phys_flux_at_q[iquad] = DGBaseState::pde_physics_double->convective_flux (soln_at_q[iquad]); - diss_phys_flux_at_q[iquad] = DGBaseState::pde_physics_double->dissipative_flux (soln_at_q[iquad], soln_grad_at_q[iquad], current_cell_index); - if(this->all_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term) { - source_at_q[iquad] = DGBaseState::pde_physics_double->source_term (fe_values_vol.quadrature_point(iquad), soln_at_q[iquad], current_cell_index); + + // Copy Metric Cofactor in a way can use for transforming Tensor Blocks to reference space + // The way it is stored in metric_operators is to use sum-factorization in each direction, + // but here it is cleaner to apply a reference transformation in each Tensor block returned by physics. + dealii::Tensor<2,dim,real> metric_cofactor; + for(int idim=0; idimdiameter(); - const unsigned int cell_index = fe_values_vol.get_cell()->active_cell_index(); - const unsigned int cell_degree = fe_values_vol.get_fe().tensor_degree(); - this->max_dt_cell[cell_index] = DGBaseState::evaluate_CFL ( soln_at_q, 0.0, cell_diameter, cell_degree); + // Evaluate physical convective flux + // If 2pt flux, transform to reference at construction to improve performance. + // We technically use a REFERENCE 2pt flux for all entropy stable schemes. + std::array,nstate> conv_phys_flux; + std::array,nstate> conv_phys_flux_2pt; + std::vector,nstate>> conv_ref_flux_2pt(n_quad_pts); + if (this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){ + for (unsigned int flux_basis=iquad; flux_basis metric_cofactor_flux_basis; + for(int idim=0; idim soln_state_flux_basis; + for(int istate=0; istatepde_physics_double->convective_numerical_split_flux(soln_state, soln_state_flux_basis); + + for(int istate=0; istatepde_physics_double->convective_flux (soln_state); + } + //Diffusion + std::array,nstate> diffusive_phys_flux; + //Compute the physical dissipative flux + diffusive_phys_flux = this->pde_physics_double->dissipative_flux(soln_state, aux_soln_state, current_cell_index); - // Evaluate flux divergence by interpolating the flux - // Since we have nodal values of the flux, we use the Lagrange polynomials to obtain the gradients at the quadrature points. - //const dealii::FEValues &fe_values_lagrange = this->fe_values_collection_volume_lagrange.get_present_fe_values(); - std::vector flux_divergence(n_quad_pts); - for (int istate = 0; istateall_parameters->use_split_form == true) - { - flux_divergence[iquad][istate] += 2* DGBaseState::pde_physics_double->convective_numerical_split_flux(soln_at_q[iquad],soln_at_q[flux_basis])[istate] * fe_values_lagrange.shape_grad(flux_basis,iquad); + // Source + std::array source; + if(this->all_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term) { + dealii::Point vol_flux_node; + for(int idim=0; idimpde_physics_double->source_term (vol_flux_node, soln_state, this->current_time, current_cell_index); + } + + //Write the values in a way that we can use sum-factorization on. + for(int istate=0; istate conv_ref_flux; + dealii::Tensor<1,dim,real> diffusive_ref_flux; + //Trnasform to reference fluxes + if (this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){ + //Do Nothing. + //I am leaving this block here so the diligent reader + //remembers that, for entropy stable schemes, we construct + //a REFERENCE two-point flux at construction, where the physical + //to reference transformation was done by splitting the metric cofactor. + } + else{ + //transform the conservative convective physical flux to reference space + metric_oper.transform_physical_to_reference( + conv_phys_flux[istate], + metric_cofactor, + conv_ref_flux); + } + //transform the dissipative flux to reference space + metric_oper.transform_physical_to_reference( + diffusive_phys_flux[istate], + metric_cofactor, + diffusive_ref_flux); + + //Write the data in a way that we can use sum-factorization on. + //Since sum-factorization improves the speed for matrix-vector multiplications, + //We need the values to have their inner elements be vectors. + for(int idim=0; idimall_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){ + for (unsigned int flux_basis=iquad; flux_basisall_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term) { + source_at_q[istate][iquad] = source[istate]; } } } - // Strong form - // The right-hand side sends all the term to the side of the source term - // Therefore, - // \divergence ( Fconv + Fdiss ) = source - // has the right-hand side - // rhs = - \divergence( Fconv + Fdiss ) + source - // Since we have done an integration by parts, the volume term resulting from the divergence of Fconv and Fdiss - // is negative. Therefore, negative of negative means we add that volume term to the right-hand-side - for (unsigned int itest=0; itest conv_flux_divergence(n_quad_pts); + std::vector diffusive_flux_divergence(n_quad_pts); - // Convective - // Now minus such 2 integrations by parts - rhs = rhs - fe_values_vol.shape_value_component(itest,iquad,istate) * flux_divergence[iquad][istate] * JxW[iquad]; + if (this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){ + //2pt flux Hadamard Product, and then multiply by vector of ones scaled by 1. + // Same as the volume term in Eq. (15) in Chan, Jesse. "Skew-symmetric entropy stable modal discontinuous Galerkin formulations." Journal of Scientific Computing 81.1 (2019): 459-485. but, + // where we use the reference skew-symmetric stiffness operator of the flux basis for the Q operator and the reference two-point flux as to make use of Alex's Hadamard product + // sum-factorization type algorithm that exploits the structure of the flux basis in the reference space to have O(n^{d+1}). + flux_basis.divergence_two_pt_flux_Hadamard_product(conv_ref_2pt_flux_at_q[istate], conv_flux_divergence, oneD_vol_quad_weights, flux_basis_stiffness.oneD_skew_symm_vol_oper, 1.0); + } + else{ + //Reference divergence of the reference convective flux. + flux_basis.divergence_matrix_vector_mult_1D(conv_ref_flux_at_q[istate], conv_flux_divergence, + flux_basis.oneD_vol_operator, + flux_basis.oneD_grad_operator); + } + //Reference divergence of the reference diffusive flux. + flux_basis.divergence_matrix_vector_mult_1D(diffusive_ref_flux_at_q[istate], diffusive_flux_divergence, + flux_basis.oneD_vol_operator, + flux_basis.oneD_grad_operator); + + + // Strong form + // The right-hand side sends all the term to the side of the source term + // Therefore, + // \divergence ( Fconv + Fdiss ) = source + // has the right-hand side + // rhs = - \divergence( Fconv + Fdiss ) + source + // Since we have done an integration by parts, the volume term resulting from the divergence of Fconv and Fdiss + // is negative. Therefore, negative of negative means we add that volume term to the right-hand-side + std::vector rhs(n_shape_fns); + + // Convective + if (this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){ + std::vector ones(n_quad_pts, 1.0); + soln_basis.inner_product_1D(conv_flux_divergence, ones, rhs, soln_basis.oneD_vol_operator, false, -1.0); + } + else { + soln_basis.inner_product_1D(conv_flux_divergence, vol_quad_weights, rhs, soln_basis.oneD_vol_operator, false, -1.0); + } - //// Diffusive - //// Note that for diffusion, the negative is defined in the physics - rhs = rhs + fe_values_vol.shape_grad_component(itest,iquad,istate) * diss_phys_flux_at_q[iquad][istate] * JxW[iquad]; - // Source + // Diffusive + // Note that for diffusion, the negative is defined in the physics. Since we used the auxiliary + // variable, put a negative here. + soln_basis.inner_product_1D(diffusive_flux_divergence, vol_quad_weights, rhs, soln_basis.oneD_vol_operator, true, -1.0); - if(this->all_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term) { - rhs = rhs + fe_values_vol.shape_value_component(itest,iquad,istate) * source_at_q[iquad][istate] * JxW[iquad]; + // Source + if(this->all_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term) { + std::vector JxW(n_quad_pts); + for(unsigned int iquad=0; iquad -void DGStrong::assemble_boundary_term_explicit( - typename dealii::DoFHandler::active_cell_iterator /*cell*/, +void DGStrong::assemble_boundary_term_strong( + const unsigned int iface, const dealii::types::global_dof_index current_cell_index, const unsigned int boundary_id, - const dealii::FEFaceValuesBase &fe_values_boundary, + const unsigned int poly_degree, const real penalty, - const std::vector &dof_indices_int, - dealii::Vector &local_rhs_int_cell) + const std::vector &dof_indices, + OPERATOR::basis_functions &soln_basis, + OPERATOR::basis_functions &flux_basis, + OPERATOR::metric_operators &metric_oper, + dealii::Vector &local_rhs_cell) { (void) current_cell_index; - using ADArray = std::array; - using ADArrayTensor1 = std::array< dealii::Tensor<1,dim,FadType>, 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; - - AssertDimension (n_dofs_cell, dof_indices_int.size()); - - const std::vector &JxW = fe_values_boundary.get_JxW_values (); - const std::vector> &normals = fe_values_boundary.get_normal_vectors (); - - std::vector residual_derivatives(n_dofs_cell); - - 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 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* - - std::vector conv_phys_flux(n_face_quad_pts); - - // AD variable - std::vector< FadType > soln_coeff_int(n_dofs_cell); - const unsigned int n_total_indep = n_dofs_cell; - for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { - soln_coeff_int[idof] = DGBase::solution(dof_indices_int[idof]); - soln_coeff_int[idof].diff(idof, n_total_indep); + const unsigned int n_face_quad_pts = this->face_quadrature_collection[poly_degree].size(); + const unsigned int n_quad_pts_vol = this->volume_quadrature_collection[poly_degree].size(); + const unsigned int n_dofs = this->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_shape_fns = n_dofs / nstate; + const std::vector &face_quad_weights = this->face_quadrature_collection[poly_degree].get_weights(); + + AssertDimension (n_dofs, dof_indices.size()); + + // Fetch the modal soln coefficients and the modal auxiliary soln coefficients + // We immediately separate them by state as to be able to use sum-factorization + // in the interpolation operator. If we left it by n_dofs_cell, then the matrix-vector + // mult would sum the states at the quadrature point. + std::array,nstate> soln_coeff; + std::array>,nstate> aux_soln_coeff; + for (unsigned int idof = 0; idof < n_dofs; ++idof) { + const unsigned int istate = this->fe_collection[poly_degree].system_to_component_index(idof).first; + const unsigned int ishape = this->fe_collection[poly_degree].system_to_component_index(idof).second; + // allocate + if(ishape == 0){ + soln_coeff[istate].resize(n_shape_fns); + } + // solve + soln_coeff[istate][ishape] = DGBase::solution(dof_indices[idof]); + for(int idim=0; idim::auxiliary_solution[idim](dof_indices[idof]); + } } - - for (unsigned int iquad=0; iquad,nstate> soln_at_vol_q; + std::array>,nstate> aux_soln_at_vol_q; + // Interpolate modal soln coefficients to the facet. + std::array,nstate> soln_at_surf_q; + std::array>,nstate> aux_soln_at_surf_q; + for(int istate=0; istate > quad_pts = fe_values_boundary.get_quadrature_points(); - for (unsigned int iquad=0; iquad normal_int = normals[iquad]; - const dealii::Tensor<1,dim,FadType> normal_ext = -normal_int; - - for (unsigned int idof=0; idof>,nstate> conv_ref_flux_at_vol_q; + std::array>,nstate> diffusive_ref_flux_at_vol_q; + for (unsigned int iquad=0; iquad metric_cofactor_vol; + for(int idim=0; idim soln_state; + std::array,nstate> aux_soln_state; + for(int istate=0; istate real_quad_point = quad_pts[iquad]; - dealii::Point ad_point; - for (int d=0;dpde_physics_fad->boundary_face_values (boundary_id, ad_point, normal_int, soln_int[iquad], soln_grad_int[iquad], soln_ext[iquad], soln_grad_ext[iquad]); - - // - // Evaluate physical convective flux, physical dissipative flux - // Following the the boundary treatment given by - // Hartmann, R., Numerical Analysis of Higher Order Discontinuous Galerkin Finite Element Methods, - // Institute of Aerodynamics and Flow Technology, DLR (German Aerospace Center), 2008. - // Details given on page 93 - //conv_num_flux_dot_n[iquad] = DGBaseState::conv_num_flux_fad->evaluate_flux(soln_ext[iquad], soln_ext[iquad], normal_int); + // Evaluate physical convective flux + std::array,nstate> conv_phys_flux; + conv_phys_flux = this->pde_physics_double->convective_flux (soln_state); + + // Compute the physical dissipative flux + std::array,nstate> diffusive_phys_flux; + diffusive_phys_flux = this->pde_physics_double->dissipative_flux(soln_state, aux_soln_state, current_cell_index); + + // Write the values in a way that we can use sum-factorization on. + for(int istate=0; istate conv_ref_flux; + dealii::Tensor<1,dim,real> diffusive_ref_flux; + // transform the conservative convective physical flux to reference space + metric_oper.transform_physical_to_reference( + conv_phys_flux[istate], + metric_cofactor_vol, + conv_ref_flux); + // transform the dissipative flux to reference space + metric_oper.transform_physical_to_reference( + diffusive_phys_flux[istate], + metric_cofactor_vol, + diffusive_ref_flux); + + // Write the data in a way that we can use sum-factorization on. + // Since sum-factorization improves the speed for matrix-vector multiplications, + // We need the values to have their inner elements be vectors. + for(int idim=0; idim::conv_num_flux_fad->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int); + diffusive_ref_flux_at_vol_q[istate][idim][iquad] = diffusive_ref_flux[idim]; + } + } + } - // Used for strong form - // Which physical convective flux to use? - conv_phys_flux[iquad] = this->pde_physics_fad->convective_flux (soln_int[iquad]); + // Interpolate the volume reference fluxes to the facet. + // And do the dot product with the UNIT REFERENCE normal. + // Since we are computing a dot product with the unit reference normal, + // we exploit the fact that the unit reference normal has a value of 0 in all reference directions except + // the outward reference normal dircetion. + const dealii::Tensor<1,dim,double> unit_ref_normal_int = dealii::GeometryInfo::unit_normal_vector[iface]; + int dim_not_zero = 0; + for(int idim=0; idim= 1e-11)//reference unit normal is 0 in all direction and 1 in outward normal direction + dim_not_zero = idim;//this is outward pointing normal reference direction + } - // Notice that the flux uses the solution given by the Dirichlet or Neumann boundary condition - diss_soln_num_flux[iquad] = DGBaseState::diss_num_flux_fad->evaluate_solution_flux(soln_ext[iquad], soln_ext[iquad], normal_int); + std::array,nstate> conv_int_vol_ref_flux_interp_to_face_dot_ref_normal; + std::array,nstate> diffusive_int_vol_ref_flux_interp_to_face_dot_ref_normal; + for(int istate=0; istate,nstate> conv_flux_dot_normal_diff; + std::array,nstate> diss_flux_dot_normal_diff; + // Get surface numerical fluxes + for (unsigned int iquad=0; iquad metric_cofactor_surf; + for(int idim=0; idim unit_phys_normal_int; + metric_oper.transform_reference_to_physical(unit_ref_normal_int, + metric_cofactor_surf, + unit_phys_normal_int); + const double face_Jac_norm_scaled = unit_phys_normal_int.norm(); + unit_phys_normal_int /= face_Jac_norm_scaled;//normalize it. + + std::array soln_state; + std::array,nstate> aux_soln_state; + for(int istate=0; istatepde_physics_fad->dissipative_flux (soln_int[iquad], diss_soln_jump_int, current_cell_index); - diss_auxi_num_flux_dot_n[iquad] = DGBaseState::diss_num_flux_fad->evaluate_auxiliary_flux( + std::array soln_boundary; + std::array,nstate> grad_soln_boundary; + dealii::Point surf_flux_node; + for(int idim=0; idimpde_physics_double->boundary_face_values (boundary_id, surf_flux_node, unit_phys_normal_int, soln_state, aux_soln_state, soln_boundary, grad_soln_boundary); + + // Convective numerical flux. + std::array conv_num_flux_dot_n_at_q; + conv_num_flux_dot_n_at_q = this->conv_num_flux_double->evaluate_flux(soln_state, soln_boundary, unit_phys_normal_int); + + // Dissipative numerical flux + std::array diss_auxi_num_flux_dot_n_at_q; + diss_auxi_num_flux_dot_n_at_q = this->diss_num_flux_double->evaluate_auxiliary_flux( current_cell_index, current_cell_index, 0.0, 0.0, - soln_int[iquad], soln_ext[iquad], - soln_grad_int[iquad], soln_grad_ext[iquad], - normal_int, penalty, true); - } - - // Boundary integral - for (unsigned int itest=0; itestall_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) { - for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { - //residual_derivatives[idof] = rhs.fastAccessDx(idof); - residual_derivatives[idof] = rhs.fastAccessDx(idof); - } - this->system_matrix.add(dof_indices_int[itest], dof_indices_int, residual_derivatives); + //solve rhs + for(int istate=0; istate rhs(n_shape_fns); + soln_basis.inner_product_surface_1D(iface, conv_flux_dot_normal_diff[istate], + face_quad_weights, rhs, + soln_basis.oneD_surf_operator, + soln_basis.oneD_vol_operator, + false, -1.0);//adding=false, scaled by factor=-1.0 bc subtract it + soln_basis.inner_product_surface_1D(iface, diss_flux_dot_normal_diff[istate], + face_quad_weights, rhs, + soln_basis.oneD_surf_operator, + soln_basis.oneD_vol_operator, + true, -1.0);//adding=true, scaled by factor=-1.0 bc subtract it + + for(unsigned int ishape=0; ishape -void DGStrong::assemble_face_term_explicit( - typename dealii::DoFHandler::active_cell_iterator /*cell*/, +void DGStrong::assemble_face_term_strong( + const unsigned int iface, const unsigned int neighbor_iface, const dealii::types::global_dof_index current_cell_index, const dealii::types::global_dof_index neighbor_cell_index, - const dealii::FEFaceValuesBase &fe_values_int, - const dealii::FEFaceValuesBase &fe_values_ext, + const unsigned int poly_degree_int, + const unsigned int poly_degree_ext, const real penalty, const std::vector &dof_indices_int, const std::vector &dof_indices_ext, + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::basis_functions &flux_basis_int, + OPERATOR::basis_functions &flux_basis_ext, + OPERATOR::metric_operators &metric_oper_int, + OPERATOR::metric_operators &metric_oper_ext, dealii::Vector &local_rhs_int_cell, dealii::Vector &local_rhs_ext_cell) { (void) current_cell_index; (void) neighbor_cell_index; - //std::cout << "assembling face terms" << std::endl; - using ADArray = std::array; - using ADArrayTensor1 = std::array< dealii::Tensor<1,dim,FadType>, nstate >; - // Use quadrature points of neighbor cell - // Might want to use the maximum n_quad_pts1 and n_quad_pts2 - const unsigned int n_face_quad_pts = fe_values_ext.n_quadrature_points; + const unsigned int n_face_quad_pts = this->face_quadrature_collection[poly_degree_int].size();//assume interior cell does the work + + const unsigned int n_quad_pts_vol_int = this->volume_quadrature_collection[poly_degree_int].size(); + const unsigned int n_quad_pts_vol_ext = this->volume_quadrature_collection[poly_degree_ext].size(); + + const unsigned int n_dofs_int = this->fe_collection[poly_degree_int].dofs_per_cell; + const unsigned int n_dofs_ext = this->fe_collection[poly_degree_ext].dofs_per_cell; - const unsigned int n_dofs_int = fe_values_int.dofs_per_cell; - const unsigned int n_dofs_ext = fe_values_ext.dofs_per_cell; + const unsigned int n_shape_fns_int = n_dofs_int / nstate; + const unsigned int n_shape_fns_ext = n_dofs_ext / nstate; AssertDimension (n_dofs_int, dof_indices_int.size()); AssertDimension (n_dofs_ext, dof_indices_ext.size()); - // Jacobian and normal should always be consistent between two elements - // even for non-conforming meshes? - const std::vector &JxW_int = fe_values_int.get_JxW_values (); - const std::vector > &normals_int = fe_values_int.get_normal_vectors (); + // Extract interior modal coefficients of solution + std::array,nstate> soln_coeff_int; + std::array>,nstate> aux_soln_coeff_int; + for (unsigned int idof = 0; idof < n_dofs_int; ++idof) { + const unsigned int istate = this->fe_collection[poly_degree_int].system_to_component_index(idof).first; + const unsigned int ishape = this->fe_collection[poly_degree_int].system_to_component_index(idof).second; + if(ishape == 0) + soln_coeff_int[istate].resize(n_shape_fns_int); + + soln_coeff_int[istate][ishape] = DGBase::solution(dof_indices_int[idof]); + for(int idim=0; idim::auxiliary_solution[idim](dof_indices_int[idof]); + } + } - // AD variable - std::vector soln_coeff_int_ad(n_dofs_int); - std::vector soln_coeff_ext_ad(n_dofs_ext); + // Extract exterior modal coefficients of solution + std::array,nstate> soln_coeff_ext; + std::array>,nstate> aux_soln_coeff_ext; + for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) { + const unsigned int istate = this->fe_collection[poly_degree_int].system_to_component_index(idof).first; + const unsigned int ishape = this->fe_collection[poly_degree_int].system_to_component_index(idof).second; + if(ishape == 0){ + soln_coeff_ext[istate].resize(n_shape_fns_ext); + } + soln_coeff_ext[istate][ishape] = DGBase::solution(dof_indices_ext[idof]); + for(int idim=0; idim::auxiliary_solution[idim](dof_indices_ext[idof]); + } + } + // Interpolate the modal coefficients to the volume cubature nodes. + std::array,nstate> soln_at_vol_q_int; + std::array,nstate> soln_at_vol_q_ext; + std::array>,nstate> aux_soln_at_vol_q_int; + std::array>,nstate> aux_soln_at_vol_q_ext; + // Interpolate modal soln coefficients to the facet. + std::array,nstate> soln_at_surf_q_int; + std::array,nstate> soln_at_surf_q_ext; + std::array>,nstate> aux_soln_at_surf_q_int; + std::array>,nstate> aux_soln_at_surf_q_ext; + for(int istate=0; istate dR1_dW1(n_dofs_int); - std::vector dR1_dW2(n_dofs_ext); - std::vector dR2_dW1(n_dofs_int); - std::vector dR2_dW2(n_dofs_ext); - std::vector conv_num_flux_dot_n(n_face_quad_pts); - std::vector conv_phys_flux_int(n_face_quad_pts); - std::vector conv_phys_flux_ext(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< 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 + // Get volume reference fluxes and interpolate them to the facet. + // Compute reference volume fluxes in both interior and exterior cells. - std::vector diss_soln_num_flux(n_face_quad_pts); // u* - std::vector diss_auxi_num_flux_dot_n(n_face_quad_pts); // sigma* + // First we do interior. + std::array>,nstate> conv_ref_flux_at_vol_q_int; + std::array>,nstate> diffusive_ref_flux_at_vol_q_int; + for (unsigned int iquad=0; iquad metric_cofactor_vol_int; + for(int idim=0; idim soln_state; + std::array,nstate> aux_soln_state; + for(int istate=0; istate diss_flux_jump_int(n_face_quad_pts); // u*-u_int - std::vector diss_flux_jump_ext(n_face_quad_pts); // u*-u_ext - // AD variable - const unsigned int n_total_indep = n_dofs_int + n_dofs_ext; - for (unsigned int idof = 0; idof < n_dofs_int; ++idof) { - soln_coeff_int_ad[idof] = DGBase::solution(dof_indices_int[idof]); - soln_coeff_int_ad[idof].diff(idof, n_total_indep); - } - for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) { - soln_coeff_ext_ad[idof] = DGBase::solution(dof_indices_ext[idof]); - soln_coeff_ext_ad[idof].diff(idof+n_dofs_int, n_total_indep); - } - for (unsigned int iquad=0; iquad,nstate> conv_phys_flux; + //Only for conservtive DG do we interpolate volume fluxes to the facet + if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){ + conv_phys_flux = this->pde_physics_double->convective_flux (soln_state); + } + + // Compute the physical dissipative flux + std::array,nstate> diffusive_phys_flux; + diffusive_phys_flux = this->pde_physics_double->dissipative_flux(soln_state, aux_soln_state, current_cell_index); + + // Write the values in a way that we can use sum-factorization on. + for(int istate=0; istate conv_ref_flux; + dealii::Tensor<1,dim,real> diffusive_ref_flux; + // transform the conservative convective physical flux to reference space + if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){ + metric_oper_int.transform_physical_to_reference( + conv_phys_flux[istate], + metric_cofactor_vol_int, + conv_ref_flux); + } + // transform the dissipative flux to reference space + metric_oper_int.transform_physical_to_reference( + diffusive_phys_flux[istate], + metric_cofactor_vol_int, + diffusive_ref_flux); + + // Write the data in a way that we can use sum-factorization on. + // Since sum-factorization improves the speed for matrix-vector multiplications, + // We need the values to have their inner elements be vectors. + for(int idim=0; idimall_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){ + conv_ref_flux_at_vol_q_int[istate][idim][iquad] = conv_ref_flux[idim]; + } + diffusive_ref_flux_at_vol_q_int[istate][idim][iquad] = diffusive_ref_flux[idim]; + } } } - for (unsigned int iquad=0; iquad normal_int = normals_int[iquad]; - const dealii::Tensor<1,dim,FadType> normal_ext = -normal_int; + // Next we do exterior volume reference fluxes. + // Note we split the quad integrals because the interior and exterior could be of different poly basis + std::array>,nstate> conv_ref_flux_at_vol_q_ext; + std::array>,nstate> diffusive_ref_flux_at_vol_q_ext; + for (unsigned int iquad=0; iquad metric_cofactor_vol_ext; + for(int idim=0; idim soln_state; + std::array,nstate> aux_soln_state; + for(int istate=0; istate,nstate> conv_phys_flux; + if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){ + conv_phys_flux = this->pde_physics_double->convective_flux (soln_state); } - //std::cout << "Density int" << soln_int[iquad][0] << std::endl; - //if(nstate>1) std::cout << "Momentum int" << soln_int[iquad][1] << std::endl; - //std::cout << "Energy int" << soln_int[iquad][nstate-1] << std::endl; - //std::cout << "Density ext" << soln_ext[iquad][0] << std::endl; - //if(nstate>1) std::cout << "Momentum ext" << soln_ext[iquad][1] << std::endl; - //std::cout << "Energy ext" << soln_ext[iquad][nstate-1] << std::endl; - // Evaluate physical convective flux, physical dissipative flux, and source term + // Compute the physical dissipative flux + std::array,nstate> diffusive_phys_flux; + diffusive_phys_flux = this->pde_physics_double->dissipative_flux(soln_state, aux_soln_state, neighbor_cell_index); + + // Write the values in a way that we can use sum-factorization on. + for(int istate=0; istate conv_ref_flux; + dealii::Tensor<1,dim,real> diffusive_ref_flux; + // transform the conservative convective physical flux to reference space + if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){ + metric_oper_ext.transform_physical_to_reference( + conv_phys_flux[istate], + metric_cofactor_vol_ext, + conv_ref_flux); + } + // transform the dissipative flux to reference space + metric_oper_ext.transform_physical_to_reference( + diffusive_phys_flux[istate], + metric_cofactor_vol_ext, + diffusive_ref_flux); + + // Write the data in a way that we can use sum-factorization on. + // Since sum-factorization improves the speed for matrix-vector multiplications, + // We need the values to have their inner elements be vectors. + for(int idim=0; idimall_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){ + conv_ref_flux_at_vol_q_ext[istate][idim][iquad] = conv_ref_flux[idim]; + } + diffusive_ref_flux_at_vol_q_ext[istate][idim][iquad] = diffusive_ref_flux[idim]; + } + } + } - //std::cout <<"evaluating numerical fluxes" <::conv_num_flux_fad->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int); + // Interpolate the volume reference fluxes to the facet. + // And do the dot product with the UNIT REFERENCE normal. + // Since we are computing a dot product with the unit reference normal, + // we exploit the fact that the unit reference normal has a value of 0 in all reference directions except + // the outward reference normal dircetion. + const dealii::Tensor<1,dim,double> unit_ref_normal_int = dealii::GeometryInfo::unit_normal_vector[iface]; + // Extract the reference direction that is outward facing on the facet. + const int dim_not_zero = abs(unit_ref_normal_int[0]) >= 1e-11 ? 0 + : (abs(unit_ref_normal_int[1]) >= 1e-11 ? 1 + : (abs(unit_ref_normal_int[2]) >= 1e-11 ? 2 : (1000)) ); + if(dim_not_zero == 1000){ + pcout<<"Error with normals. Assume dim <=3."<pde_physics_fad->convective_flux (soln_int[iquad]); - conv_phys_flux_ext[iquad] = this->pde_physics_fad->convective_flux (soln_ext[iquad]); + std::array,nstate> conv_int_vol_ref_flux_interp_to_face_dot_ref_normal; + std::array,nstate> conv_ext_vol_ref_flux_interp_to_face_dot_ref_normal; + std::array,nstate> diffusive_int_vol_ref_flux_interp_to_face_dot_ref_normal; + std::array,nstate> diffusive_ext_vol_ref_flux_interp_to_face_dot_ref_normal; + for(int istate=0; istateall_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){ + flux_basis_int.matrix_vector_mult_surface_1D(iface, + conv_ref_flux_at_vol_q_int[istate][dim_not_zero], + conv_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate], + flux_basis_int.oneD_surf_operator,//the flux basis interpolates from the flux nodes + flux_basis_int.oneD_vol_operator, + false, unit_ref_normal_int[dim_not_zero]);//don't add to previous value, scale by unit_normal int + flux_basis_ext.matrix_vector_mult_surface_1D(neighbor_iface, + conv_ref_flux_at_vol_q_ext[istate][dim_not_zero], + conv_ext_vol_ref_flux_interp_to_face_dot_ref_normal[istate], + flux_basis_ext.oneD_surf_operator, + flux_basis_ext.oneD_vol_operator, + false, -unit_ref_normal_int[dim_not_zero]);//don't add to previous value, unit_normal ext is -unit normal int + } - // std::cout <<"done evaluating numerical fluxes" <::diss_num_flux_fad->evaluate_solution_flux(soln_int[iquad], soln_ext[iquad], normal_int); + //Note that for entropy-dissipation and entropy stability, the conservative variables + //are functions of projected entropy variables. For Euler etc, the transformation is nonlinear + //so careful attention to what is evaluated where and interpolated to where is needed. + //For further information, please see Chan, Jesse. "On discretely entropy conservative and entropy stable discontinuous Galerkin methods." Journal of Computational Physics 362 (2018): 346-374. + //pages 355 (Eq. 57 with text around it) and page 359 (Eq 86 and text below it). - ADArrayTensor1 diss_soln_jump_int, diss_soln_jump_ext; - for (int s=0; s,nstate> entropy_var_vol_int; + for(unsigned int iquad=0; iquad soln_state; + for(int istate=0; istate entropy_var; + entropy_var = this->pde_physics_double->compute_entropy_variables(soln_state); + for(int istate=0; istatepde_physics_fad->dissipative_flux (soln_int[iquad], diss_soln_jump_int, current_cell_index); - diss_flux_jump_ext[iquad] = this->pde_physics_fad->dissipative_flux (soln_ext[iquad], diss_soln_jump_ext, neighbor_cell_index); - - diss_auxi_num_flux_dot_n[iquad] = DGBaseState::diss_num_flux_fad->evaluate_auxiliary_flux( - current_cell_index, neighbor_cell_index, - 0.0, 0.0, - soln_int[iquad], soln_ext[iquad], - soln_grad_int[iquad], soln_grad_ext[iquad], - normal_int, penalty); } - - // From test functions associated with interior cell point of view - for (unsigned int itest_int=0; itest_int,nstate> entropy_var_vol_ext; + for(unsigned int iquad=0; iquad soln_state; + for(int istate=0; istate entropy_var; + entropy_var = this->pde_physics_double->compute_entropy_variables(soln_state); + for(int istate=0; istate,nstate> entropy_var_vol_int_interp_to_surf; + std::array,nstate> entropy_var_vol_ext_interp_to_surf; + for(int istate=0; istateall_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) { - for (unsigned int idof = 0; idof < n_dofs_int; ++idof) { - dR1_dW1[idof] = rhs.fastAccessDx(idof); + std::array,nstate> surf_vol_ref_2pt_flux_interp_surf_int; + std::array,nstate> surf_vol_ref_2pt_flux_interp_surf_ext; + std::array,nstate> surf_vol_ref_2pt_flux_interp_vol_int; + std::array,nstate> surf_vol_ref_2pt_flux_interp_vol_ext; + if(this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){ + //get surface-volume hybrid 2pt flux from Eq.(15) in Chan, Jesse. "Skew-symmetric entropy stable modal discontinuous Galerkin formulations." Journal of Scientific Computing 81.1 (2019): 459-485. + std::array,nstate> surface_ref_2pt_flux_int; + std::array,nstate> surface_ref_2pt_flux_ext; + for(int istate=0; istate metric_cofactor_surf; + for(int idim=0; idim entropy_var_face_int; + std::array entropy_var_face_ext; + for(int istate=0; istate soln_state_face_int; + soln_state_face_int = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var_face_int); + std::array soln_state_face_ext; + soln_state_face_ext = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var_face_ext); + + for (unsigned int iquad_vol=0; iquad_vol metric_cofactor_vol_int; + for(int idim=0; idim soln_state; + for(int istate=0; istate,nstate> conv_phys_flux_2pt; + conv_phys_flux_2pt = this->pde_physics_double->convective_numerical_split_flux(soln_state, soln_state_face_int); + for(int istate=0; istate conv_ref_flux_2pt; + //For each state, transform the physical flux to a reference flux. + metric_oper_int.transform_physical_to_reference( + conv_phys_flux_2pt[istate], + 0.5*(metric_cofactor_surf + metric_cofactor_vol_int), + conv_ref_flux_2pt); + //only store the dim not zero in reference space bc dot product with unit ref normal later. + surface_ref_2pt_flux_int[istate][iquad_face][iquad_vol] = conv_ref_flux_2pt[dim_not_zero]; + } } - for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) { - dR1_dW2[idof] = rhs.fastAccessDx(n_dofs_int+idof); + for (unsigned int iquad_vol=0; iquad_vol metric_cofactor_vol_ext; + for(int idim=0; idim soln_state; + for(int istate=0; istate,nstate> conv_phys_flux_2pt; + conv_phys_flux_2pt = this->pde_physics_double->convective_numerical_split_flux(soln_state, soln_state_face_ext); + for(int istate=0; istate conv_ref_flux_2pt; + //For each state, transform the physical flux to a reference flux. + metric_oper_ext.transform_physical_to_reference( + conv_phys_flux_2pt[istate], + 0.5*(metric_cofactor_surf + metric_cofactor_vol_ext), + conv_ref_flux_2pt); + //only store the dim not zero in reference space bc dot product with unit ref normal later. + surface_ref_2pt_flux_ext[istate][iquad_face][iquad_vol] = conv_ref_flux_2pt[dim_not_zero]; + } } - this->system_matrix.add(dof_indices_int[itest_int], dof_indices_int, dR1_dW1); - this->system_matrix.add(dof_indices_int[itest_int], dof_indices_ext, dR1_dW2); + } + + // Apply the surface Hadamard products and multiply with vector of ones for both off diagonal terms in + // Eq.(15) in Chan, Jesse. "Skew-symmetric entropy stable modal discontinuous Galerkin formulations." Journal of Scientific Computing 81.1 (2019): 459-485. + const std::vector &oneD_quad_weights_vol_int = this->oneD_quadrature_collection[poly_degree_int].get_weights(); + const std::vector &oneD_quad_weights_vol_ext = this->oneD_quadrature_collection[poly_degree_ext].get_weights(); + for(int istate=0; istate,nstate> conv_num_flux_dot_n; + std::array,nstate> diss_auxi_num_flux_dot_n; + for (unsigned int iquad=0; iquad metric_cofactor_surf; + for(int idim=0; idim entropy_var_face_int; + std::array entropy_var_face_ext; + std::array,nstate> aux_soln_state_int; + std::array,nstate> aux_soln_state_ext; + for(int istate=0; istateall_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) { - for (unsigned int idof = 0; idof < n_dofs_int; ++idof) { - dR2_dW1[idof] = rhs.fastAccessDx(idof); + std::array soln_state_int; + soln_state_int = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var_face_int); + std::array soln_state_ext; + soln_state_ext = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var_face_ext); + + + if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){ + for(int istate=0; istate unit_phys_normal_int; + metric_oper_int.transform_reference_to_physical(unit_ref_normal_int, + metric_cofactor_surf, + unit_phys_normal_int); + const double face_Jac_norm_scaled = unit_phys_normal_int.norm(); + unit_phys_normal_int /= face_Jac_norm_scaled;//normalize it. + // Note that the facet determinant of metric jacobian is the above norm multiplied by the determinant of the metric Jacobian evaluated on the facet. + // Since the determinant of the metric Jacobian evaluated on the face cancels off, we can just scale the numerical flux by the norm. + + std::array conv_num_flux_dot_n_at_q; + std::array diss_auxi_num_flux_dot_n_at_q; + // Convective numerical flux. + conv_num_flux_dot_n_at_q = this->conv_num_flux_double->evaluate_flux(soln_state_int, soln_state_ext, unit_phys_normal_int); + // dissipative numerical flux + diss_auxi_num_flux_dot_n_at_q = this->diss_num_flux_double->evaluate_auxiliary_flux( + current_cell_index, neighbor_cell_index, + 0.0, 0.0, + soln_state_int, soln_state_ext, + aux_soln_state_int, aux_soln_state_ext, + unit_phys_normal_int, penalty, false); + + // Write the values in a way that we can use sum-factorization on. + for(int istate=0; istatesystem_matrix.add(dof_indices_ext[itest_ext], dof_indices_int, dR2_dW1); - this->system_matrix.add(dof_indices_ext[itest_ext], dof_indices_ext, dR2_dW2); + + // write data + conv_num_flux_dot_n[istate][iquad] = face_Jac_norm_scaled * conv_num_flux_dot_n_at_q[istate]; + diss_auxi_num_flux_dot_n[istate][iquad] = face_Jac_norm_scaled * diss_auxi_num_flux_dot_n_at_q[istate]; + } + } + + // Compute RHS + const std::vector &surf_quad_weights = this->face_quadrature_collection[poly_degree_int].get_weights(); + for(int istate=0; istate rhs_int(n_shape_fns_int); + + // convective flux + if(this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){ + std::vector ones_surf(n_face_quad_pts, 1.0); + soln_basis_int.inner_product_surface_1D(iface, + surf_vol_ref_2pt_flux_interp_surf_int[istate], + ones_surf, rhs_int, + soln_basis_int.oneD_surf_operator, + soln_basis_int.oneD_vol_operator, + false, -1.0); + std::vector ones_vol(n_quad_pts_vol_int, 1.0); + soln_basis_int.inner_product_1D(surf_vol_ref_2pt_flux_interp_vol_int[istate], + ones_vol, rhs_int, + soln_basis_int.oneD_vol_operator, + true, -1.0); + } + else + { + soln_basis_int.inner_product_surface_1D(iface, + conv_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate], + surf_quad_weights, rhs_int, + soln_basis_int.oneD_surf_operator, + soln_basis_int.oneD_vol_operator, + false, 1.0); + } + // dissipative flux + soln_basis_int.inner_product_surface_1D(iface, + diffusive_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate], + surf_quad_weights, rhs_int, + soln_basis_int.oneD_surf_operator, + soln_basis_int.oneD_vol_operator, + true, 1.0);//adding=true, subtract the negative so add it + // convective numerical flux + soln_basis_int.inner_product_surface_1D(iface, conv_num_flux_dot_n[istate], + surf_quad_weights, rhs_int, + soln_basis_int.oneD_surf_operator, + soln_basis_int.oneD_vol_operator, + true, -1.0);//adding=true, scaled by factor=-1.0 bc subtract it + // dissipative numerical flux + soln_basis_int.inner_product_surface_1D(iface, diss_auxi_num_flux_dot_n[istate], + surf_quad_weights, rhs_int, + soln_basis_int.oneD_surf_operator, + soln_basis_int.oneD_vol_operator, + true, -1.0);//adding=true, scaled by factor=-1.0 bc subtract it + + + for(unsigned int ishape=0; ishape rhs_ext(n_shape_fns_int); + + // convective flux + if(this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){ + std::vector ones_surf(n_face_quad_pts, 1.0); + soln_basis_ext.inner_product_surface_1D(neighbor_iface, + surf_vol_ref_2pt_flux_interp_surf_ext[istate], + ones_surf, rhs_ext, + soln_basis_ext.oneD_surf_operator, + soln_basis_ext.oneD_vol_operator, + false, -1.0);//the negative sign is bc the surface Hadamard function computes it on the otherside. + //to satisfy the unit test that checks consistency with Jesse Chan's formulation. + std::vector ones_vol(n_quad_pts_vol_ext, 1.0); + soln_basis_ext.inner_product_1D(surf_vol_ref_2pt_flux_interp_vol_ext[istate], + ones_vol, rhs_ext, + soln_basis_ext.oneD_vol_operator, + true, -1.0); + } + else + { + soln_basis_ext.inner_product_surface_1D(neighbor_iface, + conv_ext_vol_ref_flux_interp_to_face_dot_ref_normal[istate], + surf_quad_weights, rhs_ext, + soln_basis_ext.oneD_surf_operator, + soln_basis_ext.oneD_vol_operator, + false, 1.0);//adding false + } + // dissipative flux + soln_basis_ext.inner_product_surface_1D(neighbor_iface, + diffusive_ext_vol_ref_flux_interp_to_face_dot_ref_normal[istate], + surf_quad_weights, rhs_ext, + soln_basis_ext.oneD_surf_operator, + soln_basis_ext.oneD_vol_operator, + true, 1.0);//adding=true + // convective numerical flux + soln_basis_ext.inner_product_surface_1D(neighbor_iface, conv_num_flux_dot_n[istate], + surf_quad_weights, rhs_ext, + soln_basis_ext.oneD_surf_operator, + soln_basis_ext.oneD_vol_operator, + true, 1.0);//adding=true, scaled by factor=1.0 because negative numerical flux and subtract it + // dissipative numerical flux + soln_basis_ext.inner_product_surface_1D(neighbor_iface, diss_auxi_num_flux_dot_n[istate], + surf_quad_weights, rhs_ext, + soln_basis_ext.oneD_surf_operator, + soln_basis_ext.oneD_vol_operator, + true, 1.0);//adding=true, scaled by factor=1.0 because negative numerical flux and subtract it + + + for(unsigned int ishape=0; ishape +void DGStrong::assemble_boundary_term_derivatives( + typename dealii::DoFHandler::active_cell_iterator /*cell*/, + const dealii::types::global_dof_index /*current_cell_index*/, + const unsigned int ,//face_number, + const unsigned int /*boundary_id*/, + const dealii::FEFaceValuesBase &/*fe_values_boundary*/, + const real /*penalty*/, + const dealii::FESystem &,//fe, + const dealii::Quadrature &,//quadrature, + const std::vector &,//metric_dof_indices, + const std::vector &/*soln_dof_indices*/, + dealii::Vector &/*local_rhs_int_cell*/, + const bool /*compute_dRdW*/, + const bool /*compute_dRdX*/, + const bool /*compute_d2R*/) +{ + //Do nothing + +// (void) current_cell_index; +// assert(compute_dRdW); assert(!compute_dRdX); assert(!compute_d2R); +// (void) compute_dRdW; (void) compute_dRdX; (void) compute_d2R; +// using ADArray = std::array; +// using ADArrayTensor1 = std::array< dealii::Tensor<1,dim,FadType>, 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; +// +// AssertDimension (n_dofs_cell, soln_dof_indices.size()); +// +// const std::vector &JxW = fe_values_boundary.get_JxW_values (); +// const std::vector> &normals = fe_values_boundary.get_normal_vectors (); +// +// std::vector residual_derivatives(n_dofs_cell); +// +// 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 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_flux_jump_ext(n_face_quad_pts); // u*-u_int +// std::vector diss_auxi_num_flux_dot_n(n_face_quad_pts); // sigma* +// +// std::vector conv_phys_flux(n_face_quad_pts); +// +// // AD variable +// std::vector< FadType > soln_coeff_int(n_dofs_cell); +// const unsigned int n_total_indep = n_dofs_cell; +// for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { +// soln_coeff_int[idof] = DGBase::solution(soln_dof_indices[idof]); +// soln_coeff_int[idof].diff(idof, n_total_indep); +// } +// +// for (unsigned int iquad=0; iquad > quad_pts = fe_values_boundary.get_quadrature_points(); +// for (unsigned int iquad=0; iquad normal_int = normals[iquad]; +// const dealii::Tensor<1,dim,FadType> normal_ext = -normal_int; +// +// for (unsigned int idof=0; idof real_quad_point = quad_pts[iquad]; +// dealii::Point ad_point; +// for (int d=0;dpde_physics_fad->boundary_face_values (boundary_id, ad_point, normal_int, soln_int[iquad], soln_grad_int[iquad], soln_ext[iquad], soln_grad_ext[iquad]); +// +// // +// // Evaluate physical convective flux, physical dissipative flux +// // Following the the boundary treatment given by +// // Hartmann, R., Numerical Analysis of Higher Order Discontinuous Galerkin Finite Element Methods, +// // Institute of Aerodynamics and Flow Technology, DLR (German Aerospace Center), 2008. +// // Details given on page 93 +// //conv_num_flux_dot_n[iquad] = DGBaseState::conv_num_flux_fad->evaluate_flux(soln_ext[iquad], soln_ext[iquad], normal_int); +// +// // So, I wasn't able to get Euler manufactured solutions to converge when F* = F*(Ubc, Ubc) +// // Changing it back to the standdard F* = F*(Uin, Ubc) +// // This is known not be adjoint consistent as per the paper above. Page 85, second to last paragraph. +// // Losing 2p+1 OOA on functionals for all PDEs. +// conv_num_flux_dot_n[iquad] = DGBaseState::conv_num_flux_fad->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int); +// +// // Used for strong form +// // Which physical convective flux to use? +// conv_phys_flux[iquad] = this->pde_physics_fad->convective_flux (soln_int[iquad]); +// +// // Notice that the flux uses the solution given by the Dirichlet or Neumann boundary condition +// diss_soln_num_flux[iquad] = DGBaseState::diss_num_flux_fad->evaluate_solution_flux(soln_ext[iquad], soln_ext[iquad], normal_int); +// +// ADArrayTensor1 diss_soln_jump_int; +// ADArrayTensor1 diss_soln_jump_ext; +// for (int s=0; spde_physics_fad->dissipative_flux (soln_int[iquad], diss_soln_jump_int, current_cell_index); +// diss_flux_jump_ext[iquad] = this->pde_physics_fad->dissipative_flux (soln_ext[iquad], diss_soln_jump_ext, neighbor_cell_index); +// +// diss_auxi_num_flux_dot_n[iquad] = DGBaseState::diss_num_flux_fad->evaluate_auxiliary_flux( +// current_cell_index, neighbor_cell_index, +// 0.0, 0.0, +// soln_int[iquad], soln_ext[iquad], +// soln_grad_int[iquad], soln_grad_ext[iquad], +// normal_int, penalty, true); +// } +// +// // Boundary integral +// for (unsigned int itest=0; itestall_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) { +// for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { +// //residual_derivatives[idof] = rhs.fastAccessDx(idof); +// residual_derivatives[idof] = rhs.fastAccessDx(idof); +// } +// this->system_matrix.add(soln_dof_indices[itest], soln_dof_indices, residual_derivatives); +// } +// } +} + +template +void DGStrong::assemble_volume_term_derivatives( + typename dealii::DoFHandler::active_cell_iterator /*cell*/, + const dealii::types::global_dof_index /*current_cell_index*/, + const dealii::FEValues &/*fe_values_vol*/, + const dealii::FESystem &,//fe, + const dealii::Quadrature &,//quadrature, + const std::vector &,//metric_dof_indices, + const std::vector &/*cell_dofs_indices*/, + dealii::Vector &/*local_rhs_int_cell*/, + const dealii::FEValues &/*fe_values_lagrange*/, + const bool /*compute_dRdW*/, + const bool /*compute_dRdX*/, + const bool /*compute_d2R*/) +{ + //Do nothing + +// (void) current_cell_index; +// assert(compute_dRdW); assert(!compute_dRdX); assert(!compute_d2R); +// (void) compute_dRdW; (void) compute_dRdX; (void) compute_d2R; +// using ADArray = std::array; +// using ADArrayTensor1 = std::array< dealii::Tensor<1,dim,FadType>, 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; +// +// AssertDimension (n_dofs_cell, cell_dofs_indices.size()); +// +// const std::vector &JxW = fe_values_vol.get_JxW_values (); +// +// std::vector residual_derivatives(n_dofs_cell); +// +// std::vector< ADArray > soln_at_q(n_quad_pts); +// std::vector< ADArrayTensor1 > soln_grad_at_q(n_quad_pts); // Tensor initialize with zeros +// +// 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); +// +// // AD variable +// std::vector< FadType > soln_coeff(n_dofs_cell); +// for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { +// soln_coeff[idof] = DGBase::solution(cell_dofs_indices[idof]); +// soln_coeff[idof].diff(idof, n_dofs_cell); +// } +// for (unsigned int iquad=0; iquad1) std::cout << "Momentum " << soln_at_q[iquad][1] << std::endl; +// //std::cout << "Energy " << soln_at_q[iquad][nstate-1] << std::endl; +// // Evaluate physical convective flux and source term +// conv_phys_flux_at_q[iquad] = DGBaseState::pde_physics_double->convective_flux (soln_at_q[iquad]); +// diss_phys_flux_at_q[iquad] = DGBaseState::pde_physics_double->dissipative_flux (soln_at_q[iquad], soln_grad_at_q[iquad], current_cell_index); +// if(this->all_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term) { +// source_at_q[iquad] = DGBaseState::pde_physics_double->source_term (fe_values_vol.quadrature_point(iquad), soln_at_q[iquad], current_cell_index, DGBase::current_time); +// } +// } +// +// +// // Evaluate flux divergence by interpolating the flux +// // Since we have nodal values of the flux, we use the Lagrange polynomials to obtain the gradients at the quadrature points. +// //const dealii::FEValues &fe_values_lagrange = this->fe_values_collection_volume_lagrange.get_present_fe_values(); +// std::vector flux_divergence(n_quad_pts); +// +// std::array,nstate>,dim> f; +// std::array,nstate>,dim> g; +// +// for (int istate = 0; istateall_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term) { +// rhs = rhs + fe_values_vol.shape_value_component(itest,iquad,istate) * source_at_q[iquad][istate] * JxW[iquad]; +// } +// } +// //local_rhs_int_cell(itest) += rhs; +// +// } +} + + +template +void DGStrong::assemble_face_term_derivatives( + typename dealii::DoFHandler::active_cell_iterator /*cell*/, + const dealii::types::global_dof_index /*current_cell_index*/, + const dealii::types::global_dof_index /*neighbor_cell_index*/, + const std::pair /*face_subface_int*/, + const std::pair /*face_subface_ext*/, + const typename dealii::QProjector::DataSetDescriptor /*face_data_set_int*/, + const typename dealii::QProjector::DataSetDescriptor /*face_data_set_ext*/, + const dealii::FEFaceValuesBase &/*fe_values_int*/, + const dealii::FEFaceValuesBase &/*fe_values_ext*/, + const real /*penalty*/, + const dealii::FESystem &,//fe_int, + const dealii::FESystem &,//fe_ext, + const dealii::Quadrature &,//face_quadrature_int, + const std::vector &,//metric_dof_indices_int, + const std::vector &,//metric_dof_indices_ext, + const std::vector &/*soln_dof_indices_int*/, + const std::vector &/*soln_dof_indices_ext*/, + dealii::Vector &/*local_rhs_int_cell*/, + dealii::Vector &/*local_rhs_ext_cell*/, + const bool /*compute_dRdW*/, + const bool /*compute_dRdX*/, + const bool /*compute_d2R*/) +{ + //Do nothing + +// (void) current_cell_index; +// (void) neighbor_cell_index; +// assert(compute_dRdW); assert(!compute_dRdX); assert(!compute_d2R); +// (void) compute_dRdW; (void) compute_dRdX; (void) compute_d2R; +// using ADArray = std::array; +// using ADArrayTensor1 = std::array< dealii::Tensor<1,dim,FadType>, nstate >; +// +// // Use quadrature points of neighbor cell +// // Might want to use the maximum n_quad_pts1 and n_quad_pts2 +// const unsigned int n_face_quad_pts = fe_values_ext.n_quadrature_points; +// +// const unsigned int n_dofs_int = fe_values_int.dofs_per_cell; +// const unsigned int n_dofs_ext = fe_values_ext.dofs_per_cell; +// +// AssertDimension (n_dofs_int, soln_dof_indices_int.size()); +// AssertDimension (n_dofs_ext, soln_dof_indices_ext.size()); +// +// // Jacobian and normal should always be consistent between two elements +// // even for non-conforming meshes? +// const std::vector &JxW_int = fe_values_int.get_JxW_values (); +// const std::vector > &normals_int = fe_values_int.get_normal_vectors (); +// +// // AD variable +// std::vector soln_coeff_int_ad(n_dofs_int); +// std::vector soln_coeff_ext_ad(n_dofs_ext); +// +// +// // Jacobian blocks +// std::vector dR1_dW1(n_dofs_int); +// std::vector dR1_dW2(n_dofs_ext); +// std::vector dR2_dW1(n_dofs_int); +// std::vector dR2_dW2(n_dofs_ext); +// +// std::vector conv_num_flux_dot_n(n_face_quad_pts); +// std::vector conv_phys_flux_int(n_face_quad_pts); +// std::vector conv_phys_flux_ext(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< 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 +// // AD variable +// const unsigned int n_total_indep = n_dofs_int + n_dofs_ext; +// for (unsigned int idof = 0; idof < n_dofs_int; ++idof) { +// soln_coeff_int_ad[idof] = DGBase::solution(soln_dof_indices_int[idof]); +// soln_coeff_int_ad[idof].diff(idof, n_total_indep); +// } +// for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) { +// soln_coeff_ext_ad[idof] = DGBase::solution(soln_dof_indices_ext[idof]); +// soln_coeff_ext_ad[idof].diff(idof+n_dofs_int, n_total_indep); +// } +// for (unsigned int iquad=0; iquad normal_int = normals_int[iquad]; +// const dealii::Tensor<1,dim,FadType> normal_ext = -normal_int; +// +// // Interpolate solution to face +// for (unsigned int idof=0; idof1) std::cout << "Momentum int" << soln_int[iquad][1] << std::endl; +// //std::cout << "Energy int" << soln_int[iquad][nstate-1] << std::endl; +// //std::cout << "Density ext" << soln_ext[iquad][0] << std::endl; +// //if(nstate>1) std::cout << "Momentum ext" << soln_ext[iquad][1] << std::endl; +// //std::cout << "Energy ext" << soln_ext[iquad][nstate-1] << std::endl; +// +// // Evaluate physical convective flux, physical dissipative flux, and source term +// conv_num_flux_dot_n[iquad] = DGBaseState::conv_num_flux_fad->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int); +// +// conv_phys_flux_int[iquad] = this->pde_physics_fad->convective_flux (soln_int[iquad]); +// conv_phys_flux_ext[iquad] = this->pde_physics_fad->convective_flux (soln_ext[iquad]); +// +// diss_soln_num_flux[iquad] = DGBaseState::diss_num_flux_fad->evaluate_solution_flux(soln_int[iquad], soln_ext[iquad], normal_int); +// +// ADArrayTensor1 diss_soln_jump_int, diss_soln_jump_ext; +// for (int s=0; spde_physics_fad->dissipative_flux (soln_int[iquad], diss_soln_jump_int, current_cell_index); +// diss_flux_jump_ext[iquad] = this->pde_physics_fad->dissipative_flux (soln_ext[iquad], diss_soln_jump_ext, neighbor_cell_index); +// +// diss_auxi_num_flux_dot_n[iquad] = DGBaseState::diss_num_flux_fad->evaluate_auxiliary_flux( +// current_cell_index, neighbor_cell_index, +// 0.0, 0.0, +// soln_int[iquad], soln_ext[iquad], +// soln_grad_int[iquad], soln_grad_ext[iquad], +// normal_int, penalty); +// } +// +// // From test functions associated with interior cell point of view +// for (unsigned int itest_int=0; itest_intall_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) { +// for (unsigned int idof = 0; idof < n_dofs_int; ++idof) { +// dR1_dW1[idof] = rhs.fastAccessDx(idof); +// } +// for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) { +// dR1_dW2[idof] = rhs.fastAccessDx(n_dofs_int+idof); +// } +// this->system_matrix.add(soln_dof_indices_int[itest_int], soln_dof_indices_int, dR1_dW1); +// this->system_matrix.add(soln_dof_indices_int[itest_int], soln_dof_indices_ext, dR1_dW2); +// } +// } +// +// // From test functions associated with neighbour cell point of view +// for (unsigned int itest_ext=0; itest_extall_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) { +// for (unsigned int idof = 0; idof < n_dofs_int; ++idof) { +// dR2_dW1[idof] = rhs.fastAccessDx(idof); +// } +// for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) { +// dR2_dW2[idof] = rhs.fastAccessDx(n_dofs_int+idof); +// } +// this->system_matrix.add(soln_dof_indices_ext[itest_ext], soln_dof_indices_int, dR2_dW1); +// this->system_matrix.add(soln_dof_indices_ext[itest_ext], soln_dof_indices_ext, dR2_dW2); +// } +// } +} + +/******************************************************* + * + * EXPLICIT + * + *******************************************************/ + +template +void DGStrong::assemble_volume_term_explicit( + typename dealii::DoFHandler::active_cell_iterator /*cell*/, + const dealii::types::global_dof_index /*current_cell_index*/, + const dealii::FEValues &/*fe_values_vol*/, + const std::vector &/*cell_dofs_indices*/, + const std::vector &/*metric_dof_indices*/, + const unsigned int /*poly_degree*/, + const unsigned int /*grid_degree*/, + dealii::Vector &/*local_rhs_int_cell*/, + const dealii::FEValues &/*fe_values_lagrange*/) +{ + //do nothing +} + +template +void DGStrong::assemble_boundary_term_explicit( + typename dealii::DoFHandler::active_cell_iterator /*cell*/, + const dealii::types::global_dof_index /*current_cell_index*/, + const unsigned int /*boundary_id*/, + const dealii::FEFaceValuesBase &/*fe_values_boundary*/, + const real /*penalty*/, + const std::vector &/*dof_indices_int*/, + dealii::Vector &/*local_rhs_int_cell*/) +{ + //Do nothing +} + +template +void DGStrong::assemble_face_term_explicit( + const unsigned int /*iface*/, const unsigned int /*neighbor_iface*/, + typename dealii::DoFHandler::active_cell_iterator /*cell*/, + const dealii::types::global_dof_index /*current_cell_index*/, + const dealii::types::global_dof_index /*neighbor_cell_index*/, + const unsigned int /*poly_degree*/, const unsigned int /*grid_degree*/, + const dealii::FEFaceValuesBase &/*fe_values_int*/, + const dealii::FEFaceValuesBase &/*fe_values_ext*/, + const real /*penalty*/, + const std::vector &/*dof_indices_int*/, + const std::vector &/*dof_indices_ext*/, + const std::vector &/*metric_dof_indices_int*/, + const std::vector &/*metric_dof_indices_ext*/, + dealii::Vector &/*local_rhs_int_cell*/, + dealii::Vector &/*local_rhs_ext_cell*/) +{ + //Do nothing +} + + // using default MeshType = Triangulation // 1D: dealii::Triangulation; -// OW: dealii::parallel::distributed::Triangulation; +// Otherwise: dealii::parallel::distributed::Triangulation; template class DGStrong >; template class DGStrong >; template class DGStrong >; @@ -981,4 +2711,3 @@ template class DGStrong protected: /// Alias to base class Triangulation. using Triangulation = typename DGBaseState::Triangulation; + public: /// Constructor DGStrong( @@ -30,11 +31,262 @@ class DGStrong: public DGBaseState /// Destructor ~DGStrong(); + /// Assembles the auxiliary equations' residuals and solves for the auxiliary variables. + void assemble_auxiliary_residual (); + private: + /// Assembles the auxiliary equations' cell residuals. + template + void assemble_cell_auxiliary_residual ( + const DoFCellAccessorType1 ¤t_cell, + const DoFCellAccessorType2 ¤t_metric_cell, + std::vector> &rhs); + +protected: + /// Builds the necessary operators and assembles volume residual for either primary or auxiliary. + void assemble_volume_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + const dealii::types::global_dof_index current_cell_index, + const std::vector &cell_dofs_indices, + const std::vector &metric_dof_indices, + const unsigned int poly_degree, + const unsigned int grid_degree, + OPERATOR::basis_functions &soln_basis, + OPERATOR::basis_functions &flux_basis, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper, + OPERATOR::mapping_shape_functions &mapping_basis, + std::array,dim> &mapping_support_points, + dealii::hp::FEValues &/*fe_values_collection_volume*/, + dealii::hp::FEValues &/*fe_values_collection_volume_lagrange*/, + const dealii::FESystem &/*current_fe_ref*/, + dealii::Vector &local_rhs_int_cell, + std::vector> &local_auxiliary_RHS, + const bool compute_auxiliary_right_hand_side, + const bool /*compute_dRdW*/, const bool /*compute_dRdX*/, const bool /*compute_d2R*/); + + /// Builds the necessary operators and assembles boundary residual for either primary or auxiliary. + void assemble_boundary_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator /*cell*/, + const dealii::types::global_dof_index current_cell_index, + const unsigned int iface, + const unsigned int boundary_id, + const real penalty, + const std::vector &cell_dofs_indices, + const std::vector &metric_dof_indices, + const unsigned int poly_degree, + const unsigned int grid_degree, + OPERATOR::basis_functions &soln_basis, + OPERATOR::basis_functions &flux_basis, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper, + OPERATOR::mapping_shape_functions &mapping_basis, + std::array,dim> &mapping_support_points, + dealii::hp::FEFaceValues &/*fe_values_collection_face_int*/, + const dealii::FESystem &/*current_fe_ref*/, + dealii::Vector &local_rhs_int_cell, + std::vector> &local_auxiliary_RHS, + const bool compute_auxiliary_right_hand_side, + const bool /*compute_dRdW*/, const bool /*compute_dRdX*/, const bool /*compute_d2R*/); + + /// Builds the necessary operators and assembles face residual. + void assemble_face_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator /*cell*/, + typename dealii::DoFHandler::active_cell_iterator /*neighbor_cell*/, + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int iface, + const unsigned int neighbor_iface, + const real penalty, + const std::vector ¤t_dofs_indices, + const std::vector &neighbor_dofs_indices, + const std::vector ¤t_metric_dofs_indices, + const std::vector &neighbor_metric_dofs_indices, + const unsigned int poly_degree_int, + const unsigned int poly_degree_ext, + const unsigned int grid_degree_int, + const unsigned int grid_degree_ext, + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::basis_functions &flux_basis_int, + OPERATOR::basis_functions &flux_basis_ext, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper_int, + OPERATOR::metric_operators &metric_oper_ext, + OPERATOR::mapping_shape_functions &mapping_basis, + std::array,dim> &mapping_support_points, + dealii::hp::FEFaceValues &/*fe_values_collection_face_int*/, + dealii::hp::FEFaceValues &/*fe_values_collection_face_ext*/, + dealii::Vector ¤t_cell_rhs, + dealii::Vector &neighbor_cell_rhs, + std::vector> ¤t_cell_rhs_aux, + dealii::LinearAlgebra::distributed::Vector &rhs, + std::array,dim> &rhs_aux, + const bool compute_auxiliary_right_hand_side, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R); + + /// Builds the necessary operators and assembles subface residual. + /** Not verified + */ + void assemble_subface_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + typename dealii::DoFHandler::active_cell_iterator neighbor_cell, + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int iface, + const unsigned int neighbor_iface, + const unsigned int /*neighbor_i_subface*/, + const real penalty, + const std::vector ¤t_dofs_indices, + const std::vector &neighbor_dofs_indices, + const std::vector ¤t_metric_dofs_indices, + const std::vector &neighbor_metric_dofs_indices, + const unsigned int poly_degree_int, + const unsigned int poly_degree_ext, + const unsigned int grid_degree_int, + const unsigned int grid_degree_ext, + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::basis_functions &flux_basis_int, + OPERATOR::basis_functions &flux_basis_ext, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper_int, + OPERATOR::metric_operators &metric_oper_ext, + OPERATOR::mapping_shape_functions &mapping_basis, + std::array,dim> &mapping_support_points, + dealii::hp::FEFaceValues &fe_values_collection_face_int, + dealii::hp::FESubfaceValues &/*fe_values_collection_subface*/, + dealii::Vector ¤t_cell_rhs, + dealii::Vector &neighbor_cell_rhs, + std::vector> ¤t_cell_rhs_aux, + dealii::LinearAlgebra::distributed::Vector &rhs, + std::array,dim> &rhs_aux, + const bool compute_auxiliary_right_hand_side, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R); + +public: + ///Evaluate the volume RHS for the auxiliary equation. + /** \f[ + * \int_{\mathbf{\Omega}_r} \chi_i(\mathbf{\xi}^r) \left( \nabla^r(u) \right)\mathbf{C}_m(\mathbf{\xi}^r) d\mathbf{\Omega}_r,\:\forall i=1,\dots,N_p. + * \f] + */ + void assemble_volume_term_auxiliary_equation( + const std::vector ¤t_dofs_indices, + const unsigned int poly_degree, + OPERATOR::basis_functions &soln_basis, + OPERATOR::basis_functions &flux_basis, + OPERATOR::metric_operators &metric_oper, + std::vector> &local_auxiliary_RHS); +protected: + /// Evaluate the boundary RHS for the auxiliary equation. + void assemble_boundary_term_auxiliary_equation( + const unsigned int iface, + const dealii::types::global_dof_index current_cell_index, + const unsigned int poly_degree, + const unsigned int boundary_id, + const std::vector &dofs_indices, + OPERATOR::basis_functions &soln_basis, + OPERATOR::metric_operators &metric_oper, + std::vector> &local_auxiliary_RHS); + +public: + /// Evaluate the facet RHS for the auxiliary equation. + /** \f[ + * \int_{\mathbf{\Gamma}_r} \chi_i \left( \hat{\mathbf{n}}^r\mathbf{C}_m(\mathbf{\xi}^r)^T\right) \cdot \left[ u^* + * - u\right]d\mathbf{\Gamma}_r,\:\forall i=1,\dots,N_p. + * \f] + */ + void assemble_face_term_auxiliary_equation( + const unsigned int iface, + const unsigned int neighbor_iface, + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int poly_degree_int, + const unsigned int poly_degree_ext, + const std::vector &dof_indices_int, + const std::vector &dof_indices_ext, + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::metric_operators &metric_oper_int, + std::vector> &local_auxiliary_RHS_int, + std::vector> &local_auxiliary_RHS_ext); + +protected: + /// Strong form primary equation's volume right-hand-side. + /** We refer to Cicchino, Alexander, et al. "Provably stable flux reconstruction high-order methods on curvilinear elements." Journal of Computational Physics 463 (2022): 111259. + * Conservative form Eq. (17):
+ *\f[ + * \int_{\mathbf{\Omega}_r} \chi_i (\mathbf{\xi}^r) \left(\nabla^r \phi(\mathbf{\xi}^r) \cdot \hat{\mathbf{f}}^r \right) d\mathbf{\Omega}_r + * ,\:\forall i=1,\dots,N_p, + * \f] + * where \f$ \chi \f$ is the basis function, \f$ \phi \f$ is the flux basis (basis collocated on the volume cubature nodes, + * and \f$\hat{\mathbf{f}}^r = \mathbf{\Pi}\left(\mathbf{f}_m\mathbf{C}_m \right) \f$ is the projection of the reference flux. + *
Entropy stable two-point flux form (extension of Eq. (22))
+ * \f[ + * \mathbf{\chi}(\mathbf{\xi}_v^r)^T \mathbf{W} 2 \left[ \nabla^r\mathbf{\phi}(\mathbf{\xi}_v^r) \circ + * \mathbf{F}^r\right] \mathbf{1}^T d\mathbf{\Omega}_r + * ,\:\forall i=1,\dots,N_p, + * \f] + * where \f$ (\mathbf{F})_{ij} = 0.5\left( \mathbf{C}_m(\mathbf{\xi}_i^r)+\mathbf{C}_m(\mathbf{\xi}_j^r) \right) \cdot \mathbf{f}_s(\mathbf{u}(\mathbf{\xi}_i^r),\mathbf{u}(\mathbf{\xi}_j^r)) \f$; that is, the + * matrix of REFERENCE two-point entropy conserving fluxes. + */ + void assemble_volume_term_strong( + typename dealii::DoFHandler::active_cell_iterator cell, + const dealii::types::global_dof_index current_cell_index, + const std::vector &cell_dofs_indices, + const unsigned int poly_degree, + OPERATOR::basis_functions &soln_basis, + OPERATOR::basis_functions &flux_basis, + OPERATOR::local_basis_stiffness &flux_basis_stiffness, + OPERATOR::metric_operators &metric_oper, + dealii::Vector &local_rhs_int_cell); + + /// Strong form primary equation's boundary right-hand-side. + void assemble_boundary_term_strong( + const unsigned int iface, + const dealii::types::global_dof_index current_cell_index, + const unsigned int boundary_id, + const unsigned int poly_degree, + const real penalty, + const std::vector &dof_indices, + OPERATOR::basis_functions &soln_basis, + OPERATOR::basis_functions &flux_basis, + OPERATOR::metric_operators &metric_oper, + dealii::Vector &local_rhs_cell); + + /// Strong form primary equation's facet right-hand-side. + /** + * \f[ + * \int_{\mathbf{\Gamma}_r}{\chi}_i(\mathbf{\xi}^r) \Big[ + * \hat{\mathbf{n}}^r\mathbf{C}_m^T \cdot \mathbf{f}^*_m - \hat{\mathbf{n}}^r \cdot \mathbf{\chi}(\mathbf{\xi}^r)\mathbf{\hat{f}}^r_m(t)^T + * \Big]d \mathbf{\Gamma}_r + * ,\:\forall i=1,\dots,N_p. + * \f] + */ + void assemble_face_term_strong( + const unsigned int iface, + const unsigned int neighbor_iface, + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int poly_degree_int, + const unsigned int poly_degree_ext, + const real penalty, + const std::vector &dof_indices_int, + const std::vector &dof_indices_ext, + OPERATOR::basis_functions &soln_basis_int, + OPERATOR::basis_functions &soln_basis_ext, + OPERATOR::basis_functions &flux_basis_int, + OPERATOR::basis_functions &flux_basis_ext, + OPERATOR::metric_operators &metric_oper_int, + OPERATOR::metric_operators &metric_oper_ext, + dealii::Vector &local_rhs_int_cell, + dealii::Vector &local_rhs_ext_cell); + +protected: /// Evaluate the integral over the cell volume and the specified derivatives. /** Compute both the right-hand side and the corresponding block of dRdW, dRdX, and/or d2R. */ - virtual void assemble_volume_term_derivatives( + void assemble_volume_term_derivatives( typename dealii::DoFHandler::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const dealii::FEValues &,//fe_values_vol, @@ -45,6 +297,8 @@ class DGStrong: public DGBaseState dealii::Vector &local_rhs_cell, const dealii::FEValues &/*fe_values_lagrange*/, const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R); + + /// Assemble boundary term derivatives void assemble_boundary_term_derivatives( typename dealii::DoFHandler::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, @@ -58,6 +312,7 @@ class DGStrong: public DGBaseState const std::vector &soln_dof_indices, dealii::Vector &local_rhs_cell, const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R); + /// Evaluate the integral over the internal cell edges and its specified derivatives. /** Compute both the right-hand side and the block of the Jacobian. * This adds the contribution to both cell's residual and effectively @@ -90,8 +345,12 @@ class DGStrong: public DGBaseState const dealii::types::global_dof_index current_cell_index, const dealii::FEValues &fe_values_volume, const std::vector ¤t_dofs_indices, + const std::vector &metric_dof_indices, + const unsigned int poly_degree, + const unsigned int grid_degree, dealii::Vector ¤t_cell_rhs, const dealii::FEValues &fe_values_lagrange); + /// Evaluate the integral over the cell edges that are on domain boundaries void assemble_boundary_term_explicit( typename dealii::DoFHandler::active_cell_iterator cell, @@ -101,23 +360,28 @@ class DGStrong: public DGBaseState const real penalty, const std::vector ¤t_dofs_indices, dealii::Vector ¤t_cell_rhs); + /// Evaluate the integral over the internal cell edges void assemble_face_term_explicit( + const unsigned int iface, + const unsigned int neighbor_iface, typename dealii::DoFHandler::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int poly_degree, + const unsigned int grid_degree, const dealii::FEFaceValuesBase &fe_values_face_int, const dealii::FEFaceValuesBase &fe_values_face_ext, const real penalty, const std::vector ¤t_dofs_indices, const std::vector &neighbor_dofs_indices, + const std::vector &metric_dof_indices_int, + const std::vector &metric_dof_indices_ext, dealii::Vector ¤t_cell_rhs, dealii::Vector &neighbor_cell_rhs); - using DGBase::all_parameters; ///< Pointer to all parameters - using DGBase::mpi_communicator; ///< MPI communicator using DGBase::pcout; ///< Parallel std::cout that only outputs on mpi_rank==0 - + }; // end of DGStrong class } // PHiLiP namespace diff --git a/src/dg/weak_dg.cpp b/src/dg/weak_dg.cpp index fd54fa8aa..474bdb25f 100644 --- a/src/dg/weak_dg.cpp +++ b/src/dg/weak_dg.cpp @@ -262,7 +262,6 @@ void evaluate_finite_element_values ( } } - template bool check_same_coords ( const std::vector> &unit_quad_pts_int, @@ -552,6 +551,9 @@ void DGWeak::assemble_volume_term_explicit( const dealii::types::global_dof_index current_cell_index, const dealii::FEValues &fe_values_vol, const std::vector &soln_dof_indices_int, + const std::vector &/*metric_dof_indices*/, + const unsigned int /*poly_degree*/, + const unsigned int /*grid_degree*/, dealii::Vector &local_rhs_int_cell, const dealii::FEValues &/*fe_values_lagrange*/) { @@ -624,8 +626,8 @@ void DGWeak::assemble_volume_term_explicit( soln_grad_at_q[iquad][istate] += soln_coeff[idof] * fe_values_vol.shape_grad_component(idof, iquad, istate); } // Evaluate physical convective flux and source term - conv_phys_flux_at_q[iquad] = DGBaseState::pde_physics_double->convective_flux (soln_at_q[iquad]); - diss_phys_flux_at_q[iquad] = DGBaseState::pde_physics_double->dissipative_flux (soln_at_q[iquad], soln_grad_at_q[iquad], current_cell_index); + conv_phys_flux_at_q[iquad] = this->pde_physics_double->convective_flux (soln_at_q[iquad]); + diss_phys_flux_at_q[iquad] = this->pde_physics_double->dissipative_flux (soln_at_q[iquad], soln_grad_at_q[iquad], current_cell_index); if(this->all_parameters->artificial_dissipation_param.add_artificial_dissipation) { const ADArrayTensor1 artificial_diss_phys_flux_at_q = DGBaseState::artificial_dissip->calc_artificial_dissipation_flux (soln_at_q[iquad], soln_grad_at_q[iquad], artificial_diss_coeff); for (int istate=0; istate::assemble_volume_term_explicit( } if(this->all_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term) { const dealii::Point point = fe_values_vol.quadrature_point(iquad); - source_at_q[iquad] = DGBaseState::pde_physics_double->source_term (point, soln_at_q[iquad], current_cell_index); + source_at_q[iquad] = this->pde_physics_double->source_term (point, soln_at_q[iquad], this->current_time, current_cell_index); //std::array artificial_source_at_q = DGBaseState::pde_physics_double->artificial_source_term (artificial_diss_coeff, point, soln_at_q[iquad]); //for (int s=0;s::assemble_boundary_term_explicit( diss_soln_jump_int[s][d] = (diss_soln_num_flux[iquad][s] - soln_int[iquad][s]) * normal_int[d]; } } - diss_flux_jump_int[iquad] = DGBaseState::pde_physics_double->dissipative_flux (soln_int[iquad], diss_soln_jump_int, current_cell_index); + diss_flux_jump_int[iquad] = this->pde_physics_double->dissipative_flux (soln_int[iquad], diss_soln_jump_int, current_cell_index); if (this->all_parameters->artificial_dissipation_param.add_artificial_dissipation) { - const ADArrayTensor1 artificial_diss_flux_jump_int = DGBaseState::artificial_dissip->calc_artificial_dissipation_flux(soln_int[iquad], diss_soln_jump_int,artificial_diss_coeff); + const ADArrayTensor1 artificial_diss_flux_jump_int = this->artificial_dissip->calc_artificial_dissipation_flux(soln_int[iquad], diss_soln_jump_int,artificial_diss_coeff); for (int s=0; s::assemble_boundary_term_explicit( template void DGWeak::assemble_face_term_explicit( + const unsigned int /*iface*/, + const unsigned int /*neighbor_iface*/, typename dealii::DoFHandler::active_cell_iterator /*cell*/, const dealii::types::global_dof_index current_cell_index, const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int /*poly_degree*/, + const unsigned int /*grid_degree*/, const dealii::FEFaceValuesBase &fe_values_int, const dealii::FEFaceValuesBase &fe_values_ext, const real penalty, const std::vector &soln_dof_indices_int, const std::vector &soln_dof_indices_ext, + const std::vector &/*metric_dof_indices_int*/, + const std::vector &/*metric_dof_indices_ext*/, dealii::Vector &local_rhs_int_cell, dealii::Vector &local_rhs_ext_cell) { @@ -3632,7 +3640,7 @@ void DGWeak::assemble_volume_term( if (this->all_parameters->artificial_dissipation_param.add_artificial_dissipation) { ArrayTensor artificial_diss_phys_flux_at_q; //artificial_diss_phys_flux_at_q = physics.artificial_dissipative_flux (artificial_diss_coeff, soln_at_q[iquad], soln_grad_at_q[iquad]); - artificial_diss_phys_flux_at_q = DGBaseState::artificial_dissip->calc_artificial_dissipation_flux(soln_at_q[iquad], soln_grad_at_q[iquad],artificial_diss_coeff_at_q[iquad]); + artificial_diss_phys_flux_at_q = this->artificial_dissip->calc_artificial_dissipation_flux(soln_at_q[iquad], soln_grad_at_q[iquad],artificial_diss_coeff_at_q[iquad]); for (int s=0; s::assemble_volume_term( const int iaxis = fe_metric.system_to_component_index(idof).first; ad_point[iaxis] += coords_coeff[idof] * fe_metric.shape_value(idof,unit_quad_pts[iquad]); } - source_at_q[iquad] = physics.source_term (ad_point, soln_at_q[iquad], current_cell_index); + source_at_q[iquad] = physics.source_term (ad_point, soln_at_q[iquad], this->current_time, current_cell_index); //Array artificial_source_at_q = physics.artificial_source_term (artificial_diss_coeff, ad_point, soln_at_q[iquad]); //Array artificial_source_at_q = physics.artificial_source_term (artificial_diss_coeff_at_q[iquad], ad_point, soln_at_q[iquad]); //for (int s=0;s::assemble_volume_term( rhs[itest] = rhs[itest] + interpolation_operator[itest][iquad]* source_at_q[iquad][istate] * JxW_iquad; } } - dual_dot_residual += local_dual[itest]*rhs[itest]; - } - } #ifdef FADFAD @@ -4141,8 +4146,6 @@ void DGWeak::assemble_volume_term_derivatives( *(DGBaseState::pde_physics_double), compute_dRdW, compute_dRdX, compute_d2R); } - - return; } template @@ -4246,14 +4249,297 @@ void DGWeak::assemble_face_term_derivatives( local_rhs_ext_cell, compute_dRdW, compute_dRdX, compute_d2R); } - - return; } #endif + +template +void DGWeak::assemble_volume_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + const dealii::types::global_dof_index current_cell_index, + const std::vector &cell_dofs_indices, + const std::vector &metric_dof_indices, + const unsigned int poly_degree, + const unsigned int grid_degree, + OPERATOR::basis_functions &/*soln_basis*/, + OPERATOR::basis_functions &/*flux_basis*/, + OPERATOR::local_basis_stiffness &/*flux_basis_stiffness*/, + OPERATOR::metric_operators &/*metric_oper*/, + OPERATOR::mapping_shape_functions &/*mapping_basis*/, + std::array,dim> &/*mapping_support_points*/, + dealii::hp::FEValues &fe_values_collection_volume, + dealii::hp::FEValues &fe_values_collection_volume_lagrange, + const dealii::FESystem ¤t_fe_ref, + dealii::Vector &local_rhs_int_cell, + std::vector> &/*local_auxiliary_RHS*/, + const bool /*compute_auxiliary_right_hand_side*/, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R) +{ + // Current reference element related to this physical cell + const int i_fele = cell->active_fe_index(); + const int i_quad = i_fele; + const int i_mapp = 0; + fe_values_collection_volume.reinit (cell, i_quad, i_mapp, i_fele); + dealii::TriaIterator> cell_iterator = static_cast> > (cell); + fe_values_collection_volume_lagrange.reinit (cell_iterator, i_quad, i_mapp, i_fele); + + const dealii::FEValues &fe_values_volume = fe_values_collection_volume.get_present_fe_values(); + const dealii::FEValues &fe_values_lagrange = fe_values_collection_volume_lagrange.get_present_fe_values(); + //Note the explicit is called first to set the max_dt_cell to a non-zero value. + assemble_volume_term_explicit ( + cell, + current_cell_index, + fe_values_volume, + cell_dofs_indices, + metric_dof_indices, + poly_degree, grid_degree, + local_rhs_int_cell, + fe_values_lagrange); + //set current rhs to zero since the explicit call was just to set the max_dt_cell. + local_rhs_int_cell*=0.0; + + assemble_volume_term_derivatives ( + cell, + current_cell_index, + fe_values_volume, current_fe_ref, this->volume_quadrature_collection[i_quad], + metric_dof_indices, cell_dofs_indices, + local_rhs_int_cell, fe_values_lagrange, + compute_dRdW, compute_dRdX, compute_d2R); +} + +template +void DGWeak::assemble_boundary_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + const dealii::types::global_dof_index current_cell_index, + const unsigned int iface, + const unsigned int boundary_id, + const real penalty, + const std::vector &cell_dofs_indices, + const std::vector &metric_dof_indices, + const unsigned int /*poly_degree*/, + const unsigned int /*grid_degree*/, + OPERATOR::basis_functions &/*soln_basis*/, + OPERATOR::basis_functions &/*flux_basis*/, + OPERATOR::local_basis_stiffness &/*flux_basis_stiffness*/, + OPERATOR::metric_operators &/*metric_oper*/, + OPERATOR::mapping_shape_functions &/*mapping_basis*/, + std::array,dim> &/*mapping_support_points*/, + dealii::hp::FEFaceValues &fe_values_collection_face_int, + const dealii::FESystem ¤t_fe_ref, + dealii::Vector &local_rhs_int_cell, + std::vector> &/*local_auxiliary_RHS*/, + const bool /*compute_auxiliary_right_hand_side*/, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R) +{ + // Current reference element related to this physical cell + const int i_fele = cell->active_fe_index(); + const int i_quad = i_fele; + const int i_mapp = 0; + + fe_values_collection_face_int.reinit (cell, iface, i_quad, i_mapp, i_fele); + const dealii::FEFaceValues &fe_values_face_int = fe_values_collection_face_int.get_present_fe_values(); + const dealii::Quadrature face_quadrature = this->face_quadrature_collection[i_quad]; + assemble_boundary_term_derivatives ( + cell, + current_cell_index, + iface, boundary_id, fe_values_face_int, penalty, + current_fe_ref, face_quadrature, + metric_dof_indices, cell_dofs_indices, local_rhs_int_cell, + compute_dRdW, compute_dRdX, compute_d2R); +} + +template +void DGWeak::assemble_face_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + typename dealii::DoFHandler::active_cell_iterator neighbor_cell, + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int iface, + const unsigned int neighbor_iface, + const real penalty, + const std::vector ¤t_dofs_indices, + const std::vector &neighbor_dofs_indices, + const std::vector ¤t_metric_dofs_indices, + const std::vector &neighbor_metric_dofs_indices, + const unsigned int /*poly_degree_int*/, + const unsigned int /*poly_degree_ext*/, + const unsigned int /*grid_degree_int*/, + const unsigned int /*grid_degree_ext*/, + OPERATOR::basis_functions &/*soln_basis_int*/, + OPERATOR::basis_functions &/*soln_basis_ext*/, + OPERATOR::basis_functions &/*flux_basis_int*/, + OPERATOR::basis_functions &/*flux_basis_ext*/, + OPERATOR::local_basis_stiffness &/*flux_basis_stiffness*/, + OPERATOR::metric_operators &/*metric_oper_int*/, + OPERATOR::metric_operators &/*metric_oper_ext*/, + OPERATOR::mapping_shape_functions &/*mapping_basis*/, + std::array,dim> &/*mapping_support_points*/, + dealii::hp::FEFaceValues &fe_values_collection_face_int, + dealii::hp::FEFaceValues &fe_values_collection_face_ext, + dealii::Vector ¤t_cell_rhs, + dealii::Vector &neighbor_cell_rhs, + std::vector> &/*current_cell_rhs_aux*/, + dealii::LinearAlgebra::distributed::Vector &rhs, + std::array,dim> &/*rhs_aux*/, + const bool /*compute_auxiliary_right_hand_side*/, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R) +{ + // Current reference element related to this physical cell + const int i_fele = cell->active_fe_index(); + const int i_quad = i_fele; + const int i_mapp = 0; + const int i_fele_n = neighbor_cell->active_fe_index(), i_quad_n = i_fele_n, i_mapp_n = 0; + + fe_values_collection_face_int.reinit (cell, iface, i_quad, i_mapp, i_fele); + fe_values_collection_face_ext.reinit (neighbor_cell, neighbor_iface, i_quad_n, i_mapp_n, i_fele_n); + + //only need to compute fevalues for the weak form. + const dealii::FEFaceValues &fe_values_face_int = fe_values_collection_face_int.get_present_fe_values(); + const dealii::FEFaceValues &fe_values_face_ext = fe_values_collection_face_ext.get_present_fe_values(); + const dealii::Quadrature &used_face_quadrature = this->face_quadrature_collection[(i_quad_n > i_quad) ? i_quad_n : i_quad]; // Use larger quadrature order on the face + + std::pair face_subface_int = std::make_pair(iface, -1); + std::pair face_subface_ext = std::make_pair(neighbor_iface, -1); + const auto face_data_set_int = dealii::QProjector::DataSetDescriptor::face ( + dealii::ReferenceCell::get_hypercube(dim), + iface, + cell->face_orientation(iface), + cell->face_flip(iface), + cell->face_rotation(iface), + used_face_quadrature.size()); + const auto face_data_set_ext = dealii::QProjector::DataSetDescriptor::face ( + dealii::ReferenceCell::get_hypercube(dim), + neighbor_iface, + neighbor_cell->face_orientation(neighbor_iface), + neighbor_cell->face_flip(neighbor_iface), + neighbor_cell->face_rotation(neighbor_iface), + used_face_quadrature.size()); + + assemble_face_term_derivatives ( + cell, + current_cell_index, + neighbor_cell_index, + face_subface_int, face_subface_ext, + face_data_set_int, + face_data_set_ext, + fe_values_face_int, fe_values_face_ext, + penalty, + this->fe_collection[i_fele], this->fe_collection[i_fele_n], + used_face_quadrature, + current_metric_dofs_indices, neighbor_metric_dofs_indices, + current_dofs_indices, neighbor_dofs_indices, + current_cell_rhs, neighbor_cell_rhs, + compute_dRdW, compute_dRdX, compute_d2R); + + // Add local contribution from neighbor cell to global vector + const unsigned int n_dofs_neigh_cell = this->fe_collection[neighbor_cell->active_fe_index()].n_dofs_per_cell(); + for (unsigned int i=0; i +void DGWeak::assemble_subface_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + typename dealii::DoFHandler::active_cell_iterator neighbor_cell, + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int iface, + const unsigned int neighbor_iface, + const unsigned int neighbor_i_subface, + const real penalty, + const std::vector ¤t_dofs_indices, + const std::vector &neighbor_dofs_indices, + const std::vector ¤t_metric_dofs_indices, + const std::vector &neighbor_metric_dofs_indices, + const unsigned int /*poly_degree_int*/, + const unsigned int /*poly_degree_ext*/, + const unsigned int /*grid_degree_int*/, + const unsigned int /*grid_degree_ext*/, + OPERATOR::basis_functions &/*soln_basis_int*/, + OPERATOR::basis_functions &/*soln_basis_ext*/, + OPERATOR::basis_functions &/*flux_basis_int*/, + OPERATOR::basis_functions &/*flux_basis_ext*/, + OPERATOR::local_basis_stiffness &/*flux_basis_stiffness*/, + OPERATOR::metric_operators &/*metric_oper_int*/, + OPERATOR::metric_operators &/*metric_oper_ext*/, + OPERATOR::mapping_shape_functions &/*mapping_basis*/, + std::array,dim> &/*mapping_support_points*/, + dealii::hp::FEFaceValues &fe_values_collection_face_int, + dealii::hp::FESubfaceValues &fe_values_collection_subface, + dealii::Vector ¤t_cell_rhs, + dealii::Vector &neighbor_cell_rhs, + std::vector> &/*current_cell_rhs_aux*/, + dealii::LinearAlgebra::distributed::Vector &rhs, + std::array,dim> &/*rhs_aux*/, + const bool /*compute_auxiliary_right_hand_side*/, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R) +{ + // Current reference element related to this physical cell + const int i_fele = cell->active_fe_index(); + const int i_quad = i_fele; + const int i_mapp = 0; + const int i_fele_n = neighbor_cell->active_fe_index(), i_quad_n = i_fele_n, i_mapp_n = 0; + + fe_values_collection_face_int.reinit (cell, iface, i_quad, i_mapp, i_fele); + fe_values_collection_subface.reinit (neighbor_cell, neighbor_iface, neighbor_i_subface, i_quad_n, i_mapp_n, i_fele_n); + + const dealii::FEFaceValues &fe_values_face_int = fe_values_collection_face_int.get_present_fe_values(); + const dealii::FESubfaceValues &fe_values_face_ext = fe_values_collection_subface.get_present_fe_values(); + const dealii::Quadrature &used_face_quadrature = this->face_quadrature_collection[(i_quad_n > i_quad) ? i_quad_n : i_quad]; // Use larger quadrature order on the face + std::pair face_subface_int = std::make_pair(iface, -1); + std::pair face_subface_ext = std::make_pair(neighbor_iface, (int)neighbor_i_subface); + + const auto face_data_set_int = dealii::QProjector::DataSetDescriptor::face( + dealii::ReferenceCell::get_hypercube(dim), + iface, + cell->face_orientation(iface), + cell->face_flip(iface), + cell->face_rotation(iface), + used_face_quadrature.size()); + const auto face_data_set_ext = dealii::QProjector::DataSetDescriptor::subface ( + dealii::ReferenceCell::get_hypercube(dim), + neighbor_iface, + neighbor_i_subface, + neighbor_cell->face_orientation(neighbor_iface), + neighbor_cell->face_flip(neighbor_iface), + neighbor_cell->face_rotation(neighbor_iface), + used_face_quadrature.size(), + neighbor_cell->subface_case(neighbor_iface)); + + assemble_face_term_derivatives ( + cell, + current_cell_index, + neighbor_cell_index, + face_subface_int, face_subface_ext, + face_data_set_int, + face_data_set_ext, + fe_values_face_int, fe_values_face_ext, + penalty, + this->fe_collection[i_fele], this->fe_collection[i_fele_n], + used_face_quadrature, + current_metric_dofs_indices, neighbor_metric_dofs_indices, + current_dofs_indices, neighbor_dofs_indices, + current_cell_rhs, neighbor_cell_rhs, + compute_dRdW, compute_dRdX, compute_d2R); + + // Add local contribution from neighbor cell to global vector + const unsigned int n_dofs_neigh_cell = this->fe_collection[neighbor_cell->active_fe_index()].n_dofs_per_cell(); + for (unsigned int i=0; i +void DGWeak::assemble_auxiliary_residual () +{ + //Do Nothing. +} + // using default MeshType = Triangulation // 1D: dealii::Triangulation; -// OW: dealii::parallel::distributed::Triangulation; +// Otherwise: dealii::parallel::distributed::Triangulation; template class DGWeak >; template class DGWeak >; template class DGWeak >; @@ -4275,4 +4561,3 @@ template class DGWeak private: + /// Builds the necessary fe values and assembles volume residual. + void assemble_volume_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + const dealii::types::global_dof_index current_cell_index, + const std::vector &cell_dofs_indices, + const std::vector &metric_dof_indices, + const unsigned int poly_degree, + const unsigned int grid_degree, + OPERATOR::basis_functions &/*soln_basis*/, + OPERATOR::basis_functions &/*flux_basis*/, + OPERATOR::local_basis_stiffness &/*flux_basis_stiffness*/, + OPERATOR::metric_operators &/*metric_oper*/, + OPERATOR::mapping_shape_functions &/*mapping_basis*/, + std::array,dim> &/*mapping_support_points*/, + dealii::hp::FEValues &fe_values_collection_volume, + dealii::hp::FEValues &fe_values_collection_volume_lagrange, + const dealii::FESystem ¤t_fe_ref, + dealii::Vector &local_rhs_int_cell, + std::vector> &/*local_auxiliary_RHS*/, + const bool /*compute_auxiliary_right_hand_side*/, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R); + + /// Builds the necessary fe values and assembles boundary residual. + void assemble_boundary_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + const dealii::types::global_dof_index current_cell_index, + const unsigned int iface, + const unsigned int boundary_id, + const real penalty, + const std::vector &cell_dofs_indices, + const std::vector &metric_dof_indices, + const unsigned int poly_degree, + const unsigned int grid_degree, + OPERATOR::basis_functions &/*soln_basis*/, + OPERATOR::basis_functions &/*flux_basis*/, + OPERATOR::local_basis_stiffness &/*flux_basis_stiffness*/, + OPERATOR::metric_operators &/*metric_oper*/, + OPERATOR::mapping_shape_functions &/*mapping_basis*/, + std::array,dim> &/*mapping_support_points*/, + dealii::hp::FEFaceValues &fe_values_collection_face_int, + const dealii::FESystem ¤t_fe_ref, + dealii::Vector &local_rhs_int_cell, + std::vector> &/*local_auxiliary_RHS*/, + const bool /*compute_auxiliary_right_hand_side*/, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R); + + /// Builds the necessary fe values and assembles face residual. + void assemble_face_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + typename dealii::DoFHandler::active_cell_iterator neighbor_cell, + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int iface, + const unsigned int neighbor_iface, + const real penalty, + const std::vector ¤t_dofs_indices, + const std::vector &neighbor_dofs_indices, + const std::vector ¤t_metric_dofs_indices, + const std::vector &neighbor_metric_dofs_indices, + const unsigned int /*poly_degree_int*/, + const unsigned int /*poly_degree_ext*/, + const unsigned int /*grid_degree_int*/, + const unsigned int /*grid_degree_ext*/, + OPERATOR::basis_functions &/*soln_basis_int*/, + OPERATOR::basis_functions &/*soln_basis_ext*/, + OPERATOR::basis_functions &/*flux_basis_int*/, + OPERATOR::basis_functions &/*flux_basis_ext*/, + OPERATOR::local_basis_stiffness &/*flux_basis_stiffness*/, + OPERATOR::metric_operators &/*metric_oper_int*/, + OPERATOR::metric_operators &/*metric_oper_ext*/, + OPERATOR::mapping_shape_functions &/*mapping_basis*/, + std::array,dim> &/*mapping_support_points*/, + dealii::hp::FEFaceValues &fe_values_collection_face_int, + dealii::hp::FEFaceValues &fe_values_collection_face_ext, + dealii::Vector ¤t_cell_rhs, + dealii::Vector &neighbor_cell_rhs, + std::vector> &/*current_cell_rhs_aux*/, + dealii::LinearAlgebra::distributed::Vector &rhs, + std::array,dim> &/*rhs_aux*/, + const bool /*compute_auxiliary_right_hand_side*/, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R); + + /// Builds the necessary fe values and assembles subface residual. + void assemble_subface_term_and_build_operators( + typename dealii::DoFHandler::active_cell_iterator cell, + typename dealii::DoFHandler::active_cell_iterator neighbor_cell, + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int iface, + const unsigned int neighbor_iface, + const unsigned int neighbor_i_subface, + const real penalty, + const std::vector ¤t_dofs_indices, + const std::vector &neighbor_dofs_indices, + const std::vector ¤t_metric_dofs_indices, + const std::vector &neighbor_metric_dofs_indices, + const unsigned int /*poly_degree_int*/, + const unsigned int /*poly_degree_ext*/, + const unsigned int /*grid_degree_int*/, + const unsigned int /*grid_degree_ext*/, + OPERATOR::basis_functions &/*soln_basis_int*/, + OPERATOR::basis_functions &/*soln_basis_ext*/, + OPERATOR::basis_functions &/*flux_basis_int*/, + OPERATOR::basis_functions &/*flux_basis_ext*/, + OPERATOR::local_basis_stiffness &/*flux_basis_stiffness*/, + OPERATOR::metric_operators &/*metric_oper_int*/, + OPERATOR::metric_operators &/*metric_oper_ext*/, + OPERATOR::mapping_shape_functions &/*mapping_basis*/, + std::array,dim> &/*mapping_support_points*/, + dealii::hp::FEFaceValues &fe_values_collection_face_int, + dealii::hp::FESubfaceValues &fe_values_collection_subface, + dealii::Vector ¤t_cell_rhs, + dealii::Vector &neighbor_cell_rhs, + std::vector> &/*current_cell_rhs_aux*/, + dealii::LinearAlgebra::distributed::Vector &rhs, + std::array,dim> &/*rhs_aux*/, + const bool /*compute_auxiliary_right_hand_side*/, + const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R); + + /// Assembles the auxiliary equations' residuals and solves for the auxiliary variables. + void assemble_auxiliary_residual (); + /// Main function responsible for evaluating the integral over the cell volume and the specified derivatives. /** This function templates the solution and metric coefficients in order to possible AD the residual. */ @@ -243,7 +365,6 @@ class DGWeak : public DGBaseState const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R); private: - /// Evaluate the integral over the cell volume. /** Compute the right-hand side only. */ void assemble_volume_residual( @@ -305,15 +426,18 @@ class DGWeak : public DGBaseState dealii::Vector &local_rhs_ext_cell, const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R); - /// Evaluate the integral over the cell volume void assemble_volume_term_explicit( typename dealii::DoFHandler::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const dealii::FEValues &fe_values_volume, const std::vector ¤t_dofs_indices, + const std::vector &metric_dof_indices, + const unsigned int poly_degree, + const unsigned int grid_degree, dealii::Vector ¤t_cell_rhs, const dealii::FEValues &fe_values_lagrange); + /// Evaluate the integral over the cell edges that are on domain boundaries void assemble_boundary_term_explicit( typename dealii::DoFHandler::active_cell_iterator cell, @@ -323,22 +447,27 @@ class DGWeak : public DGBaseState const real penalty, const std::vector ¤t_dofs_indices, dealii::Vector ¤t_cell_rhs); + /// Evaluate the integral over the internal cell edges void assemble_face_term_explicit( + const unsigned int /*iface*/, + const unsigned int /*neighbor_iface*/, typename dealii::DoFHandler::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const dealii::types::global_dof_index neighbor_cell_index, + const unsigned int poly_degree, + const unsigned int grid_degree, const dealii::FEFaceValuesBase &fe_values_face_int, const dealii::FEFaceValuesBase &fe_values_face_ext, const real penalty, const std::vector ¤t_dofs_indices, const std::vector &neighbor_dofs_indices, + const std::vector &metric_dof_indices_int, + const std::vector &metric_dof_indices_ext, dealii::Vector ¤t_cell_rhs, dealii::Vector &neighbor_cell_rhs); - using DGBase::mpi_communicator; ///< MPI communicator using DGBase::pcout; ///< Parallel std::cout that only outputs on mpi_rank==0 - }; // end of DGWeak class } // PHiLiP namespace diff --git a/src/flow_solver/flow_solver.cpp b/src/flow_solver/flow_solver.cpp index 2fc171ca1..8755fbf9f 100644 --- a/src/flow_solver/flow_solver.cpp +++ b/src/flow_solver/flow_solver.cpp @@ -6,6 +6,7 @@ #include #include #include "reduced_order/pod_basis_offline.h" +#include "physics/initial_conditions/set_initial_condition.h" #include "mesh/mesh_adaptation.h" namespace PHiLiP { @@ -49,9 +50,6 @@ FlowSolver::FlowSolver( flow_solver_case->display_flow_solver_setup(dg); - dealii::LinearAlgebra::distributed::Vector solution_no_ghost; - solution_no_ghost.reinit(dg->locally_owned_dofs, this->mpi_communicator); - if(flow_solver_param.restart_computation_from_file == true) { if(dim == 1) { pcout << "Error: restart_computation_from_file is not possible for 1D. Set to false." << std::endl; @@ -71,15 +69,17 @@ FlowSolver::FlowSolver( // Note: Future development with hp-capabilities, see section "Note on usage with DoFHandler with hp-capabilities" // ----- Ref: https://www.dealii.org/current/doxygen/deal.II/classparallel_1_1distributed_1_1SolutionTransfer.html + dealii::LinearAlgebra::distributed::Vector solution_no_ghost; + solution_no_ghost.reinit(dg->locally_owned_dofs, this->mpi_communicator); dealii::parallel::distributed::SolutionTransfer, dealii::DoFHandler> solution_transfer(dg->dof_handler); solution_transfer.deserialize(solution_no_ghost); + dg->solution = solution_no_ghost; //< assignment #endif } else { // Initialize solution from initial_condition_function pcout << "Initializing solution with initial condition function... " << std::flush; - dealii::VectorTools::interpolate(dg->dof_handler, *(flow_solver_case->initial_condition_function), solution_no_ghost); + SetInitialCondition::set_initial_condition(flow_solver_case->initial_condition_function, dg, &all_param); } - dg->solution = solution_no_ghost; //< assignment dg->solution.update_ghost_values(); pcout << "done." << std::endl; ode_solver->allocate_ode_system(); diff --git a/src/flow_solver/flow_solver.h b/src/flow_solver/flow_solver.h index 36cf4d57c..8d50cede1 100644 --- a/src/flow_solver/flow_solver.h +++ b/src/flow_solver/flow_solver.h @@ -3,7 +3,6 @@ // for FlowSolver class: #include "flow_solver_cases/flow_solver_case_base.h" -#include "physics/initial_conditions/initial_condition.h" #include "physics/physics.h" #include "parameters/all_parameters.h" diff --git a/src/flow_solver/flow_solver_cases/1D_burgers_rewienski_snapshot.h b/src/flow_solver/flow_solver_cases/1D_burgers_rewienski_snapshot.h index fa1a29b1e..0627ad9cd 100644 --- a/src/flow_solver/flow_solver_cases/1D_burgers_rewienski_snapshot.h +++ b/src/flow_solver/flow_solver_cases/1D_burgers_rewienski_snapshot.h @@ -2,7 +2,7 @@ #define __1D_BURGERS_REWIENSKI_SNAPSHOT__ // for FlowSolver class: -#include "physics/initial_conditions/initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" #include "dg/dg.h" #include "physics/physics.h" #include "parameters/all_parameters.h" diff --git a/src/flow_solver/flow_solver_cases/1d_burgers_viscous_snapshot.h b/src/flow_solver/flow_solver_cases/1d_burgers_viscous_snapshot.h index 1bf5c4b05..8b3b4297c 100644 --- a/src/flow_solver/flow_solver_cases/1d_burgers_viscous_snapshot.h +++ b/src/flow_solver/flow_solver_cases/1d_burgers_viscous_snapshot.h @@ -2,7 +2,7 @@ #define __1D_BURGERS_VISCOUS_SNAPSHOT__ // for FlowSolver class: -#include "physics/initial_conditions/initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" #include "dg/dg.h" #include "physics/physics.h" #include "parameters/all_parameters.h" diff --git a/src/flow_solver/flow_solver_cases/flow_solver_case_base.cpp b/src/flow_solver/flow_solver_cases/flow_solver_case_base.cpp index feba895f4..b4a0844c3 100644 --- a/src/flow_solver/flow_solver_cases/flow_solver_case_base.cpp +++ b/src/flow_solver/flow_solver_cases/flow_solver_case_base.cpp @@ -108,8 +108,13 @@ void FlowSolverCaseBase::set_higher_order_grid(std::shared_ptr double FlowSolverCaseBase::get_constant_time_step(std::shared_ptr> /*dg*/) const { - pcout << "Using initial time step in ODE parameters." < 0.0) { + pcout << "Using constant time step in FlowSolver parameters." << std::endl; + return all_param.flow_solver_param.constant_time_step; + } else { + pcout << "Using initial time step in ODE parameters." < diff --git a/src/flow_solver/flow_solver_cases/flow_solver_case_base.h b/src/flow_solver/flow_solver_cases/flow_solver_case_base.h index 20a403a78..a5d2c7ab2 100644 --- a/src/flow_solver/flow_solver_cases/flow_solver_case_base.h +++ b/src/flow_solver/flow_solver_cases/flow_solver_case_base.h @@ -2,7 +2,7 @@ #define __FLOW_SOLVER_CASE_BASE__ // for FlowSolver class: -#include "physics/initial_conditions/initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" #include "dg/dg.h" #include "parameters/all_parameters.h" #include diff --git a/src/flow_solver/flow_solver_cases/naca0012.h b/src/flow_solver/flow_solver_cases/naca0012.h index 6e1ad1701..a8bdd37a0 100644 --- a/src/flow_solver/flow_solver_cases/naca0012.h +++ b/src/flow_solver/flow_solver_cases/naca0012.h @@ -2,7 +2,7 @@ #define __NACA0012__ // for FlowSolver class: -#include "physics/initial_conditions/initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" #include "dg/dg.h" #include "physics/physics.h" #include "parameters/all_parameters.h" @@ -46,4 +46,4 @@ class NACA0012 : public FlowSolverCaseBase } // FlowSolver namespace } // PHiLiP namespace -#endif \ No newline at end of file +#endif diff --git a/src/flow_solver/flow_solver_cases/periodic_turbulence.cpp b/src/flow_solver/flow_solver_cases/periodic_turbulence.cpp index 9cf4a1b55..62031a956 100644 --- a/src/flow_solver/flow_solver_cases/periodic_turbulence.cpp +++ b/src/flow_solver/flow_solver_cases/periodic_turbulence.cpp @@ -31,6 +31,7 @@ PeriodicTurbulence::PeriodicTurbulence(const PHiLiP::Parameters::Al // Flow case identifiers this->is_taylor_green_vortex = (flow_type == FlowCaseEnum::taylor_green_vortex); this->is_viscous_flow = (this->all_param.pde_type != Parameters::AllParameters::PartialDifferentialEquation::euler); + this->do_calculate_numerical_entropy= this->all_param.flow_solver_param.do_calculate_numerical_entropy; // Navier-Stokes object; create using dynamic_pointer_cast and the create_Physics factory PHiLiP::Parameters::AllParameters parameters_navier_stokes = this->all_param; @@ -60,10 +61,16 @@ void PeriodicTurbulence::display_additional_flow_case_specific_param template double PeriodicTurbulence::get_constant_time_step(std::shared_ptr> dg) const { - const unsigned int number_of_degrees_of_freedom_per_state = dg->dof_handler.n_dofs()/nstate; - const double approximate_grid_spacing = (this->domain_right-this->domain_left)/pow(number_of_degrees_of_freedom_per_state,(1.0/dim)); - const double constant_time_step = this->all_param.flow_solver_param.courant_friedrich_lewy_number * approximate_grid_spacing; - return constant_time_step; + if(this->all_param.flow_solver_param.constant_time_step > 0.0) { + const double constant_time_step = this->all_param.flow_solver_param.constant_time_step; + this->pcout << "- - Using constant time step in FlowSolver parameters: " << constant_time_step << std::endl; + return constant_time_step; + } else { + const unsigned int number_of_degrees_of_freedom_per_state = dg->dof_handler.n_dofs()/nstate; + const double approximate_grid_spacing = (this->domain_right-this->domain_left)/pow(number_of_degrees_of_freedom_per_state,(1.0/dim)); + const double constant_time_step = this->all_param.flow_solver_param.courant_friedrich_lewy_number * approximate_grid_spacing; + return constant_time_step; + } } template @@ -88,34 +95,128 @@ void PeriodicTurbulence::compute_and_update_integrated_quantities(D // Overintegrate the error to make sure there is not integration error in the error estimate int overintegrate = 10; + + // Set the quadrature of size dim and 1D for sum-factorization. dealii::QGauss quad_extra(dg.max_degree+1+overintegrate); - dealii::FEValues fe_values_extra(*(dg.high_order_grid->mapping_fe_field), dg.fe_collection[dg.max_degree], quad_extra, - dealii::update_values | dealii::update_gradients | dealii::update_JxW_values | dealii::update_quadrature_points); + dealii::QGauss<1> quad_extra_1D(dg.max_degree+1+overintegrate); - const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points; - std::array soln_at_q; - std::array,nstate> soln_grad_at_q; + const unsigned int n_quad_pts = quad_extra.size(); + const unsigned int grid_degree = dg.high_order_grid->fe_system.tensor_degree(); + const unsigned int poly_degree = dg.max_degree; + // Construct the basis functions and mapping shape functions. + OPERATOR::basis_functions soln_basis(1, poly_degree, grid_degree); + OPERATOR::mapping_shape_functions mapping_basis(1, poly_degree, grid_degree); + // Build basis function volume operator and gradient operator from 1D finite element for 1 state. + soln_basis.build_1D_volume_operator(dg.oneD_fe_collection_1state[poly_degree], quad_extra_1D); + soln_basis.build_1D_gradient_operator(dg.oneD_fe_collection_1state[poly_degree], quad_extra_1D); + // Build mapping shape functions operators using the oneD high_ordeR_grid finite element + mapping_basis.build_1D_shape_functions_at_grid_nodes(dg.high_order_grid->oneD_fe_system, dg.high_order_grid->oneD_grid_nodes); + mapping_basis.build_1D_shape_functions_at_flux_nodes(dg.high_order_grid->oneD_fe_system, quad_extra_1D, dg.oneD_face_quadrature); + const std::vector &quad_weights = quad_extra.get_weights(); + // If in the future we need the physical quadrature node location, turn these flags to true and the constructor will + // automatically compute it for you. Currently set to false as to not compute extra unused terms. + const bool store_vol_flux_nodes = false;//currently doesn't need the volume physical nodal position + const bool store_surf_flux_nodes = false;//currently doesn't need the surface physical nodal position - std::vector dofs_indices (fe_values_extra.dofs_per_cell); - for (auto cell : dg.dof_handler.active_cell_iterators()) { + const unsigned int n_dofs = dg.fe_collection[poly_degree].n_dofs_per_cell(); + const unsigned int n_shape_fns = n_dofs / nstate; + std::vector dofs_indices (n_dofs); + auto metric_cell = dg.high_order_grid->dof_handler_grid.begin_active(); + // Changed for loop to update metric_cell. + for (auto cell = dg.dof_handler.begin_active(); cell!= dg.dof_handler.end(); ++cell, ++metric_cell) { if (!cell->is_locally_owned()) continue; - fe_values_extra.reinit (cell); cell->get_dof_indices (dofs_indices); - for (unsigned int iquad=0; iquad &fe_metric = dg.high_order_grid->fe_system; + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + const unsigned int n_grid_nodes = n_metric_dofs / dim; + std::vector metric_dof_indices(n_metric_dofs); + metric_cell->get_dof_indices (metric_dof_indices); + std::array,dim> mapping_support_points; + for(int idim=0; idim &index_renumbering = dealii::FETools::hierarchic_to_lexicographic_numbering(grid_degree); + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const double val = (dg.high_order_grid->volume_nodes[metric_dof_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + const unsigned int ishape = fe_metric.system_to_component_index(idof).second; + const unsigned int igrid_node = index_renumbering[ishape]; + mapping_support_points[istate][igrid_node] = val; + } + // Construct the metric operators. + OPERATOR::metric_operators metric_oper(nstate, poly_degree, grid_degree, store_vol_flux_nodes, store_surf_flux_nodes); + // Build the metric terms to compute the gradient and volume node positions. + // This functions will compute the determinant of the metric Jacobian and metric cofactor matrix. + // If flags store_vol_flux_nodes and store_surf_flux_nodes set as true it will also compute the physical quadrature positions. + metric_oper.build_volume_metric_operators( + n_quad_pts, n_grid_nodes, + mapping_support_points, + mapping_basis, + dg.all_parameters->use_invariant_curl_form); - std::fill(soln_at_q.begin(), soln_at_q.end(), 0.0); - for (int s=0; s,nstate> soln_coeff; + for (unsigned int idof = 0; idof < n_dofs; ++idof) { + const unsigned int istate = dg.fe_collection[poly_degree].system_to_component_index(idof).first; + const unsigned int ishape = dg.fe_collection[poly_degree].system_to_component_index(idof).second; + if(ishape == 0){ + soln_coeff[istate].resize(n_shape_fns); + } + + soln_coeff[istate][ishape] = dg.solution(dofs_indices[idof]); + } + // Interpolate each state to the quadrature points using sum-factorization + // with the basis functions in each reference direction. + std::array,nstate> soln_at_q_vect; + std::array>,nstate> soln_grad_at_q_vect; + for(int istate=0; istate> ref_gradient_basis_fns_times_soln; + for(int idim=0; idim soln_at_q; + std::array,nstate> soln_grad_at_q; + // Extract solution and gradient in a way that the physics ca n use them. + for(int istate=0; istate qpoint = (fe_values_extra.quadrature_point(iquad)); std::array integrand_values; std::fill(integrand_values.begin(), integrand_values.end(), 0.0); @@ -125,7 +226,7 @@ void PeriodicTurbulence::compute_and_update_integrated_quantities(D integrand_values[IntegratedQuantitiesEnum::deviatoric_strain_rate_tensor_magnitude_sqr] = this->navier_stokes_physics->compute_deviatoric_strain_rate_tensor_magnitude_sqr(soln_at_q,soln_grad_at_q); for(int i_quantity=0; i_quantity::compute_and_update_integrated_quantities(D } } } + this->maximum_local_wave_speed = dealii::Utilities::MPI::max(this->maximum_local_wave_speed, this->mpi_communicator); // update integrated quantities for(int i_quantity=0; i_quantity::get_deviatoric_strain_rate_tensor_based_ return deviatoric_strain_rate_tensor_based_dissipation_rate; } +template +double PeriodicTurbulence::get_numerical_entropy(const std::shared_ptr > dg) const +{ + const double poly_degree = this->all_param.flow_solver_param.poly_degree; + dealii::LinearAlgebra::distributed::Vector mass_matrix_times_solution(dg->right_hand_side); + if(this->all_param.use_inverse_mass_on_the_fly){ + dg->apply_global_mass_matrix(dg->solution,mass_matrix_times_solution); + } else { + dg->global_mass_matrix.vmult( mass_matrix_times_solution, dg->solution); + } + + const unsigned int n_dofs_cell = dg->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size(); + const unsigned int n_shape_fns = n_dofs_cell / nstate; + // We have to project the vector of entropy variables because the mass matrix has an interpolation from solution nodes built into it. + OPERATOR::vol_projection_operator vol_projection(1, poly_degree, dg->max_grid_degree); + vol_projection.build_1D_volume_operator(dg->oneD_fe_collection_1state[poly_degree], dg->oneD_quadrature_collection[poly_degree]); + + OPERATOR::basis_functions soln_basis(1, poly_degree, dg->max_grid_degree); + soln_basis.build_1D_volume_operator(dg->oneD_fe_collection_1state[poly_degree], dg->oneD_quadrature_collection[poly_degree]); + + dealii::LinearAlgebra::distributed::Vector entropy_var_hat_global(dg->right_hand_side); + std::vector dofs_indices (n_dofs_cell); + + for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) { + if (!cell->is_locally_owned()) continue; + cell->get_dof_indices (dofs_indices); + + std::array,nstate> soln_coeff; + for(unsigned int idof=0; idoffe_collection[poly_degree].system_to_component_index(idof).first; + const unsigned int ishape = dg->fe_collection[poly_degree].system_to_component_index(idof).second; + if(ishape == 0) + soln_coeff[istate].resize(n_shape_fns); + soln_coeff[istate][ishape] = dg->solution(dofs_indices[idof]); + } + + std::array,nstate> soln_at_q; + for(int istate=0; istate,nstate> entropy_var_at_q; + for(unsigned int iquad=0; iquad soln_state; + for(int istate=0; istate entropy_var = this->navier_stokes_physics->compute_entropy_variables(soln_state); + + for(int istate=0; istate entropy_var_hat(n_shape_fns); + vol_projection.matrix_vector_mult_1D(entropy_var_at_q[istate], entropy_var_hat, + vol_projection.oneD_vol_operator); + + for(unsigned int ishape=0; ishape void PeriodicTurbulence::compute_unsteady_data_and_write_to_table( const unsigned int current_iteration, @@ -207,10 +386,14 @@ void PeriodicTurbulence::compute_unsteady_data_and_write_to_table( const double vorticity_based_dissipation_rate = this->get_vorticity_based_dissipation_rate(); const double pressure_dilatation_based_dissipation_rate = this->get_pressure_dilatation_based_dissipation_rate(); const double deviatoric_strain_rate_tensor_based_dissipation_rate = this->get_deviatoric_strain_rate_tensor_based_dissipation_rate(); + + double numerical_entropy = 0; + if (do_calculate_numerical_entropy) numerical_entropy = this->get_numerical_entropy(dg); if(this->mpi_rank==0) { // Add values to data table this->add_value_to_data_table(current_time,"time",unsteady_data_table); + if(do_calculate_numerical_entropy) this->add_value_to_data_table(numerical_entropy,"numerical_entropy",unsteady_data_table); this->add_value_to_data_table(integrated_kinetic_energy,"kinetic_energy",unsteady_data_table); this->add_value_to_data_table(integrated_enstrophy,"enstrophy",unsteady_data_table); if(is_viscous_flow) this->add_value_to_data_table(vorticity_based_dissipation_rate,"eps_vorticity",unsteady_data_table); @@ -226,8 +409,11 @@ void PeriodicTurbulence::compute_unsteady_data_and_write_to_table( << " Energy: " << integrated_kinetic_energy << " Enstrophy: " << integrated_enstrophy; if(is_viscous_flow) { - this->pcout << " eps_vorticity: " << vorticity_based_dissipation_rate - << " eps_p+eps_strain: " << (pressure_dilatation_based_dissipation_rate + deviatoric_strain_rate_tensor_based_dissipation_rate); + this->pcout << " eps_vorticity: " << vorticity_based_dissipation_rate + << " eps_p+eps_strain: " << (pressure_dilatation_based_dissipation_rate + deviatoric_strain_rate_tensor_based_dissipation_rate); + } + if(do_calculate_numerical_entropy){ + this->pcout << " Num. Entropy: " << std::setprecision(16) << numerical_entropy; } this->pcout << std::endl; diff --git a/src/flow_solver/flow_solver_cases/periodic_turbulence.h b/src/flow_solver/flow_solver_cases/periodic_turbulence.h index 9ed867725..dc8925f7d 100644 --- a/src/flow_solver/flow_solver_cases/periodic_turbulence.h +++ b/src/flow_solver/flow_solver_cases/periodic_turbulence.h @@ -62,6 +62,9 @@ class PeriodicTurbulence : public PeriodicCubeFlow * */ double get_deviatoric_strain_rate_tensor_based_dissipation_rate() const; + /// Calculate numerical entropy by matrix-vector product + double get_numerical_entropy(const std::shared_ptr > dg) const; + protected: /// Filename (with extension) for the unsteady data table const std::string unsteady_data_table_filename_with_extension; @@ -71,6 +74,7 @@ class PeriodicTurbulence : public PeriodicCubeFlow bool is_taylor_green_vortex = false; ///< Identifies if taylor green vortex case; initialized as false. bool is_viscous_flow = true; ///< Identifies if viscous flow; initialized as true. + bool do_calculate_numerical_entropy = false; ///< Identifies if numerical entropy should be calculated; initialized as false. /// Display additional more specific flow case parameters void display_additional_flow_case_specific_parameters() const override; @@ -104,4 +108,4 @@ class PeriodicTurbulence : public PeriodicCubeFlow } // FlowSolver namespace } // PHiLiP namespace -#endif \ No newline at end of file +#endif diff --git a/src/mesh/grids/CMakeLists.txt b/src/mesh/grids/CMakeLists.txt index a7cd84de6..6b3b7c1bd 100644 --- a/src/mesh/grids/CMakeLists.txt +++ b/src/mesh/grids/CMakeLists.txt @@ -7,6 +7,9 @@ set(GRIDS_SOURCE naca_airfoil_grid.cpp spline_channel.cpp straight_periodic_cube.cpp + nonsymmetric_curved_periodic_grid.cpp + nonsymmetric_curved_nonperiodic_grid.cpp + skew_symmetric_periodic_grid.cpp ) foreach(dim RANGE 1 3) diff --git a/src/mesh/grids/nonsymmetric_curved_nonperiodic_grid.cpp b/src/mesh/grids/nonsymmetric_curved_nonperiodic_grid.cpp new file mode 100644 index 000000000..32d9ceb7a --- /dev/null +++ b/src/mesh/grids/nonsymmetric_curved_nonperiodic_grid.cpp @@ -0,0 +1,244 @@ +#include +#include + +#include +#include "nonsymmetric_curved_nonperiodic_grid.hpp" + +namespace PHiLiP { +namespace Grids { + +template +void nonsymmetric_curved_nonperiodic_grid( + TriangulationType &grid, + const unsigned int n_subdivisions) +{ + + const double left = -1.0; + const double right = 1.0; + const bool colorize = true; + dealii::GridGenerator::hyper_cube (grid, left, right, colorize); + + std::vector > matched_pairs; + if (dim>=1) { + matched_pairs.clear(); + dealii::GridTools::collect_periodic_faces(grid,0,1,0,matched_pairs); + grid.add_periodicity(matched_pairs); + } + if (dim>=2) { + matched_pairs.clear(); + dealii::GridTools::collect_periodic_faces(grid,2,3,1,matched_pairs); + grid.add_periodicity(matched_pairs); + } + if (dim>=3) { + matched_pairs.clear(); + dealii::GridTools::collect_periodic_faces(grid,4,5,2,matched_pairs); + grid.add_periodicity(matched_pairs); + } + + grid.refine_global(n_subdivisions); + + const NonsymmetricCurvedNonPerGridManifold periodic_nonsym_curved_manifold; + + dealii::GridTools::transform ( + [&periodic_nonsym_curved_manifold](const dealii::Point &chart_point) { + return periodic_nonsym_curved_manifold.push_forward(chart_point);}, grid); + + // Assign a manifold to have curved geometry + unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true + grid.reset_all_manifolds(); + grid.set_all_manifold_ids(manifold_id); + grid.set_manifold ( manifold_id, periodic_nonsym_curved_manifold ); + + //grid.reset_all_manifolds(); + //for (auto cell = grid.begin_active(); cell != grid.end(); ++cell) { + // // Set a dummy boundary ID + // cell->set_material_id(9002); + // for (unsigned int face=0; face::faces_per_cell; ++face) { + // if (cell->face(face)->at_boundary()) cell->face(face)->set_boundary_id (1000); + // } + //} +} + +template +template +dealii::Point NonsymmetricCurvedNonPerGridManifold::mapping(const dealii::Point &p) const +{ + dealii::Point q = p; + + if (dim == 1){ + q[dim-1] = p[dim-1] + cos(2.0 * pi* p[dim-1]); + } + if (dim == 2){ + //non sym transform + q[dim-2] =p[dim-2] + beta*std::cos(pi/2.0 * p[dim-2]) * std::cos(3.0 * pi/2.0 * p[dim-1]); + q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); + + } + if(dim==3){ + //periodic non sym + double temp1 = alpha*(std::sin(pi * p[0]) * std::sin(pi * p[1])); + double temp2 = alpha*exp(1.0-p[1])*(std::sin(pi * p[0]) * std::sin(pi* p[1])); + q[0] =p[0] + temp1; + q[1] =p[1] + temp2; + q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * q[0]) + std::sin(2.0 * pi * q[1])); + + } + + return q; +} + +template +dealii::Point NonsymmetricCurvedNonPerGridManifold::pull_back(const dealii::Point &space_point) const { + + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim function(dim); + dealii::FullMatrix derivative(dim); + int flag =0; + while(flag != dim){ + //set function value + if(dim==1){ + function[0] = x_ref[0] - x_phys[0] +cos(2.0*pi*x_ref[0]); + } + if(dim==2){ + function[0] = x_ref[0] - x_phys[0] +beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function[1] = x_ref[1] - x_phys[1] +beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + + } + else if(dim==3){ + double temp1 = alpha*(std::sin(pi * x_ref[0]) * std::sin(pi * x_ref[1])); + double temp2 = alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) * std::sin(pi* x_ref[1])); + function[0] = x_ref[0] - x_phys[0] + temp1; + function[1] = x_ref[1] - x_phys[1] + temp2; + function[2] = x_ref[2] - x_phys[2] +1.0/20.0*( std::sin(2.0 * pi * (temp1+x_ref[0])) + std::sin(2.0 * pi * (temp2+x_ref[1]))); + } + //set derivative value + if(dim==1){ + derivative[0][0] = 1.0 - 2.0*pi*sin(2.0*pi*x_ref[0]); + } + if(dim==2){ + derivative[0][0] = 1.0 - beta* pi/2.0 * std::sin(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + derivative[0][1] = - beta*3.0 *pi/2.0 * std::cos(pi/2.0*x_ref[0])*std::sin(3.0*pi/2.0*x_ref[1]); + + derivative[1][0] = beta*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + derivative[1][1] = 1.0 -beta*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1]); + + } + else if(dim==3){ + derivative[0][0] = 1.0 + alpha*pi*std::cos(pi*x_ref[0])*std::sin(pi*x_ref[1]); + derivative[0][1] = alpha*pi*std::sin(pi*x_ref[0])*std::cos(pi*x_ref[1]); + derivative[0][2] = 0.0; + + derivative[1][0] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[0])*std::sin(pi*x_ref[1]); + derivative[1][1] = 1.0 -alpha*exp(1.0-x_ref[1])*(std::sin(pi*x_ref[0])+std::sin(pi*x_ref[1])) +alpha*exp(1.0-x_ref[1])*(std::sin(pi*x_ref[0])+std::cos(pi*x_ref[1])); + derivative[1][2] = 0.0; + double xtemp = x_ref[0] + alpha*std::sin(pi*x_ref[0])*std::sin(pi*x_ref[1]); + double ytemp = x_ref[1] + alpha*exp(1.0-x_ref[1])*std::sin(pi*x_ref[0])*std::sin(pi*x_ref[1]); + derivative[2][0] = 1.0/10.0*pi*(std::cos(2.0*pi*xtemp)*derivative[0][0] + std::cos(2.0*pi*ytemp)*derivative[1][0]); + derivative[2][1] = 1.0/10.0*pi*(std::cos(2.0*pi*xtemp)*derivative[0][1] + std::cos(2.0*pi*ytemp)*derivative[1][1]); + derivative[2][2] = 1.0; + } + + dealii::FullMatrix Jacobian_inv(dim); + Jacobian_inv.invert(derivative); + dealii::Vector Newton_Step(dim); + Jacobian_inv.vmult(Newton_Step, function); + for(int idim=0; idim function_check(dim); + if(dim==1){ + function_check[0] = x_ref[0] + cos(2.0*pi*x_ref[0]); + } + if(dim==2){ + function_check[0] = x_ref[0] + beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function_check[1] = x_ref[1] + beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else if(dim==3){ + double temp1 = alpha*(std::sin(pi * x_ref[0]) * std::sin(pi * x_ref[1])); + double temp2 = alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) * std::sin(pi* x_ref[1])); + function_check[0] = x_ref[0] + temp1; + function_check[1] = x_ref[1] + temp2; + function_check[2] = x_ref[2] +1.0/20.0*( std::sin(2.0 * pi * (temp1+x_ref[0])) + std::sin(2.0 * pi * (temp2+x_ref[1]))); + } + std::vector error(dim); + for(int idim=0; idim 1e-13) { + std::cout << "Large error " << error[0] << std::endl; + for(int idim=0;idim +dealii::Point NonsymmetricCurvedNonPerGridManifold::push_forward(const dealii::Point &chart_point) const +{ + return mapping(chart_point); +} + +template +dealii::DerivativeForm<1,chartdim,spacedim> NonsymmetricCurvedNonPerGridManifold::push_forward_gradient(const dealii::Point &chart_point) const +{ + dealii::DerivativeForm<1, dim, dim> dphys_dref; + dealii::Point x_ref; + for(int idim=0; idim +std::unique_ptr > NonsymmetricCurvedNonPerGridManifold::clone() const +{ + return std::make_unique>(); +} + +template void nonsymmetric_curved_nonperiodic_grid<1, dealii::Triangulation<1> > (dealii::Triangulation<1> &grid, const unsigned int n_subdivisions); +template void nonsymmetric_curved_nonperiodic_grid<2, dealii::parallel::distributed::Triangulation<2>> (dealii::parallel::distributed::Triangulation<2> &grid, const unsigned int n_subdivisions); +template void nonsymmetric_curved_nonperiodic_grid<3, dealii::parallel::distributed::Triangulation<3>> (dealii::parallel::distributed::Triangulation<3> &grid, const unsigned int n_subdivisions); + +} // namespace Grids +} // namespace PHiLiP + diff --git a/src/mesh/grids/nonsymmetric_curved_nonperiodic_grid.hpp b/src/mesh/grids/nonsymmetric_curved_nonperiodic_grid.hpp new file mode 100644 index 000000000..12cdab859 --- /dev/null +++ b/src/mesh/grids/nonsymmetric_curved_nonperiodic_grid.hpp @@ -0,0 +1,44 @@ +#ifndef __NONSYMMETRIC_CURVED_NONPERIODIC_GRID_H__ +#define __NONSYMMETRIC_CURVED_NONPERIODIC_GRID_H__ + +#include +#include + +namespace PHiLiP { +namespace Grids { + +/// Create a nonsymmetric grid with an associated nonlinear manifold. +/*The mapping for the 2D and 3D grids follows from Cicchino, Alexander, et al. "Provably Stable Flux Reconstruction High-Order Methods on Curvilinear Elements.". The 2D is Eq. (66), and the 3D is Eq. (64). +*/ +template +void nonsymmetric_curved_nonperiodic_grid( + TriangulationType &grid, + const unsigned int n_subdivisions); + +/// Nonsymmetric manifold. +template +class NonsymmetricCurvedNonPerGridManifold: public dealii::ChartManifold { +protected: + static constexpr double pi = atan(1) * 4.0; ///< PI. + const double beta = 1.0/10.0; + const double alpha = 1.0/10.0; +public: + /// Constructor. + NonsymmetricCurvedNonPerGridManifold() + : dealii::ChartManifold() + {}; + template + dealii::Point mapping(const dealii::Point &chart_point) const; ///< Templated mapping from square to the nonsymmetric warping. + + virtual dealii::Point pull_back(const dealii::Point &space_point) const override; ///< See dealii::Manifold. + virtual dealii::Point push_forward(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + virtual dealii::DerivativeForm<1,chartdim,spacedim> push_forward_gradient(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + + virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. + +}; + +} // namespace Grids +} // namespace PHiLiP +#endif + diff --git a/src/mesh/grids/nonsymmetric_curved_periodic_grid.cpp b/src/mesh/grids/nonsymmetric_curved_periodic_grid.cpp new file mode 100644 index 000000000..fcffd5ee7 --- /dev/null +++ b/src/mesh/grids/nonsymmetric_curved_periodic_grid.cpp @@ -0,0 +1,245 @@ +#include +#include + +#include +#include "nonsymmetric_curved_periodic_grid.hpp" + +namespace PHiLiP { +namespace Grids { + +template +void nonsymmetric_curved_grid( + TriangulationType &grid, + const unsigned int n_subdivisions) +{ + double left, right; + if constexpr(dim==3){ + left = 0.0; + right = 2.0 * atan(1) * 4.0; + } else{ + left = -1.0; + right = 1.0; + } + // const double left = 0.0; + // const double right = 2.0 * atan(1) * 4.0; + // const double left = -1.0; + // const double right = 1.0; + const bool colorize = true; + dealii::GridGenerator::hyper_cube (grid, left, right, colorize); + + std::vector > matched_pairs; + if constexpr(dim>=1) { + matched_pairs.clear(); + dealii::GridTools::collect_periodic_faces(grid,0,1,0,matched_pairs); + grid.add_periodicity(matched_pairs); + } + if constexpr(dim>=2) { + matched_pairs.clear(); + dealii::GridTools::collect_periodic_faces(grid,2,3,1,matched_pairs); + grid.add_periodicity(matched_pairs); + } + if constexpr(dim>=3) { + matched_pairs.clear(); + dealii::GridTools::collect_periodic_faces(grid,4,5,2,matched_pairs); + grid.add_periodicity(matched_pairs); + } + + grid.refine_global(n_subdivisions); + + const NonsymmetricCurvedGridManifold periodic_nonsym_curved_manifold; + + dealii::GridTools::transform ( + [&periodic_nonsym_curved_manifold](const dealii::Point &chart_point) { + return periodic_nonsym_curved_manifold.push_forward(chart_point);}, grid); + + // Assign a manifold to have curved geometry + unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true + grid.reset_all_manifolds(); + grid.set_all_manifold_ids(manifold_id); + grid.set_manifold ( manifold_id, periodic_nonsym_curved_manifold ); + + // grid.reset_all_manifolds(); + // for (auto cell = grid.begin_active(); cell != grid.end(); ++cell) { + // // Set a dummy boundary ID + // cell->set_material_id(9002); + // for (unsigned int face=0; face::faces_per_cell; ++face) { + // if (cell->face(face)->at_boundary()) cell->face(face)->set_boundary_id (1000); + // } + // } +} + +template +template +dealii::Point NonsymmetricCurvedGridManifold +::mapping(const dealii::Point &p) const +{ + dealii::Point q = p; + + if constexpr(dim == 1) { + q[dim-1] = p[dim-1] + cos(2.0 * pi* p[dim-1]); + } + if constexpr(dim == 2) { + //non sym transform + q[dim-2] =p[dim-2] + beta*std::cos(pi/2.0 * p[dim-2]) * std::cos(3.0 * pi/2.0 * p[dim-1]); + q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); + } + if constexpr(dim==3) { + // periodic non sym + q[0] = p[0] + beta * std::sin(p[0]) * std::sin(p[1]) * std::sin(2.0*p[2]); + q[1] = p[1] + beta * std::sin(4.0*p[0]) * std::sin(p[1]) * std::sin(3.0*p[2]); + q[2] = p[2] + beta * std::sin(2.0*p[0]) * std::sin(5.0*p[1]) * std::sin(p[2]); + } + + return q; +} + +template +dealii::Point NonsymmetricCurvedGridManifold +::pull_back(const dealii::Point &space_point) const +{ + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim function(dim); + dealii::FullMatrix derivative(dim); + + int flag =0; + while(flag != dim){ + //set function value + if constexpr(dim==1) { + function[0] = x_ref[0] - x_phys[0] +cos(2.0*pi*x_ref[0]); + } + if constexpr(dim==2) { + function[0] = x_ref[0] - x_phys[0] +beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function[1] = x_ref[1] - x_phys[1] +beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else if constexpr(dim==3) { + function[0] = x_ref[0] - x_phys[0] + beta * std::sin(x_ref[0]) * std::sin(x_ref[1]) * std::sin(2.0*x_ref[2]); + function[1] = x_ref[1] - x_phys[1] + beta * std::sin(4.0*x_ref[0]) * std::sin(x_ref[1]) * std::sin(3.0*x_ref[2]); + function[2] = x_ref[2] - x_phys[2] + beta * std::sin(2.0*x_ref[0]) * std::sin(5.0*x_ref[1]) * std::sin(x_ref[2]); + } + //set derivative value + if constexpr(dim==1) { + derivative[0][0] = 1.0 - 2.0*pi*sin(2.0*pi*x_ref[0]); + } + if constexpr(dim==2) { + derivative[0][0] = 1.0 - beta* pi/2.0 * std::sin(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + derivative[0][1] = - beta*3.0 *pi/2.0 * std::cos(pi/2.0*x_ref[0])*std::sin(3.0*pi/2.0*x_ref[1]); + + derivative[1][0] = beta*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + derivative[1][1] = 1.0 -beta*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1]); + } + else if constexpr(dim==3) { + derivative[0][0] = 1.0 + beta * std::cos(x_ref[0]) * std::sin(x_ref[1]) * std::sin(2.0*x_ref[2]); + derivative[0][1] = beta * std::sin(x_ref[0]) * std::cos(x_ref[1]) * std::sin(2.0*x_ref[2]); + derivative[0][2] = beta * std::sin(x_ref[0]) * std::sin(x_ref[1]) * 2.0* std::cos(2.0*x_ref[2]); + + derivative[1][0] = beta * 4.0 * std::cos(4.0*x_ref[0]) * std::sin(x_ref[1]) * std::sin(3.0*x_ref[2]); + derivative[1][1] = 1.0 + beta * std::sin(4.0*x_ref[0]) * std::cos(x_ref[1]) * std::sin(3.0*x_ref[2]); + derivative[1][2] = beta * std::sin(4.0*x_ref[0]) * std::sin(x_ref[1]) * 3.0 * std::cos(3.0*x_ref[2]); + + derivative[2][0] = beta * 2.0 * std::cos(2.0*x_ref[0])*std::sin(5.0*x_ref[1])*std::sin(x_ref[2]); + derivative[2][1] = beta * std::sin(2.0*x_ref[0])*5.0*std::cos(5.0*x_ref[1]) *std::sin(x_ref[2]); + derivative[2][2] = 1.0 + beta * std::sin(2.0*x_ref[0])*std::sin(5.0*x_ref[1]) * std::cos(x_ref[2]); + } + + dealii::FullMatrix Jacobian_inv(dim); + Jacobian_inv.invert(derivative); + dealii::Vector Newton_Step(dim); + Jacobian_inv.vmult(Newton_Step, function); + for(int idim=0; idim function_check(dim); + if constexpr(dim==1) { + function_check[0] = x_ref[0] + cos(2.0*pi*x_ref[0]); + } + if constexpr(dim==2) { + function_check[0] = x_ref[0] + beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function_check[1] = x_ref[1] + beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else if constexpr(dim==3) { + function_check[0] = x_ref[0] + beta * std::sin(x_ref[0]) * std::sin(x_ref[1]) * std::sin(2.0*x_ref[2]); + function_check[1] = x_ref[1] + beta * std::sin(4.0*x_ref[0]) * std::sin(x_ref[1]) * std::sin(3.0*x_ref[2]); + function_check[2] = x_ref[2] + beta * std::sin(2.0*x_ref[0]) * std::sin(5.0*x_ref[1]) * std::sin(x_ref[2]); + } + std::vector error(dim); + for(int idim=0; idim 1e-13) { + std::cout << "Large error " << error[0] << std::endl; + for(int idim=0;idim +dealii::Point NonsymmetricCurvedGridManifold +::push_forward(const dealii::Point &chart_point) const +{ + return mapping(chart_point); +} + +template +dealii::DerivativeForm<1,chartdim,spacedim> NonsymmetricCurvedGridManifold +::push_forward_gradient(const dealii::Point &chart_point) const +{ + dealii::DerivativeForm<1, dim, dim> dphys_dref; + + dealii::Point x_ref; + for(int idim=0; idim +std::unique_ptr > NonsymmetricCurvedGridManifold +::clone() const +{ + return std::make_unique>(); +} + +template void nonsymmetric_curved_grid<1, dealii::Triangulation<1> > (dealii::Triangulation<1> &grid, const unsigned int n_subdivisions); +template void nonsymmetric_curved_grid<2, dealii::parallel::distributed::Triangulation<2>> (dealii::parallel::distributed::Triangulation<2> &grid, const unsigned int n_subdivisions); +template void nonsymmetric_curved_grid<3, dealii::parallel::distributed::Triangulation<3>> (dealii::parallel::distributed::Triangulation<3> &grid, const unsigned int n_subdivisions); + +} // namespace Grids +} // namespace PHiLiP + diff --git a/src/mesh/grids/nonsymmetric_curved_periodic_grid.hpp b/src/mesh/grids/nonsymmetric_curved_periodic_grid.hpp new file mode 100644 index 000000000..f78b32846 --- /dev/null +++ b/src/mesh/grids/nonsymmetric_curved_periodic_grid.hpp @@ -0,0 +1,45 @@ +#ifndef __NONSYMMETRIC_CURVED_PERIODIC_GRID_H__ +#define __NONSYMMETRIC_CURVED_PERIODIC_GRID_H__ + +#include +#include + +namespace PHiLiP { +namespace Grids { + +/// Create a nonsymmetric grid with an associated nonlinear manifold. +/** The mapping for the 2D and 3D grids follows from + * Cicchino, Alexander, et al. "Provably Stable Flux Reconstruction High-Order Methods on Curvilinear Elements.". + * The 2D is Eq. (66), and the 3D is Eq. (64). +*/ +template +void nonsymmetric_curved_grid( + TriangulationType &grid, + const unsigned int n_subdivisions); + +/// Nonsymmetric manifold. +template +class NonsymmetricCurvedGridManifold : public dealii::ChartManifold { +protected: + static constexpr double pi = atan(1) * 4.0; ///< PI. + const double beta = 1.0/10.0; + +public: + /// Constructor. + NonsymmetricCurvedGridManifold() + : dealii::ChartManifold() {}; + + /// Templated mapping from square to the nonsymmetric warping. + template + dealii::Point mapping(const dealii::Point &chart_point) const; + + virtual dealii::Point pull_back(const dealii::Point &space_point) const override; ///< See dealii::Manifold. + virtual dealii::Point push_forward(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + virtual dealii::DerivativeForm<1,chartdim,spacedim> push_forward_gradient(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. +}; + +} // namespace Grids +} // namespace PHiLiP +#endif + diff --git a/src/mesh/grids/skew_symmetric_periodic_grid.cpp b/src/mesh/grids/skew_symmetric_periodic_grid.cpp new file mode 100644 index 000000000..0a444be5e --- /dev/null +++ b/src/mesh/grids/skew_symmetric_periodic_grid.cpp @@ -0,0 +1,199 @@ +#include +#include + +#include +#include "skew_symmetric_periodic_grid.hpp" + +namespace PHiLiP { +namespace Grids { + +template +void skewsymmetric_curved_grid( + TriangulationType &grid, + const unsigned int n_subdivisions) +{ + + const double left = 0.0; + const double right = 1.0; + const bool colorize = true; + dealii::GridGenerator::hyper_cube (grid, left, right, colorize); + + std::vector > matched_pairs; + if (dim>=1) { + matched_pairs.clear(); + dealii::GridTools::collect_periodic_faces(grid,0,1,0,matched_pairs); + grid.add_periodicity(matched_pairs); + } + if (dim>=2) { + matched_pairs.clear(); + dealii::GridTools::collect_periodic_faces(grid,2,3,1,matched_pairs); + grid.add_periodicity(matched_pairs); + } + if (dim>=3) { + matched_pairs.clear(); + dealii::GridTools::collect_periodic_faces(grid,4,5,2,matched_pairs); + grid.add_periodicity(matched_pairs); + } + + grid.refine_global(n_subdivisions); + + const SkewsymmetricCurvedGridManifold periodic_skewsym_curved_manifold; + + dealii::GridTools::transform ( + [&periodic_skewsym_curved_manifold](const dealii::Point &chart_point) { + return periodic_skewsym_curved_manifold.push_forward(chart_point);}, grid); + + // Assign a manifold to have curved geometry + unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true + grid.reset_all_manifolds(); + grid.set_all_manifold_ids(manifold_id); + grid.set_manifold ( manifold_id, periodic_skewsym_curved_manifold ); + +} + +template +template +dealii::Point SkewsymmetricCurvedGridManifold +::mapping(const dealii::Point &p) const +{ + dealii::Point q = p; + + if constexpr(dim >= 2){ + /* Ref: G. Gassner, "A Skew-Symmetric Discontinuous Galerkin Spectral Element + Discretization and Its Relation to SBP-SAT Finite Difference Methods", + SIAM J. Sci. Comput., 2013. */ + q[0] =p[0] - 0.1*std::sin(2.0*pi*p[1]); + q[1] =p[1] + 0.1*std::sin(2.0*pi*p[0]); + } + + return q; +} + +template +dealii::Point SkewsymmetricCurvedGridManifold +::pull_back(const dealii::Point &space_point) const +{ + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim function(dim); + dealii::FullMatrix derivative(dim); + int flag =0; + while(flag != dim){ + dealii::Point new_point = mapping(x_ref); + for (int d=0; d=1){ + derivative[0][0] = 1.0; + } + if constexpr(dim>=2){ + derivative[0][0] = 1.0; + derivative[0][1] = - 2.0 * pi * 0.1*std::cos(2.0 * pi * x_ref[1]); + + derivative[1][0] = 2.0 * pi * 0.1*std::cos(2.0 * pi * x_ref[0]); + derivative[1][1] = 1.0; + } + else if constexpr(dim>=3){ + derivative[0][2] = 0.0; + derivative[1][2] = 0.0; + derivative[2][0] = 0.0; + derivative[2][1] = 0.0; + derivative[2][2] = 1.0; + } + + dealii::FullMatrix Jacobian_inv(dim); + Jacobian_inv.invert(derivative); + dealii::Vector Newton_Step(dim); + Jacobian_inv.vmult(Newton_Step, function); + for(int idim=0; idim function_check(dim); + if constexpr(dim==1){ + function_check[0] = x_ref[0]; + } + if constexpr(dim>=2){ + function_check[0] = x_ref[0] - 0.1*std::sin(2.0*pi*x_ref[1]); + function_check[1] = x_ref[1] + 0.1*std::sin(2.0*pi*x_ref[0]); + } + else if constexpr(dim>=3){ + function_check[2] = x_ref[2] + x_ref[2]; + } + + std::vector error(dim); + for(int idim=0; idim 1e-13) { + std::cout << "Large error " << error[0] << std::endl; + for(int idim=0;idim +dealii::Point SkewsymmetricCurvedGridManifold::push_forward(const dealii::Point &chart_point) const +{ + return mapping(chart_point); +} + +template +dealii::DerivativeForm<1,chartdim,spacedim> SkewsymmetricCurvedGridManifold::push_forward_gradient(const dealii::Point &chart_point) const +{ + dealii::DerivativeForm<1, dim, dim> dphys_dref; + dealii::Point x_ref; + for(int idim=0; idim +std::unique_ptr > SkewsymmetricCurvedGridManifold::clone() const +{ + return std::make_unique>(); +} + +template void skewsymmetric_curved_grid<1, dealii::Triangulation<1> > (dealii::Triangulation<1> &grid, const unsigned int n_subdivisions); +template void skewsymmetric_curved_grid<2, dealii::parallel::distributed::Triangulation<2>> (dealii::parallel::distributed::Triangulation<2> &grid, const unsigned int n_subdivisions); +template void skewsymmetric_curved_grid<3, dealii::parallel::distributed::Triangulation<3>> (dealii::parallel::distributed::Triangulation<3> &grid, const unsigned int n_subdivisions); + +} // namespace Grids +} // namespace PHiLiP + diff --git a/src/mesh/grids/skew_symmetric_periodic_grid.hpp b/src/mesh/grids/skew_symmetric_periodic_grid.hpp new file mode 100644 index 000000000..bd40f1050 --- /dev/null +++ b/src/mesh/grids/skew_symmetric_periodic_grid.hpp @@ -0,0 +1,45 @@ +#ifndef __SKEWSYMMETRIC_CURVED_PERIODIC_GRID_H__ +#define __SKEWSYMMETRIC_CURVED_PERIODIC_GRID_H__ + +#include +#include + +namespace PHiLiP { +namespace Grids { + +/// Create a skew-symmetric grid with an associated nonlinear manifold. +/** The mapping for the 2D grid follows from + * Hennemann, Sebastian, et al. "A provably entropy stable subcell shock capturing + * approach for high order split form DG for the compressible Euler equations." + * Journal of Computational Physics 426 (2021): 109935. Eq.(59). +*/ +template +void skewsymmetric_curved_grid( + TriangulationType &grid, + const unsigned int n_subdivisions); + +/// Skew-symmetric manifold. +template +class SkewsymmetricCurvedGridManifold : public dealii::ChartManifold +{ +protected: + static constexpr double pi = atan(1) * 4.0; ///< PI. + +public: + /// Constructor. + SkewsymmetricCurvedGridManifold() + : dealii::ChartManifold() {}; + + /// Templated mapping from square to the nonsymmetric warping. + template + dealii::Point mapping(const dealii::Point &chart_point) const; + + virtual dealii::Point pull_back(const dealii::Point &space_point) const override; ///< See dealii::Manifold. + virtual dealii::Point push_forward(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + virtual dealii::DerivativeForm<1,chartdim,spacedim> push_forward_gradient(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. +}; + +} // namespace Grids +} // namespace PHiLiP +#endif diff --git a/src/mesh/grids/straight_periodic_cube.cpp b/src/mesh/grids/straight_periodic_cube.cpp index 7bbcd4fc5..a53b858a4 100644 --- a/src/mesh/grids/straight_periodic_cube.cpp +++ b/src/mesh/grids/straight_periodic_cube.cpp @@ -22,6 +22,20 @@ void straight_periodic_cube(std::shared_ptr &grid, // Get equivalent number of refinements const int number_of_refinements = log(number_of_cells_per_direction)/log(2); + // Check that number_of_cells_per_direction is a power of 2 if number_of_refinements is non-zero + if(number_of_refinements >= 0){ + int val_check = number_of_cells_per_direction; + while(val_check > 1) { + if(val_check % 2 == 0) val_check /= 2; + else{ + std::cout << "ERROR: number_of_cells_per_direction is not a power of 2. " + << "Current value is " << number_of_cells_per_direction << ". " + << "Change value of number_of_grid_elements_per_dimension in .prm file." << std::endl; + std::abort(); + } + } + } + // Definition for each type of grid std::string grid_type_string; const bool colorize = true; diff --git a/src/mesh/high_order_grid.cpp b/src/mesh/high_order_grid.cpp index d287f58e0..1fad54bf3 100644 --- a/src/mesh/high_order_grid.cpp +++ b/src/mesh/high_order_grid.cpp @@ -52,12 +52,17 @@ unsigned int HighOrderGrid::nth_ref template HighOrderGrid::HighOrderGrid( const unsigned int max_degree, - const std::shared_ptr triangulation_input) + const std::shared_ptr triangulation_input, + const bool output_high_order_grid) : max_degree(max_degree) , triangulation(triangulation_input) , dof_handler_grid(*triangulation) , fe_q(max_degree) // The grid must be at least p1. A p0 solution required a p1 grid. , fe_system(dealii::FESystem(fe_q,dim)) // The grid must be at least p1. A p0 solution required a p1 grid. + , oneD_fe_q(max_degree) + , oneD_fe_system(oneD_fe_q,1) + , oneD_grid_nodes(max_degree+1) + , dim_grid_nodes(max_degree+1) , solution_transfer(dof_handler_grid) , mpi_communicator(MPI_COMM_WORLD) , pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(mpi_communicator)==0) @@ -71,7 +76,7 @@ HighOrderGrid::HighOrderGrid( // Do nothing // Assume stuff will be read later on. } else { - initialize_with_triangulation_manifold(); + initialize_with_triangulation_manifold(output_high_order_grid); } } diff --git a/src/mesh/high_order_grid.h b/src/mesh/high_order_grid.h index e38a57374..c057e84ab 100644 --- a/src/mesh/high_order_grid.h +++ b/src/mesh/high_order_grid.h @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -133,7 +134,8 @@ class HighOrderGrid /// Principal constructor that will call delegated constructor. HighOrderGrid( const unsigned int max_degree, - const std::shared_ptr triangulation_input); + const std::shared_ptr triangulation_input, + const bool output_high_order_grid=true); /// Reinitialize high_order_grid after a change in triangulation void reinit(); @@ -148,7 +150,7 @@ class HighOrderGrid void ensure_conforming_mesh(); /// Sets the volume_nodes to the interpolated position of the Manifold associated to the triangulation. - void initialize_with_triangulation_manifold(const bool output_mesh = false); + void initialize_with_triangulation_manifold(const bool output_mesh = true); /// Needed to allocate the correct number of volume_nodes when initializing and after the mesh is refined void allocate(); @@ -372,6 +374,22 @@ class HighOrderGrid const dealii::FE_Q fe_q; /// Using system of polynomials to represent the x, y, and z directions. const dealii::FESystem fe_system; + /// Use oneD Lagrange polynomial to represent the spatial location. + /** We use FE_DGQ instead of FE_Q for this because DGQ orders in a tensor-product way, + * with x running fastest, then y, and z the slowest; whereas FE_Q order by the vertices + * first, then proceeds to do the edges, then volume. We need it in a tensor product + * indexing in order to use sum-factorization on the mapping support nodes.
+ * Lastly, since it is collocated on the 1D Gauss-Legendre-Lobatto quadrature set, + * the nodal location recovers the FE_Q nodeal set, but indexed in a way we can use + * sum-factorization on. + */ + const dealii::FE_DGQ<1> oneD_fe_q; + /// One-dimensional fe system for each direction. + const dealii::FESystem<1> oneD_fe_system; + /// One Dimensional grid nodes in reference space. + const dealii::QGaussLobatto<1> oneD_grid_nodes; + /// Dim-Dimensional grid nodes in reference space. + const dealii::QGaussLobatto dim_grid_nodes; /// MappingFEField that will provide the polynomial-based grid. diff --git a/src/numerical_flux/CMakeLists.txt b/src/numerical_flux/CMakeLists.txt index f0f46123e..74ec2826f 100644 --- a/src/numerical_flux/CMakeLists.txt +++ b/src/numerical_flux/CMakeLists.txt @@ -1,9 +1,7 @@ set(FLUX_SOURCE viscous_numerical_flux.cpp convective_numerical_flux.cpp - split_form_numerical_flux.cpp - numerical_flux_factory.cpp - ) + numerical_flux_factory.cpp) foreach(dim RANGE 1 3) # Output library @@ -20,8 +18,6 @@ foreach(dim RANGE 1 3) DEAL_II_SETUP_TARGET(${NumericalFluxLib}) endif() - unset(NumericalFluxLib) unset(PhysicsLib) - endforeach() diff --git a/src/numerical_flux/convective_numerical_flux.cpp b/src/numerical_flux/convective_numerical_flux.cpp index de6265e7d..c972591c3 100644 --- a/src/numerical_flux/convective_numerical_flux.cpp +++ b/src/numerical_flux/convective_numerical_flux.cpp @@ -20,16 +20,109 @@ std::array array_average( return array_average; } - template -NumericalFluxConvective::~NumericalFluxConvective() {} +NumericalFluxConvective::NumericalFluxConvective( + std::unique_ptr< BaselineNumericalFluxConvective > baseline_input, + std::unique_ptr< RiemannSolverDissipation > riemann_solver_dissipation_input) + : baseline(std::move(baseline_input)) + , riemann_solver_dissipation(std::move(riemann_solver_dissipation_input)) +{ } template -std::array LaxFriedrichs +std::array NumericalFluxConvective ::evaluate_flux ( const std::array &soln_int, const std::array &soln_ext, const dealii::Tensor<1,dim,real> &normal_int) const +{ + // baseline flux (without upwind dissipation) + const std::array baseline_flux_dot_n + = this->baseline->evaluate_flux(soln_int, soln_ext, normal_int); + + // Riemann solver dissipation + const std::array riemann_solver_dissipation_dot_n + = this->riemann_solver_dissipation->evaluate_riemann_solver_dissipation(soln_int, soln_ext, normal_int); + + // convective numerical flux: sum of baseline and Riemann solver dissipation term + std::array numerical_flux_dot_n; + for (int s=0; s +LaxFriedrichs::LaxFriedrichs( + std::shared_ptr> physics_input) + : NumericalFluxConvective( + std::make_unique< CentralBaselineNumericalFluxConvective > (physics_input), + std::make_unique< LaxFriedrichsRiemannSolverDissipation > (physics_input)) +{} + +template +RoePike::RoePike( + std::shared_ptr> physics_input) + : NumericalFluxConvective( + std::make_unique< CentralBaselineNumericalFluxConvective > (physics_input), + std::make_unique< RoePikeRiemannSolverDissipation > (physics_input)) +{} + +template +L2Roe::L2Roe( + std::shared_ptr> physics_input) + : NumericalFluxConvective( + std::make_unique< CentralBaselineNumericalFluxConvective > (physics_input), + std::make_unique< L2RoeRiemannSolverDissipation > (physics_input)) +{} + +template +Central::Central( + std::shared_ptr> physics_input) + : NumericalFluxConvective( + std::make_unique< CentralBaselineNumericalFluxConvective > (physics_input), + std::make_unique< ZeroRiemannSolverDissipation > ()) +{} + +template +EntropyConserving::EntropyConserving( + std::shared_ptr> physics_input) + : NumericalFluxConvective( + std::make_unique< EntropyConservingBaselineNumericalFluxConvective > (physics_input), + std::make_unique< ZeroRiemannSolverDissipation > ()) +{} + +template +EntropyConservingWithLaxFriedrichsDissipation::EntropyConservingWithLaxFriedrichsDissipation( + std::shared_ptr> physics_input) + : NumericalFluxConvective( + std::make_unique< EntropyConservingBaselineNumericalFluxConvective > (physics_input), + std::make_unique< LaxFriedrichsRiemannSolverDissipation > (physics_input)) +{} + +template +EntropyConservingWithRoeDissipation::EntropyConservingWithRoeDissipation( + std::shared_ptr> physics_input) + : NumericalFluxConvective( + std::make_unique< EntropyConservingBaselineNumericalFluxConvective > (physics_input), + std::make_unique< RoePikeRiemannSolverDissipation > (physics_input)) +{} + +template +EntropyConservingWithL2RoeDissipation::EntropyConservingWithL2RoeDissipation( + std::shared_ptr> physics_input) + : NumericalFluxConvective( + std::make_unique< EntropyConservingBaselineNumericalFluxConvective > (physics_input), + std::make_unique< L2RoeRiemannSolverDissipation > (physics_input)) +{} + +template +BaselineNumericalFluxConvective::~BaselineNumericalFluxConvective() {} + +template +std::array CentralBaselineNumericalFluxConvective::evaluate_flux( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &normal_int) const { using RealArrayVector = std::array,nstate>; RealArrayVector conv_phys_flux_int; @@ -38,7 +131,6 @@ ::evaluate_flux ( conv_phys_flux_int = pde_physics->convective_flux (soln_int); conv_phys_flux_ext = pde_physics->convective_flux (soln_ext); - //RealArrayVector flux_avg = array_average> (conv_phys_flux_int, conv_phys_flux_ext); RealArrayVector flux_avg; for (int s=0; s numerical_flux_dot_n; + for (int s=0; s +std::array EntropyConservingBaselineNumericalFluxConvective::evaluate_flux( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &normal_int) const +{ + using RealArrayVector = std::array,nstate>; + RealArrayVector conv_phys_split_flux; + + conv_phys_split_flux = pde_physics->convective_numerical_split_flux (soln_int,soln_ext); + + // Scalar dissipation + std::array numerical_flux_dot_n; + for (int s=0; s +RiemannSolverDissipation::~RiemannSolverDissipation() {} + +template +std::array ZeroRiemannSolverDissipation +::evaluate_riemann_solver_dissipation ( + const std::array &/*soln_int*/, + const std::array &/*soln_ext*/, + const dealii::Tensor<1,dim,real> &/*normal_int*/) const +{ + // zero upwind dissipation + std::array numerical_flux_dot_n; + numerical_flux_dot_n.fill(0.0); + return numerical_flux_dot_n; +} + +template +std::array LaxFriedrichsRiemannSolverDissipation +::evaluate_riemann_solver_dissipation ( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &/*normal_int*/) const +{ const real conv_max_eig_int = pde_physics->max_convective_eigenvalue(soln_int); const real conv_max_eig_ext = pde_physics->max_convective_eigenvalue(soln_ext); // Replaced the std::max with an if-statement for the AD to work properly. @@ -61,19 +210,14 @@ ::evaluate_flux ( // Scalar dissipation std::array numerical_flux_dot_n; for (int s=0; s -void RoePike +void RoePikeRiemannSolverDissipation ::evaluate_entropy_fix ( const std::array &eig_L, const std::array &eig_R, @@ -92,7 +236,7 @@ ::evaluate_entropy_fix ( } template -void RoePike +void RoePikeRiemannSolverDissipation ::evaluate_additional_modifications ( const std::array &/*soln_int*/, const std::array &/*soln_ext*/, @@ -106,7 +250,7 @@ ::evaluate_additional_modifications ( } template -void L2Roe +void L2RoeRiemannSolverDissipation ::evaluate_shock_indicator ( const std::array &eig_L, const std::array &eig_R, @@ -130,7 +274,7 @@ ::evaluate_shock_indicator ( } template -void L2Roe +void L2RoeRiemannSolverDissipation ::evaluate_entropy_fix ( const std::array &eig_L, const std::array &eig_R, @@ -160,7 +304,7 @@ ::evaluate_entropy_fix ( } template -void L2Roe +void L2RoeRiemannSolverDissipation ::evaluate_additional_modifications ( const std::array &soln_int, const std::array &soln_ext, @@ -189,8 +333,8 @@ ::evaluate_additional_modifications ( } template -std::array RoeBase -::evaluate_flux ( +std::array RoeBaseRiemannSolverDissipation +::evaluate_riemann_solver_dissipation ( const std::array &soln_int, const std::array &soln_ext, const dealii::Tensor<1,dim,real> &normal_int) const @@ -291,10 +435,6 @@ ::evaluate_flux ( // Evaluate additional modifications to the Roe-Pike scheme (if applicable) evaluate_additional_modifications (soln_int, soln_ext, eig_L, eig_R, dVn, dVt); - // Physical fluxes - const std::array normal_flux_int = euler_physics->convective_normal_flux (soln_int, normal_int); - const std::array normal_flux_ext = euler_physics->convective_normal_flux (soln_ext, normal_int); - // Product of eigenvalues and wave strengths real coeff[4]; coeff[0] = eig_ravg[0]*(dp-density_ravg*sound_ravg*dVn)/(2.0*sound2_ravg); @@ -337,7 +477,7 @@ ::evaluate_flux ( std::array numerical_flux_dot_n; for (int s=0; s; template class NumericalFluxConvective; template class NumericalFluxConvective; template class NumericalFluxConvective; - template class NumericalFluxConvective; template class NumericalFluxConvective; template class NumericalFluxConvective; @@ -397,12 +536,6 @@ template class LaxFriedrichs; template class LaxFriedrichs; template class LaxFriedrichs; -template class RoeBase; -template class RoeBase; -template class RoeBase; -template class RoeBase; -template class RoeBase; - template class RoePike; template class RoePike; template class RoePike; @@ -414,6 +547,269 @@ template class L2Roe; template class L2Roe; template class L2Roe; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; +template class Central; + +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; +template class EntropyConserving; + +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; +template class EntropyConservingWithLaxFriedrichsDissipation; + +template class EntropyConservingWithRoeDissipation; +template class EntropyConservingWithRoeDissipation; +template class EntropyConservingWithRoeDissipation; +template class EntropyConservingWithRoeDissipation; +template class EntropyConservingWithRoeDissipation; + +template class EntropyConservingWithL2RoeDissipation; +template class EntropyConservingWithL2RoeDissipation; +template class EntropyConservingWithL2RoeDissipation; +template class EntropyConservingWithL2RoeDissipation; +template class EntropyConservingWithL2RoeDissipation; + +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; +template class BaselineNumericalFluxConvective; + +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; +template class CentralBaselineNumericalFluxConvective; + +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; +template class EntropyConservingBaselineNumericalFluxConvective; + +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; +template class RiemannSolverDissipation; + +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; +template class ZeroRiemannSolverDissipation; + +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; +template class LaxFriedrichsRiemannSolverDissipation; + +template class RoeBaseRiemannSolverDissipation; +template class RoeBaseRiemannSolverDissipation; +template class RoeBaseRiemannSolverDissipation; +template class RoeBaseRiemannSolverDissipation; +template class RoeBaseRiemannSolverDissipation; + +template class RoePikeRiemannSolverDissipation; +template class RoePikeRiemannSolverDissipation; +template class RoePikeRiemannSolverDissipation; +template class RoePikeRiemannSolverDissipation; +template class RoePikeRiemannSolverDissipation; + +template class L2RoeRiemannSolverDissipation; +template class L2RoeRiemannSolverDissipation; +template class L2RoeRiemannSolverDissipation; +template class L2RoeRiemannSolverDissipation; +template class L2RoeRiemannSolverDissipation; } // NumericalFlux namespace } // PHiLiP namespace diff --git a/src/numerical_flux/convective_numerical_flux.hpp b/src/numerical_flux/convective_numerical_flux.hpp index 4d7145a56..b90fe5899 100644 --- a/src/numerical_flux/convective_numerical_flux.hpp +++ b/src/numerical_flux/convective_numerical_flux.hpp @@ -1,5 +1,5 @@ -#ifndef __NUMERICAL_FLUX__ -#define __NUMERICAL_FLUX__ +#ifndef __CONVECTIVE_NUMERICAL_FLUX__ +#define __CONVECTIVE_NUMERICAL_FLUX__ #include #include "physics/physics.h" @@ -10,162 +10,355 @@ namespace NumericalFlux { using AllParam = Parameters::AllParameters; -/// Base class of numerical flux associated with convection +/// Base class of baseline numerical flux (without upwind term) associated with convection template -class NumericalFluxConvective +class BaselineNumericalFluxConvective { public: -virtual ~NumericalFluxConvective() = 0; ///< Base class destructor required for abstract classes. + virtual ~BaselineNumericalFluxConvective() = 0; ///< Base class destructor required for abstract classes. + + /// Returns the convective numerical flux at an interface. + virtual std::array evaluate_flux ( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &normal1) const = 0; +}; -/// Returns the convective numerical flux at an interface. -virtual std::array evaluate_flux ( - const std::array &soln_int, - const std::array &soln_ext, - const dealii::Tensor<1,dim,real> &normal1) const = 0; +/// Central numerical flux. Derived from BaselineNumericalFluxConvective. +template +class CentralBaselineNumericalFluxConvective : public BaselineNumericalFluxConvective +{ +public: + /// Constructor + CentralBaselineNumericalFluxConvective(std::shared_ptr > physics_input) + : pde_physics(physics_input) {}; + + /// Destructor + ~CentralBaselineNumericalFluxConvective() {}; + /// Returns the convective numerical flux at an interface. + std::array evaluate_flux ( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &normal1) const; + +protected: + /// Numerical flux requires physics to evaluate convective flux + const std::shared_ptr < Physics::PhysicsBase > pde_physics; }; +/// Entropy Conserving Numerical Flux. Derived from BaselineNumericalFluxConvective. +template +class EntropyConservingBaselineNumericalFluxConvective : public BaselineNumericalFluxConvective +{ +public: + /// Constructor + EntropyConservingBaselineNumericalFluxConvective(std::shared_ptr > physics_input) + : pde_physics(physics_input) {}; + + /// Destructor + ~EntropyConservingBaselineNumericalFluxConvective() {}; -/// Lax-Friedrichs numerical flux. Derived from NumericalFluxConvective. + /// Returns the convective numerical flux at an interface. + std::array evaluate_flux ( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &normal1) const; + +protected: + /// Numerical flux requires physics to evaluate split form convective flux. + const std::shared_ptr < Physics::PhysicsBase > pde_physics; +}; + +/// Base class of Riemann solver dissipation (i.e. upwind-term) for numerical flux associated with convection template -class LaxFriedrichs: public NumericalFluxConvective +class RiemannSolverDissipation { public: + virtual ~RiemannSolverDissipation() = 0; ///< Base class destructor required for abstract classes. + + /// Returns the convective numerical flux at an interface. + virtual std::array evaluate_riemann_solver_dissipation ( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &normal1) const = 0; +}; -/// Constructor -LaxFriedrichs(std::shared_ptr > physics_input) -: -pde_physics(physics_input) -{}; -/// Destructor -~LaxFriedrichs() {}; +/// Zero Riemann solver dissipation. Derived from RiemannSolverDissipation. +template +class ZeroRiemannSolverDissipation : public RiemannSolverDissipation +{ +public: + /// Constructor + ZeroRiemannSolverDissipation() {}; + + /// Destructor + ~ZeroRiemannSolverDissipation() {}; -/// Returns the Lax-Friedrichs convective numerical flux at an interface. -std::array evaluate_flux ( - const std::array &soln_int, - const std::array &soln_ext, - const dealii::Tensor<1,dim,real> &normal1) const; + /// Returns zeros + std::array evaluate_riemann_solver_dissipation ( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &normal1) const; +}; -protected: -/// Numerical flux requires physics to evaluate convective eigenvalues. -const std::shared_ptr < Physics::PhysicsBase > pde_physics; +/// Lax-Friedrichs Riemann solver dissipation. Derived from RiemannSolverDissipation. +template +class LaxFriedrichsRiemannSolverDissipation : public RiemannSolverDissipation +{ +public: + /// Constructor + LaxFriedrichsRiemannSolverDissipation(std::shared_ptr > physics_input) + : pde_physics(physics_input) {}; + /// Destructor + ~LaxFriedrichsRiemannSolverDissipation() {}; + /// Returns the Lax-Friedrichs convective numerical flux at an interface. + std::array evaluate_riemann_solver_dissipation ( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &normal1) const; + +protected: + /// Numerical flux requires physics to evaluate convective eigenvalues. + const std::shared_ptr < Physics::PhysicsBase > pde_physics; }; -/// Base class of Roe (Roe-Pike) flux with entropy fix. Derived from NumericalFluxConvective. +/// Base class of Roe (Roe-Pike) flux with entropy fix. Derived from RiemannSolverDissipation. template -class RoeBase: public NumericalFluxConvective +class RoeBaseRiemannSolverDissipation : public RiemannSolverDissipation { protected: - /// Numerical flux requires physics to evaluate convective eigenvalues. - const std::shared_ptr < Physics::Euler > euler_physics; - -public: - /// Constructor - RoeBase(std::shared_ptr > physics_input) - : - euler_physics(std::dynamic_pointer_cast>(physics_input)) - {}; - - /// Destructor - ~RoeBase() {}; - - /// Virtual member function for evaluating the entropy fix for a Roe-Pike flux. - virtual void evaluate_entropy_fix ( - const std::array &eig_L, - const std::array &eig_R, - std::array &eig_RoeAvg, - const real vel2_ravg, - const real sound_ravg) const = 0; - - /// Virtual member function for evaluating additional modifications/corrections for a Roe-Pike flux. - virtual void evaluate_additional_modifications ( - const std::array &soln_int, - const std::array &soln_ext, - const std::array &eig_L, - const std::array &eig_R, - real &dV_normal, - dealii::Tensor<1,dim,real> &dV_tangent) const = 0; - - /// Returns the convective flux at an interface - /// --- See Blazek 2015, p.103-105 - /// --- Note: Modified calculation of alpha_{3,4} to use - /// dVt (jump in tangential velocities); - /// expressions are equivalent. - std::array evaluate_flux ( - const std::array &soln_int, - const std::array &soln_ext, - const dealii::Tensor<1,dim,real> &normal1) const; + /// Numerical flux requires physics to evaluate convective eigenvalues. + const std::shared_ptr < Physics::Euler > euler_physics; + +public: + /// Constructor + RoeBaseRiemannSolverDissipation(std::shared_ptr > physics_input) + : euler_physics(std::dynamic_pointer_cast>(physics_input)) {}; + + /// Destructor + ~RoeBaseRiemannSolverDissipation() {}; + + /// Virtual member function for evaluating the entropy fix for a Roe-Pike flux. + virtual void evaluate_entropy_fix ( + const std::array &eig_L, + const std::array &eig_R, + std::array &eig_RoeAvg, + const real vel2_ravg, + const real sound_ravg) const = 0; + + /// Virtual member function for evaluating additional modifications/corrections for a Roe-Pike flux. + virtual void evaluate_additional_modifications ( + const std::array &soln_int, + const std::array &soln_ext, + const std::array &eig_L, + const std::array &eig_R, + real &dV_normal, + dealii::Tensor<1,dim,real> &dV_tangent) const = 0; + + /// Returns the convective flux at an interface + /// --- See Blazek 2015, p.103-105 + /// --- Note: Modified calculation of alpha_{3,4} to use + /// dVt (jump in tangential velocities); + /// expressions are equivalent. + std::array evaluate_riemann_solver_dissipation ( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &normal1) const; }; /// RoePike flux with entropy fix. Derived from RoeBase. template -class RoePike: public RoeBase +class RoePikeRiemannSolverDissipation : public RoeBaseRiemannSolverDissipation { public: - /// Constructor - RoePike(std::shared_ptr > physics_input) - : RoeBase(physics_input){} + /// Constructor + RoePikeRiemannSolverDissipation(std::shared_ptr > physics_input) + : RoeBaseRiemannSolverDissipation(physics_input){}; - /// Evaluates the entropy fix of Harten - /// --- See Blazek 2015, p.103-105 - void evaluate_entropy_fix( - const std::array &eig_L, - const std::array &eig_R, - std::array &eig_RoeAvg, - const real vel2_ravg, - const real sound_ravg) const; + /// Evaluates the entropy fix of Harten + /// --- See Blazek 2015, p.103-105 + void evaluate_entropy_fix( + const std::array &eig_L, + const std::array &eig_R, + std::array &eig_RoeAvg, + const real vel2_ravg, + const real sound_ravg) const; - /// Empty function. No additional modifications for the Roe-Pike scheme. - void evaluate_additional_modifications( - const std::array &soln_int, - const std::array &soln_ext, - const std::array &eig_L, - const std::array &eig_R, - real &dV_normal, - dealii::Tensor<1,dim,real> &dV_tangent) const; + /// Empty function. No additional modifications for the Roe-Pike scheme. + void evaluate_additional_modifications( + const std::array &soln_int, + const std::array &soln_ext, + const std::array &eig_L, + const std::array &eig_R, + real &dV_normal, + dealii::Tensor<1,dim,real> &dV_tangent) const; }; /// L2Roe flux with entropy fix. Derived from RoeBase. /// --- Reference: Osswald et al. (2016 L2Roe) template -class L2Roe: public RoeBase -{ -public: - /// Constructor - L2Roe(std::shared_ptr > physics_input) - : RoeBase(physics_input){} - - /// (1) Van Leer et al. (1989 Sonic) entropy fix for acoustic waves (i.e. i=1,5) - /// (2) For waves (i=2,3,4) --> Entropy fix of Liou (2000 Mass) - /// --- See p.74 of Osswald et al. (2016 L2Roe) - void evaluate_entropy_fix( - const std::array &eig_L, - const std::array &eig_R, - std::array &eig_RoeAvg, - const real vel2_ravg, - const real sound_ravg) const; - - /// Osswald's two modifications to Roe-Pike scheme --> L2Roe - /// --- Scale jump in (1) normal and (2) tangential velocities using a blending factor - void evaluate_additional_modifications( - const std::array &soln_int, - const std::array &soln_ext, - const std::array &eig_L, - const std::array &eig_R, - real &dV_normal, - dealii::Tensor<1,dim,real> &dV_tangent) const; +class L2RoeRiemannSolverDissipation : public RoeBaseRiemannSolverDissipation +{ +public: + /// Constructor + L2RoeRiemannSolverDissipation(std::shared_ptr > physics_input) + : RoeBaseRiemannSolverDissipation(physics_input){}; + + /// (1) Van Leer et al. (1989 Sonic) entropy fix for acoustic waves (i.e. i=1,5) + /// (2) For waves (i=2,3,4) --> Entropy fix of Liou (2000 Mass) + /// --- See p.74 of Osswald et al. (2016 L2Roe) + void evaluate_entropy_fix( + const std::array &eig_L, + const std::array &eig_R, + std::array &eig_RoeAvg, + const real vel2_ravg, + const real sound_ravg) const; + + /// Osswald's two modifications to Roe-Pike scheme --> L2Roe + /// --- Scale jump in (1) normal and (2) tangential velocities using a blending factor + void evaluate_additional_modifications( + const std::array &soln_int, + const std::array &soln_ext, + const std::array &eig_L, + const std::array &eig_R, + real &dV_normal, + dealii::Tensor<1,dim,real> &dV_tangent) const; protected: - /// Shock indicator of Wada & Liou (1994 Flux) -- Eq.(39) - /// --- See also p.74 of Osswald et al. (2016 L2Roe) - void evaluate_shock_indicator( - const std::array &eig_L, - const std::array &eig_R, - int &ssw_LEFT, - int &ssw_RIGHT) const; + /// Shock indicator of Wada & Liou (1994 Flux) -- Eq.(39) + /// --- See also p.74 of Osswald et al. (2016 L2Roe) + void evaluate_shock_indicator( + const std::array &eig_L, + const std::array &eig_R, + int &ssw_LEFT, + int &ssw_RIGHT) const; }; +/// Base class of numerical flux associated with convection +template +class NumericalFluxConvective +{ +public: + /// Constructor + NumericalFluxConvective( + std::unique_ptr< BaselineNumericalFluxConvective > baseline_input, + std::unique_ptr< RiemannSolverDissipation > riemann_solver_dissipation_input); + + /// Destructor + ~NumericalFluxConvective() {}; + +protected: + /// Baseline convective numerical flux object + std::unique_ptr< BaselineNumericalFluxConvective > baseline; + + /// Upwind convective numerical flux object + std::unique_ptr< RiemannSolverDissipation > riemann_solver_dissipation; + +public: + /// Returns the convective numerical flux at an interface. + std::array evaluate_flux ( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &normal1) const; +}; + +/// Lax-Friedrichs numerical flux. Derived from NumericalFluxConvective. +template +class LaxFriedrichs : public NumericalFluxConvective +{ +public: + /// Constructor + LaxFriedrichs(std::shared_ptr> physics_input); + + /// Destructor + ~LaxFriedrichs() {}; +}; + +/// Roe-Pike numerical flux. Derived from NumericalFluxConvective. +template +class RoePike : public NumericalFluxConvective +{ +public: + /// Constructor + RoePike(std::shared_ptr> physics_input); + + /// Destructor + ~RoePike() {}; +}; + +/// L2Roe numerical flux. Derived from NumericalFluxConvective. +template +class L2Roe : public NumericalFluxConvective +{ +public: + /// Constructor + L2Roe(std::shared_ptr> physics_input); + + /// Destructor + ~L2Roe() {}; +}; + +/// Central numerical flux. Derived from NumericalFluxConvective. +template +class Central : public NumericalFluxConvective +{ +public: + /// Constructor + Central(std::shared_ptr> physics_input); + + /// Destructor + ~Central() {}; +}; + +/// Entropy conserving numerical flux. Derived from NumericalFluxConvective. +template +class EntropyConserving : public NumericalFluxConvective +{ +public: + /// Constructor + EntropyConserving(std::shared_ptr> physics_input); + + /// Destructor + ~EntropyConserving() {}; +}; + +/// Entropy conserving numerical flux with Lax Friedrichs dissipation. Derived from NumericalFluxConvective. +template +class EntropyConservingWithLaxFriedrichsDissipation : public NumericalFluxConvective +{ +public: + /// Constructor + EntropyConservingWithLaxFriedrichsDissipation(std::shared_ptr> physics_input); + + /// Destructor + ~EntropyConservingWithLaxFriedrichsDissipation() {}; +}; + +/// Entropy conserving numerical flux with Roe dissipation. Derived from NumericalFluxConvective. +template +class EntropyConservingWithRoeDissipation : public NumericalFluxConvective +{ +public: + /// Constructor + EntropyConservingWithRoeDissipation(std::shared_ptr> physics_input); + + /// Destructor + ~EntropyConservingWithRoeDissipation() {}; +}; + +/// Entropy conserving numerical flux with L2Roe dissipation. Derived from NumericalFluxConvective. +template +class EntropyConservingWithL2RoeDissipation : public NumericalFluxConvective +{ +public: + /// Constructor + EntropyConservingWithL2RoeDissipation(std::shared_ptr> physics_input); + + /// Destructor + ~EntropyConservingWithL2RoeDissipation() {}; +}; } /// NumericalFlux namespace } /// PHiLiP namespace diff --git a/src/numerical_flux/numerical_flux_factory.cpp b/src/numerical_flux/numerical_flux_factory.cpp index 38b0ecacf..371934bee 100644 --- a/src/numerical_flux/numerical_flux_factory.cpp +++ b/src/numerical_flux/numerical_flux_factory.cpp @@ -1,7 +1,7 @@ #include "numerical_flux_factory.hpp" +#include "convective_numerical_flux.hpp" #include "ADTypes.hpp" -#include "split_form_numerical_flux.hpp" #include "physics/physics_model.h" namespace PHiLiP { @@ -19,21 +19,34 @@ ::create_convective_numerical_flux( std::shared_ptr> physics_input) { // checks if conv_num_flux_type exists only for Euler equations - const bool is_euler_based_flux = ((conv_num_flux_type == AllParam::roe) || - (conv_num_flux_type == AllParam::l2roe)); + const bool is_euler_based = ((conv_num_flux_type == AllParam::ConvectiveNumericalFlux::roe) || + (conv_num_flux_type == AllParam::ConvectiveNumericalFlux::l2roe) || + (conv_num_flux_type == AllParam::ConvectiveNumericalFlux::two_point_flux_with_roe_dissipation) || + (conv_num_flux_type == AllParam::ConvectiveNumericalFlux::two_point_flux_with_l2roe_dissipation)); - if(conv_num_flux_type == AllParam::lax_friedrichs) { + if (conv_num_flux_type == AllParam::ConvectiveNumericalFlux::central_flux) { + return std::make_unique< Central > (physics_input); + } + else if(conv_num_flux_type == AllParam::ConvectiveNumericalFlux::lax_friedrichs) { return std::make_unique< LaxFriedrichs > (physics_input); - } else if(is_euler_based_flux) { - if constexpr (dim+2==nstate) return create_euler_based_convective_numerical_flux(conv_num_flux_type, pde_type, model_type, physics_input); - } else if (conv_num_flux_type == AllParam::split_form) { - return std::make_unique< SplitFormNumFlux > (physics_input); - } else { + } + else if(is_euler_based) { + if constexpr (dim+2==nstate) { + return create_euler_based_convective_numerical_flux(conv_num_flux_type, pde_type, model_type, physics_input); + } + } + else if (conv_num_flux_type == AllParam::ConvectiveNumericalFlux::two_point_flux) { + return std::make_unique< EntropyConserving > (physics_input); + } + else if (conv_num_flux_type == AllParam::ConvectiveNumericalFlux::two_point_flux_with_lax_friedrichs_dissipation) { + return std::make_unique< EntropyConservingWithLaxFriedrichsDissipation > (physics_input); + } + else { (void) pde_type; (void) model_type; } - std::cout << "Invalid convective numerical flux" << std::endl; + std::cout << "Invalid convective numerical flux and/or invalid added Riemann solver dissipation type." << std::endl; return nullptr; } @@ -68,10 +81,17 @@ ::create_euler_based_convective_numerical_flux( std::abort(); } #endif - if(conv_num_flux_type == AllParam::roe) { + if(conv_num_flux_type == AllParam::ConvectiveNumericalFlux::roe) { if constexpr (dim+2==nstate) return std::make_unique< RoePike > (euler_based_physics_to_be_passed); - } else if(conv_num_flux_type == AllParam::l2roe) { + } + else if(conv_num_flux_type == AllParam::ConvectiveNumericalFlux::l2roe) { if constexpr (dim+2==nstate) return std::make_unique< L2Roe > (euler_based_physics_to_be_passed); + } + else if(conv_num_flux_type == AllParam::ConvectiveNumericalFlux::two_point_flux_with_roe_dissipation) { + if constexpr (dim+2==nstate) return std::make_unique< EntropyConservingWithRoeDissipation > (euler_based_physics_to_be_passed); + } + else if(conv_num_flux_type == AllParam::ConvectiveNumericalFlux::two_point_flux_with_l2roe_dissipation) { + if constexpr (dim+2==nstate) return std::make_unique< EntropyConservingWithL2RoeDissipation > (euler_based_physics_to_be_passed); } (void) pde_type; @@ -93,6 +113,8 @@ ::create_dissipative_numerical_flux( return std::make_unique < SymmetricInternalPenalty > (physics_input,artificial_dissipation_input); } else if(diss_num_flux_type == AllParam::bassi_rebay_2) { return std::make_unique < BassiRebay2 > (physics_input,artificial_dissipation_input); + } else if(diss_num_flux_type == AllParam::central_visc_flux) { + return std::make_unique < CentralViscousNumericalFlux > (physics_input,artificial_dissipation_input); } std::cout << "Invalid dissipative flux" << std::endl; diff --git a/src/numerical_flux/numerical_flux_factory.hpp b/src/numerical_flux/numerical_flux_factory.hpp index a1f9eb3ae..f34176d53 100644 --- a/src/numerical_flux/numerical_flux_factory.hpp +++ b/src/numerical_flux/numerical_flux_factory.hpp @@ -1,5 +1,5 @@ -#ifndef __PHILIP_NUMERICAL_FLUX_FACTORY__ -#define __PHILIP_NUMERICAL_FLUX_FACTORY__ +#ifndef __NUMERICAL_FLUX_FACTORY__ +#define __NUMERICAL_FLUX_FACTORY__ #include "physics/physics.h" #include "dg/artificial_dissipation.h" @@ -9,12 +9,13 @@ namespace PHiLiP { namespace NumericalFlux { + /// Creates a NumericalFluxConvective or NumericalFluxDissipative based on input. template class NumericalFluxFactory { public: - /// Creates convective numerical flux based on input. + /// Creates convective numerical flux (baseline flux + upwind term) based on input. static std::unique_ptr < NumericalFluxConvective > create_convective_numerical_flux( const AllParam::ConvectiveNumericalFlux conv_num_flux_type, @@ -30,6 +31,7 @@ class NumericalFluxFactory std::shared_ptr> artificial_dissipation_input); protected: + /// Creates euler-based convective numerical flux (upwind term) static std::unique_ptr< NumericalFluxConvective > create_euler_based_convective_numerical_flux( const AllParam::ConvectiveNumericalFlux conv_num_flux_type, @@ -38,7 +40,6 @@ class NumericalFluxFactory std::shared_ptr> physics_input); }; - } // NumericalFlux namespace } // PHiLiP namespace diff --git a/src/numerical_flux/split_form_numerical_flux.cpp b/src/numerical_flux/split_form_numerical_flux.cpp deleted file mode 100644 index 29131114c..000000000 --- a/src/numerical_flux/split_form_numerical_flux.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "split_form_numerical_flux.hpp" -#include "ADTypes.hpp" -//#include -//#include - -namespace PHiLiP { -namespace NumericalFlux { - -template -std::array SplitFormNumFlux::evaluate_flux( - const std::array &soln_int, - const std::array &soln_ext, - const dealii::Tensor<1,dim,real> &normal_int) const - { - //std::cout << "evaluating the split form flux" <,nstate>; - RealArrayVector conv_phys_split_flux; - - conv_phys_split_flux = pde_physics->convective_numerical_split_flux (soln_int,soln_ext); - //std::cout << "done evaluating the conv num split flux" <max_convective_eigenvalue(soln_int); - // std::cout << "1st eig" << std::endl; - const real conv_max_eig_ext = pde_physics->max_convective_eigenvalue(soln_ext); - //std::cout << "2nd eig" << std::endl; - const real conv_max_eig = std::max(conv_max_eig_int, conv_max_eig_ext); - - // std::cout << "obtained the max eig" < numerical_flux_dot_n; - for (int s=0; s; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; -template class SplitFormNumFlux; - -} -} diff --git a/src/numerical_flux/split_form_numerical_flux.hpp b/src/numerical_flux/split_form_numerical_flux.hpp deleted file mode 100644 index c399c00f3..000000000 --- a/src/numerical_flux/split_form_numerical_flux.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __SPLIT_NUM_FLUX__ -#define __SPLIT_NUM_FLUX__ - -#include -#include "physics/physics.h" -#include "numerical_flux/convective_numerical_flux.hpp" - -namespace PHiLiP { -namespace NumericalFlux { - -/// Lax-Friedrichs numerical flux. Derived from NumericalFluxConvective. -template -class SplitFormNumFlux: public NumericalFluxConvective -{ -public: - -/// Constructor -SplitFormNumFlux(std::shared_ptr > physics_input) -: -pde_physics(physics_input) -{}; -/// Destructor -~SplitFormNumFlux() {}; - -/// Returns the convective numerical flux at an interface. -std::array evaluate_flux ( - const std::array &soln_int, - const std::array &soln_ext, - const dealii::Tensor<1,dim,real> &normal1) const; - -protected: -/// Numerical flux requires physics to evaluate convective eigenvalues. -const std::shared_ptr < Physics::PhysicsBase > pde_physics; - -}; - -} -} - -#endif diff --git a/src/numerical_flux/viscous_numerical_flux.cpp b/src/numerical_flux/viscous_numerical_flux.cpp index 4ddfe6aed..ef69d4164 100644 --- a/src/numerical_flux/viscous_numerical_flux.cpp +++ b/src/numerical_flux/viscous_numerical_flux.cpp @@ -19,6 +19,7 @@ std::array array_average( } return array_average; } + template std::array, nstate> array_average( const std::array,nstate> &array1, @@ -48,6 +49,99 @@ std::array,nstate> array_jump( return array_jump; } +template +std::array CentralViscousNumericalFlux +::evaluate_solution_flux ( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &/*normal_int*/) const +{ + std::array soln_avg = array_average(soln_int, soln_ext); + + return soln_avg; +} + +template +std::array CentralViscousNumericalFlux +::evaluate_auxiliary_flux ( + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const real artificial_diss_coeff_int, + const real artificial_diss_coeff_ext, + 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 dealii::Tensor<1,dim,real> &normal_int, + const real &penalty, + const bool on_boundary) const +{ + using ArrayTensor1 = std::array, nstate>; + + if (on_boundary) { + // Following the the boundary treatment given by + // Hartmann, R., Numerical Analysis of Higher Order Discontinuous Galerkin Finite Element Methods, Institute of Aerodynamics and Flow Technology, DLR (German Aerospace Center), 2008. + // Details given on page 93 + const std::array soln_bc = soln_ext; + const std::array, nstate> soln_grad_bc = soln_grad_int; + //const std::array, nstate> soln_grad_bc = soln_grad_ext; + real artificial_diss_coeff_bc = artificial_diss_coeff_int; + const dealii::types::global_dof_index boundary_cell_index = current_cell_index; + + return evaluate_auxiliary_flux ( current_cell_index, boundary_cell_index, + artificial_diss_coeff_int, artificial_diss_coeff_bc, + soln_int, soln_bc, + soln_grad_int, soln_grad_bc, + normal_int, penalty, + false); + } + + ArrayTensor1 phys_flux_int, phys_flux_ext; + + // {{A*grad_u}} + phys_flux_int = pde_physics->dissipative_flux (soln_int, soln_grad_int, current_cell_index); + phys_flux_ext = pde_physics->dissipative_flux (soln_ext, soln_grad_ext, neighbor_cell_index); + + ArrayTensor1 phys_flux_avg = array_average(phys_flux_int, phys_flux_ext); + + std::array auxiliary_flux_dot_n; + for (int s=0; s 1e-13 || artificial_diss_coeff_ext > 1e-13) { + ArrayTensor1 artificial_phys_flux_int, artificial_phys_flux_ext; + + // {{A*grad_u}} + artificial_phys_flux_int = artificial_dissip->calc_artificial_dissipation_flux (soln_int, soln_grad_int, artificial_diss_coeff_int); + artificial_phys_flux_ext = artificial_dissip->calc_artificial_dissipation_flux (soln_ext, soln_grad_ext, artificial_diss_coeff_ext); + ArrayTensor1 artificial_phys_flux_avg = array_average(artificial_phys_flux_int, artificial_phys_flux_ext); + + // {{A}}*[[u]] + ArrayTensor1 soln_jump = array_jump(soln_int, soln_ext, normal_int); + ArrayTensor1 artificial_A_jumpu_int, artificial_A_jumpu_ext; + artificial_A_jumpu_int = artificial_dissip->calc_artificial_dissipation_flux (soln_int, soln_jump, artificial_diss_coeff_int); + artificial_A_jumpu_ext = artificial_dissip->calc_artificial_dissipation_flux (soln_ext, soln_jump, artificial_diss_coeff_ext); + const ArrayTensor1 artificial_A_jumpu_avg = array_average(artificial_A_jumpu_int, artificial_A_jumpu_ext); + + for (int s=0; s std::array SymmetricInternalPenalty ::evaluate_solution_flux ( @@ -231,7 +325,6 @@ ::evaluate_auxiliary_flux ( return auxiliary_flux_dot_n; } - // Instantiation template class NumericalFluxDissipative; template class NumericalFluxDissipative; @@ -312,5 +405,31 @@ template class BassiRebay2; template class BassiRebay2; template class BassiRebay2; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; +template class CentralViscousNumericalFlux; + } // NumericalFlux namespace } // PHiLiP namespace diff --git a/src/numerical_flux/viscous_numerical_flux.hpp b/src/numerical_flux/viscous_numerical_flux.hpp index 6b750fe61..0aff4b05d 100644 --- a/src/numerical_flux/viscous_numerical_flux.hpp +++ b/src/numerical_flux/viscous_numerical_flux.hpp @@ -44,6 +44,48 @@ const std::shared_ptr < Physics::PhysicsBase > pde_physics; / const std::shared_ptr < ArtificialDissipationBase > artificial_dissip; ///< Link to artificial dissipation }; +/// Central Flux method. +template +class CentralViscousNumericalFlux: public NumericalFluxDissipative +{ +using NumericalFluxDissipative::pde_physics; +using NumericalFluxDissipative::artificial_dissip; +public: +/// Constructor +CentralViscousNumericalFlux(std::shared_ptr> physics_input, std::shared_ptr < ArtificialDissipationBase> artificial_dissipation_input) +: NumericalFluxDissipative(physics_input,artificial_dissipation_input) +{}; + +/// Evaluate solution flux at the interface +/** \f[\hat{u} = {u_h} \f] + */ +std::array evaluate_solution_flux ( + const std::array &soln_int, + const std::array &soln_ext, + const dealii::Tensor<1,dim,real> &normal_int) const override; + +/// Evaluate auxiliary flux at the interface +/** \f[ \hat{A} = {{ A \nabla u_h }} - \mu {{ A }} [[ u_h ]] \f] + * + * Note that \f$\mu\f$ must be chosen to have a stable scheme. + * + * + */ +std::array evaluate_auxiliary_flux ( + const dealii::types::global_dof_index current_cell_index, + const dealii::types::global_dof_index neighbor_cell_index, + const real artificial_diss_coeff_int, + const real artificial_diss_coeff_ext, + 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 dealii::Tensor<1,dim,real> &normal_int, + const real &penalty, + const bool on_boundary = false) const override; + +}; + /// Symmetric interior penalty method. template class SymmetricInternalPenalty: public NumericalFluxDissipative diff --git a/src/ode_solver/explicit_ode_solver.cpp b/src/ode_solver/explicit_ode_solver.cpp index cadf54f7d..2eb478ad6 100644 --- a/src/ode_solver/explicit_ode_solver.cpp +++ b/src/ode_solver/explicit_ode_solver.cpp @@ -16,7 +16,7 @@ template void RungeKuttaODESolver::step_in_time (real dt, const bool pseudotime) { this->solution_update = this->dg->solution; //storing u_n - + //calculating stages **Note that rk_stage[i] stores the RHS at a partial time-step (not solution u) for (int i = 0; i < n_rk_stages; ++i){ @@ -66,9 +66,18 @@ void RungeKuttaODESolver::step_in_time (real dt, } // u_n + dt * sum(a_ij * k_j) + dt * a_ii * u^(i) this->dg->solution = this->rk_stage[i]; + + //set the DG current time for unsteady source terms + this->dg->set_current_time(this->current_time + this->butcher_tableau->get_c(i)*dt); + + //solve the system's right hande side this->dg->assemble_residual(); //RHS : du/dt = RHS = F(u_n + dt* sum(a_ij*k_j) + dt * a_ii * u^(i))) - this->dg->global_inverse_mass_matrix.vmult(this->rk_stage[i], this->dg->right_hand_side); //rk_stage[i] = IMM*RHS = F(u_n + dt*sum(a_ij*k_j)) + if(this->all_parameters->use_inverse_mass_on_the_fly){ + this->dg->apply_inverse_global_mass_matrix(this->dg->right_hand_side, this->rk_stage[i]); //rk_stage[i] = IMM*RHS = F(u_n + dt*sum(a_ij*k_j)) + } else{ + this->dg->global_inverse_mass_matrix.vmult(this->rk_stage[i], this->dg->right_hand_side); //rk_stage[i] = IMM*RHS = F(u_n + dt*sum(a_ij*k_j)) + } } modify_time_step(dt); @@ -99,9 +108,10 @@ template void RungeKuttaODESolver::allocate_ode_system () { this->pcout << "Allocating ODE system and evaluating inverse mass matrix..." << std::endl; - const bool do_inverse_mass_matrix = true; this->solution_update.reinit(this->dg->right_hand_side); - this->dg->evaluate_mass_matrices(do_inverse_mass_matrix); + if(this->all_parameters->use_inverse_mass_on_the_fly == false) { + this->dg->evaluate_mass_matrices(true); // creates and stores global inverse mass matrix + } this->rk_stage.resize(n_rk_stages); for (int i=0; i } // PHiLiP namespace #endif + diff --git a/src/ode_solver/ode_solver_base.cpp b/src/ode_solver/ode_solver_base.cpp index 5dddc2fca..3ffbabd94 100644 --- a/src/ode_solver/ode_solver_base.cpp +++ b/src/ode_solver/ode_solver_base.cpp @@ -140,6 +140,7 @@ int ODESolverBase::steady_state () << std::endl << " Nonlinear iteration: " << this->current_iteration << " Residual norm (normalized) : " << this->residual_norm + << " Residual norm decrease : " << this->residual_norm_decrease << " ( " << this->residual_norm / this->initial_residual_norm << " ) " << std::endl; @@ -223,8 +224,9 @@ int ODESolverBase::steady_state () template int ODESolverBase::advance_solution_time (double time_advance) { - const unsigned int number_of_time_steps = static_cast(ceil(time_advance/ode_param.initial_time_step)); - const double constant_time_step = time_advance/number_of_time_steps; + + const unsigned int number_of_time_steps = (!this->all_parameters->use_energy) ? static_cast(ceil(time_advance/ode_param.initial_time_step)) : this->current_iteration+1; + const double constant_time_step = time_advance/static_cast(ceil(time_advance/ode_param.initial_time_step)); try { valid_initial_conditions(); @@ -233,12 +235,13 @@ int ODESolverBase::advance_solution_time (double time_advance std::abort(); } - pcout - << " Advancing solution by " << time_advance << " time units, using " - << number_of_time_steps << " iterations of size dt=" << constant_time_step << " ... " << std::endl; - allocate_ode_system (); + pcout << " Advancing solution by " << time_advance << " time units, using " + << number_of_time_steps << " iterations of size dt=" << constant_time_step << " ... " << std::endl; + + if(!this->all_parameters->use_energy) this->current_iteration = 0; + + if(this->current_iteration == 0) allocate_ode_system (); - this->current_iteration = 0; if (ode_param.output_solution_every_x_steps >= 0) { this->dg->output_results_vtk(this->current_iteration); } else if (ode_param.output_solution_every_dt_time_intervals > 0.0) { diff --git a/src/operators/CMakeLists.txt b/src/operators/CMakeLists.txt index 0d9f9cf0f..968a65b96 100644 --- a/src/operators/CMakeLists.txt +++ b/src/operators/CMakeLists.txt @@ -1,5 +1,6 @@ SET(OPERSOURCE operators.cpp +# operators_factory.cpp ) foreach(dim RANGE 1 3) @@ -7,11 +8,10 @@ foreach(dim RANGE 1 3) string(CONCAT OperatorsLib Operator_Lib_${dim}D) add_library(${OperatorsLib} STATIC ${OPERSOURCE}) - target_compile_definitions(${OperatorsLib} PRIVATE PHILIP_DIM=${dim}) # Library dependency - string(CONCAT DiscontinuousGalerkinLib DiscontinuousGalerkin_${dim}D) - target_link_libraries(${OperatorsLib} ${DiscontinuousGalerkinLib}) + string(CONCAT ParameterLib ParametersLibrary) + target_link_libraries(${ParameterLib}) # Setup target with deal.II if(NOT DOC_ONLY) @@ -19,6 +19,5 @@ foreach(dim RANGE 1 3) endif() unset(OperatorsLib) - unset(DiscontinuousGalerkinLib) endforeach() diff --git a/src/operators/operators.cpp b/src/operators/operators.cpp index 0cc3dd549..fc7f4eda7 100644 --- a/src/operators/operators.cpp +++ b/src/operators/operators.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -37,1023 +38,559 @@ namespace PHiLiP { namespace OPERATOR { //Constructor -template -OperatorBase::OperatorBase( - const Parameters::AllParameters *const parameters_input, - const unsigned int degree, +template +OperatorsBase::OperatorsBase( + const int nstate_input, const unsigned int max_degree_input, const unsigned int grid_degree_input) - : OperatorBase(parameters_input, degree, max_degree_input, grid_degree_input, this->create_collection_tuple(max_degree_input, parameters_input)) -{ } - -template -OperatorBase::OperatorBase( - const Parameters::AllParameters *const parameters_input, - const unsigned int /*degree*/, - const unsigned int max_degree_input, - const unsigned int grid_degree_input, - const MassiveCollectionTuple collection_tuple) - : all_parameters(parameters_input) - , max_degree(max_degree_input) + : max_degree(max_degree_input) , max_grid_degree(grid_degree_input) - , fe_collection_basis(std::get<0>(collection_tuple)) - , volume_quadrature_collection(std::get<1>(collection_tuple)) - , face_quadrature_collection(std::get<2>(collection_tuple)) - , oned_quadrature_collection(std::get<3>(collection_tuple)) - , fe_collection_flux_basis(std::get<4>(collection_tuple)) + , nstate(nstate_input) + , max_grid_degree_check(grid_degree_input) , mpi_communicator(MPI_COMM_WORLD) , pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(mpi_communicator)==0) -{ - pcout<<" Constructing Operators ..."< -OperatorBase::~OperatorBase () -{ - pcout << "Destructing Operators..." << std::endl; -} -template -std::tuple< - dealii::hp::FECollection, // Solution FE basis functions - dealii::hp::QCollection, // Volume quadrature - dealii::hp::QCollection, // Face quadrature - dealii::hp::QCollection<1>, // 1D quadrature for strong form - dealii::hp::FECollection > // Flux Basis polynomials for strong form -OperatorBase::create_collection_tuple(const unsigned int max_degree, const Parameters::AllParameters *const parameters_input) const -{ - dealii::hp::FECollection fe_coll;//basis functions collection - dealii::hp::QCollection volume_quad_coll;//volume flux nodes - dealii::hp::QCollection face_quad_coll;//facet flux nodes - dealii::hp::QCollection<1> oned_quad_coll;//1D flux nodes - - dealii::hp::FECollection fe_coll_lagr;//flux basis collocated on flux nodes - - // for p=0, we use a p=1 FE for collocation, since there's no p=0 quadrature for Gauss Lobatto - if (parameters_input->use_collocated_nodes==true) - { - int degree = 1; - - const dealii::FE_DGQ fe_dg(degree); - const dealii::FESystem fe_system(fe_dg, nstate); - fe_coll.push_back (fe_system); - - dealii::Quadrature<1> oned_quad(degree+1); - dealii::Quadrature volume_quad(degree+1); - dealii::Quadrature face_quad(degree+1); //removed const - - if (parameters_input->use_collocated_nodes) { - - dealii::QGaussLobatto<1> oned_quad_Gauss_Lobatto (degree+1); - dealii::QGaussLobatto vol_quad_Gauss_Lobatto (degree+1); - oned_quad = oned_quad_Gauss_Lobatto; - volume_quad = vol_quad_Gauss_Lobatto; - - if(dim == 1) { - dealii::QGauss face_quad_Gauss_Legendre (degree+1); - face_quad = face_quad_Gauss_Legendre; - } else { - dealii::QGaussLobatto face_quad_Gauss_Lobatto (degree+1); - face_quad = face_quad_Gauss_Lobatto; - } - } else { - dealii::QGauss<1> oned_quad_Gauss_Legendre (degree+1); - dealii::QGauss vol_quad_Gauss_Legendre (degree+1); - dealii::QGauss face_quad_Gauss_Legendre (degree+1); - oned_quad = oned_quad_Gauss_Legendre; - volume_quad = vol_quad_Gauss_Legendre; - face_quad = face_quad_Gauss_Legendre; - } - - volume_quad_coll.push_back (volume_quad); - face_quad_coll.push_back (face_quad); - oned_quad_coll.push_back (oned_quad); - - dealii::FE_DGQArbitraryNodes lagrange_poly(oned_quad); - fe_coll_lagr.push_back (lagrange_poly); - } - - int minimum_degree = (parameters_input->use_collocated_nodes==true) ? 1 : 0; - for (unsigned int degree=minimum_degree; degree<=max_degree; ++degree) { - - // Solution FECollection - const dealii::FE_DGQ fe_dg(degree); - //const dealii::FE_DGQArbitraryNodes fe_dg(dealii::QGauss<1>(degree+1)); - //std::cout << degree << " fe_dg.tensor_degree " << fe_dg.tensor_degree() << " fe_dg.n_dofs_per_cell " << fe_dg.n_dofs_per_cell() << std::endl; - const dealii::FESystem fe_system(fe_dg, nstate); - fe_coll.push_back (fe_system); - - dealii::Quadrature<1> oned_quad(degree+1); - dealii::Quadrature volume_quad(degree+1); - dealii::Quadrature face_quad(degree+1); //removed const - - if (parameters_input->use_collocated_nodes) { - dealii::QGaussLobatto<1> oned_quad_Gauss_Lobatto (degree+1); - dealii::QGaussLobatto vol_quad_Gauss_Lobatto (degree+1); - oned_quad = oned_quad_Gauss_Lobatto; - volume_quad = vol_quad_Gauss_Lobatto; - - if(dim == 1) - { - dealii::QGauss face_quad_Gauss_Legendre (degree+1); - face_quad = face_quad_Gauss_Legendre; - } - else - { - dealii::QGaussLobatto face_quad_Gauss_Lobatto (degree+1); - face_quad = face_quad_Gauss_Lobatto; +{} + +template +dealii::FullMatrix OperatorsBase::tensor_product( + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z) +{ + const unsigned int rows_x = basis_x.m(); + const unsigned int columns_x = basis_x.n(); + const unsigned int rows_y = basis_y.m(); + const unsigned int columns_y = basis_y.n(); + const unsigned int rows_z = basis_z.m(); + const unsigned int columns_z = basis_z.n(); + + if constexpr (dim==1) + return basis_x; + if constexpr (dim==2){ + dealii::FullMatrix tens_prod(rows_x * rows_y, columns_x * columns_y); + for(unsigned int jdof=0; jdofoverintegration; - dealii::QGauss<1> oned_quad_Gauss_Legendre (degree+1+overintegration); - dealii::QGauss vol_quad_Gauss_Legendre (degree+1+overintegration); - dealii::QGauss face_quad_Gauss_Legendre (degree+1+overintegration); - oned_quad = oned_quad_Gauss_Legendre; - volume_quad = vol_quad_Gauss_Legendre; - face_quad = face_quad_Gauss_Legendre; } - - volume_quad_coll.push_back (volume_quad); - face_quad_coll.push_back (face_quad); - oned_quad_coll.push_back (oned_quad); - - dealii::FE_DGQArbitraryNodes lagrange_poly(oned_quad); - fe_coll_lagr.push_back (lagrange_poly); + return tens_prod; } - - return std::make_tuple(fe_coll, volume_quad_coll, face_quad_coll, oned_quad_coll, fe_coll_lagr); -} - -template -double OperatorBase::compute_factorial(double n) -{ - if ((n==0)||(n==1)) - return 1; - else - return n*compute_factorial(n-1); -} -/******************************************* - * - * VOLUME OPERATORS FUNCTIONS - * - * - * *****************************************/ -template -void OperatorBase::allocate_volume_operators () -{ - - //basis functions evaluated at volume cubature (flux) nodes - basis_at_vol_cubature.resize(max_degree+1); - vol_integral_basis.resize(max_degree+1); - flux_basis_at_vol_cubature.resize(max_degree+1); - gradient_flux_basis.resize(max_degree+1); - modal_basis_differential_operator.resize(max_degree+1); - local_mass.resize(max_degree+1); - local_basis_stiffness.resize(max_degree+1); - local_flux_basis_stiffness.resize(max_degree+1); - vol_integral_gradient_basis.resize(max_degree+1); - derivative_p.resize(max_degree+1); - derivative_2p.resize(max_degree+1); - derivative_3p.resize(max_degree+1); - local_K_operator.resize(max_degree+1); - c_param_FR.resize(max_degree+1); - local_K_operator_aux.resize(max_degree+1); - k_param_FR.resize(max_degree+1); - vol_projection_operator.resize(max_degree+1); - vol_projection_operator_FR.resize(max_degree+1); - for(unsigned int idegree=0; idegree<=max_degree; idegree++){ - unsigned int n_quad_pts = volume_quadrature_collection[idegree].size(); - unsigned int n_dofs = fe_collection_basis[idegree].dofs_per_cell; - basis_at_vol_cubature[idegree].reinit(n_quad_pts, n_dofs); - vol_integral_basis[idegree].reinit(n_quad_pts, n_dofs); - modal_basis_differential_operator[idegree].resize(dim); - local_mass[idegree].reinit(n_dofs, n_dofs); - local_basis_stiffness[idegree].resize(dim); - derivative_p[idegree].resize(dim); - derivative_2p[idegree].resize(dim); - derivative_3p[idegree].reinit(n_dofs, n_dofs); - local_K_operator[idegree].reinit(n_dofs, n_dofs); - local_K_operator_aux[idegree].resize(dim); - vol_projection_operator[idegree].reinit(n_dofs, n_quad_pts); - vol_projection_operator_FR[idegree].reinit(n_dofs, n_quad_pts); - for(int idim=0; idimuse_collocated_nodes==true && idegree==0) ? 1 : idegree; - const unsigned int n_shape_functions = pow(shape_degree+1,dim); - for(int idim=0; idim tens_prod(rows_x * rows_y * rows_z, columns_x * columns_y * columns_z); + for(unsigned int idof=0; idof -void OperatorBase::create_vol_basis_operators () +template +dealii::FullMatrix OperatorsBase::tensor_product_state( + const int nstate, + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z) { - - for(unsigned int idegree=0; idegree<=max_degree; idegree++){ - unsigned int n_quad_pts = volume_quadrature_collection[idegree].size(); - unsigned int n_dofs = fe_collection_basis[idegree].dofs_per_cell; - unsigned int n_dofs_flux = fe_collection_flux_basis[idegree].dofs_per_cell; - for(unsigned int iquad=0; iquad qpoint = volume_quadrature_collection[idegree].point(iquad); - const std::vector &quad_weights = volume_quadrature_collection[idegree].get_weights (); - for(unsigned int idof=0; idof tens_prod(rows_all_states, columns_all_states); + + + for(int istate=0; istate basis_x_1state(rows_1state_x, columns_1state_x); + dealii::FullMatrix basis_y_1state(rows_1state_y, columns_1state_y); + dealii::FullMatrix basis_z_1state(rows_1state_z, columns_1state_z); + for(unsigned int r=0; r=2){ + for(unsigned int r=0; r qpoint = volume_quadrature_collection[idegree].point(iquad); - for(int istate=0; istate derivative; - derivative = fe_collection_flux_basis[idegree].shape_grad_component(idof, qpoint, 0); - for(int idim=0; idim=3){ + for(unsigned int r=0; r tens_prod_1state(r1state, c1state); + tens_prod_1state = tensor_product(basis_x_1state, basis_y_1state, basis_z_1state); + for(unsigned int r=0; r -void OperatorBase::build_local_Mass_Matrix ( - const std::vector &quad_weights, - const unsigned int n_dofs_cell, const unsigned int n_quad_pts, - const int current_fe_index, - dealii::FullMatrix &Mass_Matrix) +template +double OperatorsBase::compute_factorial(double n) { - for (unsigned int itest=0; itest +SumFactorizedOperators::SumFactorizedOperators( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : OperatorsBase::OperatorsBase(nstate_input, max_degree_input, grid_degree_input) +{} + +template +void SumFactorizedOperators::matrix_vector_mult( + const std::vector &input_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z, + const bool adding, + const double factor) +{ + //assert that each basis matrix is of size (rows x columns) + const unsigned int rows_x = basis_x.m(); + const unsigned int rows_y = basis_y.m(); + const unsigned int rows_z = basis_z.m(); + const unsigned int columns_x = basis_x.n(); + const unsigned int columns_y = basis_y.n(); + const unsigned int columns_z = basis_z.n(); + if constexpr (dim == 1){ + assert(rows_x == output_vect.size()); + assert(columns_x == input_vect.size()); + } + if constexpr (dim == 2){ + assert(rows_x * rows_y == output_vect.size()); + assert(columns_x * columns_y == input_vect.size()); + } + if constexpr (dim == 3){ + assert(rows_x * rows_y * rows_z == output_vect.size()); + assert(columns_x * columns_y * columns_z == input_vect.size()); + } - Mass_Matrix[itrial][itest] = 0.0; - Mass_Matrix[itest][itrial] = 0.0; - if(istate_test==istate_trial) { - Mass_Matrix[itrial][itest] = value; - Mass_Matrix[itest][itrial] = value; + if constexpr (dim==1){ + for(unsigned int iquad=0; iquad input_mat(columns_x, columns_y); + for(unsigned int idof=0; idof temp(rows_x, columns_y); + basis_x.mmult(temp, input_mat);//apply x tensor product + dealii::FullMatrix output_mat(rows_y, rows_x); + basis_y.mTmult(output_mat, temp);//apply y tensor product + //convert mat back to vect + for(unsigned int iquad=0; iquad -void OperatorBase::build_Mass_Matrix_operators () -{ - for(unsigned int idegree=0; idegree<=max_degree; idegree++){ - unsigned int n_quad_pts = volume_quadrature_collection[idegree].size(); - unsigned int n_dofs_cell = fe_collection_basis[idegree].dofs_per_cell; - const std::vector &quad_weights = volume_quadrature_collection[idegree].get_weights (); - build_local_Mass_Matrix(quad_weights, n_dofs_cell, n_quad_pts, idegree, local_mass[idegree]); } -} -template -void OperatorBase::build_Stiffness_Matrix_operators () -{ - for(unsigned int idegree=0; idegree<=max_degree; idegree++){ - unsigned int n_quad_pts = volume_quadrature_collection[idegree].size(); - unsigned int n_dofs = fe_collection_basis[idegree].dofs_per_cell; - unsigned int n_dofs_flux = fe_collection_flux_basis[idegree].dofs_per_cell; - const std::vector &quad_weights = volume_quadrature_collection[idegree].get_weights (); - for(unsigned int itest=0; itest value; - for(unsigned int iquad=0; iquad qpoint = volume_quadrature_collection[idegree].point(iquad); - dealii::Tensor<1,dim,real> derivative; - derivative = fe_collection_basis[idegree].shape_grad_component(idof, qpoint, istate); - value += basis_at_vol_cubature[idegree][iquad][itest] * quad_weights[iquad] * derivative; - } - if(istate == istate_test){ - for(int idim=0; idim input_mat(columns_x, columns_y * columns_z); + for(unsigned int idof=0; idof value; - for(unsigned int iquad=0; iquad qpoint = volume_quadrature_collection[idegree].point(iquad); - dealii::Tensor<1,dim,real> derivative; - derivative = fe_collection_flux_basis[idegree].shape_grad_component(idof, qpoint, 0); - value += basis_at_vol_cubature[idegree][iquad][itest] * quad_weights[iquad] * derivative; + } + dealii::FullMatrix temp(rows_x, columns_y * columns_z); + basis_x.mmult(temp, input_mat);//apply x tensor product + //convert to have y dofs ie/ change the stride + dealii::FullMatrix temp2(columns_y, rows_x * columns_z); + for(unsigned int iquad=0; iquad qpoint = volume_quadrature_collection[idegree].point(iquad); - dealii::Tensor<1,dim,real> derivative; - derivative = fe_collection_basis[idegree].shape_grad_component(itest, qpoint, istate_test); - for(int idim=0; idim temp3(rows_y, rows_x * columns_z); + basis_y.mmult(temp3, temp2);//apply y tensor product + dealii::FullMatrix temp4(columns_z, rows_x * rows_y); + //convert to have z dofs ie/ change the stride + for(unsigned int iquad=0; iquad inv_mass(n_dofs); - inv_mass.invert(local_mass[idegree]); - inv_mass.mmult(modal_basis_differential_operator[idegree][idim],local_basis_stiffness[idegree][idim]); + dealii::FullMatrix output_mat(rows_z, rows_x * rows_y); + basis_z.mmult(output_mat, temp4); + //convert mat to vect + for(unsigned int iquad=0; iquad -void OperatorBase::get_higher_derivatives () -{ - - for(unsigned int curr_cell_degree=0;curr_cell_degree<=max_degree; curr_cell_degree++){ - // unsigned int degree_index = curr_cell_degree - 1; - unsigned int degree_index = curr_cell_degree; - unsigned int n_dofs_cell = fe_collection_basis[degree_index].dofs_per_cell; - //write each deriv p to identity - for(int idim=0; idim derivative_p_temp(n_dofs_cell, n_dofs_cell); - derivative_p_temp.add(1, derivative_p[degree_index][idim]); - modal_basis_differential_operator[degree_index][idim].mmult(derivative_p[degree_index][idim], derivative_p_temp); - } - #if 0 - //method above loses accuracy for higher poly - if(curr_cell_degree==3){ - const unsigned int n_quad_pts = volume_quadrature_collection[curr_cell_degree].size(); - dealii::FullMatrix temp(n_quad_pts, n_dofs_cell); - for(unsigned int idof=0; idof qpoint = volume_quadrature_collection[curr_cell_degree].point(iquad); - const int istate = fe_collection_basis[curr_cell_degree].system_to_component_index(idof).first; - dealii::Tensor<3, dim, real> deriv_3 = fe_collection_basis[curr_cell_degree].shape_3rd_derivative_component(idof, qpoint, istate); - temp[iquad][idof] = deriv_3[idim][idim][idim]; - } - } - dealii::FullMatrix project(n_dofs_cell,n_quad_pts); - compute_local_vol_projection_operator(curr_cell_degree,n_dofs_cell,local_mass[curr_cell_degree],project); - } - if(curr_cell_degree >= 4){ - const unsigned int n_quad_pts = volume_quadrature_collection[curr_cell_degree].size(); - dealii::FullMatrix temp(n_quad_pts, n_dofs_cell); - for(unsigned int idof=0; idof qpoint = volume_quadrature_collection[curr_cell_degree].point(iquad); - const int istate = fe_collection_basis[curr_cell_degree].system_to_component_index(idof).first; - dealii::Tensor<4, dim, real> deriv_4 = fe_collection_basis[curr_cell_degree].shape_4th_derivative_component(idof,qpoint, istate); - temp[iquad][idof] = deriv_4[idim][idim][idim][idim]; - } - } - dealii::FullMatrix project(n_dofs_cell,n_quad_pts); - compute_local_vol_projection_operator(curr_cell_degree,n_dofs_cell,local_mass[curr_cell_degree],project); - project.mmult(derivative_p[degree_index][idim], temp); - for(unsigned int idegree=4; idegree< curr_cell_degree; idegree++){ - dealii::FullMatrix derivative_p_temp(n_dofs_cell, n_dofs_cell); - derivative_p_temp.add(1, derivative_p[degree_index][idim]); - modal_basis_differential_operator[degree_index][idim].mmult(derivative_p[degree_index][idim], derivative_p_temp); - } - } - #endif - } - if(dim == 2){ - derivative_p[degree_index][0].mmult(derivative_2p[degree_index][0],derivative_p[degree_index][1]); - } - if(dim==3){ - derivative_p[degree_index][0].mmult(derivative_2p[degree_index][0],derivative_p[degree_index][1]); - derivative_p[degree_index][0].mmult(derivative_2p[degree_index][1],derivative_p[degree_index][2]); - derivative_p[degree_index][1].mmult(derivative_2p[degree_index][2],derivative_p[degree_index][2]); - derivative_p[degree_index][0].mmult(derivative_3p[degree_index],derivative_2p[degree_index][2]); - } - } +template +void SumFactorizedOperators::matrix_vector_mult_1D( + const std::vector &input_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis_x, + const bool adding, + const double factor) +{ + this->matrix_vector_mult(input_vect, output_vect, basis_x, basis_x, basis_x, adding, factor); } -template -void OperatorBase::get_FR_correction_parameter ( - const unsigned int curr_cell_degree, - real &c, real &k) + +template +void SumFactorizedOperators::matrix_vector_mult_surface_1D( + const unsigned int face_number, + const std::vector &input_vect, + std::vector &output_vect, + const std::array,2> &basis_surf, + const dealii::FullMatrix &basis_vol, + const bool adding, + const double factor) { - using FR_enum = Parameters::AllParameters::Flux_Reconstruction; - using FR_Aux_enum = Parameters::AllParameters::Flux_Reconstruction_Aux; - FR_enum c_input = this->all_parameters->flux_reconstruction_type; - FR_Aux_enum k_input = this->all_parameters->flux_reconstruction_aux_type; - if(c_input == FR_enum::cHU || c_input == FR_enum::cHULumped){ - const double pfact = compute_factorial(curr_cell_degree); - const double pfact2 = compute_factorial(2.0 * curr_cell_degree); - // double cp = 1.0/(pow(2.0,curr_cell_degree)) * pfact2/(pow(pfact,2)); - double cp = pfact2/(pow(pfact,2));//since ref element [0,1] - //c = 2.0 * (curr_cell_degree+1)/( curr_cell_degree*pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),dim)); - c = 2.0 * (curr_cell_degree+1)/( curr_cell_degree*((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)))); - c/=2.0;//since orthonormal - } - else if(c_input == FR_enum::cSD){ - const double pfact = compute_factorial(curr_cell_degree); - const double pfact2 = compute_factorial(2.0 * curr_cell_degree); - // double cp = 1.0/(pow(2.0,curr_cell_degree)) * pfact2/(pow(pfact,2)); - double cp = pfact2/(pow(pfact,2)); - // c = 2.0 * (curr_cell_degree)/( (curr_cell_degree+1.0)*pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),dim)); - c = 2.0 * (curr_cell_degree)/( (curr_cell_degree+1.0)*((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)))); - c/=2.0;//since orthonormal - } - else if(c_input == FR_enum::cNegative){ - const double pfact = compute_factorial(curr_cell_degree); - const double pfact2 = compute_factorial(2.0 * curr_cell_degree); - // double cp = 1.0/(pow(2,curr_cell_degree)) * pfact2/(pow(pfact,2)); - double cp = pfact2/(pow(pfact,2)); - // c = - 2.0 / ( pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),dim)); - c = - 2.0 / ( pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),1.0)); - c/=2.0;//since orthonormal - } - else if(c_input == FR_enum::cNegative2){ - const double pfact = compute_factorial(curr_cell_degree); - const double pfact2 = compute_factorial(2.0 * curr_cell_degree); - // double cp = 1.0/(pow(2,curr_cell_degree)) * pfact2/(pow(pfact,2)); - double cp = pfact2/(pow(pfact,2)); - // c = - 2.0 / ( pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),dim)); - c = - 2.0 / ( pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),1.0)); - c/=2.0;//since orthonormal - c/=2.0;//since cneg/2 - } - else if(c_input == FR_enum::cDG){ - c = 0.0; - } - else if(c_input == FR_enum::c10Thousand){ - c = 10000.0; - // c = 10.0; - } - else if(c_input == FR_enum::cPlus){ - // const double pfact = compute_factorial(curr_cell_degree); - // const double pfact2 = compute_factorial(2.0 * curr_cell_degree); - // double cp = pfact2/(pow(pfact,2)); - if(curr_cell_degree == 2){ - c = 0.186; - // c = 0.173;//RK33 - } - if(curr_cell_degree == 3) - c = 3.67e-3; - if(curr_cell_degree == 4){ - c = 4.79e-5; - // c = 4.92e-5;//RK33 - } - if(curr_cell_degree == 5) - c = 4.24e-7; - - // c=0.01; - c/=2.0;//since orthonormal - c/=pow(pow(2.0,curr_cell_degree),2);//since ref elem [0,1] - // c /= pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),dim -1.0);//for multiple dim tensor product - // c *= pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),dim -1.0);//for multiple dim tensor product - - // c= 100000000.0; - } - else if(c_input == FR_enum::cPlus1D){ - if(curr_cell_degree == 2){ - c = 0.186; - // c = 0.173;//RK33 - } - if(curr_cell_degree == 3) - c = 3.67e-3; - if(curr_cell_degree == 4){ - c = 4.79e-5; - // c = 4.92e-5;//RK33 - } - if(curr_cell_degree == 5) - c = 4.24e-7; - - c/=2.0;//since orthonormal - c/=pow(pow(2.0,curr_cell_degree),2);//since ref elem [0,1] - // c+=0.001; - // c+=0.01; - } - if(k_input == FR_Aux_enum::kHU){ - const double pfact = compute_factorial(curr_cell_degree); - const double pfact2 = compute_factorial(2.0 * curr_cell_degree); - // double cp = 1.0/(pow(2.0,curr_cell_degree)) * pfact2/(pow(pfact,2)); - double cp = pfact2/(pow(pfact,2)); - // k = 2.0 * (curr_cell_degree+1.0)/( curr_cell_degree*pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),dim)); - k = 2.0 * (curr_cell_degree+1.0)/( curr_cell_degree*pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),1.0)); - k/=2.0;//since orthonormal - } - else if(k_input == FR_Aux_enum::kSD){ - const double pfact = compute_factorial(curr_cell_degree); - const double pfact2 = compute_factorial(2.0 * curr_cell_degree); - // double cp = 1.0/(pow(2.0,curr_cell_degree)) * pfact2/(pow(pfact,2)); - double cp = pfact2/(pow(pfact,2)); - // k = 2.0 * (curr_cell_degree)/( (curr_cell_degree+1.0)*pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),dim)); - k = 2.0 * (curr_cell_degree)/( (curr_cell_degree+1.0)*pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),1.0)); - k/=2.0;//since orthonormal - } - else if(k_input == FR_Aux_enum::kNegative){ - const double pfact = compute_factorial(curr_cell_degree); - const double pfact2 = compute_factorial(2.0 * curr_cell_degree); - // double cp = 1.0/(pow(2.0,curr_cell_degree)) * pfact2/(pow(pfact,2)); - double cp = pfact2/(pow(pfact,2)); - // k = - 2.0 / ( pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),dim)); - k = - 2.0 / ( pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),1.0)); - k/=2.0;//since orthonormal - } - else if(k_input == FR_Aux_enum::kNegative2){ - const double pfact = compute_factorial(curr_cell_degree); - const double pfact2 = compute_factorial(2.0 * curr_cell_degree); - // double cp = 1.0/(pow(2.0,curr_cell_degree)) * pfact2/(pow(pfact,2)); - double cp = pfact2/(pow(pfact,2)); - // k = - 2.0 / ( pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),dim)); - k = - 2.0 / ( pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),1.0)); - k/=2.0;//since orthonormal - k/=2.0; - } - else if(k_input == FR_Aux_enum::kDG){ - k = 0.0; - } - else if(k_input == FR_Aux_enum::k10Thousand){ - k = 10000.0; - } - else if(k_input == FR_Aux_enum::kPlus){ - // const double pfact = compute_factorial(curr_cell_degree); - // const double pfact2 = compute_factorial(2.0 * curr_cell_degree); - // double cp = pfact2/(pow(pfact,2)); - if(curr_cell_degree == 2) - { - k = 0.186; - // k = 0.173;//RK33 - } - if(curr_cell_degree == 3) - { - k = 3.67e-3; - } - if(curr_cell_degree == 4){ - k = 4.79e-5; - // k = 4.92e-5;//RK33 - } - if(curr_cell_degree == 5) - k = 4.24e-7; - k/=2.0;//since orthonormal - k/=pow(pow(2.0,curr_cell_degree),2);//since ref elem [0,1] -// k /= pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),dim -1.0);//for multiple dim tensor product - } -} -template -void OperatorBase::build_local_K_operator( - const dealii::FullMatrix &local_Mass_Matrix, - const unsigned int n_dofs_cell, const unsigned int degree_index, - dealii::FullMatrix &K_operator) -{ - real c = 0.0; -//get the K operator - - c = c_param_FR[degree_index]; - if(dim == 1){ - dealii::FullMatrix derivative_p_temp(n_dofs_cell, n_dofs_cell); - derivative_p_temp.add(c, derivative_p[degree_index][0]); - dealii::FullMatrix K_operator_temp(n_dofs_cell); - derivative_p_temp.Tmmult(K_operator_temp, local_Mass_Matrix); - K_operator_temp.mmult(K_operator, derivative_p[degree_index][0]); - } - if(dim == 2){ - for(int idim=0; idim derivative_p_temp(n_dofs_cell, n_dofs_cell); - derivative_p_temp.add(c, derivative_p[degree_index][idim]); - dealii::FullMatrix K_operator_temp(n_dofs_cell); - derivative_p_temp.Tmmult(K_operator_temp, local_Mass_Matrix); - K_operator_temp.mmult(K_operator, derivative_p[degree_index][idim], true); - } - double c_2 = pow(c,2.0); - dealii::FullMatrix derivative_p_temp(n_dofs_cell, n_dofs_cell); - derivative_p_temp.add(c_2, derivative_2p[degree_index][0]); - dealii::FullMatrix K_operator_temp(n_dofs_cell); - derivative_p_temp.Tmmult(K_operator_temp, local_Mass_Matrix); - K_operator_temp.mmult(K_operator, derivative_2p[degree_index][0], true); - } - if(dim == 3){ - for(int idim=0; idim derivative_p_temp(n_dofs_cell, n_dofs_cell); - derivative_p_temp.add(c, derivative_p[degree_index][idim]); - dealii::FullMatrix K_operator_temp(n_dofs_cell); - derivative_p_temp.Tmmult(K_operator_temp, local_Mass_Matrix); - K_operator_temp.mmult(K_operator, derivative_p[degree_index][idim], true); - } - for(int idim=0; idim derivative_p_temp(n_dofs_cell, n_dofs_cell); - derivative_p_temp.add(c_2, derivative_2p[degree_index][idim]); - dealii::FullMatrix K_operator_temp(n_dofs_cell); - derivative_p_temp.Tmmult(K_operator_temp, local_Mass_Matrix); - K_operator_temp.mmult(K_operator, derivative_2p[degree_index][idim], true); - } - double c_3 = pow(c,3.0); - dealii::FullMatrix derivative_p_temp(n_dofs_cell, n_dofs_cell); - derivative_p_temp.add(c_3, derivative_3p[degree_index]); - dealii::FullMatrix K_operator_temp(n_dofs_cell); - derivative_p_temp.Tmmult(K_operator_temp, local_Mass_Matrix); - K_operator_temp.mmult(K_operator, derivative_3p[degree_index], true); - } - + if(face_number == 0) + this->matrix_vector_mult(input_vect, output_vect, basis_surf[0], basis_vol, basis_vol, adding, factor); + if(face_number == 1) + this->matrix_vector_mult(input_vect, output_vect, basis_surf[1], basis_vol, basis_vol, adding, factor); + if(face_number == 2) + this->matrix_vector_mult(input_vect, output_vect, basis_vol, basis_surf[0], basis_vol, adding, factor); + if(face_number == 3) + this->matrix_vector_mult(input_vect, output_vect, basis_vol, basis_surf[1], basis_vol, adding, factor); + if(face_number == 4) + this->matrix_vector_mult(input_vect, output_vect, basis_vol, basis_vol, basis_surf[0], adding, factor); + if(face_number == 5) + this->matrix_vector_mult(input_vect, output_vect, basis_vol, basis_vol, basis_surf[1], adding, factor); } -template -void OperatorBase::build_local_K_operator_AUX( - const dealii::FullMatrix &local_Mass_Matrix, - const unsigned int n_dofs_cell, const unsigned int degree_index, - std::vector> &K_operator_aux) + + +template +void SumFactorizedOperators::inner_product_surface_1D( + const unsigned int face_number, + const std::vector &input_vect, + const std::vector &weight_vect, + std::vector &output_vect, + const std::array,2> &basis_surf, + const dealii::FullMatrix &basis_vol, + const bool adding, + const double factor) { - real k = 0.0; -//get the K AUX operator - k = k_param_FR[degree_index]; - for(int idim=0; idim derivative_p_temp2(n_dofs_cell, n_dofs_cell); - dealii::FullMatrix K_operator_temp(n_dofs_cell); - derivative_p_temp2.add(k,derivative_p[degree_index][idim]); - derivative_p_temp2.Tmmult(K_operator_temp, local_Mass_Matrix); - K_operator_temp.mmult(K_operator_aux[idim], derivative_p[degree_index][idim]); - } - + if(face_number == 0) + this->inner_product(input_vect, weight_vect, output_vect, basis_surf[0], basis_vol, basis_vol, adding, factor); + if(face_number == 1) + this->inner_product(input_vect, weight_vect, output_vect, basis_surf[1], basis_vol, basis_vol, adding, factor); + if(face_number == 2) + this->inner_product(input_vect, weight_vect, output_vect, basis_vol, basis_surf[0], basis_vol, adding, factor); + if(face_number == 3) + this->inner_product(input_vect, weight_vect, output_vect, basis_vol, basis_surf[1], basis_vol, adding, factor); + if(face_number == 4) + this->inner_product(input_vect, weight_vect, output_vect, basis_vol, basis_vol, basis_surf[0], adding, factor); + if(face_number == 5) + this->inner_product(input_vect, weight_vect, output_vect, basis_vol, basis_vol, basis_surf[1], adding, factor); } -template -void OperatorBase::build_K_operators () + +template +void SumFactorizedOperators::divergence_matrix_vector_mult_1D( + const dealii::Tensor<1,dim,std::vector> &input_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis, + const dealii::FullMatrix &gradient_basis) { - for(unsigned int degree_index=0; degree_index<=max_degree; degree_index++){ - unsigned int n_dofs_cell = fe_collection_basis[degree_index].dofs_per_cell; - unsigned int curr_cell_degree = degree_index; - get_FR_correction_parameter(curr_cell_degree, c_param_FR[degree_index], k_param_FR[degree_index]); - build_local_K_operator(local_mass[degree_index], n_dofs_cell, degree_index, local_K_operator[degree_index]); - build_local_K_operator_AUX(local_mass[degree_index], n_dofs_cell, degree_index, local_K_operator_aux[degree_index]); -#if 0 -pcout<<"K operator "< +void SumFactorizedOperators::divergence_matrix_vector_mult( + const dealii::Tensor<1,dim,std::vector> &input_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z, + const dealii::FullMatrix &gradient_basis_x, + const dealii::FullMatrix &gradient_basis_y, + const dealii::FullMatrix &gradient_basis_z) +{ + for(int idim=0; idimmatrix_vector_mult(input_vect[idim], output_vect, + gradient_basis_x, + basis_y, + basis_z, + false);//first one doesn't add in the divergence + if(idim==1) + this->matrix_vector_mult(input_vect[idim], output_vect, + basis_x, + gradient_basis_y, + basis_z, + true); + if(idim==2) + this->matrix_vector_mult(input_vect[idim], output_vect, + basis_x, + basis_y, + gradient_basis_z, + true); + } } -#endif - } + +template +void SumFactorizedOperators::gradient_matrix_vector_mult_1D( + const std::vector &input_vect, + dealii::Tensor<1,dim,std::vector> &output_vect, + const dealii::FullMatrix &basis, + const dealii::FullMatrix &gradient_basis) +{ + gradient_matrix_vector_mult(input_vect, output_vect, + basis, basis, basis, + gradient_basis, gradient_basis, gradient_basis); } -template -void OperatorBase::compute_local_vol_projection_operator( - const unsigned int degree_index, - const unsigned int n_dofs_cell, - const dealii::FullMatrix &norm_matrix, - dealii::FullMatrix &volume_projection) +template +void SumFactorizedOperators::gradient_matrix_vector_mult( + const std::vector &input_vect, + dealii::Tensor<1,dim,std::vector> &output_vect, + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z, + const dealii::FullMatrix &gradient_basis_x, + const dealii::FullMatrix &gradient_basis_y, + const dealii::FullMatrix &gradient_basis_z) { - dealii::FullMatrix norm_inv(n_dofs_cell); - norm_inv.invert(norm_matrix); - norm_inv.mTmult(volume_projection, vol_integral_basis[degree_index]); + for(int idim=0; idimmatrix_vector_mult(input_vect, output_vect[idim], + gradient_basis_x, + basis_y, + basis_z, + false);//first one doesn't add in the divergence + if(idim==1) + this->matrix_vector_mult(input_vect, output_vect[idim], + basis_x, + gradient_basis_y, + basis_z, + false); + if(idim==2) + this->matrix_vector_mult(input_vect, output_vect[idim], + basis_x, + basis_y, + gradient_basis_z, + false); + } } -template -void OperatorBase::get_vol_projection_operators () + +template +void SumFactorizedOperators::inner_product( + const std::vector &input_vect, + const std::vector &weight_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z, + const bool adding, + const double factor) { - for(unsigned int degree_index=0; degree_index<=max_degree; degree_index++){ - unsigned int n_dofs = fe_collection_basis[degree_index].dofs_per_cell; - compute_local_vol_projection_operator(degree_index, n_dofs, local_mass[degree_index], vol_projection_operator[degree_index]); - dealii::FullMatrix M_plus_K(n_dofs); - M_plus_K.add(1.0, local_mass[degree_index], 1.0, local_K_operator[degree_index]); - compute_local_vol_projection_operator(degree_index, n_dofs, M_plus_K, vol_projection_operator_FR[degree_index]); + //assert that each basis matrix is of size (rows x columns) + const unsigned int rows_x = basis_x.m(); + const unsigned int rows_y = basis_y.m(); + const unsigned int rows_z = basis_z.m(); + const unsigned int columns_x = basis_x.n(); + const unsigned int columns_y = basis_y.n(); + const unsigned int columns_z = basis_z.n(); + //Note the assertion has columns to output and rows to input + //bc we transpose the basis inputted for the inner product + if constexpr (dim == 1){ + assert(rows_x == input_vect.size()); + assert(columns_x == output_vect.size()); } -} + if constexpr (dim == 2){ + assert(rows_x * rows_y == input_vect.size()); + assert(columns_x * columns_y == output_vect.size()); + } + if constexpr (dim == 3){ + assert(rows_x * rows_y * rows_z == input_vect.size()); + assert(columns_x * columns_y * columns_z == output_vect.size()); + } + assert(weight_vect.size() == input_vect.size()); -/******************************************* - * - * SURFACE OPERATORS FUNCTIONS - * - * - * *****************************************/ -template -void OperatorBase::allocate_surface_operators () -{ - unsigned int n_faces = dealii::GeometryInfo::faces_per_cell; - basis_at_facet_cubature.resize(max_degree+1); - flux_basis_at_facet_cubature.resize(max_degree+1); - face_integral_basis.resize(max_degree+1); - lifting_operator.resize(max_degree+1); - lifting_operator_FR.resize(max_degree+1); - for(unsigned int idegree=0; idegree<=max_degree; idegree++){ - unsigned int n_quad_face_pts = face_quadrature_collection[idegree].size(); - unsigned int n_dofs = fe_collection_basis[idegree].dofs_per_cell; - unsigned int n_dofs_flux = fe_collection_flux_basis[idegree].dofs_per_cell; - basis_at_facet_cubature[idegree].resize(n_faces); - face_integral_basis[idegree].resize(n_faces); - lifting_operator[idegree].resize(n_faces); - lifting_operator_FR[idegree].resize(n_faces); - for(unsigned int iface=0; iface basis_x_trans(columns_x, rows_x); + dealii::FullMatrix basis_y_trans(columns_y, rows_y); + dealii::FullMatrix basis_z_trans(columns_z, rows_z); + + //set as the transpose as inputed basis + //found an issue with Tadd for arbitrary size so I manually do it here. + for(unsigned int row=0; rowuse_collocated_nodes==true && idegree==0) ? 1 : idegree; - // const unsigned int n_shape_functions = pow(shape_degree+1,dim); - for(int istate=0; istate -void OperatorBase::create_surface_basis_operators () -{ - unsigned int n_faces = dealii::GeometryInfo::faces_per_cell; - for(unsigned int idegree=0; idegree<=max_degree; idegree++){ - unsigned int n_dofs = fe_collection_basis[idegree].dofs_per_cell; - unsigned int n_dofs_flux = fe_collection_flux_basis[idegree].dofs_per_cell; - //int shape_degree = (all_parameters->use_collocated_nodes==true && idegree==0) ? 1 : idegree; - //const unsigned int n_shape_functions = pow(shape_degree+1,dim); - unsigned int n_quad_face_pts = face_quadrature_collection[idegree].size(); - const std::vector &quad_weights = face_quadrature_collection[idegree].get_weights (); - for(unsigned int iface=0; iface quadrature = dealii::QProjector::project_to_face(dealii::ReferenceCell::get_hypercube(dim), - face_quadrature_collection[idegree], - iface); - - const dealii::Tensor<1,dim,real> unit_normal_int = dealii::GeometryInfo::unit_normal_vector[iface]; - for(unsigned int iquad=0; iquad -void OperatorBase::build_local_surface_lifting_operator ( - const unsigned int degree_index, - const unsigned int n_dofs_cell, - const unsigned int face_number, - const dealii::FullMatrix &norm_matrix, - std::vector> &lifting) -{ - dealii::FullMatrix norm_inv(n_dofs_cell); - norm_inv.invert(norm_matrix); - for(int idim=0; idim new_input_vect(input_vect.size()); + for(unsigned int iquad=0; iquadmatrix_vector_mult(new_input_vect, output_vect, basis_x_trans, basis_y_trans, basis_z_trans, adding, factor); } -template -void OperatorBase::get_surface_lifting_operators () + +template +void SumFactorizedOperators::inner_product_1D( + const std::vector &input_vect, + const std::vector &weight_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis_x, + const bool adding, + const double factor) { - unsigned int n_faces = dealii::GeometryInfo::faces_per_cell; - for(unsigned int degree_index=0; degree_index<=max_degree; degree_index++){ - unsigned int n_dofs = fe_collection_basis[degree_index].dofs_per_cell; -#if 0 -pcout<<"K operator "<inner_product(input_vect, weight_vect, output_vect, basis_x, basis_x, basis_x, adding, factor); } -pcout< M_plus_K(n_dofs); - M_plus_K.add(1.0, local_mass[degree_index], 1.0, local_K_operator[degree_index]); - build_local_surface_lifting_operator(degree_index, n_dofs, iface, M_plus_K, lifting_operator_FR[degree_index][iface]); - } - } -} -/********************************************************************* - * - * METRIC OPERATOR FUNCTIONS - * - * ******************************************************/ -template -void OperatorBase::allocate_metric_operators () -{ - unsigned int n_faces = dealii::GeometryInfo::faces_per_cell; - mapping_shape_functions_grid_nodes.resize(max_grid_degree+1); - gradient_mapping_shape_functions_grid_nodes.resize(max_grid_degree+1); - mapping_shape_functions_vol_flux_nodes.resize(max_grid_degree+1); - mapping_shape_functions_face_flux_nodes.resize(max_grid_degree+1); - gradient_mapping_shape_functions_vol_flux_nodes.resize(max_grid_degree+1); - gradient_mapping_shape_functions_face_flux_nodes.resize(max_grid_degree+1); - for(unsigned int idegree=0; idegree<=max_grid_degree; idegree++){ - // unsigned int n_dofs = dim * pow(idegree+1,dim); - unsigned int n_dofs = pow(idegree+1,dim); - mapping_shape_functions_grid_nodes[idegree].reinit(n_dofs, n_dofs); - gradient_mapping_shape_functions_grid_nodes[idegree].resize(dim); - for(int idim=0; idim +void SumFactorizedOperators::divergence_two_pt_flux_Hadamard_product( + const dealii::Tensor<1,dim,dealii::FullMatrix> &input_mat, + std::vector &output_vect, + const std::vector &weights, + const dealii::FullMatrix &basis, + const double scaling) +{ + assert(input_mat[0].m() == output_vect.size()); - } - - } -} -template -void OperatorBase::create_metric_basis_operators () -{ -#if 0 //GRID CANNOT BE DEGREE 0 - //degree 0 GLL not exist - dealii::QGauss<1> GL (0+1); - // dealii::FE_DGQArbitraryNodes fe1(GL); - dealii::FE_Q feq1(GL); - dealii::FESystem fe1(feq1, dim); - dealii::Quadrature vol_GL(GL); - const unsigned int n_quad_pts1 = vol_GL.size(); - const unsigned int n_dofs1 = fe1.dofs_per_cell; - for(unsigned int iquad=0; iquad grid_node = vol_GL.point(iquad); - const dealii::Point flux_node = volume_quadrature_collection[0].point(iquad); - for(unsigned int idof=0; idof derivative; - derivative = fe1.shape_grad_component(idof, grid_node, 0); - for(int idim=0; idim quadrature1 = dealii::QProjector::project_to_face(dealii::ReferenceCell::get_hypercube(dim), - face_quadrature_collection[0], - iface); - const unsigned int n_quad_face_pts1 = face_quadrature_collection[0].size(); - for(unsigned int iquad=0; iquad flux_node = quadrature1.point(iquad); - for(unsigned int idof=0; idof=1 - for(unsigned int idegree=1; idegree<=max_grid_degree; idegree++){ - // dealii::QGaussLobatto<1> GLL (idegree+1); - // dealii::FE_DGQArbitraryNodes fe(GLL); - dealii::FE_Q feq(idegree); - dealii::FESystem fe(feq, 1); - // dealii::Quadrature vol_GLL(GLL); - dealii::QGaussLobatto vol_GLL(idegree +1); - const unsigned int n_dofs = fe.dofs_per_cell; - for(unsigned int iquad_GN=0; iquad_GN grid_node = vol_GLL.point(iquad_GN); - for(unsigned int idof=0; idof derivative; - derivative = fe.shape_grad_component(idof, grid_node, 0); - for(int idim=0; idim output_mat(input_mat[0].m(), input_mat[0].n()); + for(int idim=0; idim flux_node = volume_quadrature_collection[ipoly].point(iquad); - for(unsigned int idof=0; idof derivative_flux; - derivative_flux = fe.shape_grad_component(idof, flux_node, 0); - for(int idim=0; idim::faces_per_cell; - for(unsigned int iface=0; iface quadrature = dealii::QProjector::project_to_face(dealii::ReferenceCell::get_hypercube(dim), - face_quadrature_collection[ipoly], - iface); - const unsigned int n_quad_face_pts = face_quadrature_collection[ipoly].size(); - for(unsigned int iquad=0; iquad flux_node = quadrature.point(iquad); - for(unsigned int idof=0; idof derivative_flux; - derivative_flux = fe.shape_grad_component(idof, flux_node, 0); - for(int idim=0; idim::create_metric_basis_operators () } } -template -void OperatorBase::build_local_vol_metric_cofactor_matrix_and_det_Jac( - const unsigned int grid_degree, const unsigned int poly_degree, - const unsigned int n_quad_pts,//number volume quad pts - const unsigned int n_metric_dofs,//dofs of metric basis - const std::vector> &mapping_support_points, - std::vector &determinant_Jacobian, - std::vector> &metric_cofactor) +template +void SumFactorizedOperators::surface_two_pt_flux_Hadamard_product( + const dealii::FullMatrix &input_mat, + std::vector &output_vect_vol, + std::vector &output_vect_surf, + const std::vector &weights, + const std::array,2> &surf_basis, + const unsigned int iface, + const unsigned int dim_not_zero, + const double scaling)//scaling is unit_ref_normal[dim_not_zero] { - //mapping support points must be passed as a vector[dim][n_metric_dofs] - assert(pow(grid_degree+1,dim) == mapping_support_points[0].size()); - assert(pow(grid_degree+1,dim) == n_metric_dofs); - std::vector> Jacobian(n_quad_pts); - for(unsigned int iquad=0; iquad output_mat(input_mat.m(), input_mat.n()); + two_pt_flux_Hadamard_product(input_mat, output_mat, surf_basis[iface_1D], weights, dim_not_zero); + if constexpr(dim==1){ + for(unsigned int row=0; row temp(dim); - temp.invert(Jacobian[iquad]); - metric_cofactor[iquad].Tadd(1.0, temp); - // metric_cofactor[iquad].invert(Jacobian[iquad]);//since we did interp within differentiation in computing Jacobian - metric_cofactor[iquad] *= determinant_Jacobian[iquad]; + if constexpr(dim==3){ + const unsigned int size_1D_row = surf_basis[iface_1D].m(); + const unsigned int size_1D_col = surf_basis[iface_1D].n(); + for(unsigned int irow=0; irow -void OperatorBase::compute_local_3D_cofactor_vol( - const unsigned int grid_degree, const unsigned int poly_degree, - const unsigned int n_quad_pts, - const unsigned int n_metric_dofs, - const std::vector> &mapping_support_points, - std::vector> &metric_cofactor) -{ - std::vector> Xl_grad_Xm(n_metric_dofs);//(x_l * \nabla(x_m)) evaluated at GRID NODES - compute_Xl_grad_Xm(grid_degree, n_metric_dofs, mapping_support_points, Xl_grad_Xm); - - // Evaluate the physical (Y grad Z), (Z grad X), (X grad - std::vector Ta(n_metric_dofs); - std::vector Tb(n_metric_dofs); - std::vector Tc(n_metric_dofs); - std::vector Td(n_metric_dofs); - std::vector Te(n_metric_dofs); - std::vector Tf(n_metric_dofs); - - std::vector Tg(n_metric_dofs); - std::vector Th(n_metric_dofs); - std::vector Ti(n_metric_dofs); +template +void SumFactorizedOperators::two_pt_flux_Hadamard_product( + const dealii::FullMatrix &input_mat, + dealii::FullMatrix &output_mat, + const dealii::FullMatrix &basis, + const std::vector &weights, + const int direction) +{ + assert(input_mat.size() == output_mat.size()); + const unsigned int size = basis.n(); + assert(size == weights.size()); - for(unsigned int igrid=0; igrid local_block(rows, size); + std::vector row_index(rows); + std::vector col_index(size); + //fill index range for diagonal blocks of rize rows_x x columns_x + std::iota(row_index.begin(), row_index.end(), idiag*rows); + std::iota(col_index.begin(), col_index.end(), idiag*size); + //extract diagonal block from input matrix + local_block.extract_submatrix_from(input_mat, row_index, col_index); + dealii::FullMatrix local_Hadamard(rows, size); + Hadamard_product(local_block, basis, local_Hadamard); + //scale by the diagonal weight from tensor product + local_Hadamard *= weights[idiag]; + //write the values into diagonal block of output + local_Hadamard.scatter_matrix_to(row_index, col_index, output_mat); + } } - - for(unsigned int iquad=0; iquad> grad_Xl_grad_Xm(n_quad_pts);//gradient of gradient of mapping support points at Flux nodes - //for the curl of interp at flux nodes - //ie/ \nabla ( x_l * \nabla(x_m)) - std::vector> Xl_grad_Xm(n_metric_dofs);//(x_l * \nabla(x_m)) evaluated at GRID NODES - compute_Xl_grad_Xm(grid_degree, n_metric_dofs, mapping_support_points, Xl_grad_Xm); - //now get the derivative of X_l*nabla(X_m) evaluated at the quadrature/flux nodes - for(unsigned int iquad=0; iquad local_block(rows, size); + std::vector row_index(rows); + std::vector col_index(size); + //fill index range for diagonal blocks of rize rows_x x columns_x + std::iota(row_index.begin(), row_index.end(), idiag*rows); + std::iota(col_index.begin(), col_index.end(), idiag*size); + //extract diagonal block from input matrix + local_block.extract_submatrix_from(input_mat, row_index, col_index); + dealii::FullMatrix local_Hadamard(rows, size); + Hadamard_product(local_block, basis, local_Hadamard); + //scale by the diagonal weight from tensor product + local_Hadamard *= weights[kdiag]; + kdiag++; + const unsigned int jdiag = idiag / size; + local_Hadamard *= weights[jdiag]; + //write the values into diagonal block of output + local_Hadamard.scatter_matrix_to(row_index, col_index, output_mat); + } + } + if(direction == 1){ + for(unsigned int zdiag=0; zdiag -void OperatorBase::build_local_face_metric_cofactor_matrix_and_det_Jac( - const unsigned int grid_degree, const unsigned int poly_degree, - const unsigned int iface, - const unsigned int n_quad_pts, const unsigned int n_metric_dofs, - const std::vector> &mapping_support_points, - std::vector &determinant_Jacobian, - std::vector> &metric_cofactor) -{ - //mapping support points must be passed as a vector[dim][n_metric_dofs] - assert(pow(grid_degree+1,dim) == mapping_support_points[0].size()); - assert(pow(grid_degree+1,dim) == n_metric_dofs); - std::vector> Jacobian(n_quad_pts); - for(unsigned int iquad=0; iquad +void SumFactorizedOperators::Hadamard_product( + const dealii::FullMatrix &input_mat1, + const dealii::FullMatrix &input_mat2, + dealii::FullMatrix &output_mat) +{ + const unsigned int rows = input_mat1.m(); + const unsigned int columns = input_mat1.n(); + assert(rows == input_mat2.m()); + assert(columns == input_mat2.n()); + + for(unsigned int irow=0; irow temp(dim); - temp.invert(Jacobian[iquad]); - metric_cofactor[iquad].Tadd(1.0, temp); - // metric_cofactor[iquad].invert(Jacobian[iquad]);//since we did interp within differentiation in computing Jacobian - metric_cofactor[iquad] *= determinant_Jacobian[iquad]; - } +} + +/******************************************* + * + * VOLUME OPERATORS FUNCTIONS + * + * + ******************************************/ + +template +basis_functions::basis_functions( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} + +template +void basis_functions::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_quad_pts = quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + //allocate the basis at volume cubature + this->oneD_vol_operator.reinit(n_quad_pts, n_dofs); + //loop and store + for(unsigned int iquad=0; iquad qpoint = quadrature.point(iquad); + for(unsigned int idof=0; idofoneD_vol_operator[iquad][idof] = finite_element.shape_value_component(idof,qpoint,istate); + } + } +} + +template +void basis_functions::build_1D_gradient_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_quad_pts = quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + //allocate the basis at volume cubature + this->oneD_grad_operator.reinit(n_quad_pts, n_dofs); + //loop and store + for(unsigned int iquad=0; iquad qpoint = quadrature.point(iquad); + for(unsigned int idof=0; idofoneD_grad_operator[iquad][idof] = finite_element.shape_grad_component(idof,qpoint,istate)[0]; + } + } +} + +template +void basis_functions::build_1D_surface_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &face_quadrature) +{ + const unsigned int n_face_quad_pts = face_quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + const unsigned int n_faces_1D = n_faces / dim; + //loop and store + for(unsigned int iface=0; ifaceoneD_surf_operator[iface].reinit(n_face_quad_pts, n_dofs); + //sum factorized operators use a 1D element. + const dealii::Quadrature<1> quadrature = dealii::QProjector<1>::project_to_face(dealii::ReferenceCell::get_hypercube(1), + face_quadrature, + iface); + for(unsigned int iquad=0; iquad qpoint = quadrature.point(iquad); + for(unsigned int idof=0; idofoneD_surf_operator[iface][iquad][idof] = finite_element.shape_value_component(idof,qpoint,istate); + } + } + } +} + +template +void basis_functions::build_1D_surface_gradient_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &face_quadrature) +{ + const unsigned int n_face_quad_pts = face_quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + const unsigned int n_faces_1D = n_faces / dim; + //loop and store + for(unsigned int iface=0; ifaceoneD_surf_grad_operator[iface].reinit(n_face_quad_pts, n_dofs); + //sum factorized operators use a 1D element. + const dealii::Quadrature<1> quadrature = dealii::QProjector<1>::project_to_face(dealii::ReferenceCell::get_hypercube(1), + face_quadrature, + iface); + for(unsigned int iquad=0; iquad qpoint = quadrature.point(iquad); + for(unsigned int idof=0; idofoneD_surf_grad_operator[iface][iquad][idof] = finite_element.shape_grad_component(idof,qpoint,istate)[0]; + } + } + } +} + +template +vol_integral_basis::vol_integral_basis( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} + +template +void vol_integral_basis::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_quad_pts = quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + //allocate + this->oneD_vol_operator.reinit(n_quad_pts, n_dofs); + //loop and store + const std::vector &quad_weights = quadrature.get_weights (); + for(unsigned int iquad=0; iquad qpoint = quadrature.point(iquad); + for(unsigned int idof=0; idofoneD_vol_operator[iquad][idof] = quad_weights[iquad] * finite_element.shape_value_component(idof,qpoint,istate); + } + } +} + +template +local_mass::local_mass( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} + +template +void local_mass::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_quad_pts = quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + const std::vector &quad_weights = quadrature.get_weights (); + //allocate + this->oneD_vol_operator.reinit(n_dofs,n_dofs); + //loop and store + for (unsigned int itest=0; itest qpoint = quadrature.point(iquad); + value += + finite_element.shape_value_component(itest,qpoint,istate_test) + * finite_element.shape_value_component(itrial,qpoint,istate_trial) + * quad_weights[iquad]; + } + + this->oneD_vol_operator[itrial][itest] = 0.0; + this->oneD_vol_operator[itest][itrial] = 0.0; + if(istate_test==istate_trial) { + this->oneD_vol_operator[itrial][itest] = value; + this->oneD_vol_operator[itest][itrial] = value; + } + } + } +} + +template +dealii::FullMatrix local_mass::build_dim_mass_matrix( + const int nstate, + const unsigned int n_dofs, const unsigned int n_quad_pts, + basis_functions &basis, + const std::vector &det_Jac, + const std::vector &quad_weights) + +{ + const unsigned int n_shape_fns = n_dofs / nstate; + assert(nstate*pow(basis.oneD_vol_operator.m() / nstate, dim) == n_dofs); + dealii::FullMatrix mass_matrix_dim(n_dofs); + dealii::FullMatrix basis_dim(n_dofs); + basis_dim = basis.tensor_product_state( + nstate, + basis.oneD_vol_operator, + basis.oneD_vol_operator, + basis.oneD_vol_operator); + //loop and store + for(int istate=0; istate +local_basis_stiffness::local_basis_stiffness( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const bool store_skew_symmetric_form_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) + , store_skew_symmetric_form(store_skew_symmetric_form_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} + +template +void local_basis_stiffness::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_quad_pts = quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + const std::vector &quad_weights = quadrature.get_weights (); + //allocate + this->oneD_vol_operator.reinit(n_dofs,n_dofs); + //loop and store + for(unsigned int itest=0; itest qpoint = quadrature.point(iquad); + value += finite_element.shape_value_component(itest,qpoint,istate_test) + * finite_element.shape_grad_component(idof, qpoint, istate)[0]//since it's a 1D operator + * quad_weights[iquad]; + } + if(istate == istate_test){ + this->oneD_vol_operator[itest][idof] = value; + } + } } - if(dim == 3){ - compute_local_3D_cofactor_face(grid_degree, poly_degree, n_quad_pts, n_metric_dofs, iface, mapping_support_points, metric_cofactor); + if(store_skew_symmetric_form){ + //allocate + oneD_skew_symm_vol_oper.reinit(n_dofs,n_dofs); + //solve + oneD_skew_symm_vol_oper.add(1.0, this->oneD_vol_operator); + oneD_skew_symm_vol_oper.Tadd(-1.0, this->oneD_vol_operator); } +} + +template +modal_basis_differential_operator::modal_basis_differential_operator( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} +template +void modal_basis_differential_operator::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + local_mass mass_matrix(this->nstate, this->max_degree, this->max_grid_degree); + mass_matrix.build_1D_volume_operator(finite_element, quadrature); + local_basis_stiffness stiffness(this->nstate, this->max_degree, this->max_grid_degree); + stiffness.build_1D_volume_operator(finite_element, quadrature); + //allocate + this->oneD_vol_operator.reinit(n_dofs,n_dofs); + dealii::FullMatrix inv_mass(n_dofs); + inv_mass.invert(mass_matrix.oneD_vol_operator); + //solves + inv_mass.mmult(this->oneD_vol_operator, stiffness.oneD_vol_operator); } -template -void OperatorBase::compute_local_3D_cofactor_face( - const unsigned int grid_degree, const unsigned int poly_degree, - const unsigned int n_quad_pts, - const unsigned int n_metric_dofs, const unsigned int iface, - const std::vector> &mapping_support_points, - std::vector> &metric_cofactor) +template +derivative_p::derivative_p( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} + +template +void derivative_p::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + //allocate + this->oneD_vol_operator.reinit(n_dofs,n_dofs); + //set as identity + for(unsigned int idof=0; idofoneD_vol_operator[idof][idof] = 1.0;//set it equal to identity + } + //get modal basis differential operator + modal_basis_differential_operator diff_oper(this->nstate, this->max_degree, this->max_grid_degree); + diff_oper.build_1D_volume_operator(finite_element, quadrature); + //loop and solve + for(unsigned int idegree=0; idegree< this->max_degree; idegree++){ + dealii::FullMatrix derivative_p_temp(n_dofs, n_dofs); + derivative_p_temp.add(1.0, this->oneD_vol_operator); + diff_oper.oneD_vol_operator.mmult(this->oneD_vol_operator, derivative_p_temp); + } +} + +template +local_Flux_Reconstruction_operator::local_Flux_Reconstruction_operator( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction FR_param_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) + , FR_param_type(FR_param_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; + //get the FR corrcetion parameter value + get_FR_correction_parameter(this->max_degree, FR_param); +} + +template +void local_Flux_Reconstruction_operator::get_Huynh_g2_parameter ( + const unsigned int curr_cell_degree, + double &c) +{ + const double pfact = this->compute_factorial(curr_cell_degree); + const double pfact2 = this->compute_factorial(2.0 * curr_cell_degree); + double cp = pfact2/(pow(pfact,2));//since ref element [0,1] + c = 2.0 * (curr_cell_degree+1)/( curr_cell_degree*((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)))); + c/=2.0;//since orthonormal +} +template +void local_Flux_Reconstruction_operator::get_spectral_difference_parameter ( + const unsigned int curr_cell_degree, + double &c) +{ + const double pfact = this->compute_factorial(curr_cell_degree); + const double pfact2 = this->compute_factorial(2.0 * curr_cell_degree); + double cp = pfact2/(pow(pfact,2)); + c = 2.0 * (curr_cell_degree)/( (curr_cell_degree+1.0)*((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)))); + c/=2.0;//since orthonormal +} +template +void local_Flux_Reconstruction_operator::get_c_negative_FR_parameter ( + const unsigned int curr_cell_degree, + double &c) +{ + const double pfact = this->compute_factorial(curr_cell_degree); + const double pfact2 = this->compute_factorial(2.0 * curr_cell_degree); + double cp = pfact2/(pow(pfact,2)); + c = - 2.0 / ( pow((2.0*curr_cell_degree+1.0)*(pow(pfact*cp,2)),1.0)); + c/=2.0;//since orthonormal +} +template +void local_Flux_Reconstruction_operator::get_c_negative_divided_by_two_FR_parameter ( + const unsigned int curr_cell_degree, + double &c) +{ + get_c_negative_FR_parameter(curr_cell_degree, c); + c/=2.0; +} +template +void local_Flux_Reconstruction_operator::get_c_plus_parameter ( + const unsigned int curr_cell_degree, + double &c) { - std::vector> Xl_grad_Xm(n_metric_dofs);//(x_l * \nabla(x_m)) evaluated at GRID NODES - compute_Xl_grad_Xm(grid_degree, n_metric_dofs, mapping_support_points, Xl_grad_Xm); + if(curr_cell_degree == 2){ + c = 0.186; +// c = 0.173;//RK33 + } + if(curr_cell_degree == 3) + c = 3.67e-3; + if(curr_cell_degree == 4){ + c = 4.79e-5; +// c = 4.92e-5;//RK33 + } + if(curr_cell_degree == 5) + c = 4.24e-7; - // Evaluate the physical (Y grad Z), (Z grad X), (X grad - std::vector Ta(n_metric_dofs); - std::vector Tb(n_metric_dofs); - std::vector Tc(n_metric_dofs); + c/=2.0;//since orthonormal + c/=pow(pow(2.0,curr_cell_degree),2);//since ref elem [0,1] +} - std::vector Td(n_metric_dofs); - std::vector Te(n_metric_dofs); - std::vector Tf(n_metric_dofs); +template +void local_Flux_Reconstruction_operator::get_FR_correction_parameter ( + const unsigned int curr_cell_degree, + double &c) +{ + using FR_enum = Parameters::AllParameters::Flux_Reconstruction; + if(FR_param_type == FR_enum::cHU || FR_param_type == FR_enum::cHULumped){ + get_Huynh_g2_parameter(curr_cell_degree, FR_param); + } + else if(FR_param_type == FR_enum::cSD){ + get_spectral_difference_parameter(curr_cell_degree, c); + } + else if(FR_param_type == FR_enum::cNegative){ + get_c_negative_FR_parameter(curr_cell_degree, c); + } + else if(FR_param_type == FR_enum::cNegative2){ + get_c_negative_divided_by_two_FR_parameter(curr_cell_degree, c); + } + else if(FR_param_type == FR_enum::cDG){ + //DG case is the 0.0 case. + c = 0.0; + } + else if(FR_param_type == FR_enum::c10Thousand){ + //Set the value to 10000 for arbitrary high-numbers. + c = 10000.0; + } + else if(FR_param_type == FR_enum::cPlus){ + get_c_plus_parameter(curr_cell_degree, c); + } +} +template +void local_Flux_Reconstruction_operator::build_local_Flux_Reconstruction_operator( + const dealii::FullMatrix &local_Mass_Matrix, + const dealii::FullMatrix &pth_derivative, + const unsigned int n_dofs, + const double c, + dealii::FullMatrix &Flux_Reconstruction_operator) +{ + dealii::FullMatrix derivative_p_temp(n_dofs); + derivative_p_temp.add(c, pth_derivative); + dealii::FullMatrix Flux_Reconstruction_operator_temp(n_dofs); + derivative_p_temp.Tmmult(Flux_Reconstruction_operator_temp, local_Mass_Matrix); + Flux_Reconstruction_operator_temp.mmult(Flux_Reconstruction_operator, pth_derivative); +} - std::vector Tg(n_metric_dofs); - std::vector Th(n_metric_dofs); - std::vector Ti(n_metric_dofs); - for(unsigned int igrid=0; igrid +void local_Flux_Reconstruction_operator::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + //allocate the volume operator + this->oneD_vol_operator.reinit(n_dofs, n_dofs); + //build the FR correction operator + derivative_p pth_derivative(this->nstate, this->max_degree, this->max_grid_degree); + pth_derivative.build_1D_volume_operator(finite_element, quadrature); + + local_mass local_Mass_Matrix(this->nstate, this->max_degree, this->max_grid_degree); + local_Mass_Matrix.build_1D_volume_operator(finite_element, quadrature); + //solves + build_local_Flux_Reconstruction_operator(local_Mass_Matrix.oneD_vol_operator, pth_derivative.oneD_vol_operator, n_dofs, FR_param, this->oneD_vol_operator); +} + +template +dealii::FullMatrix local_Flux_Reconstruction_operator::build_dim_Flux_Reconstruction_operator_directly( + const int nstate, + const unsigned int n_dofs, + dealii::FullMatrix &pth_deriv, + dealii::FullMatrix &mass_matrix) +{ + dealii::FullMatrix Flux_Reconstruction_operator(n_dofs); + dealii::FullMatrix identity (dealii::IdentityMatrix(pth_deriv.m())); + for(int idim=0; idim pth_deriv_dim(n_dofs); + if(idim==0){ + pth_deriv_dim = this->tensor_product_state(nstate, pth_deriv, identity, identity); + } + if(idim==1){ + pth_deriv_dim = this->tensor_product_state(nstate, identity, pth_deriv, identity); + } + if(idim==2){ + pth_deriv_dim = this->tensor_product_state(nstate, identity, identity, pth_deriv); + } + dealii::FullMatrix derivative_p_temp(n_dofs); + derivative_p_temp.add(FR_param, pth_deriv_dim); + dealii::FullMatrix Flux_Reconstruction_operator_temp(n_dofs); + derivative_p_temp.Tmmult(Flux_Reconstruction_operator_temp, mass_matrix); + Flux_Reconstruction_operator_temp.mmult(Flux_Reconstruction_operator, pth_deriv_dim, true); + } + if constexpr (dim>=2){ + const int deriv_2p_loop = (dim==2) ? 1 : dim; + double FR_param_sqrd = pow(FR_param,2.0); + for(int idim=0; idim pth_deriv_dim(n_dofs); + if(idim==0){ + pth_deriv_dim = this->tensor_product_state(nstate, pth_deriv, pth_deriv, identity); + } + if(idim==1){ + pth_deriv_dim = this->tensor_product_state(nstate, identity, pth_deriv, pth_deriv); + } + if(idim==2){ + pth_deriv_dim = this->tensor_product_state(nstate, pth_deriv, identity, pth_deriv); + } + dealii::FullMatrix derivative_p_temp(n_dofs); + derivative_p_temp.add(FR_param_sqrd, pth_deriv_dim); + dealii::FullMatrix Flux_Reconstruction_operator_temp(n_dofs); + derivative_p_temp.Tmmult(Flux_Reconstruction_operator_temp, mass_matrix); + Flux_Reconstruction_operator_temp.mmult(Flux_Reconstruction_operator, pth_deriv_dim, true); } + } + if constexpr (dim == 3){ + double FR_param_cubed = pow(FR_param,3.0); + dealii::FullMatrix pth_deriv_dim(n_dofs); + pth_deriv_dim = this->tensor_product_state(nstate, pth_deriv, pth_deriv, pth_deriv); + dealii::FullMatrix derivative_p_temp(n_dofs); + derivative_p_temp.add(FR_param_cubed, pth_deriv_dim); + dealii::FullMatrix Flux_Reconstruction_operator_temp(n_dofs); + derivative_p_temp.Tmmult(Flux_Reconstruction_operator_temp, mass_matrix); + Flux_Reconstruction_operator_temp.mmult(Flux_Reconstruction_operator, pth_deriv_dim, true); + } + + return Flux_Reconstruction_operator; +} + +template +dealii::FullMatrix local_Flux_Reconstruction_operator::build_dim_Flux_Reconstruction_operator( + const dealii::FullMatrix &local_Mass_Matrix, + const int nstate, + const unsigned int n_dofs) +{ + dealii::FullMatrix dim_FR_operator(n_dofs); + if constexpr (dim == 1){ + dim_FR_operator = this->oneD_vol_operator; + } + if (dim >= 2){ + dealii::FullMatrix FR1(n_dofs); + FR1 = this->tensor_product_state(nstate, this->oneD_vol_operator, local_Mass_Matrix, local_Mass_Matrix); + dealii::FullMatrix FR2(n_dofs); + FR2 = this->tensor_product_state(nstate, local_Mass_Matrix, this->oneD_vol_operator, local_Mass_Matrix); + dealii::FullMatrix FR_cross1(n_dofs); + FR_cross1 = this->tensor_product_state(nstate, this->oneD_vol_operator, this->oneD_vol_operator, local_Mass_Matrix); + dim_FR_operator.add(1.0, FR1, 1.0, FR2, 1.0, FR_cross1); + } + if constexpr (dim == 3){ + dealii::FullMatrix FR3(n_dofs); + FR3 = this->tensor_product_state(nstate, local_Mass_Matrix, local_Mass_Matrix, this->oneD_vol_operator); + dealii::FullMatrix FR_cross2(n_dofs); + FR_cross2 = this->tensor_product_state(nstate, this->oneD_vol_operator, local_Mass_Matrix, this->oneD_vol_operator); + dealii::FullMatrix FR_cross3(n_dofs); + FR_cross3 = this->tensor_product_state(nstate, local_Mass_Matrix, this->oneD_vol_operator, this->oneD_vol_operator); + dealii::FullMatrix FR_triple(n_dofs); + FR_triple = this->tensor_product_state(nstate, this->oneD_vol_operator, this->oneD_vol_operator, this->oneD_vol_operator); + dim_FR_operator.add(1.0, FR3, 1.0, FR_cross2, 1.0, FR_cross3); + dim_FR_operator.add(1.0, FR_triple); + } + return dim_FR_operator; + +} + + +template +local_Flux_Reconstruction_operator_aux::local_Flux_Reconstruction_operator_aux( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction_Aux FR_param_aux_input) + : local_Flux_Reconstruction_operator::local_Flux_Reconstruction_operator(nstate_input, max_degree_input, grid_degree_input, Parameters::AllParameters::Flux_Reconstruction::cDG) + , FR_param_aux_type(FR_param_aux_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; + //get the FR corrcetion parameter value + get_FR_aux_correction_parameter(this->max_degree, FR_param_aux); +} + +template +void local_Flux_Reconstruction_operator_aux::get_FR_aux_correction_parameter ( + const unsigned int curr_cell_degree, + double &k) +{ + using FR_Aux_enum = Parameters::AllParameters::Flux_Reconstruction_Aux; + if(FR_param_aux_type == FR_Aux_enum::kHU){ + this->get_Huynh_g2_parameter(curr_cell_degree, k); + } + else if(FR_param_aux_type == FR_Aux_enum::kSD){ + this->get_spectral_difference_parameter(curr_cell_degree, k); + } + else if(FR_param_aux_type == FR_Aux_enum::kNegative){ + this->get_c_negative_FR_parameter(curr_cell_degree, k); + } + else if(FR_param_aux_type == FR_Aux_enum::kNegative2){//knegative divided by 2 + this->get_c_negative_divided_by_two_FR_parameter(curr_cell_degree, k); + } + else if(FR_param_aux_type == FR_Aux_enum::kDG){ + k = 0.0; + } + else if(FR_param_aux_type == FR_Aux_enum::k10Thousand){ + k = 10000.0; + } + else if(FR_param_aux_type == FR_Aux_enum::kPlus){ + this->get_c_plus_parameter(curr_cell_degree, k); + } +} +template +void local_Flux_Reconstruction_operator_aux::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + //build the FR correction operator + derivative_p pth_derivative(this->nstate, this->max_degree, this->max_grid_degree); + pth_derivative.build_1D_volume_operator(finite_element, quadrature); + local_mass local_Mass_Matrix(this->nstate, this->max_degree, this->max_grid_degree); + local_Mass_Matrix.build_1D_volume_operator(finite_element, quadrature); + //allocate the volume operator + this->oneD_vol_operator.reinit(n_dofs, n_dofs); + //solves + this->build_local_Flux_Reconstruction_operator(local_Mass_Matrix.oneD_vol_operator, pth_derivative.oneD_vol_operator, n_dofs, FR_param_aux, this->oneD_vol_operator); +} - for(unsigned int iquad=0; iquad +vol_projection_operator::vol_projection_operator( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} - for(unsigned int igrid=0; igrid +void vol_projection_operator::compute_local_vol_projection_operator( + const dealii::FullMatrix &norm_matrix_inverse, + const dealii::FullMatrix &integral_vol_basis, + dealii::FullMatrix &volume_projection) +{ + norm_matrix_inverse.mTmult(volume_projection, integral_vol_basis); +} +template +void vol_projection_operator::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + const unsigned int n_quad_pts = quadrature.size(); + vol_integral_basis integral_vol_basis(this->nstate, this->max_degree, this->max_grid_degree); + integral_vol_basis.build_1D_volume_operator(finite_element, quadrature); + local_mass local_Mass_Matrix(this->nstate, this->max_degree, this->max_grid_degree); + local_Mass_Matrix.build_1D_volume_operator(finite_element, quadrature); + dealii::FullMatrix mass_inv(n_dofs); + mass_inv.invert(local_Mass_Matrix.oneD_vol_operator); + //allocate the volume operator + this->oneD_vol_operator.reinit(n_dofs, n_quad_pts); + //solves + compute_local_vol_projection_operator(mass_inv, integral_vol_basis.oneD_vol_operator, this->oneD_vol_operator); +} + +template +vol_projection_operator_FR::vol_projection_operator_FR( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction FR_param_input, + const bool store_transpose_input) + : vol_projection_operator::vol_projection_operator(nstate_input, max_degree_input, grid_degree_input) + , store_transpose(store_transpose_input) + , FR_param_type(FR_param_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} + +template +void vol_projection_operator_FR::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + const unsigned int n_quad_pts = quadrature.size(); + vol_integral_basis integral_vol_basis(this->nstate, this->max_degree, this->max_grid_degree); + integral_vol_basis.build_1D_volume_operator(finite_element, quadrature); + FR_mass_inv local_FR_Mass_Matrix_inv(this->nstate, this->max_degree, this->max_grid_degree, FR_param_type); + local_FR_Mass_Matrix_inv.build_1D_volume_operator(finite_element, quadrature); + //allocate the volume operator + this->oneD_vol_operator.reinit(n_dofs, n_quad_pts); + //solves + this->compute_local_vol_projection_operator(local_FR_Mass_Matrix_inv.oneD_vol_operator, integral_vol_basis.oneD_vol_operator, this->oneD_vol_operator); + + if(store_transpose){ + oneD_transpose_vol_operator.reinit(n_quad_pts, n_dofs); + oneD_transpose_vol_operator.Tadd(1.0, this->oneD_vol_operator); + } +} +template +vol_projection_operator_FR_aux::vol_projection_operator_FR_aux( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction_Aux FR_param_input, + const bool store_transpose_input) + : vol_projection_operator::vol_projection_operator(nstate_input, max_degree_input, grid_degree_input) + , store_transpose(store_transpose_input) + , FR_param_type(FR_param_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} - metric_cofactor[iquad][0][0] += gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][2][iquad][igrid] * Ta[igrid] - - gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][1][iquad][igrid] * Tb[igrid]; +template +void vol_projection_operator_FR_aux::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + const unsigned int n_quad_pts = quadrature.size(); + vol_integral_basis integral_vol_basis(this->nstate, this->max_degree, this->max_grid_degree); + integral_vol_basis.build_1D_volume_operator(finite_element, quadrature); + FR_mass_inv_aux local_FR_Mass_Matrix_inv(this->nstate, this->max_degree, this->max_grid_degree, FR_param_type); + local_FR_Mass_Matrix_inv.build_1D_volume_operator(finite_element, quadrature); + //allocate the volume operator + this->oneD_vol_operator.reinit(n_dofs, n_quad_pts); + //solves + this->compute_local_vol_projection_operator(local_FR_Mass_Matrix_inv.oneD_vol_operator, integral_vol_basis.oneD_vol_operator, this->oneD_vol_operator); + + if(store_transpose){ + oneD_transpose_vol_operator.reinit(n_quad_pts, n_dofs); + oneD_transpose_vol_operator.Tadd(1.0, this->oneD_vol_operator); + } +} - metric_cofactor[iquad][1][0] += gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][2][iquad][igrid] * Td[igrid] - - gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][1][iquad][igrid] * Te[igrid]; +template +FR_mass_inv::FR_mass_inv( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction FR_param_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) + , FR_param_type(FR_param_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} - metric_cofactor[iquad][2][0] += gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][2][iquad][igrid] * Tg[igrid] - - gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][1][iquad][igrid] * Th[igrid]; +template +void FR_mass_inv::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + local_mass local_Mass_Matrix(this->nstate, this->max_degree, this->max_grid_degree); + local_Mass_Matrix.build_1D_volume_operator(finite_element, quadrature); + local_Flux_Reconstruction_operator local_FR_oper(this->nstate, this->max_degree, this->max_grid_degree, FR_param_type); + local_FR_oper.build_1D_volume_operator(finite_element, quadrature); + dealii::FullMatrix FR_mass_matrix(n_dofs); + FR_mass_matrix.add(1.0, local_Mass_Matrix.oneD_vol_operator, 1.0, local_FR_oper.oneD_vol_operator); + //allocate the volume operator + this->oneD_vol_operator.reinit(n_dofs, n_dofs); + //solves + this->oneD_vol_operator.invert(FR_mass_matrix); +} +template +FR_mass_inv_aux::FR_mass_inv_aux( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction_Aux FR_param_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) + , FR_param_type(FR_param_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} - metric_cofactor[iquad][0][1] += gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][0][iquad][igrid] * Tb[igrid] - - gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][2][iquad][igrid] * Tc[igrid]; +template +void FR_mass_inv_aux::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + local_mass local_Mass_Matrix(this->nstate, this->max_degree, this->max_grid_degree); + local_Mass_Matrix.build_1D_volume_operator(finite_element, quadrature); + local_Flux_Reconstruction_operator_aux local_FR_oper(this->nstate, this->max_degree, this->max_grid_degree, FR_param_type); + local_FR_oper.build_1D_volume_operator(finite_element, quadrature); + dealii::FullMatrix FR_mass_matrix(n_dofs); + FR_mass_matrix.add(1.0, local_Mass_Matrix.oneD_vol_operator, 1.0, local_FR_oper.oneD_vol_operator); + //allocate the volume operator + this->oneD_vol_operator.reinit(n_dofs, n_dofs); + //solves + this->oneD_vol_operator.invert(FR_mass_matrix); +} +template +FR_mass::FR_mass( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction FR_param_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) + , FR_param_type(FR_param_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} - metric_cofactor[iquad][1][1] += gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][0][iquad][igrid] * Te[igrid] - - gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][2][iquad][igrid] * Tf[igrid]; +template +void FR_mass::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + local_mass local_Mass_Matrix(this->nstate, this->max_degree, this->max_grid_degree); + local_Mass_Matrix.build_1D_volume_operator(finite_element, quadrature); + local_Flux_Reconstruction_operator local_FR_oper(this->nstate, this->max_degree, this->max_grid_degree, FR_param_type); + local_FR_oper.build_1D_volume_operator(finite_element, quadrature); + dealii::FullMatrix FR_mass_matrix(n_dofs); + FR_mass_matrix.add(1.0, local_Mass_Matrix.oneD_vol_operator, 1.0, local_FR_oper.oneD_vol_operator); + //allocate the volume operator + this->oneD_vol_operator.reinit(n_dofs, n_dofs); + //solves + this->oneD_vol_operator.add(1.0, FR_mass_matrix); +} +template +FR_mass_aux::FR_mass_aux( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction_Aux FR_param_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) + , FR_param_type(FR_param_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} - metric_cofactor[iquad][2][1] += gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][0][iquad][igrid] * Th[igrid] - - gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][2][iquad][igrid] * Ti[igrid]; +template +void FR_mass_aux::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + local_mass local_Mass_Matrix(this->nstate, this->max_degree, this->max_grid_degree); + local_Mass_Matrix.build_1D_volume_operator(finite_element, quadrature); + local_Flux_Reconstruction_operator_aux local_FR_oper(this->nstate, this->max_degree, this->max_grid_degree, FR_param_type); + local_FR_oper.build_1D_volume_operator(finite_element, quadrature); + dealii::FullMatrix FR_mass_matrix(n_dofs); + FR_mass_matrix.add(1.0, local_Mass_Matrix.oneD_vol_operator, 1.0, local_FR_oper.oneD_vol_operator); + //allocate the volume operator + this->oneD_vol_operator.reinit(n_dofs, n_dofs); + //solves + this->oneD_vol_operator.add(1.0, FR_mass_matrix); +} +template +vol_integral_gradient_basis::vol_integral_gradient_basis( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} - metric_cofactor[iquad][0][2] += gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][1][iquad][igrid] * Tc[igrid] - - gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][0][iquad][igrid] * Ta[igrid]; +template +void vol_integral_gradient_basis::build_1D_gradient_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_quad_pts = quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + //allocate + this->oneD_grad_operator.reinit(n_quad_pts, n_dofs); + //loop and store + const std::vector &quad_weights = quadrature.get_weights (); + for(unsigned int itest=0; itest qpoint = quadrature.point(iquad); + this->oneD_grad_operator[iquad][itest] = finite_element.shape_grad_component(itest, qpoint, istate_test)[0] + * quad_weights[iquad]; + } + } +} - metric_cofactor[iquad][1][2] += gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][1][iquad][igrid] * Tf[igrid] - - gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][0][iquad][igrid] * Td[igrid]; +/************************************* +* +* SURFACE OPERATORS +* +*************************************/ - metric_cofactor[iquad][2][2] += gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][1][iquad][igrid] * Ti[igrid] - - gradient_mapping_shape_functions_face_flux_nodes[grid_degree][poly_degree][iface][0][iquad][igrid] * Tg[igrid]; +template +face_integral_basis::face_integral_basis( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} +template +void face_integral_basis::build_1D_surface_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &face_quadrature) +{ + const unsigned int n_face_quad_pts = face_quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + const unsigned int n_faces_1D = n_faces / dim; + const std::vector &quad_weights = face_quadrature.get_weights (); + //loop and store + for(unsigned int iface=0; ifaceoneD_surf_operator[iface].reinit(n_face_quad_pts, n_dofs); + //sum factorized operators use a 1D element. + const dealii::Quadrature<1> quadrature = dealii::QProjector<1>::project_to_face(dealii::ReferenceCell::get_hypercube(1), + face_quadrature, + iface); + for(unsigned int iquad=0; iquad qpoint = quadrature.point(iquad); + for(unsigned int idof=0; idofoneD_surf_operator[iface][iquad][idof] = finite_element.shape_value_component(idof,qpoint,istate) + * quad_weights[iquad]; } + } + } +} + +template +lifting_operator::lifting_operator( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} + +template +void lifting_operator::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + local_mass local_Mass_Matrix(this->nstate, this->max_degree, this->max_grid_degree); + local_Mass_Matrix.build_1D_volume_operator(finite_element, quadrature); + //allocate the volume operator + this->oneD_vol_operator.reinit(n_dofs, n_dofs); + //solves + this->oneD_vol_operator.add(1.0, local_Mass_Matrix.oneD_vol_operator); +} +template +void lifting_operator::build_local_surface_lifting_operator( + const unsigned int n_dofs, + const dealii::FullMatrix &norm_matrix, + const dealii::FullMatrix &face_integral, + dealii::FullMatrix &lifting) +{ + dealii::FullMatrix norm_inv(n_dofs); + norm_inv.invert(norm_matrix); + norm_inv.mTmult(lifting, face_integral); +} +template +void lifting_operator::build_1D_surface_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &face_quadrature) +{ + const unsigned int n_face_quad_pts = face_quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + const unsigned int n_faces_1D = n_faces / dim; + //create surface integral of basis functions + face_integral_basis basis_int_facet(this->nstate, this->max_degree, this->max_grid_degree); + basis_int_facet.build_1D_surface_operator(finite_element, face_quadrature); + //loop and store + for(unsigned int iface=0; ifaceoneD_surf_operator[iface].reinit(n_dofs, n_face_quad_pts); + build_local_surface_lifting_operator(n_dofs, this->oneD_vol_operator, basis_int_facet.oneD_surf_operator[iface], this->oneD_surf_operator[iface]); + } +} + +template +lifting_operator_FR::lifting_operator_FR( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction FR_param_input) + : lifting_operator::lifting_operator(nstate_input, max_degree_input, grid_degree_input) + , FR_param_type(FR_param_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} + +template +void lifting_operator_FR::build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_dofs = finite_element.dofs_per_cell; + local_mass local_Mass_Matrix(this->nstate, this->max_degree, this->max_grid_degree); + local_Mass_Matrix.build_1D_volume_operator(finite_element, quadrature); + local_Flux_Reconstruction_operator local_FR(this->nstate, this->max_degree, this->max_grid_degree, FR_param_type); + local_FR.build_1D_volume_operator(finite_element, quadrature); + //allocate the volume operator + this->oneD_vol_operator.reinit(n_dofs, n_dofs); + //solves + this->oneD_vol_operator.add(1.0, local_Mass_Matrix.oneD_vol_operator); + this->oneD_vol_operator.add(1.0, local_FR.oneD_vol_operator); +} +template +void lifting_operator_FR::build_1D_surface_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &face_quadrature) +{ + const unsigned int n_face_quad_pts = face_quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + const unsigned int n_faces_1D = n_faces / dim; + //create surface integral of basis functions + face_integral_basis basis_int_facet(this->nstate, this->max_degree, this->max_grid_degree); + basis_int_facet.build_1D_surface_operator(finite_element, face_quadrature); + //loop and store + for(unsigned int iface=0; ifaceoneD_surf_operator[iface].reinit(n_dofs, n_face_quad_pts); + this->build_local_surface_lifting_operator(n_dofs, this->oneD_vol_operator, basis_int_facet.oneD_surf_operator[iface], this->oneD_surf_operator[iface]); + } +} + + +/****************************************************************************** +* +* METRIC MAPPING OPERATORS +* +******************************************************************************/ + +template +mapping_shape_functions::mapping_shape_functions( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) + , mapping_shape_functions_grid_nodes(nstate_input, max_degree_input, grid_degree_input) + , mapping_shape_functions_flux_nodes(nstate_input, max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; + current_grid_degree = grid_degree_input; +} + +template +void mapping_shape_functions::build_1D_shape_functions_at_grid_nodes( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + assert(finite_element.dofs_per_cell == quadrature.size());//checks collocation + mapping_shape_functions_grid_nodes.build_1D_volume_operator(finite_element, quadrature); + mapping_shape_functions_grid_nodes.build_1D_gradient_operator(finite_element, quadrature); +} +template +void mapping_shape_functions::build_1D_shape_functions_at_flux_nodes( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature, + const dealii::Quadrature<0> &face_quadrature) +{ + mapping_shape_functions_flux_nodes.build_1D_volume_operator(finite_element, quadrature); + mapping_shape_functions_flux_nodes.build_1D_gradient_operator(finite_element, quadrature); + mapping_shape_functions_flux_nodes.build_1D_surface_operator(finite_element, face_quadrature); + mapping_shape_functions_flux_nodes.build_1D_surface_gradient_operator(finite_element, face_quadrature); +} +template +void mapping_shape_functions::build_1D_shape_functions_at_volume_flux_nodes( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + mapping_shape_functions_flux_nodes.build_1D_volume_operator(finite_element, quadrature); + mapping_shape_functions_flux_nodes.build_1D_gradient_operator(finite_element, quadrature); +} + +/*********************************************** +* +* METRIC DET JAC AND COFACTOR +* +************************************************/ +//Constructor +template +metric_operators::metric_operators( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const bool store_vol_flux_nodes_input, + const bool store_surf_flux_nodes_input, + const bool store_Jacobian_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate_input, max_degree_input, grid_degree_input) + , store_Jacobian(store_Jacobian_input) + , store_vol_flux_nodes(store_vol_flux_nodes_input) + , store_surf_flux_nodes(store_surf_flux_nodes_input) +{} + +template +void metric_operators::transform_physical_to_reference( + const dealii::Tensor<1,dim,real> &phys, + const dealii::Tensor<2,dim,real> &metric_cofactor, + dealii::Tensor<1,dim,real> &ref) +{ + for(int idim=0; idim +void metric_operators::transform_reference_to_physical( + const dealii::Tensor<1,dim,real> &ref, + const dealii::Tensor<2,dim,real> &metric_cofactor, + dealii::Tensor<1,dim,real> &phys) +{ + for(int idim=0; idim> grad_Xl_grad_Xm(n_quad_pts);//gradient of gradient of mapping support points at Flux nodes - //for the curl of interp at flux nodes - //ie/ \nabla ( x_l * \nabla(x_m)) - std::vector> Xl_grad_Xm(n_metric_dofs);//(x_l * \nabla(x_m)) evaluated at GRID NODES - compute_Xl_grad_Xm(grid_degree, n_metric_dofs, mapping_support_points, Xl_grad_Xm); - //now get the derivative of X_l*nabla(X_m) evaluated at the quadrature/flux nodes - for(unsigned int iquad=0; iquad +void metric_operators::transform_physical_to_reference_vector( + const dealii::Tensor<1,dim,std::vector> &phys, + const dealii::Tensor<2,dim,std::vector> &metric_cofactor, + dealii::Tensor<1,dim,std::vector> &ref) +{ + assert(phys[0].size() == metric_cofactor[0][0].size()); + const unsigned int n_pts = phys[0].size(); + for(int idim=0; idim -void OperatorBase::compute_Xl_grad_Xm( - const unsigned int grid_degree, - const unsigned int n_metric_dofs, - const std::vector> &mapping_support_points, - std::vector> &Xl_grad_Xm) + +template +void metric_operators::transform_reference_unit_normal_to_physical_unit_normal( + const unsigned int n_quad_pts, + const dealii::Tensor<1,dim,real> &ref, + const dealii::Tensor<2,dim,std::vector> &metric_cofactor, + std::vector> &phys) { - std::vector> grad_Xm(n_metric_dofs);//gradient of mapping support points at Grid nodes - for(unsigned int iquad=0; iquad +void metric_operators::build_determinant_volume_metric_Jacobian( + const unsigned int n_quad_pts, + const unsigned int /*n_metric_dofs*/,//dofs of metric basis. NOTE: this is the number of mapping support points + const std::array,dim> &mapping_support_points, + mapping_shape_functions &mapping_basis) +{ + det_Jac_vol.resize(n_quad_pts); + //compute determinant of metric Jacobian + build_determinant_metric_Jacobian( + n_quad_pts, + mapping_support_points, + mapping_basis.mapping_shape_functions_flux_nodes.oneD_vol_operator, + mapping_basis.mapping_shape_functions_flux_nodes.oneD_vol_operator, + mapping_basis.mapping_shape_functions_flux_nodes.oneD_vol_operator, + mapping_basis.mapping_shape_functions_flux_nodes.oneD_grad_operator, + mapping_basis.mapping_shape_functions_flux_nodes.oneD_grad_operator, + mapping_basis.mapping_shape_functions_flux_nodes.oneD_grad_operator, + det_Jac_vol); +} + +template +void metric_operators::build_volume_metric_operators( + const unsigned int n_quad_pts, + const unsigned int n_metric_dofs,//dofs of metric basis. NOTE: this is the number of mapping support points + const std::array,dim> &mapping_support_points, + mapping_shape_functions &mapping_basis, + const bool use_invariant_curl_form) +{ + det_Jac_vol.resize(n_quad_pts); + for(int idim=0; idimmatrix_vector_mult(mapping_support_points[idim], + flux_nodes_vol[idim], + mapping_basis.mapping_shape_functions_flux_nodes.oneD_vol_operator, + mapping_basis.mapping_shape_functions_flux_nodes.oneD_vol_operator, + mapping_basis.mapping_shape_functions_flux_nodes.oneD_vol_operator); + } + } +} + +template +void metric_operators::build_facet_metric_operators( + const unsigned int iface, + const unsigned int n_quad_pts, + const unsigned int n_metric_dofs,//dofs of metric basis. NOTE: this is the number of mapping support points + const std::array,dim> &mapping_support_points, + mapping_shape_functions &mapping_basis, + const bool use_invariant_curl_form) +{ + det_Jac_surf.resize(n_quad_pts); + for(int idim=0; idimmatrix_vector_mult(mapping_support_points[idim], + flux_nodes_surf[iface][idim], + (iface == 0) ? mapping_basis.mapping_shape_functions_flux_nodes.oneD_surf_operator[0] : + ((iface == 1) ? mapping_basis.mapping_shape_functions_flux_nodes.oneD_surf_operator[1] : + mapping_basis.mapping_shape_functions_flux_nodes.oneD_vol_operator), + (iface == 2) ? mapping_basis.mapping_shape_functions_flux_nodes.oneD_surf_operator[0] : + ((iface == 3) ? mapping_basis.mapping_shape_functions_flux_nodes.oneD_surf_operator[1] : + mapping_basis.mapping_shape_functions_flux_nodes.oneD_vol_operator), + (iface == 4) ? mapping_basis.mapping_shape_functions_flux_nodes.oneD_surf_operator[0] : + ((iface == 5) ? mapping_basis.mapping_shape_functions_flux_nodes.oneD_surf_operator[1] : + mapping_basis.mapping_shape_functions_flux_nodes.oneD_vol_operator)); } - if(ndim == 0){ - ldim = dim - 1; + } + } +} + +template +void metric_operators::build_metric_Jacobian( + const unsigned int n_quad_pts, + const std::array,dim> &mapping_support_points, + const dealii::FullMatrix &basis_x_flux_nodes, + const dealii::FullMatrix &basis_y_flux_nodes, + const dealii::FullMatrix &basis_z_flux_nodes, + const dealii::FullMatrix &grad_basis_x_flux_nodes, + const dealii::FullMatrix &grad_basis_y_flux_nodes, + const dealii::FullMatrix &grad_basis_z_flux_nodes, + std::vector> &local_Jac) +{ + for(int idim=0; idim output_vect(pow(n_quad_pts_1D,dim)); + std::vector output_vect(n_quad_pts); + if(jdim == 0) + this->matrix_vector_mult(mapping_support_points[idim], output_vect, + grad_basis_x_flux_nodes, + basis_y_flux_nodes, + basis_z_flux_nodes); + if(jdim == 1) + this->matrix_vector_mult(mapping_support_points[idim], output_vect, + basis_x_flux_nodes, + grad_basis_y_flux_nodes, + basis_z_flux_nodes); + if(jdim == 2) + this->matrix_vector_mult(mapping_support_points[idim], output_vect, + basis_x_flux_nodes, + basis_y_flux_nodes, + grad_basis_z_flux_nodes); + for(unsigned int iquad=0; iquad +void metric_operators::build_determinant_metric_Jacobian( + const unsigned int n_quad_pts,//number volume quad pts + const std::array,dim> &mapping_support_points, + const dealii::FullMatrix &basis_x_flux_nodes, + const dealii::FullMatrix &basis_y_flux_nodes, + const dealii::FullMatrix &basis_z_flux_nodes, + const dealii::FullMatrix &grad_basis_x_flux_nodes, + const dealii::FullMatrix &grad_basis_y_flux_nodes, + const dealii::FullMatrix &grad_basis_z_flux_nodes, + std::vector &det_metric_Jac) +{ + //mapping support points must be passed as a vector[dim][n_metric_dofs] + assert(pow(this->max_grid_degree+1,dim) == mapping_support_points[0].size()); + + std::vector> Jacobian_flux_nodes(n_quad_pts); + this->build_metric_Jacobian(n_quad_pts, + mapping_support_points, + basis_x_flux_nodes, + basis_y_flux_nodes, + basis_z_flux_nodes, + grad_basis_x_flux_nodes, + grad_basis_y_flux_nodes, + grad_basis_z_flux_nodes, + Jacobian_flux_nodes); + if(store_Jacobian){ + for(int idim=0; idim +void metric_operators::build_local_metric_cofactor_matrix( + const unsigned int n_quad_pts,//number flux pts + const unsigned int n_metric_dofs,//dofs of metric basis. NOTE: this is the number of mapping support points + const std::array,dim> &mapping_support_points, + const dealii::FullMatrix &basis_x_grid_nodes, + const dealii::FullMatrix &basis_y_grid_nodes, + const dealii::FullMatrix &basis_z_grid_nodes, + const dealii::FullMatrix &basis_x_flux_nodes, + const dealii::FullMatrix &basis_y_flux_nodes, + const dealii::FullMatrix &basis_z_flux_nodes, + const dealii::FullMatrix &grad_basis_x_grid_nodes, + const dealii::FullMatrix &grad_basis_y_grid_nodes, + const dealii::FullMatrix &grad_basis_z_grid_nodes, + const dealii::FullMatrix &grad_basis_x_flux_nodes, + const dealii::FullMatrix &grad_basis_y_flux_nodes, + const dealii::FullMatrix &grad_basis_z_flux_nodes, + dealii::Tensor<2,dim,std::vector> &metric_cofactor, + const bool use_invariant_curl_form) +{ + //mapping support points must be passed as a vector[dim][n_metric_dofs] + //Solve for Cofactor + if (dim == 1){//constant for 1D + std::fill(metric_cofactor[0][0].begin(), metric_cofactor[0][0].end(), 1.0); + } + if (dim == 2){ + std::vector> Jacobian_flux_nodes(n_quad_pts); + this->build_metric_Jacobian(n_quad_pts, + mapping_support_points, + basis_x_flux_nodes, + basis_y_flux_nodes, + basis_z_flux_nodes, + grad_basis_x_flux_nodes, + grad_basis_y_flux_nodes, + grad_basis_z_flux_nodes, + Jacobian_flux_nodes); + for(unsigned int iquad=0; iquad +void metric_operators::compute_local_3D_cofactor( + const unsigned int n_metric_dofs, + const unsigned int /*n_quad_pts*/, + const std::array,dim> &mapping_support_points, + const dealii::FullMatrix &basis_x_grid_nodes, + const dealii::FullMatrix &basis_y_grid_nodes, + const dealii::FullMatrix &basis_z_grid_nodes, + const dealii::FullMatrix &basis_x_flux_nodes, + const dealii::FullMatrix &basis_y_flux_nodes, + const dealii::FullMatrix &basis_z_flux_nodes, + const dealii::FullMatrix &grad_basis_x_grid_nodes, + const dealii::FullMatrix &grad_basis_y_grid_nodes, + const dealii::FullMatrix &grad_basis_z_grid_nodes, + const dealii::FullMatrix &grad_basis_x_flux_nodes, + const dealii::FullMatrix &grad_basis_y_flux_nodes, + const dealii::FullMatrix &grad_basis_z_flux_nodes, + dealii::Tensor<2,dim,std::vector> &metric_cofactor, + const bool use_invariant_curl_form) +{ + //Conservative Curl Form + + //compute grad Xm, NOTE: it is the same as the Jacobian at Grid Nodes + std::vector> grad_Xm(n_metric_dofs);//gradient of mapping support points at Grid Nodes + this->build_metric_Jacobian(n_metric_dofs, + mapping_support_points, + basis_x_grid_nodes, + basis_y_grid_nodes, + basis_z_grid_nodes, + grad_basis_x_grid_nodes, + grad_basis_y_grid_nodes, + grad_basis_z_grid_nodes, + grad_Xm); + + //Store Xl * grad Xm using fact the mapping shape functions collocated on Grid Nodes. + //Also, we only store the ones needed, not all to reduce computational cost. + std::vector z_dy_dxi(n_metric_dofs); + std::vector z_dy_deta(n_metric_dofs); + std::vector z_dy_dzeta(n_metric_dofs); + + std::vector x_dz_dxi(n_metric_dofs); + std::vector x_dz_deta(n_metric_dofs); + std::vector x_dz_dzeta(n_metric_dofs); + + std::vector y_dx_dxi(n_metric_dofs); + std::vector y_dx_deta(n_metric_dofs); + std::vector y_dx_dzeta(n_metric_dofs); + + for(unsigned int grid_node=0; grid_nodematrix_vector_mult(z_dy_dzeta, metric_cofactor[0][0], + basis_x_flux_nodes, grad_basis_y_flux_nodes, basis_z_flux_nodes, false, -1.0); + this->matrix_vector_mult(z_dy_deta, metric_cofactor[0][0], + basis_x_flux_nodes, basis_y_flux_nodes, grad_basis_z_flux_nodes, true); + //C12 + this->matrix_vector_mult(z_dy_dzeta, metric_cofactor[0][1], + grad_basis_x_flux_nodes, basis_y_flux_nodes, basis_z_flux_nodes); + this->matrix_vector_mult(z_dy_dxi, metric_cofactor[0][1], + basis_x_flux_nodes, basis_y_flux_nodes, grad_basis_z_flux_nodes, true, -1.0); + //C13 + this->matrix_vector_mult(z_dy_deta, metric_cofactor[0][2], + grad_basis_x_flux_nodes, basis_y_flux_nodes, basis_z_flux_nodes, false, -1.0); + this->matrix_vector_mult(z_dy_dxi, metric_cofactor[0][2], + basis_x_flux_nodes, grad_basis_y_flux_nodes, basis_z_flux_nodes, true); + + //C21 + this->matrix_vector_mult(x_dz_dzeta, metric_cofactor[1][0], + basis_x_flux_nodes, grad_basis_y_flux_nodes, basis_z_flux_nodes, false, -1.0); + this->matrix_vector_mult(x_dz_deta, metric_cofactor[1][0], + basis_x_flux_nodes, basis_y_flux_nodes, grad_basis_z_flux_nodes, true); + //C22 + this->matrix_vector_mult(x_dz_dzeta, metric_cofactor[1][1], + grad_basis_x_flux_nodes, basis_y_flux_nodes, basis_z_flux_nodes); + this->matrix_vector_mult(x_dz_dxi, metric_cofactor[1][1], + basis_x_flux_nodes, basis_y_flux_nodes, grad_basis_z_flux_nodes, true, -1.0); + //C23 + this->matrix_vector_mult(x_dz_deta, metric_cofactor[1][2], + grad_basis_x_flux_nodes, basis_y_flux_nodes, basis_z_flux_nodes, false, -1.0); + this->matrix_vector_mult(x_dz_dxi, metric_cofactor[1][2], + basis_x_flux_nodes, grad_basis_y_flux_nodes, basis_z_flux_nodes, true); + + //C31 + this->matrix_vector_mult(y_dx_dzeta, metric_cofactor[2][0], + basis_x_flux_nodes, grad_basis_y_flux_nodes, basis_z_flux_nodes, false, -1.0); + this->matrix_vector_mult(y_dx_deta, metric_cofactor[2][0], + basis_x_flux_nodes, basis_y_flux_nodes, grad_basis_z_flux_nodes, true); + //C32 + this->matrix_vector_mult(y_dx_dzeta, metric_cofactor[2][1], + grad_basis_x_flux_nodes, basis_y_flux_nodes, basis_z_flux_nodes); + this->matrix_vector_mult(y_dx_dxi, metric_cofactor[2][1], + basis_x_flux_nodes, basis_y_flux_nodes, grad_basis_z_flux_nodes, true, -1.0); + //C33 + this->matrix_vector_mult(y_dx_deta, metric_cofactor[2][2], + grad_basis_x_flux_nodes, basis_y_flux_nodes, basis_z_flux_nodes, false, -1.0); + this->matrix_vector_mult(y_dx_dxi, metric_cofactor[2][2], + basis_x_flux_nodes, grad_basis_y_flux_nodes, basis_z_flux_nodes, true); + +} + +/********************************** +* +* Sum Factorization STATE class +* +**********************************/ +//Constructor +template +SumFactorizedOperatorsState::SumFactorizedOperatorsState( + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperators::SumFactorizedOperators(nstate, max_degree_input, grid_degree_input) +{} + +template +basis_functions_state::basis_functions_state( + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperatorsState::SumFactorizedOperatorsState(max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} + +template +void basis_functions_state::build_1D_volume_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_quad_pts = quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + const unsigned int n_shape_fns = n_dofs / nstate; + //Note thate the flux basis should only have one state in the finite element. + //loop and store + for(unsigned int iquad=0; iquad qpoint = quadrature.point(iquad); + for(unsigned int idof=0; idofoneD_vol_state_operator[istate].reinit(n_quad_pts, n_shape_fns); + + //Basis function idof of poly degree idegree evaluated at cubature node qpoint. + this->oneD_vol_state_operator[istate][iquad][ishape] = finite_element.shape_value_component(idof,qpoint,istate); + } + } } -template -void OperatorBase::do_curl_loop_metric_cofactor( - const unsigned int n_quad_pts, - const std::vector> grad_Xl_grad_Xm, - std::vector> &metric_cofactor) + +template +void basis_functions_state::build_1D_gradient_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) { + const unsigned int n_quad_pts = quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + const unsigned int n_shape_fns = n_dofs / nstate; + //loop and store for(unsigned int iquad=0; iquad qpoint = quadrature.point(iquad); + for(unsigned int idof=0; idofoneD_grad_state_operator[istate].reinit(n_quad_pts, n_shape_fns); + + this->oneD_grad_state_operator[istate][iquad][ishape] = finite_element.shape_grad_component(idof, qpoint, istate)[0]; + } + } +} +template +void basis_functions_state::build_1D_surface_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &face_quadrature) +{ + const unsigned int n_face_quad_pts = face_quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + const unsigned int n_faces_1D = n_faces / dim; + const unsigned int n_shape_fns = n_dofs / nstate; + //loop and store + for(unsigned int iface=0; iface quadrature = dealii::QProjector<1>::project_to_face(dealii::ReferenceCell::get_hypercube(1), + face_quadrature, + iface); + for(unsigned int iquad=0; iquadoneD_surf_state_operator[istate][iface].reinit(n_face_quad_pts, n_shape_fns); + + this->oneD_surf_state_operator[istate][iface][iquad][ishape] = finite_element.shape_value_component(idof,quadrature.point(iquad),istate); } - else{ - jdim = idim + 1; + } + } +} + +template +flux_basis_functions_state::flux_basis_functions_state( + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : SumFactorizedOperatorsState::SumFactorizedOperatorsState(max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} + +template +void flux_basis_functions_state::build_1D_volume_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_quad_pts = quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + assert(n_dofs == n_quad_pts); + //Note thate the flux basis should only have one state in the finite element. + //loop and store + for(int istate=0; istateoneD_vol_state_operator[istate].reinit(n_quad_pts, n_dofs); + for(unsigned int iquad=0; iquad qpoint = quadrature.point(iquad); + for(unsigned int idof=0; idofoneD_vol_state_operator[istate][iquad][idof] = finite_element.shape_value_component(idof,qpoint,0); } - if(idim == 0){ - kdim = dim - 1; + } + } +} + +template +void flux_basis_functions_state::build_1D_gradient_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_quad_pts = quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + assert(n_dofs == n_quad_pts); + //loop and store + for(int istate=0; istateoneD_grad_state_operator[istate].reinit(n_quad_pts, n_dofs); + for(unsigned int iquad=0; iquad qpoint = quadrature.point(iquad); + for(unsigned int idof=0; idofoneD_grad_state_operator[istate][iquad][idof] = finite_element.shape_grad_component(idof, qpoint, 0)[0]; } - else{ - kdim = idim - 1; - }//computed cyclic index loop - // metric_cofactor[iquad][ndim][idim] = - (grad_Xl_grad_Xm[iquad][ndim][kdim][jdim] - grad_Xl_grad_Xm[iquad][ndim][jdim][kdim]); - metric_cofactor[iquad][idim][ndim] = - (grad_Xl_grad_Xm[iquad][ndim][kdim][jdim] - grad_Xl_grad_Xm[iquad][ndim][jdim][kdim]); - //index is idim then ndim to be consistent with inverse of Jacobian dealii notation and 2D equivalent + } + } +} +template +void flux_basis_functions_state::build_1D_surface_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &face_quadrature) +{ + const unsigned int n_face_quad_pts = face_quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + const unsigned int n_faces_1D = n_faces / dim; + //loop and store + for(unsigned int iface=0; iface quadrature = dealii::QProjector<1>::project_to_face(dealii::ReferenceCell::get_hypercube(1), + face_quadrature, + iface); + for(int istate=0; istateoneD_surf_state_operator[istate][iface].reinit(n_face_quad_pts, n_dofs); + for(unsigned int iquad=0; iquadoneD_surf_state_operator[istate][iface][iquad][idof] = finite_element.shape_value_component(idof,quadrature.point(iquad),0); + } } } } } +template +local_flux_basis_stiffness::local_flux_basis_stiffness( + const unsigned int max_degree_input, + const unsigned int grid_degree_input) + : flux_basis_functions_state::flux_basis_functions_state(max_degree_input, grid_degree_input) +{ + //Initialize to the max degrees + current_degree = max_degree_input; +} +template +void local_flux_basis_stiffness::build_1D_volume_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature) +{ + const unsigned int n_quad_pts = quadrature.size(); + const unsigned int n_dofs_flux = quadrature.size(); + const unsigned int n_dofs = finite_element.dofs_per_cell; + //loop and store + const std::vector &quad_weights = quadrature.get_weights (); + for(int istate_flux=0; istate_fluxoneD_vol_state_operator[istate_flux].reinit(n_dofs, n_quad_pts); + for(unsigned int itest=0; itest qpoint = quadrature.point(iquad); + value += finite_element.shape_value_component(itest, qpoint, istate_test) + * quad_weights[iquad] + * this->oneD_grad_state_operator[istate_flux][iquad][idof]; + } + this->oneD_vol_state_operator[istate_flux][itest][idof] = value; + } + } + } +} -template class OperatorBase ; -template class OperatorBase ; -template class OperatorBase ; -template class OperatorBase ; -template class OperatorBase ; +template class OperatorsBase ; + +template class SumFactorizedOperators ; + +template class SumFactorizedOperatorsState ; +template class SumFactorizedOperatorsState ; +template class SumFactorizedOperatorsState ; +template class SumFactorizedOperatorsState ; +template class SumFactorizedOperatorsState ; + +template class basis_functions ; +template class vol_integral_basis ; +template class local_mass ; +template class local_basis_stiffness ; +template class modal_basis_differential_operator ; +template class derivative_p ; +template class local_Flux_Reconstruction_operator ; +template class local_Flux_Reconstruction_operator_aux ; +template class vol_projection_operator ; +template class vol_projection_operator_FR ; +template class vol_projection_operator_FR_aux ; +template class FR_mass_inv ; +template class FR_mass_inv_aux ; +template class FR_mass ; +template class FR_mass_aux ; +template class vol_integral_gradient_basis ; + +//template class basis_at_facet_cubature ; +template class face_integral_basis ; +template class lifting_operator ; +template class lifting_operator_FR ; + +template class mapping_shape_functions ; + +template class metric_operators ; +//template class vol_metric_operators ; +//template class vol_determinant_metric_Jacobian; +//template class vol_metric_cofactor; +//template class surface_metric_cofactor; +// +template class basis_functions_state ; +template class basis_functions_state ; +template class basis_functions_state ; +template class basis_functions_state ; +template class basis_functions_state ; + +template class flux_basis_functions_state ; +template class flux_basis_functions_state ; +template class flux_basis_functions_state ; +template class flux_basis_functions_state ; +template class flux_basis_functions_state ; +template class local_flux_basis_stiffness ; +template class local_flux_basis_stiffness ; +template class local_flux_basis_stiffness ; +template class local_flux_basis_stiffness ; +template class local_flux_basis_stiffness ; } // OPERATOR namespace } // PHiLiP namespace + diff --git a/src/operators/operators.h b/src/operators/operators.h index 604e01983..6e268cfa4 100644 --- a/src/operators/operators.h +++ b/src/operators/operators.h @@ -12,7 +12,7 @@ #include #include #include - +#include #include @@ -32,13 +32,12 @@ #include #include - #include "parameters/all_parameters.h" #include "parameters/parameters.h" -#include "dg/dg.h" namespace PHiLiP { namespace OPERATOR { + ///Operator base class /** *This base class constructs 4 different types of operators: volume, surface, flux and metric. In addition it has corresponding functions to compute the operators. @@ -50,349 +49,1398 @@ namespace OPERATOR { * (3) Flux Operators: See above. It is important to note that since flux operators are "collocated" on the cubature set, the number of degrees of freedom of the flux basis MUST equal the number of cubature nodes. Importantly on the surface, the flux basis interpolates from the volume to the surface, thus corresponds to volume cubature nodes collocation. * (4) Metric Operators: Since the solution polynomial degree for each state varies, along with the local grid element's polynomial degree varying, the operators distinguish between polynomial degree (for solution or flux) and grid degree (for element). Explicitly, they first go vector of grid_degree, then vector of polynomial degree for the ones that are applied on the flux nodes. The mapping-support-points follow the standard from dealii, where they are always Gauss-Legendre-Lobatto quadrature nodes making the polynomial elements continuous in a sense. */ - -template -class OperatorBase +template +class OperatorsBase { public: -#if PHILIP_DIM==1 // dealii::parallel::distributed::Triangulation does not work for 1D - /** Triangulation to store the grid. - * In 1D, dealii::Triangulation is used. - * In 2D, 3D, dealii::parallel::distributed::Triangulation is used. - */ - using Triangulation = dealii::Triangulation; -#else - /** Triangulation to store the grid. - * In 1D, dealii::Triangulation is used. - * In 2D, 3D, dealii::parallel::distributed::Triangulation is used. - */ - using Triangulation = dealii::parallel::distributed::Triangulation; -#endif -public: - - - ///Constructor - OperatorBase( - const Parameters::AllParameters *const parameters_input, - const unsigned int degree,//degree not really needed at the moment + /// Constructor + OperatorsBase( + const int nstate_input,//number of states input const unsigned int max_degree_input,//max poly degree for operators const unsigned int grid_degree_input);//max grid degree for operators - ///Destructor - ~OperatorBase(); - + + /// Destructor + ~OperatorsBase() {}; - /// Input parameters. - const Parameters::AllParameters *const all_parameters; ///Max polynomial degree. const unsigned int max_degree; ///Max grid degree. const unsigned int max_grid_degree; + ///Number of states. + const int nstate; + +protected: + ///Check to see if the metrics used are a higher order then the initialized grid. + unsigned int max_grid_degree_check; + +public: + ///Returns the tensor product of matrices passed. + dealii::FullMatrix tensor_product( + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z); - /// Makes for cleaner doxygen documentation. - using MassiveCollectionTuple = std::tuple< - dealii::hp::FECollection, // Solution FE - dealii::hp::QCollection, // Volume quadrature - dealii::hp::QCollection, // Face quadrature - dealii::hp::QCollection<1>, // 1D quadrature for strong form - dealii::hp::FECollection >; // Lagrange polynomials for strong form - ///Second constructor call - /** Since a function is used to generate multiple different objects, a delegated - * constructor is used to unwrap the tuple and initialize the collections. - * - * The tuple is built from create_collection_tuple(). */ - OperatorBase( - const Parameters::AllParameters *const parameters_input, - const unsigned int degree, - const unsigned int max_degree_input, - const unsigned int grid_degree_input, - const MassiveCollectionTuple collection_tuple); - - ///The collection tuple. - MassiveCollectionTuple create_collection_tuple(const unsigned int max_degree, const Parameters::AllParameters *const parameters_input) const; - - ///The collections of FE (basis) and Quadrature sets. - const dealii::hp::FECollection fe_collection_basis; - /// Quadrature used to evaluate volume integrals. - dealii::hp::QCollection volume_quadrature_collection; - /// Quadrature used to evaluate face integrals. - dealii::hp::QCollection face_quadrature_collection; - /// 1D quadrature to generate Lagrange polynomials for the sake of flux interpolation. - dealii::hp::QCollection<1> oned_quadrature_collection; - ///Storing the "Flux" basis (basis collocated on flux volume nodes) previously referred to as the fe_collection_Lagrange. - const dealii::hp::FECollection fe_collection_flux_basis; - - ///Allocates the volume operators. - void allocate_volume_operators (); - ///Allocates the surface operators. - void allocate_surface_operators (); + ///Returns the tensor product of matrices passed, but makes it sparse diagonal by state. + /** An example for this would be a multi-state mass matrix. When the mass matrix + * is constructed, it is not templated by nstate. Also, if each 1D mass matrix is multi-state + * then their tensor product does not match the dim multi-state mass matrix. + * Instead, only if the states match, then do the tensor product. This results in a diagonal + * sparse matrix by state number, with each state's block being a dim-ordered tensor product. + */ + dealii::FullMatrix tensor_product_state( + const int nstate, + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z); ///Standard function to compute factorial of a number. double compute_factorial(double n); -protected: - /// Smart pointer to DGBase. - std::shared_ptr> dg; + ///virtual function to be defined. + virtual void matrix_vector_mult( + const std::vector &input_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z, + const bool adding = false, + const double factor = 1.0) = 0; + ///virtual function to be defined. + virtual void inner_product( + const std::vector &input_vect, + const std::vector &weight_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z, + const bool adding = false, + const double factor = 1.0) = 0; +protected: const MPI_Comm mpi_communicator; ///< MPI communicator. dealii::ConditionalOStream pcout; ///< Parallel std::cout that only outputs on mpi_rank==0 +};//End of OperatorsBase + +///Sum Factorization derived class. +/* All dim-sized operators are constructed by their one dimensional equivalent, and we use +* sum factorization to perform their operations. +* Note that we assume tensor product elements in this operators class. +*/ +template +class SumFactorizedOperators : public OperatorsBase +{ + +public: + /// Precompute 1D operator in constructor + SumFactorizedOperators( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + ///Destructor + ~SumFactorizedOperators () {}; + + ///Computes a matrix-vector product using sum-factorization. Pass the one-dimensional basis, where x runs the fastest, then y, and z runs the slowest. Also, assume each one-dimensional basis is the same size. + /** Uses sum-factorization with BLAS techniques to solve the the matrix-vector multiplication, where the matrix is the tensor product of three one-dimensional matrices. We use the standard notation that x runs the fastest, then y, and z runs the slowest. + * For an operator \f$\mathbf{A}\f$ of size \f$n^d\f$ with \f$n\f$ the one dimensional dofs + * and \f$ d\f$ the dim, for ouput row vector \f$ v \f$ and input row vector \f$ u \f$, + * we compute \f$v^T=\mathbf{A}u^T\f$. + * Lastly, the adding allows the result to add onto the previous output_vect scaled by "factor". + */ + void matrix_vector_mult( + const std::vector &input_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z, + const bool adding = false, + const double factor = 1.0) override; + ///Computes the divergence using the sum factorization matrix-vector multiplication. + /** Often, we compute a dot product in dim, where each matrix multiplictaion uses + * sum factorization. Example, consider taking the reference divergence of the reference flux: + * \f[ + * \nabla^r \cdot f^r = \frac{\partial f^r}{\partial \xi} + \frac{\partial f^r}{\partial \eta} + + * \frac{\partial f^r}{\partial \zeta} = + * \left( \frac{d \mathbf{\chi}(\mathbf{\xi})}{d\xi} \otimes \mathbf{\chi}(\mathbf{\eta}) \otimes \mathbf{\chi}(\mathbf{\zeta}) \right) \left(\hat{\mathbf{f}^r}\right)^T + * + \left( \mathbf{\chi}(\mathbf{\xi}) \otimes \frac{d\mathbf{\chi}(\mathbf{\eta})}{d\eta} \otimes \mathbf{\chi}(\mathbf{\zeta}) \right) \left(\hat{\mathbf{f}^r}\right)^T + * + \left( \mathbf{\chi}(\mathbf{\xi}) \otimes \mathbf{\chi}(\mathbf{\eta} \otimes \frac{d\mathbf{\chi}(\mathbf{\zeta})}{d\zeta})\right) \left(\hat{\mathbf{f}^r}\right)^T, + * \f] where we use sum factorization to evaluate each matrix-vector multiplication in each dim direction. + */ + void divergence_matrix_vector_mult( + const dealii::Tensor<1,dim,std::vector> &input_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z, + const dealii::FullMatrix &gradient_basis_x, + const dealii::FullMatrix &gradient_basis_y, + const dealii::FullMatrix &gradient_basis_z); + + ///Computes the divergence using sum-factorization where the basis are the same in each direction. + void divergence_matrix_vector_mult_1D( + const dealii::Tensor<1,dim,std::vector> &input_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis, + const dealii::FullMatrix &gradient_basis); + + ///Computes the gradient of a scalar using sum-factorization. + void gradient_matrix_vector_mult( + const std::vector &input_vect, + dealii::Tensor<1,dim,std::vector> &output_vect, + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z, + const dealii::FullMatrix &gradient_basis_x, + const dealii::FullMatrix &gradient_basis_y, + const dealii::FullMatrix &gradient_basis_z); + ///Computes the gradient of a scalar using sum-factorization where the basis are the same in each direction. + void gradient_matrix_vector_mult_1D( + const std::vector &input_vect, + dealii::Tensor<1,dim,std::vector> &output_vect, + const dealii::FullMatrix &basis, + const dealii::FullMatrix &gradient_basis); + + ///Computes the inner product between a matrix and a vector multiplied by some weight function. + /** That is, we compute \f$ \int Awu d\mathbf{\Omega}_r = \mathbf{A}^T \text{diag}(w) \mathbf{u}^T \f$. When using this function, pass \f$ \mathbf{A} \f$ and NOT it's transpose--the function transposes it in the first few lines. + */ + void inner_product( + const std::vector &input_vect, + const std::vector &weight_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis_x, + const dealii::FullMatrix &basis_y, + const dealii::FullMatrix &basis_z, + const bool adding = false, + const double factor = 1.0) override; + + + ///Computes the divergence of the 2pt flux Hadamard products, then sums the rows. + /** Note that we have the factor of 2.0 definied in this function. + * We also make use of the structure of the flux basis to get the matrix vector product after the Hadamard product + * to be \f$ \mathcal{O}(n^{d+1})\f$. + */ + void divergence_two_pt_flux_Hadamard_product( + const dealii::Tensor<1,dim,dealii::FullMatrix> &input_mat, + std::vector &output_vect, + const std::vector &weights, + const dealii::FullMatrix &basis, + const double scaling = 2.0);//the only direction that isn't identity + + + /// Computes the surface cross Hadamard products for skew-symmetric form from Eq. (15) in Chan, Jesse. "Skew-symmetric entropy stable modal discontinuous Galerkin formulations." Journal of Scientific Computing 81.1 (2019): 459-485. + void surface_two_pt_flux_Hadamard_product( + const dealii::FullMatrix &input_mat, + std::vector &output_vect_vol, + std::vector &output_vect_surf, + const std::vector &weights, + const std::array,2> &surf_basis, + const unsigned int iface, + const unsigned int dim_not_zero, + const double scaling = 2.0); + + ///Computes the Hadamard product ONLY for 2pt flux calculations. + /** + * The Hadamard product comes up naturally in calculcating 2-point fluxes, so we needed an efficient way to compute it. + * Using the commutative property of Hadamard products: \f$ (A \otimes B) \circ ( C \otimes D) = (A\circ C) \otimes (B\circ D) \f$, + * we can find a "sum-factorization" type expression for \f$ A \circ U \f$, where here \f$ A = A_x \otimes A_y \otimes A_z \f$ + * and \f$ U \f$ is an \f$ n \times n \f$ matrix.
+ * We make use of the flux basis being collocated on flux nodes, so the directions that aren't the derivative are identity. (Note that weights can be a diagonal matrix not necessarily identity). + * This results in the Hadamard product only needing \f$ \mathcal{O}(n^{d+1})\f$ flops to compute non-zero entries.
+ * This is NOT for GENERAL Hadamard products since those are \f$ \mathcal{O}(n^{2d})\f$ . + */ + void two_pt_flux_Hadamard_product( + const dealii::FullMatrix &input_mat, + dealii::FullMatrix &output_mat, + const dealii::FullMatrix &basis,//the only direction that isn't identity + const std::vector &weights,//vector storing diagonal entries for case not identity + const int direction);//direction for the derivative that corresponds to basis + + /// Apply the matrix vector operation using the 1D operator in each direction + /** This is for the case where the operator of size dim is the dyadic product of + * the same 1D operator in each direction + */ + void matrix_vector_mult_1D( + const std::vector &input_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis_x, + const bool adding = false, + const double factor = 1.0); + + /// Apply the inner product operation using the 1D operator in each direction + /* This is for the case where the operator of size dim is the dyadic product of + * the same 1D operator in each direction + */ + void inner_product_1D( + const std::vector &input_vect, + const std::vector &weight_vect, + std::vector &output_vect, + const dealii::FullMatrix &basis_x, + const bool adding = false, + const double factor = 1.0); + + /// Apply sum-factorization matrix vector multiplication on a surface. + /** Often times we have to interpolate to a surface, where in multiple dimensions, + * that's the tensor product of a surface operator with volume operators. This simplifies + * the function call. + * Explicitly, this passes basis_surf in the direction by face_number, and basis_vol + * in all other directions. + */ + void matrix_vector_mult_surface_1D( + const unsigned int face_number, + const std::vector &input_vect, + std::vector &output_vect, + const std::array,2> &basis_surf,//only 2 faces in 1D + const dealii::FullMatrix &basis_vol, + const bool adding = false, + const double factor = 1.0); + + /// Apply sum-factorization inner product on a surface. + void inner_product_surface_1D( + const unsigned int face_number, + const std::vector &input_vect, + const std::vector &weight_vect, + std::vector &output_vect, + const std::array,2> &basis_surf,//only 2 faces in 1D + const dealii::FullMatrix &basis_vol, + const bool adding = false, + const double factor = 1.0); + +protected: + ///Computes a single Hadamard product. + /** For input mat1 \f$ A \f$ and input mat2 \f$ B \f$, this computes + * \f$ A \circ B = C \implies \left( C \right)_{ij} = \left( A \right)_{ij}\left( B \right)_{ij}\f$. + */ + void Hadamard_product( + const dealii::FullMatrix &input_mat1, + const dealii::FullMatrix &input_mat2, + dealii::FullMatrix &output_mat); + +//protected: public: + ///Stores the one dimensional volume operator. + dealii::FullMatrix oneD_vol_operator; + + ///Stores the one dimensional surface operator. + /** Note that in 1D there are only 2 faces + */ + std::array,2> oneD_surf_operator; + + ///Stores the one dimensional gradient operator. + dealii::FullMatrix oneD_grad_operator; + + ///Stores the one dimensional surface gradient operator. + std::array,2> oneD_surf_grad_operator; + +};//End of SumFactorizedOperators Class + +/************************************************************************ +* +* VOLUME OPERATORS +* +************************************************************************/ + +///Basis functions. +/* This class stores the basis functions evaluated at volume and facet +* cubature nodes, as well as it's gradient in REFERENCE space. +*/ +template +class basis_functions : public SumFactorizedOperators +{ +public: + /// Constructor. + basis_functions ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + /// Destructor. + ~basis_functions () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); + + ///Assembles the one dimensional operator. + void build_1D_gradient_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); + + ///Assembles the one dimensional operator. + void build_1D_surface_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &quadrature); + + ///Assembles the one dimensional operator. + void build_1D_surface_gradient_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &quadrature); +}; + +///\f$ \mathbf{W}*\mathbf{\chi}(\mathbf{\xi}_v^r) \f$ That is Quadrature Weights multiplies with basis_at_vol_cubature. +template +class vol_integral_basis : public SumFactorizedOperators +{ +public: + /// Constructor. + vol_integral_basis ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + /// Destructor. + ~vol_integral_basis () {}; + + /// Stores the degree of the current poly degree. + unsigned int current_degree; + + /// Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); +}; + +///Local mass matrix without jacobian dependence. +template +class local_mass : public SumFactorizedOperators +{ +public: + /// Constructor. + local_mass ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + /// Destructor. + ~local_mass () {}; + + /// Stores the degree of the current poly degree. + unsigned int current_degree; - ///Solution basis functions evaluated at volume cubature nodes. - std::vector> basis_at_vol_cubature; - ///\f$ \mathbf{W}*\mathbf{\chi}(\mathbf{\xi}_v^r) \f$ That is Quadrature Weights multiplies with basis_at_vol_cubature. - std::vector> vol_integral_basis; - ///The flux basis functions evaluated at volume cubature nodes. - /**Flux (over int) basis functions evaluated at volume cubature nodes (should always be identity). - *NOTE THE FLUX BASIS IS COLLOCATED ON FLUX NODES - *so it does not have vector state embedded in its degrees of freedom, so we make the operator have a vector by state, ie/ - *\f$\text{n_dofs_for_solution_basis} = \text{nstate} *pow(p+1,dim)\f$ - *but \f$\text{n_dofs_flux_basis} = pow(p+1,dim)\f$. - *Also flux basis has an extra vector by nstate so that we can use .vmult later on with state vectors (in the residuals) - *So example flux_basis_at_vol_cubature[poly_degree][state_number][test_functions_for_state_number][flux_basis_shape_functions] - */ - std::vector>> flux_basis_at_vol_cubature; - ///Gradient of flux basis functions evaluated at volume cubature nodes. - /**Note that since it is gradient and not derivative, it is a tensor of dim. - */ - std::vector>>> gradient_flux_basis; - ///This is the solution basis \f$\mathbf{D}_i\f$, the modal differential opertaor commonly seen in DG defined as \f$\mathbf{D}_i=\mathbf{M}^{-1}*\mathbf{S}_i\f$. - std::vector>> modal_basis_differential_operator; - ///Local mass matrix without jacobian dependence. - std::vector> local_mass; - ///Local stiffness matrix without jacobian dependence. - /**NOTE: this is not used in DG volume integral since that needs to use the derivative of the flux basis and is multiplied by flux at volume cubature nodes this is strictly for consturtcing D operator - *\f[ + /// Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); //override; + + /// Assemble the dim mass matrix on the fly with metric Jacobian dependence. + /** Note: n_shape_functions is not the same as n_dofs, but the number of + * shape functions for the state. + */ + dealii::FullMatrix build_dim_mass_matrix( + const int nstate, + const unsigned int n_dofs, const unsigned int n_quad_pts, + basis_functions &basis, + const std::vector &det_Jac, + const std::vector &quad_weights); +}; + +///Local stiffness matrix without jacobian dependence. +/**NOTE: this is not used in DG volume integral since that needs to use the derivative of the flux basis and is multiplied by flux at volume cubature nodes this is strictly for consturtcing D operator +*\f[ (\mathbf{S}_\xi)_{ij} = \int_\mathbf{{\Omega}_r} \mathbf{\chi}_i(\mathbf{\xi}^r) \frac{\mathbf{\chi}_{j}(\mathbf{\xi}^r)}{\partial \xi} d\mathbf{\Omega}_r \f] +*/ +template +class local_basis_stiffness : public SumFactorizedOperators +{ +public: + /// Constructor. + local_basis_stiffness ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const bool store_skew_symmetric_form_input = false); + + /// Destructor. + ~local_basis_stiffness () {}; + + /// Stores the degree of the current poly degree. + unsigned int current_degree; + + /// Flag to store the skew symmetric form \f$S-S^T\f$. + const bool store_skew_symmetric_form; + + /// Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); + + /// Skew-symmetric volume operator \f$S-S^T\f$. + dealii::FullMatrix oneD_skew_symm_vol_oper; +}; + +///This is the solution basis \f$\mathbf{D}_i\f$, the modal differential opertaor commonly seen in DG defined as \f$\mathbf{D}_i=\mathbf{M}^{-1}*\mathbf{S}_i\f$. +template +class modal_basis_differential_operator : public SumFactorizedOperators +{ +public: + /// Constructor. + modal_basis_differential_operator ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + /// Destructor. + ~modal_basis_differential_operator () {}; + + /// Stores the degree of the current poly degree. + unsigned int current_degree; + + /// Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); +}; + +///\f$ p\f$ -th order modal derivative of basis fuctions, ie/\f$ [D_\xi^p, D_\eta^p, D_\zeta^p]\f$ +template +class derivative_p : public SumFactorizedOperators +{ +public: + /// Constructor. + derivative_p ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + /// Destructor. + ~derivative_p () {}; + + /// Stores the degree of the current poly degree. + unsigned int current_degree; + + /// Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); +}; + +/// ESFR correction matrix without jac dependence +template +class local_Flux_Reconstruction_operator : public SumFactorizedOperators +{ +public: + ///Constructor. + local_Flux_Reconstruction_operator ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction FR_param_input); + ///Destructor. + ~local_Flux_Reconstruction_operator () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Flux reconstruction parameter type. + const Parameters::AllParameters::Flux_Reconstruction FR_param_type; + + ///Flux reconstruction paramater value. + double FR_param; + + ///Evaluates Huynh's g2 parameter for flux reconstruction. + /* This parameter recovers Huynh, Hung T. "A flux reconstruction approach to high-order schemes including discontinuous Galerkin methods." 18th AIAA computational fluid dynamics conference. 2007. */ - std::vector>> local_basis_stiffness; - ///"Stiffness" opertaor used in DG Strong form. - /**Since the volume integral in strong form uses the flux basis spanning the flux. - *Explicitly, this is integral of basis_functions and the gradient of the flux basis - *\f[ - (\mathbf{S}_{\text{FLUX},\xi})_{ij} = \int_\mathbf{{\Omega}_r} \mathbf{\chi}_i(\mathbf{\xi}^r) \frac{\mathbf{\chi}_{\text{FLUX},j}(\mathbf{\xi}^r)}{\partial \xi} d\mathbf{\Omega}_r - \f] + void get_Huynh_g2_parameter ( + const unsigned int curr_cell_degree, + double &c); + + ///Evaluates the spectral difference parameter for flux reconstruction. + /**Value from Allaneau, Y., and Antony Jameson. "Connections between the filtered discontinuous Galerkin method and the flux reconstruction approach to high order discretizations." Computer Methods in Applied Mechanics and Engineering 200.49-52 (2011): 3628-3636. */ - std::vector>>> local_flux_basis_stiffness; - ///The integration of gradient of solution basis. - /**Please note that for the weak form volume integral with arbitrary integration strength, use the transpose of the following operator. - *Note: that it is also a vector of nstate since it will be applied to a flux vector per state. - *Lastly its gradient of basis functions NOT flux basis because in the weak form the test function is the basis function not the flux basis (technically the flux is spanned by the flux basis at quadrature nodes). - * \f[ - * \mathbf{W}\nabla\Big(\chi_i(\mathbf{\xi}^r)\Big) - * \f] + void get_spectral_difference_parameter ( + const unsigned int curr_cell_degree, + double &c); + + ///Evaluates the flux reconstruction parameter at the bottom limit where the scheme is unstable. + /**Value from Allaneau, Y., and Antony Jameson. "Connections between the filtered discontinuous Galerkin method and the flux reconstruction approach to high order discretizations." Computer Methods in Applied Mechanics and Engineering 200.49-52 (2011): 3628-3636. */ - std::vector>>> vol_integral_gradient_basis; - /// ESFR correction matrix without jac dependence - std::vector> local_K_operator; - ///ESFR c parameter K operator - std::vector c_param_FR; - /// ESFR correction matrix for AUX EQUATION without jac dependence - /** NOTE Auxiliary equation is a vector in dim, so theres an ESFR correction for each dim -> K_aux also a vector of dim - * ie/ local_K_operator_aux[degree_index][dimension_index] = K_operator for AUX eaquation in direction dimension_index for - * polynomial degree of degree_index+1 - */ - std::vector>> local_K_operator_aux; - ///ESFR k parameter K-auxiliary operator - std::vector k_param_FR; - ///\f$ p\f$ -th order modal derivative of basis fuctions, ie/\f$ [D_\xi^p, D_\eta^p, D_\zeta^p]\f$ - std::vector>> derivative_p; - /// \f$2p\f$-th order modal derivative of basis fuctions, ie/ \f$[D_\xi^p D_\eta^p, D_\xi^p D_\zeta^p, D_\eta^p D_\zeta^p]\f$ - std::vector>> derivative_2p; - /// \f$3p\f$-th order modal derivative of basis fuctions \f$[D_\xi^p D_\eta^p D_\zeta^p]\f$ - std::vector> derivative_3p; - - ///Projection operator corresponding to basis functions onto M-norm (L2). - std::vector> vol_projection_operator; - ///Projection operator corresponding to basis functions onto \f$(M+K)\f$-norm. - std::vector> vol_projection_operator_FR; - - ///Builds basis and flux functions operators and gradient operator. - void create_vol_basis_operators (); - ///Constructs a mass matrix on the fly for a single degree NOTE: for Jacobian dependence pass JxW to quad_weights. - void build_local_Mass_Matrix ( - const std::vector &quad_weights, - const unsigned int n_dofs_cell, const unsigned int n_quad_pts, - const int current_fe_index, - dealii::FullMatrix &Mass_Matrix); - ///Constructs local_mass which is a vector of metric Jacobian independent local mass matrices. - void build_Mass_Matrix_operators (); - ///Constructs local stiffness operator corresponding to the basis. - /**Also it constructs the flux basis stiffness as \f$\int_{\mathbf{\Omega}_r}\chi_i(\mathbf{\xi}^r)\frac{\partial \chi_{\text{FLUX},j}(\mathbf{\xi}^r)}{\partial \xi} d\mathbf{\Omega}_r \f$. - *Also builds modal_basis_differential_operator since has the stiffness matrix there. + void get_c_negative_FR_parameter ( + const unsigned int curr_cell_degree, + double &c); + + ///Evaluates the flux reconstruction parameter at the bottom limit where the scheme is unstable, divided by 2. + /**Value from Allaneau, Y., and Antony Jameson. "Connections between the filtered discontinuous Galerkin method and the flux reconstruction approach to high order discretizations." Computer Methods in Applied Mechanics and Engineering 200.49-52 (2011): 3628-3636. + * Commonly in the lterature we use this value to show the approach to the bottom limit of stability. */ - void build_Stiffness_Matrix_operators (); - ///FR specific build operator functions - /**builds the \f$ p,\: 2p,\f$ and \f$ 3p \f$ derivative operators to compute broken Sobolev-space. - */ - void get_higher_derivatives (); - ///Gets the FR correction parameter for both primary and auxiliary equations and stores for each degree. + void get_c_negative_divided_by_two_FR_parameter ( + const unsigned int curr_cell_degree, + double &c); + + ///Gets the FR correction parameter corresponding to the maximum timestep. + /** Note that this parameter is also a good approximation for when the FR scheme begins to + * lose an order of accuracy, but the original definition is that it corresponds to the maximum timestep. + * Value from Table 3.4 in Castonguay, Patrice. High-order energy stable flux reconstruction schemes for fluid flow simulations on unstructured grids. Stanford University, 2012. + */ + void get_c_plus_parameter ( + const unsigned int curr_cell_degree, + double &c); + + ///Gets the FR correction parameter for the primary equation and stores. /**These values are name specified in parameters/all_parameters.h, passed through control file/or test and here converts/stores as value. + * Please note that in all the functions within this that evaluate the parameter, we divide the value in the literature by 2.0 + * because our basis are contructed by an orthonormal Legendre basis rather than the orthogonal basis in the literature. + * Also, we have the additional scaling by pow(pow(2.0,curr_cell_degree),2) because our basis functions are defined on + * a reference element between [0,1], whereas the values in the literature are based on [-1,1]. + * For further details please refer to Cicchino, Alexander, and Siva Nadarajah. "A new norm and stability condition for tensor product flux reconstruction schemes." Journal of Computational Physics 429 (2021): 110025. */ void get_FR_correction_parameter ( - const unsigned int curr_cell_degree, - real &c, real &k); - ///Constructs the vector of K operators (ESFR correction operator) for each poly degree. - void build_K_operators (); - ///Computes a single local K operator (ESFR correction operator) on the fly for a local element. + const unsigned int curr_cell_degree, + double &c); + + ///Computes a single local Flux_Reconstruction operator (ESFR correction operator) on the fly for a local element. /**Note that this is dependent on the Mass Matrix, so for metric Jacobian dependent \f$K_m\f$, *pass the metric Jacobian dependent Mass Matrix \f$M_m\f$. */ - void build_local_K_operator( - const dealii::FullMatrix &local_Mass_Matrix, - const unsigned int n_dofs_cell, const unsigned int degree_index, - dealii::FullMatrix &K_operator); - ///Similar to above but for the local K operator for the Auxiliary equation. - void build_local_K_operator_AUX( - const dealii::FullMatrix &local_Mass_Matrix, - const unsigned int n_dofs_cell, const unsigned int degree_index, - std::vector> &K_operator_aux); - - ///Computes the volume projection operators. - void get_vol_projection_operators(); - ///Computes a single local projection operator on some space (norm). - void compute_local_vol_projection_operator( - const unsigned int degree_index, - const unsigned int n_dofs_cell, - const dealii::FullMatrix &norm_matrix, - dealii::FullMatrix &volume_projection); - - ///Solution basis functions evaluated at facet cubature nodes. - std::vector>> basis_at_facet_cubature; - ///Flux basis functions evaluated at facet cubature nodes. - std::vector>>> flux_basis_at_facet_cubature; - ///The surface integral of test functions WITH unit reference normals. - /**\f[ - * \text{diag}(\hat{\mathbf{n}}^r) \mathbf{W}_f \mathbf{\chi}(\mathbf{\xi}_f^r) - * \f] - *ie/ diag of REFERENCE unit normal times facet quadrature weights times solution basis functions evaluated on that face - *in DG surface integral would be transpose(face_integral_basis) times flux_on_face - */ - std::vector>>> face_integral_basis; - /// The DG lifting operator is defined as the operator that lifts inner products of polynomials of some order \f$p\f$ onto the L2-space. - /**In DG lifting operator is \f$L=\mathbf{M}^{-1}*(\text{face_integral_basis})^T\f$. - *So DG surface is \f$L*\text{flux_interpolated_to_face}\f$. - *NOTE this doesn't have metric Jacobian dependence, for DG solver - *we build that using the functions below on the fly! + void build_local_Flux_Reconstruction_operator( + const dealii::FullMatrix &local_Mass_Matrix, + const dealii::FullMatrix &pth_derivative, + const unsigned int n_dofs, + const double c, + dealii::FullMatrix &Flux_Reconstruction_operator); + + ///Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); + + ///Computes the dim sized flux reconstruction operator with simplified tensor product form. + /** The formula for the dim sized flux reconstruction operator is + * \f$ \mathbf{K}_m = \sum_{s,v,w} c_{(s,v,w)} \Big( \mathbf{D}_\xi^s\mathbf{D}_\eta^v\mathbf{D}_\zeta^w \Big)^T \mathbf{M}_m \Big( \mathbf{D}_\xi^s\mathbf{D}_\eta^v\mathbf{D}_\zeta^w \Big) \f$, + * where \f$ c_{(s,v,w)} = c^{\frac{s}{p} + \frac{v}{p} +\frac{w}{p}}\f$. + * Please pass the number of dofs for the dim sized operator. */ - std::vector>>> lifting_operator; - ///The ESFR lifting operator. - /** - *Consider the broken Sobolev-space \f$W_{\delta}^{dim*p,2}(\mathbf{\Omega}_r)\f$ (which is the ESFR norm) - * for \f$u \in W_{\delta}^{dim*p,2}(\mathbf{\Omega}_r)\f$, - * \f[ - * L_{FR}:\: _{\mathbf{\Omega}_r} = _{\mathbf{\Gamma}_2}, \forall v\in P^p(\mathbf{\Omega}_r) - * \f]. + dealii::FullMatrix build_dim_Flux_Reconstruction_operator( + const dealii::FullMatrix &local_Mass_Matrix, + const int nstate, + const unsigned int n_dofs); + + ///Computes the dim sized flux reconstruction operator for general Mass Matrix (needed for curvilinear). + /** The formula for the dim sized flux reconstruction operator is + * \f$ \mathbf{K}_m = \sum_{s,v,w} c_{(s,v,w)} \Big( \mathbf{D}_\xi^s\mathbf{D}_\eta^v\mathbf{D}_\zeta^w \Big)^T \mathbf{M}_m \Big( \mathbf{D}_\xi^s\mathbf{D}_\eta^v\mathbf{D}_\zeta^w \Big) \f$, + * where \f$ c_{(s,v,w)} = c^{\frac{s}{p} + \frac{v}{p} +\frac{w}{p}}\f$. + * Please pass the number of dofs for the dim sized operator. + * For pth deriv, please pass the 1D operator. */ - std::vector>>> lifting_operator_FR; + dealii::FullMatrix build_dim_Flux_Reconstruction_operator_directly( + const int nstate, + const unsigned int n_dofs, + dealii::FullMatrix &pth_deriv, + dealii::FullMatrix &mass_matrix); +}; + +/// ESFR correction matrix for AUX EQUATION without jac dependence +/** NOTE Auxiliary equation is a vector in dim, so theres an ESFR correction for each dim -> Flux_Reconstruction_aux also a vector of dim +* ie/ local_Flux_Reconstruction_operator_aux[degree_index][dimension_index] = Flux_Reconstruction_operator for AUX eaquation in direction dimension_index for +* polynomial degree of degree_index+1 +*/ +template +class local_Flux_Reconstruction_operator_aux : public local_Flux_Reconstruction_operator +{ +public: + ///Constructor. + local_Flux_Reconstruction_operator_aux ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction_Aux FR_param_aux_input); + + ///Destructor. + ~local_Flux_Reconstruction_operator_aux () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Flux reconstruction parameter type. + const Parameters::AllParameters::Flux_Reconstruction_Aux FR_param_aux_type; + + ///Flux reconstruction paramater value. + double FR_param_aux; + + ///Gets the FR correction parameter for the auxiliary equations and stores. + /**These values are name specified in parameters/all_parameters.h, passed through control file/or test and here converts/stores as value. + * Please note that in all the functions within this that evaluate the parameter, we divide the value in the literature by 2.0 + * because our basis are contructed by an orthonormal Legendre basis rather than the orthogonal basis in the literature. + * Also, we have the additional scaling by pow(pow(2.0,curr_cell_degree),2) because our basis functions are defined on + * a reference element between [0,1], whereas the values in the literature are based on [-1,1]. + * For further details please refer to Cicchino, Alexander, and Siva Nadarajah. "A new norm and stability condition for tensor product flux reconstruction schemes." Journal of Computational Physics 429 (2021): 110025. + */ + void get_FR_aux_correction_parameter ( + const unsigned int curr_cell_degree, + double &k); + + ///Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); +}; + +///Projection operator corresponding to basis functions onto M-norm (L2). +template +class vol_projection_operator : public SumFactorizedOperators +{ +public: + ///Constructor. + vol_projection_operator ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + ///Destructor. + ~vol_projection_operator () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Computes a single local projection operator on some space (norm). + void compute_local_vol_projection_operator( + const dealii::FullMatrix &norm_matrix_inverse, + const dealii::FullMatrix &integral_vol_basis, + dealii::FullMatrix &volume_projection); + + ///Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); +}; + +///Projection operator corresponding to basis functions onto \f$(M+K)\f$-norm. +template +class vol_projection_operator_FR : public vol_projection_operator +{ +public: + ///Constructor. + vol_projection_operator_FR ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction FR_param_input, + const bool store_transpose_input = false); + + ///Destructor. + ~vol_projection_operator_FR () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Flag is store transpose operator. + bool store_transpose; + + ///Flux reconstruction parameter type. + const Parameters::AllParameters::Flux_Reconstruction FR_param_type; + + ///Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); + + ///Stores the transpose of the operator for fast weight-adjusted solves. + dealii::FullMatrix oneD_transpose_vol_operator; +}; + +///Projection operator corresponding to basis functions onto \f$(M+K)\f$-norm for auxiliary equation. +template +class vol_projection_operator_FR_aux : public vol_projection_operator +{ +public: + ///Constructor. + vol_projection_operator_FR_aux ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction_Aux FR_param_input, + const bool store_transpose_input = false); + ///Destructor. + ~vol_projection_operator_FR_aux () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Flag is store transpose operator. + bool store_transpose; + + ///Flux reconstruction parameter type. + const Parameters::AllParameters::Flux_Reconstruction_Aux FR_param_type; + + ///Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); + + ///Stores the transpose of the operator for fast weight-adjusted solves. + dealii::FullMatrix oneD_transpose_vol_operator; +}; + +///The metric independent inverse of the FR mass matrix \f$(M+K)^{-1}\f$. +template +class FR_mass_inv : public SumFactorizedOperators +{ +public: + ///Constructor. + FR_mass_inv ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction FR_param_input); + + ///Destructor. + ~FR_mass_inv () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Flux reconstruction parameter type. + const Parameters::AllParameters::Flux_Reconstruction FR_param_type; + + ///Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); +}; +///The metric independent inverse of the FR mass matrix for auxiliary equation \f$(M+K)^{-1}\f$. +template +class FR_mass_inv_aux : public SumFactorizedOperators +{ +public: + ///Constructor. + FR_mass_inv_aux ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction_Aux FR_param_input); + + ///Destructor. + ~FR_mass_inv_aux () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Flux reconstruction parameter type. + const Parameters::AllParameters::Flux_Reconstruction_Aux FR_param_type; + + ///Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); +}; +///The metric independent FR mass matrix \f$(M+K)\f$. +template +class FR_mass : public SumFactorizedOperators +{ +public: + ///Constructor. + FR_mass ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction FR_param_input); + + ///Destructor. + ~FR_mass () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Flux reconstruction parameter type. + const Parameters::AllParameters::Flux_Reconstruction FR_param_type; + + ///Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); +}; + +///The metric independent FR mass matrix for auxiliary equation \f$(M+K)\f$. +template +class FR_mass_aux : public SumFactorizedOperators +{ +public: + ///Constructor. + FR_mass_aux ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction_Aux FR_param_input); + + ///Destructor. + ~FR_mass_aux () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Flux reconstruction parameter type. + const Parameters::AllParameters::Flux_Reconstruction_Aux FR_param_type; + + ///Assembles the one dimensional operator. + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); +}; + +///The integration of gradient of solution basis. +/**Please note that for the weak form volume integral with arbitrary integration strength, use the transpose of the following operator. +*Note: that it is also a vector of nstate since it will be applied to a flux vector per state. +*Lastly its gradient of basis functions NOT flux basis because in the weak form the test function is the basis function not the flux basis (technically the flux is spanned by the flux basis at quadrature nodes). + * \f[ + * \mathbf{W}\nabla\Big(\chi_i(\mathbf{\xi}^r)\Big) + * \f] + */ +template +class vol_integral_gradient_basis : public SumFactorizedOperators +{ +public: + ///Constructor. + vol_integral_gradient_basis ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + ///Destructor. + ~vol_integral_gradient_basis () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Assembles the one dimensional operator. + void build_1D_gradient_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); +}; + +/************************************************************************ +* +* SURFACE OPERATORS +* +************************************************************************/ + + +///The surface integral of test functions. +/**\f[ +* \mathbf{W}_f \mathbf{\chi}(\mathbf{\xi}_f^r) +* \f] +*ie/ diag of REFERENCE unit normal times facet quadrature weights times solution basis functions evaluated on that face +*in DG surface integral would be transpose(face_integral_basis) times flux_on_face +*/ +template +class face_integral_basis : public SumFactorizedOperators +{ +public: + ///Constructor. + face_integral_basis ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + ///Destructor. + ~face_integral_basis () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Assembles the one dimensional operator. + void build_1D_surface_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &face_quadrature); +}; + +/// The DG lifting operator is defined as the operator that lifts inner products of polynomials of some order \f$p\f$ onto the L2-space. +/**In DG lifting operator is \f$L=\mathbf{M}^{-1}*(\text{face_integral_basis})^T\f$. +*So DG surface is \f$L*\text{flux_interpolated_to_face}\f$. +*NOTE this doesn't have metric Jacobian dependence, for DG solver +*we build that using the functions below on the fly! +*/ +template +class lifting_operator : public SumFactorizedOperators +{ +public: + ///Constructor. + lifting_operator ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + ///Destructor. + ~lifting_operator () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; - ///Builds surface basis and flux functions operators and gradient operator. - void create_surface_basis_operators (); - ///Builds surface lifting operators. - void get_surface_lifting_operators (); ///Builds the local lifting operator. void build_local_surface_lifting_operator ( - const unsigned int degree_index, - const unsigned int n_dofs_cell, - const unsigned int face_number, - const dealii::FullMatrix &norm_matrix, - std::vector> &lifting); - - ///The mapping shape functions evaluated at the volume grid nodes (facet set included in volume grid nodes for consistency). - std::vector> mapping_shape_functions_grid_nodes; - ///REFERENCE gradient of the the mapping shape functions evaluated at the volume grid nodes. - std::vector>> gradient_mapping_shape_functions_grid_nodes; - - ///Mapping shape functions evaluated at the VOLUME flux nodes (arbitrary, does not have to be on the surface ex/ GL). -/** FOR Flux Nodes operators there is the grid degree, then the degree of the cubature set it is applied on -* to handle all general cases. + const unsigned int n_dofs, + const dealii::FullMatrix &norm_matrix, + const dealii::FullMatrix &face_integral, + dealii::FullMatrix &lifting); + + ///Assembles the one dimensional norm operator that it is lifted onto. + /** Note that the norm is the DG mass matrix in this case. This has to be called before build_1D_surface_operator. + */ + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &face_quadrature); + + ///Assembles the one dimensional operator. + void build_1D_surface_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &face_quadrature); +}; + +///The ESFR lifting operator. +/** +*Consider the broken Sobolev-space \f$W_{\delta}^{dim*p,2}(\mathbf{\Omega}_r)\f$ (which is the ESFR norm) +* for \f$u \in W_{\delta}^{dim*p,2}(\mathbf{\Omega}_r)\f$, +* \f[ +* L_{FR}:\: _{\mathbf{\Omega}_r} = _{\mathbf{\Gamma}_2}, \forall v\in P^p(\mathbf{\Omega}_r) +* \f]. */ - std::vector>> mapping_shape_functions_vol_flux_nodes; - ///Mapping shape functions evaluated at the SURFACE flux nodes. - std::vector>>> mapping_shape_functions_face_flux_nodes; - ///Gradient of mapping shape functions evalutated at VOLUME flux nodes. - /**Note that for a single grid degree it can evaluate at varying degree of fluxnodes - *ie allows of sub/super parametric etc and over integration - *Vector order goes: [Grid_Degree][Flux_Poly_Degree][Dim][n_quad_pts][n_mapping_shape_functions] +template +class lifting_operator_FR : public lifting_operator +{ +public: + ///Constructor. + lifting_operator_FR ( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const Parameters::AllParameters::Flux_Reconstruction FR_param_input); + + ///Destructor. + ~lifting_operator_FR () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Flux reconstruction parameter type. + const Parameters::AllParameters::Flux_Reconstruction FR_param_type; + + ///Assembles the one dimensional norm operator that it is lifted onto. + /** Note that the norm is the FR mass matrix in this case. This has to be called before build_1D_surface_operator. */ - std::vector>>> gradient_mapping_shape_functions_vol_flux_nodes; - ///Gradient of mapping shape functions evalutated at surface flux nodes. - /**Is a vector of degree->vector of n_faces -> vector of dim -> Matrix n_face_quad_pts x n_shape_functions. - */ - std::vector>>>> gradient_mapping_shape_functions_face_flux_nodes; + void build_1D_volume_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &face_quadrature); + + ///Assembles the one dimensional operator. + void build_1D_surface_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &face_quadrature); +}; + + +/************************************************************************ +* +* METRIC MAPPING OPERATORS +* +************************************************************************/ + + +///The mapping shape functions evaluated at the desired nodes (facet set included in volume grid nodes for consistency). +/** +* The finite element passed has to be the metric finite element. That is the one +* collocated on the mapping support points. +* By default, we use Gauss-Lobatto-Legendre as the mapping support points. +*/ +template +class mapping_shape_functions: public SumFactorizedOperators +{ +public: + ///Constructor. + mapping_shape_functions( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + ///Destructor. + ~mapping_shape_functions() {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Stores the degree of the current grid degree. + unsigned int current_grid_degree; - ///Allocates metric shape functions operators. - void allocate_metric_operators(); - ///Creates metric shape functions operators. - void create_metric_basis_operators (); - ///Called on the fly and returns the metric cofactor and determinant of Jacobian at VOLUME cubature nodes. + ///Object of mapping shape functions evaluated at grid nodes. + basis_functions mapping_shape_functions_grid_nodes; + + ///Object of mapping shape functions evaluated at flux nodes. + basis_functions mapping_shape_functions_flux_nodes; + + ///Constructs the volume operator and gradient operator. /** - *We compute the metric cofactor matrix \f$\mathbf{C}_m\f$ via the invariant curl form of Abe 2014 and Kopriva 2006. To ensure consistent normals, we consider - * the two cubature sets, grid nodes (mapping-support-points), and flux nodes (quadrature nodes). The metric cofactor matrix is thus: - * \f[ - * (\mathbf{C})_{ni} = J(\mathbf{a}^i)_n= -\frac{1}{2}\hat{\mathbf{e}}_i \cdot \nabla^r\times\mathbf{\Theta}(\mathbf{\xi}_{\text{flux nodes}}^r)\Big[ - \mathbf{\Theta}(\mathbf{\xi}_{\text{grid nodes}}^r)\hat{\mathbf{x}}_l^{c^T} - \nabla^r \mathbf{\Theta}(\mathbf{\xi}_{\text{grid nodes}}^r)\hat{\mathbf{x}}_m^{c^T} - - - \mathbf{\Theta}(\mathbf{\xi}_{\text{grid nodes}}^r)\hat{\mathbf{x}}_m^{c^T} - \nabla^r \mathbf{\Theta}(\mathbf{\xi}_{\text{grid nodes}}^r)\hat{\mathbf{x}}_l^{c^T}\Big] - \text{, }\\i=1,2,3\text{, }n=1,2,3\text{ }(n,m,l)\text{ cyclic.} - * \f] - * where we let \f$\mathbf{\Theta}(\mathbf{\xi}^r)\f$ represent the mapping shape functions. - */ - void build_local_vol_metric_cofactor_matrix_and_det_Jac( - const unsigned int grid_degree, const unsigned int poly_degree, - const unsigned int n_quad_pts, - const unsigned int n_metric_dofs, - const std::vector> &mapping_support_points, - std::vector &determinant_Jacobian, - std::vector> &metric_cofactor); - ///Called on the fly and returns the metric cofactor and determinant of Jacobian at face cubature nodes. - void build_local_face_metric_cofactor_matrix_and_det_Jac( - const unsigned int grid_degree, const unsigned int poly_degree, - const unsigned int iface, - const unsigned int n_quad_pts, const unsigned int n_metric_dofs, - const std::vector> &mapping_support_points, - std::vector &determinant_Jacobian, - std::vector> &metric_cofactor); - ///Computes local 3D cofactor matrix in VOLUME. - void compute_local_3D_cofactor_vol( - const unsigned int grid_degree, const unsigned int poly_degree, - const unsigned int n_quad_pts, - const unsigned int n_metric_dofs, - const std::vector> &mapping_support_points, - std::vector> &metric_cofactor); - ///Computes local 3D cofactor matrix on FACE for consistent normals with water-tight mesh. - void compute_local_3D_cofactor_face( - const unsigned int grid_degree, const unsigned int poly_degree, - const unsigned int n_quad_pts, - const unsigned int n_metric_dofs, const unsigned int iface, - const std::vector> &mapping_support_points, - std::vector> &metric_cofactor); - ///Computes \f$(\mathbf{x}_l * \nabla(\mathbf{x}_m))\f$ at GRID NODES. - void compute_Xl_grad_Xm( - const unsigned int grid_degree, - const unsigned int n_metric_dofs, - const std::vector> &mapping_support_points, - std::vector> &Xl_grad_Xm); - ///Computes the cyclic curl loop for metric cofactor matrix. + * This function assures that the shape + * functions are collocated on the grid nodes. + * Also, makes for easier function calls. + * Function builds the 1D operators in mapping_shape_functions_grid_nodes. + * Note that at grid nodes, we do NOT need any surface information. + */ + void build_1D_shape_functions_at_grid_nodes( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); + + ///Constructs the volume, gradient, surface, and surface gradient operator. /** - * This function is currently no longer used, but left in with the conservative curl form commented out - * incase we want to compare the forms in the future. - */ - void do_curl_loop_metric_cofactor( - const unsigned int n_quad_pts, - const std::vector> grad_Xl_grad_Xm, - std::vector> &metric_cofactor); - + * Function builds the 1D operators in mapping_shape_functions_flux_nodes. + */ + void build_1D_shape_functions_at_flux_nodes( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature, + const dealii::Quadrature<0> &face_quadrature); + + ///Constructs the volume and volume gradient operator. + /** + * Often times, we only need the values at just the volume flux nodes. + * Function builds the 1D operators in mapping_shape_functions_flux_nodes. + */ + void build_1D_shape_functions_at_volume_flux_nodes( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); + +}; + +/***************************************************************************** +* +* METRIC OPERTAORS TO BE CALLED ON-THE-FLY +* +*****************************************************************************/ +///Base metric operators class that stores functions used in both the volume and on surface. +template +class metric_operators: public SumFactorizedOperators +{ +public: + ///Constructor. + metric_operators( + const int nstate_input, + const unsigned int max_degree_input, + const unsigned int grid_degree_input, + const bool store_vol_flux_nodes_input = false, + const bool store_surf_flux_nodes_input = false, + const bool store_Jacobian_input = false); + + ///Destructor. + ~metric_operators() {}; + + ///Flag if store metric Jacobian at flux nodes. + const bool store_Jacobian; + + ///Flag if store metric Jacobian at flux nodes. + const bool store_vol_flux_nodes; + + ///Flag if store metric Jacobian at flux nodes. + const bool store_surf_flux_nodes; + + ///Given a physical tensor, return the reference tensor. + void transform_physical_to_reference( + const dealii::Tensor<1,dim,real> &phys, + const dealii::Tensor<2,dim,real> &metric_cofactor, + dealii::Tensor<1,dim,real> &ref); + + ///Given a reference tensor, return the physical tensor. + void transform_reference_to_physical( + const dealii::Tensor<1,dim,real> &ref, + const dealii::Tensor<2,dim,real> &metric_cofactor, + dealii::Tensor<1,dim,real> &phys); + + ///Given a physical tensor of vector of points, return the reference tensor of vector. + void transform_physical_to_reference_vector( + const dealii::Tensor<1,dim,std::vector> &phys, + const dealii::Tensor<2,dim,std::vector> &metric_cofactor, + dealii::Tensor<1,dim,std::vector> &ref); + + ///Given a reference tensor, return the physical tensor. + void transform_reference_unit_normal_to_physical_unit_normal( + const unsigned int n_quad_pts, + const dealii::Tensor<1,dim,real> &ref, + const dealii::Tensor<2,dim,std::vector> &metric_cofactor, + std::vector> &phys); + + ///Builds just the determinant of the volume metric determinant. + void build_determinant_volume_metric_Jacobian( + const unsigned int n_quad_pts,//number volume quad pts + const unsigned int n_metric_dofs,//dofs of metric basis. NOTE: this is the number of mapping support points + const std::array,dim> &mapping_support_points, + mapping_shape_functions &mapping_basis); + + ///Builds the volume metric operators. + /** Builds and stores volume metric cofactor and determinant of metric Jacobian + * at the volume cubature nodes. If passed flag to store Jacobian when metric + * operators is constructed, will also store the JAcobian at flux nodes. + */ + void build_volume_metric_operators( + const unsigned int n_quad_pts,//number volume quad pts + const unsigned int n_metric_dofs,//dofs of metric basis. NOTE: this is the number of mapping support points + const std::array,dim> &mapping_support_points, + mapping_shape_functions &mapping_basis, + const bool use_invariant_curl_form = false); + + ///Builds the facet metric operators. + /** Builds and stores facet metric cofactor and determinant of metric Jacobian + * at the facet cubature nodes (one face). If passed flag to store Jacobian when metric + * operators is constructed, will also store the JAcobian at flux nodes. + */ + void build_facet_metric_operators( + const unsigned int iface, + const unsigned int n_quad_pts,//number facet quad pts + const unsigned int n_metric_dofs,//dofs of metric basis. NOTE: this is the number of mapping support points + const std::array,dim> &mapping_support_points, + mapping_shape_functions &mapping_basis, + const bool use_invariant_curl_form = false); + + ///The volume metric cofactor matrix. + dealii::Tensor<2,dim,std::vector> metric_cofactor_vol; + + ///The facet metric cofactor matrix, for ONE face. + dealii::Tensor<2,dim,std::vector> metric_cofactor_surf; + + ///The determinant of the metric Jacobian at volume cubature nodes. + std::vector det_Jac_vol; + + ///The determinant of the metric Jacobian at facet cubature nodes. + std::vector det_Jac_surf; + + ///Stores the metric Jacobian at flux nodes. + dealii::Tensor<2,dim,std::vector> metric_Jacobian_vol_cubature; + + ///Stores the physical volume flux nodes. + dealii::Tensor<1,dim,std::vector> flux_nodes_vol; + + ///Stores the physical facet flux nodes. + std::array>,n_faces> flux_nodes_surf; + +protected: + + ///Builds the metric Jacobian evaluated at a vector of points. + /** \f$ \mathbf{J} = [\mathbf{a}_1, \mathbf{a}_2, \mathbf{a}_3]^T \f$ + * where \f$\mathbf{a}_i = \mathbf{\nabla}^r x_i \f$ are the physical vector bases. + */ + void build_metric_Jacobian( + const unsigned int n_quad_pts,//the dim sized n_quad_pts, NOT the 1D + const std::array,dim> &mapping_support_points, + const dealii::FullMatrix &basis_x_flux_nodes, + const dealii::FullMatrix &basis_y_flux_nodes, + const dealii::FullMatrix &basis_z_flux_nodes, + const dealii::FullMatrix &grad_basis_x_flux_nodes, + const dealii::FullMatrix &grad_basis_y_flux_nodes, + const dealii::FullMatrix &grad_basis_z_flux_nodes, + std::vector> &local_Jac); + + ///Assembles the determinant of metric Jacobian. + /** \f$ \|J^\Omega \| = \mathbf{a}_1 \cdot (\mathbf{a}_2 \otimes \mathbf{a}_3)\f$, + * where \f$\mathbf{a}_i = \mathbf{\nabla}^r x_i \f$ are the physical vector bases. + * Pass the 1D mapping shape functions evaluated at flux nodes, + * and the 1D gradient of mapping shape functions evaluated at flux nodes. + */ + void build_determinant_metric_Jacobian( + const unsigned int n_quad_pts,//number volume quad pts + const std::array,dim> &mapping_support_points, + const dealii::FullMatrix &basis_x_flux_nodes, + const dealii::FullMatrix &basis_y_flux_nodes, + const dealii::FullMatrix &basis_z_flux_nodes, + const dealii::FullMatrix &grad_basis_x_flux_nodes, + const dealii::FullMatrix &grad_basis_y_flux_nodes, + const dealii::FullMatrix &grad_basis_z_flux_nodes, + std::vector &det_metric_Jac); + + ///Called on the fly and returns the metric cofactor at cubature nodes. + void build_local_metric_cofactor_matrix( + const unsigned int n_quad_pts,//number volume quad pts + const unsigned int n_metric_dofs,//dofs of metric basis. NOTE: this is the number of mapping support points + const std::array,dim> &mapping_support_points, + const dealii::FullMatrix &basis_x_grid_nodes, + const dealii::FullMatrix &basis_y_grid_nodes, + const dealii::FullMatrix &basis_z_grid_nodes, + const dealii::FullMatrix &basis_x_flux_nodes, + const dealii::FullMatrix &basis_y_flux_nodes, + const dealii::FullMatrix &basis_z_flux_nodes, + const dealii::FullMatrix &grad_basis_x_grid_nodes, + const dealii::FullMatrix &grad_basis_y_grid_nodes, + const dealii::FullMatrix &grad_basis_z_grid_nodes, + const dealii::FullMatrix &grad_basis_x_flux_nodes, + const dealii::FullMatrix &grad_basis_y_flux_nodes, + const dealii::FullMatrix &grad_basis_z_flux_nodes, + dealii::Tensor<2,dim,std::vector> &metric_cofactor, + const bool use_invariant_curl_form = false); + + ///Computes local 3D cofactor matrix. + /** + *We compute the metric cofactor matrix \f$\mathbf{C}_m\f$ via the conservative curl form of Abe 2014 and Kopriva 2006 by default. Can use invariant curl form by passing flag. To ensure consistent normals, we consider + * the two cubature sets, grid nodes (mapping-support-points), and flux nodes (quadrature nodes). The metric cofactor matrix is thus: + * \f[ + * (\mathbf{C})_{ni} = J(\mathbf{a}^i)_n= -\hat{\mathbf{e}}_i \cdot \nabla^r\times\mathbf{\Theta}(\mathbf{\xi}_{\text{flux nodes}}^r)\Big[ + \mathbf{\Theta}(\mathbf{\xi}_{\text{grid nodes}}^r)\hat{\mathbf{x}}_l^{c^T} + \nabla^r \mathbf{\Theta}(\mathbf{\xi}_{\text{grid nodes}}^r)\hat{\mathbf{x}}_m^{c^T} + \Big] + \text{, }\\i=1,2,3\text{, }n=1,2,3\text{ }(n,m,l)\text{ cyclic,} + * \f] for the conservative curl form, and + * \f[ + * (\mathbf{C})_{ni} = J(\mathbf{a}^i)_n= -\frac{1}{2}\hat{\mathbf{e}}_i \cdot \nabla^r\times\mathbf{\Theta}(\mathbf{\xi}_{\text{flux nodes}}^r)\Big[ + \mathbf{\Theta}(\mathbf{\xi}_{\text{grid nodes}}^r)\hat{\mathbf{x}}_l^{c^T} + \nabla^r \mathbf{\Theta}(\mathbf{\xi}_{\text{grid nodes}}^r)\hat{\mathbf{x}}_m^{c^T} + - + \mathbf{\Theta}(\mathbf{\xi}_{\text{grid nodes}}^r)\hat{\mathbf{x}}_m^{c^T} + \nabla^r \mathbf{\Theta}(\mathbf{\xi}_{\text{grid nodes}}^r)\hat{\mathbf{x}}_l^{c^T}\Big] + \text{, }\\i=1,2,3\text{, }n=1,2,3\text{ }(n,m,l)\text{ cyclic,} + * \f] for the invariant curl form.
+ * We let \f$\mathbf{\Theta}(\mathbf{\xi}^r)\f$ represent the mapping shape functions. + */ + void compute_local_3D_cofactor( + const unsigned int n_metric_dofs, + const unsigned int n_quad_pts, + const std::array,dim> &mapping_support_points, + const dealii::FullMatrix &basis_x_grid_nodes, + const dealii::FullMatrix &basis_y_grid_nodes, + const dealii::FullMatrix &basis_z_grid_nodes, + const dealii::FullMatrix &basis_x_flux_nodes, + const dealii::FullMatrix &basis_y_flux_nodes, + const dealii::FullMatrix &basis_z_flux_nodes, + const dealii::FullMatrix &grad_basis_x_grid_nodes, + const dealii::FullMatrix &grad_basis_y_grid_nodes, + const dealii::FullMatrix &grad_basis_z_grid_nodes, + const dealii::FullMatrix &grad_basis_x_flux_nodes, + const dealii::FullMatrix &grad_basis_y_flux_nodes, + const dealii::FullMatrix &grad_basis_z_flux_nodes, + dealii::Tensor<2,dim,std::vector> &metric_cofactor, + const bool use_invariant_curl_form = false); +}; + +/************************************************************ +* +* SUMFACTORIZED STATE +* +************************************************************/ + +///In order to have all state operators be arrays of array, we template by dim, type, nstate, and number of faces. +/**Note that dofs and quad points aren't templated because they are variable with respect to each polynomial degree. +*Also I couldn't template by polynomial degree/grid degree since they aren't compile time constant expressions. +*/ +template +class SumFactorizedOperatorsState : public SumFactorizedOperators +{ +public: + ///Constructor. + SumFactorizedOperatorsState ( + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + ///Destructor. + ~SumFactorizedOperatorsState () {}; + + ///Stores the one dimensional volume operator. + std::array,nstate> oneD_vol_state_operator; + + ///Stores the one dimensional surface operator. + std::array,2>,nstate> oneD_surf_state_operator; + + ///Stores the one dimensional gradient operator. + std::array,nstate> oneD_grad_state_operator; + + ///Stores the one dimensional surface gradient operator. + std::array,2>,nstate> oneD_surf_grad_state_operator; + +};//end of OperatorsBaseState Class + +///The basis functions separated by nstate with n shape functions. +template +class basis_functions_state : public SumFactorizedOperatorsState +{ +public: + ///Constructor. + basis_functions_state ( + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + ///Destructor. + ~basis_functions_state () {}; -};///End operator base class. + ///Stores the degree of the current poly degree. + unsigned int current_degree; + ///Assembles the one dimensional operator. + void build_1D_volume_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); + + ///Assembles the one dimensional operator. + void build_1D_gradient_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); + + ///Assembles the one dimensional operator. + void build_1D_surface_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &face_quadrature); +}; + +///The FLUX basis functions separated by nstate with n shape functions. +/** The flux basis are collocated on the flux nodes (volume cubature nodes). +* Thus, they are the order of the quadrature set, not by the state! +*/ +template +class flux_basis_functions_state : public SumFactorizedOperatorsState +{ +public: + ///Constructor. + flux_basis_functions_state ( + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + ///Destructor. + ~flux_basis_functions_state () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Assembles the one dimensional operator. + virtual void build_1D_volume_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); + + ///Assembles the one dimensional operator. + void build_1D_gradient_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<1> &quadrature); + + ///Assembles the one dimensional operator. + void build_1D_surface_state_operator( + const dealii::FESystem<1,1> &finite_element, + const dealii::Quadrature<0> &face_quadrature); +}; + +///"Stiffness" operator used in DG Strong form. +/**Since the volume integral in strong form uses the flux basis spanning the flux. +*Explicitly, this is integral of basis_functions and the gradient of the flux basis +*\f[ + (\mathbf{S}_{\text{FLUX},\xi})_{ij} = \int_\mathbf{{\Omega}_r} \mathbf{\chi}_i(\mathbf{\xi}^r) \frac{\mathbf{\chi}_{\text{FLUX},j}(\mathbf{\xi}^r)}{\partial \xi} d\mathbf{\Omega}_r + \f] +*/ +template +class local_flux_basis_stiffness : public flux_basis_functions_state +{ +public: + ///Constructor. + local_flux_basis_stiffness ( + const unsigned int max_degree_input, + const unsigned int grid_degree_input); + + ///Destructor. + ~local_flux_basis_stiffness () {}; + + ///Stores the degree of the current poly degree. + unsigned int current_degree; + + ///Assembles the one dimensional operator. + void build_1D_volume_state_operator( + const dealii::FESystem<1,1> &finite_element,//pass the finite element of the TEST FUNCTION + const dealii::Quadrature<1> &quadrature); +}; } /// OPERATOR namespace } /// PHiLiP namespace #endif + diff --git a/src/operators/operators_factory.cpp b/src/operators/operators_factory.cpp new file mode 100644 index 000000000..0bbbdf640 --- /dev/null +++ b/src/operators/operators_factory.cpp @@ -0,0 +1,60 @@ +#include +#include "operators_factory.hpp" +#include "operators.h" + +namespace PHiLiP { +namespace OPERATOR { + +template +std::shared_ptr< OperatorsBase >//returns type OperatorsBase +OperatorsFactory +::create_operators( + const Parameters::AllParameters *const parameters_input, + const int nstate_input,//number of states input + const unsigned int /*degree*/,//degree not really needed at the moment + const unsigned int max_degree_input,//max poly degree for operators + const unsigned int grid_degree_input)//max grid degree for operators +{ + +// const unsigned int n_dofs_max = pow(max_degree_input + 1, dim); +// const unsigned int overintegration = parameters_input->overintegration; +// const unsigned int n_quad_pts_vol = pow(max_degree_input + 1 + overintegration, dim); +// const unsigned int n_quad_pts_face = pow(max_degree_input + 1 + overintegration, dim-1); +// const unsigned int n_dofs_max_metric = pow(grid_degree_input + 1, dim); + const unsigned int n_faces = dealii::GeometryInfo::faces_per_cell; + if(n_faces == 2*dim){ + if(nstate_input == 1){ + return std::make_shared< OperatorsBaseState >(parameters_input, max_degree_input, grid_degree_input);//, degree, max_degree_input, grid_degree_input); + } + else if(nstate_input == 2){ + return std::make_shared< OperatorsBaseState >(parameters_input, max_degree_input, grid_degree_input);//, degree, max_degree_input, grid_degree_input); + } + else if(nstate_input == 3){ + return std::make_shared< OperatorsBaseState >(parameters_input, max_degree_input, grid_degree_input);//, degree, max_degree_input, grid_degree_input); + } + else if(nstate_input == 4){ + return std::make_shared< OperatorsBaseState >(parameters_input, max_degree_input, grid_degree_input);//, degree, max_degree_input, grid_degree_input); + } + else if(nstate_input == 5){ + return std::make_shared< OperatorsBaseState >(parameters_input, max_degree_input, grid_degree_input);//, degree, max_degree_input, grid_degree_input); + } + else{ + std::cout<<"Number of states "< (parameters_input, degree, max_degree_input, grid_degree_input, triangulation_input); +// return std::make_shared< OperatorsVolume >(parameters_input, degree, max_degree_input, grid_degree_input, triangulation_input); +// return std::make_shared< OperatorsSurface >(parameters_input, degree, max_degree_input, grid_degree_input, triangulation_input); +// return std::make_shared< OperatorsMetric >(parameters_input, degree, max_degree_input, grid_degree_input, triangulation_input); +} + +template class OperatorsFactory ; + +} // OPERATOR namespace +} // PHiLiP namespace diff --git a/src/operators/operators_factory.hpp b/src/operators/operators_factory.hpp new file mode 100644 index 000000000..bd8de7bc4 --- /dev/null +++ b/src/operators/operators_factory.hpp @@ -0,0 +1,34 @@ +#ifndef __OPERATORS_FACTORY_H__ +#define __OPERATORS_FACTORY_H__ + +#include "parameters/all_parameters.h" +#include "operators.h" + +namespace PHiLiP { +namespace OPERATOR { + +/// This class creates a new Operators object +/** This allows the Operators to not be templated on the number of state variables, + * and number of faces + * while allowing the volume, face, and metric operators to be templated on them */ +template +class OperatorsFactory +{ +public: + /// Creates a derived object Operators, but returns it as OperatorsBase. + /** That way, the caller is agnostic to the number of state variables, + * poly degree, dofs, etc.*/ + static std::shared_ptr< OperatorsBase > + create_operators( + const Parameters::AllParameters *const parameters_input, + const int nstate_input,//number of states input + const unsigned int degree,//degree not really needed at the moment + const unsigned int max_degree_input,//max poly degree for operators + const unsigned int grid_degree_input);//max grid degree for operators + +}; + +} // OPERATOR namespace +} // PHiLiP namespace + +#endif diff --git a/src/parameters/all_parameters.cpp b/src/parameters/all_parameters.cpp index c8301137e..51158ad4f 100644 --- a/src/parameters/all_parameters.cpp +++ b/src/parameters/all_parameters.cpp @@ -70,6 +70,20 @@ void AllParameters::declare_parameters (dealii::ParameterHandler &prm) dealii::Patterns::Bool(), "Use original form by defualt. Otherwise, split the fluxes."); + prm.declare_entry("two_point_num_flux_type", "KG", + dealii::Patterns::Selection( + "KG | IR | CH | Ra"), + "Two point flux type. " + "Choices are ."); + + prm.declare_entry("use_curvilinear_split_form", "false", + dealii::Patterns::Bool(), + "Use original form by defualt. Otherwise, split the curvilinear fluxes."); + + prm.declare_entry("use_weight_adjusted_mass", "false", + dealii::Patterns::Bool(), + "Use original form by defualt. Otherwise, use the weight adjusted low storage mass matrix for curvilinear."); + prm.declare_entry("use_periodic_bc", "false", dealii::Patterns::Bool(), "Use other boundary conditions by default. Otherwise use periodic (for 1d burgers only"); @@ -82,17 +96,20 @@ void AllParameters::declare_parameters (dealii::ParameterHandler &prm) dealii::Patterns::Bool(), "Not calculate L2 norm by default (M+K). Otherwise, get L2 norm per iteration."); - prm.declare_entry("use_classical_Flux_Reconstruction", "false", + prm.declare_entry("use_classical_FR", "false", dealii::Patterns::Bool(), "Not use Classical Flux Reconstruction by default. Otherwise, use Classical Flux Reconstruction."); prm.declare_entry("flux_reconstruction", "cDG", - dealii::Patterns::Selection("cDG | cSD | cHU | cNegative | cNegative2 | cPlus | cPlus1D |c10Thousand | cHULumped"), + dealii::Patterns::Selection( + "cDG | cSD | cHU | cNegative | cNegative2 | cPlus | c10Thousand | cHULumped"), "Flux Reconstruction. " - "Choices are ."); + "Choices are " + " ."); prm.declare_entry("flux_reconstruction_aux", "kDG", - dealii::Patterns::Selection("kDG | kSD | kHU | kNegative | kNegative2 | kPlus | k10Thousand"), + dealii::Patterns::Selection( + "kDG | kSD | kHU | kNegative | kNegative2 | kPlus | k10Thousand"), "Flux Reconstruction for Auxiliary Equation. " "Choices are ."); @@ -100,6 +117,18 @@ void AllParameters::declare_parameters (dealii::ParameterHandler &prm) dealii::Patterns::Double(1.0,1e200), "Scaling of Symmetric Interior Penalty term to ensure coercivity."); + prm.declare_entry("use_invariant_curl_form", "false", + dealii::Patterns::Bool(), + "Use conservative curl form for metric cofactor by default. If true, then use invariant curl form."); + + prm.declare_entry("use_inverse_mass_on_the_fly", "false", + dealii::Patterns::Bool(), + "Build global mass inverse matrix and apply it. Otherwise, use inverse mass on-the-fly by default for explicit timestepping."); + + prm.declare_entry("energy_file", "energy_file", + dealii::Patterns::FileName(dealii::Patterns::FileName::FileType::input), + "Input file for energy test."); + prm.declare_entry("test_type", "run_control", dealii::Patterns::Selection( " run_control | " @@ -120,6 +149,7 @@ void AllParameters::declare_parameters (dealii::ParameterHandler &prm) " shock_1d | " " euler_naca0012 | " " reduced_order | " + " convection_diffusion_periodicity |" " POD_adaptation | " " POD_adaptive_sampling | " " adaptive_sampling_testing | " @@ -130,7 +160,8 @@ void AllParameters::declare_parameters (dealii::ParameterHandler &prm) " taylor_green_vortex_restart_check | " " time_refinement_study | " " time_refinement_study_reference | " - " burgers_energy_conservation_rrk"), + " burgers_energy_conservation_rrk | " + " euler_ismail_roe_entropy_check"), "The type of test we want to solve. " "Choices are " " ."); + " burgers_energy_conservation_rrk | " + " euler_ismail_roe_entropy_check>."); prm.declare_entry("pde_type", "advection", dealii::Patterns::Selection( @@ -199,19 +232,39 @@ void AllParameters::declare_parameters (dealii::ParameterHandler &prm) " ."); prm.declare_entry("conv_num_flux", "lax_friedrichs", - dealii::Patterns::Selection("lax_friedrichs | roe | l2roe | split_form"), + dealii::Patterns::Selection( + " lax_friedrichs | " + " roe | " + " l2roe | " + " central_flux | " + " two_point_flux | " + " two_point_flux_with_lax_friedrichs_dissipation | " + " two_point_flux_with_roe_dissipation | " + " two_point_flux_with_l2roe_dissipation"), "Convective numerical flux. " - "Choices are ."); + "Choices are " + " ."); prm.declare_entry("diss_num_flux", "symm_internal_penalty", - dealii::Patterns::Selection("symm_internal_penalty | bassi_rebay_2"), + dealii::Patterns::Selection("symm_internal_penalty | bassi_rebay_2 | central_visc_flux"), "Dissipative numerical flux. " - "Choices are ."); + "Choices are ."); prm.declare_entry("solution_vtk_files_directory_name", ".", dealii::Patterns::FileName(dealii::Patterns::FileName::FileType::input), "Name of directory for writing solution vtk files. Current directory by default."); + prm.declare_entry("output_high_order_grid", "false", + dealii::Patterns::Bool(), + "Outputs the high-order mesh vtu files. False by default"); + prm.declare_entry("enable_higher_order_vtk_output", "false", dealii::Patterns::Bool(), "Enable writing of higher-order vtk files." @@ -267,6 +320,7 @@ void AllParameters::parse_parameters (dealii::ParameterHandler &prm) else if (test_string == "euler_vortex") { test_type = euler_vortex; } else if (test_string == "euler_entropy_waves") { test_type = euler_entropy_waves; } else if (test_string == "advection_periodicity") { test_type = advection_periodicity; } + else if (test_string == "convection_diffusion_periodicity") { test_type = convection_diffusion_periodicity; } else if (test_string == "euler_split_taylor_green") { test_type = euler_split_taylor_green; } else if (test_string == "euler_bump_optimization") { test_type = euler_bump_optimization; } else if (test_string == "euler_naca_optimization") { test_type = euler_naca_optimization; } @@ -284,6 +338,7 @@ void AllParameters::parse_parameters (dealii::ParameterHandler &prm) else if (test_string == "time_refinement_study") { test_type = time_refinement_study; } else if (test_string == "time_refinement_study_reference") { test_type = time_refinement_study_reference; } else if (test_string == "burgers_energy_conservation_rrk") { test_type = burgers_energy_conservation_rrk; } + else if (test_string == "euler_ismail_roe_entropy_check") { test_type = euler_ismail_roe_entropy_check; } // WARNING: Must assign model_type before pde_type const std::string model_string = prm.get("model_type"); @@ -337,46 +392,64 @@ void AllParameters::parse_parameters (dealii::ParameterHandler &prm) use_weak_form = prm.get_bool("use_weak_form"); use_collocated_nodes = prm.get_bool("use_collocated_nodes"); use_split_form = prm.get_bool("use_split_form"); + + const std::string two_point_num_flux_string = prm.get("two_point_num_flux_type"); + if (two_point_num_flux_string == "KG") { two_point_num_flux_type = TwoPointNumericalFlux::KG; } + if (two_point_num_flux_string == "IR") { two_point_num_flux_type = TwoPointNumericalFlux::IR; } + if (two_point_num_flux_string == "CH") { two_point_num_flux_type = TwoPointNumericalFlux::CH; } + if (two_point_num_flux_string == "Ra") { two_point_num_flux_type = TwoPointNumericalFlux::Ra; } + + use_curvilinear_split_form = prm.get_bool("use_curvilinear_split_form"); + use_weight_adjusted_mass = prm.get_bool("use_weight_adjusted_mass"); use_periodic_bc = prm.get_bool("use_periodic_bc"); use_energy = prm.get_bool("use_energy"); use_L2_norm = prm.get_bool("use_L2_norm"); - use_classical_FR = prm.get_bool("use_classical_Flux_Reconstruction"); + use_classical_FR = prm.get_bool("use_classical_FR"); sipg_penalty_factor = prm.get_double("sipg_penalty_factor"); + use_invariant_curl_form = prm.get_bool("use_invariant_curl_form"); + use_inverse_mass_on_the_fly = prm.get_bool("use_inverse_mass_on_the_fly"); + + energy_file = prm.get("energy_file"); const std::string conv_num_flux_string = prm.get("conv_num_flux"); - if (conv_num_flux_string == "lax_friedrichs") conv_num_flux_type = lax_friedrichs; - if (conv_num_flux_string == "split_form") conv_num_flux_type = split_form; - if (conv_num_flux_string == "roe") conv_num_flux_type = roe; - if (conv_num_flux_string == "l2roe") conv_num_flux_type = l2roe; + if (conv_num_flux_string == "lax_friedrichs") { conv_num_flux_type = ConvectiveNumericalFlux::lax_friedrichs; } + if (conv_num_flux_string == "roe") { conv_num_flux_type = ConvectiveNumericalFlux::roe; } + if (conv_num_flux_string == "l2roe") { conv_num_flux_type = ConvectiveNumericalFlux::l2roe; } + if (conv_num_flux_string == "central_flux") { conv_num_flux_type = ConvectiveNumericalFlux::central_flux; } + if (conv_num_flux_string == "two_point_flux") { conv_num_flux_type = ConvectiveNumericalFlux::two_point_flux; } + if (conv_num_flux_string == "two_point_flux_with_lax_friedrichs_dissipation") { conv_num_flux_type = ConvectiveNumericalFlux::two_point_flux_with_lax_friedrichs_dissipation; } + if (conv_num_flux_string == "two_point_flux_with_roe_dissipation") { conv_num_flux_type = ConvectiveNumericalFlux::two_point_flux_with_roe_dissipation; } + if (conv_num_flux_string == "two_point_flux_with_l2roe_dissipation") { conv_num_flux_type = ConvectiveNumericalFlux::two_point_flux_with_l2roe_dissipation; } const std::string diss_num_flux_string = prm.get("diss_num_flux"); - if (diss_num_flux_string == "symm_internal_penalty") diss_num_flux_type = symm_internal_penalty; + if (diss_num_flux_string == "symm_internal_penalty") { diss_num_flux_type = symm_internal_penalty; } if (diss_num_flux_string == "bassi_rebay_2") { diss_num_flux_type = bassi_rebay_2; sipg_penalty_factor = 0.0; } + if (diss_num_flux_string == "central_visc_flux") diss_num_flux_type = central_visc_flux; const std::string flux_reconstruction_string = prm.get("flux_reconstruction"); - if (flux_reconstruction_string == "cDG") flux_reconstruction_type = cDG; - if (flux_reconstruction_string == "cSD") flux_reconstruction_type = cSD; - if (flux_reconstruction_string == "cHU") flux_reconstruction_type = cHU; - if (flux_reconstruction_string == "cNegative") flux_reconstruction_type = cNegative; - if (flux_reconstruction_string == "cNegative2") flux_reconstruction_type = cNegative2; - if (flux_reconstruction_string == "cPlus") flux_reconstruction_type = cPlus; - if (flux_reconstruction_string == "cPlus1D") flux_reconstruction_type = cPlus1D; - if (flux_reconstruction_string == "c10Thousand") flux_reconstruction_type = c10Thousand; - if (flux_reconstruction_string == "cHULumped") flux_reconstruction_type = cHULumped; + if (flux_reconstruction_string == "cDG") { flux_reconstruction_type = cDG; } + if (flux_reconstruction_string == "cSD") { flux_reconstruction_type = cSD; } + if (flux_reconstruction_string == "cHU") { flux_reconstruction_type = cHU; } + if (flux_reconstruction_string == "cNegative") { flux_reconstruction_type = cNegative; } + if (flux_reconstruction_string == "cNegative2") { flux_reconstruction_type = cNegative2; } + if (flux_reconstruction_string == "cPlus") { flux_reconstruction_type = cPlus; } + if (flux_reconstruction_string == "c10Thousand") { flux_reconstruction_type = c10Thousand; } + if (flux_reconstruction_string == "cHULumped") { flux_reconstruction_type = cHULumped; } const std::string flux_reconstruction_aux_string = prm.get("flux_reconstruction_aux"); - if (flux_reconstruction_aux_string == "kDG") flux_reconstruction_aux_type = kDG; - if (flux_reconstruction_aux_string == "kSD") flux_reconstruction_aux_type = kSD; - if (flux_reconstruction_aux_string == "kHU") flux_reconstruction_aux_type = kHU; - if (flux_reconstruction_aux_string == "kNegative") flux_reconstruction_aux_type = kNegative; - if (flux_reconstruction_aux_string == "kNegative2") flux_reconstruction_aux_type = kNegative2; - if (flux_reconstruction_aux_string == "kPlus") flux_reconstruction_aux_type = kPlus; - if (flux_reconstruction_aux_string == "k10Thousand") flux_reconstruction_aux_type = k10Thousand; + if (flux_reconstruction_aux_string == "kDG") { flux_reconstruction_aux_type = kDG; } + if (flux_reconstruction_aux_string == "kSD") { flux_reconstruction_aux_type = kSD; } + if (flux_reconstruction_aux_string == "kHU") { flux_reconstruction_aux_type = kHU; } + if (flux_reconstruction_aux_string == "kNegative") { flux_reconstruction_aux_type = kNegative; } + if (flux_reconstruction_aux_string == "kNegative2") { flux_reconstruction_aux_type = kNegative2; } + if (flux_reconstruction_aux_string == "kPlus") { flux_reconstruction_aux_type = kPlus; } + if (flux_reconstruction_aux_string == "k10Thousand") { flux_reconstruction_aux_type = k10Thousand; } solution_vtk_files_directory_name = prm.get("solution_vtk_files_directory_name"); + output_high_order_grid = prm.get_bool("output_high_order_grid"); enable_higher_order_vtk_output = prm.get_bool("enable_higher_order_vtk_output"); pcout << "Parsing linear solver subsection..." << std::endl; diff --git a/src/parameters/all_parameters.h b/src/parameters/all_parameters.h index b6a18c3f9..c1c1a32bc 100644 --- a/src/parameters/all_parameters.h +++ b/src/parameters/all_parameters.h @@ -96,6 +96,17 @@ class AllParameters /// Flag to use split form. bool use_split_form; + /// Two point numerical flux type for split form + enum TwoPointNumericalFlux { KG, IR, CH, Ra }; + /// Store selected TwoPointNumericalFlux from the input file + TwoPointNumericalFlux two_point_num_flux_type; + + /// Flag to use curvilinear metric split form. + bool use_curvilinear_split_form; + + /// Flag to use weight-adjusted Mass Matrix for curvilinear elements. + bool use_weight_adjusted_mass; + /// Flag to use periodic BC. /** Not fully tested. */ @@ -111,9 +122,21 @@ class AllParameters //The default ESFR scheme is the Nonlinearly Stable FR where the volume is also reconstructed bool use_classical_FR; + ///Flag to store global mass matrix + bool store_global_mass_matrix; + /// Scaling of Symmetric Interior Penalty term to ensure coercivity. double sipg_penalty_factor; + /// Flag to use invariant curl form for metric cofactor operator. + bool use_invariant_curl_form; + + /// Flag to use inverse mass matrix on-the-fly for explicit solves. + bool use_inverse_mass_on_the_fly; + + /// Energy file. + std::string energy_file; + /// Number of state variables. Will depend on PDE int nstate; @@ -138,6 +161,7 @@ class AllParameters shock_1d, euler_naca0012, reduced_order, + convection_diffusion_periodicity, POD_adaptation, POD_adaptive_sampling, adaptive_sampling_testing, @@ -149,6 +173,7 @@ class AllParameters time_refinement_study, time_refinement_study_reference, burgers_energy_conservation_rrk, + euler_ismail_roe_entropy_check, }; /// Store selected TestType from the input file. TestType test_type; @@ -192,22 +217,26 @@ class AllParameters }; /// Possible convective numerical flux types - enum ConvectiveNumericalFlux { - lax_friedrichs, - roe, - l2roe, - split_form + enum ConvectiveNumericalFlux { + lax_friedrichs, + roe, + l2roe, + central_flux, + two_point_flux, + two_point_flux_with_lax_friedrichs_dissipation, + two_point_flux_with_roe_dissipation, + two_point_flux_with_l2roe_dissipation }; /// Store convective flux type ConvectiveNumericalFlux conv_num_flux_type; - /// Currently only symmetric internal penalty can be used as an input parameter - enum DissipativeNumericalFlux { symm_internal_penalty, bassi_rebay_2 }; + /// Possible dissipative numerical flux types + enum DissipativeNumericalFlux { symm_internal_penalty, bassi_rebay_2, central_visc_flux }; /// Store diffusive flux type DissipativeNumericalFlux diss_num_flux_type; /// Type of correction in Flux Reconstruction - enum Flux_Reconstruction {cDG, cSD, cHU, cNegative, cNegative2, cPlus, cPlus1D, c10Thousand, cHULumped}; + enum Flux_Reconstruction {cDG, cSD, cHU, cNegative, cNegative2, cPlus, c10Thousand, cHULumped}; /// Store flux reconstruction type Flux_Reconstruction flux_reconstruction_type; @@ -219,6 +248,9 @@ class AllParameters /// Name of directory for writing solution vtk files std::string solution_vtk_files_directory_name; + /// Flag for outputting the high-order grid vtk files + bool output_high_order_grid; + /// Enable writing of higher-order vtk results bool enable_higher_order_vtk_output; diff --git a/src/parameters/parameters_flow_solver.cpp b/src/parameters/parameters_flow_solver.cpp index 7e7bb869c..b1432ba5f 100644 --- a/src/parameters/parameters_flow_solver.cpp +++ b/src/parameters/parameters_flow_solver.cpp @@ -19,6 +19,9 @@ void FlowSolverParam::declare_parameters(dealii::ParameterHandler &prm) " burgers_viscous_snapshot | " " naca0012 | " " burgers_rewienski_snapshot | " + " burgers_inviscid | " + " convection_diffusion | " + " advection | " " periodic_1D_unsteady | " " gaussian_bump | " " sshock "), @@ -28,6 +31,9 @@ void FlowSolverParam::declare_parameters(dealii::ParameterHandler &prm) " burgers_viscous_snapshot | " " naca0012 | " " burgers_rewienski_snapshot | " + " burgers_inviscid | " + " convection_diffusion | " + " advection | " " periodic_1D_unsteady | " " gaussian_bump | " " sshock>. "); @@ -46,6 +52,10 @@ void FlowSolverParam::declare_parameters(dealii::ParameterHandler &prm) dealii::Patterns::Double(0, dealii::Patterns::Double::max_double_value), "Final solution time."); + prm.declare_entry("constant_time_step", "0", + dealii::Patterns::Double(0, dealii::Patterns::Double::max_double_value), + "Constant time step."); + prm.declare_entry("courant_friedrich_lewy_number", "1", dealii::Patterns::Double(0, dealii::Patterns::Double::max_double_value), "Courant-Friedrich-Lewy (CFL) number for constant time step."); @@ -105,11 +115,11 @@ void FlowSolverParam::declare_parameters(dealii::ParameterHandler &prm) "Polynomial degree of the grid. Curvilinear grid if set greater than 1; default is 1."); prm.declare_entry("grid_left_bound", "0.0", - dealii::Patterns::Double(0, dealii::Patterns::Double::max_double_value), + dealii::Patterns::Double(-dealii::Patterns::Double::max_double_value, dealii::Patterns::Double::max_double_value), "Left bound of domain for hyper_cube mesh based cases."); prm.declare_entry("grid_right_bound", "1.0", - dealii::Patterns::Double(0, dealii::Patterns::Double::max_double_value), + dealii::Patterns::Double(-dealii::Patterns::Double::max_double_value, dealii::Patterns::Double::max_double_value), "Right bound of domain for hyper_cube mesh based cases."); prm.declare_entry("number_of_grid_elements_per_dimension", "4", @@ -168,8 +178,17 @@ void FlowSolverParam::declare_parameters(dealii::ParameterHandler &prm) "Choices are " " ."); + prm.declare_entry("do_calculate_numerical_entropy", "false", + dealii::Patterns::Bool(), + "Flag to calculate numerical entropy and write to file. By default, do not calculate."); + } prm.leave_subsection(); + + prm.declare_entry("interpolate_initial_condition", "true", + dealii::Patterns::Bool(), + "Interpolate the initial condition function onto the DG solution. If false, then it projects the physical value. True by default."); + } prm.leave_subsection(); } @@ -179,12 +198,15 @@ void FlowSolverParam::parse_parameters(dealii::ParameterHandler &prm) prm.enter_subsection("flow_solver"); { const std::string flow_case_type_string = prm.get("flow_case_type"); - if (flow_case_type_string == "taylor_green_vortex") {flow_case_type = taylor_green_vortex;} - else if (flow_case_type_string == "burgers_viscous_snapshot") {flow_case_type = burgers_viscous_snapshot;} - else if (flow_case_type_string == "burgers_rewienski_snapshot") {flow_case_type = burgers_rewienski_snapshot;} - else if (flow_case_type_string == "naca0012") {flow_case_type = naca0012;} - else if (flow_case_type_string == "periodic_1D_unsteady") {flow_case_type = periodic_1D_unsteady;} - else if (flow_case_type_string == "gaussian_bump") {flow_case_type = gaussian_bump;} + if (flow_case_type_string == "taylor_green_vortex") {flow_case_type = taylor_green_vortex;} + else if (flow_case_type_string == "burgers_viscous_snapshot") {flow_case_type = burgers_viscous_snapshot;} + else if (flow_case_type_string == "burgers_rewienski_snapshot") {flow_case_type = burgers_rewienski_snapshot;} + else if (flow_case_type_string == "naca0012") {flow_case_type = naca0012;} + else if (flow_case_type_string == "burgers_inviscid") {flow_case_type = burgers_inviscid;} + else if (flow_case_type_string == "convection_diffusion") {flow_case_type = convection_diffusion;} + else if (flow_case_type_string == "advection") {flow_case_type = advection;} + else if (flow_case_type_string == "periodic_1D_unsteady") {flow_case_type = periodic_1D_unsteady;} + else if (flow_case_type_string == "gaussian_bump") {flow_case_type = gaussian_bump;} else if (flow_case_type_string == "sshock") {flow_case_type = sshock;} poly_degree = prm.get_integer("poly_degree"); @@ -195,6 +217,7 @@ void FlowSolverParam::parse_parameters(dealii::ParameterHandler &prm) if(max_poly_degree_for_adaptation == 0) max_poly_degree_for_adaptation = poly_degree; final_time = prm.get_double("final_time"); + constant_time_step = prm.get_double("constant_time_step"); courant_friedrich_lewy_number = prm.get_double("courant_friedrich_lewy_number"); unsteady_data_table_filename = prm.get("unsteady_data_table_filename"); steady_state = prm.get_bool("steady_state"); @@ -238,12 +261,15 @@ void FlowSolverParam::parse_parameters(dealii::ParameterHandler &prm) const std::string density_initial_condition_type_string = prm.get("density_initial_condition_type"); if (density_initial_condition_type_string == "uniform") {density_initial_condition_type = uniform;} else if (density_initial_condition_type_string == "isothermal") {density_initial_condition_type = isothermal;} + do_calculate_numerical_entropy = prm.get_bool("do_calculate_numerical_entropy"); } prm.leave_subsection(); + + interpolate_initial_condition = prm.get_bool("interpolate_initial_condition"); + } prm.leave_subsection(); } } // Parameters namespace - } // PHiLiP namespace diff --git a/src/parameters/parameters_flow_solver.h b/src/parameters/parameters_flow_solver.h index 1020cb3e0..c9657681b 100644 --- a/src/parameters/parameters_flow_solver.h +++ b/src/parameters/parameters_flow_solver.h @@ -20,6 +20,9 @@ class FlowSolverParam burgers_viscous_snapshot, naca0012, burgers_rewienski_snapshot, + burgers_inviscid, + convection_diffusion, + advection, periodic_1D_unsteady, gaussian_bump, sshock @@ -29,6 +32,7 @@ class FlowSolverParam unsigned int poly_degree; ///< Polynomial order (P) of the basis functions for DG. unsigned int max_poly_degree_for_adaptation; ///< Maximum polynomial order of the DG basis functions for adaptation. double final_time; ///< Final solution time + double constant_time_step; ///< Constant time step double courant_friedrich_lewy_number; ///< Courant-Friedrich-Lewy (CFL) number for constant time step /** Name of the output file for writing the unsteady data; @@ -61,7 +65,6 @@ class FlowSolverParam double grid_right_bound; ///< Right bound of domain for hyper_cube mesh based cases unsigned int number_of_grid_elements_per_dimension; ///< Number of grid elements per dimension for hyper_cube mesh based cases int number_of_mesh_refinements; ///< Number of refinements for naca0012 and Gaussian bump based cases - double channel_height; ///< Height of channel for gaussian bump case double channel_length; ///< Width of channel for gaussian bump case double bump_height; ///< Height of gaussian bump @@ -84,12 +87,17 @@ class FlowSolverParam }; /// Selected DensityInitialConditionType from the input file DensityInitialConditionType density_initial_condition_type; + /// For TGV, flag to calculate and write numerical entropy + bool do_calculate_numerical_entropy; /// Declares the possible variables and sets the defaults. static void declare_parameters (dealii::ParameterHandler &prm); /// Parses input file and sets the variables. void parse_parameters (dealii::ParameterHandler &prm); + + ///Interpolate or project the initial condition. + bool interpolate_initial_condition; }; } // Parameters namespace diff --git a/src/parameters/parameters_manufactured_solution.cpp b/src/parameters/parameters_manufactured_solution.cpp index 0386fcdc7..90d197503 100644 --- a/src/parameters/parameters_manufactured_solution.cpp +++ b/src/parameters/parameters_manufactured_solution.cpp @@ -29,6 +29,7 @@ void ManufacturedSolutionParam::declare_parameters(dealii::ParameterHandler &prm " boundary_layer_solution | " " s_shock_solution | " " quadratic_solution | " + " example_solution | " " navah_solution_1 | " " navah_solution_2 | " " navah_solution_3 | " @@ -98,23 +99,24 @@ void ManufacturedSolutionParam::parse_parameters(dealii::ParameterHandler &prm) use_manufactured_source_term = prm.get_bool("use_manufactured_source_term"); const std::string manufactured_solution_string = prm.get("manufactured_solution_type"); - if(manufactured_solution_string == "sine_solution") {manufactured_solution_type = sine_solution;} - else if(manufactured_solution_string == "zero_solution") {manufactured_solution_type = zero_solution;} - else if(manufactured_solution_string == "cosine_solution") {manufactured_solution_type = cosine_solution;} - else if(manufactured_solution_string == "additive_solution") {manufactured_solution_type = additive_solution;} - else if(manufactured_solution_string == "exp_solution") {manufactured_solution_type = exp_solution;} - else if(manufactured_solution_string == "poly_solution") {manufactured_solution_type = poly_solution;} - else if(manufactured_solution_string == "even_poly_solution") {manufactured_solution_type = even_poly_solution;} - else if(manufactured_solution_string == "atan_solution") {manufactured_solution_type = atan_solution;} - else if(manufactured_solution_string == "boundary_layer_solution"){manufactured_solution_type = boundary_layer_solution;} - else if(manufactured_solution_string == "s_shock_solution") {manufactured_solution_type = s_shock_solution;} - else if(manufactured_solution_string == "quadratic_solution") {manufactured_solution_type = quadratic_solution;} - else if(manufactured_solution_string == "navah_solution_1") {manufactured_solution_type = navah_solution_1;} - else if(manufactured_solution_string == "navah_solution_2") {manufactured_solution_type = navah_solution_2;} - else if(manufactured_solution_string == "navah_solution_3") {manufactured_solution_type = navah_solution_3;} - else if(manufactured_solution_string == "navah_solution_4") {manufactured_solution_type = navah_solution_4;} - else if(manufactured_solution_string == "navah_solution_5") {manufactured_solution_type = navah_solution_5;} - + if(manufactured_solution_string == "sine_solution") {manufactured_solution_type = sine_solution;} + else if(manufactured_solution_string == "zero_solution") {manufactured_solution_type = zero_solution;} + else if(manufactured_solution_string == "cosine_solution") {manufactured_solution_type = cosine_solution;} + else if(manufactured_solution_string == "additive_solution") {manufactured_solution_type = additive_solution;} + else if(manufactured_solution_string == "exp_solution") {manufactured_solution_type = exp_solution;} + else if(manufactured_solution_string == "poly_solution") {manufactured_solution_type = poly_solution;} + else if(manufactured_solution_string == "even_poly_solution") {manufactured_solution_type = even_poly_solution;} + else if(manufactured_solution_string == "atan_solution") {manufactured_solution_type = atan_solution;} + else if(manufactured_solution_string == "boundary_layer_solution") {manufactured_solution_type = boundary_layer_solution;} + else if(manufactured_solution_string == "s_shock_solution") {manufactured_solution_type = s_shock_solution;} + else if(manufactured_solution_string == "quadratic_solution") {manufactured_solution_type = quadratic_solution;} + else if(manufactured_solution_string == "example_solution") {manufactured_solution_type = example_solution;} + else if(manufactured_solution_string == "navah_solution_1") {manufactured_solution_type = navah_solution_1;} + else if(manufactured_solution_string == "navah_solution_2") {manufactured_solution_type = navah_solution_2;} + else if(manufactured_solution_string == "navah_solution_3") {manufactured_solution_type = navah_solution_3;} + else if(manufactured_solution_string == "navah_solution_4") {manufactured_solution_type = navah_solution_4;} + else if(manufactured_solution_string == "navah_solution_5") {manufactured_solution_type = navah_solution_5;} + diffusion_tensor[0][0] = prm.get_double("diffusion_00"); diffusion_tensor[0][1] = prm.get_double("diffusion_01"); diffusion_tensor[1][0] = prm.get_double("diffusion_10"); diff --git a/src/parameters/parameters_manufactured_solution.h b/src/parameters/parameters_manufactured_solution.h index f4ba457d9..d48bf6247 100644 --- a/src/parameters/parameters_manufactured_solution.h +++ b/src/parameters/parameters_manufactured_solution.h @@ -32,6 +32,7 @@ class ManufacturedSolutionParam boundary_layer_solution, s_shock_solution, quadratic_solution, + example_solution, navah_solution_1, navah_solution_2, navah_solution_3, @@ -68,3 +69,4 @@ class ManufacturedSolutionParam #endif // __PARAMETERS_MANUFACTURED_SOLUTION_H__ + diff --git a/src/parameters/parameters_navier_stokes.cpp b/src/parameters/parameters_navier_stokes.cpp index 06fbc0633..5921c49c3 100644 --- a/src/parameters/parameters_navier_stokes.cpp +++ b/src/parameters/parameters_navier_stokes.cpp @@ -12,10 +12,15 @@ void NavierStokesParam::declare_parameters (dealii::ParameterHandler &prm) { prm.declare_entry("prandtl_number", "0.72", dealii::Patterns::Double(1e-15, dealii::Patterns::Double::max_double_value), - "Prandlt number"); + "Prandlt number. Default value is 0.72. " + "NOTE: Must be consitent with temperature_inf."); prm.declare_entry("reynolds_number_inf", "10000000.0", dealii::Patterns::Double(1e-15, dealii::Patterns::Double::max_double_value), "Farfield Reynolds number"); + prm.declare_entry("temperature_inf", "273.15", + dealii::Patterns::Double(1e-15, dealii::Patterns::Double::max_double_value), + "Farfield temperature in degree Kelvin [K]. Default value is 273.15K. " + "NOTE: Must be consistent with specified Prandtl number."); prm.declare_entry("nondimensionalized_isothermal_wall_temperature", "1.0", dealii::Patterns::Double(1e-15, dealii::Patterns::Double::max_double_value), "Nondimensionalized isothermal wall temperature."); @@ -33,6 +38,7 @@ void NavierStokesParam::parse_parameters (dealii::ParameterHandler &prm) { prandtl_number = prm.get_double("prandtl_number"); reynolds_number_inf = prm.get_double("reynolds_number_inf"); + temperature_inf = prm.get_double("temperature_inf"); nondimensionalized_isothermal_wall_temperature = prm.get_double("nondimensionalized_isothermal_wall_temperature"); const std::string thermal_boundary_condition_type_string = prm.get("thermal_boundary_condition_type"); diff --git a/src/parameters/parameters_navier_stokes.h b/src/parameters/parameters_navier_stokes.h index cff99d0e7..546e3ea7f 100644 --- a/src/parameters/parameters_navier_stokes.h +++ b/src/parameters/parameters_navier_stokes.h @@ -13,6 +13,7 @@ class NavierStokesParam double prandtl_number; ///< Prandtl number double reynolds_number_inf; ///< Farfield Reynolds number + double temperature_inf; ///< Farfield temperature in degree Kelvin [K] double nondimensionalized_isothermal_wall_temperature; ///< Nondimensionalized isothermal wall temperature /// Types of thermal boundary conditions available. diff --git a/src/parameters/parameters_physics_model.cpp b/src/parameters/parameters_physics_model.cpp index ff77c70fa..a4f342083 100644 --- a/src/parameters/parameters_physics_model.cpp +++ b/src/parameters/parameters_physics_model.cpp @@ -36,12 +36,12 @@ void PhysicsModelParam::declare_parameters (dealii::ParameterHandler &prm) dealii::Patterns::Double(1e-15, dealii::Patterns::Double::max_double_value), "Smagorinsky model constant (default is 0.1)"); - prm.declare_entry("WALE_model_constant", "0.6", - dealii::Patterns::Double(1e-15, 0.6), - "WALE (Wall-Adapting Local Eddy-viscosity) eddy viscosity model constant (default is 0.6)"); + prm.declare_entry("WALE_model_constant", "0.325", + dealii::Patterns::Double(1e-15, dealii::Patterns::Double::max_double_value), + "WALE (Wall-Adapting Local Eddy-viscosity) eddy viscosity model constant (default is 0.325)"); prm.declare_entry("vreman_model_constant", "0.025", - dealii::Patterns::Double(1e-15, 0.6), + dealii::Patterns::Double(1e-15, dealii::Patterns::Double::max_double_value), "Vreman eddy viscosity model constant (default is 0.025)"); prm.declare_entry("ratio_of_filter_width_to_cell_size", "1.0", diff --git a/src/physics/burgers.cpp b/src/physics/burgers.cpp index 6506e1554..cd4de0f95 100644 --- a/src/physics/burgers.cpp +++ b/src/physics/burgers.cpp @@ -68,18 +68,44 @@ ::convective_flux (const std::array &solution) const template std::array,nstate> Burgers::convective_numerical_split_flux ( - const std::array &soln_const, - const std::array & soln_loop) const + const std::array &conservative_soln1, + const std::array &conservative_soln2) const { std::array,nstate> conv_flux; for (int flux_dim=0; flux_dim +real Burgers::convective_surface_numerical_split_flux ( + const real &surface_flux, + const real &flux_interp_to_surface) const +{ + real surface_split_flux; + surface_split_flux = 2.0/3.0 * flux_interp_to_surface + 1.0/3.0 * surface_flux; + return surface_split_flux; +} + +template +std::array Burgers +::compute_entropy_variables ( + const std::array &conservative_soln) const +{ + return conservative_soln; +} + +template +std::array Burgers +::compute_conservative_variables_from_entropy_variables ( + const std::array &entropy_var) const +{ + return entropy_var; +} + template real Burgers ::diffusion_coefficient () const @@ -119,6 +145,13 @@ ::max_convective_eigenvalue (const std::array &soln) const return max_eig; } +template +real Burgers +::max_viscous_eigenvalue (const std::array &/*conservative_soln*/) const +{ + return 0.0; +} + template std::array,nstate> Burgers ::dissipative_flux ( @@ -153,18 +186,36 @@ std::array Burgers ::source_term ( const dealii::Point &pos, const std::array &solution, + const real current_time, const dealii::types::global_dof_index /*cell_index*/) const { - return source_term(pos,solution); + return source_term(pos,solution,current_time); } template std::array Burgers ::source_term ( const dealii::Point &pos, - const std::array &/*solution*/) const + const std::array &/*solution*/, + const real current_time) const { std::array source; + + using TestType = Parameters::AllParameters::TestType; + + if(this->test_type == TestType::burgers_energy_stability){ + for(int istate =0; istate manufactured_gradient = this->manufactured_solution_function.gradient (pos, istate); @@ -203,6 +254,7 @@ ::source_term ( source[istate] += 0.5*manufactured_solution*divergence; } + } // for (int istate=0; istate; + diff --git a/src/physics/burgers.h b/src/physics/burgers.h index 7a633edaf..69e2070a8 100644 --- a/src/physics/burgers.h +++ b/src/physics/burgers.h @@ -48,7 +48,8 @@ class Burgers : public PhysicsBase const bool hasConvection; /// Turns on diffusive part of the Burgers problem. const bool hasDiffusion; - + ///Allows Burgers to distinguish between different unsteady test types. + const Parameters::AllParameters::TestType test_type; ///< Pointer to all parameters /// Constructor Burgers( @@ -56,11 +57,13 @@ class Burgers : public PhysicsBase const bool convection = true, const bool diffusion = true, const dealii::Tensor<2,3,double> input_diffusion_tensor = Parameters::ManufacturedSolutionParam::get_default_diffusion_tensor(), - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr) : - PhysicsBase(input_diffusion_tensor, manufactured_solution_function), + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr, + const Parameters::AllParameters::TestType parameters_test = Parameters::AllParameters::TestType::run_control) : + PhysicsBase(diffusion, input_diffusion_tensor, manufactured_solution_function), diffusion_scaling_coeff(diffusion_coefficient), hasConvection(convection), - hasDiffusion(diffusion) + hasDiffusion(diffusion), + test_type(parameters_test) { static_assert(nstate==dim, "Physics::Burgers() should be created with nstate==dim"); }; @@ -72,8 +75,21 @@ class Burgers : public PhysicsBase /// Convective split flux std::array,nstate> convective_numerical_split_flux ( - const std::array &soln_const, - const std::array & soln_loop) const; + const std::array &conservative_soln1, + const std::array &conservative_soln2) const; + + /// Convective surface split flux + real convective_surface_numerical_split_flux ( + const real &surface_flux, + const real &flux_interp_to_surface) const; + + /// Computes the entropy variables. + std::array compute_entropy_variables ( + const std::array &conservative_soln) const; + + /// Computes the conservative variables from the entropy variables. + std::array compute_conservative_variables_from_entropy_variables ( + const std::array &entropy_var) const; /// Spectral radius of convective term Jacobian is 'c' std::array convective_eigenvalues ( @@ -83,6 +99,9 @@ class Burgers : public PhysicsBase /// Maximum convective eigenvalue used in Lax-Friedrichs real max_convective_eigenvalue (const std::array &soln) const; + /// Maximum viscous eigenvalue. + real max_viscous_eigenvalue (const std::array &soln) const; + // /// Diffusion matrix is identity // std::array,nstate> apply_diffusion_matrix ( // const std::array &solution, @@ -103,12 +122,14 @@ class Burgers : public PhysicsBase std::array source_term ( const dealii::Point &pos, const std::array &solution, + const real current_time, const dealii::types::global_dof_index cell_index) const; /// (function overload) Source term is zero or depends on manufactured solution virtual std::array source_term ( const dealii::Point &pos, - const std::array &solution) const; + const std::array &solution, + const real current_time) const; /// If diffusion is present, assign Dirichlet boundary condition /** Using Neumann boundary conditions might need to modify the functional diff --git a/src/physics/burgers_rewienski.cpp b/src/physics/burgers_rewienski.cpp index abd452e64..0c6d08103 100644 --- a/src/physics/burgers_rewienski.cpp +++ b/src/physics/burgers_rewienski.cpp @@ -72,7 +72,8 @@ template std::array BurgersRewienski ::source_term ( const dealii::Point &pos, - const std::array &/*solution*/) const + const std::array &/*solution*/, + const real /*current_time*/) const { std::array source; diff --git a/src/physics/burgers_rewienski.h b/src/physics/burgers_rewienski.h index fad8a45b6..b6f569c4c 100644 --- a/src/physics/burgers_rewienski.h +++ b/src/physics/burgers_rewienski.h @@ -47,7 +47,8 @@ class BurgersRewienski : public Burgers /// PDE Source term. If rewienski_manufactured_solution==true then the manufactured solution source term is also included. std::array source_term ( const dealii::Point &pos, - const std::array &solution) const override; + const std::array &solution, + const real current_time) const override; /// If diffusion is present, assign Dirichlet boundary condition void boundary_face_values ( diff --git a/src/physics/convection_diffusion.cpp b/src/physics/convection_diffusion.cpp index beb53a989..19b8a2d1c 100644 --- a/src/physics/convection_diffusion.cpp +++ b/src/physics/convection_diffusion.cpp @@ -84,11 +84,36 @@ ::convective_numerical_split_flux ( { std::array arr_avg; for (int i = 0 ; i < nstate; ++i) { - arr_avg[i] = (soln1[i] + soln2[i])/2.; + arr_avg[i] = (soln1[i] + soln2[i])/2.0; } return convective_flux(arr_avg); } +template +real ConvectionDiffusion +::convective_surface_numerical_split_flux ( + const real &surface_flux, + const real &flux_interp_to_surface) const +{ + return 0.5*(flux_interp_to_surface + surface_flux); +} + +template +std::array ConvectionDiffusion +::compute_entropy_variables ( + const std::array &conservative_soln) const +{ + return conservative_soln; +} + +template +std::array ConvectionDiffusion +::compute_conservative_variables_from_entropy_variables ( + const std::array &entropy_var) const +{ + return entropy_var; +} + template dealii::Tensor<1,dim,real> ConvectionDiffusion ::advection_speed () const @@ -147,6 +172,21 @@ ::max_convective_eigenvalue (const std::array &/*soln*/) const return max_eig; } +template +real ConvectionDiffusion +::max_viscous_eigenvalue (const std::array &/*soln*/) const +{ + const real diff_coeff = this->diffusion_coefficient(); + real max_eig = 0; + for (int i=0; idiffusion_tensor[i][j]); + max_eig = std::max(max_eig,abs_visc); + } + } + return max_eig; +} + template std::array,nstate> ConvectionDiffusion ::dissipative_flux ( @@ -181,53 +221,88 @@ std::array ConvectionDiffusion ::source_term ( const dealii::Point &pos, const std::array &solution, + const real current_time, const dealii::types::global_dof_index /*cell_index*/) const { - return source_term(pos,solution); + return source_term(pos,solution,current_time); } template std::array ConvectionDiffusion ::source_term ( const dealii::Point &pos, - const std::array &/*solution*/) const + const std::array &/*solution*/, + const real current_time) const { std::array source; const dealii::Tensor<1,dim,real> velocity_field = this->advection_speed(); const real diff_coeff = diffusion_coefficient(); - for (int istate=0; istate manufactured_gradient = this->manufactured_solution_function->gradient (pos, istate); - // dealii::Tensor<1,dim,real> manufactured_gradient_fd = this->manufactured_solution_function.gradient_fd (pos, istate); - // std::cout<<"FD" < manufactured_hessian = this->manufactured_solution_function->hessian (pos, istate); - // dealii::SymmetricTensor<2,dim,real> manufactured_hessian_fd = this->manufactured_solution_function.hessian_fd (pos, istate); - // std::cout<<"FD" <diffusion_tensor)[dr][dc] * manufactured_hessian[dr][dc]; + using TestType = Parameters::AllParameters::TestType; + + if(this->test_type == TestType::convection_diffusion_periodicity){ + for(int istate =0; istatediffusion_tensor[idim][idim] * sine_term; + } + for(int idim=0; idimdiffusion_tensor[idim][jdim] * cross_term; + } + } + } + } + } + else{ + for (int istate=0; istate manufactured_gradient = this->manufactured_solution_function->gradient (pos, istate); + // dealii::Tensor<1,dim,real> manufactured_gradient_fd = this->manufactured_solution_function.gradient_fd (pos, istate); + // std::cout<<"FD" < manufactured_hessian = this->manufactured_solution_function->hessian (pos, istate); + // dealii::SymmetricTensor<2,dim,real> manufactured_hessian_fd = this->manufactured_solution_function.hessian_fd (pos, istate); + // std::cout<<"FD" <diffusion_tensor)[dr][dc] * manufactured_hessian[dr][dc]; + } } + source[istate] += -diff_coeff*hess; } - source[istate] += -diff_coeff*hess; } return source; } diff --git a/src/physics/convection_diffusion.h b/src/physics/convection_diffusion.h index f0e0e5f30..fac46a774 100644 --- a/src/physics/convection_diffusion.h +++ b/src/physics/convection_diffusion.h @@ -47,6 +47,8 @@ class ConvectionDiffusion : public PhysicsBase const bool hasConvection; ///< Turns ON/OFF convection term. const bool hasDiffusion; ///< Turns ON/OFF diffusion term. + ///Allows convection diffusion to distinguish between different unsteady test types. + const Parameters::AllParameters::TestType test_type; ///< Pointer to all parameters /// Constructor ConvectionDiffusion ( @@ -55,12 +57,14 @@ class ConvectionDiffusion : public PhysicsBase const dealii::Tensor<2,3,double> input_diffusion_tensor = Parameters::ManufacturedSolutionParam::get_default_diffusion_tensor(), const dealii::Tensor<1,3,double> input_advection_vector = Parameters::ManufacturedSolutionParam::get_default_advection_vector(), const double input_diffusion_coefficient = Parameters::ManufacturedSolutionParam::get_default_diffusion_coefficient(), - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr) : - PhysicsBase(input_diffusion_tensor, manufactured_solution_function), + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr, + const Parameters::AllParameters::TestType parameters_test = Parameters::AllParameters::TestType::run_control) : + PhysicsBase(diffusion, input_diffusion_tensor, manufactured_solution_function), linear_advection_velocity{input_advection_vector[0], input_advection_vector[1], input_advection_vector[2]}, diffusion_scaling_coeff(input_diffusion_coefficient), hasConvection(convection), - hasDiffusion(diffusion) + hasDiffusion(diffusion), + test_type(parameters_test) { static_assert(nstate<=5, "Physics::ConvectionDiffusion() should be created with nstate<=5"); }; @@ -70,10 +74,24 @@ class ConvectionDiffusion : public PhysicsBase /// Convective flux: \f$ \mathbf{F}_{conv} = u \f$ std::array,nstate> convective_flux (const std::array &solution) const; + /// Convective numerical split flux for split form std::array,nstate> convective_numerical_split_flux ( const std::array &soln1, const std::array &soln2) const; + /// Convective surface numerical split flux for split form + real convective_surface_numerical_split_flux ( + const real &surface_flux, + const real &flux_interp_to_surface) const; + + /// Computes the entropy variables. + std::array compute_entropy_variables ( + const std::array &conservative_soln) const; + + /// Computes the conservative variables from the entropy variables. + std::array compute_conservative_variables_from_entropy_variables ( + const std::array &entropy_var) const; + /// Spectral radius of convective term Jacobian is 'c' std::array convective_eigenvalues ( const std::array &/*solution*/, @@ -82,6 +100,9 @@ class ConvectionDiffusion : public PhysicsBase /// Maximum convective eigenvalue used in Lax-Friedrichs real max_convective_eigenvalue (const std::array &soln) const; + /// Maximum viscous eigenvalue. + real max_viscous_eigenvalue (const std::array &soln) const; + // /// Diffusion matrix is identity // std::array,nstate> apply_diffusion_matrix ( // const std::array &solution, @@ -102,12 +123,14 @@ class ConvectionDiffusion : public PhysicsBase std::array source_term ( const dealii::Point &pos, const std::array &solution, + const real current_time, const dealii::types::global_dof_index cell_index) const; /// (function overload) Source term is zero or depends on manufactured solution std::array source_term ( const dealii::Point &pos, - const std::array &solution) const; + const std::array &solution, + const real current_time) const; /// If diffusion is present, assign Dirichlet boundary condition /** Using Neumann boundary conditions might need to modify the functional diff --git a/src/physics/euler.cpp b/src/physics/euler.cpp index c3ed04b2e..42fa663db 100644 --- a/src/physics/euler.cpp +++ b/src/physics/euler.cpp @@ -5,6 +5,7 @@ #include "physics.h" #include "euler.h" + const double BIG_NUMBER = 1e100; namespace PHiLiP { @@ -17,8 +18,10 @@ Euler::Euler ( const double mach_inf, const double angle_of_attack, const double side_slip_angle, - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function) - : PhysicsBase(manufactured_solution_function) + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function, + const two_point_num_flux_enum two_point_num_flux_type_input, + const bool has_nonzero_diffusion) + : PhysicsBase(has_nonzero_diffusion,manufactured_solution_function) , ref_length(ref_length) , gam(gamma_gas) , gamm1(gam-1.0) @@ -30,6 +33,7 @@ Euler::Euler ( , sound_inf(1.0/(mach_inf)) , pressure_inf(1.0/(gam*mach_inf_sqr)) , entropy_inf(pressure_inf*pow(density_inf,-gam)) + , two_point_num_flux_type(two_point_num_flux_type_input) //, internal_energy_inf(1.0/(gam*(gam-1.0)*mach_inf_sqr)) // Note: Eq.(3.11.18) has a typo in internal_energy_inf expression, mach_inf_sqr should be in denominator. { @@ -66,16 +70,18 @@ std::array Euler ::source_term ( const dealii::Point &pos, const std::array &conservative_soln, + const real current_time, const dealii::types::global_dof_index /*cell_index*/) const { - return source_term(pos,conservative_soln); + return source_term(pos,conservative_soln,current_time); } template std::array Euler ::source_term ( const dealii::Point &pos, - const std::array &/*conservative_soln*/) const + const std::array &/*conservative_soln*/, + const real /*current_time*/) const { std::array source_term = convective_source_term(pos); return source_term; @@ -292,21 +298,11 @@ ::compute_specific_enthalpy ( const std::array &conservative_soln, template template inline real2 Euler -::compute_dimensional_temperature ( const std::array &primitive_soln ) const +::compute_temperature ( const std::array &primitive_soln ) const { const real2 density = primitive_soln[0]; const real2 pressure = primitive_soln[nstate-1]; - const real2 temperature = gam*pressure/density; - return temperature; -} - -template -template -inline real2 Euler -::compute_temperature ( const std::array &primitive_soln ) const -{ - const real2 dimensional_temperature = compute_dimensional_temperature(primitive_soln); - const real2 temperature = dimensional_temperature * mach_inf_sqr; + const real2 temperature = gam*mach_inf_sqr*(pressure/density); return temperature; } @@ -314,7 +310,7 @@ template inline real Euler ::compute_density_from_pressure_temperature ( const real pressure, const real temperature ) const { - const real density = gam*pressure/temperature * mach_inf_sqr; + const real density = gam*mach_inf_sqr*(pressure/temperature); return density; } @@ -322,7 +318,7 @@ template inline real Euler ::compute_temperature_from_density_pressure ( const real density, const real pressure ) const { - const real temperature = gam*pressure/density * mach_inf_sqr; + const real temperature = gam*mach_inf_sqr*(pressure/density); return temperature; } @@ -398,29 +394,318 @@ template std::array,nstate> Euler ::convective_numerical_split_flux(const std::array &conservative_soln1, const std::array &conservative_soln2) const +{ + std::array,nstate> conv_num_split_flux; + if(two_point_num_flux_type == two_point_num_flux_enum::KG) { + conv_num_split_flux = convective_numerical_split_flux_kennedy_gruber(conservative_soln1, conservative_soln2); + } else if(two_point_num_flux_type == two_point_num_flux_enum::IR) { + conv_num_split_flux = convective_numerical_split_flux_ismail_roe(conservative_soln1, conservative_soln2); + } else if(two_point_num_flux_type == two_point_num_flux_enum::CH) { + conv_num_split_flux = convective_numerical_split_flux_chandrashekar(conservative_soln1, conservative_soln2); + } else if(two_point_num_flux_type == two_point_num_flux_enum::Ra) { + conv_num_split_flux = convective_numerical_split_flux_ranocha(conservative_soln1, conservative_soln2); + } + + return conv_num_split_flux; +} + +template +std::array,nstate> Euler +::convective_numerical_split_flux_kennedy_gruber(const std::array &conservative_soln1, + const std::array &conservative_soln2) const { std::array,nstate> conv_num_split_flux; const real mean_density = compute_mean_density(conservative_soln1, conservative_soln2); const real mean_pressure = compute_mean_pressure(conservative_soln1, conservative_soln2); const dealii::Tensor<1,dim,real> mean_velocities = compute_mean_velocities(conservative_soln1,conservative_soln2); - const real mean_specific_energy = compute_mean_specific_energy(conservative_soln1, conservative_soln2); + const real mean_specific_total_energy = compute_mean_specific_total_energy(conservative_soln1, conservative_soln2); for (int flux_dim = 0; flux_dim < dim; ++flux_dim) { // Density equation - conv_num_split_flux[0][flux_dim] = mean_density * mean_velocities[flux_dim];//conservative_soln[1+flux_dim]; + conv_num_split_flux[0][flux_dim] = mean_density * mean_velocities[flux_dim]; // Momentum equation for (int velocity_dim=0; velocity_dim +std::array Euler +::compute_ismail_roe_parameter_vector_from_primitive(const std::array &primitive_soln) const +{ + // Ismail-Roe parameter vector; Eq (3.14) [Gassner, Winters, and Kopriva, 2016, SBP] + std::array ismail_roe_parameter_vector; + ismail_roe_parameter_vector[0] = sqrt(primitive_soln[0]/primitive_soln[nstate-1]); + for(int d=0; d +std::array,nstate> Euler +::convective_numerical_split_flux_chandrashekar(const std::array &conservative_soln1, + const std::array &conservative_soln2) const +{ + + std::array,nstate> conv_num_split_flux; + const real rho_log = compute_ismail_roe_logarithmic_mean(conservative_soln1[0], conservative_soln2[0]); + const real pressure1 = compute_pressure(conservative_soln1); + const real pressure2 = compute_pressure(conservative_soln2); + + const real beta1 = conservative_soln1[0]/(2.0*pressure1); + const real beta2 = conservative_soln2[0]/(2.0*pressure2); + + const real beta_log = compute_ismail_roe_logarithmic_mean(beta1, beta2); + const dealii::Tensor<1,dim,real> vel1 = compute_velocities(conservative_soln1); + const dealii::Tensor<1,dim,real> vel2 = compute_velocities(conservative_soln2); + + const real pressure_hat = 0.5*(conservative_soln1[0] + conservative_soln2[0])/(2.0*0.5*(beta1+beta2)); + + dealii::Tensor<1,dim,real> vel_avg; + real vel_square_avg = 0.0;; + for(int idim=0; idim +std::array,nstate> Euler +::convective_numerical_split_flux_ranocha(const std::array &conservative_soln1, + const std::array &conservative_soln2) const +{ + + std::array,nstate> conv_num_split_flux; + const real rho_log = compute_ismail_roe_logarithmic_mean(conservative_soln1[0], conservative_soln2[0]); + const real pressure1 = compute_pressure(conservative_soln1); + const real pressure2 = compute_pressure(conservative_soln2); + + const real beta1 = conservative_soln1[0]/(pressure1); + const real beta2 = conservative_soln2[0]/(pressure2); + + const real beta_log = compute_ismail_roe_logarithmic_mean(beta1, beta2); + const dealii::Tensor<1,dim,real> vel1 = compute_velocities(conservative_soln1); + const dealii::Tensor<1,dim,real> vel2 = compute_velocities(conservative_soln2); + + const real pressure_hat = 0.5*(pressure1+pressure2); + + dealii::Tensor<1,dim,real> vel_avg; + real vel_square_avg = 0.0;; + for(int idim=0; idim +real Euler +::compute_ismail_roe_logarithmic_mean(const real val1, const real val2) const +{ + // See Appendix B [Ismail and Roe, 2009, Entropy-Consistent Euler Flux Functions II] + // -- Numerically stable algorithm for computing the logarithmic mean + const real zeta = val1/val2; + const real f = (zeta-1.0)/(zeta+1.0); + const real u = f*f; + + real F; + if(u<1.0e-2){ F = 1.0 + u/3.0 + u*u/5.0 + u*u*u/7.0; } + else { + if constexpr(std::is_same::value) F = std::log(zeta)/2.0/f; + } + + const real log_mean_val = (val1+val2)/(2.0*F); + + return log_mean_val; +} + +template +std::array,nstate> Euler +::convective_numerical_split_flux_ismail_roe(const std::array &conservative_soln1, + const std::array &conservative_soln2) const +{ + // Get Ismail Roe parameter vectors + const std::array parameter_vector1 = compute_ismail_roe_parameter_vector_from_primitive( + convert_conservative_to_primitive(conservative_soln1)); + const std::array parameter_vector2 = compute_ismail_roe_parameter_vector_from_primitive( + convert_conservative_to_primitive(conservative_soln2)); + + // Compute mean (average) parameter vector + std::array avg_parameter_vector; + for(int s=0; s log_mean_parameter_vector; + for(int s=0; s mean_velocities; + const real mean_density = avg_parameter_vector[0]*log_mean_parameter_vector[nstate-1]; + for(int d=0; d,nstate> conv_num_split_flux; + for (int flux_dim = 0; flux_dim < dim; ++flux_dim) + { + // Density equation + conv_num_split_flux[0][flux_dim] = mean_density * mean_velocities[flux_dim]; + // Momentum equation + for (int velocity_dim=0; velocity_dim +real Euler +::convective_surface_numerical_split_flux ( + const real &/*surface_flux*/, + const real &flux_interp_to_surface) const +{ + return flux_interp_to_surface; +} + +template +std::array Euler +::compute_entropy_variables ( + const std::array &conservative_soln) const +{ + std::array entropy_var; + const real density = conservative_soln[0]; + const real pressure = compute_pressure(conservative_soln); + + real entropy = pressure * pow(density, -gam); + if (entropy > 0) entropy = log( entropy ); + else entropy = BIG_NUMBER; + + const real rho_theta = pressure / gamm1; + + entropy_var[0] = (rho_theta *(gam + 1.0 - entropy) - conservative_soln[nstate-1])/rho_theta; + for(int idim=0; idim +std::array Euler +::compute_conservative_variables_from_entropy_variables ( + const std::array &entropy_var) const +{ + //Eq. 119 and 120 from Chan, Jesse. "On discretely entropy conservative and entropy stable discontinuous Galerkin methods." Journal of Computational Physics 362 (2018): 346-374. + //Extrapolated for 3D + std::array conservative_var; + real entropy_var_vel_squared = 0.0; + for(int idim=0; idim +std::array Euler +::compute_kinetic_energy_variables ( + const std::array &conservative_soln) const +{ + std::array kin_energy_var; + const dealii::Tensor<1,dim,real> vel = compute_velocities(conservative_soln); + const real vel2 = compute_velocity_squared(vel); + + kin_energy_var[0] = - 0.5 * vel2; + for(int idim=0; idim inline real Euler:: @@ -456,7 +741,7 @@ compute_mean_velocities(const std::array &conservative_soln1, template inline real Euler:: -compute_mean_specific_energy(const std::array &conservative_soln1, +compute_mean_specific_total_energy(const std::array &conservative_soln1, const std::array &conservative_soln2) const { return ((conservative_soln1[nstate-1]/conservative_soln1[0]) + (conservative_soln2[nstate-1]/conservative_soln2[0]))/2.; @@ -597,6 +882,13 @@ ::max_convective_eigenvalue (const std::array &conservative_soln) c return max_eig; } +template +real Euler +::max_viscous_eigenvalue (const std::array &/*conservative_soln*/) const +{ + return 0.0; +} + template std::array,nstate> Euler ::dissipative_flux ( @@ -1162,17 +1454,6 @@ template FadType Euler < PHILIP_DIM, PHILIP_DIM+2, double >::compute_pres template FadType Euler < PHILIP_DIM, PHILIP_DIM+2, RadType >::compute_pressure< FadType >(const std::array &conservative_soln) const; template FadType Euler < PHILIP_DIM, PHILIP_DIM+2, FadFadType >::compute_pressure< FadType >(const std::array &conservative_soln) const; template FadType Euler < PHILIP_DIM, PHILIP_DIM+2, RadFadType >::compute_pressure< FadType >(const std::array &conservative_soln) const; -// -- compute_dimensional_temperature() -template double Euler < PHILIP_DIM, PHILIP_DIM+2, double >::compute_dimensional_temperature< double >(const std::array &primitive_soln) const; -template FadType Euler < PHILIP_DIM, PHILIP_DIM+2, FadType >::compute_dimensional_temperature< FadType >(const std::array &primitive_soln) const; -template RadType Euler < PHILIP_DIM, PHILIP_DIM+2, RadType >::compute_dimensional_temperature< RadType >(const std::array &primitive_soln) const; -template FadFadType Euler < PHILIP_DIM, PHILIP_DIM+2, FadFadType >::compute_dimensional_temperature< FadFadType >(const std::array &primitive_soln) const; -template RadFadType Euler < PHILIP_DIM, PHILIP_DIM+2, RadFadType >::compute_dimensional_temperature< RadFadType >(const std::array &primitive_soln) const; -// -- -- instantiate all the real types with real2 = FadType for automatic differentiation in NavierStokes::dissipative_flux_directional_jacobian() -template FadType Euler < PHILIP_DIM, PHILIP_DIM+2, double >::compute_dimensional_temperature< FadType >(const std::array &primitive_soln) const; -template FadType Euler < PHILIP_DIM, PHILIP_DIM+2, RadType >::compute_dimensional_temperature< FadType >(const std::array &primitive_soln) const; -template FadType Euler < PHILIP_DIM, PHILIP_DIM+2, FadFadType >::compute_dimensional_temperature< FadType >(const std::array &primitive_soln) const; -template FadType Euler < PHILIP_DIM, PHILIP_DIM+2, RadFadType >::compute_dimensional_temperature< FadType >(const std::array &primitive_soln) const; // -- compute_temperature() template double Euler < PHILIP_DIM, PHILIP_DIM+2, double >::compute_temperature< double >(const std::array &primitive_soln) const; template FadType Euler < PHILIP_DIM, PHILIP_DIM+2, FadType >::compute_temperature< FadType >(const std::array &primitive_soln) const; @@ -1233,4 +1514,3 @@ template dealii::Tensor<1,PHILIP_DIM,FadType > Euler < PHILIP_DIM, PHILIP_DIM+ } // Physics namespace } // PHiLiP namespace - diff --git a/src/physics/euler.h b/src/physics/euler.h index c3921503d..0d3a6edf8 100644 --- a/src/physics/euler.h +++ b/src/physics/euler.h @@ -3,6 +3,7 @@ #include #include "physics.h" +#include "parameters/all_parameters.h" #include "parameters/parameters_manufactured_solution.h" namespace PHiLiP { @@ -86,6 +87,7 @@ class Euler : public PhysicsBase using PhysicsBase::dissipative_flux; using PhysicsBase::source_term; public: + using two_point_num_flux_enum = Parameters::AllParameters::TwoPointNumericalFlux; /// Constructor Euler ( const double ref_length, @@ -93,7 +95,9 @@ class Euler : public PhysicsBase const double mach_inf, const double angle_of_attack, const double side_slip_angle, - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr); + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr, + const two_point_num_flux_enum two_point_num_flux_type = two_point_num_flux_enum::KG, + const bool has_nonzero_diffusion = false); /// Destructor // virtual ~Euler() =0; @@ -123,6 +127,7 @@ class Euler : public PhysicsBase const double sound_inf; ///< Non-dimensionalized sound* at infinity const double pressure_inf; ///< Non-dimensionalized pressure* at infinity const double entropy_inf; ///< Entropy measure at infinity + const two_point_num_flux_enum two_point_num_flux_type; ///< Two point numerical flux type (for split form) double temperature_inf; ///< Non-dimensionalized temperature* at infinity. Should equal 1/density*(inf) double dynamic_pressure_inf; ///< Non-dimensionalized dynamic pressure* at infinity @@ -157,6 +162,9 @@ class Euler : public PhysicsBase /// Maximum convective eigenvalue used in Lax-Friedrichs real max_convective_eigenvalue (const std::array &soln) const; + /// Maximum viscous eigenvalue. + real max_viscous_eigenvalue (const std::array &soln) const; + /// Dissipative flux: 0 std::array,nstate> dissipative_flux ( const std::array &conservative_soln, @@ -172,12 +180,14 @@ class Euler : public PhysicsBase std::array source_term ( const dealii::Point &pos, const std::array &conservative_soln, + const real current_time, const dealii::types::global_dof_index cell_index) const; /// (function overload) Source term is zero or depends on manufactured solution virtual std::array source_term ( const dealii::Point &pos, - const std::array &conservative_soln) const; + const std::array &conservative_soln, + const real current_time) const; /// Convective flux contribution to the source term std::array convective_source_term ( @@ -250,10 +260,6 @@ class Euler : public PhysicsBase /// Given conservative variables, returns Mach number real compute_mach_number ( const std::array &conservative_soln ) const; - /// Given primitive variables, returns DIMENSIONALIZED temperature using the equation of state - template - real2 compute_dimensional_temperature ( const std::array &primitive_soln ) const; - /// Given primitive variables, returns NON-DIMENSIONALIZED temperature using free-stream non-dimensionalization /** See the book I do like CFD, sec 4.14.2 */ template @@ -271,12 +277,31 @@ class Euler : public PhysicsBase /** See the book I do like CFD, sec 4.14.2 */ real compute_pressure_from_density_temperature ( const real density, const real temperature ) const; - /// The Euler split form is that of Kennedy & Gruber. - /** Refer to Gassner's paper (2016) Eq. 3.10 for more information: */ + /// The Euler split form is that of Kennedy & Gruber or Ismail & Roe. std::array,nstate> convective_numerical_split_flux ( const std::array &conservative_soln1, const std::array &conservative_soln2) const; + /// Convective Numerical Split Flux for split form + real convective_surface_numerical_split_flux ( + const real &surface_flux, + const real &flux_interp_to_surface) const; + + /// Computes the entropy variables. + /// Given conservative variables [density, [momentum], total energy], + /// Computes entropy variables according to Chan 2018, eq. 119 + std::array compute_entropy_variables ( + const std::array &conservative_soln) const; + + /// Computes the conservative variables [density, [momentum], total energy + /// from the entropy variables according to Chan 2018, eq. 120 + std::array compute_conservative_variables_from_entropy_variables ( + const std::array &entropy_var) const; + + /// Computes the kinetic energy variables. + std::array compute_kinetic_energy_variables ( + const std::array &conservative_soln) const; + /// Mean density given two sets of conservative solutions. /** Used in the implementation of the split form. */ @@ -298,10 +323,10 @@ class Euler : public PhysicsBase const std::array &conservative_soln1, const std::array &convervative_soln2) const; - /// Mean specific energy given two sets of conservative solutions. + /// Mean specific total energy given two sets of conservative solutions. /** Used in the implementation of the split form. */ - real compute_mean_specific_energy( + real compute_mean_specific_total_energy( const std::array &conservative_soln1, const std::array &convervative_soln2) const; @@ -398,6 +423,35 @@ class Euler : public PhysicsBase /// Get manufactured solution gradient std::array,nstate> get_manufactured_solution_gradient( const dealii::Point &pos) const; + + /** Entropy conserving split form flux of Kennedy and Gruber. + * Refer to Gassner's paper (2016) Eq. 3.10 */ + std::array,nstate> convective_numerical_split_flux_kennedy_gruber ( + const std::array &conservative_soln1, + const std::array &conservative_soln2) const; + + /// Compute Ismail-Roe parameter vector from primitive solution + std::array compute_ismail_roe_parameter_vector_from_primitive( + const std::array &primitive_soln) const; + + /// Compute Ismail-Roe logarithmic mean + real compute_ismail_roe_logarithmic_mean(const real val1, const real val2) const; + + /** Entropy conserving split form flux of Ismail & Roe. + * Refer to Gassner's paper (2016) Eq. 3.17 */ + std::array,nstate> convective_numerical_split_flux_ismail_roe ( + const std::array &conservative_soln1, + const std::array &conservative_soln2) const; + + /// Chandrashekar entropy conserving flux. + std::array,nstate> convective_numerical_split_flux_chandrashekar ( + const std::array &conservative_soln1, + const std::array &conservative_soln2) const; + + /// Ranocha pressure equilibrium preserving, entropy and energy conserving flux. + std::array,nstate> convective_numerical_split_flux_ranocha ( + const std::array &conservative_soln1, + const std::array &conservative_soln2) const; }; } // Physics namespace diff --git a/src/physics/initial_conditions/CMakeLists.txt b/src/physics/initial_conditions/CMakeLists.txt index 6e39aedef..ddc51749e 100644 --- a/src/physics/initial_conditions/CMakeLists.txt +++ b/src/physics/initial_conditions/CMakeLists.txt @@ -1,22 +1,26 @@ set(INITIAL_CONDITIONS_SOURCE - initial_condition.cpp + set_initial_condition.cpp + initial_condition_function.cpp ) foreach(dim RANGE 1 3) # Output library string(CONCAT InitialConditionsLib InitialConditions_${dim}D) add_library(${InitialConditionsLib} STATIC ${INITIAL_CONDITIONS_SOURCE}) - # Link with PhysicsLib + target_compile_definitions(${InitialConditionsLib} PRIVATE PHILIP_DIM=${dim}) + + # Link with Libraries string(CONCAT PhysicsLib Physics_${dim}D) + string(CONCAT DiscontinuousGalerkinLib DiscontinuousGalerkin_${dim}D) target_link_libraries(${InitialConditionsLib} ${PhysicsLib}) - - target_compile_definitions(${InitialConditionsLib} PRIVATE PHILIP_DIM=${dim}) - unset(PhysicsLib) + target_link_libraries(${InitialConditionsLib} ${DiscontinuousGalerkinLib}) # Setup target with deal.II if(NOT DOC_ONLY) DEAL_II_SETUP_TARGET(${InitialConditionsLib}) endif() + unset(PhysicsLib) + unset(DiscontinuousGalerkinLib) unset(InitialConditionsLib) -endforeach() \ No newline at end of file +endforeach() diff --git a/src/physics/initial_conditions/initial_condition.cpp b/src/physics/initial_conditions/initial_condition_function.cpp similarity index 50% rename from src/physics/initial_conditions/initial_condition.cpp rename to src/physics/initial_conditions/initial_condition_function.cpp index e41731317..22d28024e 100644 --- a/src/physics/initial_conditions/initial_condition.cpp +++ b/src/physics/initial_conditions/initial_condition_function.cpp @@ -1,7 +1,19 @@ #include -#include "initial_condition.h" +#include "initial_condition_function.h" namespace PHiLiP { + +// ========================================================= +// Initial Condition Base Class +// ========================================================= +template +InitialConditionFunction +::InitialConditionFunction () + : dealii::Function(nstate)//,0.0) // 0.0 denotes initial time (t=0) +{ + // Nothing to do here yet +} + // ======================================================== // TAYLOR GREEN VORTEX -- Initial Condition (Uniform density) // ======================================================== @@ -158,6 +170,165 @@ ::value(const dealii::Point &point, const unsigned int /*istate*/) con } +// ======================================================== +// 1D BURGERS Inviscid -- Initial Condition +// ======================================================== +template +InitialConditionFunction_BurgersInviscid +::InitialConditionFunction_BurgersInviscid () + : InitialConditionFunction() +{ + // Nothing to do here yet +} + +template +inline real InitialConditionFunction_BurgersInviscid +::value(const dealii::Point &point, const unsigned int /*istate*/) const +{ + real value = 1.0; + if constexpr(dim >= 1) + value *= cos(dealii::numbers::PI*point[0]); + if constexpr(dim >= 2) + value *= cos(dealii::numbers::PI*point[1]); + if constexpr(dim == 3) + value *= cos(dealii::numbers::PI*point[2]); + + return value; +} + +// ======================================================== +// 1D BURGERS Inviscid Energy-- Initial Condition +// ======================================================== +template +InitialConditionFunction_BurgersInviscidEnergy +::InitialConditionFunction_BurgersInviscidEnergy () + : InitialConditionFunction() +{ + // Nothing to do here yet +} + +template +inline real InitialConditionFunction_BurgersInviscidEnergy +::value(const dealii::Point &point, const unsigned int /*istate*/) const +{ + real value = 1.0; + if constexpr(dim >= 1) + value *= sin(dealii::numbers::PI*point[0]); + if constexpr(dim >= 2) + value *= sin(dealii::numbers::PI*point[1]); + if constexpr(dim == 3) + value *= sin(dealii::numbers::PI*point[2]); + + value += 0.01; + return value; +} + +// ======================================================== +// Advection -- Initial Condition +// ======================================================== +template +InitialConditionFunction_AdvectionEnergy +::InitialConditionFunction_AdvectionEnergy () + : InitialConditionFunction() +{ + // Nothing to do here yet +} + +template +inline real InitialConditionFunction_AdvectionEnergy +::value(const dealii::Point &point, const unsigned int /*istate*/) const +{ + real value = 1.0; + if constexpr(dim >= 1) + value *= exp(-20.0*point[0]*point[0]); + if constexpr(dim >= 2) + value *= exp(-20.0*point[1]*point[1]); + if constexpr(dim == 3) + value *= exp(-20.0*point[2]*point[2]); + + return value; +} + +// ======================================================== +// Advection OOA -- Initial Condition +// ======================================================== +template +InitialConditionFunction_Advection +::InitialConditionFunction_Advection() + : InitialConditionFunction() +{ + // Nothing to do here yet +} + +template +inline real InitialConditionFunction_Advection +::value(const dealii::Point &point, const unsigned int /*istate*/) const +{ + real value = 1.0; + if constexpr(dim >= 1) + value *= sin(2.0*dealii::numbers::PI*point[0]); + if constexpr(dim >= 2) + value *= sin(2.0*dealii::numbers::PI*point[1]); + if constexpr(dim == 3) + value *= sin(2.0*dealii::numbers::PI*point[2]); + + return value; +} + +// ======================================================== +// Convection_diffusion -- Initial Condition +// ======================================================== +template +InitialConditionFunction_ConvDiff +::InitialConditionFunction_ConvDiff () + : InitialConditionFunction() +{ + // Nothing to do here yet +} + +template +inline real InitialConditionFunction_ConvDiff +::value(const dealii::Point &point, const unsigned int /*istate*/) const +{ + real value = 1.0; + if constexpr(dim >= 1) + value *= sin(dealii::numbers::PI*point[0]); + if constexpr(dim >= 2) + value *= sin(dealii::numbers::PI*point[1]); + if constexpr(dim == 3) + value *= sin(dealii::numbers::PI*point[2]); + + return value; +} + +// ======================================================== +// Convection_diffusion Energy -- Initial Condition +// ======================================================== +template +InitialConditionFunction_ConvDiffEnergy +::InitialConditionFunction_ConvDiffEnergy () + : InitialConditionFunction() +{ + // Nothing to do here yet +} + +template +inline real InitialConditionFunction_ConvDiffEnergy +::value(const dealii::Point &point, const unsigned int /*istate*/) const +{ + real value = 1.0; + if constexpr(dim >= 1) + value *= sin(dealii::numbers::PI*point[0]); + if constexpr(dim >= 2) + value *= sin(dealii::numbers::PI*point[1]); + if constexpr(dim == 3) + value *= sin(dealii::numbers::PI*point[2]); + + value += 0.1; + + return value; +} + // ======================================================== // 1D SINE -- Initial Condition for advection_explicit_time_study // ======================================================== @@ -181,18 +352,27 @@ ::value(const dealii::Point &point, const unsigned int /*istate*/) con return value; } - -//========================================================= -// FLOW SOLVER -- Initial Condition Base Class + Factory -//========================================================= +// ======================================================== +// ZERO INITIAL CONDITION +// ======================================================== template -InitialConditionFunction -::InitialConditionFunction () - : dealii::Function(nstate)//,0.0) // 0.0 denotes initial time (t=0) +InitialConditionFunction_Zero +::InitialConditionFunction_Zero() + : InitialConditionFunction() { // Nothing to do here yet } +template +real InitialConditionFunction_Zero +::value(const dealii::Point &/*point*/, const unsigned int /*istate*/) const +{ + return 0.0; +} + +// ========================================================= +// Initial Condition Factory +// ========================================================= template std::shared_ptr> InitialConditionFactory::create_InitialConditionFunction( @@ -215,11 +395,11 @@ InitialConditionFactory::create_InitialConditionFunction( } } } else if (flow_type == FlowCaseEnum::burgers_rewienski_snapshot) { - if constexpr (dim==1 && nstate==dim) return std::make_shared > (); + if constexpr (dim==1 && nstate==1) return std::make_shared > (); } else if (flow_type == FlowCaseEnum::burgers_viscous_snapshot) { - if constexpr (dim==1 && nstate==dim) return std::make_shared > (); - } else if (flow_type == FlowCaseEnum::naca0012 || flow_type == FlowCaseEnum::gaussian_bump) { - if constexpr (dim==2 && nstate==dim+2){ + if constexpr (dim==1 && nstate==1) return std::make_shared > (); + } else if (flow_type == FlowCaseEnum::naca0012 || flow_type == FlowCaseEnum::gaussian_bump) { + if constexpr (dim==2 && nstate==dim+2) { Physics::Euler euler_physics_double = Physics::Euler( param->euler_param.ref_length, param->euler_param.gamma_gas, @@ -228,48 +408,56 @@ InitialConditionFactory::create_InitialConditionFunction( param->euler_param.side_slip_angle); return std::make_shared>(euler_physics_double); } - } else if (flow_type == FlowCaseEnum::periodic_1D_unsteady){ - if constexpr (dim==1 && nstate==dim) return std::make_shared > (); + } else if (flow_type == FlowCaseEnum::burgers_inviscid && param->use_energy==false) { + if constexpr (dim==1 && nstate==1) return std::make_shared > (); + } else if (flow_type == FlowCaseEnum::burgers_inviscid && param->use_energy==true) { + if constexpr (dim==1 && nstate==1) return std::make_shared > (); + } else if (flow_type == FlowCaseEnum::advection && param->use_energy==true) { + if constexpr (nstate==1) return std::make_shared > (); + } else if (flow_type == FlowCaseEnum::advection && param->use_energy==false) { + if constexpr (nstate==1) return std::make_shared > (); + } else if (flow_type == FlowCaseEnum::convection_diffusion && !param->use_energy) { + if constexpr (nstate==1) return std::make_shared > (); + } else if (flow_type == FlowCaseEnum::convection_diffusion && param->use_energy) { + return std::make_shared > (); + } else if (flow_type == FlowCaseEnum::periodic_1D_unsteady) { + if constexpr (dim==1 && nstate==1) return std::make_shared > (); } else if (flow_type == FlowCaseEnum::sshock) { if constexpr (dim==2 && nstate==1) return std::make_shared > (); } else { - std::cout << "Invalid Flow Case Type. You probably forgot to add it to the list of flow cases in initial_condition.cpp" << std::endl; + std::cout << "Invalid Flow Case Type. You probably forgot to add it to the list of flow cases in initial_condition_function.cpp" << std::endl; std::abort(); } return nullptr; } -// ======================================================== -// ZERO INITIAL CONDITION -// ======================================================== -template -real InitialConditionFunction_Zero :: value(const dealii::Point &/*point*/, const unsigned int /*istate*/) const -{ - return 0.0; -} - -template class InitialConditionFunction ; -template class InitialConditionFunction ; -template class InitialConditionFunction ; -template class InitialConditionFunction ; -template class InitialConditionFunction ; +template class InitialConditionFunction ; +template class InitialConditionFunction ; template class InitialConditionFactory ; template class InitialConditionFactory ; template class InitialConditionFactory ; template class InitialConditionFactory ; template class InitialConditionFactory ; + #if PHILIP_DIM==1 -template class InitialConditionFunction_BurgersViscous; -template class InitialConditionFunction_BurgersRewienski; +template class InitialConditionFunction_BurgersViscous ; +template class InitialConditionFunction_BurgersRewienski ; +template class InitialConditionFunction_BurgersInviscid ; +template class InitialConditionFunction_BurgersInviscidEnergy ; #endif #if PHILIP_DIM==3 -template class InitialConditionFunction_TaylorGreenVortex ; -template class InitialConditionFunction_TaylorGreenVortex_Isothermal ; +template class InitialConditionFunction_TaylorGreenVortex ; +template class InitialConditionFunction_TaylorGreenVortex_Isothermal ; #endif -template class InitialConditionFunction_Zero ; -template class InitialConditionFunction_Zero ; -template class InitialConditionFunction_Zero ; -template class InitialConditionFunction_Zero ; -template class InitialConditionFunction_Zero ; +// functions instantiated for all dim +template class InitialConditionFunction_Zero ; +template class InitialConditionFunction_Zero ; +template class InitialConditionFunction_Zero ; +template class InitialConditionFunction_Zero ; +template class InitialConditionFunction_Zero ; +template class InitialConditionFunction_Advection ; +template class InitialConditionFunction_AdvectionEnergy ; +template class InitialConditionFunction_ConvDiff ; +template class InitialConditionFunction_ConvDiffEnergy ; } // PHiLiP namespace diff --git a/src/physics/initial_conditions/initial_condition.h b/src/physics/initial_conditions/initial_condition_function.h similarity index 67% rename from src/physics/initial_conditions/initial_condition.h rename to src/physics/initial_conditions/initial_condition_function.h index c74228e42..b2fb6720c 100644 --- a/src/physics/initial_conditions/initial_condition.h +++ b/src/physics/initial_conditions/initial_condition_function.h @@ -1,5 +1,5 @@ -#ifndef __INITIAL_CONDITION_H__ -#define __INITIAL_CONDITION_H__ +#ifndef __INITIAL_CONDITION_FUNCTION_H__ +#define __INITIAL_CONDITION_FUNCTION_H__ // for the initial condition function: #include @@ -155,6 +155,107 @@ class InitialConditionFunction_BurgersViscous: public InitialConditionFunction &point, const unsigned int istate = 0) const override; }; +/// Initial Condition Function: 1D Burgers Inviscid +template +class InitialConditionFunction_BurgersInviscid: public InitialConditionFunction +{ +protected: + using dealii::Function::value; ///< dealii::Function we are templating on + +public: + /// Constructor for InitialConditionFunction_BurgersInviscid + /** Calls the Function(const unsigned int n_components) constructor in deal.II*/ + InitialConditionFunction_BurgersInviscid (); + + /// Value of initial condition + real value (const dealii::Point &point, const unsigned int istate = 0) const override; +}; + +/// Initial Condition Function: 1D Burgers Inviscid Energy +template +class InitialConditionFunction_BurgersInviscidEnergy + : public InitialConditionFunction +{ +protected: + using dealii::Function::value; ///< dealii::Function we are templating on + +public: + /// Constructor for InitialConditionFunction_BurgersInviscidEnergy + /** Calls the Function(const unsigned int n_components) constructor in deal.II*/ + InitialConditionFunction_BurgersInviscidEnergy (); + + /// Value of initial condition + real value (const dealii::Point &point, const unsigned int istate) const override; +}; + +/// Initial Condition Function: 1D Burgers Inviscid +template +class InitialConditionFunction_Advection + : public InitialConditionFunction +{ +protected: + using dealii::Function::value; ///< dealii::Function we are templating on + +public: + /// Constructor for InitialConditionFunction_Inviscid + /** Calls the Function(const unsigned int n_components) constructor in deal.II*/ + InitialConditionFunction_Advection (); + + /// Value of initial condition + real value (const dealii::Point &point, const unsigned int istate) const override; +}; + +/// Initial Condition Function: Advection Energy +template +class InitialConditionFunction_AdvectionEnergy + : public InitialConditionFunction +{ +protected: + using dealii::Function::value; ///< dealii::Function we are templating on + +public: + /// Constructor for InitialConditionFunction_AdvectionEnergy + /** Calls the Function(const unsigned int n_components) constructor in deal.II*/ + InitialConditionFunction_AdvectionEnergy (); + + /// Value of initial condition + real value (const dealii::Point &point, const unsigned int istate) const override; +}; + +/// Initial Condition Function: Convection Diffusion Orders of Accuracy +template +class InitialConditionFunction_ConvDiff + : public InitialConditionFunction +{ +protected: + using dealii::Function::value; ///< dealii::Function we are templating on + +public: + /// Constructor for InitialConditionFunction_ConvDiffEnergy + /** Calls the Function(const unsigned int n_components) constructor in deal.II*/ + InitialConditionFunction_ConvDiff (); + + /// Value of initial condition + real value (const dealii::Point &point, const unsigned int istate) const override; +}; + +/// Initial Condition Function: Convection Diffusion Energy +template +class InitialConditionFunction_ConvDiffEnergy + : public InitialConditionFunction +{ +protected: + using dealii::Function::value; ///< dealii::Function we are templating on + +public: + /// Constructor for InitialConditionFunction_ConvDiffEnergy + /** Calls the Function(const unsigned int n_components) constructor in deal.II*/ + InitialConditionFunction_ConvDiffEnergy (); + + /// Value of initial condition + real value (const dealii::Point &point, const unsigned int istate) const override; +}; + /// Initial Condition Function: 1D Sine Function; used for temporal convergence template class InitialConditionFunction_1DSine @@ -171,6 +272,20 @@ class InitialConditionFunction_1DSine real value (const dealii::Point &point, const unsigned int istate = 0) const override; }; +/// Initial condition 0. +template +class InitialConditionFunction_Zero : public InitialConditionFunction +{ +protected: + using dealii::Function::value; ///< dealii::Function we are templating on + +public: + /// Constructor + InitialConditionFunction_Zero(); + + /// Returns zero. + real value(const dealii::Point &point, const unsigned int istate = 0) const override; +}; /// Initial condition function factory template @@ -189,22 +304,5 @@ class InitialConditionFactory Parameters::AllParameters const *const param); }; -/// Initial condition 0. -template -class InitialConditionFunction_Zero : public InitialConditionFunction -{ -protected: - using dealii::Function::value; ///< dealii::Function we are templating on - -public: - /// Constructor to initialize dealii::Function - InitialConditionFunction_Zero() - : InitialConditionFunction() - {} - - /// Returns zero. - real value(const dealii::Point &point, const unsigned int istate = 0) const override; -}; - } // PHiLiP namespace #endif diff --git a/src/physics/initial_conditions/set_initial_condition.cpp b/src/physics/initial_conditions/set_initial_condition.cpp new file mode 100644 index 000000000..8630f86c8 --- /dev/null +++ b/src/physics/initial_conditions/set_initial_condition.cpp @@ -0,0 +1,92 @@ +#include "set_initial_condition.h" +#include +// #include + +namespace PHiLiP{ + +template +void SetInitialCondition::set_initial_condition( + std::shared_ptr< InitialConditionFunction > initial_condition_function_input, + std::shared_ptr< PHiLiP::DGBase > dg_input, + const Parameters::AllParameters *const parameters_input) +{ + // Apply initial condition depending on the application type + const bool interpolate_initial_condition = parameters_input->flow_solver_param.interpolate_initial_condition; + if(interpolate_initial_condition == true) { + // for non-curvilinear + SetInitialCondition::interpolate_initial_condition(initial_condition_function_input, dg_input); + } else { + // for curvilinear + SetInitialCondition::project_initial_condition(initial_condition_function_input, dg_input); + } +} + +template +void SetInitialCondition::interpolate_initial_condition( + std::shared_ptr< InitialConditionFunction > &initial_condition_function, + std::shared_ptr < PHiLiP::DGBase > &dg) +{ + dealii::LinearAlgebra::distributed::Vector solution_no_ghost; + solution_no_ghost.reinit(dg->locally_owned_dofs, MPI_COMM_WORLD); + dealii::VectorTools::interpolate(dg->dof_handler,*initial_condition_function,solution_no_ghost); + dg->solution = solution_no_ghost; +} + +template +void SetInitialCondition::project_initial_condition( + std::shared_ptr< InitialConditionFunction > &initial_condition_function, + std::shared_ptr < PHiLiP::DGBase > &dg) +{ + // Commented since this has not yet been tested + // dealii::LinearAlgebra::distributed::Vector solution_no_ghost; + // solution_no_ghost.reinit(dg->locally_owned_dofs, MPI_COMM_WORLD); + // dealii::AffineConstraints affine_constraints(dof_handler.locally_owned_dofs()); + // dealii::VectorTools::project(*(dg->high_order_grid->mapping_fe_field),dg->dof_handler,affine_constraints,dg->volume_quadrature_collection,*initial_condition_function,solution_no_ghost); + // dg->solution = solution_no_ghost; + + //Note that for curvilinear, can't use dealii interpolate since it doesn't project at the correct order. + //Thus we interpolate it directly. + const auto mapping = (*(dg->high_order_grid->mapping_fe_field)); + dealii::hp::MappingCollection mapping_collection(mapping); + dealii::hp::FEValues fe_values_collection(mapping_collection, dg->fe_collection, dg->volume_quadrature_collection, + dealii::update_quadrature_points); + const unsigned int max_dofs_per_cell = dg->dof_handler.get_fe_collection().max_dofs_per_cell(); + std::vector current_dofs_indices(max_dofs_per_cell); + OPERATOR::vol_projection_operator vol_projection(1, dg->max_degree, dg->max_grid_degree); + vol_projection.build_1D_volume_operator(dg->oneD_fe_collection_1state[dg->max_degree], dg->oneD_quadrature_collection[dg->max_degree]); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell) { + if (!current_cell->is_locally_owned()) continue; + + const int i_fele = current_cell->active_fe_index(); + const int i_quad = i_fele; + const int i_mapp = 0; + fe_values_collection.reinit (current_cell, i_quad, i_mapp, i_fele); + const dealii::FEValues &fe_values = fe_values_collection.get_present_fe_values(); + const unsigned int poly_degree = i_fele; + const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size(); + const unsigned int n_dofs_cell = dg->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_shape_fns = n_dofs_cell/nstate; + current_dofs_indices.resize(n_dofs_cell); + current_cell->get_dof_indices (current_dofs_indices); + for(int istate=0; istate exact_value(n_quad_pts); + for(unsigned int iquad=0; iquad qpoint = (fe_values.quadrature_point(iquad)); + exact_value[iquad] = initial_condition_function->value(qpoint, istate); + } + std::vector sol(n_shape_fns); + vol_projection.matrix_vector_mult_1D(exact_value, sol, vol_projection.oneD_vol_operator); + for(unsigned int ishape=0; ishapesolution[current_dofs_indices[ishape+istate*n_shape_fns]] = sol[ishape]; + } + } + } +} + +template class SetInitialCondition; +template class SetInitialCondition; +template class SetInitialCondition; +template class SetInitialCondition; +template class SetInitialCondition; + +}//end of namespace PHILIP diff --git a/src/physics/initial_conditions/set_initial_condition.h b/src/physics/initial_conditions/set_initial_condition.h new file mode 100644 index 000000000..b0dff8ea4 --- /dev/null +++ b/src/physics/initial_conditions/set_initial_condition.h @@ -0,0 +1,42 @@ +#ifndef __SET_INITIAL_CONDITION_H__ +#define __SET_INITIAL_CONDITION_H__ + +#include "parameters/all_parameters.h" +#include "dg/dg.h" +#include "initial_condition_function.h" + +namespace PHiLiP { + +/// Class for setting/applying the initial condition +template +class SetInitialCondition +{ +public: + /// Applies the given initial condition function to the given dg object + static void set_initial_condition( + std::shared_ptr< InitialConditionFunction > initial_condition_function_input, + std::shared_ptr< PHiLiP::DGBase > dg_input, + const Parameters::AllParameters *const parameters_input); +private: + ///Interpolates the initial condition function onto the dg solution. + static void interpolate_initial_condition( + std::shared_ptr< InitialConditionFunction > &initial_condition_function, + std::shared_ptr < PHiLiP::DGBase > &dg); + + ///Projects the initial condition function physical value onto the dg solution modal coefficients. + /*This is critical for curvilinear coordinates since the physical coordinates are + * nonlinear functions of the reference coordinates. This leads to the interpolation + * of the dealii::function not equivalent to the projection of the function on the flux + * nodes to the modal coefficients. The latter is the correct form. + * This differs from dealii::project, since here, the projection is purely in the reference space. That is, we solve + * \f$ \hat{\mathbf{f}}^T = \mathbf{M}^{-1} \int_{\mathbf{\Omega}_r} \mathbf{\chi}^T \mathbf{f} d\mathbf{\Omega}_r \f$ where \f$\mathbf{\chi}\f$ are the reference basis functions, and \f$\mathbf{M}\f$ is the reference mass matrix. + * Note that the physical mapping only appears in the function to be projected \f$\mathbf{f}\f$ and the determinant of the metric Jacobian is not in the projection. + * For more information, please refer to Sections 3.1 and 3.2 in Cicchino, Alexander, et al. "Provably stable flux reconstruction high-order methods on curvilinear elements." Journal of Computational Physics (2022): 111259. + */ + static void project_initial_condition( + std::shared_ptr< InitialConditionFunction > &initial_condition_function, + std::shared_ptr < PHiLiP::DGBase > &dg); +}; + +}//end PHiLiP namespace +#endif diff --git a/src/physics/large_eddy_simulation.cpp b/src/physics/large_eddy_simulation.cpp index 6f1b9da38..6bb8b901f 100644 --- a/src/physics/large_eddy_simulation.cpp +++ b/src/physics/large_eddy_simulation.cpp @@ -22,11 +22,13 @@ LargeEddySimulationBase::LargeEddySimulationBase( const double side_slip_angle, const double prandtl_number, const double reynolds_number_inf, + const double temperature_inf, const double turbulent_prandtl_number, const double ratio_of_filter_width_to_cell_size, const double isothermal_wall_temperature, const thermal_boundary_condition_enum thermal_boundary_condition_type, - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function) + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function, + const two_point_num_flux_enum two_point_num_flux_type) : ModelBase(manufactured_solution_function) , turbulent_prandtl_number(turbulent_prandtl_number) , ratio_of_filter_width_to_cell_size(ratio_of_filter_width_to_cell_size) @@ -38,9 +40,11 @@ LargeEddySimulationBase::LargeEddySimulationBase( side_slip_angle, prandtl_number, reynolds_number_inf, + temperature_inf, isothermal_wall_temperature, thermal_boundary_condition_type, - manufactured_solution_function)) + manufactured_solution_function, + two_point_num_flux_type)) { static_assert(nstate==dim+2, "ModelBase::LargeEddySimulationBase() should be created with nstate=dim+2"); } @@ -127,6 +131,7 @@ std::array LargeEddySimulationBase ::source_term ( const dealii::Point &pos, const std::array &/*solution*/, + const real /*current_time*/, const dealii::types::global_dof_index cell_index) const { /* TO DO Note: Since this is only used for the manufactured solution source term, @@ -378,12 +383,14 @@ LargeEddySimulation_Smagorinsky::LargeEddySimulation_Smagorin const double side_slip_angle, const double prandtl_number, const double reynolds_number_inf, + const double temperature_inf, const double turbulent_prandtl_number, const double ratio_of_filter_width_to_cell_size, const double model_constant, const double isothermal_wall_temperature, const thermal_boundary_condition_enum thermal_boundary_condition_type, - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function) + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function, + const two_point_num_flux_enum two_point_num_flux_type) : LargeEddySimulationBase(ref_length, gamma_gas, mach_inf, @@ -391,11 +398,13 @@ LargeEddySimulation_Smagorinsky::LargeEddySimulation_Smagorin side_slip_angle, prandtl_number, reynolds_number_inf, + temperature_inf, turbulent_prandtl_number, ratio_of_filter_width_to_cell_size, isothermal_wall_temperature, thermal_boundary_condition_type, - manufactured_solution_function) + manufactured_solution_function, + two_point_num_flux_type) , model_constant(model_constant) { } //---------------------------------------------------------------- @@ -596,12 +605,14 @@ LargeEddySimulation_WALE::LargeEddySimulation_WALE( const double side_slip_angle, const double prandtl_number, const double reynolds_number_inf, + const double temperature_inf, const double turbulent_prandtl_number, const double ratio_of_filter_width_to_cell_size, const double model_constant, const double isothermal_wall_temperature, const thermal_boundary_condition_enum thermal_boundary_condition_type, - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function) + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function, + const two_point_num_flux_enum two_point_num_flux_type) : LargeEddySimulation_Smagorinsky(ref_length, gamma_gas, mach_inf, @@ -609,12 +620,14 @@ LargeEddySimulation_WALE::LargeEddySimulation_WALE( side_slip_angle, prandtl_number, reynolds_number_inf, + temperature_inf, turbulent_prandtl_number, ratio_of_filter_width_to_cell_size, model_constant, isothermal_wall_temperature, thermal_boundary_condition_type, - manufactured_solution_function) + manufactured_solution_function, + two_point_num_flux_type) { } //---------------------------------------------------------------- template @@ -715,12 +728,14 @@ LargeEddySimulation_Vreman::LargeEddySimulation_Vreman( const double side_slip_angle, const double prandtl_number, const double reynolds_number_inf, + const double temperature_inf, const double turbulent_prandtl_number, const double ratio_of_filter_width_to_cell_size, const double model_constant, const double isothermal_wall_temperature, const thermal_boundary_condition_enum thermal_boundary_condition_type, - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function) + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function, + const two_point_num_flux_enum two_point_num_flux_type) : LargeEddySimulation_Smagorinsky(ref_length, gamma_gas, mach_inf, @@ -728,12 +743,14 @@ LargeEddySimulation_Vreman::LargeEddySimulation_Vreman( side_slip_angle, prandtl_number, reynolds_number_inf, + temperature_inf, turbulent_prandtl_number, ratio_of_filter_width_to_cell_size, model_constant, isothermal_wall_temperature, thermal_boundary_condition_type, - manufactured_solution_function) + manufactured_solution_function, + two_point_num_flux_type) { } //---------------------------------------------------------------- template @@ -860,4 +877,4 @@ template FadType LargeEddySimulationBase < PHILIP_DIM, PHILIP_DIM+2, RadFadTy } // Physics namespace -} // PHiLiP namespace \ No newline at end of file +} // PHiLiP namespace diff --git a/src/physics/large_eddy_simulation.h b/src/physics/large_eddy_simulation.h index 968a3da53..f0aface5c 100644 --- a/src/physics/large_eddy_simulation.h +++ b/src/physics/large_eddy_simulation.h @@ -14,6 +14,7 @@ class LargeEddySimulationBase : public ModelBase { public: using thermal_boundary_condition_enum = Parameters::NavierStokesParam::ThermalBoundaryCondition; + using two_point_num_flux_enum = Parameters::AllParameters::TwoPointNumericalFlux; /// Constructor LargeEddySimulationBase( const double ref_length, @@ -23,11 +24,13 @@ class LargeEddySimulationBase : public ModelBase const double side_slip_angle, const double prandtl_number, const double reynolds_number_inf, + const double temperature_inf, const double turbulent_prandtl_number, const double ratio_of_filter_width_to_cell_size, const double isothermal_wall_temperature = 1.0, const thermal_boundary_condition_enum thermal_boundary_condition_type = thermal_boundary_condition_enum::adiabatic, - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr); + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr, + const two_point_num_flux_enum two_point_num_flux_type = two_point_num_flux_enum::KG); /// Destructor ~LargeEddySimulationBase() {}; @@ -55,6 +58,7 @@ class LargeEddySimulationBase : public ModelBase std::array source_term ( const dealii::Point &pos, const std::array &solution, + const real current_time, const dealii::types::global_dof_index cell_index) const; /// Compute the nondimensionalized filter width used by the SGS model given a cell index @@ -137,6 +141,7 @@ class LargeEddySimulation_Smagorinsky : public LargeEddySimulationBase > manufactured_solution_function = nullptr); + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr, + const two_point_num_flux_enum two_point_num_flux_type = two_point_num_flux_enum::KG); /// SGS model constant const double model_constant; @@ -233,6 +240,7 @@ class LargeEddySimulation_WALE : public LargeEddySimulation_Smagorinsky > manufactured_solution_function = nullptr); + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr, + const two_point_num_flux_enum two_point_num_flux_type = two_point_num_flux_enum::KG); /// Destructor ~LargeEddySimulation_WALE() {}; @@ -287,6 +297,7 @@ class LargeEddySimulation_Vreman : public LargeEddySimulation_Smagorinsky > manufactured_solution_function = nullptr); + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr, + const two_point_num_flux_enum two_point_num_flux_type = two_point_num_flux_enum::KG); /// Destructor ~LargeEddySimulation_Vreman() {}; diff --git a/src/physics/manufactured_solution.cpp b/src/physics/manufactured_solution.cpp index 2c4e83c8a..9cb2b2e6e 100644 --- a/src/physics/manufactured_solution.cpp +++ b/src/physics/manufactured_solution.cpp @@ -178,7 +178,20 @@ ::value(const dealii::Point &point, const unsigned int /*istate*/) con } template -real ManufacturedSolutionNavahBase +inline real ManufacturedSolutionExample +::value (const dealii::Point &point, const unsigned int istate) const +{ + real value = 0.0; + for (int d=0; dbase_values[istate]; + return value; +} + +template +inline real ManufacturedSolutionNavahBase ::primitive_value(const dealii::Point &point, const unsigned int istate) const { real value = 0.; @@ -235,7 +248,6 @@ ::value(const dealii::Point &point, const unsigned int istate) const // - transport of the turbulent working variable: if(istate==4) value = density*turbulent_working_variable; } - return value; } @@ -501,7 +513,18 @@ ::gradient(const dealii::Point &point, const unsigned int /*istate*/) } template -dealii::Tensor<1,dim,real> ManufacturedSolutionNavahBase +inline dealii::Tensor<1,dim,real> ManufacturedSolutionExample +::gradient(const dealii::Point &point, const unsigned int /*istate*/) const +{ + dealii::Tensor<1,dim,real> gradient; + for(unsigned int d = 0; d < dim; ++d){ + gradient[d] = exp(point[d]) + cos(point[d]); + } + return gradient; +} + +template +inline dealii::Tensor<1,dim,real> ManufacturedSolutionNavahBase ::primitive_gradient (const dealii::Point &point, const unsigned int istate) const { dealii::Tensor<1,dim,real> gradient; @@ -947,7 +970,23 @@ ::hessian(const dealii::Point &/* point */, const unsigned int /* ista } template -dealii::SymmetricTensor<2,dim,real> ManufacturedSolutionNavahBase +inline dealii::SymmetricTensor<2,dim,real> ManufacturedSolutionExample +::hessian (const dealii::Point &point, const unsigned int /*istate*/) const +{ + dealii::SymmetricTensor<2,dim,real> hessian; + for(int idim=0; idim +inline dealii::SymmetricTensor<2,dim,real> ManufacturedSolutionNavahBase ::primitive_hessian (const dealii::Point &point, const unsigned int istate) const { dealii::SymmetricTensor<2,dim,real> hessian; @@ -1196,6 +1235,8 @@ ManufacturedSolutionFactory::create_ManufacturedSolution( return std::make_shared>(nstate); }else if(solution_type == ManufacturedSolutionEnum::quadratic_solution){ return std::make_shared>(nstate); + }else if(solution_type == ManufacturedSolutionEnum::example_solution){ + return std::make_shared>(nstate); }else if((solution_type == ManufacturedSolutionEnum::navah_solution_1) && (dim==2) && (nstate==dim+2 || nstate==dim+3)){ return std::make_shared>(nstate); }else if((solution_type == ManufacturedSolutionEnum::navah_solution_2) && (dim==2) && (nstate==dim+2 || nstate==dim+3)){ diff --git a/src/physics/manufactured_solution.h b/src/physics/manufactured_solution.h index cf099394a..34ba58dc5 100644 --- a/src/physics/manufactured_solution.h +++ b/src/physics/manufactured_solution.h @@ -503,6 +503,35 @@ class ManufacturedSolutionQuadratic std::array alpha_diag; ///< Diagonal hessian component scaling }; + +/** Sum of example manufactured solutions + * (i.e. those used in group lab presentation on implementing Manufactured Solutions). + * */ +template +class ManufacturedSolutionExample + : public ManufacturedSolutionFunction +{ +// We want the Point to be templated on the type, +// however, dealii does not template that part of the Function. +// Therefore, we end up overloading the functions and need to "import" +// those non-overloaded functions to avoid the warning -Woverloaded-virtual +// See: https://stackoverflow.com/questions/18515183/c-overloaded-virtual-function-warning-by-clang +protected: + using dealii::Function::value; + using dealii::Function::gradient; + using dealii::Function::hessian; +public: + ///Constructor + ManufacturedSolutionExample(const unsigned int nstate = 1) + : ManufacturedSolutionFunction(nstate){} + /// Value + real value (const dealii::Point &point, const unsigned int istate = 0) const override; + /// Gradient + dealii::Tensor<1,dim,real> gradient (const dealii::Point &point, const unsigned int istate = 0) const override; + /// Hessian + dealii::SymmetricTensor<2,dim,real> hessian (const dealii::Point &point, const unsigned int istate = 0) const override; +}; + /// Navah and Nadarajah free flows manufactured solution base /// Reference: Navah F. and Nadarajah S., A comprehensive high-order solver verification methodology for free fluid flows, 2018 template diff --git a/src/physics/mhd.cpp b/src/physics/mhd.cpp index f96091a1f..1b8d1203a 100644 --- a/src/physics/mhd.cpp +++ b/src/physics/mhd.cpp @@ -15,16 +15,18 @@ std::array MHD ::source_term ( const dealii::Point &pos, const std::array &conservative_soln, + const real current_time, const dealii::types::global_dof_index /*cell_index*/) const { - return source_term(pos,conservative_soln); + return source_term(pos,conservative_soln,current_time); } template std::array MHD ::source_term ( const dealii::Point &/*pos*/, - const std::array &/*conservative_soln*/) const + const std::array &/*conservative_soln*/, + const real /*current_time*/) const { std::array source_term; for (int s=0; s &soln_const, return conv_num_split_flux; } +template +real MHD +::convective_surface_numerical_split_flux ( + const real &/*surface_flux*/, + const real &flux_interp_to_surface) const +{ + return flux_interp_to_surface; +} + +template +std::array MHD +::compute_entropy_variables ( + const std::array &conservative_soln) const +{ + std::cout<<"Entropy variables for MHD hasn't been done yet."< +std::array MHD +::compute_conservative_variables_from_entropy_variables ( + const std::array &entropy_var) const +{ + std::cout<<"Entropy variables for MHD hasn't been done yet."< std::array MHD ::convective_normal_flux (const std::array &conservative_soln, const dealii::Tensor<1,dim,real> &normal) const @@ -464,6 +495,13 @@ ::max_convective_eigenvalue (const std::array &conservative_soln) c return max_eig; } +template +real MHD +::max_viscous_eigenvalue (const std::array &/*conservative_soln*/) const +{ + return 0.0; +} + template std::array,nstate> MHD ::dissipative_flux ( diff --git a/src/physics/mhd.h b/src/physics/mhd.h index 4040e98dd..744db93be 100644 --- a/src/physics/mhd.h +++ b/src/physics/mhd.h @@ -91,8 +91,9 @@ class MHD : public PhysicsBase MHD( const double gamma_gas, const dealii::Tensor<2,3,double> input_diffusion_tensor = Parameters::ManufacturedSolutionParam::get_default_diffusion_tensor(), - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr) - : PhysicsBase(input_diffusion_tensor, manufactured_solution_function) + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr, + const bool has_nonzero_diffusion = false) + : PhysicsBase(has_nonzero_diffusion, input_diffusion_tensor, manufactured_solution_function) , gam(gamma_gas) , gamm1(gam-1.0) { @@ -132,6 +133,9 @@ class MHD : public PhysicsBase /// Maximum convective eigenvalue used in Lax-Friedrichs real max_convective_eigenvalue (const std::array &soln) const; + /// Maximum viscous eigenvalue. + real max_viscous_eigenvalue (const std::array &soln) const; + /// Dissipative flux: 0 std::array,nstate> dissipative_flux ( const std::array &conservative_soln, @@ -147,12 +151,14 @@ class MHD : public PhysicsBase std::array source_term ( const dealii::Point &pos, const std::array &conservative_soln, + const real current_time, const dealii::types::global_dof_index cell_index) const; /// (function overload) Source term is zero or depends on manufactured solution std::array source_term ( const dealii::Point &pos, - const std::array &conservative_soln) const; + const std::array &conservative_soln, + const real current_time) const; /// Given conservative variables [density, [momentum], total energy], /// returns primitive variables [density, [velocities], pressure]. @@ -225,6 +231,19 @@ class MHD : public PhysicsBase const std::array &conservative_soln1, const std::array &conservative_soln2) const; + /// Convective surface split flux + real convective_surface_numerical_split_flux ( + const real &surface_flux, + const real &flux_interp_to_surface) const; + + /// Computes the entropy variables. + std::array compute_entropy_variables ( + const std::array &conservative_soln) const; + + /// Computes the conservative variables from the entropy variables. + std::array compute_conservative_variables_from_entropy_variables ( + const std::array &entropy_var) const; + /// Mean density given two sets of conservative solutions. /** Used in the implementation of the split form. */ diff --git a/src/physics/model.h b/src/physics/model.h index 2d098bb18..afe18c34e 100644 --- a/src/physics/model.h +++ b/src/physics/model.h @@ -42,6 +42,7 @@ class ModelBase virtual std::array source_term ( const dealii::Point &pos, const std::array &solution, + const real current_time, const dealii::types::global_dof_index cell_index) const = 0; // Quantities needed to be updated by DG for the model -- accomplished by DGBase update_model_variables() diff --git a/src/physics/model_factory.cpp b/src/physics/model_factory.cpp index eecdd793e..59b958b27 100644 --- a/src/physics/model_factory.cpp +++ b/src/physics/model_factory.cpp @@ -51,12 +51,14 @@ ::create_Model(const Parameters::AllParameters *const parameters_input) parameters_input->euler_param.side_slip_angle, parameters_input->navier_stokes_param.prandtl_number, parameters_input->navier_stokes_param.reynolds_number_inf, + parameters_input->navier_stokes_param.temperature_inf, parameters_input->physics_model_param.turbulent_prandtl_number, parameters_input->physics_model_param.ratio_of_filter_width_to_cell_size, parameters_input->physics_model_param.smagorinsky_model_constant, parameters_input->navier_stokes_param.nondimensionalized_isothermal_wall_temperature, parameters_input->navier_stokes_param.thermal_boundary_condition_type, - manufactured_solution_function); + manufactured_solution_function, + parameters_input->two_point_num_flux_type); } else if (sgs_model_type == SGS_enum::wall_adaptive_local_eddy_viscosity) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // WALE (Wall-Adapting Local Eddy-viscosity) eddy viscosity model @@ -69,12 +71,14 @@ ::create_Model(const Parameters::AllParameters *const parameters_input) parameters_input->euler_param.side_slip_angle, parameters_input->navier_stokes_param.prandtl_number, parameters_input->navier_stokes_param.reynolds_number_inf, + parameters_input->navier_stokes_param.temperature_inf, parameters_input->physics_model_param.turbulent_prandtl_number, parameters_input->physics_model_param.ratio_of_filter_width_to_cell_size, parameters_input->physics_model_param.WALE_model_constant, parameters_input->navier_stokes_param.nondimensionalized_isothermal_wall_temperature, parameters_input->navier_stokes_param.thermal_boundary_condition_type, - manufactured_solution_function); + manufactured_solution_function, + parameters_input->two_point_num_flux_type); } else if (sgs_model_type == SGS_enum::vreman) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Vreman eddy viscosity model @@ -87,12 +91,14 @@ ::create_Model(const Parameters::AllParameters *const parameters_input) parameters_input->euler_param.side_slip_angle, parameters_input->navier_stokes_param.prandtl_number, parameters_input->navier_stokes_param.reynolds_number_inf, + parameters_input->navier_stokes_param.temperature_inf, parameters_input->physics_model_param.turbulent_prandtl_number, parameters_input->physics_model_param.ratio_of_filter_width_to_cell_size, parameters_input->physics_model_param.vreman_model_constant, parameters_input->navier_stokes_param.nondimensionalized_isothermal_wall_temperature, parameters_input->navier_stokes_param.thermal_boundary_condition_type, - manufactured_solution_function); + manufactured_solution_function, + parameters_input->two_point_num_flux_type); } else { std::cout << "Can't create LargeEddySimulationBase, invalid SGSModelType type: " << sgs_model_type << std::endl; diff --git a/src/physics/navier_stokes.cpp b/src/physics/navier_stokes.cpp index acbee1359..e0d46b026 100644 --- a/src/physics/navier_stokes.cpp +++ b/src/physics/navier_stokes.cpp @@ -20,20 +20,27 @@ NavierStokes::NavierStokes( const double side_slip_angle, const double prandtl_number, const double reynolds_number_inf, + const double temperature_inf, const double isothermal_wall_temperature, const thermal_boundary_condition_enum thermal_boundary_condition_type, - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function) + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function, + const two_point_num_flux_enum two_point_num_flux_type) : Euler(ref_length, gamma_gas, mach_inf, angle_of_attack, side_slip_angle, - manufactured_solution_function) + manufactured_solution_function, + two_point_num_flux_type, + true) //has_nonzero_diffusion = true , viscosity_coefficient_inf(1.0) // Nondimensional - Free stream values , prandtl_number(prandtl_number) , reynolds_number_inf(reynolds_number_inf) , isothermal_wall_temperature(isothermal_wall_temperature) // Nondimensional - Free stream values , thermal_boundary_condition_type(thermal_boundary_condition_type) + , sutherlands_temperature(110.4) // Sutherland's temperature. Units: [K] + , freestream_temperature(temperature_inf) // Freestream temperature. Units: [K] + , temperature_ratio(sutherlands_temperature/freestream_temperature) { static_assert(nstate==dim+2, "Physics::NavierStokes() should be created with nstate=dim+2"); // Nothing to do here so far @@ -54,7 +61,6 @@ ::convert_conservative_gradient_to_primitive_gradient ( // extract from primitive solution const real2 density = primitive_soln[0]; const dealii::Tensor<1,dim,real2> vel = this->template extract_velocities_from_primitive(primitive_soln); // from Euler - const real2 vel2 = this->template compute_velocity_squared(vel); // from Euler // density gradient for (int d=0; dtemplate compute_velocity_squared(vel); // from Euler + // for (int d1=0; d1gamm1; + // } + // -- formulation 2 (equivalent to formulation 1): for (int d1=0; d1gamm1; } @@ -641,7 +658,8 @@ template std::array NavierStokes ::source_term ( const dealii::Point &pos, - const std::array &/*conservative_soln*/) const + const std::array &/*conservative_soln*/, + const real /*current_time*/) const { // will probably have to change this line: -- modify so we only need to provide a jacobian const std::array conv_source_term = this->convective_source_term(pos); diff --git a/src/physics/navier_stokes.h b/src/physics/navier_stokes.h index 4e77a28f9..d498d74f0 100644 --- a/src/physics/navier_stokes.h +++ b/src/physics/navier_stokes.h @@ -23,6 +23,7 @@ class NavierStokes : public Euler using PhysicsBase::source_term; public: using thermal_boundary_condition_enum = Parameters::NavierStokesParam::ThermalBoundaryCondition; + using two_point_num_flux_enum = Parameters::AllParameters::TwoPointNumericalFlux; /// Constructor NavierStokes( const double ref_length, @@ -32,9 +33,11 @@ class NavierStokes : public Euler const double side_slip_angle, const double prandtl_number, const double reynolds_number_inf, + const double temperature_inf = 273.15, const double isothermal_wall_temperature = 1.0, const thermal_boundary_condition_enum thermal_boundary_condition_type = thermal_boundary_condition_enum::adiabatic, - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr); + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function = nullptr, + const two_point_num_flux_enum two_point_num_flux_type = two_point_num_flux_enum::KG); /// Nondimensionalized viscosity coefficient at infinity. const double viscosity_coefficient_inf; @@ -47,6 +50,18 @@ class NavierStokes : public Euler /// Thermal boundary condition type (adiabatic or isothermal) const thermal_boundary_condition_enum thermal_boundary_condition_type; +protected: + ///@{ + /** Constants for Sutherland's law for viscosity + * Reference: Sutherland, W. (1893), "The viscosity of gases and molecular force", Philosophical Magazine, S. 5, 36, pp. 507-531 (1893) + * Values: https://www.cfd-online.com/Wiki/Sutherland%27s_law + */ + const double sutherlands_temperature; ///< Sutherland's temperature. Units: [K] + const double freestream_temperature; ///< Freestream temperature. Units: [K] + const double temperature_ratio; ///< Ratio of Sutherland's temperature to freestream temperature + //@} + +public: /// Destructor ~NavierStokes() {}; @@ -239,7 +254,8 @@ class NavierStokes : public Euler /// Source term is zero or depends on manufactured solution std::array source_term ( const dealii::Point &pos, - const std::array &conservative_soln) const override; + const std::array &conservative_soln, + const real current_time) const override; /// Convective flux Jacobian computed via dfad (automatic differentiation) /// -- Only used for verifying the dfad procedure used in dissipative flux jacobian @@ -263,16 +279,7 @@ class NavierStokes : public Euler const dealii::Tensor<2,dim,real2> &viscous_stress_tensor, const dealii::Tensor<1,dim,real2> &heat_flux) const; -protected: - ///@{ - /** Constants for Sutherland's law for viscosity - * Reference: Sutherland, W. (1893), "The viscosity of gases and molecular force", Philosophical Magazine, S. 5, 36, pp. 507-531 (1893) - * Values: https://www.cfd-online.com/Wiki/Sutherland%27s_law - */ - const double free_stream_temperature = 273.15; ///< Free stream temperature. Units: [K] - const double sutherlands_temperature = 110.4; ///< Sutherland's temperature. Units: [K] - const double temperature_ratio = sutherlands_temperature/free_stream_temperature; - //@} +protected: /** Nondimensionalized viscous flux (i.e. dissipative flux) * Reference: Masatsuka 2018 "I do like CFD", p.142, eq.(4.12.1-4.12.4) diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index a27a13bbb..93f9a7ba6 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -11,9 +11,11 @@ namespace Physics { template PhysicsBase::PhysicsBase( + const bool has_nonzero_diffusion_input, const dealii::Tensor<2,3,double> input_diffusion_tensor, - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function_input): - manufactured_solution_function(manufactured_solution_function_input) + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function_input) + : has_nonzero_diffusion(has_nonzero_diffusion_input) + , manufactured_solution_function(manufactured_solution_function_input) { // if provided with a null ptr, give it the default manufactured solution // currently only necessary for the unit test @@ -38,12 +40,14 @@ PhysicsBase::PhysicsBase( template PhysicsBase::PhysicsBase( + const bool has_nonzero_diffusion_input, std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function_input) - : PhysicsBase(Parameters::ManufacturedSolutionParam::get_default_diffusion_tensor(),manufactured_solution_function_input) + : PhysicsBase( + has_nonzero_diffusion_input, + Parameters::ManufacturedSolutionParam::get_default_diffusion_tensor(), + manufactured_solution_function_input) { } -template -PhysicsBase::~PhysicsBase() {} /* template std::array,nstate> PhysicsBase diff --git a/src/physics/physics.h b/src/physics/physics.h index ac116723a..f3d7e93c9 100644 --- a/src/physics/physics.h +++ b/src/physics/physics.h @@ -35,14 +35,20 @@ class PhysicsBase public: /// Default constructor that will set the constants. PhysicsBase( + const bool has_nonzero_diffusion_input, const dealii::Tensor<2,3,double> input_diffusion_tensor = Parameters::ManufacturedSolutionParam::get_default_diffusion_tensor(), std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function_input = nullptr); /// Constructor that will call default constructor. - PhysicsBase(std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function_input = nullptr); + PhysicsBase( + const bool has_nonzero_diffusion_input, + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function_input = nullptr); /// Virtual destructor required for abstract classes. - virtual ~PhysicsBase() = 0; + virtual ~PhysicsBase() {}; + + /// Flag to signal that diffusion term is non-zero + const bool has_nonzero_diffusion; /// Manufactured solution function std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function; @@ -53,7 +59,21 @@ class PhysicsBase /// Convective Numerical Split Flux for split form virtual std::array,nstate> convective_numerical_split_flux ( - const std::array &soln_const, const std::array &soln_loop) const = 0; + const std::array &conservative_soln1, + const std::array &conservative_soln2) const = 0; + + /// Convective Numerical Split Flux for split form + virtual real convective_surface_numerical_split_flux ( + const real &surface_flux, + const real &flux_interp_to_surface) const = 0; + + /// Computes the entropy variables. + virtual std::array compute_entropy_variables ( + const std::array &conservative_soln) const = 0; + + /// Computes the conservative variables from the entropy variables. + virtual std::array compute_conservative_variables_from_entropy_variables ( + const std::array &entropy_var) const = 0; /// Spectral radius of convective term Jacobian. /** Used for scalar dissipation @@ -65,6 +85,9 @@ class PhysicsBase /// Maximum convective eigenvalue used in Lax-Friedrichs virtual real max_convective_eigenvalue (const std::array &soln) const = 0; + /// Maximum viscous eigenvalue. + virtual real max_viscous_eigenvalue (const std::array &soln) const = 0; + // /// Evaluate the diffusion matrix \f$ A \f$ such that \f$F_v = A \nabla u\f$. // virtual std::array,nstate> apply_diffusion_matrix ( // const std::array &solution, @@ -87,6 +110,7 @@ class PhysicsBase virtual std::array source_term ( const dealii::Point &pos, const std::array &solution, + const real current_time, const dealii::types::global_dof_index cell_index) const = 0; /// Artificial source term that does not require differentiation stemming from artificial dissipation. diff --git a/src/physics/physics_factory.cpp b/src/physics/physics_factory.cpp index bdb465030..1b70255ef 100644 --- a/src/physics/physics_factory.cpp +++ b/src/physics/physics_factory.cpp @@ -60,20 +60,23 @@ ::create_Physics(const Parameters::AllParameters *c return std::make_shared < ConvectionDiffusion >( false, true, diffusion_tensor, advection_vector, diffusion_coefficient, - manufactured_solution_function); + manufactured_solution_function, + parameters_input->test_type); } else if (pde_type == PDE_enum::convection_diffusion) { if constexpr (nstate==1) return std::make_shared < ConvectionDiffusion >( true, true, diffusion_tensor, advection_vector, diffusion_coefficient, - manufactured_solution_function); + manufactured_solution_function, + parameters_input->test_type); } else if (pde_type == PDE_enum::burgers_inviscid) { if constexpr (nstate==dim) return std::make_shared < Burgers >( parameters_input->burgers_param.diffusion_coefficient, true, false, diffusion_tensor, - manufactured_solution_function); + manufactured_solution_function, + parameters_input->test_type); } else if (pde_type == PDE_enum::burgers_viscous) { if constexpr (nstate==dim) return std::make_shared < Burgers >( @@ -99,7 +102,8 @@ ::create_Physics(const Parameters::AllParameters *c parameters_input->euler_param.mach_inf, parameters_input->euler_param.angle_of_attack, parameters_input->euler_param.side_slip_angle, - manufactured_solution_function); + manufactured_solution_function, + parameters_input->two_point_num_flux_type); } } else if (pde_type == PDE_enum::mhd) { if constexpr (nstate == 8) @@ -117,9 +121,11 @@ ::create_Physics(const Parameters::AllParameters *c parameters_input->euler_param.side_slip_angle, parameters_input->navier_stokes_param.prandtl_number, parameters_input->navier_stokes_param.reynolds_number_inf, + parameters_input->navier_stokes_param.temperature_inf, parameters_input->navier_stokes_param.nondimensionalized_isothermal_wall_temperature, parameters_input->navier_stokes_param.thermal_boundary_condition_type, - manufactured_solution_function); + manufactured_solution_function, + parameters_input->two_point_num_flux_type); } } else if (pde_type == PDE_enum::physics_model) { if constexpr (nstate>=dim+2) { @@ -157,10 +163,14 @@ ::create_Physics_Model(const Parameters::AllParameters // Create baseline physics object PDE_enum baseline_physics_type; + // Flag to signal non-zero diffusion + bool has_nonzero_diffusion; + // ------------------------------------------------------------------------------- // Large Eddy Simulation (LES) // ------------------------------------------------------------------------------- if (model_type == Model_enum::large_eddy_simulation) { + has_nonzero_diffusion = true; // because of SGS model term if constexpr ((nstate==dim+2) && (dim==3)) { // Assign baseline physics type (and corresponding nstates) based on the physics model type // -- Assign nstates for the baseline physics (constexpr because template parameter) @@ -178,16 +188,19 @@ ::create_Physics_Model(const Parameters::AllParameters parameters_input, baseline_physics_type, model_input, - manufactured_solution_function); + manufactured_solution_function, + has_nonzero_diffusion); } else { // LES does not exist for nstate!=(dim+2) || dim!=3 (void) baseline_physics_type; + (void) has_nonzero_diffusion; return nullptr; } } else { // prevent warnings for dim=3,nstate=4, etc. (void) baseline_physics_type; + (void) has_nonzero_diffusion; } std::cout << "Can't create PhysicsModel, invalid ModelType type: " << model_type << std::endl; assert(0==1 && "Can't create PhysicsModel, invalid ModelType type"); diff --git a/src/physics/physics_model.cpp b/src/physics/physics_model.cpp index a0521a182..e500c8074 100644 --- a/src/physics/physics_model.cpp +++ b/src/physics/physics_model.cpp @@ -20,8 +20,9 @@ PhysicsModel::PhysicsModel( const Parameters::AllParameters *const parameters_input, Parameters::AllParameters::PartialDifferentialEquation baseline_physics_type, std::shared_ptr< ModelBase > model_input, - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function) - : PhysicsBase(manufactured_solution_function) + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function, + const bool has_nonzero_diffusion) + : PhysicsBase(has_nonzero_diffusion, manufactured_solution_function) , n_model_equations(nstate-nstate_baseline_physics) , physics_baseline(PhysicsFactory::create_Physics(parameters_input, baseline_physics_type)) , model(model_input) @@ -97,10 +98,15 @@ std::array PhysicsModel ::source_term ( const dealii::Point &pos, const std::array &conservative_soln, + const real current_time, const dealii::types::global_dof_index cell_index) const { // Initialize source_term as the model source term - std::array source_term = model->source_term(pos,conservative_soln,cell_index); + std::array source_term = model->source_term( + pos, + conservative_soln, + current_time, + cell_index); // Get baseline conservative solution with nstate_baseline_physics std::array baseline_conservative_soln; @@ -111,7 +117,11 @@ ::source_term ( // Get the baseline physics source term /* Note: Even though the physics baseline source term does not depend on cell_index, we pass it anyways to accomodate the pure virtual member function defined in the PhysicsBase class */ - std::array baseline_source_term = physics_baseline->source_term(pos,baseline_conservative_soln,cell_index); + std::array baseline_source_term = physics_baseline->source_term( + pos, + baseline_conservative_soln, + current_time, + cell_index); // Add the baseline_source_term terms to source_term for(int s=0; s &conservative_so return conv_num_split_flux; } +template +real PhysicsModel +::convective_surface_numerical_split_flux ( + const real &surface_flux, + const real &flux_interp_to_surface) const +{ + // TO DO: Update for when nstate > nstate_baseline_physics + real conv_surf_num_split_flux; + if(nstate==nstate_baseline_physics) { + conv_surf_num_split_flux = physics_baseline->convective_surface_numerical_split_flux(surface_flux,flux_interp_to_surface); + } else { + // TO DO, make use of the physics_model object for nstate>nstate_baseline_physics + std::abort(); + } + return conv_surf_num_split_flux; +} + +template +std::array PhysicsModel +::compute_entropy_variables ( + const std::array &conservative_soln) const +{ + std::array entropy_var; + if(nstate==nstate_baseline_physics) { + entropy_var = physics_baseline->compute_entropy_variables(conservative_soln); + } else { + // TO DO, make use of the physics_model object for nstate>nstate_baseline_physics + std::abort(); + } + return entropy_var; +} + +template +std::array PhysicsModel +::compute_conservative_variables_from_entropy_variables ( + const std::array &entropy_var) const +{ + std::array conservative_soln; + if(nstate==nstate_baseline_physics) { + conservative_soln = physics_baseline->compute_conservative_variables_from_entropy_variables(entropy_var); + } else { + // TO DO, make use of the physics_model object for nstate>nstate_baseline_physics + std::abort(); + } + return conservative_soln; +} + template std::array PhysicsModel ::convective_eigenvalues ( @@ -169,6 +226,13 @@ ::max_convective_eigenvalue (const std::array &conservative_soln) c return max_eig; } +template +real PhysicsModel +::max_viscous_eigenvalue (const std::array &/*conservative_soln*/) const +{ + return 0.0; +} + template void PhysicsModel ::boundary_face_values ( @@ -261,4 +325,4 @@ template class PhysicsModel < PHILIP_DIM, PHILIP_DIM+2, FadFadType, PHILIP_DIM+2 template class PhysicsModel < PHILIP_DIM, PHILIP_DIM+2, RadFadType, PHILIP_DIM+2 >; } // Physics namespace -} // PHiLiP namespace \ No newline at end of file +} // PHiLiP namespace diff --git a/src/physics/physics_model.h b/src/physics/physics_model.h index 78a3b5cb8..8717c56f3 100644 --- a/src/physics/physics_model.h +++ b/src/physics/physics_model.h @@ -19,7 +19,8 @@ class PhysicsModel : public PhysicsBase const Parameters::AllParameters *const parameters_input, Parameters::AllParameters::PartialDifferentialEquation baseline_physics_type, std::shared_ptr< ModelBase > model_input, - std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function); + std::shared_ptr< ManufacturedSolutionFunction > manufactured_solution_function, + const bool has_nonzero_diffusion); /// Destructor ~PhysicsModel() {}; @@ -47,6 +48,7 @@ class PhysicsModel : public PhysicsBase std::array source_term ( const dealii::Point &pos, const std::array &conservative_soln, + const real current_time, const dealii::types::global_dof_index cell_index) const; //=========================================================================================== @@ -54,7 +56,21 @@ class PhysicsModel : public PhysicsBase //=========================================================================================== /// Convective Numerical Split Flux for split form std::array,nstate> convective_numerical_split_flux ( - const std::array &soln_const, const std::array &soln_loop) const; + const std::array &conservative_soln1, + const std::array &conservative_soln2) const; + + /// Convective surface split flux + real convective_surface_numerical_split_flux ( + const real &surface_flux, + const real &flux_interp_to_surface) const; + + /// Computes the entropy variables. + std::array compute_entropy_variables ( + const std::array &conservative_soln) const; + + /// Computes the conservative variables from the entropy variables. + std::array compute_conservative_variables_from_entropy_variables ( + const std::array &entropy_var) const; /** Spectral radius of convective term Jacobian. * Used for scalar dissipation @@ -66,6 +82,9 @@ class PhysicsModel : public PhysicsBase /// Maximum convective eigenvalue used in Lax-Friedrichs real max_convective_eigenvalue (const std::array &soln) const; + /// Maximum viscous eigenvalue. + real max_viscous_eigenvalue (const std::array &soln) const; + /// Evaluates boundary values and gradients on the other side of the face. void boundary_face_values ( const int /*boundary_type*/, diff --git a/src/reduced_order/CMakeLists.txt b/src/reduced_order/CMakeLists.txt index f72aee3b8..95c707d12 100644 --- a/src/reduced_order/CMakeLists.txt +++ b/src/reduced_order/CMakeLists.txt @@ -27,4 +27,4 @@ foreach(dim RANGE 1 3) # Setup target with deal.II unset(PODLib) -endforeach() \ No newline at end of file +endforeach() diff --git a/src/testing/CMakeLists.txt b/src/testing/CMakeLists.txt index 08a549503..78e988a5d 100644 --- a/src/testing/CMakeLists.txt +++ b/src/testing/CMakeLists.txt @@ -17,6 +17,7 @@ set(TESTS_SOURCE euler_vortex.cpp euler_entropy_waves.cpp advection_explicit_periodic.cpp + convection_diffusion_explicit_periodic.cpp euler_split_inviscid_taylor_green_vortex.cpp optimization_inverse_manufactured/optimization_inverse_manufactured.cpp dual_weighted_residual_mesh_adaptation.cpp @@ -27,7 +28,8 @@ set(TESTS_SOURCE reduced_order.cpp time_refinement_study.cpp time_refinement_study_reference.cpp - burgers_energy_conservation_rrk.cpp) + burgers_energy_conservation_rrk.cpp + euler_ismail_roe_entropy_check.cpp) foreach(dim RANGE 1 3) # Output library diff --git a/src/testing/advection_explicit_periodic.cpp b/src/testing/advection_explicit_periodic.cpp index af70f81d9..f178e8fec 100644 --- a/src/testing/advection_explicit_periodic.cpp +++ b/src/testing/advection_explicit_periodic.cpp @@ -10,180 +10,363 @@ #include #include #include +#include #include "parameters/all_parameters.h" #include "parameters/parameters.h" #include "physics/physics_factory.h" #include "physics/physics.h" +#include "dg/dg.h" #include "dg/dg_factory.hpp" #include "ode_solver/ode_solver_factory.h" #include "advection_explicit_periodic.h" +#include "physics/initial_conditions/set_initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" + +#include "mesh/grids/nonsymmetric_curved_periodic_grid.hpp" #include +#include +#include +#include + namespace PHiLiP { namespace Tests { template AdvectionPeriodic::AdvectionPeriodic(const PHiLiP::Parameters::AllParameters *const parameters_input) -: -TestsBase::TestsBase(parameters_input) + : TestsBase::TestsBase(parameters_input) {} +template +double AdvectionPeriodic::compute_energy(std::shared_ptr < PHiLiP::DGBase > &dg) const +{ + double energy = 0.0; + dealii::LinearAlgebra::distributed::Vector mass_matrix_times_solution(dg->right_hand_side); + if(dg->all_parameters->use_inverse_mass_on_the_fly) + dg->apply_global_mass_matrix(dg->solution,mass_matrix_times_solution); + else + dg->global_mass_matrix.vmult( mass_matrix_times_solution, dg->solution); + //Since we normalize the energy later, don't bother scaling by 0.5 + //Energy \f$ = 0.5 * \int u^2 d\Omega_m \f$ + energy = dg->solution * mass_matrix_times_solution; + + return energy; +} + +template +double AdvectionPeriodic::compute_conservation(std::shared_ptr < PHiLiP::DGBase > &dg, const double poly_degree) const +{ + //Conservation \f$ = \int 1 * u d\Omega_m \f$ + double conservation = 0.0; + dealii::LinearAlgebra::distributed::Vector mass_matrix_times_solution(dg->right_hand_side); + if(dg->all_parameters->use_inverse_mass_on_the_fly) + dg->apply_global_mass_matrix(dg->solution,mass_matrix_times_solution); + else + dg->global_mass_matrix.vmult( mass_matrix_times_solution, dg->solution); + + const unsigned int n_dofs_cell = dg->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size(); + std::vector ones(n_quad_pts, 1.0); + // std::vector ones(n_quad_pts); + // for(unsigned int iquad=0; iquad ones_hat(n_dofs_cell); + // We have to project the vector of ones because the mass matrix has an interpolation from solution nodes built into it. + OPERATOR::vol_projection_operator vol_projection(dg->nstate, poly_degree, dg->max_grid_degree); + vol_projection.build_1D_volume_operator(dg->oneD_fe_collection[poly_degree], dg->oneD_quadrature_collection[poly_degree]); + vol_projection.matrix_vector_mult_1D(ones, ones_hat, + vol_projection.oneD_vol_operator); + + dealii::LinearAlgebra::distributed::Vector ones_hat_global(dg->right_hand_side); + std::vector dofs_indices (n_dofs_cell); + for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) { + if (!cell->is_locally_owned()) continue; + cell->get_dof_indices (dofs_indices); + for(unsigned int idof=0;idof int AdvectionPeriodic::run_test() const { -#if PHILIP_DIM==1 - using Triangulation = dealii::Triangulation; + + printf("starting test\n"); + PHiLiP::Parameters::AllParameters all_parameters_new = *all_parameters; + + const unsigned int n_grids = (all_parameters_new.use_energy) ? 4 : 5; + std::vector grid_size(n_grids); + std::vector soln_error(n_grids); + std::vector soln_error_inf(n_grids); + using ADtype = double; + using ADArray = std::array; + using ADArrayTensor1 = std::array< dealii::Tensor<1,dim,ADtype>, nstate >; + + const double left = -1.0; + const double right = 1.0; + unsigned int n_refinements = n_grids; + unsigned int poly_degree = 3; + unsigned int grid_degree = poly_degree; + + dealii::ConvergenceTable convergence_table; + const unsigned int igrid_start = 3; + + for(unsigned int igrid=igrid_start; igrid does not work for 1D + using Triangulation = dealii::Triangulation; + std::shared_ptr grid = std::make_shared( + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); #else - using Triangulation = dealii::parallel::distributed::Triangulation; + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); #endif - std::shared_ptr grid = std::make_shared( -#if PHILIP_DIM!=1 - MPI_COMM_WORLD, -#endif - typename dealii::Triangulation::MeshSmoothing( - dealii::Triangulation::smoothing_on_refinement | - dealii::Triangulation::smoothing_on_coarsening)); - - double left = 0.0; - double right = 2.0; - const bool colorize = true; - int n_refinements = 5; - unsigned int poly_degree = 2; - dealii::GridGenerator::hyper_cube(*grid, left, right, colorize); - - std::vector > matched_pairs; - dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); - dealii::GridTools::collect_periodic_faces(*grid,2,3,1,matched_pairs); - //dealii::GridTools::collect_periodic_faces(*grid,4,5,2,matched_pairs); - grid->add_periodicity(matched_pairs); - - grid->refine_global(n_refinements); - - std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(all_parameters, poly_degree, grid); - dg->allocate_system (); - -// for (auto current_cell = dg->dof_handler.begin_active(); current_cell != dg->dof_handler.end(); ++current_cell) { -// if (!current_cell->is_locally_owned()) continue; -// -// dg->fe_values_volume.reinit(current_cell); -// int cell_index = current_cell->index(); -// std::cout << "cell number " << cell_index << std::endl; -// for (unsigned int face_no = 0; face_no < dealii::GeometryInfo::faces_per_cell; ++face_no) -// { -// if (current_cell->face(face_no)->at_boundary()) -// { -// std::cout << "face " << face_no << " is at boundary" << std::endl; -// typename dealii::DoFHandler::active_cell_iterator neighbor = current_cell->neighbor_or_periodic_neighbor(face_no); -// std::cout << "the neighbor is " << neighbor->index() << std::endl; -// } -// } -// -// } - - std::cout << "Implement initial conditions" << std::endl; - dealii::FunctionParser<2> initial_condition; - std::string variables = "x,y"; - std::map constants; - constants["pi"] = dealii::numbers::PI; - std::string expression = "exp( -( 20*(x-1)*(x-1) + 20*(y-1)*(y-1) ) )";//"sin(pi*x)*sin(pi*y)"; - initial_condition.initialize(variables, - expression, - constants); - dealii::VectorTools::interpolate(dg->dof_handler,initial_condition,dg->solution); - // Create ODE solver using the factory and providing the DG object - std::shared_ptr> ode_solver = PHiLiP::ODE::ODESolverFactory::create_ODESolver(dg); - - double finalTime = 1.5; - - //double dt = all_parameters->ode_solver_param.initial_time_step; - ode_solver->advance_solution_time(finalTime); - - return 0; //need to change -} + //set the warped grid + PHiLiP::Grids::nonsymmetric_curved_grid(*grid, igrid); -//int main (int argc, char * argv[]) -//{ -// //parse parameters first -// feenableexcept(FE_INVALID | FE_OVERFLOW); // catch nan -// dealii::deallog.depth_console(99); -// dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); -// const int n_mpi = dealii::Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD); -// const int mpi_rank = dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); -// dealii::ConditionalOStream pcout(std::cout, mpi_rank==0); -// pcout << "Starting program with " << n_mpi << " processors..." << std::endl; -// if ((PHILIP_DIM==1) && !(n_mpi==1)) { -// std::cout << "********************************************************" << std::endl; -// std::cout << "Can't use mpirun -np X, where X>1, for 1D." << std::endl -// << "Currently using " << n_mpi << " processors." << std::endl -// << "Aborting..." << std::endl; -// std::cout << "********************************************************" << std::endl; -// std::abort(); -// } -// int test_error = 1; -// try -// { -// // Declare possible inputs -// dealii::ParameterHandler parameter_handler; -// PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); -// PHiLiP::Parameters::parse_command_line (argc, argv, parameter_handler); -// -// // Read inputs from parameter file and set those values in AllParameters object -// PHiLiP::Parameters::AllParameters all_parameters; -// std::cout << "Reading input..." << std::endl; -// all_parameters.parse_parameters (parameter_handler); -// -// AssertDimension(all_parameters.dimension, PHILIP_DIM); -// -// std::cout << "Starting program..." << std::endl; -// -// using namespace PHiLiP; -// //const Parameters::AllParameters parameters_input; -// AdvectionPeriodic advection_test(&all_parameters); -// int i = advection_test.run_test(); -// return i; -// } -// catch (std::exception &exc) -// { -// std::cerr << std::endl << std::endl -// << "----------------------------------------------------" -// << std::endl -// << "Exception on processing: " << std::endl -// << exc.what() << std::endl -// << "Aborting!" << std::endl -// << "----------------------------------------------------" -// << std::endl; -// return 1; -// } -// -// catch (...) -// { -// std::cerr << std::endl -// << std::endl -// << "----------------------------------------------------" -// << std::endl -// << "Unknown exception!" << std::endl -// << "Aborting!" << std::endl -// << "----------------------------------------------------" -// << std::endl; -// return 1; -// } -// std::cout << "End of program." << std::endl; -// return test_error; -//} - -#if PHILIP_DIM==2 - template class AdvectionPeriodic ; -#endif + //CFL number + const unsigned int n_global_active_cells2 = grid->n_global_active_cells(); + double n_dofs_cfl = pow(n_global_active_cells2,dim) * pow(poly_degree+1.0, dim); + double delta_x = (right-left)/pow(n_dofs_cfl,(1.0/dim)); + all_parameters_new.ode_solver_param.initial_time_step = delta_x /(1.0*(2.0*poly_degree+1)) ; + all_parameters_new.ode_solver_param.initial_time_step = (all_parameters_new.use_energy) ? 0.05*delta_x : 0.5*delta_x; + std::cout << "dt " < > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); + std::cout << "Implement initial conditions" << std::endl; + // Create initial condition function + std::shared_ptr< InitialConditionFunction > initial_condition_function = + InitialConditionFactory::create_InitialConditionFunction(&all_parameters_new); + SetInitialCondition::set_initial_condition(initial_condition_function, dg, &all_parameters_new); + // Create ODE solver using the factory and providing the DG object + std::shared_ptr> ode_solver = PHiLiP::ODE::ODESolverFactory::create_ODESolver(dg); + double finalTime = 2.0; + if constexpr(dim==3) finalTime = 0.1;//to speed things up locally + + // need to call ode_solver before calculating energy because mass matrix isn't allocated yet. + if (all_parameters_new.use_energy == true){//for split form get energy + double dt = all_parameters_new.ode_solver_param.initial_time_step; + + ode_solver->current_iteration = 0; + + // advance by small amount, basically 0 + ode_solver->advance_solution_time(dt/10.0); + // compute the initial energy and conservation + double initial_energy = compute_energy(dg); + double initial_conservation = compute_conservation(dg, poly_degree); + + // create file to write energy and conservation results + // outputs results as Time, Energy Newline Time, Conservation + // And energy and conservation values are normalized by the initial value. + std::ofstream myfile ("energy_plot.gpl" , std::ios::trunc); + + ode_solver->current_iteration = 0; + + // loop over time steps because needs to evaluate energy and conservation at each time step. + for (int i = 0; i < std::ceil(finalTime/dt); ++ i){ + + ode_solver->advance_solution_time(dt); + //energy + double current_energy = compute_energy(dg); + current_energy /=initial_energy; + std::cout << std::setprecision(16) << std::fixed; + this->pcout << "Energy at time " << i * dt << " is " << current_energy<< std::endl; + myfile << i * dt << " " << std::fixed << std::setprecision(16) << current_energy << std::endl; + if (current_energy*initial_energy - initial_energy >= 1.00)//since normalized by initial + { + this->pcout << " Energy was not monotonically decreasing" << std::endl; + return 1; + } + if ( (current_energy*initial_energy - initial_energy >= 1.0e-12) && (all_parameters_new.conv_num_flux_type == Parameters::AllParameters::ConvectiveNumericalFlux::central_flux)) + { + this->pcout << " Energy was not conserved" << std::endl; + return 1; + } + // Conservation + double current_conservation = compute_conservation(dg, poly_degree); + current_conservation /=initial_conservation; + std::cout << std::setprecision(16) << std::fixed; + this->pcout << "Normalized Conservation at time " << i * dt << " is " << current_conservation<< std::endl; + myfile << i * dt << " " << std::fixed << std::setprecision(16) << current_conservation << std::endl; + if (current_conservation*initial_conservation - initial_conservation >= 10.00) + // if (current_energy - initial_energy >= 10.00) + { + this->pcout << "Not conserved" << std::endl; + return 1; + } + } + + // Close the file + myfile.close(); + } + else{// do OOA + if(left==-1){ + finalTime = 0.5; + } + if(left==0){ + finalTime=1.0; + } + ode_solver->current_iteration = 0; + // advance solution until the final time + ode_solver->advance_solution_time(finalTime); + // output results + const unsigned int n_global_active_cells = grid->n_global_active_cells(); + const unsigned int n_dofs = dg->dof_handler.n_dofs(); + this->pcout << "Dimension: " << dim + << "\t Polynomial degree p: " << poly_degree + << std::endl + << "Grid number: " << igrid+1 << "/" << n_grids + << ". Number of active cells: " << n_global_active_cells + << ". Number of degrees of freedom: " << n_dofs + << std::endl; + + // Overintegrate the error to make sure there is not integration error in the error estimate + int overintegrate = 10; + dealii::QGauss quad_extra(poly_degree+1+overintegrate); + dealii::FEValues fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], quad_extra, + dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points); + const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points; + std::array soln_at_q; + + double l2error = 0.0; + + // Integrate every cell and compute L2 and Linf errors. + const double pi = atan(1)*4.0; + std::vector dofs_indices (fe_values_extra.dofs_per_cell); + double linf_error = 0.0; + const dealii::Tensor<1,3,double> adv_speeds = Parameters::ManufacturedSolutionParam::get_default_advection_vector(); + for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) { + if (!cell->is_locally_owned()) continue; + + fe_values_extra.reinit (cell); + cell->get_dof_indices (dofs_indices); + + for (unsigned int iquad=0; iquadsolution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate); + } + + for (int istate=0; istate qpoint = (fe_values_extra.quadrature_point(iquad)); + double uexact=1.0; + for(int idim=0; idim linf_error){ + linf_error = inf_temp; + } + } + } + + } + const double l2error_mpi_sum = std::sqrt(dealii::Utilities::MPI::sum(l2error, this->mpi_communicator)); + const double linferror_mpi= (dealii::Utilities::MPI::max(linf_error, this->mpi_communicator)); + + // Convergence table + const double dx = 1.0/pow(n_dofs,(1.0/dim)); + grid_size[igrid] = dx; + soln_error[igrid] = l2error_mpi_sum; + soln_error_inf[igrid] = linferror_mpi; + // output_error[igrid] = std::abs(solution_integral - exact_solution_integral); + + convergence_table.add_value("p", poly_degree); + convergence_table.add_value("cells", n_global_active_cells); + convergence_table.add_value("DoFs", n_dofs); + convergence_table.add_value("dx", dx); + convergence_table.add_value("soln_L2_error", l2error_mpi_sum); + convergence_table.add_value("soln_Linf_error", linferror_mpi); + // convergence_table.add_value("output_error", output_error[igrid]); + + + this->pcout << " Grid size h: " << dx + << " L2-soln_error: " << l2error_mpi_sum + << " Linf-soln_error: " << linferror_mpi + << " Residual: " << ode_solver->residual_norm + << std::endl; + + if (igrid > igrid_start) { + const double slope_soln_err = log(soln_error[igrid]/soln_error[igrid-1]) + / log(grid_size[igrid]/grid_size[igrid-1]); + const double slope_soln_err_inf = log(soln_error_inf[igrid]/soln_error_inf[igrid-1]) + / log(grid_size[igrid]/grid_size[igrid-1]); + // const double slope_output_err = log(output_error[igrid]/output_error[igrid-1]) + // / log(grid_size[igrid]/grid_size[igrid-1]); + this->pcout << "From grid " << igrid-1 + << " to grid " << igrid + << " dimension: " << dim + << " polynomial degree p: " << poly_degree + << std::endl + << " solution_error1 " << soln_error[igrid-1] + << " solution_error2 " << soln_error[igrid] + << " slope " << slope_soln_err + << " solution_error1_inf " << soln_error_inf[igrid-1] + << " solution_error2_inf " << soln_error_inf[igrid] + << " slope " << slope_soln_err_inf + << std::endl; + + if(igrid == n_grids-1){ + if(std::abs(slope_soln_err_inf-(poly_degree+1))>0.1) + return 1; + } + } + }//end of OOA else statement + this->pcout << " ********************************************" + << std::endl + << " Convergence rates for p = " << poly_degree + << std::endl + << " ********************************************" + << std::endl; + convergence_table.evaluate_convergence_rates("soln_L2_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim); + convergence_table.evaluate_convergence_rates("soln_Linf_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim); + convergence_table.evaluate_convergence_rates("output_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim); + convergence_table.set_scientific("dx", true); + convergence_table.set_scientific("soln_L2_error", true); + convergence_table.set_scientific("soln_Linf_error", true); + convergence_table.set_scientific("output_error", true); + if (this->pcout.is_active()) convergence_table.write_text(this->pcout.get_stream()); + + }//end of grid loop + + return 0;//if reaches here mean passed test +} + +template class AdvectionPeriodic ; + +} //Tests namespace +} //PHiLiP namespace diff --git a/src/testing/advection_explicit_periodic.h b/src/testing/advection_explicit_periodic.h index ae73b948a..1b2094972 100644 --- a/src/testing/advection_explicit_periodic.h +++ b/src/testing/advection_explicit_periodic.h @@ -8,20 +8,26 @@ namespace PHiLiP { namespace Tests { -/// Linear advection through periodic boundary conditions. +/// Advection periodic unsteady test template class AdvectionPeriodic: public TestsBase { public: - /// Constructor. - AdvectionPeriodic(const Parameters::AllParameters *const parameters_input); + /// Constructor + AdvectionPeriodic(const Parameters::AllParameters *const parameters_input); - /// Currently passes no matter what. - /** Since it is linear advection, the exact solution about time T is known. Convergence orders can/should be checked. - * TO BE FIXED. - */ + /// Destructor + ~AdvectionPeriodic() {}; + + /// Run test int run_test () const override; private: + /// Function computes the energy + double compute_energy(std::shared_ptr < PHiLiP::DGBase > &dg) const; + /// Function computes the conservation + double compute_conservation(std::shared_ptr < PHiLiP::DGBase > &dg, const double poly_degree) const; + /// Warping for nonlinear manifold (see CurvManifold above) + static dealii::Point warp (const dealii::Point &p); }; } // End of Tests namespace diff --git a/src/testing/burgers_stability.cpp b/src/testing/burgers_stability.cpp index 989c88a23..3cdad3afd 100644 --- a/src/testing/burgers_stability.cpp +++ b/src/testing/burgers_stability.cpp @@ -1,5 +1,3 @@ -#include - #include #include #include @@ -12,12 +10,18 @@ #include #include #include +#include #include "burgers_stability.h" #include "parameters/all_parameters.h" #include "parameters/parameters.h" +#include "dg/dg.h" #include "dg/dg_factory.hpp" +#include "ode_solver/ode_solver_base.h" +#include #include "ode_solver/ode_solver_factory.h" +#include "physics/initial_conditions/set_initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" namespace PHiLiP { @@ -31,88 +35,321 @@ BurgersEnergyStability::BurgersEnergyStability(const PHiLiP::Parame template double BurgersEnergyStability::compute_energy(std::shared_ptr < PHiLiP::DGBase > &dg) const { - double energy = 0.0; - for (unsigned int i = 0; i < dg->solution.size(); ++i) - { - energy += 1./(dg->global_inverse_mass_matrix(i,i)) * dg->solution(i) * dg->solution(i); - } - return energy; + double energy = 0.0; + dealii::LinearAlgebra::distributed::Vector mass_matrix_times_solution(dg->right_hand_side); + if(dg->all_parameters->use_inverse_mass_on_the_fly) + dg->apply_global_mass_matrix(dg->solution,mass_matrix_times_solution); + else + dg->global_mass_matrix.vmult( mass_matrix_times_solution, dg->solution); + //Since we normalize the energy later, don't bother scaling by 0.5 + //Energy \f$ = 0.5 * \int u^2 d\Omega_m \f$ + energy = dg->solution * mass_matrix_times_solution; + + return energy; +} + +template +double BurgersEnergyStability::compute_conservation(std::shared_ptr < PHiLiP::DGBase > &dg, const double poly_degree) const +{ + // Conservation \f$ = \int 1 * u d\Omega_m \f$ + double conservation = 0.0; + dealii::LinearAlgebra::distributed::Vector mass_matrix_times_solution(dg->right_hand_side); + if(dg->all_parameters->use_inverse_mass_on_the_fly) + dg->apply_global_mass_matrix(dg->solution,mass_matrix_times_solution); + else + dg->global_mass_matrix.vmult( mass_matrix_times_solution, dg->solution); + + const unsigned int n_dofs_cell = dg->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size(); + std::vector ones(n_quad_pts, 1.0); + //Projected vector of ones. That is, the interpolation of ones_hat to the volume nodes is 1. + std::vector ones_hat(n_dofs_cell); + //We have to project the vector of ones because the mass matrix has an interpolation from solution nodes built into it. + OPERATOR::vol_projection_operator vol_projection(dg->nstate, poly_degree, dg->max_grid_degree); + vol_projection.build_1D_volume_operator(dg->oneD_fe_collection[poly_degree], dg->oneD_quadrature_collection[poly_degree]); + vol_projection.matrix_vector_mult_1D(ones, ones_hat, + vol_projection.oneD_vol_operator); + + dealii::LinearAlgebra::distributed::Vector ones_hat_global(dg->right_hand_side); + std::vector dofs_indices (n_dofs_cell); + for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) { + if (!cell->is_locally_owned()) continue; + cell->get_dof_indices (dofs_indices); + for(unsigned int idof=0;idof int BurgersEnergyStability::run_test() const { pcout << " Running Burgers energy stability. " << std::endl; - using Triangulation = dealii::Triangulation; - std::shared_ptr grid = std::make_shared(); - + + PHiLiP::Parameters::AllParameters all_parameters_new = *all_parameters; double left = 0.0; double right = 2.0; - const bool colorize = true; - int n_refinements = 5; - unsigned int poly_degree = 7; - dealii::GridGenerator::hyper_cube(*grid, left, right, colorize); - - std::vector > matched_pairs; - dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); - grid->add_periodicity(matched_pairs); - - - grid->refine_global(n_refinements); - pcout << "Grid generated and refined" << std::endl; - - std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(all_parameters, poly_degree, grid); - pcout << "dg created" <allocate_system (); - - pcout << "Implement initial conditions" << std::endl; - dealii::FunctionParser<1> initial_condition; - std::string variables = "x"; - std::map constants; - constants["pi"] = dealii::numbers::PI; - std::string expression = "sin(pi*(x)) + 0.01"; - initial_condition.initialize(variables, - expression, - constants); - dealii::VectorTools::interpolate(dg->dof_handler,initial_condition,dg->solution); - // Create ODE solver using the factory and providing the DG object - std::shared_ptr> ode_solver = PHiLiP::ODE::ODESolverFactory::create_ODESolver(dg); - - double finalTime = 3.; - - double dt = all_parameters->ode_solver_param.initial_time_step; - //(void) dt; - - //need to call ode_solver before calculating energy because mass matrix isn't allocated yet. - - ode_solver->advance_solution_time(0.000001); - double initial_energy = compute_energy(dg); - - //currently the only way to calculate energy at each time-step is to advance solution by dt instead of finaltime - //this causes some issues with outputs (only one file is output, which is overwritten at each time step) - //also the ode solver output doesn't make sense (says "iteration 1 out of 1") - //but it works. I'll keep it for now and need to modify the output functions later to account for this. - std::ofstream myfile ("energy_plot.gpl" , std::ios::trunc); - - for (int i = 0; i < std::ceil(finalTime/dt); ++ i) { - ode_solver->advance_solution_time(dt); - double current_energy = compute_energy(dg); - pcout << "Energy at time " << i * dt << " is " << current_energy << std::endl; - myfile << i * dt << " " << current_energy << std::endl; - if (current_energy - initial_energy >= 0.001) { - return 1; - break; - } - } - myfile.close(); - - - //ode_solver->advance_solution_time(finalTime); - - return 0; //need to change + const unsigned int n_grids = (all_parameters_new.use_energy) ? 4 : 5; + std::vector grid_size(n_grids); + std::vector soln_error(n_grids); + unsigned int poly_degree = 4; + dealii::ConvergenceTable convergence_table; + const unsigned int igrid_start = 3; + const unsigned int grid_degree = 1; + + for(unsigned int igrid = igrid_start; igrid does not work for 1D + using Triangulation = dealii::Triangulation; + std::shared_ptr grid = std::make_shared( + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#else + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#endif + //straight grid setup + dealii::GridGenerator::hyper_cube(*grid, left, right, true); + //found the periodicity in dealii doesn't work as expected in 1D so I hard coded the 1D periodic condition in DG +#if PHILIP_DIM==1 + std::vector::cell_iterator> > matched_pairs; + dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); + grid->add_periodicity(matched_pairs); +#else + std::vector::cell_iterator> > matched_pairs; + dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); + if(dim>=2) dealii::GridTools::collect_periodic_faces(*grid,2,3,1,matched_pairs); + if(dim>=3) dealii::GridTools::collect_periodic_faces(*grid,4,5,2,matched_pairs); + grid->add_periodicity(matched_pairs); +#endif + grid->refine_global(igrid); + pcout << "Grid generated and refined" << std::endl; + //CFL number + const unsigned int n_global_active_cells2 = grid->n_global_active_cells(); + double n_dofs_cfl = pow(n_global_active_cells2,dim) * pow(poly_degree+1.0, dim); + double delta_x = (right-left)/pow(n_dofs_cfl,(1.0/dim)); + all_parameters_new.ode_solver_param.initial_time_step = 0.5*delta_x; + //use 0.0001 to be consisitent with Ranocha and Gassner papers + all_parameters_new.ode_solver_param.initial_time_step = 0.0001; + + //allocate dg + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + pcout << "dg created" <allocate_system (); + + //initialize IC + pcout<<"Setting up Initial Condition"< > initial_condition_function = + InitialConditionFactory::create_InitialConditionFunction(&all_parameters_new); + SetInitialCondition::set_initial_condition(initial_condition_function, dg, &all_parameters_new); + + // Create ODE solver using the factory and providing the DG object + std::shared_ptr> ode_solver = ODE::ODESolverFactory::create_ODESolver(dg); + + double finalTime = 3.0; + + if (all_parameters_new.use_energy == true){//for split form get energy + + double dt = all_parameters_new.ode_solver_param.initial_time_step; + + // need to call ode_solver before calculating energy because mass matrix isn't allocated yet. + ode_solver->current_iteration = 0; + ode_solver->advance_solution_time(0.000001); + double initial_energy = compute_energy(dg); + double initial_conservation = compute_conservation(dg, poly_degree); + + // currently the only way to calculate energy at each time-step is to advance solution by dt instead of finaltime + // this causes some issues with outputs (only one file is output, which is overwritten at each time step) + // also the ode solver output doesn't make sense (says "iteration 1 out of 1") + // but it works. I'll keep it for now and need to modify the output functions later to account for this. + std::ofstream myfile ("energy_plot_burgers.gpl" , std::ios::trunc); + + ode_solver->current_iteration = 0; + for (int i = 0; i < std::ceil(finalTime/dt); ++ i) + { + ode_solver->advance_solution_time(dt); + //Energy + double current_energy = compute_energy(dg); + current_energy /=initial_energy; + std::cout << std::setprecision(16) << std::fixed; + pcout << "Energy at time " << i * dt << " is " << current_energy << std::endl; + myfile << i * dt << " " << std::fixed << std::setprecision(16) << current_energy << std::endl; + if (current_energy*initial_energy - initial_energy >= 1.0) + { + pcout<<"Energy not monotonicaly decreasing"<= 1.0e-11)&&(all_parameters_new.conv_num_flux_type == Parameters::AllParameters::ConvectiveNumericalFlux::two_point_flux) ) + { + pcout<<"Energy not conserved"<= 10.00) + { + pcout << "Not conserved" << std::endl; + return 1; + break; + } + } + myfile.close(); + + //Print to a file the final solution vs x to plot + std::ofstream myfile2 ("solution_burgers.gpl" , std::ios::trunc); + + dealii::QGaussLobatto quad_extra(dg->max_degree+1); + dealii::FEValues fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], quad_extra, + dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points); + const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points; + std::array soln_at_q; + std::vector dofs_indices (fe_values_extra.dofs_per_cell); + + for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) { + if (!cell->is_locally_owned()) continue; + + fe_values_extra.reinit (cell); + cell->get_dof_indices (dofs_indices); + + for (unsigned int iquad=0; iquadsolution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate); + } + const dealii::Point qpoint = (fe_values_extra.quadrature_point(iquad)); + + std::cout << std::setprecision(16) << std::fixed; + myfile2<< std::fixed << std::setprecision(16) << qpoint[0] << std::fixed << std::setprecision(16) <<" " << soln_at_q[0]<< std::endl; + } + } + myfile2.close(); + }//end of energy + else{//do OOA + finalTime = 0.001;//This is sufficient for verification + + ode_solver->current_iteration = 0; + + ode_solver->advance_solution_time(finalTime); + const unsigned int n_global_active_cells = grid->n_global_active_cells(); + const unsigned int n_dofs = dg->dof_handler.n_dofs(); + pcout << "Dimension: " << dim + << "\t Polynomial degree p: " << poly_degree + << std::endl + << "Grid number: " << igrid+1 << "/" << n_grids + << ". Number of active cells: " << n_global_active_cells + << ". Number of degrees of freedom: " << n_dofs + << std::endl; + + // Overintegrate the error to make sure there is not integration error in the error estimate + int overintegrate = 10; + dealii::QGauss quad_extra(poly_degree+1+overintegrate); + dealii::FEValues fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], quad_extra, + dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points); + const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points; + std::array soln_at_q; + + double l2error = 0.0; + + // Integrate solution error and output error + const double pi = atan(1)*4.0; + std::vector dofs_indices (fe_values_extra.dofs_per_cell); + for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) { + + if (!cell->is_locally_owned()) continue; + + fe_values_extra.reinit (cell); + cell->get_dof_indices (dofs_indices); + + for (unsigned int iquad=0; iquadsolution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate); + } + + for (int istate=0; istate qpoint = (fe_values_extra.quadrature_point(iquad)); + double uexact = 0.0; + for(int idim=0; idimresidual_norm + << std::endl; + + if (igrid > igrid_start) { + const double slope_soln_err = log(soln_error[igrid]/soln_error[igrid-1]) + / log(grid_size[igrid]/grid_size[igrid-1]); + pcout << "From grid " << igrid + << " to grid " << igrid+1 + << " dimension: " << dim + << " polynomial degree p: " << poly_degree + << std::endl + << " solution_error1 " << soln_error[igrid-1] + << " solution_error2 " << soln_error[igrid] + << " slope " << slope_soln_err + << std::endl; + if(igrid == n_grids-1){ + if(std::abs(slope_soln_err-(poly_degree+1))>0.05){ + return 1; + } + } + } + + pcout << " ********************************************" + << std::endl + << " Convergence rates for p = " << poly_degree + << std::endl + << " ********************************************" + << std::endl; + convergence_table.evaluate_convergence_rates("soln_L2_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim); + convergence_table.set_scientific("dx", true); + convergence_table.set_scientific("soln_L2_error", true); + if (pcout.is_active()) convergence_table.write_text(pcout.get_stream()); + }//end of OOA + }//end of grid loop + return 0; //if got to here means passed the test, otherwise would've failed earlier } + #if PHILIP_DIM==1 - template class BurgersEnergyStability; +template class BurgersEnergyStability; #endif + } // Tests namespace } // PHiLiP namespace diff --git a/src/testing/burgers_stability.h b/src/testing/burgers_stability.h index f2a5ad840..ee59b953c 100644 --- a/src/testing/burgers_stability.h +++ b/src/testing/burgers_stability.h @@ -8,26 +8,24 @@ namespace PHiLiP { namespace Tests { -/// Burgers sine wave to shock. -/** Ensure that the kinetic energy is bounded. - * Gassner 2017. - */ +/// Burgers' periodic unsteady test template class BurgersEnergyStability: public TestsBase { public: - /// Constructor. - BurgersEnergyStability(const Parameters::AllParameters *const parameters_input); - /// Ensure that the kinetic energy is bounded. - /** If the kinetic energy increases about its initial value, then the test should fail. - * Gassner 2017. - */ + /// Constructor + BurgersEnergyStability(const Parameters::AllParameters *const parameters_input); + + /// Destructor + ~BurgersEnergyStability() {}; + + /// Run test int run_test () const override; private: - /// Computes an integral of the kinetic energy (solution squared) in the entire domain. - /** Uses Inverse of inverse mass matrix (?) to evaluate integral of u^2. - */ - double compute_energy(std::shared_ptr < PHiLiP::DGBase > &dg) const; + /// Function computes the energy + double compute_energy(std::shared_ptr < PHiLiP::DGBase > &dg) const; + /// Function computes the conservation + double compute_conservation(std::shared_ptr < PHiLiP::DGBase > &dg, const double poly_degree) const; }; } // End of Tests namespace diff --git a/src/testing/convection_diffusion_explicit_periodic.cpp b/src/testing/convection_diffusion_explicit_periodic.cpp new file mode 100644 index 000000000..f862c30b3 --- /dev/null +++ b/src/testing/convection_diffusion_explicit_periodic.cpp @@ -0,0 +1,368 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "convection_diffusion_explicit_periodic.h" +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "dg/dg.h" +#include "dg/dg_factory.hpp" +#include "ode_solver/ode_solver_base.h" +#include +#include "ode_solver/ode_solver_factory.h" +#include "physics/initial_conditions/set_initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" + + +namespace PHiLiP { +namespace Tests { + +template +ConvectionDiffusionPeriodic::ConvectionDiffusionPeriodic(const PHiLiP::Parameters::AllParameters *const parameters_input) + : TestsBase::TestsBase(parameters_input) +{} + +template +double ConvectionDiffusionPeriodic::compute_energy_derivative_norm(std::shared_ptr < PHiLiP::DGBase > &dg) const +{ + double energy = 0.0; + dg->assemble_residual(); + energy = dg->solution * dg->right_hand_side; + + //diffusion contribution + const double diff_coeff = dg->all_parameters->manufactured_convergence_study_param.manufactured_solution_param.diffusion_coefficient; + const dealii::Tensor<2,3,double> diff_tensor = Parameters::ManufacturedSolutionParam::get_default_diffusion_tensor(); + for(int idim=0; idimauxiliary_solution[jdim] * dg->auxiliary_right_hand_side[idim] * diff_tensor[idim][jdim]; + energy += diff_coeff * temp_energy; + } + } + + return energy; +} + +template +double ConvectionDiffusionPeriodic::compute_conservation(std::shared_ptr < PHiLiP::DGBase > &dg, const double poly_degree) const +{ + // Conservation \f$ = \int 1 * u d\Omega_m \f$ + double conservation = 0.0; + dealii::LinearAlgebra::distributed::Vector mass_matrix_times_solution(dg->right_hand_side); + if(dg->all_parameters->use_inverse_mass_on_the_fly) + dg->apply_global_mass_matrix(dg->solution,mass_matrix_times_solution); + else + dg->global_mass_matrix.vmult(mass_matrix_times_solution, dg->solution); + + const unsigned int n_dofs_cell = dg->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size(); + std::vector ones(n_quad_pts); + for(unsigned int iquad=0; iquad ones_hat(n_dofs_cell); + // We have to project the vector of ones because the mass matrix has an interpolation from solution nodes built into it. + OPERATOR::vol_projection_operator vol_projection(dg->nstate, poly_degree, dg->max_grid_degree); + vol_projection.build_1D_volume_operator(dg->oneD_fe_collection[poly_degree], dg->oneD_quadrature_collection[poly_degree]); + vol_projection.matrix_vector_mult_1D(ones, ones_hat, vol_projection.oneD_vol_operator); + + dealii::LinearAlgebra::distributed::Vector ones_hat_global(dg->right_hand_side); + std::vector dofs_indices (n_dofs_cell); + for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) { + if (!cell->is_locally_owned()) continue; + cell->get_dof_indices (dofs_indices); + for(unsigned int idof=0;idof diff_tensor = Parameters::ManufacturedSolutionParam::get_default_diffusion_tensor(); + for(int idim=0; idim mass_matrix_times_auxiliary_variable(dg->right_hand_side); + if(dg->all_parameters->use_inverse_mass_on_the_fly) + dg->apply_global_mass_matrix(dg->auxiliary_solution[idim], mass_matrix_times_auxiliary_variable,true); + else + dg->global_mass_matrix_auxiliary.vmult( mass_matrix_times_auxiliary_variable, dg->auxiliary_solution[idim]); + for(int jdim=0; jdim +int ConvectionDiffusionPeriodic::run_test() const +{ + this->pcout << " Running Convection Diffusion Periodicity test. " << std::endl; + + PHiLiP::Parameters::AllParameters all_parameters_new = *all_parameters; + double left = 0.0; + double right = 2.0; + const unsigned int n_grids = (all_parameters_new.use_energy) ? 4 : 5; + std::vector grid_size(n_grids); + std::vector soln_error(n_grids); + unsigned int poly_degree = 3; + dealii::ConvergenceTable convergence_table; + const unsigned int igrid_start = (all_parameters_new.use_energy) ? 3 : 3; + const unsigned int grid_degree = 1; + + for(unsigned int igrid = igrid_start; igrid does not work for 1D + using Triangulation = dealii::Triangulation; + std::shared_ptr grid = std::make_shared( + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#else + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#endif + // straight grid + dealii::GridGenerator::hyper_cube(*grid, left, right, true); +#if PHILIP_DIM==1 + std::vector::cell_iterator> > matched_pairs; + dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); + grid->add_periodicity(matched_pairs); +#else + std::vector::cell_iterator> > matched_pairs; + dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); + if(dim>=2) dealii::GridTools::collect_periodic_faces(*grid,2,3,1,matched_pairs); + if(dim>=3) dealii::GridTools::collect_periodic_faces(*grid,4,5,2,matched_pairs); + grid->add_periodicity(matched_pairs); +#endif + grid->refine_global(igrid); + this->pcout << "Grid generated and refined" << std::endl; + // CFL number + const unsigned int n_global_active_cells2 = grid->n_global_active_cells(); + double n_dofs_cfl = pow(n_global_active_cells2,dim) * pow(poly_degree+1.0, dim); + double delta_x = (right-left)/pow(n_dofs_cfl,(1.0/dim)); + const double diff_coeff2 = Parameters::ManufacturedSolutionParam::get_default_diffusion_coefficient(); + //const double diff_coeff2 = dg->all_parameters->manufactured_convergence_study_param.manufactured_solution_param.diffusion_coefficient; + const dealii::Tensor<2,3,double> diff_tensor2 = Parameters::ManufacturedSolutionParam::get_default_diffusion_tensor(); + double max_diff_tens=0.0; + for(int i=0; i max_diff_tens) max_diff_tens = std::abs(diff_tensor2[i][j]); + } + } + all_parameters_new.ode_solver_param.initial_time_step = 0.5*pow(delta_x,2)/diff_coeff2; + all_parameters_new.ode_solver_param.initial_time_step = 0.05*pow(delta_x,2)/diff_coeff2 / max_diff_tens; + + // allocate dg + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + this->pcout << "dg created" <allocate_system (); + + this->pcout << "Setting up Initial Condition" << std::endl; + // Create initial condition function + std::shared_ptr< InitialConditionFunction > initial_condition_function = + InitialConditionFactory::create_InitialConditionFunction(&all_parameters_new); + SetInitialCondition::set_initial_condition(initial_condition_function, dg, &all_parameters_new); + + // Create ODE solver using the factory and providing the DG object + std::shared_ptr> ode_solver = ODE::ODESolverFactory::create_ODESolver(dg); + + double finalTime = 2.0; + + if(all_parameters_new.use_energy == true){//for split form get energy + finalTime = 0.01; + + double dt = all_parameters_new.ode_solver_param.initial_time_step; + + // need to call ode_solver before calculating energy because mass matrix isn't allocated yet. + + ode_solver->current_iteration = 0; + ode_solver->advance_solution_time(0.000001); + + double initial_energy = compute_energy_derivative_norm(dg); + double initial_conservation = compute_conservation(dg, poly_degree); + + // currently the only way to calculate energy at each time-step is to advance solution by dt instead of finaltime + // this causes some issues with outputs (only one file is output, which is overwritten at each time step) + // also the ode solver output doesn't make sense (says "iteration 1 out of 1") + // but it works. I'll keep it for now and need to modify the output functions later to account for this. + std::ofstream myfile ("energy_plot_cons_diff.gpl" , std::ios::trunc); + + ode_solver->current_iteration = 0; + for(int i = 0; i < std::ceil(finalTime/dt); ++ i) { + ode_solver->advance_solution_time(dt); + double current_energy = compute_energy_derivative_norm(dg); + std::cout << std::setprecision(16) << std::fixed; + this->pcout << "Energy at time " << i * dt << " is " << current_energy << std::endl; + myfile << i * dt << " " << std::fixed << std::setprecision(16) << current_energy << std::endl; + + if (current_energy>1e-12)/*if (current_energy*initial_energy - initial_energy >= 10000.0)*/ + { + this->pcout<<"Energy Fail Not montonically decrease with current "<< current_energy<<" vs initial "<= 1.0e-12) && + (all_parameters_new.diss_num_flux_type == Parameters::AllParameters::DissipativeNumericalFlux::central_visc_flux)) + { + this->pcout<<"Energy Not conserved with current "<< current_energy<<" vs initial "<pcout << "Normalized Conservation at time " << i * dt << " is " << current_conservation<< std::endl; + myfile << i * dt << " " << std::fixed << std::setprecision(16) << current_conservation << std::endl; + if (current_conservation*initial_conservation - initial_conservation >= 1e-12) + //if (current_energy - initial_energy >= 10.00) + { + this->pcout << "Not conserved" << std::endl; + return 1; + break; + } + } + myfile.close(); + }//end of energy + else {//do OOA + + finalTime = 1e-3; + + ode_solver->current_iteration = 0; + + ode_solver->advance_solution_time(finalTime); + const unsigned int n_global_active_cells = grid->n_global_active_cells(); + const unsigned int n_dofs = dg->dof_handler.n_dofs(); + this->pcout << "Dimension: " << dim + << "\t Polynomial degree p: " << poly_degree + << std::endl + << "Grid number: " << igrid+1 << "/" << n_grids + << ". Number of active cells: " << n_global_active_cells + << ". Number of degrees of freedom: " << n_dofs + << std::endl; + + // Overintegrate the error to make sure there is not integration error in the error estimate + int overintegrate = 10; + dealii::QGauss quad_extra(poly_degree+1+overintegrate); + dealii::FEValues fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], quad_extra, + dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points); + const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points; + std::array soln_at_q; + + double l2error = 0.0; + + // Integrate solution error and output error + const double pi = atan(1)*4.0; + const double diff_coeff = Parameters::ManufacturedSolutionParam::get_default_diffusion_coefficient(); + std::vector dofs_indices (fe_values_extra.dofs_per_cell); + for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) { + + if (!cell->is_locally_owned()) continue; + + fe_values_extra.reinit (cell); + cell->get_dof_indices (dofs_indices); + + for (unsigned int iquad=0; iquadsolution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate); + } + + for (int istate=0; istate qpoint = (fe_values_extra.quadrature_point(iquad)); + double uexact=1.0; + for(int idim=0; idimmpi_communicator)); +#endif + + // Convergence table + const double dx = 1.0/pow(n_dofs,(1.0/dim)); + grid_size[igrid] = dx; + soln_error[igrid] = l2error_mpi_sum; + convergence_table.add_value("p", poly_degree); + convergence_table.add_value("cells", n_global_active_cells); + convergence_table.add_value("DoFs", n_dofs); + convergence_table.add_value("dx", dx); + convergence_table.add_value("soln_L2_error", l2error_mpi_sum); + + this->pcout << " Grid size h: " << dx + << " L2-soln_error: " << l2error_mpi_sum + << " Residual: " << ode_solver->residual_norm + << std::endl; + + if (igrid > igrid_start) { + const double slope_soln_err = log(soln_error[igrid]/soln_error[igrid-1]) + / log(grid_size[igrid]/grid_size[igrid-1]); + // const double slope_output_err = log(output_error[igrid]/output_error[igrid-1]) + // / log(grid_size[igrid]/grid_size[igrid-1]); + this->pcout << "From grid " << igrid + << " to grid " << igrid+1 + << " dimension: " << dim + << " polynomial degree p: " << poly_degree + << std::endl + << " solution_error1 " << soln_error[igrid-1] + << " solution_error2 " << soln_error[igrid] + << " slope " << slope_soln_err + << std::endl; + if(igrid == n_grids-1){ + if(std::abs(slope_soln_err-(poly_degree+1))>0.1){ + return 1; + } + } + } + + this->pcout << " ********************************************" + << std::endl + << " Convergence rates for p = " << poly_degree + << std::endl + << " ********************************************" + << std::endl; + convergence_table.evaluate_convergence_rates("soln_L2_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim); + convergence_table.set_scientific("dx", true); + convergence_table.set_scientific("soln_L2_error", true); + if (this->pcout.is_active()) convergence_table.write_text(this->pcout.get_stream()); + }//end of OOA + }//end of grid loop + + return 0; +} + +template class ConvectionDiffusionPeriodic; + +} // Tests namespace +} // PHiLiP namespace diff --git a/src/testing/convection_diffusion_explicit_periodic.h b/src/testing/convection_diffusion_explicit_periodic.h new file mode 100644 index 000000000..c190234f6 --- /dev/null +++ b/src/testing/convection_diffusion_explicit_periodic.h @@ -0,0 +1,41 @@ +#ifndef __CONVECTION_DIFFUSION_EXPLICIT_PERIODIC_H__ +#define __CONVECTION_DIFFUSION_EXPLICIT_PERIODIC_H__ + +#include "tests.h" +#include "dg/dg.h" +#include "parameters/all_parameters.h" + +namespace PHiLiP { +namespace Tests { + +/// Convection Diffusion periodic unsteady test (currently only diffusion) +template +class ConvectionDiffusionPeriodic: public TestsBase +{ +public: + /// Constructor + ConvectionDiffusionPeriodic(const Parameters::AllParameters *const parameters_input); + + /// Destructor + ~ConvectionDiffusionPeriodic() {}; + + /// Run test + int run_test () const override; +private: + /// Function computes the energy bound. + /** Note that for convection-diffusion, we have a proof on the norm of the time rate of + * change of the energy with respect to the norm of the auxiliary variable. + * Explicitly, \f$ \frac{1}{2}\frac{d}{dt}\| U\|^2 + b\|Q\|^2 \leq 0\f$. + * The energy dissipation is related to the auxiliary variable. Thus, for a central flux, + * we can prove the above is equal to 0 within machine precision. This is not the same + * as the energy being conserved. + */ + double compute_energy_derivative_norm(std::shared_ptr < PHiLiP::DGBase > &dg) const; + + /// Function computes the conservation + double compute_conservation(std::shared_ptr < PHiLiP::DGBase > &dg, const double poly_degree) const; +}; + +} // Tests namespace +} // PHiLiP namespace +#endif diff --git a/src/testing/diffusion_exact_adjoint.cpp b/src/testing/diffusion_exact_adjoint.cpp index edc331630..870a0748d 100644 --- a/src/testing/diffusion_exact_adjoint.cpp +++ b/src/testing/diffusion_exact_adjoint.cpp @@ -155,6 +155,7 @@ template std::array diffusion_u::source_term ( const dealii::Point &pos, const std::array &/*solution*/, + const real /*current_time*/, const dealii::types::global_dof_index /*cell_index*/) const { std::array source; @@ -226,6 +227,7 @@ template std::array diffusion_v::source_term ( const dealii::Point &pos, const std::array &/*solution*/, + const real /*current_time*/, const dealii::types::global_dof_index /*cell_index*/) const { const double pi = std::acos(-1); diff --git a/src/testing/diffusion_exact_adjoint.h b/src/testing/diffusion_exact_adjoint.h index 289720d4f..5862488f7 100644 --- a/src/testing/diffusion_exact_adjoint.h +++ b/src/testing/diffusion_exact_adjoint.h @@ -189,7 +189,8 @@ class diffusion_u : public diffusion_objective std::array source_term ( const dealii::Point &pos, const std::array &solution, - const dealii::types::global_dof_index cell_index) const; + const real current_time, + const dealii::types::global_dof_index cell_index) const override; /// objective function = g real objective_function( @@ -225,7 +226,8 @@ class diffusion_v : public diffusion_objective std::array source_term ( const dealii::Point &pos, const std::array &solution, - const dealii::types::global_dof_index cell_index) const; + const real current_time, + const dealii::types::global_dof_index cell_index) const override; /// objective function = f real objective_function( diff --git a/src/testing/euler_bump_optimization.cpp b/src/testing/euler_bump_optimization.cpp index ad1c30d6d..919dc17c0 100644 --- a/src/testing/euler_bump_optimization.cpp +++ b/src/testing/euler_bump_optimization.cpp @@ -16,7 +16,7 @@ #include "euler_bump_optimization.h" -#include "physics/initial_conditions/initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" #include "physics/euler.h" #include "dg/dg_factory.hpp" #include "ode_solver/ode_solver_factory.h" diff --git a/src/testing/euler_cylinder.cpp b/src/testing/euler_cylinder.cpp index 4f3506086..305a90e2a 100644 --- a/src/testing/euler_cylinder.cpp +++ b/src/testing/euler_cylinder.cpp @@ -23,7 +23,7 @@ #include "euler_cylinder.h" -#include "physics/initial_conditions/initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" #include "physics/euler.h" #include "physics/manufactured_solution.h" #include "dg/dg_factory.hpp" diff --git a/src/testing/euler_cylinder_adjoint.cpp b/src/testing/euler_cylinder_adjoint.cpp index 6713233bd..bb358fa5a 100644 --- a/src/testing/euler_cylinder_adjoint.cpp +++ b/src/testing/euler_cylinder_adjoint.cpp @@ -27,7 +27,7 @@ #include "physics/physics.h" #include "physics/physics_factory.h" -#include "physics/initial_conditions/initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" #include "physics/euler.h" #include "physics/manufactured_solution.h" diff --git a/src/testing/euler_gaussian_bump.cpp b/src/testing/euler_gaussian_bump.cpp index 9ab5ccc44..6b95d82eb 100644 --- a/src/testing/euler_gaussian_bump.cpp +++ b/src/testing/euler_gaussian_bump.cpp @@ -6,6 +6,7 @@ #include "euler_gaussian_bump.h" +#include "physics/initial_conditions/initial_condition_function.h" #include "physics/euler.h" #include "flow_solver/flow_solver_factory.h" diff --git a/src/testing/euler_ismail_roe_entropy_check.cpp b/src/testing/euler_ismail_roe_entropy_check.cpp new file mode 100644 index 000000000..5d62eb969 --- /dev/null +++ b/src/testing/euler_ismail_roe_entropy_check.cpp @@ -0,0 +1,45 @@ +#include "euler_ismail_roe_entropy_check.h" +#include "flow_solver/flow_solver_factory.h" +#include "flow_solver/flow_solver_cases/periodic_turbulence.h" + +namespace PHiLiP { +namespace Tests { + +template +EulerIsmailRoeEntropyCheck::EulerIsmailRoeEntropyCheck( + const PHiLiP::Parameters::AllParameters *const parameters_input, + const dealii::ParameterHandler ¶meter_handler_input) + : TestsBase::TestsBase(parameters_input) + , parameter_handler(parameter_handler_input) +{} + +template +int EulerIsmailRoeEntropyCheck::run_test() const +{ + // Initialize flow_solver + std::unique_ptr> flow_solver = FlowSolver::FlowSolverFactory::select_flow_case(this->all_parameters, parameter_handler); + + // Compute initial and final entropy + std::unique_ptr> flow_solver_case = std::make_unique>(this->all_parameters); + const double initial_entropy = flow_solver_case->get_numerical_entropy(flow_solver->dg); + static_cast(flow_solver->run()); + const double final_entropy = flow_solver_case->get_numerical_entropy(flow_solver->dg); + + //Compare initial and final entropy to confirm entropy preservation + pcout << "Initial num. entropy: " << std::setprecision(16) << initial_entropy + << " final: " << final_entropy + << " scaled difference " << abs((initial_entropy-final_entropy)/initial_entropy) + << std::endl; + if (abs((initial_entropy-final_entropy)/initial_entropy) > 1E-15){ + pcout << "Entropy change is not within allowable tolerance. Test failing."; + return 1; + } + + return 0; +} + +#if PHILIP_DIM==3 + template class EulerIsmailRoeEntropyCheck; +#endif +} // Tests namespace +} // PHiLiP namespace diff --git a/src/testing/euler_ismail_roe_entropy_check.h b/src/testing/euler_ismail_roe_entropy_check.h new file mode 100644 index 000000000..b7faebea7 --- /dev/null +++ b/src/testing/euler_ismail_roe_entropy_check.h @@ -0,0 +1,32 @@ +#ifndef __EULER_ISMAIL_ROE_ENTROPY_CHECK__ +#define __EULER_ISMAIL_ROE_ENTROPY_CHECK__ + +#include "tests.h" + +namespace PHiLiP { +namespace Tests { + +/// Euler Ismail-Roe Entropy Check +template +class EulerIsmailRoeEntropyCheck: public TestsBase +{ +public: + /// Constructor + EulerIsmailRoeEntropyCheck( + const Parameters::AllParameters *const parameters_input, + const dealii::ParameterHandler ¶meter_handler_input); + + /// Destructor + ~EulerIsmailRoeEntropyCheck() {}; + + /// Parameter handler for storing the .prm file being ran + const dealii::ParameterHandler ¶meter_handler; + + /// Run test + int run_test () const override; +}; + +} // End of Tests namespace +} // End of PHiLiP namespace + +#endif diff --git a/src/testing/euler_naca0012_optimization.cpp b/src/testing/euler_naca0012_optimization.cpp index 6563029f4..7c8383e7a 100644 --- a/src/testing/euler_naca0012_optimization.cpp +++ b/src/testing/euler_naca0012_optimization.cpp @@ -19,7 +19,7 @@ #include "euler_naca0012_optimization.hpp" -#include "physics/initial_conditions/initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" #include "physics/euler.h" #include "dg/dg_factory.hpp" #include "ode_solver/ode_solver_factory.h" diff --git a/src/testing/euler_split_inviscid_taylor_green_vortex.cpp b/src/testing/euler_split_inviscid_taylor_green_vortex.cpp index a592ed557..584579a51 100644 --- a/src/testing/euler_split_inviscid_taylor_green_vortex.cpp +++ b/src/testing/euler_split_inviscid_taylor_green_vortex.cpp @@ -1,253 +1,380 @@ #include #include "dg/dg_factory.hpp" #include "euler_split_inviscid_taylor_green_vortex.h" +#include "physics/initial_conditions/set_initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" +#include "mesh/grids/nonsymmetric_curved_periodic_grid.hpp" namespace PHiLiP { namespace Tests { template EulerTaylorGreen::EulerTaylorGreen(const Parameters::AllParameters *const parameters_input) -: -TestsBase::TestsBase(parameters_input) + : TestsBase::TestsBase(parameters_input) {} +template +std::array EulerTaylorGreen::compute_change_in_entropy(std::shared_ptr < DGBase > &dg, unsigned int poly_degree) const +{ + const unsigned int n_dofs_cell = dg->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size(); + const unsigned int n_shape_fns = n_dofs_cell / nstate; + //We have to project the vector of entropy variables because the mass matrix has an interpolation from solution nodes built into it. + OPERATOR::vol_projection_operator vol_projection(1, poly_degree, dg->max_grid_degree); + vol_projection.build_1D_volume_operator(dg->oneD_fe_collection_1state[poly_degree], dg->oneD_quadrature_collection[poly_degree]); + + OPERATOR::basis_functions soln_basis(1, poly_degree, dg->max_grid_degree); + soln_basis.build_1D_volume_operator(dg->oneD_fe_collection_1state[poly_degree], dg->oneD_quadrature_collection[poly_degree]); + + dealii::LinearAlgebra::distributed::Vector entropy_var_hat_global(dg->right_hand_side); + dealii::LinearAlgebra::distributed::Vector energy_var_hat_global(dg->right_hand_side); + std::vector dofs_indices (n_dofs_cell); + + std::shared_ptr < Physics::Euler > euler_double = std::dynamic_pointer_cast>(PHiLiP::Physics::PhysicsFactory::create_Physics(dg->all_parameters)); + + for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) { + if (!cell->is_locally_owned()) continue; + cell->get_dof_indices (dofs_indices); + + std::array,nstate> soln_coeff; + for(unsigned int idof=0; idoffe_collection[poly_degree].system_to_component_index(idof).first; + const unsigned int ishape = dg->fe_collection[poly_degree].system_to_component_index(idof).second; + if(ishape == 0) + soln_coeff[istate].resize(n_shape_fns); + soln_coeff[istate][ishape] = dg->solution(dofs_indices[idof]); + } + + std::array,nstate> soln_at_q; + for(int istate=0; istate,nstate> entropy_var_at_q; + std::array,nstate> energy_var_at_q; + for(unsigned int iquad=0; iquad soln_state; + for(int istate=0; istate entropy_var_state = euler_double->compute_entropy_variables(soln_state); + std::array kin_energy_state = euler_double->compute_kinetic_energy_variables(soln_state); + for(int istate=0; istate entropy_var_hat(n_shape_fns); + vol_projection.matrix_vector_mult_1D(entropy_var_at_q[istate], entropy_var_hat, + vol_projection.oneD_vol_operator); + std::vector energy_var_hat(n_shape_fns); + vol_projection.matrix_vector_mult_1D(energy_var_at_q[istate], energy_var_hat, + vol_projection.oneD_vol_operator); + + for(unsigned int ishape=0; ishapeassemble_residual(); + std::array change_entropy_and_energy; + change_entropy_and_energy[0] = entropy_var_hat_global * dg->right_hand_side; + change_entropy_and_energy[1] = energy_var_hat_global * dg->right_hand_side; + return change_entropy_and_energy; +} + +template +double EulerTaylorGreen::compute_entropy(std::shared_ptr < DGBase > &dg, unsigned int poly_degree) const +{ + //returns the entropy evaluated in the broken Sobolev-norm rather than L2-norm + dealii::LinearAlgebra::distributed::Vector mass_matrix_times_solution(dg->right_hand_side); + if(dg->all_parameters->use_inverse_mass_on_the_fly) + dg->apply_global_mass_matrix(dg->solution,mass_matrix_times_solution); + else + dg->global_mass_matrix.vmult( mass_matrix_times_solution, dg->solution); + + const unsigned int n_dofs_cell = dg->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size(); + const unsigned int n_shape_fns = n_dofs_cell / nstate; + //We have to project the vector of entropy variables because the mass matrix has an interpolation from solution nodes built into it. + OPERATOR::vol_projection_operator vol_projection(1, poly_degree, dg->max_grid_degree); + vol_projection.build_1D_volume_operator(dg->oneD_fe_collection_1state[poly_degree], dg->oneD_quadrature_collection[poly_degree]); + + OPERATOR::basis_functions soln_basis(1, poly_degree, dg->max_grid_degree); + soln_basis.build_1D_volume_operator(dg->oneD_fe_collection_1state[poly_degree], dg->oneD_quadrature_collection[poly_degree]); + + dealii::LinearAlgebra::distributed::Vector entropy_var_hat_global(dg->right_hand_side); + std::vector dofs_indices (n_dofs_cell); + + std::shared_ptr < Physics::PhysicsBase > pde_physics_double = PHiLiP::Physics::PhysicsFactory::create_Physics(dg->all_parameters); + + for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) { + if (!cell->is_locally_owned()) continue; + cell->get_dof_indices (dofs_indices); + + std::array,nstate> soln_coeff; + for(unsigned int idof=0; idoffe_collection[poly_degree].system_to_component_index(idof).first; + const unsigned int ishape = dg->fe_collection[poly_degree].system_to_component_index(idof).second; + if(ishape == 0) + soln_coeff[istate].resize(n_shape_fns); + soln_coeff[istate][ishape] = dg->solution(dofs_indices[idof]); + } -//template -//double EulerTaylorGreen::compute_quadrature_kinetic_energy(std::array soln_at_q) const -//{ -// const double density = soln_at_q[0]; -// -// const double quad_kin_energ = 0.5*(soln_at_q[1]*soln_at_q[1] + -// soln_at_q[2]*soln_at_q[2] + -// soln_at_q[3]*soln_at_q[3] )/density; -// return quad_kin_energ; -//} + std::array,nstate> soln_at_q; + for(int istate=0; istate,nstate> entropy_var_at_q; + for(unsigned int iquad=0; iquad soln_state; + for(int istate=0; istate entropy_var_state = pde_physics_double->compute_entropy_variables(soln_state); + for(int istate=0; istate entropy_var_hat(n_shape_fns); + vol_projection.matrix_vector_mult_1D(entropy_var_at_q[istate], entropy_var_hat, + vol_projection.oneD_vol_operator); + + for(unsigned int ishape=0; ishape double EulerTaylorGreen::compute_kinetic_energy(std::shared_ptr < DGBase > &dg, unsigned int poly_degree) const { - // Overintegrate the error to make sure there is not integration error in the error estimate - int overintegrate = 10 ;//10; - dealii::QGauss quad_extra(dg->max_degree+1+overintegrate); - dealii::FEValues fe_values_extra(dealii::MappingQ(dg->max_degree+overintegrate), dg->fe_collection[poly_degree], quad_extra, - dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points); -// dealii::QGauss quad_extra(dg->fe_system.tensor_degree()+overintegrate); -// dealii::FEValues fe_values_extra(dg->mapping, dg->fe_system, quad_extra, -// dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points); - const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points; - std::array soln_at_q; - - double total_kinetic_energy = 0; - - // Integrate solution error and output error - typename dealii::DoFHandler::active_cell_iterator - cell = dg->dof_handler.begin_active(), - endc = dg->dof_handler.end(); - - std::vector dofs_indices (fe_values_extra.dofs_per_cell); - - //const double gam = euler_physics_double.gam; - //const double mach_inf = euler_physics_double.mach_inf; - //const double tot_temperature_inf = 1.0; - //const double tot_pressure_inf = 1.0; - //// Assuming a tank at rest, velocity = 0, therefore, static pressure and temperature are same as total - //const double density_inf = gam*tot_pressure_inf/tot_temperature_inf * mach_inf * mach_inf; - //const double entropy_inf = tot_pressure_inf*pow(density_inf,-gam); - //const double entropy_inf = euler_physics_double.entropy_inf; - - for (; cell!=endc; ++cell) { - - fe_values_extra.reinit (cell); - //std::cout << "sitting on cell " << cell->index() << std::endl; - cell->get_dof_indices (dofs_indices); + //returns the energy in the L2-norm (physically relevant) + int overintegrate = 10 ; + dealii::QGauss quad_extra(dg->max_degree+1+overintegrate); + const dealii::Mapping &mapping = (*(dg->high_order_grid->mapping_fe_field)); + dealii::FEValues fe_values_extra(mapping, dg->fe_collection[poly_degree], quad_extra, + dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points); + const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points; + std::array soln_at_q; + + double total_kinetic_energy = 0; + + std::vector dofs_indices (fe_values_extra.dofs_per_cell); + + for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) { + if (!cell->is_locally_owned()) continue; + + fe_values_extra.reinit (cell); + cell->get_dof_indices (dofs_indices); + + //Please see Eq. 3.21 in Gassner, Gregor J., Andrew R. Winters, and David A. Kopriva. "Split form nodal discontinuous Galerkin schemes with summation-by-parts property for the compressible Euler equations." Journal of Computational Physics 327 (2016): 39-66. for (unsigned int iquad=0; iquadsolution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate); - } + std::fill(soln_at_q.begin(), soln_at_q.end(), 0); + for (unsigned int idof=0; idofsolution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate); + } - const double density = soln_at_q[0]; + const double density = soln_at_q[0]; - const double quadrature_kinetic_energy = 0.5*(soln_at_q[1]*soln_at_q[1] + - soln_at_q[2]*soln_at_q[2] + - soln_at_q[3]*soln_at_q[3] )/density; + const double quadrature_kinetic_energy = 0.5*(soln_at_q[1]*soln_at_q[1] + + soln_at_q[2]*soln_at_q[2] + + soln_at_q[3]*soln_at_q[3])/density; - //const double quadrature_kinetic_energy = compute_quadrature_kinetic_energy(soln_at_q); + total_kinetic_energy += quadrature_kinetic_energy * fe_values_extra.JxW(iquad); + } + } + return total_kinetic_energy; +} - total_kinetic_energy += quadrature_kinetic_energy * fe_values_extra.JxW(iquad); +template +double EulerTaylorGreen::get_timestep(std::shared_ptr < DGBase > &dg, unsigned int poly_degree, const double delta_x) const +{ + //get local CFL + const unsigned int n_dofs_cell = nstate*pow(poly_degree+1,dim); + const unsigned int n_quad_pts = pow(poly_degree+1,dim); + std::vector dofs_indices1 (n_dofs_cell); + + double cfl_min = 1e100; + std::shared_ptr < Physics::PhysicsBase > pde_physics_double = PHiLiP::Physics::PhysicsFactory::create_Physics(dg->all_parameters); + for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) { + if (!cell->is_locally_owned()) continue; + + cell->get_dof_indices (dofs_indices1); + std::vector< std::array> soln_at_q(n_quad_pts); + for (unsigned int iquad=0; iquad qpoint = dg->volume_quadrature_collection[poly_degree].point(iquad); + for(unsigned int idof=0; idoffe_collection[poly_degree].system_to_component_index(idof).first; + soln_at_q[iquad][istate] += dg->solution[dofs_indices1[idof]] * dg->fe_collection[poly_degree].shape_value_component(idof, qpoint, istate); + } + } + + std::vector< double > convective_eigenvalues(n_quad_pts); + for (unsigned int isol = 0; isol < n_quad_pts; ++isol) { + convective_eigenvalues[isol] = pde_physics_double->max_convective_eigenvalue (soln_at_q[isol]); + } + const double max_eig = *(std::max_element(convective_eigenvalues.begin(), convective_eigenvalues.end())); + + const double max_eig_mpi = dealii::Utilities::MPI::max(max_eig, mpi_communicator); + double cfl = 0.1 * delta_x/max_eig_mpi; + if(cfl < cfl_min) + cfl_min = cfl; + + } + return cfl_min; } template int EulerTaylorGreen::run_test() const { - //dealii::Triangulation grid; + // using Triangulation = dealii::parallel::distributed::Triangulation; + // std::shared_ptr grid = std::make_shared (mpi_communicator); using Triangulation = dealii::parallel::distributed::Triangulation; - std::shared_ptr grid = std::make_shared (mpi_communicator); - - double left = 0.0; - double right = 2 * dealii::numbers::PI; - const bool colorize = true; - int n_refinements = 2; - unsigned int poly_degree = 1; - dealii::GridGenerator::hyper_cube(*grid, left, right, colorize); - - std::vector::cell_iterator> > matched_pairs; - dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); - dealii::GridTools::collect_periodic_faces(*grid,2,3,1,matched_pairs); - dealii::GridTools::collect_periodic_faces(*grid,4,5,2,matched_pairs); - grid->add_periodicity(matched_pairs); - - grid->refine_global(n_refinements); - - std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(all_parameters, poly_degree, grid); - dg->allocate_system (); - - std::cout << "Implement initial conditions" << std::endl; - dealii::FunctionParser initial_condition(5); - std::string variables = "x,y,z"; - std::map constants; - constants["pi"] = dealii::numbers::PI; - std::vector expressions(5); - expressions[0] = "1"; - expressions[1] = "sin(x)*cos(y)*cos(z)"; - expressions[2] = "-cos(x)*sin(y)*cos(z)"; - expressions[3] = "0"; - expressions[4] = "250.0/1.4 + 2.5/16.0 * (cos(2.0*x)*cos(2.0*z) + 2.0*cos(2.0*y) + 2.0*cos(2.0*x) + cos(2.0*y)*cos(2.0*z)) + 0.5 * pow(cos(z),2.0) * (pow(cos(x),2.0) * pow(sin(y),2.0) +pow(sin(x),2.0) * pow(cos(y),2.0))"; - initial_condition.initialize(variables, - expressions, - constants); -// dealii::Point<3> point (0.0,1.0,1.0); -// dealii::Vector result(5); -// initial_condition.vector_value(point,result); -// dealii::deallog << result; - - std::cout << "initial condition successfully implemented" << std::endl; - dealii::VectorTools::interpolate(dg->dof_handler,initial_condition,dg->solution); - std::cout << "initial condition interpolated to DG solution" << std::endl; - // Create ODE solver using the factory and providing the DG object - - std::cout << "creating ODE solver" << std::endl; - std::shared_ptr> ode_solver = ODE::ODESolverFactory::create_ODESolver(dg); - std::cout << "ODE solver successfully created" << std::endl; - double finalTime = 14.; - double dt = all_parameters->ode_solver_param.initial_time_step; - - //double dt = all_parameters->ode_solver_param.initial_time_step; - //need to call ode_solver before calculating energy because mass matrix isn't allocated yet. - //ode_solver->advance_solution_time(0.000001); - //double initial_energy = compute_energy(dg); - - std::cout << "preparing to advance solution in time" << std::endl; -// //(void) finalTime; -// std::cout << "kinetic energy is" << compute_kinetic_energy(dg) <advance_solution_time(finalTime); -// //std::cout << "kinetic energy is" << compute_kinetic_energy(dg) <advance_solution_time(dt); - double current_energy = compute_kinetic_energy(dg,poly_degree); - std::cout << "Energy at time " << i * dt << " is " << current_energy << std::endl; - myfile << i * dt << " " << current_energy << std::endl; - - } - - myfile.close(); - -// ode_solver->advance_solution_time(finalTime); -// (void) dt; - return 0; //need to change -} + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); + + using real = double; + + PHiLiP::Parameters::AllParameters all_parameters_new = *all_parameters; + double left = 0.0; + double right = 2 * dealii::numbers::PI; + const int n_refinements = 2; + unsigned int poly_degree = 3; + + // set the warped grid + const unsigned int grid_degree = poly_degree; + PHiLiP::Grids::nonsymmetric_curved_grid(*grid, n_refinements); + +// const unsigned int grid_degree = 1; +// const bool colorize = true; +// dealii::GridGenerator::hyper_cube(*grid, left, right, colorize); +// std::vector::cell_iterator> > matched_pairs; +// dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); +// dealii::GridTools::collect_periodic_faces(*grid,2,3,1,matched_pairs); +// dealii::GridTools::collect_periodic_faces(*grid,4,5,2,matched_pairs); +// grid->add_periodicity(matched_pairs); +// grid->refine_global(n_refinements); + + // Create DG + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); + + std::cout << "Implement initial conditions" << std::endl; + std::shared_ptr< InitialConditionFunction > initial_condition_function = + InitialConditionFactory::create_InitialConditionFunction(&all_parameters_new); + SetInitialCondition::set_initial_condition(initial_condition_function, dg, &all_parameters_new); + + const unsigned int n_global_active_cells2 = grid->n_global_active_cells(); + double delta_x = (right-left)/n_global_active_cells2/(poly_degree+1.0); + pcout<<" delta x "<> ode_solver = ODE::ODESolverFactory::create_ODESolver(dg); + std::cout << "ODE solver successfully created" << std::endl; + double finalTime = 14.; + finalTime = 0.4; + // finalTime = 0.1;//to speed things up locally in tests, doesn't need full 14seconds to verify. + double dt = all_parameters_new.ode_solver_param.initial_time_step; + // double dt = all_parameters_new.ode_solver_param.initial_time_step / 10.0; +// finalTime = 14.0; + + std::cout << " number dofs " << dg->dof_handler.n_dofs()<current_iteration = 0; + ode_solver->advance_solution_time(dt/10.0); + double initial_energy = compute_kinetic_energy(dg, poly_degree); + double initial_entropy = compute_entropy(dg, poly_degree); + pcout<<"Initial MK Entropy "< initial_change_entropy = compute_change_in_entropy(dg, poly_degree); + pcout<<"Initial change in Entropy "<advance_solution_time(dt); + double current_energy = compute_kinetic_energy(dg,poly_degree); + std::cout << std::setprecision(16) << std::fixed; + pcout << "Energy at time " << i * dt << " is " << current_energy / initial_energy << std::endl; + pcout << "Actual Energy Divided by volume at time " << i * dt << " is " << current_energy/(8*pow(dealii::numbers::PI,3)) << std::endl; + if (current_energy - initial_energy >= 1.00) + { + pcout << " Energy was not monotonically decreasing" << std::endl; + return 1; + } + double current_entropy = compute_entropy(dg, poly_degree); + std::cout << std::setprecision(16) << std::fixed; + pcout << "M plus K norm Entropy at time " << i * dt << " is " << current_entropy / initial_entropy<< std::endl; + myfile << i * dt << " " << std::fixed << std::setprecision(16) << current_entropy / initial_entropy<< std::endl; + + std::array current_change_entropy = compute_change_in_entropy(dg, poly_degree); + std::cout << std::setprecision(16) << std::fixed; + pcout << "M plus K norm Change in Entropy at time " << i * dt << " is " << current_change_entropy[0]<< std::endl; + pcout << "M plus K norm Change in Kinetic Energy at time " << i * dt << " is " << current_change_entropy[1]<< std::endl; + if(abs(current_change_entropy[0]) > 1e-12 && (dg->all_parameters->two_point_num_flux_type == Parameters::AllParameters::TwoPointNumericalFlux::IR || dg->all_parameters->two_point_num_flux_type == Parameters::AllParameters::TwoPointNumericalFlux::CH || dg->all_parameters->two_point_num_flux_type == Parameters::AllParameters::TwoPointNumericalFlux::Ra)){ + pcout << " Entropy was not monotonically decreasing" << std::endl; + return 1; + } + myfile << i * dt << " " << std::fixed << std::setprecision(16) << current_change_entropy[0]<< std::endl; + myfile << i * dt << " " << std::fixed << std::setprecision(16) << current_change_entropy[1]<< std::endl; + all_parameters_new.ode_solver_param.initial_time_step = get_timestep(dg,poly_degree, delta_x); + } -//int main (int argc, char * argv[]) -//{ -// //parse parameters first -// feenableexcept(FE_INVALID | FE_OVERFLOW); // catch nan -// dealii::deallog.depth_console(99); -// dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); -// const int n_mpi = dealii::Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD); -// const int mpi_rank = dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); -// dealii::ConditionalOStream pcout(std::cout, mpi_rank==0); -// pcout << "Starting program with " << n_mpi << " processors..." << std::endl; -// if ((PHILIP_DIM==1) && !(n_mpi==1)) { -// std::cout << "********************************************************" << std::endl; -// std::cout << "Can't use mpirun -np X, where X>1, for 1D." << std::endl -// << "Currently using " << n_mpi << " processors." << std::endl -// << "Aborting..." << std::endl; -// std::cout << "********************************************************" << std::endl; -// std::abort(); -// } -// int test_error = 1; -// try -// { -// // Declare possible inputs -// dealii::ParameterHandler parameter_handler; -// Parameters::AllParameters::declare_parameters (parameter_handler); -// Parameters::parse_command_line (argc, argv, parameter_handler); -// -// // Read inputs from parameter file and set those values in AllParameters object -// Parameters::AllParameters all_parameters; -// std::cout << "Reading input..." << std::endl; -// all_parameters.parse_parameters (parameter_handler); -// -// AssertDimension(all_parameters.dimension, PHILIP_DIM); -// -// std::cout << "Starting program..." << std::endl; -// -// using namespace PHiLiP; -// //const Parameters::AllParameters parameters_input; -// EulerTaylorGreen euler_test(&all_parameters); -// int i = euler_test.run_test(); -// return i; -// } -// catch (std::exception &exc) -// { -// std::cerr << std::endl << std::endl -// << "----------------------------------------------------" -// << std::endl -// << "Exception on processing: " << std::endl -// << exc.what() << std::endl -// << "Aborting!" << std::endl -// << "----------------------------------------------------" -// << std::endl; -// return 1; -// } -// -// catch (...) -// { -// std::cerr << std::endl -// << std::endl -// << "----------------------------------------------------" -// << std::endl -// << "Unknown exception!" << std::endl -// << "Aborting!" << std::endl -// << "----------------------------------------------------" -// << std::endl; -// return 1; -// } -// std::cout << "End of program." << std::endl; -// return test_error; -//} + myfile.close(); + + return 0; +} #if PHILIP_DIM==3 template class EulerTaylorGreen ; #endif -} -} - - - +} // Tests namespace +} // PHiLiP namespace diff --git a/src/testing/euler_split_inviscid_taylor_green_vortex.h b/src/testing/euler_split_inviscid_taylor_green_vortex.h index 1002283d1..a149a435c 100644 --- a/src/testing/euler_split_inviscid_taylor_green_vortex.h +++ b/src/testing/euler_split_inviscid_taylor_green_vortex.h @@ -32,7 +32,7 @@ namespace Tests { /// Euler Taylor Green Vortex /** Ensure that the kinetic energy is bounded. - * Gassner 2016. + * Ref: Gassner 2016. */ template class EulerTaylorGreen : public TestsBase @@ -40,23 +40,33 @@ class EulerTaylorGreen : public TestsBase public: /// Constructor. /** Simply calls the TestsBase constructor to set its parameters = parameters_input - */ - EulerTaylorGreen(const Parameters::AllParameters *const parameters_input); + * */ + EulerTaylorGreen(const Parameters::AllParameters *const parameters_input); -/// Ensure that the kinetic energy is bounded. -/* If the kinetic energy increases about its initial value, then the test should fail. - * CURRENTLY PASSES NO MATTER WHAT. TO BE FIXED. - * Gassner 2016. - */ - int run_test() const override; + /// Ensure that the kinetic energy is bounded. + /** If the kinetic energy increases about its initial value, then the test should fail. + * Ref: Gassner 2016. + * */ + int run_test() const override; private: - /// Computes an integral of the kinetic energy (density * velocity squared) in the entire domain. - /** Overintegration of kinetic energy. + /// Computes kinetic energy. + /** In the future this function should change to: let \f$ v\f$ represent the kinetic energy "entropy" variables, it computes \f$v(M+K)u^T\f$. + */ + double compute_kinetic_energy(std::shared_ptr < DGBase > &dg, unsigned int poly_degree) const; + + ///Computes entropy in the norm. + /** That is let \f$ v\f$ represent the entropy variables, it computes \f$v(M+K)u^T\f$. + */ + double compute_entropy(std::shared_ptr < DGBase > &dg, unsigned int poly_degree) const; + + ///Computes change in entropy in the norm. + /** That is let \f$ v\f$ represent the entropy variables, it computes \f$v(M+K)\frac{du}{dt}^T\f$. */ - double compute_kinetic_energy(std::shared_ptr < DGBase > &dg, unsigned int poly_degree) const; - //double compute_quadrature_kinetic_energy(std::array soln_at_q) const ; - //const Parameters::AllParameters *const all_parameters; ///< Pointer to all parameters + std::array compute_change_in_entropy(std::shared_ptr < DGBase > &dg, unsigned int poly_degree) const; + + /// Computes the timestep from max eigenvector. + double get_timestep(std::shared_ptr < DGBase > &dg, unsigned int poly_degree, const double delta_x) const; }; diff --git a/src/testing/grid_refinement_study.cpp b/src/testing/grid_refinement_study.cpp index 4e0547eee..4bf0d4e5f 100644 --- a/src/testing/grid_refinement_study.cpp +++ b/src/testing/grid_refinement_study.cpp @@ -605,4 +605,4 @@ template class GridRefinementStudy &dg, const Physics::PhysicsBa solution_no_ghost.reinit(dg.locally_owned_dofs, MPI_COMM_WORLD); const auto mapping = (*(dg.high_order_grid->mapping_fe_field)); dealii::VectorTools::interpolate(mapping, dg.dof_handler, *physics.manufactured_solution_function, solution_no_ghost); - //solution_no_ghost *= 1.0+1e-3; - //solution_no_ghost = 0.0; - //int i = 0; - //for (auto sol = solution_no_ghost.begin(); sol != solution_no_ghost.end(); ++sol) { - // *sol = (++i) * 0.01; - //} + // solution_no_ghost *= 1.0+1e-3; + // solution_no_ghost = 0.0; + // int i = 0; + // for (auto sol = solution_no_ghost.begin(); sol != solution_no_ghost.end(); ++sol) { + // *sol = (++i) * 0.01; + // } dg.solution = solution_no_ghost; } template diff --git a/src/testing/tests.cpp b/src/testing/tests.cpp index 38627e0b2..d5780822d 100644 --- a/src/testing/tests.cpp +++ b/src/testing/tests.cpp @@ -28,6 +28,7 @@ #include "shock_1d.h" #include "euler_naca0012.hpp" #include "reduced_order.h" +#include "convection_diffusion_explicit_periodic.h" #include "dual_weighted_residual_mesh_adaptation.h" #include "pod_adaptive_sampling.h" #include "pod_adaptive_sampling_testing.h" @@ -36,6 +37,7 @@ #include "time_refinement_study.h" #include "time_refinement_study_reference.h" #include "burgers_energy_conservation_rrk.h" +#include "euler_ismail_roe_entropy_check.h" namespace PHiLiP { namespace Tests { @@ -106,9 +108,18 @@ std::string TestsBase::get_conv_num_flux_string(const Parameters::AllParameters const CNF_enum CNF_type = param->conv_num_flux_type; std::string conv_num_flux_string; if (CNF_type == CNF_enum::lax_friedrichs) {conv_num_flux_string = "lax_friedrichs";} - if (CNF_type == CNF_enum::split_form) {conv_num_flux_string = "split_form";} if (CNF_type == CNF_enum::roe) {conv_num_flux_string = "roe";} if (CNF_type == CNF_enum::l2roe) {conv_num_flux_string = "l2roe";} + if (CNF_type == CNF_enum::central_flux) {conv_num_flux_string = "central_flux";} + if (CNF_type == CNF_enum::two_point_flux) {conv_num_flux_string = "two_point_flux";} + if (CNF_type == CNF_enum::two_point_flux_with_lax_friedrichs_dissipation) { + conv_num_flux_string = "two_point_flux_with_lax_friedrichs_dissipation"; + } if (CNF_type == CNF_enum::two_point_flux_with_roe_dissipation) { + conv_num_flux_string = "two_point_flux_with_roe_dissipation"; + } if (CNF_type == CNF_enum::two_point_flux_with_l2roe_dissipation) { + conv_num_flux_string = "two_point_flux_with_l2roe_dissipation"; + } + return conv_num_flux_string; } @@ -139,6 +150,7 @@ std::string TestsBase::get_manufactured_solution_string(const Parameters::AllPar if (MS_type == ManufacturedSolutionEnum::boundary_layer_solution) {manufactured_solution_string = "boundary_layer_solution";} if (MS_type == ManufacturedSolutionEnum::s_shock_solution) {manufactured_solution_string = "s_shock_solution";} if (MS_type == ManufacturedSolutionEnum::quadratic_solution) {manufactured_solution_string = "quadratic_solution";} + if (MS_type == ManufacturedSolutionEnum::example_solution) {manufactured_solution_string = "example_solution";} if (MS_type == ManufacturedSolutionEnum::navah_solution_1) {manufactured_solution_string = "navah_solution_1";} if (MS_type == ManufacturedSolutionEnum::navah_solution_2) {manufactured_solution_string = "navah_solution_2";} if (MS_type == ManufacturedSolutionEnum::navah_solution_3) {manufactured_solution_string = "navah_solution_3";} @@ -205,7 +217,7 @@ ::select_test(const AllParam *const parameters_input, (void) parameter_handler_input; } - if(test_type == Test_enum::run_control) { + if(test_type == Test_enum::run_control) { // TO DO: rename to grid_study return std::make_unique>(parameters_input); } else if(test_type == Test_enum::grid_refinement_study) { return std::make_unique>(parameters_input); @@ -214,7 +226,9 @@ ::select_test(const AllParam *const parameters_input, } else if(test_type == Test_enum::diffusion_exact_adjoint) { if constexpr (dim>=1 && nstate==1) return std::make_unique>(parameters_input); } else if (test_type == Test_enum::advection_periodicity){ - if constexpr (dim == 2 && nstate == 1) return std::make_unique> (parameters_input); + if constexpr (nstate == 1) return std::make_unique> (parameters_input); + } else if (test_type == Test_enum::convection_diffusion_periodicity){ + if constexpr (nstate == 1) return std::make_unique> (parameters_input); } else if(test_type == Test_enum::euler_gaussian_bump) { if constexpr (dim==2 && nstate==dim+2) return std::make_unique>(parameters_input,parameter_handler_input); } else if(test_type == Test_enum::euler_gaussian_bump_enthalpy) { @@ -230,7 +244,7 @@ ::select_test(const AllParam *const parameters_input, } else if(test_type == Test_enum::euler_entropy_waves) { if constexpr (dim>=2 && nstate==PHILIP_DIM+2) return std::make_unique>(parameters_input); } else if(test_type == Test_enum::euler_split_taylor_green) { - if constexpr (dim==3 && nstate == dim+2) return std::make_unique>(parameters_input); + if constexpr (dim==3 && nstate == dim+2) return std::make_unique>(parameters_input); } else if(test_type == Test_enum::optimization_inverse_manufactured) { return std::make_unique>(parameters_input); } else if(test_type == Test_enum::euler_bump_optimization) { @@ -259,6 +273,8 @@ ::select_test(const AllParam *const parameters_input, if constexpr (dim==1 && nstate==1) return std::make_unique>(parameters_input, parameter_handler_input); } else if(test_type == Test_enum::burgers_energy_conservation_rrk) { if constexpr (dim==1 && nstate==1) return std::make_unique>(parameters_input, parameter_handler_input); + } else if(test_type == Test_enum::euler_ismail_roe_entropy_check) { + if constexpr (dim==3 && nstate==dim+2) return std::make_unique>(parameters_input, parameter_handler_input); } else { std::cout << "Invalid test. You probably forgot to add it to the list of tests in tests.cpp" << std::endl; std::abort(); diff --git a/src/testing/time_refinement_study.cpp b/src/testing/time_refinement_study.cpp index 5d50e2fe2..8c11180e2 100644 --- a/src/testing/time_refinement_study.cpp +++ b/src/testing/time_refinement_study.cpp @@ -39,7 +39,7 @@ double TimeRefinementStudy::calculate_L2_error_at_final_time_wrt_fun exact_solution_function = ExactSolutionFactory::create_ExactSolutionFunction(parameters.flow_solver_param, final_time); int poly_degree = parameters.grid_refinement_study_param.poly_degree; dealii::Vector difference_per_cell(dg->solution.size()); - + dealii::VectorTools::integrate_difference(dg->dof_handler, dg->solution, *exact_solution_function, @@ -50,6 +50,7 @@ double TimeRefinementStudy::calculate_L2_error_at_final_time_wrt_fun double L2_error = dealii::VectorTools::compute_global_error(*dg->triangulation, difference_per_cell, dealii::VectorTools::L2_norm); + return L2_error; } diff --git a/tests/integration_tests_control_files/CMakeLists.txt b/tests/integration_tests_control_files/CMakeLists.txt index 85d5623ec..7db720a94 100644 --- a/tests/integration_tests_control_files/CMakeLists.txt +++ b/tests/integration_tests_control_files/CMakeLists.txt @@ -7,6 +7,7 @@ add_subdirectory(burgers_inviscid_implicit) add_subdirectory(burgers_split_stability) add_subdirectory(euler_split_inviscid_taylor_green_vortex) add_subdirectory(advection_explicit_periodic) +add_subdirectory(convection_diffusion_explicit_periodic) add_subdirectory(euler_integration) add_subdirectory(grid_refinement) add_subdirectory(euler_bump_optimization) @@ -18,3 +19,4 @@ add_subdirectory(reduced_order) add_subdirectory(flow_solver) add_subdirectory(taylor_green_vortex_integration) add_subdirectory(time_refinement_study) +add_subdirectory(euler_entropy_conservation) diff --git a/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic.prm b/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic.prm deleted file mode 100644 index f03916d8f..000000000 --- a/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic.prm +++ /dev/null @@ -1,31 +0,0 @@ -# ------------------- - -set test_type = advection_periodicity - -# Number of dimensions -set dimension = 2 - -set use_weak_form = true - -set use_collocated_nodes = false - -set use_split_form = false - -# The PDE we want to solve -set pde_type = advection - -set conv_num_flux = lax_friedrichs - -subsection ODE solver - - set ode_output = verbose - - set nonlinear_max_iterations = 500 - - set print_iteration_modulo = 100 - - set ode_solver_type = runge_kutta - - set initial_time_step = 0.001 - -end diff --git a/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_OOA.prm b/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_OOA.prm new file mode 100644 index 000000000..efe19623d --- /dev/null +++ b/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_OOA.prm @@ -0,0 +1,58 @@ +# ------------------- + +set test_type = advection_periodicity + +# Number of dimensions +set dimension = 2 + +set use_weak_form = false + +set overintegration = 0 + +set use_collocated_nodes = false + +set use_split_form = false + +set use_curvilinear_split_form = true + +set use_weight_adjusted_mass = true + +set use_periodic_bc = true + +set use_energy = false + +set flux_reconstruction = cPlus + +set use_inverse_mass_on_the_fly = false + +set use_classical_FR = false + +# The PDE we want to solve +set pde_type = advection + +set conv_num_flux = lax_friedrichs +#set conv_num_flux = central_flux + +subsection ODE solver + + set ode_output = verbose + +# set nonlinear_max_iterations = 500 + set nonlinear_max_iterations = 50000 + set nonlinear_steady_residual_tolerance = 1e-12 + + set print_iteration_modulo = 100 + # set print_iteration_modulo = 1 + + set ode_solver_type = runge_kutta + + set initial_time_step = 0.001 + + set runge_kutta_method = rk4_ex + +end + +subsection flow_solver + set flow_case_type = convection_diffusion + set interpolate_initial_condition = false +end diff --git a/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_energy.prm b/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_energy.prm new file mode 100644 index 000000000..b88f790b9 --- /dev/null +++ b/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_energy.prm @@ -0,0 +1,59 @@ +# ------------------- + +set test_type = advection_periodicity + +# Number of dimensions +set dimension = 2 + +set use_weak_form = false + +set overintegration = 0 + +set use_collocated_nodes = false + +set use_split_form = false + +set use_curvilinear_split_form = true + +set use_weight_adjusted_mass = false + +set use_periodic_bc = true + +set use_energy = true + +set flux_reconstruction = cPlus + +set use_inverse_mass_on_the_fly = false + +set use_classical_FR = false + +# The PDE we want to solve +set pde_type = advection + +#set conv_num_flux = lax_friedrichs +set conv_num_flux = central_flux + +subsection ODE solver + + set ode_output = verbose + +# set nonlinear_max_iterations = 500 + set nonlinear_max_iterations = 50000 + set nonlinear_steady_residual_tolerance = 1e-12 + + set print_iteration_modulo = 100 + # set print_iteration_modulo = 1 + + set ode_solver_type = runge_kutta + + set initial_time_step = 0.001 + + set runge_kutta_method = rk4_ex + +end + +subsection flow_solver + set flow_case_type = advection + set interpolate_initial_condition = false +end + diff --git a/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_energy_weight_adjusted.prm b/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_energy_weight_adjusted.prm new file mode 100644 index 000000000..bfc3e23e9 --- /dev/null +++ b/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_energy_weight_adjusted.prm @@ -0,0 +1,59 @@ +# ------------------- + +set test_type = advection_periodicity + +# Number of dimensions +set dimension = 2 + +set use_weak_form = false + +set overintegration = 0 + +set use_collocated_nodes = false + +set use_split_form = false + +set use_curvilinear_split_form = true + +set use_weight_adjusted_mass = true + +set use_periodic_bc = true + +set use_energy = true + +set flux_reconstruction = cPlus + +set use_inverse_mass_on_the_fly = false + +set use_classical_FR = false + +# The PDE we want to solve +set pde_type = advection + +#set conv_num_flux = lax_friedrichs +set conv_num_flux = central_flux + +subsection ODE solver + + set ode_output = verbose + +# set nonlinear_max_iterations = 500 + set nonlinear_max_iterations = 50000 + set nonlinear_steady_residual_tolerance = 1e-12 + + set print_iteration_modulo = 100 + # set print_iteration_modulo = 1 + + set ode_solver_type = runge_kutta + + set initial_time_step = 0.001 + + set runge_kutta_method = rk4_ex + +end + +subsection flow_solver + set flow_case_type = advection + set interpolate_initial_condition = false +end + diff --git a/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_energy_weight_adjusted_on_the_fly.prm b/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_energy_weight_adjusted_on_the_fly.prm new file mode 100644 index 000000000..a0cde6ed6 --- /dev/null +++ b/tests/integration_tests_control_files/advection_explicit_periodic/2D_advection_explicit_periodic_energy_weight_adjusted_on_the_fly.prm @@ -0,0 +1,59 @@ +# ------------------- + +set test_type = advection_periodicity + +# Number of dimensions +set dimension = 2 + +set use_weak_form = false + +set overintegration = 0 + +set use_collocated_nodes = false + +set use_split_form = false + +set use_curvilinear_split_form = true + +set use_weight_adjusted_mass = true + +set use_periodic_bc = true + +set use_energy = true + +set flux_reconstruction = cPlus + +set use_classical_FR = false + +set use_inverse_mass_on_the_fly = true + +# The PDE we want to solve +set pde_type = advection + +#set conv_num_flux = lax_friedrichs +set conv_num_flux = central_flux + +subsection ODE solver + + set ode_output = verbose + +# set nonlinear_max_iterations = 500 + set nonlinear_max_iterations = 50000 + set nonlinear_steady_residual_tolerance = 1e-12 + + set print_iteration_modulo = 100 + # set print_iteration_modulo = 1 + + set ode_solver_type = runge_kutta + + set initial_time_step = 0.001 + + set runge_kutta_method = rk4_ex + +end + +subsection flow_solver + set flow_case_type = advection + set interpolate_initial_condition = false +end + diff --git a/tests/integration_tests_control_files/advection_explicit_periodic/3D_advection_explicit_periodic_energy_weight_adjusted.prm b/tests/integration_tests_control_files/advection_explicit_periodic/3D_advection_explicit_periodic_energy_weight_adjusted.prm new file mode 100644 index 000000000..f6581943a --- /dev/null +++ b/tests/integration_tests_control_files/advection_explicit_periodic/3D_advection_explicit_periodic_energy_weight_adjusted.prm @@ -0,0 +1,59 @@ +# ------------------- + +set test_type = advection_periodicity + +# Number of dimensions +set dimension = 3 + +set use_weak_form = false + +set overintegration = 0 + +set use_collocated_nodes = false + +set use_split_form = false + +set use_curvilinear_split_form = true + +set use_weight_adjusted_mass = true + +set use_periodic_bc = true + +set use_energy = true + +set flux_reconstruction = cPlus + +set use_inverse_mass_on_the_fly = true + +set use_classical_FR = false + +# The PDE we want to solve +set pde_type = advection + +#set conv_num_flux = lax_friedrichs +set conv_num_flux = central_flux + +subsection ODE solver + + set ode_output = verbose + +# set nonlinear_max_iterations = 500 + set nonlinear_max_iterations = 50000 + set nonlinear_steady_residual_tolerance = 1e-12 + + set print_iteration_modulo = 100 + # set print_iteration_modulo = 1 + + set ode_solver_type = runge_kutta + + set initial_time_step = 0.001 + + set runge_kutta_method = rk4_ex + +end + +subsection flow_solver + set flow_case_type = advection + set interpolate_initial_condition = false +end + diff --git a/tests/integration_tests_control_files/advection_explicit_periodic/CMakeLists.txt b/tests/integration_tests_control_files/advection_explicit_periodic/CMakeLists.txt index b74740f25..e453042b5 100644 --- a/tests/integration_tests_control_files/advection_explicit_periodic/CMakeLists.txt +++ b/tests/integration_tests_control_files/advection_explicit_periodic/CMakeLists.txt @@ -1,7 +1,38 @@ set(TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) -configure_file(2D_advection_explicit_periodic.prm 2D_advection_explicit_periodic.prm COPYONLY) +configure_file(2D_advection_explicit_periodic_energy.prm 2D_advection_explicit_periodic_energy.prm COPYONLY) add_test( - NAME MPI_2D_ADVECTION_EXPLICIT_PERIODIC_LONG -COMMAND mpirun -n ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_2D -i ${CMAKE_CURRENT_BINARY_DIR}/2D_advection_explicit_periodic.prm + NAME MPI_2D_ADVECTION_EXPLICIT_PERIODIC_ENERGY_LONG +COMMAND mpirun -n ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_2D -i ${CMAKE_CURRENT_BINARY_DIR}/2D_advection_explicit_periodic_energy.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) +set(TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +configure_file(2D_advection_explicit_periodic_OOA.prm 2D_advection_explicit_periodic_OOA.prm COPYONLY) +add_test( + NAME MPI_2D_ADVECTION_EXPLICIT_PERIODIC_OOA_LONG +COMMAND mpirun -n ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_2D -i ${CMAKE_CURRENT_BINARY_DIR}/2D_advection_explicit_periodic_OOA.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) + +set(TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +configure_file(2D_advection_explicit_periodic_energy_weight_adjusted.prm 2D_advection_explicit_periodic_energy_weight_adjusted.prm COPYONLY) +add_test( + NAME MPI_2D_ADVECTION_EXPLICIT_PERIODIC_ENERGY_WEIGHT_ADJUSTED_LONG +COMMAND mpirun -n ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_2D -i ${CMAKE_CURRENT_BINARY_DIR}/2D_advection_explicit_periodic_energy_weight_adjusted.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) + +set(TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +configure_file(2D_advection_explicit_periodic_energy_weight_adjusted_on_the_fly.prm 2D_advection_explicit_periodic_energy_weight_adjusted_on_the_fly.prm COPYONLY) +add_test( + NAME MPI_2D_ADVECTION_EXPLICIT_PERIODIC_ENERGY_WEIGHT_ADJUSTED_ON_THE_FLY_LONG +COMMAND mpirun -n ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_2D -i ${CMAKE_CURRENT_BINARY_DIR}/2D_advection_explicit_periodic_energy_weight_adjusted_on_the_fly.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) + +set(TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +configure_file(3D_advection_explicit_periodic_energy_weight_adjusted.prm 3D_advection_explicit_periodic_energy_weight_adjusted.prm COPYONLY) +add_test( + NAME MPI_3D_ADVECTION_EXPLICIT_PERIODIC_ENERGY_WEIGHT_ADJUSTED_LONG +COMMAND mpirun -n ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/3D_advection_explicit_periodic_energy_weight_adjusted.prm WORKING_DIRECTORY ${TEST_OUTPUT_DIR} ) diff --git a/tests/integration_tests_control_files/advection_implicit/1d_advection_explicit_strong.prm b/tests/integration_tests_control_files/advection_implicit/1d_advection_explicit_strong.prm new file mode 100644 index 000000000..c17e4da51 --- /dev/null +++ b/tests/integration_tests_control_files/advection_implicit/1d_advection_explicit_strong.prm @@ -0,0 +1,48 @@ +# Listing of Parameters +# --------------------- +# Number of dimensions +set dimension = 1 + +set use_weak_form = false + +# The PDE we want to solve. Choices are +# . +set pde_type = advection + +set conv_num_flux = lax_friedrichs + +subsection ODE solver + # Maximum nonlinear solver iterations + set nonlinear_max_iterations = 50000 + + # Nonlinear solver residual tolerance + set nonlinear_steady_residual_tolerance = 1e-12 + + set initial_time_step = 0.99 + + # Print every print_iteration_modulo iterations of the nonlinear solver + set print_iteration_modulo = 250 + + # Explicit or implicit solverChoices are . + set ode_solver_type = runge_kutta +end + +subsection manufactured solution convergence study + set use_manufactured_source_term = true + # Last degree used for convergence study + set degree_end = 4 + + # Starting degree for convergence study + set degree_start = 0 + + # 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 + + # Number of grids in grid study + set number_of_grids = 6 +end + diff --git a/tests/integration_tests_control_files/advection_implicit/2d_advection_explicit_strong.prm b/tests/integration_tests_control_files/advection_implicit/2d_advection_explicit_strong.prm new file mode 100644 index 000000000..2396b1c30 --- /dev/null +++ b/tests/integration_tests_control_files/advection_implicit/2d_advection_explicit_strong.prm @@ -0,0 +1,47 @@ +# Listing of Parameters +# --------------------- +# Number of dimensions +set dimension = 2 + +set use_weak_form = false +# The PDE we want to solve. Choices are +# . +set pde_type = advection + +set conv_num_flux = lax_friedrichs + +subsection ODE solver + # Maximum nonlinear solver iterations + set nonlinear_max_iterations = 50000 + + # Nonlinear solver residual tolerance + set nonlinear_steady_residual_tolerance = 1e-12 + + set initial_time_step = 0.99 + + # Print every print_iteration_modulo iterations of the nonlinear solver + set print_iteration_modulo = 250 + + # Explicit or implicit solverChoices are . + set ode_solver_type = runge_kutta +end + +subsection manufactured solution convergence study + set use_manufactured_source_term = true + # Last degree used for convergence study + set degree_end = 4 + + # Starting degree for convergence study + set degree_start = 0 + + # 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 + + # Number of grids in grid study + set number_of_grids = 6 +end + diff --git a/tests/integration_tests_control_files/advection_implicit/3d_advection_explicit_strong.prm b/tests/integration_tests_control_files/advection_implicit/3d_advection_explicit_strong.prm new file mode 100644 index 000000000..ca2ddb7f9 --- /dev/null +++ b/tests/integration_tests_control_files/advection_implicit/3d_advection_explicit_strong.prm @@ -0,0 +1,53 @@ +# Listing of Parameters +# --------------------- +# Number of dimensions +set dimension = 3 + +set use_weak_form = false +# The PDE we want to solve. Choices are +# . +set pde_type = advection + +set use_weak_form = false + +set conv_num_flux = lax_friedrichs + +subsection ODE solver + set initial_time_step = 1e10 + # Maximum nonlinear solver iterations + set nonlinear_max_iterations = 500000 + + # Nonlinear solver residual tolerance + set nonlinear_steady_residual_tolerance = 1e-12 + + set initial_time_step = .9 +# set time_step_factor_residual = 20.0 +# set time_step_factor_residual_exp = 3.0 + + # Print every print_iteration_modulo iterations of the nonlinear solver + #set print_iteration_modulo = 1 + + # Explicit or implicit solverChoices are . + set ode_solver_type = runge_kutta +end + +subsection manufactured solution convergence study + set use_manufactured_source_term = true + # Last degree used for convergence study + set degree_end = 2 + + # Starting degree for convergence study + set degree_start = 0 + + # Multiplier on grid size. nth-grid will be of size + # (initial_grid^grid_progression)^dim + set grid_progression = 1.5 + + set grid_progression_add = 2 + + # Initial grid of size (initial_grid_size)^dim + set initial_grid_size = 2 + + # Number of grids in grid study + set number_of_grids = 3 +end diff --git a/tests/integration_tests_control_files/advection_implicit/CMakeLists.txt b/tests/integration_tests_control_files/advection_implicit/CMakeLists.txt index cd7776a41..d5f13187b 100644 --- a/tests/integration_tests_control_files/advection_implicit/CMakeLists.txt +++ b/tests/integration_tests_control_files/advection_implicit/CMakeLists.txt @@ -64,3 +64,24 @@ add_test( WORKING_DIRECTORY ${TEST_OUTPUT_DIR} ) +configure_file(1d_advection_explicit_strong.prm 1d_advection_explicit_strong.prm COPYONLY) +add_test( + NAME 1D_ADVECTION_EXPLICIT_MANUFACTURED_SOLUTION_LONG_STRONG + COMMAND mpirun -n 1 ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_1D -i ${CMAKE_CURRENT_BINARY_DIR}/1d_advection_explicit_strong.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) + +configure_file(2d_advection_explicit_strong.prm 2d_advection_explicit_strong.prm COPYONLY) +add_test( + NAME MPI_2D_ADVECTION_EXPLICIT_MANUFACTURED_SOLUTION_STRONG_LONG + COMMAND mpirun -n ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_2D -i ${CMAKE_CURRENT_BINARY_DIR}/2d_advection_explicit_strong.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) + +configure_file(3d_advection_explicit_strong.prm 3d_advection_explicit_strong.prm COPYONLY) +add_test( + NAME MPI_3D_ADVECTION_EXPLICIT_MANUFACTURED_SOLUTION_STRONG + COMMAND mpirun -n ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/3d_advection_explicit_strong.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) + diff --git a/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_energy_conservation_rrk.prm b/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_energy_conservation_rrk.prm index b7fa7d18d..b4f7794bf 100644 --- a/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_energy_conservation_rrk.prm +++ b/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_energy_conservation_rrk.prm @@ -13,7 +13,7 @@ set use_periodic_bc = true set use_weak_form = false set use_collocated_nodes = true set use_split_form = true -set conv_num_flux = split_form +set conv_num_flux = two_point_flux # ODE solver subsection ODE solver diff --git a/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_stability.prm b/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_stability.prm deleted file mode 100644 index 668b58d54..000000000 --- a/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_stability.prm +++ /dev/null @@ -1,27 +0,0 @@ -set test_type = burgers_energy_stability - -set dimension = 1 - -set use_weak_form = false - -set use_collocated_nodes = true - -set use_split_form = true - -set pde_type = burgers_inviscid - -set conv_num_flux = split_form - -subsection ODE solver - - set ode_output = verbose - - set nonlinear_max_iterations = 500 - - set print_iteration_modulo = 100 - - set ode_solver_type = runge_kutta - - set initial_time_step = 0.0001 - -end diff --git a/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_stability_OOA.prm b/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_stability_OOA.prm new file mode 100644 index 000000000..3f59e9870 --- /dev/null +++ b/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_stability_OOA.prm @@ -0,0 +1,56 @@ +set test_type = burgers_energy_stability + +set dimension = 1 + +set use_weak_form = false + +set overintegration = 0 + +set use_collocated_nodes = false + +set use_split_form = true + +set use_energy = false + +set use_L2_norm = false + +set use_classical_FR = false + +set use_periodic_bc = true + +set flux_reconstruction = cPlus + +set use_inverse_mass_on_the_fly = true + +#set use_skew_sym_deriv = false + +set pde_type = burgers_inviscid + +set conv_num_flux = lax_friedrichs +#set conv_num_flux = central_flux +#set conv_num_flux = two_point_flux_with_lax_friedrichs_dissipation + +subsection ODE solver + + set ode_output = verbose + + set nonlinear_max_iterations = 500000 + + set print_iteration_modulo = 1000 + + set ode_solver_type = runge_kutta + + set initial_time_step = 0.0001 + #set initial_time_step = 0.00005 + + set runge_kutta_method = rk4_ex + +end + +subsection manufactured solution convergence study + set use_manufactured_source_term = true +end + +subsection flow_solver + set flow_case_type = burgers_inviscid +end diff --git a/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_stability_energy.prm b/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_stability_energy.prm new file mode 100644 index 000000000..5d05fbd59 --- /dev/null +++ b/tests/integration_tests_control_files/burgers_split_stability/1D_burgers_stability_energy.prm @@ -0,0 +1,53 @@ +set test_type = burgers_energy_stability + +set dimension = 1 + +set use_weak_form = false + +set overintegration = 2 + +set use_collocated_nodes = false + +set use_split_form = true + +set use_energy = true + +set use_L2_norm = false + +set use_classical_FR = false + +set use_periodic_bc = true + +set flux_reconstruction = cPlus + +set use_inverse_mass_on_the_fly = true + +#set use_skew_sym_deriv = false + +set pde_type = burgers_inviscid + +#set conv_num_flux = lax_friedrichs +#set conv_num_flux = central_flux +#set conv_num_flux = two_point_flux_with_lax_friedrichs_dissipation +set conv_num_flux = two_point_flux + +subsection ODE solver + + set ode_output = verbose + + set nonlinear_max_iterations = 500000 + + set print_iteration_modulo = 1000 + + set ode_solver_type = runge_kutta + + set initial_time_step = 0.0001 + #set initial_time_step = 0.00005 + + set runge_kutta_method = rk4_ex + +end + +subsection flow_solver + set flow_case_type = burgers_inviscid +end diff --git a/tests/integration_tests_control_files/burgers_split_stability/CMakeLists.txt b/tests/integration_tests_control_files/burgers_split_stability/CMakeLists.txt index fd607c318..23e8d03ef 100644 --- a/tests/integration_tests_control_files/burgers_split_stability/CMakeLists.txt +++ b/tests/integration_tests_control_files/burgers_split_stability/CMakeLists.txt @@ -1,8 +1,15 @@ set(TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) -configure_file(1D_burgers_stability.prm 1D_burgers_stability.prm COPYONLY) +configure_file(1D_burgers_stability_energy.prm 1D_burgers_stability_energy.prm COPYONLY) add_test( - NAME 1D_burgers_stability_LONG - COMMAND mpirun -n 1 ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_1D -i ${CMAKE_CURRENT_BINARY_DIR}/1D_burgers_stability.prm + NAME 1D_BURGERS_STABILITY_ENERGY_LONG + COMMAND mpirun -n 1 ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_1D -i ${CMAKE_CURRENT_BINARY_DIR}/1D_burgers_stability_energy.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) +set(TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +configure_file(1D_burgers_stability_OOA.prm 1D_burgers_stability_OOA.prm COPYONLY) +add_test( + NAME 1D_BURGERS_STABILITY_ORDERS_OF_ACCURACY_LONG + COMMAND mpirun -n 1 ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_1D -i ${CMAKE_CURRENT_BINARY_DIR}/1D_burgers_stability_OOA.prm WORKING_DIRECTORY ${TEST_OUTPUT_DIR} ) diff --git a/tests/integration_tests_control_files/convection_diffusion_explicit_periodic/1D_conv_diff_explicit_periodic_energy.prm b/tests/integration_tests_control_files/convection_diffusion_explicit_periodic/1D_conv_diff_explicit_periodic_energy.prm new file mode 100644 index 000000000..3605eba92 --- /dev/null +++ b/tests/integration_tests_control_files/convection_diffusion_explicit_periodic/1D_conv_diff_explicit_periodic_energy.prm @@ -0,0 +1,65 @@ +# ------------------- + +set test_type = convection_diffusion_periodicity + +# Number of dimensions +set dimension = 1 + +set use_weak_form = false + +set overintegration = 0 + +set use_collocated_nodes = false + +set use_split_form = false + +set use_curvilinear_split_form = false + +set use_weight_adjusted_mass = false + +set use_periodic_bc = true + +set use_energy = true + +set flux_reconstruction = cDG + +set flux_reconstruction_aux = kDG + +set use_inverse_mass_on_the_fly = false + +set use_classical_FR = false + +# The PDE we want to solve +set pde_type = diffusion + +#set conv_num_flux = lax_friedrichs +set conv_num_flux = central_flux +set diss_num_flux = central_visc_flux +#set diss_num_flux = symm_internal_penalty + +subsection ODE solver + + set ode_output = verbose + +# set nonlinear_max_iterations = 500 + set nonlinear_max_iterations = 50000 + set nonlinear_steady_residual_tolerance = 1e-12 + + set print_iteration_modulo = 100 + # set print_iteration_modulo = 1 + + set ode_solver_type = runge_kutta + + set initial_time_step = 0.001 + + set runge_kutta_method = rk4_ex + +end + +#subsection manufactured solution convergence study +# set diffusion_coefficient = 1.0 +#end + +subsection flow_solver + set flow_case_type = convection_diffusion +end diff --git a/tests/integration_tests_control_files/convection_diffusion_explicit_periodic/2D_conv_diff_explicit_periodic_OOA.prm b/tests/integration_tests_control_files/convection_diffusion_explicit_periodic/2D_conv_diff_explicit_periodic_OOA.prm new file mode 100644 index 000000000..469a4a414 --- /dev/null +++ b/tests/integration_tests_control_files/convection_diffusion_explicit_periodic/2D_conv_diff_explicit_periodic_OOA.prm @@ -0,0 +1,63 @@ +# ------------------- + +set test_type = convection_diffusion_periodicity + +# Number of dimensions +set dimension = 2 + +set use_weak_form = false + +set overintegration = 0 + +set use_collocated_nodes = false + +set use_split_form = false + +set use_curvilinear_split_form = false + +set use_weight_adjusted_mass = false + +set use_periodic_bc = true + +set use_energy = false + +set flux_reconstruction = cPlus + +set use_inverse_mass_on_the_fly = true + +set flux_reconstruction_aux = kPlus + +set use_classical_FR = false + +# The PDE we want to solve +set pde_type = diffusion + +set conv_num_flux = lax_friedrichs +#set conv_num_flux = central_flux + +subsection ODE solver + + set ode_output = verbose + +# set nonlinear_max_iterations = 500 + set nonlinear_max_iterations = 50000 + set nonlinear_steady_residual_tolerance = 1e-12 + + set print_iteration_modulo = 100 + # set print_iteration_modulo = 1 + + set ode_solver_type = runge_kutta + + set initial_time_step = 0.001 + + set runge_kutta_method = rk4_ex + +end + +subsection manufactured solution convergence study + set use_manufactured_source_term = true +end + +subsection flow_solver + set flow_case_type = convection_diffusion +end diff --git a/tests/integration_tests_control_files/convection_diffusion_explicit_periodic/2D_conv_diff_explicit_periodic_energy.prm b/tests/integration_tests_control_files/convection_diffusion_explicit_periodic/2D_conv_diff_explicit_periodic_energy.prm new file mode 100644 index 000000000..9d5c85c94 --- /dev/null +++ b/tests/integration_tests_control_files/convection_diffusion_explicit_periodic/2D_conv_diff_explicit_periodic_energy.prm @@ -0,0 +1,64 @@ +# ------------------- + +set test_type = convection_diffusion_periodicity + +# Number of dimensions +set dimension = 2 + +set use_weak_form = false + +set overintegration = 0 + +set use_collocated_nodes = false + +set use_split_form = false + +set use_curvilinear_split_form = false + +set use_weight_adjusted_mass = false + +set use_periodic_bc = true + +set use_energy = true + +set flux_reconstruction = cDG + +set flux_reconstruction_aux = kDG + +set use_inverse_mass_on_the_fly = true + +set use_classical_FR = false + +# The PDE we want to solve +set pde_type = diffusion + +#set conv_num_flux = lax_friedrichs +set conv_num_flux = central_flux +set diss_num_flux = central_visc_flux + +subsection ODE solver + + set ode_output = verbose + +# set nonlinear_max_iterations = 500 + set nonlinear_max_iterations = 50000 + set nonlinear_steady_residual_tolerance = 1e-12 + + set print_iteration_modulo = 100 + # set print_iteration_modulo = 1 + + set ode_solver_type = runge_kutta + + set initial_time_step = 0.001 + + set runge_kutta_method = rk4_ex + +end + +#subsection manufactured solution convergence study +# set use_manufactured_source_term = true +#end + +subsection flow_solver + set flow_case_type = convection_diffusion +end diff --git a/tests/integration_tests_control_files/convection_diffusion_explicit_periodic/CMakeLists.txt b/tests/integration_tests_control_files/convection_diffusion_explicit_periodic/CMakeLists.txt new file mode 100644 index 000000000..cb3c878ce --- /dev/null +++ b/tests/integration_tests_control_files/convection_diffusion_explicit_periodic/CMakeLists.txt @@ -0,0 +1,21 @@ +set(TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +configure_file(2D_conv_diff_explicit_periodic_energy.prm 2D_conv_diff_explicit_periodic_energy.prm COPYONLY) +add_test( + NAME MPI_2D_CONVECTION_DIFFUSION_EXPLICIT_PERIODIC_ENERGY_LONG +COMMAND mpirun -n ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_2D -i ${CMAKE_CURRENT_BINARY_DIR}/2D_conv_diff_explicit_periodic_energy.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) +set(TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +configure_file(2D_conv_diff_explicit_periodic_OOA.prm 2D_conv_diff_explicit_periodic_OOA.prm COPYONLY) +add_test( + NAME MPI_2D_CONVECTION_DIFFUSION_EXPLICIT_PERIODIC_OOA_LONG +COMMAND mpirun -n ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_2D -i ${CMAKE_CURRENT_BINARY_DIR}/2D_conv_diff_explicit_periodic_OOA.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) +set(TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +configure_file(1D_conv_diff_explicit_periodic_energy.prm 1D_conv_diff_explicit_periodic_energy.prm COPYONLY) +add_test( + NAME 1D_CONVECTION_DIFFUSION_EXPLICIT_PERIODIC_ENERGY_LONG +COMMAND mpirun -n 1 ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_1D -i ${CMAKE_CURRENT_BINARY_DIR}/1D_conv_diff_explicit_periodic_energy.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) diff --git a/tests/integration_tests_control_files/diffusion_implicit/1d_diffusion_sipg_explicit_strong.prm b/tests/integration_tests_control_files/diffusion_implicit/1d_diffusion_sipg_explicit_strong.prm new file mode 100644 index 000000000..507fdc9f1 --- /dev/null +++ b/tests/integration_tests_control_files/diffusion_implicit/1d_diffusion_sipg_explicit_strong.prm @@ -0,0 +1,52 @@ +# Listing of Parameters +# --------------------- +# Number of dimensions +set dimension = 1 + +set use_weak_form = false + +# The PDE we want to solve. Choices are +# . +set pde_type = diffusion + +#set diss_num_flux = bassi_rebay_2 +set diss_num_flux = symm_internal_penalty + +subsection ODE solver + + set ode_output = verbose + + # Maximum nonlinear solver iterations + set nonlinear_max_iterations = 100000 + + # Nonlinear solver residual tolerance + set nonlinear_steady_residual_tolerance = 1e-7 + + # set initial_time_step = 0.001 + set initial_time_step = 0.01 + + # Print every print_iteration_modulo iterations of the nonlinear solver + set print_iteration_modulo = 500 + + # Explicit or implicit solverChoices are . + set ode_solver_type = runge_kutta +end + +subsection manufactured solution convergence study + set use_manufactured_source_term = true + # Last degree used for convergence study + set degree_end = 4 + + # Starting degree for convergence study + set degree_start = 3 + + # 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 = 3 + + # Number of grids in grid study + set number_of_grids = 3 +end diff --git a/tests/integration_tests_control_files/diffusion_implicit/CMakeLists.txt b/tests/integration_tests_control_files/diffusion_implicit/CMakeLists.txt index 134f25c03..fe70c00a6 100644 --- a/tests/integration_tests_control_files/diffusion_implicit/CMakeLists.txt +++ b/tests/integration_tests_control_files/diffusion_implicit/CMakeLists.txt @@ -25,6 +25,13 @@ add_test( COMMAND mpirun -n 1 ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_1D -i ${CMAKE_CURRENT_BINARY_DIR}/1d_diffusion_br2_implicit.prm WORKING_DIRECTORY ${TEST_OUTPUT_DIR} ) + +configure_file(1d_diffusion_sipg_explicit_strong.prm 1d_diffusion_sipg_explicit_strong.prm COPYONLY) +add_test( + NAME 1D_DIFFUSION_SIPG_EXPLICIT_MANUFACTURED_SOLUTION_STRONG_LONG + COMMAND mpirun -n 1 ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_1D -i ${CMAKE_CURRENT_BINARY_DIR}/1d_diffusion_sipg_explicit_strong.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) configure_file(2d_diffusion_br2_implicit.prm 2d_diffusion_br2_implicit.prm COPYONLY) add_test( NAME 2D_DIFFUSION_BR2_IMPLICIT_MANUFACTURED_SOLUTION diff --git a/tests/integration_tests_control_files/euler_entropy_conservation/CMakeLists.txt b/tests/integration_tests_control_files/euler_entropy_conservation/CMakeLists.txt new file mode 100644 index 000000000..067e3a786 --- /dev/null +++ b/tests/integration_tests_control_files/euler_entropy_conservation/CMakeLists.txt @@ -0,0 +1,16 @@ +set(TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +# ======================================= +# Entropy conservation test +# ======================================= +# ---------------------------------------- +# - Runs a short time on TGV +# - test will fail if entropy is not conserved +# ---------------------------------------- +configure_file(euler_ismail_roe_entropy_check.prm euler_ismail_roe_entropy_check.prm COPYONLY) +add_test( + NAME MPI_3D_EULER_ISMAIL_ROE_ENTROPY_CHECK + COMMAND mpirun -np ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/euler_ismail_roe_entropy_check.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) +# ---------------------------------------- diff --git a/tests/integration_tests_control_files/euler_entropy_conservation/euler_ismail_roe_entropy_check.prm b/tests/integration_tests_control_files/euler_entropy_conservation/euler_ismail_roe_entropy_check.prm new file mode 100644 index 000000000..1af1b9cb7 --- /dev/null +++ b/tests/integration_tests_control_files/euler_entropy_conservation/euler_ismail_roe_entropy_check.prm @@ -0,0 +1,54 @@ +# Listing of Parameters +# --------------------- +# Number of dimensions + +set dimension = 3 +set run_type = integration_test +set test_type = euler_ismail_roe_entropy_check +set pde_type = euler + +# DG formulation +set use_weak_form = false +set use_split_form = true +set use_collocated_nodes = true + +set flux_reconstruction = cDG +set use_inverse_mass_on_the_fly = true +# set use_collocated_nodes = true + +# Note: this was added to turn off check_same_coords() -- has no other function when dim!=1 +set use_periodic_bc = true + +# numerical fluxes +set conv_num_flux = two_point_flux +set two_point_num_flux_type = IR + +# ODE solver +subsection ODE solver + set ode_output = quiet + set ode_solver_type = runge_kutta + set output_solution_every_x_steps = 10 + set runge_kutta_method = rk4_ex +end + +# freestream Mach number +subsection euler + set mach_infinity = 0.1 +end + +subsection flow_solver + set flow_case_type = taylor_green_vortex + set poly_degree = 3 + set final_time = 0.1 + set courant_friedrich_lewy_number = 0.005 + set unsteady_data_table_filename = tgv_kinetic_energy_vs_time_table + subsection grid + set grid_left_bound = 0.0 + set grid_right_bound = 6.28318530717958623200 + set number_of_grid_elements_per_dimension = 4 + end + subsection taylor_green_vortex + set do_calculate_numerical_entropy = true + set density_initial_condition_type = isothermal + end +end diff --git a/tests/integration_tests_control_files/euler_split_inviscid_taylor_green_vortex/3D_euler_split_inviscid_taylor_green_vortex.prm b/tests/integration_tests_control_files/euler_split_inviscid_taylor_green_vortex/3D_euler_split_inviscid_taylor_green_vortex.prm index 6b394d9dc..b1fa2fe55 100644 --- a/tests/integration_tests_control_files/euler_split_inviscid_taylor_green_vortex/3D_euler_split_inviscid_taylor_green_vortex.prm +++ b/tests/integration_tests_control_files/euler_split_inviscid_taylor_green_vortex/3D_euler_split_inviscid_taylor_green_vortex.prm @@ -6,14 +6,35 @@ set test_type = euler_split_taylor_green set use_weak_form = false -set use_collocated_nodes = true +set use_collocated_nodes = false -set use_split_form = false +set overintegration = 0 + +set use_split_form = true + +set two_point_num_flux_type = Ra + +set use_curvilinear_split_form = true + +set energy_file = testing_4x4 # The PDE we want to solve set pde_type = euler -set conv_num_flux = split_form +#set conv_num_flux = two_point_flux_with_lax_friedrichs_dissipation +set conv_num_flux = two_point_flux + +set use_energy = true + +set flux_reconstruction = cPlus + +set use_inverse_mass_on_the_fly = true + +set use_weight_adjusted_mass = true + +set use_periodic_bc = true + +set use_classical_FR = false subsection ODE solver @@ -21,10 +42,24 @@ subsection ODE solver set nonlinear_max_iterations = 500 - set print_iteration_modulo = 10 + set print_iteration_modulo = 100 set ode_solver_type = runge_kutta set initial_time_step = 0.001 + set output_solution_every_x_steps = 1 + + set runge_kutta_method = rk4_ex + +end + +# freestream Mach number +subsection euler + set mach_infinity = 0.1 +end + +subsection flow_solver + set flow_case_type = taylor_green_vortex + set interpolate_initial_condition = false end diff --git a/tests/integration_tests_control_files/reduced_order/CMakeLists.txt b/tests/integration_tests_control_files/reduced_order/CMakeLists.txt index de0afe86f..f13da8975 100644 --- a/tests/integration_tests_control_files/reduced_order/CMakeLists.txt +++ b/tests/integration_tests_control_files/reduced_order/CMakeLists.txt @@ -108,4 +108,4 @@ add_test( NAME 1D_BURGERS_REWIENSKI_MANUFACTURED_SOLUTION COMMAND mpirun -np 1 ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_1D -i ${CMAKE_CURRENT_BINARY_DIR}/1d_burgers_rewienski_manufactured.prm WORKING_DIRECTORY ${TEST_OUTPUT_DIR} -) \ No newline at end of file +) diff --git a/tests/integration_tests_control_files/taylor_green_vortex_integration/CMakeLists.txt b/tests/integration_tests_control_files/taylor_green_vortex_integration/CMakeLists.txt index 64382920a..b9efb95e8 100644 --- a/tests/integration_tests_control_files/taylor_green_vortex_integration/CMakeLists.txt +++ b/tests/integration_tests_control_files/taylor_green_vortex_integration/CMakeLists.txt @@ -7,24 +7,41 @@ set(TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) # -- Reference for flow setup: # -- -- Diosady, L., and S. Murman. "Case 3.3: Taylor green vortex evolution." Case Summary for 3rd International Workshop on Higher-Order CFD Methods. 2015. # ---------------------------------------- -configure_file(viscous_taylor_green_vortex_energy_check_quick.prm viscous_taylor_green_vortex_energy_check_quick.prm COPYONLY) +configure_file(viscous_taylor_green_vortex_energy_check_weak_quick.prm viscous_taylor_green_vortex_energy_check_weak_quick.prm COPYONLY) add_test( - NAME MPI_VISCOUS_TAYLOR_GREEN_VORTEX_ENERGY_CHECK_QUICK - COMMAND mpirun -np ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/viscous_taylor_green_vortex_energy_check_quick.prm + NAME MPI_VISCOUS_TAYLOR_GREEN_VORTEX_ENERGY_CHECK_WEAK_DG_QUICK + COMMAND mpirun -np ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/viscous_taylor_green_vortex_energy_check_weak_quick.prm WORKING_DIRECTORY ${TEST_OUTPUT_DIR} ) # ---------------------------------------- -configure_file(viscous_taylor_green_vortex_energy_check_long.prm viscous_taylor_green_vortex_energy_check_long.prm COPYONLY) +configure_file(viscous_taylor_green_vortex_energy_check_strong_quick.prm viscous_taylor_green_vortex_energy_check_strong_quick.prm COPYONLY) add_test( - NAME MPI_VISCOUS_TAYLOR_GREEN_VORTEX_ENERGY_CHECK_LONG - COMMAND mpirun -np ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/viscous_taylor_green_vortex_energy_check_long.prm + NAME MPI_VISCOUS_TAYLOR_GREEN_VORTEX_ENERGY_CHECK_STRONG_DG_QUICK + COMMAND mpirun -np ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/viscous_taylor_green_vortex_energy_check_strong_quick.prm + WORKING_DIRECTORY ${TEST_OUTPUT_DIR} +) +# ---------------------------------------- +configure_file(viscous_taylor_green_vortex_energy_check_weak_long.prm viscous_taylor_green_vortex_energy_check_weak_long.prm COPYONLY) +add_test( + NAME MPI_VISCOUS_TAYLOR_GREEN_VORTEX_ENERGY_CHECK_WEAK_DG_LONG + COMMAND mpirun -np ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/viscous_taylor_green_vortex_energy_check_weak_long.prm WORKING_DIRECTORY ${TEST_OUTPUT_DIR} ) # ---------------------------------------- configure_file(viscous_taylor_green_vortex_restart_check.prm viscous_taylor_green_vortex_restart_check.prm COPYONLY) add_test( NAME MPI_VISCOUS_TAYLOR_GREEN_VORTEX_RESTART_CHECK - COMMAND mpirun -np ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/viscous_taylor_green_vortex_restart_check.prm + COMMAND bash -c + "numprocs=1 ; + numprocstimestwo=$(( $numprocs * 2 )) ; + while [[ $numprocstimestwo -le $MPIMAX ]]; + do + numprocs=$numprocstimestwo; + numprocstimestwo=$(( $numprocs * 2 )); + done ; + mpirun -np $numprocs ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/viscous_taylor_green_vortex_restart_check.prm; + return_val=$? ; + if [ $return_val -ne 0 ]; then exit 1; else exit 0; fi" WORKING_DIRECTORY ${TEST_OUTPUT_DIR} ) # ---------------------------------------- @@ -35,7 +52,14 @@ add_test( COMMAND bash -c "./viscous_taylor_green_vortex_restart_from_parameter_file_check.sh ${EXECUTABLE_OUTPUT_PATH} return_val1=$? ; - mpirun -np ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/restart-00004.prm; + numprocs=1 ; + numprocstimestwo=$(( $numprocs * 2 )) ; + while [[ $numprocstimestwo -le $MPIMAX ]]; + do + numprocs=$numprocstimestwo; + numprocstimestwo=$(( $numprocs * 2 )); + done ; + mpirun -np $numprocs ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/restart-00004.prm; return_val2=$? ; if [ $return_val1 -ne 0 ] || [ $return_val2 -ne 0 ]; then exit 1; else exit 0; fi" WORKING_DIRECTORY ${TEST_OUTPUT_DIR} @@ -61,4 +85,4 @@ add_test( COMMAND mpirun -np ${MPIMAX} ${EXECUTABLE_OUTPUT_PATH}/PHiLiP_3D -i ${CMAKE_CURRENT_BINARY_DIR}/viscous_TGV_LES_vreman_model_energy_check_quick.prm WORKING_DIRECTORY ${TEST_OUTPUT_DIR} ) -# ---------------------------------------- \ No newline at end of file +# ---------------------------------------- diff --git a/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_strong_quick.prm b/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_strong_quick.prm new file mode 100644 index 000000000..eaf3d710e --- /dev/null +++ b/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_strong_quick.prm @@ -0,0 +1,65 @@ +# Listing of Parameters +# --------------------- +# Number of dimensions + +set dimension = 3 +set test_type = taylor_green_vortex_energy_check +set pde_type = navier_stokes + +# DG formulation +set use_weak_form = false +# set use_collocated_nodes = true + +# Note: this was added to turn off check_same_coords() -- has no other function when dim!=1 +set use_periodic_bc = true + +# numerical fluxes +set conv_num_flux = roe +set diss_num_flux = symm_internal_penalty + +# ODE solver +subsection ODE solver + set ode_output = quiet + set ode_solver_type = runge_kutta + set runge_kutta_method = ssprk3_ex +end + +# Reference for freestream values specified below: +# Diosady, L., and S. Murman. "Case 3.3: Taylor green vortex evolution." Case Summary for 3rd International Workshop on Higher-Order CFD Methods. 2015. + +# freestream Mach number +subsection euler + set mach_infinity = 0.1 +end + +# freestream Reynolds number and Prandtl number +subsection navier_stokes + set prandtl_number = 0.71 + set reynolds_number_inf = 1600.0 +end + +# polynomial order and number of cells per direction (i.e. grid_size) +subsection grid refinement study + set poly_degree = 2 + set grid_size = 4 + set grid_left = 0.0 + set grid_right = 6.2831853072 +end + + +subsection flow_solver + set flow_case_type = taylor_green_vortex + set poly_degree = 2 + set final_time = 1.2566370614400000e-02 + set courant_friedrich_lewy_number = 0.003 + set unsteady_data_table_filename = tgv_kinetic_energy_vs_time_table_for_energy_check_strong + subsection grid + set grid_left_bound = 0.0 + set grid_right_bound = 6.28318530717958623200 + set number_of_grid_elements_per_dimension = 4 + end + subsection taylor_green_vortex + set expected_kinetic_energy_at_final_time = 1.2073987154899971e-01 + set expected_theoretical_dissipation_rate_at_final_time = 4.5422272551211095e-04 + end +end diff --git a/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_long.prm b/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_weak_long.prm similarity index 100% rename from tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_long.prm rename to tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_weak_long.prm diff --git a/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_quick.prm b/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_weak_quick.prm similarity index 93% rename from tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_quick.prm rename to tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_weak_quick.prm index 09f00a08e..e994e6d65 100644 --- a/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_quick.prm +++ b/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_energy_check_weak_quick.prm @@ -43,14 +43,14 @@ subsection flow_solver set poly_degree = 2 set final_time = 1.2566370614400000e-02 set courant_friedrich_lewy_number = 0.003 - set unsteady_data_table_filename = tgv_kinetic_energy_vs_time_table_for_energy_check + set unsteady_data_table_filename = tgv_kinetic_energy_vs_time_table_for_energy_check_weak subsection grid set grid_left_bound = 0.0 set grid_right_bound = 6.28318530717958623200 set number_of_grid_elements_per_dimension = 4 end subsection taylor_green_vortex - set expected_kinetic_energy_at_final_time = 1.2073987162682624e-01 - set expected_theoretical_dissipation_rate_at_final_time = 4.5422264559811485e-04 + set expected_kinetic_energy_at_final_time = 1.2073987162646824e-01 + set expected_theoretical_dissipation_rate_at_final_time = 4.5422264559968770e-04 end end diff --git a/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_restart_check.prm b/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_restart_check.prm index cf2d4ef24..9a0a748d3 100644 --- a/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_restart_check.prm +++ b/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_restart_check.prm @@ -51,7 +51,7 @@ subsection flow_solver set number_of_grid_elements_per_dimension = 4 end subsection taylor_green_vortex - set expected_kinetic_energy_at_final_time = 1.2073987162682624e-01 - set expected_theoretical_dissipation_rate_at_final_time = 4.5422264559811485e-04 + set expected_kinetic_energy_at_final_time = 1.2073987162646824e-01 + set expected_theoretical_dissipation_rate_at_final_time = 4.5422264559968770e-04 end end diff --git a/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_restart_from_parameter_file_check.sh b/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_restart_from_parameter_file_check.sh index d47bc1d75..1ad29bb30 100755 --- a/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_restart_from_parameter_file_check.sh +++ b/tests/integration_tests_control_files/taylor_green_vortex_integration/viscous_taylor_green_vortex_restart_from_parameter_file_check.sh @@ -1,7 +1,6 @@ #!/bin/bash # Assign the filename -# filename="/home/julien/Codes/2022-06-15/PHiLiP/build_release/tests/integration_tests_control_files/taylor_green_vortex_integration/restart-00004.prm" filename="restart-00004.prm" if [[ ! -f "${filename}" ]]; then diff --git a/tests/integration_tests_control_files/time_refinement_study/time_refinement_study_burgers_explicit.prm b/tests/integration_tests_control_files/time_refinement_study/time_refinement_study_burgers_explicit.prm index 9f9fe6e05..7eaf9d990 100644 --- a/tests/integration_tests_control_files/time_refinement_study/time_refinement_study_burgers_explicit.prm +++ b/tests/integration_tests_control_files/time_refinement_study/time_refinement_study_burgers_explicit.prm @@ -13,7 +13,7 @@ set use_periodic_bc = true set use_weak_form = false set use_collocated_nodes = true set use_split_form = true -set conv_num_flux = split_form #change to entropy_conserving_flux after merging ESFR +set conv_num_flux = two_point_flux # ODE solver subsection ODE solver diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 77ba7544b..4a579d3d8 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -9,3 +9,5 @@ add_subdirectory(msh_output) add_subdirectory(navier_stokes_unit_test) add_subdirectory(optimization) add_subdirectory(operator_tests) +add_subdirectory(flow_variable_tests) +add_subdirectory(ode_solver_unit_test) diff --git a/tests/unit_tests/euler_unit_test/euler_manufactured_solution_source.cpp b/tests/unit_tests/euler_unit_test/euler_manufactured_solution_source.cpp index fffa7b7b4..d3918f0bb 100644 --- a/tests/unit_tests/euler_unit_test/euler_manufactured_solution_source.cpp +++ b/tests/unit_tests/euler_unit_test/euler_manufactured_solution_source.cpp @@ -49,7 +49,8 @@ int main (int /*argc*/, char * /*argv*/[]) for (unsigned int v=0; v < dealii::GeometryInfo::vertices_per_cell; ++v) { const dealii::Point vertex = cell->vertex(v); - std::array source_term = euler_physics.source_term(vertex, soln_plus); + constexpr double dummy_time = 0; + std::array source_term = euler_physics.source_term(vertex, soln_plus, dummy_time); std::array divergence_finite_differences; divergence_finite_differences.fill(0.0); diff --git a/tests/unit_tests/euler_unit_test/freestream_preservation.cpp b/tests/unit_tests/euler_unit_test/freestream_preservation.cpp index 8c15402af..f03fa443f 100644 --- a/tests/unit_tests/euler_unit_test/freestream_preservation.cpp +++ b/tests/unit_tests/euler_unit_test/freestream_preservation.cpp @@ -13,7 +13,7 @@ #include "mesh/grids/curved_periodic_grid.hpp" #include "mesh/grids/wavy_periodic_grid.hpp" -#include "physics/initial_conditions/initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" #include "physics/euler.h" #include "dg/dg_factory.hpp" #include "ode_solver/ode_solver_factory.h" diff --git a/tests/unit_tests/flow_variable_tests/CMakeLists.txt b/tests/unit_tests/flow_variable_tests/CMakeLists.txt new file mode 100644 index 000000000..9d907a2c4 --- /dev/null +++ b/tests/unit_tests/flow_variable_tests/CMakeLists.txt @@ -0,0 +1,81 @@ +set(TEST_SRC + auxiliary_variable_test.cpp) + +foreach(dim RANGE 1 3) + + # Output executable + string(CONCAT TEST_TARGET ${dim}D_AUXILIARY_SOLUTION_TEST) + message("Adding executable " ${TEST_TARGET} " with files " ${TEST_SRC} "\n") + add_executable(${TEST_TARGET} ${TEST_SRC}) + # Replace occurences of PHILIP_DIM with 1, 2, or 3 in the code + target_compile_definitions(${TEST_TARGET} PRIVATE PHILIP_DIM=${dim}) + + # Compile this executable when 'make unit_tests' + add_dependencies(unit_tests ${TEST_TARGET}) + add_dependencies(${dim}D ${TEST_TARGET}) + + # Library dependency + target_link_libraries(${TEST_TARGET} ParametersLibrary) + string(CONCAT OperatorsLib Operator_Lib_${dim}D) + target_link_libraries(${TEST_TARGET} ${OperatorsLib}) + target_link_libraries(${TEST_TARGET} DiscontinuousGalerkin_${dim}D) + # Setup target with deal.II + if (NOT DOC_ONLY) + DEAL_II_SETUP_TARGET(${TEST_TARGET}) + endif() + + if (dim EQUAL 1) + set(NMPI 1) + else() + set(NMPI ${MPIMAX}) + endif() + add_test( + NAME ${TEST_TARGET} + COMMAND mpirun -n ${NMPI} ${EXECUTABLE_OUTPUT_PATH}/${TEST_TARGET} + WORKING_DIRECTORY ${TEST_OUTPUT_DIR}) + + unset(TEST_TARGET) + unset(OperatorsLib) + +endforeach() + +set(TEST_SRC + auxiliary_equations_int_by_parts.cpp) + +foreach(dim RANGE 1 3) + + # Output executable + string(CONCAT TEST_TARGET ${dim}D_AUXILIARY_RHS_TEST) + message("Adding executable " ${TEST_TARGET} " with files " ${TEST_SRC} "\n") + add_executable(${TEST_TARGET} ${TEST_SRC}) + # Replace occurences of PHILIP_DIM with 1, 2, or 3 in the code + target_compile_definitions(${TEST_TARGET} PRIVATE PHILIP_DIM=${dim}) + + # Compile this executable when 'make unit_tests' + add_dependencies(unit_tests ${TEST_TARGET}) + add_dependencies(${dim}D ${TEST_TARGET}) + + # Library dependency + target_link_libraries(${TEST_TARGET} ParametersLibrary) + string(CONCAT OperatorsLib Operator_Lib_${dim}D) + target_link_libraries(${TEST_TARGET} ${OperatorsLib}) + target_link_libraries(${TEST_TARGET} DiscontinuousGalerkin_${dim}D) + # Setup target with deal.II + if (NOT DOC_ONLY) + DEAL_II_SETUP_TARGET(${TEST_TARGET}) + endif() + + if (dim EQUAL 1) + set(NMPI 1) + else() + set(NMPI ${MPIMAX}) + endif() + add_test( + NAME ${TEST_TARGET} + COMMAND mpirun -n ${NMPI} ${EXECUTABLE_OUTPUT_PATH}/${TEST_TARGET} + WORKING_DIRECTORY ${TEST_OUTPUT_DIR}) + + unset(TEST_TARGET) + unset(OperatorsLib) + +endforeach() diff --git a/tests/unit_tests/flow_variable_tests/auxiliary_equations_int_by_parts.cpp b/tests/unit_tests/flow_variable_tests/auxiliary_equations_int_by_parts.cpp new file mode 100644 index 000000000..acba9cd99 --- /dev/null +++ b/tests/unit_tests/flow_variable_tests/auxiliary_equations_int_by_parts.cpp @@ -0,0 +1,473 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "dg/strong_dg.hpp" +#include "operators/operators.h" + +const double TOLERANCE = 1E-6; +using namespace std; +//namespace PHiLiP { + +template +void assemble_weak_auxiliary_volume( + std::shared_ptr < PHiLiP::DGStrong > &dg, + const std::vector ¤t_dofs_indices, + const unsigned int poly_degree, + PHiLiP::OPERATOR::basis_functions &soln_basis, + PHiLiP::OPERATOR::metric_operators &metric_oper, + std::vector> &local_auxiliary_RHS) +{ + const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size(); + const unsigned int n_dofs_cell = dg->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_shape_fns = n_dofs_cell / nstate; + const std::vector &quad_weights = dg->volume_quadrature_collection[poly_degree].get_weights(); + + //Fetch the modal soln coefficients and the modal auxiliary soln coefficients + //We immediately separate them by state as to be able to use sum-factorization + //in the interpolation operator. If we left it by n_dofs_cell, then the matrix-vector + //mult would sum the states at the quadrature point. + //That is why the basis functions are of derived class state rather than base. + std::array,nstate> soln_coeff; + for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) { + const unsigned int istate = dg->fe_collection[poly_degree].system_to_component_index(idof).first; + const unsigned int ishape = dg->fe_collection[poly_degree].system_to_component_index(idof).second; + if(ishape == 0) + soln_coeff[istate].resize(n_shape_fns); + + soln_coeff[istate][ishape] = dg->solution(current_dofs_indices[idof]); + } + + //Interpolate coefficients to quad points and evaluate rhs + for(int istate=0; istate soln_at_q(n_shape_fns); + soln_basis.matrix_vector_mult_1D(soln_coeff[istate], soln_at_q, + soln_basis.oneD_vol_operator); + + for(int idim=0; idim rhs(n_shape_fns); + for(int jdim=0; jdim metric_cofactor_times_quad_weights(n_quad_pts); + //For Reference transofrmation + for(unsigned int iquad=0; iquad +void assemble_face_term_auxiliary_weak( + std::shared_ptr < PHiLiP::DGStrong > &dg, + const unsigned int iface, const unsigned int neighbor_iface, + const dealii::types::global_dof_index /*current_cell_index*/, + const dealii::types::global_dof_index /*neighbor_cell_index*/, + const unsigned int poly_degree_int, + const unsigned int /*poly_degree_ext*/, + const unsigned int n_dofs_int, + const unsigned int n_dofs_ext, + const unsigned int n_face_quad_pts, + const std::vector &dof_indices_int, + const std::vector &dof_indices_ext, + PHiLiP::OPERATOR::basis_functions &soln_basis_int, + PHiLiP::OPERATOR::basis_functions &soln_basis_ext, + PHiLiP::OPERATOR::metric_operators &metric_oper_int, + std::vector> &local_auxiliary_RHS_int, + std::vector> &local_auxiliary_RHS_ext) +{ + + const unsigned int n_shape_fns_int = n_dofs_int / nstate; + const unsigned int n_shape_fns_ext = n_dofs_ext / nstate; + //Extract interior modal coefficients of solution + std::array,nstate> soln_coeff_int; + std::array,nstate> soln_coeff_ext; + for (unsigned int idof = 0; idof < n_dofs_int; ++idof) { + const unsigned int istate = dg->fe_collection[poly_degree_int].system_to_component_index(idof).first; + const unsigned int ishape = dg->fe_collection[poly_degree_int].system_to_component_index(idof).second; + //allocate + if(ishape == 0) + soln_coeff_int[istate].resize(n_shape_fns_int); + + //solve + soln_coeff_int[istate][ishape] = dg->solution(dof_indices_int[idof]); + //allocate + if(ishape == 0) + soln_coeff_ext[istate].resize(n_shape_fns_ext); + + //solve + soln_coeff_ext[istate][ishape] = dg->solution(dof_indices_ext[idof]); + } + //Interpolate soln modal coefficients to the facet + std::array,nstate> soln_at_surf_q_int; + std::array,nstate> soln_at_surf_q_ext; + for(int istate=0; istate unit_ref_normal_int = dealii::GeometryInfo::unit_normal_vector[iface]; + std::array>,nstate> surf_num_flux_int_dot_normal; + std::array>,nstate> surf_num_flux_ext_dot_normal; + for (unsigned int iquad=0; iquad metric_cofactor_surf; + for(int idim=0; idim unit_phys_normal_int; + metric_oper_int.transform_reference_to_physical(unit_ref_normal_int, + metric_cofactor_surf, + unit_phys_normal_int); + const double face_Jac_norm_scaled = unit_phys_normal_int.norm(); + unit_phys_normal_int /= face_Jac_norm_scaled;//normalize it. + + std::array diss_soln_num_flux; + std::array soln_state_int; + std::array soln_state_ext; + for(int istate=0; istate &surf_quad_weights = dg->face_quadrature_collection[poly_degree_int].get_weights(); + for(int istate=0; istate rhs_int(n_shape_fns_int); + + soln_basis_int.inner_product_surface_1D(iface, + surf_num_flux_int_dot_normal[istate][idim], + surf_quad_weights, rhs_int, + soln_basis_int.oneD_surf_operator, + soln_basis_int.oneD_vol_operator, + true, 1.0);//it's added since auxiliary is EQUAL to the gradient of the soln + + for(unsigned int ishape=0; ishape rhs_ext(n_shape_fns_ext); + + soln_basis_ext.inner_product_surface_1D(neighbor_iface, + surf_num_flux_ext_dot_normal[istate][idim], + surf_quad_weights, rhs_ext, + soln_basis_ext.oneD_surf_operator, + soln_basis_ext.oneD_vol_operator, + true, 1.0);//it's added since auxiliary is EQUAL to the gradient of the soln + + for(unsigned int ishape=0; ishape::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + + all_parameters_new.use_curvilinear_split_form=true; + + double left = 0.0; + double right = 1.0; + const unsigned int igrid_start = 2; + const unsigned int n_grids = 3; + const unsigned int final_poly_degree = 4; + for(unsigned int poly_degree = 3; poly_degree does not work for 1D + using Triangulation = dealii::Triangulation; + std::shared_ptr grid = std::make_shared( + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#else + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#endif +//straight + dealii::GridGenerator::hyper_cube(*grid, left, right, true); +#if PHILIP_DIM==1 + std::vector::cell_iterator> > matched_pairs; + dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); + grid->add_periodicity(matched_pairs); +#else + std::vector::cell_iterator> > matched_pairs; + dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); + if(dim >= 2) + dealii::GridTools::collect_periodic_faces(*grid,2,3,1,matched_pairs); + if(dim>=3) + dealii::GridTools::collect_periodic_faces(*grid,4,5,2,matched_pairs); + grid->add_periodicity(matched_pairs); +#endif + grid->refine_global(igrid); + pcout<<" made grid for Index"< > dg = std::make_shared< PHiLiP::DGStrong >(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (false,false,false); + if(!all_parameters_new.use_inverse_mass_on_the_fly){ + dg->evaluate_mass_matrices(true); + } + + //set solution as some random number between [1e-8,30] at each dof + //loop over cells as to write only to local solution indices + const unsigned int n_dofs = dg->dof_handler.get_fe_collection().max_dofs_per_cell(); + std::vector current_dofs_indices(n_dofs); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell) { + if (!current_cell->is_locally_owned()) continue; + current_cell->get_dof_indices (current_dofs_indices); + for(unsigned int i=0; isolution[current_dofs_indices[i]] = 1e-8 + static_cast (rand()) / ( static_cast (RAND_MAX/(30-1e-8))); + } + } + + const unsigned int n_dofs_cell = dg->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size(); + + const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + const unsigned int n_grid_nodes = n_metric_dofs / dim; + auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); + + //build 1D reference operators + PHiLiP::OPERATOR::mapping_shape_functions mapping_basis(dg->nstate, poly_degree, 1); + mapping_basis.build_1D_shape_functions_at_grid_nodes(dg->high_order_grid->oneD_fe_system, dg->high_order_grid->oneD_grid_nodes); + mapping_basis.build_1D_shape_functions_at_flux_nodes(dg->high_order_grid->oneD_fe_system, dg->oneD_quadrature_collection[poly_degree], dg->oneD_face_quadrature); + + PHiLiP::OPERATOR::basis_functions basis(dg->nstate, dg->max_degree, dg->max_grid_degree); + basis.build_1D_volume_operator(dg->oneD_fe_collection_1state[dg->max_degree], dg->oneD_quadrature_collection[dg->max_degree]); + basis.build_1D_gradient_operator(dg->oneD_fe_collection_1state[dg->max_degree], dg->oneD_quadrature_collection[dg->max_degree]); + basis.build_1D_surface_operator(dg->oneD_fe_collection_1state[dg->max_degree], dg->oneD_face_quadrature); + + PHiLiP::OPERATOR::basis_functions flux_basis(dg->nstate, dg->max_degree, dg->max_grid_degree); + flux_basis.build_1D_volume_operator(dg->oneD_fe_collection_flux[dg->max_degree], dg->oneD_quadrature_collection[dg->max_degree]); + flux_basis.build_1D_gradient_operator(dg->oneD_fe_collection_flux[dg->max_degree], dg->oneD_quadrature_collection[dg->max_degree]); + flux_basis.build_1D_surface_operator(dg->oneD_fe_collection_flux[dg->max_degree], dg->oneD_face_quadrature); + + //loop over cells and compare rhs strong versus rhs weak + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + //get mapping support points + std::vector current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + for(int idim=0; idim vol_GLL(grid_degree +1); + for (unsigned int igrid_node = 0; igrid_node< n_metric_dofs/dim; ++igrid_node) { + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + mapping_support_points[istate][igrid_node] += val * fe_metric.shape_value_component(idof,vol_GLL.point(igrid_node),istate); + } + } + + //build volume metric operators + PHiLiP::OPERATOR::metric_operators metric_oper(dg->nstate,poly_degree,1,true); + metric_oper.build_volume_metric_operators(n_quad_pts, n_grid_nodes, + mapping_support_points, + mapping_basis); + + std::vector current_dofs_indices; + std::vector neighbor_dofs_indices; + current_dofs_indices.resize(n_dofs_cell); + current_cell->get_dof_indices (current_dofs_indices); + const dealii::types::global_dof_index current_cell_index = current_cell->active_cell_index(); + + std::vector> rhs_strong(n_dofs_cell); + std::vector> rhs_weak(n_dofs_cell); + + //assemble DG strong rhs auxiliary + dg->assemble_volume_term_auxiliary_equation ( + current_dofs_indices, + poly_degree, + basis, + flux_basis, + metric_oper, + rhs_strong); + //assemble weak DG auxiliary eq + assemble_weak_auxiliary_volume( + dg, + current_dofs_indices, + poly_degree, + basis, + metric_oper, + rhs_weak); + + //loop over faces + for (unsigned int iface=0; iface < dealii::GeometryInfo::faces_per_cell; ++iface) { + const auto neighbor_cell = current_cell->neighbor_or_periodic_neighbor(iface); + std::vector> rhs_ext_strong(n_dofs_cell); + std::vector> rhs_ext_weak(n_dofs_cell); + + //get facet metric operators + metric_oper.build_facet_metric_operators( + iface, + dg->face_quadrature_collection[poly_degree].size(), + n_grid_nodes, + mapping_support_points, + mapping_basis, + false); + + const unsigned int neighbor_iface = current_cell->periodic_neighbor_of_periodic_neighbor(iface); + neighbor_dofs_indices.resize(n_dofs_cell); + neighbor_cell->get_dof_indices (neighbor_dofs_indices); + const dealii::types::global_dof_index neighbor_cell_index = neighbor_cell->active_cell_index(); + + //evaluate facet auxiliary RHS + dg->assemble_face_term_auxiliary_equation ( + iface, neighbor_iface, + current_cell_index, neighbor_cell_index, + poly_degree, poly_degree, + current_dofs_indices, neighbor_dofs_indices, + basis, basis, + metric_oper, + rhs_strong, rhs_ext_strong); + + const unsigned int n_face_quad_pts = dg->face_quadrature_collection[poly_degree].size();//assume interior cell does the work + //assemble facet auxiliary WEAK DG RHS + //note that for the ext rhs, this function will return the DG strong + //facet rhs in rhs_ext_weak to directly compare to the above's neighbour + assemble_face_term_auxiliary_weak ( + dg, + iface, neighbor_iface, + current_cell_index, neighbor_cell_index, + poly_degree, poly_degree, + n_dofs_cell, n_dofs_cell, + n_face_quad_pts, + current_dofs_indices, neighbor_dofs_indices, + basis, basis, + metric_oper, + rhs_weak, rhs_ext_weak); + + for(unsigned int idof=0; idof1e-13){ + pcout<<"The strong external cell face RHS is not correct."<1e-13){ + pcout<<"The strong and weak RHS are not equivalent interior cell."< +#include +#include +#include +#include +#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "dg/dg.h" +#include +#include +#include "dg/dg_factory.hpp" +#include "operators/operators.h" + +const double TOLERANCE = 1E-6; +using namespace std; +//namespace PHiLiP { + +int main (int argc, char * argv[]) +{ + + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + + all_parameters_new.use_curvilinear_split_form=true; + const int dim_check = 0; + const int nstate = 1; + + double left = 0.0; + double right = 1.0; + dealii::ConvergenceTable convergence_table; + const unsigned int igrid_start = 2; + const unsigned int n_grids = 7; + std::array grid_size; + std::array soln_error; + std::array soln_error_inf; + unsigned int exit_grid=0; + const unsigned int final_poly_degree = (dim==3) ? 5 : 6; + for(unsigned int poly_degree = 3; poly_degree does not work for 1D + using Triangulation = dealii::Triangulation; + std::shared_ptr grid = std::make_shared( + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#else + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#endif + // straight + dealii::GridGenerator::hyper_cube(*grid, left, right, true); +#if PHILIP_DIM==1 + std::vector::cell_iterator> > matched_pairs; + dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); + grid->add_periodicity(matched_pairs); +#else + std::vector::cell_iterator> > matched_pairs; + dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); + if(dim >= 2) dealii::GridTools::collect_periodic_faces(*grid,2,3,1,matched_pairs); + if(dim >= 3) dealii::GridTools::collect_periodic_faces(*grid,4,5,2,matched_pairs); + grid->add_periodicity(matched_pairs); +#endif + grid->refine_global(igrid); + pcout<<" made grid for Index"< > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + pcout<<"going in allocate"<allocate_system (false,false,false); + if(!all_parameters_new.use_inverse_mass_on_the_fly){ + dg->evaluate_mass_matrices(true); + } + + // Interpolate IC + + const double pi = atan(1)*4.0; + const unsigned int max_dofs_per_cell = dg->dof_handler.get_fe_collection().max_dofs_per_cell(); + std::vector current_dofs_indices(max_dofs_per_cell); + const unsigned int n_dofs_cell = dg->fe_collection[poly_degree].dofs_per_cell; + const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size(); + const unsigned int n_shape_fns = n_dofs_cell / dg->nstate; + + const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + const unsigned int n_grid_nodes = n_metric_dofs / dim; + auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); + + PHiLiP::OPERATOR::mapping_shape_functions mapping_basis(dg->nstate, poly_degree, 1); + mapping_basis.build_1D_shape_functions_at_grid_nodes(dg->high_order_grid->oneD_fe_system, dg->high_order_grid->oneD_grid_nodes); + mapping_basis.build_1D_shape_functions_at_flux_nodes(dg->high_order_grid->oneD_fe_system, dg->oneD_quadrature_collection[poly_degree], dg->oneD_face_quadrature); + + OPERATOR::vol_projection_operator vol_projection(dg->nstate, dg->max_degree, dg->max_grid_degree); + vol_projection.build_1D_volume_operator(dg->oneD_fe_collection[dg->max_degree], dg->oneD_quadrature_collection[dg->max_degree]); + + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + std::vector current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + for(int idim=0; idim vol_GLL(grid_degree +1); + for (unsigned int igrid_node = 0; igrid_node< n_metric_dofs/dim; ++igrid_node) { + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + mapping_support_points[istate][igrid_node] += val * fe_metric.shape_value_component(idof,vol_GLL.point(igrid_node),istate); + } + } + + PHiLiP::OPERATOR::metric_operators metric_oper(dg->nstate,poly_degree,1,true); + metric_oper.build_volume_metric_operators(n_quad_pts, n_grid_nodes, + mapping_support_points, + mapping_basis); + + //interpolate solution + current_dofs_indices.resize(n_dofs_cell); + current_cell->get_dof_indices (current_dofs_indices); + std::vector soln(n_quad_pts); + std::vector exact(n_quad_pts); + for(int istate=0; istate sol(n_shape_fns); + vol_projection.matrix_vector_mult_1D(exact, sol, + vol_projection.oneD_vol_operator); + for(unsigned int ishape=0; ishapesolution[current_dofs_indices[ishape+istate*n_shape_fns]] = sol[ishape]; + } + } + } + //end interpolated solution + } + dg->solution.update_ghost_values(); + + pcout<<"assembling aux residual"<assemble_auxiliary_residual(); + + + //TEST ERROR OOA + + pcout<<"OOA here"< quad_extra(poly_degree+1+overintegrate); + dealii::FEValues fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], quad_extra, + dealii::update_values | dealii::update_JxW_values | + dealii::update_jacobians | + dealii::update_quadrature_points | dealii::update_inverse_jacobians); + const unsigned int n_quad_pts_extra = fe_values_extra.n_quadrature_points; + std::vector dofs_indices (fe_values_extra.dofs_per_cell); + dealii::Vector soln_at_q(n_quad_pts_extra); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell) { + if (!current_cell->is_locally_owned()) continue; + + fe_values_extra.reinit(current_cell); + dofs_indices.resize(fe_values_extra.dofs_per_cell); + current_cell->get_dof_indices (dofs_indices); + + for (unsigned int iquad=0; iquadauxiliary_solution[dim_check][dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, 0); + } + + const dealii::Point qpoint = (fe_values_extra.quadrature_point(iquad)); + double uexact_x=1.0; + for(int idim=0; idim linf_error){ + linf_error = inf_temp; + } + } + + } + pcout<<"got OOA here"<n_global_active_cells(); + const double l2error_mpi_sum = std::sqrt(dealii::Utilities::MPI::sum(l2error, MPI_COMM_WORLD)); + const double linferror_mpi= (dealii::Utilities::MPI::max(linf_error, MPI_COMM_WORLD)); + // Convergence table + const unsigned int n_dofs = dg->dof_handler.n_dofs(); + const double dx = 1.0/pow(n_dofs,(1.0/dim)); + grid_size[igrid] = dx; + soln_error[igrid] = l2error_mpi_sum; + soln_error_inf[igrid] = linferror_mpi; + + convergence_table.add_value("p", poly_degree); + convergence_table.add_value("cells", n_global_active_cells); + convergence_table.add_value("DoFs", n_dofs); + convergence_table.add_value("dx", dx); + convergence_table.add_value("soln_L2_error", l2error_mpi_sum); + convergence_table.add_value("soln_Linf_error", linferror_mpi); + + pcout << " Grid size h: " << dx + << " L2-soln_error: " << l2error_mpi_sum + << " Linf-soln_error: " << linferror_mpi + << std::endl; + + + if (igrid > igrid_start) { + const double slope_soln_err = log(soln_error[igrid]/soln_error[igrid-1]) + / log(grid_size[igrid]/grid_size[igrid-1]); + const double slope_soln_err_inf = log(soln_error_inf[igrid]/soln_error_inf[igrid-1]) + / log(grid_size[igrid]/grid_size[igrid-1]); + pcout << "From grid " << igrid-1 + << " to grid " << igrid + << " dimension: " << dim + << " polynomial degree p: " << poly_degree + << std::endl + << " solution_error1 " << soln_error[igrid-1] + << " solution_error2 " << soln_error[igrid] + << " slope " << slope_soln_err + << " solution_error1_inf " << soln_error_inf[igrid-1] + << " solution_error2_inf " << soln_error_inf[igrid] + << " slope " << slope_soln_err_inf + << std::endl; + + //if hit correct convergence rates skip to next poly + if(std::abs(slope_soln_err_inf-poly_degree)<0.1 && poly_degree % 2 == 1){ + exit_grid = igrid; + break; + } + //if(std::abs(slope_soln_err-(poly_degree+1))<0.1 && poly_degree % 2 == 0){ + if(std::abs(slope_soln_err_inf-(poly_degree))<0.1 && poly_degree % 2 == 0){ + exit_grid = igrid; + break; + } + } + }//end grid refinement loop + + //const int igrid = n_grids-1; + const unsigned int igrid = exit_grid; + //const double slope_soln_err = log(soln_error[igrid]/soln_error[igrid-1]) + // / log(grid_size[igrid]/grid_size[igrid-1]); + const double slope_soln_err = log(soln_error_inf[igrid]/soln_error_inf[igrid-1]) + / log(grid_size[igrid]/grid_size[igrid-1]); + if(std::abs(slope_soln_err-poly_degree)>0.1 && poly_degree % 2 == 1){ + pcout<<" wrong order for poly "<0.1 && poly_degree % 2 == 0){ + if(std::abs(slope_soln_err-(poly_degree))>0.1 && poly_degree % 2 == 0){ + //if(std::abs(slope_soln_err-(poly_degree))>0.05 && poly_degree % 2 == 0){ + pcout<<" wrong order for poly "<::vertices_per_cell; ++v) { const dealii::Point vertex = cell->vertex(v); - std::array source_term = navier_stokes_physics.source_term(vertex, soln_plus); + constexpr double dummy_time = 0; + std::array source_term = navier_stokes_physics.source_term(vertex, soln_plus, dummy_time); std::array divergence_finite_differences; divergence_finite_differences.fill(0.0); diff --git a/tests/unit_tests/numerical_flux/numerical_flux_conservation.cpp b/tests/unit_tests/numerical_flux/numerical_flux_conservation.cpp index b92124716..b95369b03 100644 --- a/tests/unit_tests/numerical_flux/numerical_flux_conservation.cpp +++ b/tests/unit_tests/numerical_flux/numerical_flux_conservation.cpp @@ -329,7 +329,12 @@ int main (int argc, char * argv[]) std::vector conv_type { ConvType::lax_friedrichs, ConvType::roe, - ConvType::l2roe + ConvType::l2roe, + ConvType::central_flux, + ConvType::two_point_flux, + ConvType::two_point_flux_with_lax_friedrichs_dissipation, + ConvType::two_point_flux_with_roe_dissipation, + ConvType::two_point_flux_with_l2roe_dissipation }; std::vector diss_type { DissType::symm_internal_penalty @@ -366,13 +371,21 @@ int main (int argc, char * argv[]) for (auto conv = conv_type.begin(); conv != conv_type.end() && success == 0; conv++) { // Roe-type fluxes are defined only for the Euler and Navier-Stokes equations - if(((*conv == ConvType::roe) || (*conv == ConvType::l2roe)) && ((*pde!=PDEType::euler) && (*pde!=PDEType::navier_stokes) && (*pde!=PDEType::physics_model))) continue; + if(((*conv == ConvType::roe) || (*conv == ConvType::l2roe) || + (*conv == ConvType::two_point_flux_with_roe_dissipation) || + (*conv == ConvType::two_point_flux_with_l2roe_dissipation)) + && ((*pde!=PDEType::euler) && (*pde!=PDEType::navier_stokes) && (*pde!=PDEType::physics_model))) continue; all_parameters.conv_num_flux_type = *conv; std::string conv_string; - if(*conv==ConvType::lax_friedrichs) conv_string = "lax_friedrichs"; - if(*conv==ConvType::roe) conv_string = "roe"; - if(*conv==ConvType::l2roe) conv_string = "l2roe"; + if(*conv==ConvType::lax_friedrichs) conv_string = "lax_friedrichs"; + if(*conv==ConvType::roe) conv_string = "roe"; + if(*conv==ConvType::l2roe) conv_string = "l2roe"; + if(*conv==ConvType::central_flux) conv_string = "central_flux"; + if(*conv==ConvType::two_point_flux) conv_string = "two_point_flux"; + if(*conv==ConvType::two_point_flux_with_lax_friedrichs_dissipation) conv_string = "two_point_flux_with_lax_friedrichs_dissipation"; + if(*conv==ConvType::two_point_flux_with_roe_dissipation) conv_string = "two_point_flux_with_roe_dissipation"; + if(*conv==ConvType::two_point_flux_with_l2roe_dissipation) conv_string = "two_point_flux_with_l2roe_dissipation"; std::cout << "============================================================================" << std::endl; std::cout << "PDE Type: " << pde_string << "\t Convective Flux Type: " << conv_string << std::endl; diff --git a/tests/unit_tests/ode_solver_unit_test/explicit_ode_solver.cpp b/tests/unit_tests/ode_solver_unit_test/explicit_ode_solver.cpp index 6b5b853a2..bc91fabb9 100755 --- a/tests/unit_tests/ode_solver_unit_test/explicit_ode_solver.cpp +++ b/tests/unit_tests/ode_solver_unit_test/explicit_ode_solver.cpp @@ -79,7 +79,7 @@ int main (int argc, char * argv[]) all_parameters.parse_parameters (parameter_handler); // copies stuff from parameter_handler into all_parameters //ode solver parameters - all_parameters.ode_solver_param.ode_solver_type = PHiLiP::Parameters::ODESolverParam::ODESolverEnum::explicit_solver; + all_parameters.ode_solver_param.ode_solver_type = PHiLiP::Parameters::ODESolverParam::ODESolverEnum::runge_kutta_solver; all_parameters.ode_solver_param.nonlinear_max_iterations = 500; all_parameters.ode_solver_param.print_iteration_modulo = 100; all_parameters.use_periodic_bc = true; @@ -87,7 +87,6 @@ int main (int argc, char * argv[]) const int rk_order = 3; double expected_order = -double(rk_order); double order_tolerance = 0.1; - all_parameters.ode_solver_param.runge_kutta_order = rk_order; const double adv_speed_x = 1.0, adv_speed_y = 0.0; all_parameters.manufactured_convergence_study_param.manufactured_solution_param.advection_vector[0] = adv_speed_x; //x-velocity diff --git a/tests/unit_tests/operator_tests/4_point_flux.cpp b/tests/unit_tests/operator_tests/4_point_flux.cpp new file mode 100644 index 000000000..7b561467b --- /dev/null +++ b/tests/unit_tests/operator_tests/4_point_flux.cpp @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "operators/operators.h" +#include "dg/dg.h" +#include "dg/dg_factory.hpp" + +const double TOLERANCE = 1E-6; +using namespace std; + +int main (int argc, char * argv[]) +{ + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 1; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + all_parameters_new.nstate = nstate; + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + using FR_enum = Parameters::AllParameters::Flux_Reconstruction; + all_parameters_new.flux_reconstruction_type = FR_enum::cHU; + // all_parameters_new.use_collocated_nodes=true; + all_parameters_new.overintegration = 0; + + for(unsigned int poly_degree=2; poly_degree<3; poly_degree++){ + + // OPERATOR::OperatorsBase operators(&all_parameters_new, nstate, poly_degree, poly_degree, poly_degree); + OPERATOR::OperatorsBaseState operators(&all_parameters_new, poly_degree, poly_degree); + + const unsigned int n_dofs = operators.fe_collection_basis[poly_degree].dofs_per_cell; + // const unsigned int n_dofs_flux = operators.fe_collection_flux_basis[poly_degree].dofs_per_cell; + const unsigned int n_quad_pts = operators.volume_quadrature_collection[poly_degree].size(); + std::vector u(n_quad_pts); + for(unsigned int iquad=0; iquad four_pt_flux(n_quad_pts); + dealii::Vector deriv_F(n_quad_pts); + for(unsigned int iquad=0; iquad qpoint_L = operators.volume_quadrature_collection[poly_degree].point(iquad); + double weight_L = (1.0/std::sqrt(qpoint_L[0]*(1.0-qpoint_L[0]))); + const dealii::Point qpoint_R = operators.volume_quadrature_collection[poly_degree].point(flux_basis); + double weight_R = (1.0/std::sqrt(qpoint_R[0]*(1.0-qpoint_R[0]))); + four_pt_flux[iquad] += 2.0 * (1.0/6.0 *(u[iquad]*u[iquad] + u[iquad]*u[flux_basis] + u[flux_basis]*u[flux_basis]) ) + * (weight_L + weight_R) + * operators.gradient_flux_basis[poly_degree][0][0][iquad][flux_basis]; + + deriv_F[iquad] += 1.0/3.0* pow(u[flux_basis],3) + // * (1.0/std::sqrt(qpoint_L[0]*(1.0-qpoint_L[0]))) + * operators.gradient_flux_basis[poly_degree][0][0][iquad][flux_basis]; + } + } + dealii::Vector vol_int(n_dofs); + pcout<<" volume integral "< qpoint = operators.volume_quadrature_collection[poly_degree].point(iquad); + vol_int[idof] += operators.vol_integral_basis[poly_degree][iquad][idof] + * four_pt_flux[iquad] + / (1.0/std::sqrt(qpoint[0]*(1.0-qpoint[0]))); + } + pcout< qpoint = operators.volume_quadrature_collection[poly_degree].point(iquad); + energy += operators.volume_quadrature_collection[poly_degree].weight(iquad) + * u[iquad] + / (1.0/std::sqrt(qpoint[0]*(1.0-qpoint[0]))) + * four_pt_flux[iquad]; + energy2 +=operators.volume_quadrature_collection[poly_degree].weight(iquad) + // / (1.0/std::sqrt(qpoint[0]*(1.0-qpoint[0]))) + * deriv_F[iquad]; + // energy2 +=operators.volume_quadrature_collection[poly_degree].weight(iquad) + // * 1.0/3.0 *pow(u[iquad],3) + // * ((2.0*qpoint[0]-1.0)/(pow(qpoint[0]*(1.0-qpoint[0]), 3.0/2.0)*2.0)) + // / (1.0/std::sqrt(qpoint[0]*(1.0-qpoint[0]))); + } + pcout<<" energy "< { virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. }; + template dealii::Point CurvManifold::pull_back(const dealii::Point &space_point) const { @@ -79,111 +80,35 @@ dealii::Point CurvManifold::pull_back(const dealii::Point &space_ double alpha =1.0/10.0; int flag =0; while(flag != dim){ -#if 0 - for(int idim=0;idim Jacobian_inv(dim); Jacobian_inv.invert(derivative); @@ -201,39 +126,15 @@ dealii::Point CurvManifold::pull_back(const dealii::Point &space_ break; } std::vector function_check(dim); -#if 0 - for(int idim=0;idim error(dim); for(int idim=0; idim CurvManifold::pull_back(const dealii::Point &space_ } return x_ref; - } template @@ -256,39 +156,17 @@ dealii::Point CurvManifold::push_forward(const dealii::Point &cha dealii::Point x_phys; for(int idim=0; idim (x_phys); // Trigonometric } @@ -297,25 +175,6 @@ dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const { const double pi = atan(1)*4.0; dealii::DerivativeForm<1, dim, dim> dphys_dref; -#if 0 - dealii::Point x; - for(int idim=0; idim x_ref; @@ -331,37 +190,6 @@ dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dphys_dref[1][1] = 1.0 -beta*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1]); } else{ - #if 0 - dphys_dref[0][0] = 1.0 - alpha*pi/2.0 * std::sin(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1])*std::sin(2.0*pi*(x_ref[2])); - dphys_dref[0][1] = - alpha*3.0*pi/2.0 * std::cos(pi/2.0*x_ref[0])*std::sin(3.0*pi/2.0*x_ref[1])*std::sin(2.0*pi*(x_ref[2])); - dphys_dref[0][2] = alpha*2.0*pi * std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1])*std::cos(2.0*pi*(x_ref[2])); - - dphys_dref[1][0] = alpha*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1])*std::sin(3.0*pi/2.0*(x_ref[2])); - dphys_dref[1][1] = 1.0 -alpha*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1])*std::sin(3.0*pi/2.0*(x_ref[2])); - dphys_dref[1][2] = alpha*3.0*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1])*std::cos(3.0*pi/2.0*(x_ref[2])); - - dphys_dref[2][0] = alpha*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(3.0*pi/2.0*x_ref[1])*std::sin(5.0*pi/2.0*(x_ref[2])); - dphys_dref[2][1] = - alpha*3.0*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(3.0*pi/2.0*x_ref[1])*std::sin(5.0*pi/2.0*(x_ref[2])); - dphys_dref[2][2] = 1.0 + alpha*5.0*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::cos(3.0*pi/2.0*x_ref[1])*std::cos(5.0*pi/2.0*(x_ref[2])); - #endif - //heavily warped - // #if 0 - // dphys_dref[0][0] = 1.0 + alpha*pi*std::cos(pi*x_ref[0])*std::sin(pi*x_ref[1]); - // dphys_dref[0][1] = alpha*pi*std::cos(pi*x_ref[1])*std::sin(pi*x_ref[0]); - // dphys_dref[0][2] = 0.0; - - // dphys_dref[1][0] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[0])*std::sin(pi*x_ref[1]); - // dphys_dref[1][1] = 1.0 -alpha*exp(1.0-x_ref[1])*std::sin(pi*x_ref[0])*std::sin(pi*x_ref[1]) - // +alpha*pi*exp(1.0-x_ref[1])*std::sin(pi*x_ref[0])*std::cos(pi*x_ref[1]); - // dphys_dref[1][2] = 0.0; - - // double x_phys = x_ref[0] + alpha*std::sin(pi*x_ref[0])*std::sin(pi*x_ref[1]); - // double y_phys = x_ref[1] + alpha*exp(1.0-x_ref[1])*std::sin(pi*x_ref[0])*std::sin(pi*x_ref[1]); - // dphys_dref[2][0] = 1.0/10.0*pi*std::cos(2.0*pi*x_phys)*dphys_dref[0][0] - // +1.0/10.0*pi*std::cos(2.0*pi*y_phys)*dphys_dref[1][0]; - // dphys_dref[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_phys)*dphys_dref[0][1] - // +1.0/10.0*pi*std::cos(2.0*pi*y_phys)*dphys_dref[1][1]; - //#endif dphys_dref[0][0] = 1.0; dphys_dref[0][1] = - alpha*pi*std::sin(pi*x_ref[1]); dphys_dref[0][2] = - alpha*pi*std::sin(pi*x_ref[2]); @@ -373,7 +201,6 @@ dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dphys_dref[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[1]); dphys_dref[2][2] = 1.0; } -//#endif return dphys_dref; } @@ -397,17 +224,6 @@ static dealii::Point warp (const dealii::Point &p) q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); } if(dim==3){ - #if 0 - q[0] =p[0] + alpha*std::cos(pi/2.0 * p[0]) * std::cos(3.0 * pi/2.0 * p[1]) * std::sin(2.0 * pi * (p[2])); - q[1] =p[1] + alpha*std::sin(2.0 * pi * (p[0])) * std::cos(pi /2.0 * p[1]) * std::sin(3.0 * pi /2.0 * p[2]); - q[2] =p[2] + alpha*std::sin(2.0 * pi * (p[0])) * std::cos(3.0 * pi/2.0 * p[1]) * std::cos(5.0 * pi/2.0 * p[2]); - #endif - //heavily warped - // #if 0 - // q[0] =p[0] + alpha*std::sin(pi * p[0]) * std::sin(pi * p[1]); - // q[1] =p[1] + alpha*exp(1.0-p[1])*std::sin(pi * p[0]) * std::sin(pi* p[1]); - // q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * q[0]) + std::sin(2.0 * pi * q[1])); - // #endif q[0] =p[0] + alpha*(std::cos(pi * p[2]) + std::cos(pi * p[1])); q[1] =p[1] + alpha*exp(1.0-p[1])*(std::sin(pi * p[0]) + std::sin(pi* p[2])); q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * p[0]) + std::sin(2.0 * pi * p[1])); @@ -422,7 +238,6 @@ static dealii::Point warp (const dealii::Point &p) int main (int argc, char * argv[]) { - dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); using real = double; using namespace PHiLiP; @@ -438,7 +253,6 @@ int main (int argc, char * argv[]) all_parameters_new.use_collocated_nodes=true; - //unsigned int poly_degree = 3; double left = 0.0; double right = 1.0; const bool colorize = true; @@ -450,127 +264,110 @@ int main (int argc, char * argv[]) typename dealii::Triangulation::MeshSmoothing( dealii::Triangulation::smoothing_on_refinement | dealii::Triangulation::smoothing_on_coarsening)); - dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); - grid->refine_global(0); + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(0); -//Warp the grid -//IF WANT NON-WARPED GRID COMMENT UNTIL SAYS "NOT COMMENT" -//#if 0 + //Warp the grid + //IF WANT NON-WARPED GRID COMMENT UNTIL SAYS "NOT COMMENT" dealii::GridTools::transform (&warp, *grid); -// Assign a manifold to have curved geometry + // Assign a manifold to have curved geometry const CurvManifold curv_manifold; unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true grid->reset_all_manifolds(); grid->set_all_manifold_ids(manifold_id); grid->set_manifold ( manifold_id, curv_manifold ); -//#endif -//"END COMMENT" TO NOT WARP GRID + //"END COMMENT" TO NOT WARP GRID double max_GCL = 0.0; + + // Loop through poly degree for(unsigned int poly_degree = 2; poly_degree<5; poly_degree++){ unsigned int grid_degree = poly_degree; - //setup operator - OPERATOR::OperatorBase operators(&all_parameters_new, poly_degree, poly_degree, grid_degree); -//setup DG - // std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, grid); - std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); - dg->allocate_system (); - - - const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size(); - - const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); - const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; - auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); - for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { - if (!current_cell->is_locally_owned()) continue; - - std::vector current_metric_dofs_indices(n_metric_dofs); - metric_cell->get_dof_indices (current_metric_dofs_indices); - std::vector> mapping_support_points(dim); - for(int idim=0; idim > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); + + dealii::QGaussLobatto<1> grid_quad(grid_degree +1); + const dealii::FE_DGQ<1> fe_grid(grid_degree); + const dealii::FESystem<1,1> fe_sys_grid(fe_grid, nstate); + dealii::QGauss<1> flux_quad(poly_degree +1); + dealii::QGauss<0> flux_quad_face(poly_degree +1); + + PHiLiP::OPERATOR::mapping_shape_functions mapping_basis(nstate,poly_degree,grid_degree); + mapping_basis.build_1D_shape_functions_at_grid_nodes(fe_sys_grid, grid_quad); + mapping_basis.build_1D_shape_functions_at_flux_nodes(fe_sys_grid, flux_quad, flux_quad_face); + + const unsigned int n_quad_pts = pow(poly_degree+1,dim); + + const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + pcout<<" degree "< current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + for(int idim=0; idim vol_GLL(grid_degree +1); + for (unsigned int igrid_node = 0; igrid_node< n_metric_dofs/dim; ++igrid_node) { + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); const unsigned int istate = fe_metric.system_to_component_index(idof).first; - const unsigned int ishape = fe_metric.system_to_component_index(idof).second; - mapping_support_points[istate][ishape] = val; - } - std::vector> metric_cofactor(n_quad_pts); - std::vector determinant_Jacobian(n_quad_pts); - for(unsigned int iquad=0;iquad>> Gij(dim); - for(int idim=0; idim metric_oper(nstate,poly_degree,grid_degree); + metric_oper.build_volume_metric_operators( + n_quad_pts, n_metric_dofs/dim, + mapping_support_points, + mapping_basis, + false); - std::vector> GCL(dim); - for(int idim=0; idim ones(n_quad_pts); - for(unsigned int idof=0; idof,dim> GCL; + for(int idim=0; idim temp(n_quad_pts); - operators.gradient_flux_basis[poly_degree][0][idim2].mmult(temp, Gij[idim2][idim]); - dealii::Vector temp2(n_quad_pts); - temp.vmult(temp2, ones); - GCL[idim].add(1, temp2); - } - } + const dealii::FE_DGQArbitraryNodes<1> fe_poly(flux_quad); + const dealii::FESystem<1,1> fe_sys_poly(fe_poly, nstate); + PHiLiP::OPERATOR::basis_functions_state flux_basis_quad(poly_degree, 1); + flux_basis_quad.build_1D_gradient_state_operator(fe_sys_poly, flux_quad); + flux_basis_quad.build_1D_volume_state_operator(fe_sys_poly, flux_quad); + for(int idim=0; idim max_GCL){ - max_GCL = std::abs(GCL[idim][idof]); - } + for(int idim=0; idim max_GCL){ + max_GCL = std::abs(GCL[idim][idof]); } } - } - - }//end poly degree loop + } //end cell loop + } //end poly degree loop + const double max_GCL_mpi= (dealii::Utilities::MPI::max(max_GCL, MPI_COMM_WORLD)); - if( max_GCL_mpi > 1e-10){ -// printf(" Metrics Do NOT Satisfy GCL Condition\n"); + if(max_GCL_mpi > 1e-10){ pcout<<" Metrics Do NOT Satisfy GCL Condition\n"< { virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. }; + template dealii::Point CurvManifold::pull_back(const dealii::Point &space_point) const { @@ -79,58 +80,17 @@ dealii::Point CurvManifold::pull_back(const dealii::Point &space_ double alpha =1.0/10.0; int flag =0; while(flag != dim){ -#if 0 - for(int idim=0;idim CurvManifold::pull_back(const dealii::Point &space_ derivative[1][1] = 1.0 -beta*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1]); } else{ - #if 0 - derivative[0][0] = 1.0 - alpha* pi/2.0 * std::sin(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1])*std::sin(2.0*pi*(x_ref[2])); - derivative[0][1] = - alpha*3.0 *pi/2.0 * std::cos(pi/2.0*x_ref[0])*std::sin(3.0*pi/2.0*x_ref[1])*std::sin(2.0*pi*(x_ref[2])); - derivative[0][2] = alpha*2.0*pi * std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1])*std::cos(2.0*pi*(x_ref[2])); - - derivative[1][0] = alpha*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1])*std::sin(3.0*pi/2.0*(x_ref[2])); - derivative[1][1] = 1.0 -alpha*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1])*std::sin(3.0*pi/2.0*(x_ref[2])); - derivative[1][2] = alpha*3.0*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1])*std::cos(3.0*pi/2.0*(x_ref[2])); - - derivative[2][0] = alpha*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(3.0*pi/2.0*x_ref[1])*std::sin(5.0*pi/2.0*(x_ref[2])); - derivative[2][1] = - alpha*3.0*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(3.0*pi/2.0*x_ref[1])*std::sin(5.0*pi/2.0*(x_ref[2])); - derivative[2][2] = 1.0 + alpha*5.0*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::cos(3.0*pi/2.0*x_ref[1])*std::cos(5.0*pi/2.0*(x_ref[2])); - #endif - //heavily warped - // #if 0 - // derivative[0][0] = 1.0 + alpha*pi*std::cos(pi*x_ref[0])*std::sin(pi*x_ref[1]); - // derivative[0][1] = alpha*pi*std::cos(pi*x_ref[1])*std::sin(pi*x_ref[0]); - // derivative[0][2] = 0.0; - - // derivative[1][0] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[0])*std::sin(pi*x_ref[1]); - // derivative[1][1] = 1.0 -alpha*exp(1.0-x_ref[1])*std::sin(pi*x_ref[0])*std::sin(pi*x_ref[1]) - // +alpha*pi*exp(1.0-x_ref[1])*std::sin(pi*x_ref[0])*std::cos(pi*x_ref[1]); - // derivative[1][2] = 0.0; - - // double x_temp = x_ref[0] + alpha*std::sin(pi * x_ref[0]) * std::sin(pi * x_ref[1]); - // double y_temp = x_ref[1] + alpha*exp(1.0-x_ref[1])*std::sin(pi * x_ref[0]) * std::sin(pi* x_ref[1]); - // derivative[2][0] = 1.0/10.0*pi*std::cos(2.0*pi*x_temp)*derivative[0][0] - // +1.0/10.0*pi*std::cos(2.0*pi*y_temp)*derivative[1][0]; - // derivative[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_temp)*derivative[0][1] - // +1.0/10.0*pi*std::cos(2.0*pi*y_temp)*derivative[1][1]; - // - // derivative[0][0] = 1.0; derivative[0][1] = - alpha*pi*std::sin(pi*x_ref[1]); derivative[0][2] = - alpha*pi*std::sin(pi*x_ref[2]); @@ -181,9 +109,7 @@ dealii::Point CurvManifold::pull_back(const dealii::Point &space_ derivative[2][0] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[0]); derivative[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[1]); derivative[2][2] = 1.0; - // #endif } -//#endif dealii::FullMatrix Jacobian_inv(dim); Jacobian_inv.invert(derivative); @@ -201,39 +127,15 @@ dealii::Point CurvManifold::pull_back(const dealii::Point &space_ break; } std::vector function_check(dim); -#if 0 - for(int idim=0;idim error(dim); for(int idim=0; idim CurvManifold::pull_back(const dealii::Point &space_ } return x_ref; - } template @@ -256,39 +157,17 @@ dealii::Point CurvManifold::push_forward(const dealii::Point &cha dealii::Point x_phys; for(int idim=0; idim (x_phys); // Trigonometric } @@ -297,25 +176,6 @@ dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const { const double pi = atan(1)*4.0; dealii::DerivativeForm<1, dim, dim> dphys_dref; -#if 0 - dealii::Point x; - for(int idim=0; idim x_ref; @@ -331,37 +191,6 @@ dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dphys_dref[1][1] = 1.0 -beta*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1]); } else{ - #if 0 - dphys_dref[0][0] = 1.0 - alpha*pi/2.0 * std::sin(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1])*std::sin(2.0*pi*(x_ref[2])); - dphys_dref[0][1] = - alpha*3.0*pi/2.0 * std::cos(pi/2.0*x_ref[0])*std::sin(3.0*pi/2.0*x_ref[1])*std::sin(2.0*pi*(x_ref[2])); - dphys_dref[0][2] = alpha*2.0*pi * std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1])*std::cos(2.0*pi*(x_ref[2])); - - dphys_dref[1][0] = alpha*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1])*std::sin(3.0*pi/2.0*(x_ref[2])); - dphys_dref[1][1] = 1.0 -alpha*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1])*std::sin(3.0*pi/2.0*(x_ref[2])); - dphys_dref[1][2] = alpha*3.0*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1])*std::cos(3.0*pi/2.0*(x_ref[2])); - - dphys_dref[2][0] = alpha*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(3.0*pi/2.0*x_ref[1])*std::sin(5.0*pi/2.0*(x_ref[2])); - dphys_dref[2][1] = - alpha*3.0*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(3.0*pi/2.0*x_ref[1])*std::sin(5.0*pi/2.0*(x_ref[2])); - dphys_dref[2][2] = 1.0 + alpha*5.0*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::cos(3.0*pi/2.0*x_ref[1])*std::cos(5.0*pi/2.0*(x_ref[2])); - #endif - //heavily warped - // #if 0 - // dphys_dref[0][0] = 1.0 + alpha*pi*std::cos(pi*x_ref[0])*std::sin(pi*x_ref[1]); - // dphys_dref[0][1] = alpha*pi*std::cos(pi*x_ref[1])*std::sin(pi*x_ref[0]); - // dphys_dref[0][2] = 0.0; - - // dphys_dref[1][0] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[0])*std::sin(pi*x_ref[1]); - // dphys_dref[1][1] = 1.0 -alpha*exp(1.0-x_ref[1])*std::sin(pi*x_ref[0])*std::sin(pi*x_ref[1]) - // +alpha*pi*exp(1.0-x_ref[1])*std::sin(pi*x_ref[0])*std::cos(pi*x_ref[1]); - // dphys_dref[1][2] = 0.0; - - // double x_phys = x_ref[0] + alpha*std::sin(pi*x_ref[0])*std::sin(pi*x_ref[1]); - // double y_phys = x_ref[1] + alpha*exp(1.0-x_ref[1])*std::sin(pi*x_ref[0])*std::sin(pi*x_ref[1]); - // dphys_dref[2][0] = 1.0/10.0*pi*std::cos(2.0*pi*x_phys)*dphys_dref[0][0] - // +1.0/10.0*pi*std::cos(2.0*pi*y_phys)*dphys_dref[1][0]; - // dphys_dref[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_phys)*dphys_dref[0][1] - // +1.0/10.0*pi*std::cos(2.0*pi*y_phys)*dphys_dref[1][1]; - //#endif dphys_dref[0][0] = 1.0; dphys_dref[0][1] = - alpha*pi*std::sin(pi*x_ref[1]); dphys_dref[0][2] = - alpha*pi*std::sin(pi*x_ref[2]); @@ -373,7 +202,6 @@ dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dphys_dref[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[1]); dphys_dref[2][2] = 1.0; } -//#endif return dphys_dref; } @@ -397,17 +225,6 @@ static dealii::Point warp (const dealii::Point &p) q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); } if(dim==3){ - #if 0 - q[0] =p[0] + alpha*std::cos(pi/2.0 * p[0]) * std::cos(3.0 * pi/2.0 * p[1]) * std::sin(2.0 * pi * (p[2])); - q[1] =p[1] + alpha*std::sin(2.0 * pi * (p[0])) * std::cos(pi /2.0 * p[1]) * std::sin(3.0 * pi /2.0 * p[2]); - q[2] =p[2] + alpha*std::sin(2.0 * pi * (p[0])) * std::cos(3.0 * pi/2.0 * p[1]) * std::cos(5.0 * pi/2.0 * p[2]); - #endif - //heavily warped - // #if 0 - // q[0] =p[0] + alpha*std::sin(pi * p[0]) * std::sin(pi * p[1]); - // q[1] =p[1] + alpha*exp(1.0-p[1])*std::sin(pi * p[0]) * std::sin(pi* p[1]); - // q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * q[0]) + std::sin(2.0 * pi * q[1])); - // #endif q[0] =p[0] + alpha*(std::cos(pi * p[2]) + std::cos(pi * p[1])); q[1] =p[1] + alpha*exp(1.0-p[1])*(std::sin(pi * p[0]) + std::sin(pi* p[2])); q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * p[0]) + std::sin(2.0 * pi * p[1])); @@ -422,7 +239,6 @@ static dealii::Point warp (const dealii::Point &p) int main (int argc, char * argv[]) { - dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); using real = double; using namespace PHiLiP; @@ -436,14 +252,10 @@ int main (int argc, char * argv[]) PHiLiP::Parameters::AllParameters all_parameters_new; all_parameters_new.parse_parameters (parameter_handler); - // all_parameters_new.use_collocated_nodes=true; - - //unsigned int poly_degree = 3; double left = 0.0; double right = 1.0; const bool colorize = true; //Generate a standard grid - using Triangulation = dealii::parallel::distributed::Triangulation; std::shared_ptr grid = std::make_shared( MPI_COMM_WORLD, @@ -451,126 +263,107 @@ int main (int argc, char * argv[]) dealii::Triangulation::smoothing_on_refinement | dealii::Triangulation::smoothing_on_coarsening)); dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); - grid->refine_global(0); + grid->refine_global(3); -//Warp the grid -//IF WANT NON-WARPED GRID COMMENT UNTIL SAYS "NOT COMMENT" -//#if 0 + //Warp the grid + //IF WANT NON-WARPED GRID COMMENT UNTIL SAYS "NOT COMMENT" dealii::GridTools::transform (&warp, *grid); - -// Assign a manifold to have curved geometry + // Assign a manifold to have curved geometry const CurvManifold curv_manifold; unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true grid->reset_all_manifolds(); grid->set_all_manifold_ids(manifold_id); grid->set_manifold ( manifold_id, curv_manifold ); -//#endif -//"END COMMENT" TO NOT WARP GRID + //"END COMMENT" TO NOT WARP GRID double max_GCL = 0.0; for(unsigned int poly_degree = 2; poly_degree<5; poly_degree++){ unsigned int grid_degree = poly_degree; - //setup operator - OPERATOR::OperatorBase operators(&all_parameters_new, poly_degree, poly_degree, grid_degree); -//setup DG - // std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, grid); - std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); - dg->allocate_system (); - + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); - const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size(); - - const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); - const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; - auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); - for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { - if (!current_cell->is_locally_owned()) continue; - - std::vector current_metric_dofs_indices(n_metric_dofs); - metric_cell->get_dof_indices (current_metric_dofs_indices); - std::vector> mapping_support_points(dim); - for(int idim=0; idim grid_quad(grid_degree +1); + const dealii::FE_DGQ<1> fe_grid(grid_degree); + const dealii::FESystem<1,1> fe_sys_grid(fe_grid, nstate); + dealii::QGauss<1> flux_quad(poly_degree +1); + dealii::QGauss<0> flux_quad_face(poly_degree +1); + + PHiLiP::OPERATOR::mapping_shape_functions mapping_basis(nstate,poly_degree,grid_degree); + mapping_basis.build_1D_shape_functions_at_grid_nodes(fe_sys_grid, grid_quad); + mapping_basis.build_1D_shape_functions_at_flux_nodes(fe_sys_grid, flux_quad, flux_quad_face); + + const unsigned int n_quad_pts = pow(poly_degree+1,dim); + + const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + std::vector current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + for(int idim=0; idim vol_GLL(grid_degree +1); + for (unsigned int igrid_node = 0; igrid_node< n_metric_dofs/dim; ++igrid_node) { + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); const unsigned int istate = fe_metric.system_to_component_index(idof).first; - const unsigned int ishape = fe_metric.system_to_component_index(idof).second; - mapping_support_points[istate][ishape] = val; - } - std::vector> metric_cofactor(n_quad_pts); - std::vector determinant_Jacobian(n_quad_pts); - for(unsigned int iquad=0;iquad>> Gij(dim); - for(int idim=0; idim metric_oper(nstate,poly_degree,grid_degree); + metric_oper.build_volume_metric_operators( + n_quad_pts, n_metric_dofs/dim, + mapping_support_points, + mapping_basis, + false); - std::vector> GCL(dim); - for(int idim=0; idim ones(n_quad_pts); - for(unsigned int idof=0; idof,dim> GCL; + for(int idim=0; idim temp(n_quad_pts); - operators.gradient_flux_basis[poly_degree][0][idim2].mmult(temp, Gij[idim2][idim]); - dealii::Vector temp2(n_quad_pts); - temp.vmult(temp2, ones); - GCL[idim].add(1, temp2); - } - } + const dealii::FE_DGQArbitraryNodes<1> fe_poly(flux_quad); + const dealii::FESystem<1,1> fe_sys_poly(fe_poly, nstate); + PHiLiP::OPERATOR::basis_functions_state flux_basis_quad(poly_degree, 1); + flux_basis_quad.build_1D_gradient_state_operator(fe_sys_poly, flux_quad); + flux_basis_quad.build_1D_volume_state_operator(fe_sys_poly, flux_quad); + for(int idim=0; idim max_GCL){ - max_GCL = std::abs(GCL[idim][idof]); - } + for(int idim=0; idim max_GCL){ + max_GCL = std::abs(GCL[idim][idof]); } } - } - + }//end cell loop }//end poly degree loop - const double max_GCL_mpi= (dealii::Utilities::MPI::max(max_GCL, MPI_COMM_WORLD)); - if( max_GCL_mpi > 1e-10){ -// printf(" Metrics Do NOT Satisfy GCL Condition\n"); + const double max_GCL_mpi= (dealii::Utilities::MPI::max(max_GCL, MPI_COMM_WORLD)); + if(max_GCL_mpi > 1e-10){ pcout<<" Metrics Do NOT Satisfy GCL Condition\n"< +#include +#include +#include +#include +#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "dg/dg.h" +#include +#include +#include "dg/dg_factory.hpp" +#include "operators/operators.h" +//#include + +const double TOLERANCE = 1E-6; +using namespace std; +//namespace PHiLiP { + + +template +class CurvManifold: public dealii::ChartManifold { + virtual dealii::Point pull_back(const dealii::Point &space_point) const override; ///< See dealii::Manifold. + virtual dealii::Point push_forward(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + virtual dealii::DerivativeForm<1,dim,dim> push_forward_gradient(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + + virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. +}; +template +dealii::Point CurvManifold::pull_back(const dealii::Point &space_point) const +{ + using namespace PHiLiP; + const double pi = atan(1)*4.0; + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim function(dim); + dealii::FullMatrix derivative(dim); + double beta =1.0/10.0; + double alpha =1.0/10.0; + int flag =0; + while(flag != dim){ + if(dim==2){ + function[0] = x_ref[0] - x_phys[0] +beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function[1] = x_ref[1] - x_phys[1] +beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function[0] = x_ref[0] - x_phys[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function[1] = x_ref[1] - x_phys[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function[2] = x_ref[2] - x_phys[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + + + if(dim==2){ + derivative[0][0] = 1.0 - beta* pi/2.0 * std::sin(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + derivative[0][1] = - beta*3.0 *pi/2.0 * std::cos(pi/2.0*x_ref[0])*std::sin(3.0*pi/2.0*x_ref[1]); + + derivative[1][0] = beta*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + derivative[1][1] = 1.0 -beta*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1]); + } + else{ + derivative[0][0] = 1.0; + derivative[0][1] = - alpha*pi*std::sin(pi*x_ref[1]); + derivative[0][2] = - alpha*pi*std::sin(pi*x_ref[2]); + + derivative[1][0] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[0]); + derivative[1][1] = 1.0 -alpha*exp(1.0-x_ref[1])*(std::sin(pi*x_ref[0])+std::sin(pi*x_ref[2])); + derivative[1][2] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[2]); + derivative[2][0] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[0]); + derivative[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[1]); + derivative[2][2] = 1.0; + } + + dealii::FullMatrix Jacobian_inv(dim); + Jacobian_inv.invert(derivative); + dealii::Vector Newton_Step(dim); + Jacobian_inv.vmult(Newton_Step, function); + for(int idim=0; idim function_check(dim); + if(dim==2){ + function_check[0] = x_ref[0] + beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function_check[1] = x_ref[1] + beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function_check[0] = x_ref[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function_check[1] = x_ref[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function_check[2] = x_ref[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + std::vector error(dim); + for(int idim=0; idim 1e-13) { + std::cout << "Large error " << error[0] << std::endl; + for(int idim=0;idim +dealii::Point CurvManifold::push_forward(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim (x_phys); // Trigonometric +} + +template +dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + dealii::DerivativeForm<1, dim, dim> dphys_dref; + double beta = 1.0/10.0; + double alpha = 1.0/10.0; + dealii::Point x_ref; + for(int idim=0; idim +std::unique_ptr > CurvManifold::clone() const +{ + return std::make_unique>(); +} + +template +static dealii::Point warp (const dealii::Point &p) +{ + const double pi = atan(1)*4.0; + dealii::Point q = p; + + double beta =1.0/10.0; + double alpha =1.0/10.0; + if (dim == 2){ + q[dim-2] =p[dim-2] + beta*std::cos(pi/2.0 * p[dim-2]) * std::cos(3.0 * pi/2.0 * p[dim-1]); + q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); + } + if(dim==3){ + q[0] =p[0] + alpha*(std::cos(pi * p[2]) + std::cos(pi * p[1])); + q[1] =p[1] + alpha*exp(1.0-p[1])*(std::sin(pi * p[0]) + std::sin(pi* p[2])); + q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * p[0]) + std::sin(2.0 * pi * p[1])); + } + + return q; +} + +/**************************** + * End of Curvilinear Grid + * ***************************/ + +int main (int argc, char * argv[]) +{ + + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 1; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + + double left = 0.0; + double right = 1.0; + const bool colorize = true; + //Generate a standard grid + + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(0); + +//Warp the grid +//IF WANT NON-WARPED GRID COMMENT UNTIL SAYS "NOT COMMENT" + dealii::GridTools::transform (&warp, *grid); + +// Assign a manifold to have curved geometry + const CurvManifold curv_manifold; + unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true + grid->reset_all_manifolds(); + grid->set_all_manifold_ids(manifold_id); + grid->set_manifold ( manifold_id, curv_manifold ); +//"END COMMENT" TO NOT WARP GRID + double max_GCL = 0.0; + for(unsigned int poly_degree = 2; poly_degree<5; poly_degree++){ + unsigned int grid_degree = poly_degree; + + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); + + dealii::QGaussLobatto<1> grid_quad(grid_degree +1); + const dealii::FE_DGQ<1> fe_grid(grid_degree); + const dealii::FESystem<1,1> fe_sys_grid(fe_grid, nstate); + dealii::QGauss<1> flux_quad(poly_degree +1); + dealii::QGauss<0> flux_quad_face(poly_degree +1); + + PHiLiP::OPERATOR::mapping_shape_functions mapping_basis(nstate,poly_degree,grid_degree); + mapping_basis.build_1D_shape_functions_at_grid_nodes(fe_sys_grid, grid_quad); + mapping_basis.build_1D_shape_functions_at_flux_nodes(fe_sys_grid, flux_quad, flux_quad_face); + + const unsigned int n_quad_pts = pow(poly_degree+1,dim); + + const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + pcout<<" degree "< current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + for(int idim=0; idim vol_GLL(grid_degree +1); + for (unsigned int igrid_node = 0; igrid_node< n_metric_dofs/dim; ++igrid_node) { + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + mapping_support_points[istate][igrid_node] += val * fe_metric.shape_value_component(idof,vol_GLL.point(igrid_node),istate); + } + } + + PHiLiP::OPERATOR::metric_operators metric_oper(nstate,poly_degree,grid_degree); + metric_oper.build_volume_metric_operators( + n_quad_pts, n_metric_dofs/dim, + mapping_support_points, + mapping_basis, + true); + + std::array,dim> GCL; + for(int idim=0; idim fe_poly(flux_quad); + const dealii::FESystem<1,1> fe_sys_poly(fe_poly, nstate); + PHiLiP::OPERATOR::basis_functions_state flux_basis_quad(poly_degree, 1); + flux_basis_quad.build_1D_gradient_state_operator(fe_sys_poly, flux_quad); + flux_basis_quad.build_1D_volume_state_operator(fe_sys_poly, flux_quad); + for(int idim=0; idim max_GCL){ + max_GCL = std::abs(GCL[idim][idof]); + } + } + } + + } + + }//end poly degree loop + const double max_GCL_mpi= (dealii::Utilities::MPI::max(max_GCL, MPI_COMM_WORLD)); + + if( max_GCL_mpi > 1e-10){ + pcout<<" Metrics Do NOT Satisfy GCL Condition\n"< -#include -#include -#include -#include -#include -#include - -#include - -#include "testing/tests.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include - -#include - -// Finally, we take our exact solution from the library as well as volume_quadrature -// and additional tools. -#include -#include -#include -#include - -#include "parameters/all_parameters.h" -#include "parameters/parameters.h" -#include "dg/dg.h" -#include -#include -#include "dg/dg_factory.hpp" -#include "operators/operators.h" -//#include - -const double TOLERANCE = 1E-6; -using namespace std; -//namespace PHiLiP { - - -template -class CurvManifold: public dealii::ChartManifold { - virtual dealii::Point pull_back(const dealii::Point &space_point) const override; ///< See dealii::Manifold. - virtual dealii::Point push_forward(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. - virtual dealii::DerivativeForm<1,dim,dim> push_forward_gradient(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. - - virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. -}; -template -dealii::Point CurvManifold::pull_back(const dealii::Point &space_point) const -{ - using namespace PHiLiP; - const double pi = atan(1)*4.0; - dealii::Point x_ref; - dealii::Point x_phys; - for(int idim=0; idim function(dim); - dealii::FullMatrix derivative(dim); - double beta =1.0/10.0; - double alpha =1.0/10.0; - int flag =0; - while(flag != dim){ -#if 0 - for(int idim=0;idim Jacobian_inv(dim); - Jacobian_inv.invert(derivative); - dealii::Vector Newton_Step(dim); - Jacobian_inv.vmult(Newton_Step, function); - for(int idim=0; idim function_check(dim); -#if 0 - for(int idim=0;idim error(dim); - for(int idim=0; idim 1e-13) { - std::cout << "Large error " << error[0] << std::endl; - for(int idim=0;idim -dealii::Point CurvManifold::push_forward(const dealii::Point &chart_point) const -{ - const double pi = atan(1)*4.0; - - dealii::Point x_ref; - dealii::Point x_phys; - for(int idim=0; idim (x_phys); // Trigonometric -} - -template -dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dealii::Point &chart_point) const -{ - const double pi = atan(1)*4.0; - dealii::DerivativeForm<1, dim, dim> dphys_dref; -#if 0 - dealii::Point x; - for(int idim=0; idim x_ref; - for(int idim=0; idim -std::unique_ptr > CurvManifold::clone() const -{ - return std::make_unique>(); -} - -template -static dealii::Point warp (const dealii::Point &p) -{ - const double pi = atan(1)*4.0; - dealii::Point q = p; - - double beta =1.0/10.0; - double alpha =1.0/10.0; - if (dim == 2){ - q[dim-2] =p[dim-2] + beta*std::cos(pi/2.0 * p[dim-2]) * std::cos(3.0 * pi/2.0 * p[dim-1]); - q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); - } - if(dim==3){ - #if 0 - q[0] =p[0] + alpha*std::cos(pi/2.0 * p[0]) * std::cos(3.0 * pi/2.0 * p[1]) * std::sin(2.0 * pi * (p[2])); - q[1] =p[1] + alpha*std::sin(2.0 * pi * (p[0])) * std::cos(pi /2.0 * p[1]) * std::sin(3.0 * pi /2.0 * p[2]); - q[2] =p[2] + alpha*std::sin(2.0 * pi * (p[0])) * std::cos(3.0 * pi/2.0 * p[1]) * std::cos(5.0 * pi/2.0 * p[2]); - #endif - //heavily warped - // #if 0 - // q[0] =p[0] + alpha*std::sin(pi * p[0]) * std::sin(pi * p[1]); - // q[1] =p[1] + alpha*exp(1.0-p[1])*std::sin(pi * p[0]) * std::sin(pi* p[1]); - // q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * q[0]) + std::sin(2.0 * pi * q[1])); - // #endif - q[0] =p[0] + alpha*(std::cos(pi * p[2]) + std::cos(pi * p[1])); - q[1] =p[1] + alpha*exp(1.0-p[1])*(std::sin(pi * p[0]) + std::sin(pi* p[2])); - q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * p[0]) + std::sin(2.0 * pi * p[1])); - } - - return q; -} - -/**************************** - * End of Curvilinear Grid - * ***************************/ - -int main (int argc, char * argv[]) -{ - - dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); - using real = double; - using namespace PHiLiP; - std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; - const int dim = PHILIP_DIM; - const int nstate = 1; - dealii::ParameterHandler parameter_handler; - PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); - dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); - - PHiLiP::Parameters::AllParameters all_parameters_new; - all_parameters_new.parse_parameters (parameter_handler); - - // all_parameters_new.use_collocated_nodes=true; - - //unsigned int poly_degree = 3; - double left = 0.0; - double right = 1.0; - const bool colorize = true; - //Generate a standard grid - - using Triangulation = dealii::parallel::distributed::Triangulation; - std::shared_ptr grid = std::make_shared( - MPI_COMM_WORLD, - typename dealii::Triangulation::MeshSmoothing( - dealii::Triangulation::smoothing_on_refinement | - dealii::Triangulation::smoothing_on_coarsening)); - dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); - grid->refine_global(0); - -//Warp the grid -//IF WANT NON-WARPED GRID COMMENT UNTIL SAYS "NOT COMMENT" -//#if 0 - dealii::GridTools::transform (&warp, *grid); - -// Assign a manifold to have curved geometry - const CurvManifold curv_manifold; - unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true - grid->reset_all_manifolds(); - grid->set_all_manifold_ids(manifold_id); - grid->set_manifold ( manifold_id, curv_manifold ); -//#endif -//"END COMMENT" TO NOT WARP GRID - - double surf_int = 0.0; - for(unsigned int poly_degree = 2; poly_degree<6; poly_degree++){ - unsigned int grid_degree = poly_degree + 1; - //setup operator - OPERATOR::OperatorBase operators(&all_parameters_new, poly_degree, poly_degree, grid_degree); -//setup DG - // std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, grid); - std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); - dg->allocate_system (); - - - const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); - const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; - auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); - for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { - if (!current_cell->is_locally_owned()) continue; - - std::vector current_metric_dofs_indices(n_metric_dofs); - metric_cell->get_dof_indices (current_metric_dofs_indices); - std::vector> mapping_support_points(dim); - for(int idim=0; idimhigh_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); - const unsigned int istate = fe_metric.system_to_component_index(idof).first; - const unsigned int ishape = fe_metric.system_to_component_index(idof).second; - mapping_support_points[istate][ishape] = val; - } - - - const unsigned int n_quad_face_pts = operators.face_quadrature_collection[poly_degree].size(); - const std::vector &quad_weights = operators.face_quadrature_collection[poly_degree].get_weights (); - for (unsigned int iface=0; iface < dealii::GeometryInfo::faces_per_cell; ++iface) { - - std::vector> metric_cofactor(n_quad_face_pts); - for(unsigned int iquad=0; iquad determinant_Jacobian(n_quad_face_pts); - operators.build_local_face_metric_cofactor_matrix_and_det_Jac(grid_degree, poly_degree, iface, - n_quad_face_pts, n_metric_dofs / dim, mapping_support_points, - determinant_Jacobian, metric_cofactor); - const dealii::Tensor<1,dim,real> unit_normal_int = dealii::GeometryInfo::unit_normal_vector[iface]; - std::vector> normals_int(n_quad_face_pts); - for(unsigned int iquad=0; iquad 1e-13){ -// printf(" Metrics Do NOT Satisfy GCL Condition\n"); - pcout<<" Metrics Do NOT Satisfy GCL Condition\n"< -#include -#include -#include -#include -#include -#include - -#include - -#include "testing/tests.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include - -#include - -// Finally, we take our exact solution from the library as well as volume_quadrature -// and additional tools. -#include -#include -#include -#include - -#include "parameters/all_parameters.h" -#include "parameters/parameters.h" -#include "dg/dg.h" -#include -#include -#include "dg/dg_factory.hpp" -#include "operators/operators.h" -//#include - -const double TOLERANCE = 1E-6; -using namespace std; -//namespace PHiLiP { - - -template -class CurvManifold: public dealii::ChartManifold { - virtual dealii::Point pull_back(const dealii::Point &space_point) const override; ///< See dealii::Manifold. - virtual dealii::Point push_forward(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. - virtual dealii::DerivativeForm<1,dim,dim> push_forward_gradient(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. - - virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. -}; -template -dealii::Point CurvManifold::pull_back(const dealii::Point &space_point) const -{ - using namespace PHiLiP; - const double pi = atan(1)*4.0; - dealii::Point x_ref; - dealii::Point x_phys; - for(int idim=0; idim function(dim); - dealii::FullMatrix derivative(dim); - double beta =1.0/10.0; - double alpha =1.0/10.0; - int flag =0; - while(flag != dim){ -#if 0 - for(int idim=0;idim Jacobian_inv(dim); - Jacobian_inv.invert(derivative); - dealii::Vector Newton_Step(dim); - Jacobian_inv.vmult(Newton_Step, function); - for(int idim=0; idim function_check(dim); -#if 0 - for(int idim=0;idim error(dim); - for(int idim=0; idim 1e-13) { - std::cout << "Large error " << error[0] << std::endl; - for(int idim=0;idim -dealii::Point CurvManifold::push_forward(const dealii::Point &chart_point) const -{ - const double pi = atan(1)*4.0; - - dealii::Point x_ref; - dealii::Point x_phys; - for(int idim=0; idim (x_phys); // Trigonometric -} - -template -dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dealii::Point &chart_point) const -{ - const double pi = atan(1)*4.0; - dealii::DerivativeForm<1, dim, dim> dphys_dref; -#if 0 - dealii::Point x; - for(int idim=0; idim x_ref; - for(int idim=0; idim -std::unique_ptr > CurvManifold::clone() const -{ - return std::make_unique>(); -} - -template -static dealii::Point warp (const dealii::Point &p) -{ - const double pi = atan(1)*4.0; - dealii::Point q = p; - - double beta =1.0/10.0; - double alpha =1.0/10.0; - if (dim == 2){ - q[dim-2] =p[dim-2] + beta*std::cos(pi/2.0 * p[dim-2]) * std::cos(3.0 * pi/2.0 * p[dim-1]); - q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); - } - if(dim==3){ - #if 0 - q[0] =p[0] + alpha*std::cos(pi/2.0 * p[0]) * std::cos(3.0 * pi/2.0 * p[1]) * std::sin(2.0 * pi * (p[2])); - q[1] =p[1] + alpha*std::sin(2.0 * pi * (p[0])) * std::cos(pi /2.0 * p[1]) * std::sin(3.0 * pi /2.0 * p[2]); - q[2] =p[2] + alpha*std::sin(2.0 * pi * (p[0])) * std::cos(3.0 * pi/2.0 * p[1]) * std::cos(5.0 * pi/2.0 * p[2]); - #endif - //heavily warped - // #if 0 - // q[0] =p[0] + alpha*std::sin(pi * p[0]) * std::sin(pi * p[1]); - // q[1] =p[1] + alpha*exp(1.0-p[1])*std::sin(pi * p[0]) * std::sin(pi* p[1]); - // q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * q[0]) + std::sin(2.0 * pi * q[1])); - // #endif - q[0] =p[0] + alpha*(std::cos(pi * p[2]) + std::cos(pi * p[1])); - q[1] =p[1] + alpha*exp(1.0-p[1])*(std::sin(pi * p[0]) + std::sin(pi* p[2])); - q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * p[0]) + std::sin(2.0 * pi * p[1])); - } - - return q; -} - -/**************************** - * End of Curvilinear Grid - * ***************************/ - -int main (int argc, char * argv[]) -{ - - dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); - using real = double; - using namespace PHiLiP; - std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; - const int dim = PHILIP_DIM; - const int nstate = 1; - dealii::ParameterHandler parameter_handler; - PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); - dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); - - PHiLiP::Parameters::AllParameters all_parameters_new; - all_parameters_new.parse_parameters (parameter_handler); - - // all_parameters_new.use_collocated_nodes=true; - - //unsigned int poly_degree = 3; - double left = 0.0; - double right = 1.0; - const bool colorize = true; - //Generate a standard grid - - using Triangulation = dealii::parallel::distributed::Triangulation; - std::shared_ptr grid = std::make_shared( - MPI_COMM_WORLD, - typename dealii::Triangulation::MeshSmoothing( - dealii::Triangulation::smoothing_on_refinement | - dealii::Triangulation::smoothing_on_coarsening)); - dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); - grid->refine_global(0); - -//Warp the grid -//IF WANT NON-WARPED GRID COMMENT UNTIL SAYS "NOT COMMENT" -//#if 0 - dealii::GridTools::transform (&warp, *grid); - -// Assign a manifold to have curved geometry - const CurvManifold curv_manifold; - unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true - grid->reset_all_manifolds(); - grid->set_all_manifold_ids(manifold_id); - grid->set_manifold ( manifold_id, curv_manifold ); -//#endif -//"END COMMENT" TO NOT WARP GRID - - double surf_int = 0.0; - for(unsigned int poly_degree = 2; poly_degree<6; poly_degree++){ - unsigned int grid_degree = poly_degree; - //setup operator - OPERATOR::OperatorBase operators(&all_parameters_new, poly_degree, poly_degree, grid_degree); -//setup DG - // std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, grid); - std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); - dg->allocate_system (); - - - const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); - const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; - auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); - for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { - if (!current_cell->is_locally_owned()) continue; - - std::vector current_metric_dofs_indices(n_metric_dofs); - metric_cell->get_dof_indices (current_metric_dofs_indices); - std::vector> mapping_support_points(dim); - for(int idim=0; idimhigh_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); - const unsigned int istate = fe_metric.system_to_component_index(idof).first; - const unsigned int ishape = fe_metric.system_to_component_index(idof).second; - mapping_support_points[istate][ishape] = val; - } - - - const unsigned int n_quad_face_pts = operators.face_quadrature_collection[poly_degree].size(); - const std::vector &quad_weights = operators.face_quadrature_collection[poly_degree].get_weights (); - for (unsigned int iface=0; iface < dealii::GeometryInfo::faces_per_cell; ++iface) { - - std::vector> metric_cofactor(n_quad_face_pts); - for(unsigned int iquad=0; iquad determinant_Jacobian(n_quad_face_pts); - operators.build_local_face_metric_cofactor_matrix_and_det_Jac(grid_degree, poly_degree, iface, - n_quad_face_pts, n_metric_dofs / dim, mapping_support_points, - determinant_Jacobian, metric_cofactor); - const dealii::Tensor<1,dim,real> unit_normal_int = dealii::GeometryInfo::unit_normal_vector[iface]; - std::vector> normals_int(n_quad_face_pts); - for(unsigned int iquad=0; iquad 1e-13){ -// printf(" Metrics Do NOT Satisfy GCL Condition\n"); - pcout<<" Metrics Do NOT Satisfy GCL Condition\n"< -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "testing/tests.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include - -#include - -// Finally, we take our exact solution from the library as well as volume_quadrature -// and additional tools. -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "parameters/all_parameters.h" -#include "parameters/parameters.h" -#include "operators/operators.h" -#include "dg/dg.h" -#include "dg/dg_factory.hpp" - -const double TOLERANCE = 1E-6; -using namespace std; - - - -int main (int argc, char * argv[]) -{ - - dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); - using real = double; - using namespace PHiLiP; - std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; - const int dim = PHILIP_DIM; - const int nstate = 2; - dealii::ParameterHandler parameter_handler; - PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); - - PHiLiP::Parameters::AllParameters all_parameters_new; - all_parameters_new.parse_parameters (parameter_handler); - all_parameters_new.nstate = nstate; - dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); - - using FR_enum = Parameters::AllParameters::Flux_Reconstruction; - all_parameters_new.flux_reconstruction_type = FR_enum::cHU; -// all_parameters_new.overintegration = 2; - // const unsigned int overint= all_parameters_new.overintegration; - // all_parameters_new.use_collocated_nodes = true; - - // double skew_sym = 0.0; - double M_K_HU =0.0; - double max_dp1 = 0.0; - double deriv3_dif = 0.0; - double deriv4_dif = 0.0; - for(unsigned int poly_degree=2; poly_degree<6; poly_degree++){ - double left = 0.0; - double right = 1.0; - const bool colorize = true; - const unsigned int igrid= 2; - - - - //Generate a standard grid - -#if PHILIP_DIM==1 // dealii::parallel::distributed::Triangulation does not work for 1D - using Triangulation = dealii::Triangulation; - std::shared_ptr grid = std::make_shared( - typename dealii::Triangulation::MeshSmoothing( - dealii::Triangulation::smoothing_on_refinement | - dealii::Triangulation::smoothing_on_coarsening)); -#else - using Triangulation = dealii::parallel::distributed::Triangulation; - std::shared_ptr grid = std::make_shared( - MPI_COMM_WORLD, - typename dealii::Triangulation::MeshSmoothing( - dealii::Triangulation::smoothing_on_refinement | - dealii::Triangulation::smoothing_on_coarsening)); -#endif - dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); - grid->refine_global(igrid); - - OPERATOR::OperatorBase operators(&all_parameters_new, poly_degree, poly_degree, poly_degree); - - const unsigned int n_dofs = nstate * pow(poly_degree+1,dim); - // dealii::QGaussLobatto vol_quad_GLL (poly_degree+1+overint); - dealii::QGaussLobatto vol_quad_GLL (poly_degree+1); - const std::vector &quad_weights = vol_quad_GLL.get_weights (); -#if 0 -pcout<<"GLL"< 1e-12) - M_K_HU = std::abs(quad_weights[idof] - operators.local_mass[poly_degree][idof][idof2] + - operators.local_K_operator[poly_degree][idof][idof2]); - } - else{ - if(std::abs(operators.local_mass[poly_degree][idof][idof2] + - operators.local_K_operator[poly_degree][idof][idof2]) > 1e-12) - if(std::abs(operators.local_mass[poly_degree][idof][idof2] + - operators.local_K_operator[poly_degree][idof][idof2]) > M_K_HU) - M_K_HU = std::abs(operators.local_mass[poly_degree][idof][idof2] + - operators.local_K_operator[poly_degree][idof][idof2]); - } - } - } -#if 0 -pcout<<"MASS"< KD(n_dofs); - for(int idim=0; idim random_u(n_dofs); - for(unsigned int idof=0; idof KDu(n_dofs); - KD.vmult(KDu, random_u); - double uKDu = random_u * KDu; - if(std::abs(uKDu)>skew_sym) - skew_sym = std::abs(uKDu); - pcout<<"SKEW SYM "< Dp(n_dofs); - const unsigned int n_quad_pts = operators.volume_quadrature_collection[poly_degree].size(); - dealii::FullMatrix Dp1(n_quad_pts, n_dofs); - dealii::FullMatrix Dp2(n_quad_pts, n_dofs); - for(int idim=0; idim qpoint = operators.volume_quadrature_collection[poly_degree].point(iquad); - const int istate = operators.fe_collection_basis[poly_degree].system_to_component_index(idof).first; - dealii::Tensor<3, dim, real> deriv_3 = operators.fe_collection_basis[poly_degree].shape_3rd_derivative_component(idof,qpoint, istate); - if( std::abs(Dp2[iquad][idof]-deriv_3[idim][idim][idim])> deriv3_dif) - deriv3_dif = std::abs(Dp2[iquad][idof]-deriv_3[idim][idim][idim]); - } - } - } - if(poly_degree == 4){ - for(unsigned int idof=0; idof qpoint = operators.volume_quadrature_collection[poly_degree].point(iquad); - const int istate = operators.fe_collection_basis[poly_degree].system_to_component_index(idof).first; - dealii::Tensor<4, dim, real> deriv_4 = operators.fe_collection_basis[poly_degree].shape_4th_derivative_component(idof,qpoint, istate); - if( std::abs(Dp2[iquad][idof]-deriv_4[idim][idim][idim][idim])> deriv4_dif) - deriv4_dif = std::abs(Dp2[iquad][idof]-deriv_4[idim][idim][idim][idim]); - } - } - } - for(unsigned int idof=0; idofmax_dp1) - max_dp1 = Dp1[idof][idof2]; - } - } - } - - }//end of poly_degree loop - - // pcout<<" max p+1 derivative "<1e-7){ - pcout<<" One of the pth order derivatives is wrong !"<1e-11){ - pcout<<" 3rd order derivatives is wrong !"<1e-9){ - pcout<<" 4th order derivatives is wrong !"<1e-15){ - pcout<<" KHU does not recover Collocated GLL M+K mass matrix with exact integration !"< 1e-11){ - printf(" KD is not skew symmetric !\n"); - return 1; - } -#endif - else{ - return 0; - } - -}//end of main diff --git a/tests/unit_tests/operator_tests/chain_rule_test.cpp b/tests/unit_tests/operator_tests/chain_rule_test.cpp new file mode 100644 index 000000000..e15edc6ed --- /dev/null +++ b/tests/unit_tests/operator_tests/chain_rule_test.cpp @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "operators/operators.h" +#include "operators/operators_factory.hpp" +#include "dg/dg.h" +#include "dg/dg_factory.hpp" + +const double TOLERANCE = 1E-6; +using namespace std; + +int main (int argc, char * argv[]) +{ + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 1; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + all_parameters_new.nstate = nstate; + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + using FR_enum = Parameters::AllParameters::Flux_Reconstruction; + all_parameters_new.flux_reconstruction_type = FR_enum::cHU; + // all_parameters_new.overintegration = 2; + // const unsigned int overint= all_parameters_new.overintegration; + // all_parameters_new.use_collocated_nodes = true; + + double chain_rule = 0.0; + // loop poly degree + for(unsigned int poly_degree=6; poly_degree<7; poly_degree++){ + double left = 0.0; + double right = 1.0; + const bool colorize = true; + const unsigned int igrid= 2; + unsigned int q_degree = poly_degree + 2; + + //Generate a standard grid +#if PHILIP_DIM==1 // dealii::parallel::distributed::Triangulation does not work for 1D + using Triangulation = dealii::Triangulation; + std::shared_ptr grid = std::make_shared( + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#else + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#endif + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(igrid); + + // OPERATOR::OperatorsBase operators_p_q(&all_parameters_new, nstate, poly_degree + q_degree, poly_degree + q_degree, 1); + all_parameters_new.overintegration = q_degree; + // std::shared_ptr> operators_p = OPERATOR::OperatorsFactory::create_operators(&all_parameters_new, nstate, poly_degree, poly_degree, 1); + std::shared_ptr> operators_p = std::make_shared< OPERATOR::OperatorsBaseState >(&all_parameters_new, poly_degree, poly_degree); + // OPERATOR::OperatorsBase operators_p(&all_parameters_new, nstate, poly_degree, poly_degree, 1); + all_parameters_new.overintegration = poly_degree; + // OPERATOR::OperatorsBase operators_q(&all_parameters_new, nstate, q_degree, q_degree, 1); + std::shared_ptr> operators_q = std::make_shared< OPERATOR::OperatorsBaseState >(&all_parameters_new, q_degree, q_degree); + // std::shared_ptr> operators_q = OPERATOR::OperatorsFactory::create_operators(&all_parameters_new, nstate, q_degree, q_degree, 1); + + const unsigned int n_dofs_p = pow(poly_degree+1, dim); + const unsigned int n_dofs_q = pow(q_degree+1, dim); + const unsigned int n_dofs_p_q = pow(all_parameters_new.overintegration+q_degree+1, dim); + dealii::Vector u_node(n_dofs_p); + dealii::Vector v_node(n_dofs_q); + dealii::QGaussLobatto GLL_p (poly_degree+1); + dealii::QGaussLobatto GLL_q (q_degree+1); + for(unsigned int idof=0; idof qpoint = (fe_values_vol.quadrature_point(iquad)); + const dealii::Point qpoint = GLL_p.point(idof); + const double pi = atan(1)*4.0; + u_node[idof] = pow(std::sin(qpoint[0]*pi)+1.0,5); + } + for(unsigned int idof=0; idof qpoint = (fe_values_vol.quadrature_point(iquad)); + const dealii::Point qpoint = GLL_q.point(idof); + v_node[idof] = 2.0*pow(std::sin(qpoint[0]),3.0); + } + + dealii::Vector u_at_p_q_nodes(n_dofs_p_q); + dealii::Vector v_at_p_q_nodes(n_dofs_p_q); + operators_p->basis_at_vol_cubature[poly_degree].vmult(u_at_p_q_nodes, u_node); + operators_q->basis_at_vol_cubature[q_degree].vmult(v_at_p_q_nodes, v_node); + dealii::Vector Du_at_p_q_nodes(n_dofs_p_q); + dealii::Vector Dv_at_p_q_nodes(n_dofs_p_q); + operators_p->gradient_flux_basis[poly_degree][0][0].vmult(Du_at_p_q_nodes, u_at_p_q_nodes); + operators_q->gradient_flux_basis[q_degree][0][0].vmult(Dv_at_p_q_nodes, v_at_p_q_nodes); + dealii::Vector u_v_at_p_q_nodes(n_dofs_p_q); + dealii::Vector Du_v_at_p_q_nodes(n_dofs_p_q); + dealii::Vector u_Dv_at_p_q_nodes(n_dofs_p_q); + for(unsigned int idof=0; idof D_u_v_at_p_q_nodes(n_dofs_p_q); + operators_p->gradient_flux_basis[poly_degree][0][0].vmult(D_u_v_at_p_q_nodes, u_v_at_p_q_nodes); + + pcout<<" ABS difference"<chain_rule) + chain_rule = std::abs(D_u_v_at_p_q_nodes[idof]-(Du_v_at_p_q_nodes[idof]+u_Dv_at_p_q_nodes[idof])); + } + pcout<<" Derivative of (u times v)"<1e-11){ + pcout<<" chain rule not satisfied !"< +#include +#include +#include +#include +#include +#include +#include + +//#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "operators/operators.h" + +const double TOLERANCE = 1E-6; +using namespace std; + + +int main (int argc, char * argv[]) +{ + + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + bool different = false; + const unsigned int poly_max = 6; + const unsigned int poly_min = 2; + for(unsigned int poly_degree=poly_min; poly_degree stiffness(1, poly_degree, 1); + PHiLiP::OPERATOR::local_mass mass(1, poly_degree, 1); + dealii::QGauss<1> quad1D (poly_degree+1); + const dealii::FE_DGQArbitraryNodes<1> fe_dg(quad1D); + const dealii::FESystem<1,1> fe_system(fe_dg, 1); + stiffness.build_1D_volume_operator(fe_system,quad1D); + mass.build_1D_volume_operator(fe_system,quad1D); + const std::vector &quad_weights_1D = quad1D.get_weights(); + + const unsigned int n_dofs = pow(poly_degree+1,dim); + const unsigned int n_quad_pts_1D = quad1D.size(); + const unsigned int n_quad_pts = pow(n_quad_pts_1D, dim); + + assert(n_quad_pts==n_dofs);//since checking for flux basis + + //build dim-sized stiffness operator + dealii::FullMatrix stiffness_dim(n_quad_pts);//solution of A*u with sum-factorization + stiffness_dim = stiffness.tensor_product(stiffness.oneD_vol_operator, mass.oneD_vol_operator, mass.oneD_vol_operator); + + //random solution vector + std::vector sol_hat(n_dofs); + for(unsigned int idof=0; idof (rand()) / ( static_cast (RAND_MAX/(30-1e-8))) ); + } + + //random solution matrix + dealii::FullMatrix sol_hat_mat(n_quad_pts); + for(unsigned int idof=0; idof sol_dim(n_quad_pts);//solution of A*u normally + for(unsigned int idof=0; idof sol_1D(n_quad_pts);//solution of A*u normally + //use a sum-factorization "type" algorithm with matrix structure for Hadamard product + stiffness.two_pt_flux_Hadamard_product(sol_hat_mat, sol_1D, stiffness.oneD_vol_operator, quad_weights_1D, 0); + + //compare that got same answer + for(unsigned int iquad=0; iquad1e-11){ + pcout<<"Dir 0 sol dim "<1){ + //dir = 1 (y-direction) + stiffness_dim = stiffness.tensor_product(mass.oneD_vol_operator, stiffness.oneD_vol_operator, mass.oneD_vol_operator); + for(unsigned int idof=0; idof1e-11){ + pcout<<"Dir 1 sol dim "<1e-11){ + pcout<<"Dir 2 sol dim "< +#include +#include +#include +#include +#include +#include +#include + +//#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "operators/operators.h" + +const double TOLERANCE = 1E-6; +using namespace std; + + +int main (int argc, char * argv[]) +{ + + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + bool different = false; + const unsigned int poly_max = 6; + const unsigned int poly_min = 2; + for(unsigned int poly_degree=poly_min; poly_degree basis(1, poly_degree, 1); + PHiLiP::OPERATOR::local_mass mass(1, poly_degree, 1); + dealii::QGauss<1> quad1D (poly_degree+1); + dealii::QGauss<0> quad1D_surf (poly_degree+1); + const dealii::FE_DGQArbitraryNodes<1> fe_dg(quad1D); + const dealii::FESystem<1,1> fe_system(fe_dg, 1); + basis.build_1D_surface_operator(fe_system,quad1D_surf); + mass.build_1D_volume_operator(fe_system,quad1D); + const std::vector &quad_weights_1D = quad1D.get_weights(); + + // const unsigned int n_dofs = pow(poly_degree+1,dim); + const unsigned int n_quad_pts_1D = quad1D.size(); + const unsigned int n_quad_pts = pow(n_quad_pts_1D, dim); + const unsigned int n_face_quad_pts = pow(n_quad_pts_1D, dim-1); + + assert(n_quad_pts==n_dofs);//since checking for flux basis + + //build dim-sized stiffness operator + dealii::FullMatrix surf_oper_dim(n_face_quad_pts, n_quad_pts);//solution of A*u with sum-factorization + surf_oper_dim = basis.tensor_product(basis.oneD_surf_operator[0], mass.oneD_vol_operator, mass.oneD_vol_operator); + + //random solution vector + std::vector sol_hat(n_quad_pts); + for(unsigned int idof=0; idof (rand()) / ( static_cast (RAND_MAX/(30-1e-8))) ); + } + + //random solution matrix + dealii::FullMatrix sol_hat_mat(n_face_quad_pts, n_quad_pts); + for(unsigned int idof=0; idof sol_dim(n_face_quad_pts, n_quad_pts);//solution of A*u normally + for(unsigned int idof=0; idof sol_1D(n_face_quad_pts, n_quad_pts);//solution of A*u normally + //use a sum-factorization "type" algorithm with matrix structure for Hadamard product + basis.two_pt_flux_Hadamard_product(sol_hat_mat, sol_1D, basis.oneD_surf_operator[0], quad_weights_1D, 0); + + //compare that got same answer + for(unsigned int iquad=0; iquad1e-11){ + pcout<<"Dir 0 sol dim "< sol_vol(n_quad_pts); + std::vector sol_surf(n_face_quad_pts); + basis.surface_two_pt_flux_Hadamard_product(sol_hat_mat, sol_vol, sol_surf, quad_weights_1D, basis.oneD_surf_operator, 0, 0, 1.0); + + std::vector sol_vol_exact(n_quad_pts); + std::vector sol_surf_exact(n_face_quad_pts); + for(unsigned int iquad=0; iquad1e-11){ + pcout<<"surf not same in 2pt"<1e-11){ + pcout<<"vol not same in 2pt"<1){ + //dir = 1 (y-direction) + surf_oper_dim = basis.tensor_product(mass.oneD_vol_operator, basis.oneD_surf_operator[0], mass.oneD_vol_operator); + for(unsigned int idof=0; idof1e-11){ + pcout<<"Dir 1 sol dim "<1e-11){ + pcout<<"Dir 1 surf not same in 2pt"<1e-11){ + pcout<<"Dir 1 vol not same in 2pt"<1e-11){ + pcout<<"Dir 2 sol dim "<1e-11){ + pcout<<"Dir 2 surf not same in 2pt"<1e-11){ + pcout<<"Dir 2 vol not same in 2pt"< #include -#include // Finally, we take our exact solution from the library as well as volume_quadrature // and additional tools. @@ -51,6 +50,8 @@ #include #include +#include + #include "parameters/all_parameters.h" #include "parameters/parameters.h" #include "operators/operators.h" @@ -70,7 +71,7 @@ int main (int argc, char * argv[]) using namespace PHiLiP; std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; const int dim = PHILIP_DIM; - const int nstate = 2; + const int nstate = 1; dealii::ParameterHandler parameter_handler; PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); @@ -81,16 +82,15 @@ int main (int argc, char * argv[]) using FR_enum = Parameters::AllParameters::Flux_Reconstruction; all_parameters_new.flux_reconstruction_type = FR_enum::cHU; + // all_parameters_new.use_collocated_nodes=true; + all_parameters_new.overintegration = 2; double left = 0.0; double right = 1.0; const bool colorize = true; const unsigned int igrid= 2; - - //Generate a standard grid - #if PHILIP_DIM==1 // dealii::parallel::distributed::Triangulation does not work for 1D using Triangulation = dealii::Triangulation; std::shared_ptr grid = std::make_shared( @@ -105,66 +105,61 @@ int main (int argc, char * argv[]) dealii::Triangulation::smoothing_on_refinement | dealii::Triangulation::smoothing_on_coarsening)); #endif - dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); - grid->refine_global(igrid); + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(igrid); double max_dif_int_parts = 0.0; for(unsigned int poly_degree=2; poly_degree<6; poly_degree++){ - - - OPERATOR::OperatorBase operators(&all_parameters_new, poly_degree, poly_degree, poly_degree); - - const unsigned int n_dofs = operators.fe_collection_basis[poly_degree].dofs_per_cell; - std::vector> vol_int_parts(dim); - std::vector> face_int_parts(dim); - for(int idim=0; idim quad1D (poly_degree+1); + const dealii::FE_DGQ<1> fe_dg(poly_degree); + const dealii::FESystem<1,1> fe_system(fe_dg, nstate); + const dealii::FE_DGQArbitraryNodes<1> fe_dg_flux(quad1D); + const dealii::FESystem<1,1> fe_system_flux(fe_dg_flux, nstate); + PHiLiP::OPERATOR::vol_integral_gradient_basis vol_int_grad_basis(nstate, poly_degree, 1); + vol_int_grad_basis.build_1D_gradient_operator(fe_system, quad1D); + PHiLiP::OPERATOR::local_flux_basis_stiffness flux_stiffness(poly_degree, 1); + flux_stiffness.build_1D_gradient_state_operator(fe_system_flux, quad1D); + flux_stiffness.build_1D_volume_state_operator(fe_system, quad1D); + + // PHiLiP::OPERATOR::basis_functions_state flux_basis_quad(poly_degree, 1); + PHiLiP::OPERATOR::flux_basis_functions_state flux_basis_quad(poly_degree, 1); + flux_basis_quad.build_1D_volume_state_operator(fe_system_flux, quad1D); + + dealii::FullMatrix vol_int_parts(n_dofs_1D); + vol_int_grad_basis.oneD_grad_operator.Tmmult(vol_int_parts, flux_basis_quad.oneD_vol_state_operator[0]); + vol_int_parts.add(1.0, flux_stiffness.oneD_vol_state_operator[0]); + + // compute surface integral + dealii::QGauss<0> face_quad1D (poly_degree+1); + dealii::FullMatrix surf_int_parts(n_dofs_1D); + flux_basis_quad.build_1D_surface_state_operator(fe_system_flux, face_quad1D); + PHiLiP::OPERATOR::face_integral_basis surf_int_basis(nstate, poly_degree, 1); + surf_int_basis.build_1D_surface_operator(fe_system, face_quad1D); + for(unsigned int iface=0; iface< dealii::GeometryInfo<1>::faces_per_cell; iface++){ + const dealii::Tensor<1,1,real> unit_normal_1D = dealii::GeometryInfo<1>::unit_normal_vector[iface]; + dealii::FullMatrix surf_int_face(n_dofs_1D); + surf_int_basis.oneD_surf_operator[iface].Tmmult(surf_int_face, flux_basis_quad.oneD_surf_state_operator[0][iface]); + surf_int_parts.add(unit_normal_1D[0], surf_int_face); } - - const unsigned int n_quad_face_pts = operators.face_quadrature_collection[poly_degree].size(); - for(unsigned int iface=0; iface< dealii::GeometryInfo::faces_per_cell; iface++){ - const dealii::Tensor<1,dim,real> unit_normal = dealii::GeometryInfo::unit_normal_vector[iface]; - int jdim=0; - for(int idim=0; idimmax_dif_int_parts) - max_dif_int_parts = std::abs(face_int_parts[idim][idof][idof2] - vol_int_parts[idim][idof][idof2]); - } + // check difference between the two for integration-by-parts + for(unsigned int idof=0; idofmax_dif_int_parts) + max_dif_int_parts = std::abs(surf_int_parts[idof][idof2] - vol_int_parts[idof][idof2]); } - } - + } }//end of poly_degree loop const double max_dif_int_parts_mpi= (dealii::Utilities::MPI::max(max_dif_int_parts, MPI_COMM_WORLD)); - if( max_dif_int_parts_mpi >1e-7){ + + pcout<<"max dif "<1e-12){ pcout<<" Surface operator not satisfy integration by parts !"< +#include +#include +#include +#include +#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "dg/dg.h" +#include +#include +#include "dg/dg_factory.hpp" +#include "operators/operators.h" +#include "mesh/grids/nonsymmetric_curved_periodic_grid.hpp" +#include "physics/initial_conditions/set_initial_condition.h" +#include "physics/initial_conditions/initial_condition_function.h" + +const double TOLERANCE = 1E-6; +using namespace std; +//namespace PHiLiP { + +int main (int argc, char * argv[]) +{ + + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + using FlowCaseEnum = Parameters::FlowSolverParam::FlowCaseType; + all_parameters_new.flow_solver_param.flow_case_type = FlowCaseEnum::taylor_green_vortex; + all_parameters_new.use_inverse_mass_on_the_fly = true; + using FR_enum = Parameters::AllParameters::Flux_Reconstruction; + all_parameters_new.flux_reconstruction_type = FR_enum::cPlus; + all_parameters_new.use_weak_form = false; + using PDE_enum = Parameters::AllParameters::PartialDifferentialEquation; + all_parameters_new.pde_type = PDE_enum::navier_stokes; + + bool different = false; + for(unsigned int grid_type=0; grid_type<2; grid_type++){ + //Generate a standard grid + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); + + const unsigned int n_refinements = 2; + const unsigned int poly_degree = 3; + + // set the warped grid + const unsigned int grid_degree = (grid_type == 1) ? poly_degree : 1; + if(grid_type == 1){ + PHiLiP::Grids::nonsymmetric_curved_grid(*grid, n_refinements); + } + + if(grid_type == 0){ + double left = 0.0; + double right = 2 * dealii::numbers::PI; + const bool colorize = true; + dealii::GridGenerator::hyper_cube(*grid, left, right, colorize); + std::vector::cell_iterator> > matched_pairs; + dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs); + dealii::GridTools::collect_periodic_faces(*grid,2,3,1,matched_pairs); + if constexpr(PHILIP_DIM == 3) + dealii::GridTools::collect_periodic_faces(*grid,4,5,2,matched_pairs); + grid->add_periodicity(matched_pairs); + grid->refine_global(n_refinements); + } + + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); + //initialize IC + //set solution as some random number between [1e-8,30] at each dof + //loop over cells as to write only to local solution indices + const unsigned int n_dofs = dg->dof_handler.get_fe_collection().max_dofs_per_cell(); + std::vector current_dofs_indices(n_dofs); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell) { + if (!current_cell->is_locally_owned()) continue; + current_cell->get_dof_indices (current_dofs_indices); + for(unsigned int i=0; isolution[current_dofs_indices[i]] = 1e-8 + static_cast (rand()) / ( static_cast (RAND_MAX/(30-1e-8))); + } + } + dg->solution.update_ghost_values(); + + dealii::LinearAlgebra::distributed::Vector mass_matrix_times_solution(dg->right_hand_side); + dg->apply_global_mass_matrix(dg->solution,mass_matrix_times_solution); + dealii::LinearAlgebra::distributed::Vector mass_inv_mass_matrix_times_solution(dg->right_hand_side); + dg->apply_inverse_global_mass_matrix(mass_matrix_times_solution, mass_inv_mass_matrix_times_solution); //rk_stage[i] = IMM*RHS = F(u_n + dt*sum(a_ij*k_j)) + mass_inv_mass_matrix_times_solution.update_ghost_values(); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell) { + if (!current_cell->is_locally_owned()) continue; + current_cell->get_dof_indices (current_dofs_indices); + for(unsigned int i=0; isolution[current_dofs_indices[i]] - mass_inv_mass_matrix_times_solution[current_dofs_indices[i]])>1e-12){ + different = true; + std::cout<solution[current_dofs_indices[i]]<<" i "< +#include +#include +#include +#include +#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "dg/dg.h" +#include +#include +#include "dg/dg_factory.hpp" +#include "operators/operators.h" +#include "mesh/grids/nonsymmetric_curved_periodic_grid.hpp" + +const double TOLERANCE = 1E-6; +using namespace std; +//namespace PHiLiP { + +int main (int argc, char * argv[]) +{ + + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + + //Generate a standard grid + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); + + bool mapping_supp_match = true; + const unsigned int n_refinements = 1; + for(unsigned int poly_degree = 5; poly_degree<6; poly_degree++){ + + // set the warped grid + const unsigned int grid_degree = poly_degree; + PHiLiP::Grids::nonsymmetric_curved_grid(*grid, n_refinements); + + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); + + const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + const unsigned int n_grid_nodes = n_metric_dofs / dim; + auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + std::vector current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + std::array,dim> mapping_support_points_new; + for(int idim=0; idimhigh_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + mapping_support_points[istate][igrid_node] += val * fe_metric.shape_value_component(idof,dg->high_order_grid->dim_grid_nodes.point(igrid_node),istate); + } + } + //get index renumbering from FE_Q->FE_DGQ + const std::vector &index_renumbering = dealii::FETools::hierarchic_to_lexicographic_numbering(poly_degree); + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const unsigned int idim = fe_metric.system_to_component_index(idof).first; + const unsigned int ishape = fe_metric.system_to_component_index(idof).second; + const unsigned int igrid_node = index_renumbering[ishape]; + const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); + mapping_support_points_new[idim][igrid_node] = val; + } + for(int idim =0; idim1e-12){ + std::cout<<"original "< +#include +#include +#include +#include +#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "dg/dg.h" +#include +#include +#include "dg/dg_factory.hpp" +#include "operators/operators.h" +//#include + +const double TOLERANCE = 1E-6; +using namespace std; +//namespace PHiLiP { + + +template +class CurvManifold: public dealii::ChartManifold { + virtual dealii::Point pull_back(const dealii::Point &space_point) const override; ///< See dealii::Manifold. + virtual dealii::Point push_forward(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + virtual dealii::DerivativeForm<1,dim,dim> push_forward_gradient(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + + virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. +}; +template +dealii::Point CurvManifold::pull_back(const dealii::Point &space_point) const +{ + using namespace PHiLiP; + const double pi = atan(1)*4.0; + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim function(dim); + dealii::FullMatrix derivative(dim); + double beta =1.0/10.0; + double alpha =1.0/10.0; + int flag =0; + while(flag != dim){ + if(dim==2){ + function[0] = x_ref[0] - x_phys[0] +beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function[1] = x_ref[1] - x_phys[1] +beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function[0] = x_ref[0] - x_phys[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function[1] = x_ref[1] - x_phys[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function[2] = x_ref[2] - x_phys[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + + + if(dim==2){ + derivative[0][0] = 1.0 - beta* pi/2.0 * std::sin(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + derivative[0][1] = - beta*3.0 *pi/2.0 * std::cos(pi/2.0*x_ref[0])*std::sin(3.0*pi/2.0*x_ref[1]); + + derivative[1][0] = beta*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + derivative[1][1] = 1.0 -beta*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1]); + } + else{ + derivative[0][0] = 1.0; + derivative[0][1] = - alpha*pi*std::sin(pi*x_ref[1]); + derivative[0][2] = - alpha*pi*std::sin(pi*x_ref[2]); + + derivative[1][0] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[0]); + derivative[1][1] = 1.0 -alpha*exp(1.0-x_ref[1])*(std::sin(pi*x_ref[0])+std::sin(pi*x_ref[2])); + derivative[1][2] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[2]); + derivative[2][0] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[0]); + derivative[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[1]); + derivative[2][2] = 1.0; + } + + dealii::FullMatrix Jacobian_inv(dim); + Jacobian_inv.invert(derivative); + dealii::Vector Newton_Step(dim); + Jacobian_inv.vmult(Newton_Step, function); + for(int idim=0; idim function_check(dim); + if(dim==2){ + function_check[0] = x_ref[0] + beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function_check[1] = x_ref[1] + beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function_check[0] = x_ref[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function_check[1] = x_ref[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function_check[2] = x_ref[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + std::vector error(dim); + for(int idim=0; idim 1e-13) { + std::cout << "Large error " << error[0] << std::endl; + for(int idim=0;idim +dealii::Point CurvManifold::push_forward(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim (x_phys); // Trigonometric +} + +template +dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + dealii::DerivativeForm<1, dim, dim> dphys_dref; + double beta = 1.0/10.0; + double alpha = 1.0/10.0; + dealii::Point x_ref; + for(int idim=0; idim +std::unique_ptr > CurvManifold::clone() const +{ + return std::make_unique>(); +} + +template +static dealii::Point warp (const dealii::Point &p) +{ + const double pi = atan(1)*4.0; + dealii::Point q = p; + + double beta =1.0/10.0; + double alpha =1.0/10.0; + if (dim == 2){ + q[dim-2] =p[dim-2] + beta*std::cos(pi/2.0 * p[dim-2]) * std::cos(3.0 * pi/2.0 * p[dim-1]); + q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); + } + if(dim==3){ + q[0] =p[0] + alpha*(std::cos(pi * p[2]) + std::cos(pi * p[1])); + q[1] =p[1] + alpha*exp(1.0-p[1])*(std::sin(pi * p[0]) + std::sin(pi* p[2])); + q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * p[0]) + std::sin(2.0 * pi * p[1])); + } + + return q; +} + +/**************************** + * End of Curvilinear Grid + * ***************************/ + +int main (int argc, char * argv[]) +{ + + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 1; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + + double left = 0.0; + double right = 1.0; + const bool colorize = true; + //Generate a standard grid + + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(3); + +//Warp the grid +// dealii::GridGenerator::hyper_cube(*grid, left, right, true); +// grid->refine_global(3); +//IF WANT NON-WARPED GRID COMMENT UNTIL SAYS "NOT COMMENT" + dealii::GridTools::transform (&warp, *grid); + +// Assign a manifold to have curved geometry + const CurvManifold curv_manifold; + unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true + grid->reset_all_manifolds(); + grid->set_all_manifold_ids(manifold_id); + grid->set_manifold ( manifold_id, curv_manifold ); +//"END COMMENT" TO NOT WARP GRID + bool det_Jac_neg = false; + bool det_match = true; + for(unsigned int poly_degree = 2; poly_degree<3; poly_degree++){ + unsigned int grid_degree = poly_degree; + + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); + + dealii::QGaussLobatto<1> grid_quad(grid_degree +1); + const dealii::FE_DGQ<1> fe_grid(grid_degree); + const dealii::FESystem<1,1> fe_sys_grid(fe_grid, nstate); + dealii::QGauss<1> flux_quad(poly_degree +1); + dealii::QGauss<0> flux_quad_face(poly_degree +1); + + PHiLiP::OPERATOR::mapping_shape_functions mapping_basis(nstate,poly_degree,grid_degree); + mapping_basis.build_1D_shape_functions_at_grid_nodes(fe_sys_grid, grid_quad); + mapping_basis.build_1D_shape_functions_at_flux_nodes(fe_sys_grid, flux_quad, flux_quad_face); + + const unsigned int n_quad_pts = pow(poly_degree+1,dim); + + const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + std::vector current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + for(int idim=0; idim vol_GLL(grid_degree +1); + for (unsigned int igrid_node = 0; igrid_node< n_metric_dofs/dim; ++igrid_node) { + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + mapping_support_points[istate][igrid_node] += val * fe_metric.shape_value_component(idof,vol_GLL.point(igrid_node),istate); + } + } + + PHiLiP::OPERATOR::metric_operators metric_oper(nstate,poly_degree,grid_degree); + metric_oper.build_volume_metric_operators( + n_quad_pts, n_metric_dofs/dim, + mapping_support_points, + mapping_basis, + false); + + for(unsigned int iquad=0; iquad fe_values(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], dg->volume_quadrature_collection[poly_degree], dealii::update_JxW_values); + fe_values.reinit(current_cell); + const std::vector &quad_weights = dg->volume_quadrature_collection[poly_degree].get_weights(); + for(unsigned int iquad=0; iquad1e-13) + det_match = false; + } + + + } + + }//end poly degree loop + + if( det_Jac_neg){ + pcout<<" Metrics give negative determinant of Jacobian\n"< +#include +#include +#include +#include +#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "dg/dg.h" +#include +#include +#include "dg/dg_factory.hpp" +#include "operators/operators.h" +//#include + +const double TOLERANCE = 1E-6; +using namespace std; +//namespace PHiLiP { + +template +class CurvManifold: public dealii::ChartManifold { + virtual dealii::Point pull_back(const dealii::Point &space_point) const override; ///< See dealii::Manifold. + virtual dealii::Point push_forward(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + virtual dealii::DerivativeForm<1,dim,dim> push_forward_gradient(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + + virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. +}; + +template +dealii::Point CurvManifold::pull_back(const dealii::Point &space_point) const +{ + using namespace PHiLiP; + const double pi = atan(1)*4.0; + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim function(dim); + dealii::FullMatrix derivative(dim); + double beta =1.0/10.0; + double alpha =1.0/10.0; + int flag =0; + while(flag != dim){ + if(dim==2){ + function[0] = x_ref[0] - x_phys[0] +beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function[1] = x_ref[1] - x_phys[1] +beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function[0] = x_ref[0] - x_phys[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function[1] = x_ref[1] - x_phys[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function[2] = x_ref[2] - x_phys[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + + + if(dim==2){ + derivative[0][0] = 1.0 - beta* pi/2.0 * std::sin(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + derivative[0][1] = - beta*3.0 *pi/2.0 * std::cos(pi/2.0*x_ref[0])*std::sin(3.0*pi/2.0*x_ref[1]); + + derivative[1][0] = beta*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + derivative[1][1] = 1.0 -beta*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1]); + } + else{ + derivative[0][0] = 1.0; + derivative[0][1] = - alpha*pi*std::sin(pi*x_ref[1]); + derivative[0][2] = - alpha*pi*std::sin(pi*x_ref[2]); + + derivative[1][0] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[0]); + derivative[1][1] = 1.0 -alpha*exp(1.0-x_ref[1])*(std::sin(pi*x_ref[0])+std::sin(pi*x_ref[2])); + derivative[1][2] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[2]); + derivative[2][0] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[0]); + derivative[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[1]); + derivative[2][2] = 1.0; + } + + dealii::FullMatrix Jacobian_inv(dim); + Jacobian_inv.invert(derivative); + dealii::Vector Newton_Step(dim); + Jacobian_inv.vmult(Newton_Step, function); + for(int idim=0; idim function_check(dim); + if(dim==2){ + function_check[0] = x_ref[0] + beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function_check[1] = x_ref[1] + beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function_check[0] = x_ref[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function_check[1] = x_ref[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function_check[2] = x_ref[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + std::vector error(dim); + for(int idim=0; idim 1e-13) { + std::cout << "Large error " << error[0] << std::endl; + for(int idim=0;idim +dealii::Point CurvManifold::push_forward(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim (x_phys); // Trigonometric +} + +template +dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + dealii::DerivativeForm<1, dim, dim> dphys_dref; + double beta = 1.0/10.0; + double alpha = 1.0/10.0; + dealii::Point x_ref; + for(int idim=0; idim +std::unique_ptr > CurvManifold::clone() const +{ + return std::make_unique>(); +} + +template +static dealii::Point warp (const dealii::Point &p) +{ + const double pi = atan(1)*4.0; + dealii::Point q = p; + + double beta =1.0/10.0; + double alpha =1.0/10.0; + if (dim == 2){ + q[dim-2] =p[dim-2] + beta*std::cos(pi/2.0 * p[dim-2]) * std::cos(3.0 * pi/2.0 * p[dim-1]); + q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); + } + if(dim==3){ + q[0] =p[0] + alpha*(std::cos(pi * p[2]) + std::cos(pi * p[1])); + q[1] =p[1] + alpha*exp(1.0-p[1])*(std::sin(pi * p[0]) + std::sin(pi* p[2])); + q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * p[0]) + std::sin(2.0 * pi * p[1])); + } + + return q; +} + +/**************************** + * End of Curvilinear Grid + * ***************************/ + +int main (int argc, char * argv[]) +{ + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 1; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + + all_parameters_new.use_curvilinear_split_form=true; + const int dim_check = 1; + + double left = 0.0; + double right = 1.0; + const bool colorize = true; + dealii::ConvergenceTable convergence_table; + const unsigned int igrid_start = 2; + const unsigned int n_grids = 5; + std::array grid_size; + std::array soln_error; + std::array soln_error_inf; + // loop poly degree + for(unsigned int poly_degree = 2; poly_degree<5; poly_degree++){ + unsigned int grid_degree = poly_degree; + for(unsigned int igrid=igrid_start; igrid; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(igrid); + pcout<<" made grid for Index"<, *grid); + + // Assign a manifold to have curved geometry + const CurvManifold curv_manifold; + unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true + grid->reset_all_manifolds(); + grid->set_all_manifold_ids(manifold_id); + grid->set_manifold ( manifold_id, curv_manifold ); + //"END COMMENT" TO NOT WARP GRID + + //setup operator + OPERATOR::OperatorsBaseState operators(&all_parameters_new, poly_degree, poly_degree); + //setup DG + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); + + dealii::IndexSet locally_owned_dofs; + dealii::IndexSet ghost_dofs; + dealii::IndexSet locally_relevant_dofs; + locally_owned_dofs = dg->dof_handler.locally_owned_dofs(); + dealii::DoFTools::extract_locally_relevant_dofs(dg->dof_handler, ghost_dofs); + locally_relevant_dofs = ghost_dofs; + ghost_dofs.subtract_set(locally_owned_dofs); + dealii::LinearAlgebra::distributed::Vector solution_deriv; + solution_deriv.reinit(locally_owned_dofs, ghost_dofs, MPI_COMM_WORLD); + //setup metric and solve + + const unsigned int max_dofs_per_cell = dg->dof_handler.get_fe_collection().max_dofs_per_cell(); + std::vector current_dofs_indices(max_dofs_per_cell); + const unsigned int n_dofs_cell = dg->operators->fe_collection_basis[poly_degree].dofs_per_cell; + const unsigned int n_quad_pts = dg->operators->volume_quadrature_collection[poly_degree].size(); + + const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + std::vector current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + std::vector> phys_quad_pts(dim); + for(int idim=0; idim vol_GLL(grid_degree +1); + for (unsigned int igrid_node = 0; igrid_node< n_metric_dofs/dim; ++igrid_node) { + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + mapping_support_points[istate][igrid_node] += val * fe_metric.shape_value_component(idof,vol_GLL.point(igrid_node),istate); + } + } + std::vector> metric_cofactor(n_quad_pts); + std::vector determinant_Jacobian(n_quad_pts); + for(unsigned int iquad=0;iquad,dim>,nstate> physical_gradient; + for(unsigned int istate=0; istateget_dof_indices (current_dofs_indices); + for(int idim=0; idim soln(n_quad_pts); + for(unsigned int iquad=0; iquad soln_derivative_x(n_quad_pts); + for(int istate=0; istate quad_extra(poly_degree+1+overintegrate); + dealii::FEValues fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->operators->fe_collection_basis[poly_degree], quad_extra, + dealii::update_values | dealii::update_JxW_values | + dealii::update_jacobians | + dealii::update_quadrature_points | dealii::update_inverse_jacobians); + const unsigned int n_quad_pts_extra = fe_values_extra.n_quadrature_points; + std::vector dofs_indices (fe_values_extra.dofs_per_cell); + dealii::Vector soln_at_q(n_quad_pts_extra); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell) { + if (!current_cell->is_locally_owned()) continue; + fe_values_extra.reinit(current_cell); + dofs_indices.resize(fe_values_extra.dofs_per_cell); + current_cell->get_dof_indices (dofs_indices); + + for (unsigned int iquad=0; iquad qpoint = (fe_values_extra.quadrature_point(iquad)); + double uexact_x=1.0; + for(int idim=0; idim linf_error){ + linf_error = inf_temp; + } + } + + }//end cell loop + pcout<<"got OOA here"<n_global_active_cells(); + const double l2error_mpi_sum = std::sqrt(dealii::Utilities::MPI::sum(l2error, MPI_COMM_WORLD)); + const double linferror_mpi= (dealii::Utilities::MPI::max(linf_error, MPI_COMM_WORLD)); + // Convergence table + const unsigned int n_dofs = dg->dof_handler.n_dofs(); + const double dx = 1.0/pow(n_dofs,(1.0/dim)); + grid_size[igrid] = dx; + soln_error[igrid] = l2error_mpi_sum; + soln_error_inf[igrid] = linferror_mpi; + + convergence_table.add_value("p", poly_degree); + convergence_table.add_value("cells", n_global_active_cells); + convergence_table.add_value("DoFs", n_dofs); + convergence_table.add_value("dx", dx); + convergence_table.add_value("soln_L2_error", l2error_mpi_sum); + convergence_table.add_value("soln_Linf_error", linferror_mpi); + + pcout << " Grid size h: " << dx + << " L2-soln_error: " << l2error_mpi_sum + << " Linf-soln_error: " << linferror_mpi + << std::endl; + + if (igrid > igrid_start) { + const double slope_soln_err = log(soln_error[igrid]/soln_error[igrid-1]) + / log(grid_size[igrid]/grid_size[igrid-1]); + const double slope_soln_err_inf = log(soln_error_inf[igrid]/soln_error_inf[igrid-1]) + / log(grid_size[igrid]/grid_size[igrid-1]); + pcout << "From grid " << igrid-1 + << " to grid " << igrid + << " dimension: " << dim + << " polynomial degree p: " << poly_degree + << std::endl + << " solution_error1 " << soln_error[igrid-1] + << " solution_error2 " << soln_error[igrid] + << " slope " << slope_soln_err + << " solution_error1_inf " << soln_error_inf[igrid-1] + << " solution_error2_inf " << soln_error_inf[igrid] + << " slope " << slope_soln_err_inf + << std::endl; + } + }//end grid refinement loop + + const int igrid = n_grids-1; + const double slope_soln_err = log(soln_error[igrid]/soln_error[igrid-1]) + / log(grid_size[igrid]/grid_size[igrid-1]); + if(std::abs(slope_soln_err-poly_degree)>0.05){ + return 1; + } + pcout << " ********************************************" + << std::endl + << " Convergence rates for p = " << poly_degree + << std::endl + << " ********************************************" + << std::endl; + convergence_table.evaluate_convergence_rates("soln_L2_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim); + convergence_table.evaluate_convergence_rates("soln_Linf_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim); + convergence_table.set_scientific("dx", true); + convergence_table.set_scientific("soln_L2_error", true); + convergence_table.set_scientific("soln_Linf_error", true); + if (pcout.is_active()) convergence_table.write_text(pcout.get_stream()); + }//end poly degree loop +}// end of main diff --git a/tests/unit_tests/operator_tests/sum_factorization_Hadamard_test.cpp b/tests/unit_tests/operator_tests/sum_factorization_Hadamard_test.cpp new file mode 100644 index 000000000..aa0c8f200 --- /dev/null +++ b/tests/unit_tests/operator_tests/sum_factorization_Hadamard_test.cpp @@ -0,0 +1,374 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +//#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "operators/operators.h" + +const double TOLERANCE = 1E-6; +using namespace std; + + +int main (int argc, char * argv[]) +{ + + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 1; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + all_parameters_new.nstate = nstate; + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + bool different = false; + bool different_mass = false; + const unsigned int poly_max = 16; + const unsigned int poly_min = 2; + std::array time_diff; + std::array time_diff_sum; + std::array time_deriv_sum_cons; + std::array time_diff_dir2; + std::array time_diff_sum_dir2; + std::array time_diff_dir3; + std::array time_diff_sum_dir3; + for(unsigned int poly_degree=poly_min; poly_degree basis(nstate,poly_degree, 1); + dealii::QGauss<1> quad1D (poly_degree+1); + const dealii::FE_DGQArbitraryNodes<1> fe_dg(quad1D); + const dealii::FESystem<1,1> fe_system(fe_dg, 1); + basis.build_1D_volume_operator(fe_system,quad1D); + basis.build_1D_gradient_operator(fe_system,quad1D); + + const unsigned int n_dofs = nstate * pow(poly_degree+1,dim); + const unsigned int n_dofs_1D = nstate * (poly_degree+1); + const unsigned int n_quad_pts_1D = quad1D.size(); + const unsigned int n_quad_pts = pow(n_quad_pts_1D, dim); + + std::vector ones(n_quad_pts_1D, 1.0);//to be used as the weights + + for(unsigned int ielement=0; ielement<10; ielement++){//do several loops as if there were elements + + std::vector sol_hat(n_dofs); + for(unsigned int idof=0; idof (rand()) / ( static_cast (RAND_MAX/(30-1e-8))) ); + } + + dealii::FullMatrix sol_hat_mat(n_dofs); + for(unsigned int idof=0; idof sol_dim(n_quad_pts);//solution of A*u normally + dealii::FullMatrix sol_1D(n_quad_pts);//solution of A*u with sum-factorization + dealii::FullMatrix basis_dim(n_quad_pts);//solution of A*u with sum-factorization + basis_dim = basis.tensor_product(basis.oneD_grad_operator, basis.oneD_vol_operator, basis.oneD_vol_operator); + + //Compute A*u normally + clock_t tfirst; + tfirst = clock(); + if(dim==2){ + for(unsigned int idof=0; idof< n_dofs_1D * n_dofs_1D; idof++){ + for(unsigned int idof2=0; idof2< n_dofs_1D * n_dofs_1D; idof2++){ + sol_dim[idof][idof2] = sol_hat_mat[idof][idof2] + * basis_dim[idof][idof2]; + } + } + } + if(dim==3){ + for(unsigned int idof=0; idof< n_dofs_1D * n_dofs_1D * n_dofs_1D; idof++){ + for(unsigned int idof2=0; idof2< n_dofs_1D * n_dofs_1D * n_dofs_1D; idof2++){ + sol_dim[idof][idof2] = sol_hat_mat[idof][idof2] + * basis_dim[idof][idof2]; + } + } + } + if(ielement==0) + time_diff[poly_degree] = clock() - tfirst; + else + time_diff[poly_degree] += clock() - tfirst; + + //compute A*u using sum-factorization + time_t tsum; + tsum = clock(); + basis.two_pt_flux_Hadamard_product(sol_hat_mat, sol_1D, basis.oneD_grad_operator, ones, 0); + + if(ielement==0) + time_diff_sum[poly_degree] = clock() - tsum; + else + time_diff_sum[poly_degree] += clock() - tsum; + + for(unsigned int iquad=0; iquad1e-11){ + pcout<<"sol dim "< sol_deriv_time(n_quad_pts);//solution of A*u with sum-factorization + time_t tderiv_sum_cons; + tderiv_sum_cons = clock(); + basis.matrix_vector_mult(sol_hat, sol_deriv_time, + basis.oneD_vol_operator, + basis.oneD_vol_operator, + basis.oneD_grad_operator); + + if(ielement==0) + time_deriv_sum_cons[poly_degree] = clock() - tderiv_sum_cons; + else + time_deriv_sum_cons[poly_degree] += clock() - tderiv_sum_cons; + + //check the other 2 directions match + basis_dim = basis.tensor_product(basis.oneD_vol_operator, basis.oneD_grad_operator, basis.oneD_vol_operator); + + clock_t tfirst_dir2; + tfirst_dir2 = clock(); + if(dim==2){ + for(unsigned int idof=0; idof< n_dofs_1D * n_dofs_1D; idof++){ + for(unsigned int idof2=0; idof2< n_dofs_1D * n_dofs_1D; idof2++){ + sol_dim[idof][idof2] = sol_hat_mat[idof][idof2] + * basis_dim[idof][idof2]; + } + } + } + if(dim==3){ + for(unsigned int idof=0; idof< n_dofs_1D * n_dofs_1D * n_dofs_1D; idof++){ + for(unsigned int idof2=0; idof2< n_dofs_1D * n_dofs_1D * n_dofs_1D; idof2++){ + sol_dim[idof][idof2] = sol_hat_mat[idof][idof2] + * basis_dim[idof][idof2]; + } + } + } + if(ielement==0) + time_diff_dir2[poly_degree] = clock() - tfirst_dir2; + else + time_diff_dir2[poly_degree] += clock() - tfirst_dir2; + + sol_1D.reinit(n_quad_pts, n_quad_pts); + + time_t tsum_dir2; + tsum_dir2 = clock(); + basis.two_pt_flux_Hadamard_product(sol_hat_mat, sol_1D, basis.oneD_grad_operator, ones, 1); + if(ielement==0) + time_diff_sum_dir2[poly_degree] = clock() - tsum_dir2; + else + time_diff_sum_dir2[poly_degree] += clock() - tsum_dir2; + + for(unsigned int iquad=0; iquad1e-11){ + pcout<<"DIR 2 sol dim "<1e-11){ + different = true; + } + } + } + } + + }//end of element loop + }//end of poly_degree loop + + double first_slope = std::log(((double)time_diff[poly_max-1]/CLOCKS_PER_SEC) / ((double)time_diff[poly_max-2]/CLOCKS_PER_SEC)) + / std::log((double)((poly_max-1.0)/(poly_max-2.0)));//technically over (p+1) since (p+1)^dim basis functions + double sum_slope = std::log(((double)time_diff_sum[poly_max-1]/CLOCKS_PER_SEC) /( (double)time_diff_sum[poly_max-2]/CLOCKS_PER_SEC)) + / std::log((double)((poly_max-1.0)/(poly_max-2.0))); + + const double first_slope_mpi = (dealii::Utilities::MPI::max(first_slope, MPI_COMM_WORLD)); + const double sum_slope_mpi = (dealii::Utilities::MPI::max(sum_slope, MPI_COMM_WORLD)); + + double avg_slope1 = 0.0; + pcout<<"Times for operation A*u"<poly_max-4){ + avg_slope1 += std::log(((double)time_diff_sum[i]/CLOCKS_PER_SEC) /( (double)time_diff_sum[i-1]/CLOCKS_PER_SEC)) + / std::log((double)((i)/(i-1.0))); + } + } + avg_slope1 /= (3.0); + + pcout<<" regular slope "<poly_max-4){ + avg_slope2 += std::log(((double)time_diff_sum_dir2[i]/CLOCKS_PER_SEC) /( (double)time_diff_sum_dir2[i-1]/CLOCKS_PER_SEC)) + / std::log((double)((i)/(i-1.0))); + } + } + avg_slope2 /= (3.0); + + double avg_slope3 = 0.0; + if(dim==3){ + pcout<<"Times for operation A*u in Direction z"<poly_max-4){ + avg_slope3 += std::log(((double)time_diff_sum_dir3[i]/CLOCKS_PER_SEC) /( (double)time_diff_sum_dir3[i-1]/CLOCKS_PER_SEC)) + / std::log((double)((i)/(i-1.0))); + } + } + avg_slope3 /= (3.0); + + } + pcout<<"average slope 1 "< dim+1.8 || avg_slope2 > dim+1.8 ||avg_slope3 > dim+1.8){ + //check if because of random number generator, take one more value for average since should converge by this order. + avg_slope1 = 0.0; + avg_slope2 = 0.0; + avg_slope3 = 0.0; + for(unsigned int i=poly_max-5; i dim+1.8 || avg_slope2 > dim+1.8 ||avg_slope3 > dim+1.8){ + pcout<<"Sum factorization not give correct comp cost slope."< +#include +#include +#include +#include +#include +#include +#include + +//#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "operators/operators.h" + +const double TOLERANCE = 1E-6; +using namespace std; + +template +void build_mass_matrix( const unsigned int n_dofs_1D, + const unsigned int dimension, + const dealii::FullMatrix &mass_1D, + dealii::FullMatrix &mass) +{ + if(dimension==2){ + for(unsigned int jdof=0; jdof::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 1; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + all_parameters_new.nstate = nstate; + // all_parameters_new.use_collocated_nodes = true; + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + bool different = false; + bool different_mass = false; + const unsigned int poly_max = 18; + const unsigned int poly_min = 2; + std::array time_diff; + std::array time_diff_sum; + std::array time_diff_mass; + std::array time_diff_mass_sum; + for(unsigned int poly_degree=poly_min; poly_degree mass_matrix(nstate, poly_degree, 1); + PHiLiP::OPERATOR::basis_functions basis(nstate, poly_degree, 1); + dealii::QGauss<1> quad1D (poly_degree+1); + const dealii::FE_DGQ<1> fe_dg(poly_degree); + const dealii::FESystem<1,1> fe_system(fe_dg, nstate); + mass_matrix.build_1D_volume_operator(fe_system,quad1D); + basis.build_1D_volume_operator(fe_system,quad1D); + + const unsigned int n_dofs = nstate * pow(poly_degree+1,dim); + const unsigned int n_dofs_1D = nstate * (poly_degree+1); + const unsigned int n_quad_pts_1D = quad1D.size(); + const unsigned int n_quad_pts = pow(n_quad_pts_1D, dim); + + for(unsigned int ielement=0; ielement<6; ielement++){//do several loops as if there were elements + std::vector sol_hat(n_dofs); + for(unsigned int idof=0; idof (rand()) / ( static_cast (RAND_MAX/(30-1e-8))); + } + std::vector sol_dim(n_quad_pts);//solution of A*u normally + std::vector sol_1D(n_quad_pts);//solution of A*u with sum-factorization + std::vector sol_mass(n_dofs);//solution of M*u normally + std::vector sol_mass_sum(n_dofs);//solution of M*u with sum-factorization + + // Compute A*u normally + clock_t tfirst; + tfirst = clock(); + if(dim==2){ + for(unsigned int jquad=0; jquad1e-11) different = true; + } + + // Mass matrix check now. So we explicitly compute Mass_matrix*u by 1) building the 3D mass matrix and doing M*u normally, + // and 2) using M*u=\chi^T* W *\chi *u, we do sum-factorization in 2 steps: a) y = \chi*u, then b) \chi^T * W * y + // First way + // build 3D mass matrix + time_t tmass; + tmass = clock(); + dealii::FullMatrix mass(n_dofs); + mass = mass_matrix.tensor_product_state(nstate, + mass_matrix.oneD_vol_operator, + mass_matrix.oneD_vol_operator,mass_matrix.oneD_vol_operator); + // compute M*u + for(unsigned int idof=0; idof &quad_weights_1D = quad1D.get_weights(); + std::vector quad_weights(n_quad_pts); + // get 2D or 3D quad weights from 1D + if(dim==2){ + for(unsigned int iquad=0; iquad interm_step(n_quad_pts); + // matrix-vect oper + basis.matrix_vector_mult(sol_hat, interm_step, basis.oneD_vol_operator, basis.oneD_vol_operator, basis.oneD_vol_operator); + // inner prod + basis.inner_product(interm_step, quad_weights, sol_mass_sum, basis.oneD_vol_operator, basis.oneD_vol_operator, basis.oneD_vol_operator); + if(ielement==0) + time_diff_mass_sum[poly_degree] = clock() - tmass_sum; + else + time_diff_mass_sum[poly_degree] += clock() - tmass_sum; + + for(unsigned int iquad=0; iquad1e-11) different_mass = true; + } + } //end of element loop + } //end of poly_degree loop + + double first_slope = std::log(((float)time_diff[poly_max-1]/CLOCKS_PER_SEC) / ((float)time_diff[poly_max-2]/CLOCKS_PER_SEC)) + / std::log((double)((poly_max)/(poly_max-1.0)));//technically over (p+1) since (p+1)^dim basis functions + // / ((double)((poly_max)/(poly_max-1.0)));//technically over (p+1) since (p+1)^dim basis functions + double sum_slope = std::log(((float)time_diff_sum[poly_max-1]/CLOCKS_PER_SEC) /( (float)time_diff_sum[poly_max-2]/CLOCKS_PER_SEC)) + / std::log((double)((poly_max)/(poly_max-1.0))); + /// ((double)((poly_max)/(poly_max-1.0))); + double first_slope_mass = std::log(((float)time_diff_mass[poly_max-1]/CLOCKS_PER_SEC) / ((float)time_diff_mass[poly_max-2]/CLOCKS_PER_SEC)) + / std::log((double)((poly_max)/(poly_max-1.0)));//technically over (p+1) since (p+1)^dim basis functions + // / ((double)((poly_max)/(poly_max-1.0)));//technically over (p+1) since (p+1)^dim basis functions + double sum_slope_mass = std::log(((float)time_diff_mass_sum[poly_max-1]/CLOCKS_PER_SEC) /( (float)time_diff_mass_sum[poly_max-2]/CLOCKS_PER_SEC)) + / std::log((double)((poly_max)/(poly_max-1.0))); + /// ((double)((poly_max)/(poly_max-1.0))); + + const double first_slope_mpi = (dealii::Utilities::MPI::max(first_slope, MPI_COMM_WORLD)); + const double sum_slope_mpi = (dealii::Utilities::MPI::max(sum_slope, MPI_COMM_WORLD)); + const double first_slope_mpi_mass = (dealii::Utilities::MPI::max(first_slope_mass, MPI_COMM_WORLD)); + const double sum_slope_mpi_mass = (dealii::Utilities::MPI::max(sum_slope_mass, MPI_COMM_WORLD)); + + pcout<<"Times for operation A*u"<poly_max-4){ + avg_slope += std::log(((float)time_diff_sum[i]/CLOCKS_PER_SEC) /( (float)time_diff_sum[i-1]/CLOCKS_PER_SEC)) + / std::log((double)((i)/(i-1.0))); + } + } + avg_slope /= (3); + + pcout<<" regular slope "<poly_max-4){ + avg_slope1 += std::log(((float)time_diff_mass_sum[i]/CLOCKS_PER_SEC) /( (float)time_diff_mass_sum[i-1]/CLOCKS_PER_SEC)) + / std::log((double)((i)/(i-1.0))); + } + } + avg_slope1 /= (3); + + pcout<<" regular slope "< dim+1.1){ + pcout<<"Sum factorization not give correct comp cost slope."< dim+1.1){ + pcout<<"Sum factorization not give correct comp cost slope."< +#include +#include +#include +#include +#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "dg/dg.h" +#include +#include +#include "dg/dg_factory.hpp" +#include "operators/operators.h" +//#include + +const double TOLERANCE = 1E-6; +using namespace std; +//namespace PHiLiP { + +template +class CurvManifold: public dealii::ChartManifold { + virtual dealii::Point pull_back(const dealii::Point &space_point) const override; ///< See dealii::Manifold. + virtual dealii::Point push_forward(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + virtual dealii::DerivativeForm<1,dim,dim> push_forward_gradient(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + + virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. +}; + +template +dealii::Point CurvManifold::pull_back(const dealii::Point &space_point) const +{ + using namespace PHiLiP; + const double pi = atan(1)*4.0; + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim function(dim); + dealii::FullMatrix derivative(dim); + double beta =1.0/10.0; + double alpha =1.0/10.0; + int flag =0; + while(flag != dim){ + if(dim==2){ + function[0] = x_ref[0] - x_phys[0] +beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function[1] = x_ref[1] - x_phys[1] +beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function[0] = x_ref[0] - x_phys[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function[1] = x_ref[1] - x_phys[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function[2] = x_ref[2] - x_phys[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + if(dim==2){ + derivative[0][0] = 1.0 - beta* pi/2.0 * std::sin(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + derivative[0][1] = - beta*3.0 *pi/2.0 * std::cos(pi/2.0*x_ref[0])*std::sin(3.0*pi/2.0*x_ref[1]); + + derivative[1][0] = beta*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + derivative[1][1] = 1.0 -beta*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1]); + } + else{ + derivative[0][0] = 1.0; + derivative[0][1] = - alpha*pi*std::sin(pi*x_ref[1]); + derivative[0][2] = - alpha*pi*std::sin(pi*x_ref[2]); + + derivative[1][0] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[0]); + derivative[1][1] = 1.0 -alpha*exp(1.0-x_ref[1])*(std::sin(pi*x_ref[0])+std::sin(pi*x_ref[2])); + derivative[1][2] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[2]); + derivative[2][0] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[0]); + derivative[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[1]); + derivative[2][2] = 1.0; + } + + dealii::FullMatrix Jacobian_inv(dim); + Jacobian_inv.invert(derivative); + dealii::Vector Newton_Step(dim); + Jacobian_inv.vmult(Newton_Step, function); + for(int idim=0; idim function_check(dim); + if(dim==2){ + function_check[0] = x_ref[0] + beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function_check[1] = x_ref[1] + beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function_check[0] = x_ref[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function_check[1] = x_ref[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function_check[2] = x_ref[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + std::vector error(dim); + for(int idim=0; idim 1e-13) { + std::cout << "Large error " << error[0] << std::endl; + for(int idim=0;idim +dealii::Point CurvManifold::push_forward(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim (x_phys); // Trigonometric +} + +template +dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + dealii::DerivativeForm<1, dim, dim> dphys_dref; + double beta = 1.0/10.0; + double alpha = 1.0/10.0; + dealii::Point x_ref; + for(int idim=0; idim +std::unique_ptr > CurvManifold::clone() const +{ + return std::make_unique>(); +} + +template +static dealii::Point warp (const dealii::Point &p) +{ + const double pi = atan(1)*4.0; + dealii::Point q = p; + + double beta =1.0/10.0; + double alpha =1.0/10.0; + if (dim == 2){ + q[dim-2] =p[dim-2] + beta*std::cos(pi/2.0 * p[dim-2]) * std::cos(3.0 * pi/2.0 * p[dim-1]); + q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); + } + if(dim==3){ + q[0] =p[0] + alpha*(std::cos(pi * p[2]) + std::cos(pi * p[1])); + q[1] =p[1] + alpha*exp(1.0-p[1])*(std::sin(pi * p[0]) + std::sin(pi* p[2])); + q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * p[0]) + std::sin(2.0 * pi * p[1])); + } + + return q; +} + +/**************************** + * End of Curvilinear Grid + * ***************************/ + +int main (int argc, char * argv[]) +{ + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 1; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + + // all_parameters_new.use_collocated_nodes=true; + + //unsigned int poly_degree = 3; + double left = 0.0; + double right = 1.0; + const bool colorize = true; + //Generate a standard grid + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(0); + + //Warp the grid + //IF WANT NON-WARPED GRID COMMENT UNTIL SAYS "NOT COMMENT" + dealii::GridTools::transform (&warp, *grid); + + // Assign a manifold to have curved geometry + const CurvManifold curv_manifold; + unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true + grid->reset_all_manifolds(); + grid->set_all_manifold_ids(manifold_id); + grid->set_manifold ( manifold_id, curv_manifold ); + //"END COMMENT" TO NOT WARP GRID + + double surf_int = 0.0; + for(unsigned int poly_degree = 2; poly_degree<6; poly_degree++){ + unsigned int grid_degree = poly_degree + 1; + //setup DG + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); + + const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); + + dealii::QGaussLobatto<1> grid_quad(grid_degree +1); + const dealii::FE_DGQ<1> fe_grid(grid_degree); + const dealii::FESystem<1,1> fe_sys_grid(fe_grid, nstate); + dealii::QGauss<1> flux_quad(poly_degree +1); + dealii::QGauss<0> flux_quad_face(poly_degree +1); + + PHiLiP::OPERATOR::mapping_shape_functions mapping_basis(nstate,poly_degree,grid_degree); + mapping_basis.build_1D_shape_functions_at_grid_nodes(fe_sys_grid, grid_quad); + mapping_basis.build_1D_shape_functions_at_flux_nodes(fe_sys_grid, flux_quad, flux_quad_face); + + PHiLiP::OPERATOR::metric_operators metric_oper(nstate, poly_degree, grid_degree); + + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + std::vector current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + for(int idim=0; idim vol_GLL(grid_degree +1); + for (unsigned int igrid_node = 0; igrid_node< n_metric_dofs/dim; ++igrid_node) { + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + mapping_support_points[istate][igrid_node] += val * fe_metric.shape_value_component(idof,vol_GLL.point(igrid_node),istate); + } + } + + const unsigned int n_quad_face_pts = dg->face_quadrature_collection[poly_degree].size(); + const std::vector &quad_weights = dg->face_quadrature_collection[poly_degree].get_weights (); + for (unsigned int iface=0; iface < dealii::GeometryInfo::faces_per_cell; ++iface) { + + metric_oper.build_facet_metric_operators( + iface, + n_quad_face_pts, n_metric_dofs/dim, + mapping_support_points, + mapping_basis, + false); + + const dealii::Tensor<1,dim,real> unit_normal_int = dealii::GeometryInfo::unit_normal_vector[iface]; + std::vector> normals_int(n_quad_face_pts); + for(unsigned int iquad=0; iquad 1e-13){ + pcout<<" Metrics Do NOT Satisfy GCL Condition\n"< +#include +#include +#include +#include +#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "dg/dg.h" +#include +#include +#include "dg/dg_factory.hpp" +#include "operators/operators.h" +//#include + +const double TOLERANCE = 1E-6; +using namespace std; +//namespace PHiLiP { + +template +class CurvManifold: public dealii::ChartManifold { + virtual dealii::Point pull_back(const dealii::Point &space_point) const override; ///< See dealii::Manifold. + virtual dealii::Point push_forward(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + virtual dealii::DerivativeForm<1,dim,dim> push_forward_gradient(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + + virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. +}; + +template +dealii::Point CurvManifold::pull_back(const dealii::Point &space_point) const +{ + using namespace PHiLiP; + const double pi = atan(1)*4.0; + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim function(dim); + dealii::FullMatrix derivative(dim); + double beta =1.0/10.0; + double alpha =1.0/10.0; + int flag =0; + while(flag != dim){ + if(dim==2){ + function[0] = x_ref[0] - x_phys[0] +beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function[1] = x_ref[1] - x_phys[1] +beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function[0] = x_ref[0] - x_phys[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function[1] = x_ref[1] - x_phys[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function[2] = x_ref[2] - x_phys[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + + if(dim==2){ + derivative[0][0] = 1.0 - beta* pi/2.0 * std::sin(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + derivative[0][1] = - beta*3.0 *pi/2.0 * std::cos(pi/2.0*x_ref[0])*std::sin(3.0*pi/2.0*x_ref[1]); + + derivative[1][0] = beta*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + derivative[1][1] = 1.0 -beta*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1]); + } + else{ + derivative[0][0] = 1.0; + derivative[0][1] = - alpha*pi*std::sin(pi*x_ref[1]); + derivative[0][2] = - alpha*pi*std::sin(pi*x_ref[2]); + + derivative[1][0] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[0]); + derivative[1][1] = 1.0 -alpha*exp(1.0-x_ref[1])*(std::sin(pi*x_ref[0])+std::sin(pi*x_ref[2])); + derivative[1][2] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[2]); + derivative[2][0] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[0]); + derivative[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[1]); + derivative[2][2] = 1.0; + } + + dealii::FullMatrix Jacobian_inv(dim); + Jacobian_inv.invert(derivative); + dealii::Vector Newton_Step(dim); + Jacobian_inv.vmult(Newton_Step, function); + for(int idim=0; idim function_check(dim); + if(dim==2){ + function_check[0] = x_ref[0] + beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function_check[1] = x_ref[1] + beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function_check[0] = x_ref[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function_check[1] = x_ref[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function_check[2] = x_ref[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + std::vector error(dim); + for(int idim=0; idim 1e-13) { + std::cout << "Large error " << error[0] << std::endl; + for(int idim=0;idim +dealii::Point CurvManifold::push_forward(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim (x_phys); // Trigonometric +} + +template +dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + dealii::DerivativeForm<1, dim, dim> dphys_dref; + double beta = 1.0/10.0; + double alpha = 1.0/10.0; + dealii::Point x_ref; + for(int idim=0; idim +std::unique_ptr > CurvManifold::clone() const +{ + return std::make_unique>(); +} + +template +static dealii::Point warp (const dealii::Point &p) +{ + const double pi = atan(1)*4.0; + dealii::Point q = p; + + double beta =1.0/10.0; + double alpha =1.0/10.0; + if (dim == 2){ + q[dim-2] =p[dim-2] + beta*std::cos(pi/2.0 * p[dim-2]) * std::cos(3.0 * pi/2.0 * p[dim-1]); + q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); + } + if(dim==3){ + q[0] =p[0] + alpha*(std::cos(pi * p[2]) + std::cos(pi * p[1])); + q[1] =p[1] + alpha*exp(1.0-p[1])*(std::sin(pi * p[0]) + std::sin(pi* p[2])); + q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * p[0]) + std::sin(2.0 * pi * p[1])); + } + + return q; +} + +/**************************** + * End of Curvilinear Grid + * ***************************/ + +int main (int argc, char * argv[]) +{ + + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 1; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + + // all_parameters_new.use_collocated_nodes=true; + + //unsigned int poly_degree = 3; + double left = 0.0; + double right = 1.0; + const bool colorize = true; + //Generate a standard grid + + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(0); + + //Warp the grid + //IF WANT NON-WARPED GRID COMMENT UNTIL SAYS "NOT COMMENT" + dealii::GridTools::transform (&warp, *grid); + + // Assign a manifold to have curved geometry + const CurvManifold curv_manifold; + unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true + grid->reset_all_manifolds(); + grid->set_all_manifold_ids(manifold_id); + grid->set_manifold ( manifold_id, curv_manifold ); + //"END COMMENT" TO NOT WARP GRID + + double surf_int = 0.0; + for(unsigned int poly_degree = 2; poly_degree<6; poly_degree++){ + unsigned int grid_degree = poly_degree; + // setup operator + // setup DG + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); + + const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); + + dealii::QGaussLobatto<1> grid_quad(grid_degree +1); + const dealii::FE_DGQ<1> fe_grid(grid_degree); + const dealii::FESystem<1,1> fe_sys_grid(fe_grid, nstate); + dealii::QGauss<1> flux_quad(poly_degree +1); + dealii::QGauss<0> flux_quad_face(poly_degree +1); + + PHiLiP::OPERATOR::mapping_shape_functions mapping_basis(nstate,poly_degree,grid_degree); + mapping_basis.build_1D_shape_functions_at_grid_nodes(fe_sys_grid, grid_quad); + mapping_basis.build_1D_shape_functions_at_flux_nodes(fe_sys_grid, flux_quad, flux_quad_face); + + PHiLiP::OPERATOR::metric_operators metric_oper(nstate, poly_degree, grid_degree); + + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + std::vector current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + for(int idim=0; idim vol_GLL(grid_degree +1); + for (unsigned int igrid_node = 0; igrid_node< n_metric_dofs/dim; ++igrid_node) { + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + mapping_support_points[istate][igrid_node] += val * fe_metric.shape_value_component(idof,vol_GLL.point(igrid_node),istate); + } + } + const unsigned int n_quad_face_pts = dg->face_quadrature_collection[poly_degree].size(); + const std::vector &quad_weights = dg->face_quadrature_collection[poly_degree].get_weights (); + for (unsigned int iface=0; iface < dealii::GeometryInfo::faces_per_cell; ++iface) { + + metric_oper.build_facet_metric_operators( + iface, + n_quad_face_pts, n_metric_dofs/dim, + mapping_support_points, + mapping_basis, + false); + + const dealii::Tensor<1,dim,real> unit_normal_int = dealii::GeometryInfo::unit_normal_vector[iface]; + std::vector> normals_int(n_quad_face_pts); + for(unsigned int iquad=0; iquad 1e-13){ + pcout<<" Metrics Do NOT Satisfy GCL Condition\n"< +#include +#include +#include +#include +#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "dg/dg.h" +#include +#include +#include "dg/dg_factory.hpp" +#include "operators/operators.h" +//#include + +const double TOLERANCE = 1E-6; +using namespace std; +//namespace PHiLiP { + +template +class CurvManifold: public dealii::ChartManifold { + virtual dealii::Point pull_back(const dealii::Point &space_point) const override; ///< See dealii::Manifold. + virtual dealii::Point push_forward(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + virtual dealii::DerivativeForm<1,dim,dim> push_forward_gradient(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + + virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. +}; + +template +dealii::Point CurvManifold::pull_back(const dealii::Point &space_point) const +{ + using namespace PHiLiP; + const double pi = atan(1)*4.0; + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim function(dim); + dealii::FullMatrix derivative(dim); + double beta =1.0/10.0; + double alpha =1.0/10.0; + int flag =0; + while(flag != dim){ + if(dim==2){ + function[0] = x_ref[0] - x_phys[0] +beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function[1] = x_ref[1] - x_phys[1] +beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function[0] = x_ref[0] - x_phys[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function[1] = x_ref[1] - x_phys[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function[2] = x_ref[2] - x_phys[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + + if(dim==2){ + derivative[0][0] = 1.0 - beta* pi/2.0 * std::sin(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + derivative[0][1] = - beta*3.0 *pi/2.0 * std::cos(pi/2.0*x_ref[0])*std::sin(3.0*pi/2.0*x_ref[1]); + + derivative[1][0] = beta*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + derivative[1][1] = 1.0 -beta*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1]); + } + else{ + derivative[0][0] = 1.0; + derivative[0][1] = - alpha*pi*std::sin(pi*x_ref[1]); + derivative[0][2] = - alpha*pi*std::sin(pi*x_ref[2]); + + derivative[1][0] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[0]); + derivative[1][1] = 1.0 -alpha*exp(1.0-x_ref[1])*(std::sin(pi*x_ref[0])+std::sin(pi*x_ref[2])); + derivative[1][2] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[2]); + derivative[2][0] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[0]); + derivative[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[1]); + derivative[2][2] = 1.0; + } + + dealii::FullMatrix Jacobian_inv(dim); + Jacobian_inv.invert(derivative); + dealii::Vector Newton_Step(dim); + Jacobian_inv.vmult(Newton_Step, function); + for(int idim=0; idim function_check(dim); + if(dim==2){ + function_check[0] = x_ref[0] + beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function_check[1] = x_ref[1] + beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function_check[0] = x_ref[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function_check[1] = x_ref[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function_check[2] = x_ref[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + std::vector error(dim); + for(int idim=0; idim 1e-13) { + std::cout << "Large error " << error[0] << std::endl; + for(int idim=0;idim +dealii::Point CurvManifold::push_forward(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim (x_phys); // Trigonometric +} + +template +dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + dealii::DerivativeForm<1, dim, dim> dphys_dref; + double beta = 1.0/10.0; + double alpha = 1.0/10.0; + dealii::Point x_ref; + for(int idim=0; idim +std::unique_ptr > CurvManifold::clone() const +{ + return std::make_unique>(); +} + +template +static dealii::Point warp (const dealii::Point &p) +{ + const double pi = atan(1)*4.0; + dealii::Point q = p; + + double beta =1.0/10.0; + double alpha =1.0/10.0; + if (dim == 2){ + q[dim-2] =p[dim-2] + beta*std::cos(pi/2.0 * p[dim-2]) * std::cos(3.0 * pi/2.0 * p[dim-1]); + q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); + } + if(dim==3){ + q[0] =p[0] + alpha*(std::cos(pi * p[2]) + std::cos(pi * p[1])); + q[1] =p[1] + alpha*exp(1.0-p[1])*(std::sin(pi * p[0]) + std::sin(pi* p[2])); + q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * p[0]) + std::sin(2.0 * pi * p[1])); + } + + return q; +} + +/**************************** + * End of Curvilinear Grid + * ***************************/ + +int main (int argc, char * argv[]) +{ + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 1; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + + // all_parameters_new.use_collocated_nodes=true; + + //unsigned int poly_degree = 3; + double left = 0.0; + double right = 1.0; + const bool colorize = true; + //Generate a standard grid + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(1); + + //Warp the grid + //IF WANT NON-WARPED GRID COMMENT UNTIL SAYS "NOT COMMENT" + dealii::GridTools::transform (&warp, *grid); + + // Assign a manifold to have curved geometry + const CurvManifold curv_manifold; + unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true + grid->reset_all_manifolds(); + grid->set_all_manifold_ids(manifold_id); + grid->set_manifold ( manifold_id, curv_manifold ); + //"END COMMENT" TO NOT WARP GRID + + for(unsigned int poly_degree = 2; poly_degree<6; poly_degree++){ + unsigned int grid_degree = poly_degree; + //setup DG + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); + + dealii::QGaussLobatto<1> grid_quad(grid_degree +1); + const dealii::FE_DGQ<1> fe_grid(grid_degree); + const dealii::FESystem<1,1> fe_sys_grid(fe_grid, nstate); + dealii::QGauss<1> flux_quad(poly_degree +1); + dealii::QGauss<0> flux_quad_face(poly_degree +1); + + PHiLiP::OPERATOR::mapping_shape_functions mapping_basis(nstate,poly_degree,grid_degree); + mapping_basis.build_1D_shape_functions_at_grid_nodes(fe_sys_grid, grid_quad); + mapping_basis.build_1D_shape_functions_at_flux_nodes(fe_sys_grid, flux_quad, flux_quad_face); + + PHiLiP::OPERATOR::metric_operators metric_oper(nstate, poly_degree, grid_degree); + PHiLiP::OPERATOR::metric_operators metric_oper_neigh(nstate, poly_degree, grid_degree); + + const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + std::vector current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + for(int idim=0; idim vol_GLL(grid_degree +1); + for (unsigned int igrid_node = 0; igrid_node< n_metric_dofs/dim; ++igrid_node) { + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + mapping_support_points[istate][igrid_node] += val * fe_metric.shape_value_component(idof,vol_GLL.point(igrid_node),istate); + } + } + + const unsigned int n_quad_face_pts = dg->face_quadrature_collection[poly_degree].size(); + for (unsigned int iface=0; iface < dealii::GeometryInfo::faces_per_cell; ++iface) { + auto current_face = current_cell->face(iface); + if(current_face->at_boundary()) + continue; + + metric_oper.build_facet_metric_operators( + iface, + n_quad_face_pts, n_metric_dofs/dim, + mapping_support_points, + mapping_basis, + false); + + + auto metric_neighbor_cell = metric_cell->neighbor(iface); + std::vector neighbor_metric_dofs_indices(n_metric_dofs); + metric_neighbor_cell->get_dof_indices(neighbor_metric_dofs_indices); + const unsigned int neighbor_iface = metric_cell->neighbor_face_no(iface); + std::array,dim> mapping_support_points_neigh; + for(int idim=0; idimhigh_order_grid->volume_nodes[neighbor_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + mapping_support_points_neigh[istate][igrid_node] += val * fe_metric.shape_value_component(idof,vol_GLL.point(igrid_node),istate); + } + } + + metric_oper_neigh.build_facet_metric_operators( + neighbor_iface, + n_quad_face_pts, n_metric_dofs/dim, + mapping_support_points_neigh, + mapping_basis, + false); + + const dealii::Tensor<1,dim> unit_normal_int = dealii::GeometryInfo::unit_normal_vector[iface]; + std::vector > normal_phys_int(n_quad_face_pts); + std::vector > normal_phys_ext(n_quad_face_pts); + metric_oper.transform_reference_unit_normal_to_physical_unit_normal(n_quad_face_pts, unit_normal_int, metric_oper.metric_cofactor_surf, normal_phys_int); + metric_oper_neigh.transform_reference_unit_normal_to_physical_unit_normal(n_quad_face_pts, unit_normal_int, metric_oper_neigh.metric_cofactor_surf, normal_phys_int); + + for(unsigned int iquad=0; iquad 1e-14){ + pcout<<" phys normal int "< +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "operators/operators.h" +#include "dg/dg.h" +#include "dg/dg_factory.hpp" + +const double TOLERANCE = 1E-6; +using namespace std; + +int main (int argc, char * argv[]) +{ + + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 2; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + all_parameters_new.nstate = nstate; + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + using FR_enum = Parameters::AllParameters::Flux_Reconstruction; + all_parameters_new.flux_reconstruction_type = FR_enum::cHU; + + double left = 0.0; + double right = 1.0; + const bool colorize = true; + const unsigned int igrid= 2; + + // Generate a standard grid +#if PHILIP_DIM==1 // dealii::parallel::distributed::Triangulation does not work for 1D + using Triangulation = dealii::Triangulation; + std::shared_ptr grid = std::make_shared( + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#else + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#endif + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(igrid); + + double max_dif_int_parts = 0.0; + double max_dif_surf_int = 0.0; + double max_dif_surf_int_FR = 0.0; + double max_dif_int_parts_dim = 0.0; + for(unsigned int poly_degree=2; poly_degree<6; poly_degree++){ + + const unsigned int n_dofs = nstate * pow(poly_degree+1,dim); + const unsigned int n_dofs_1D = nstate * (poly_degree+1); + + // build stiffness 1D + PHiLiP::OPERATOR::local_basis_stiffness stiffness(nstate, poly_degree, 1); + dealii::QGauss<1> quad1D (poly_degree+1); + const dealii::FE_DGQ<1> fe_dg(poly_degree); + const dealii::FESystem<1,1> fe_system(fe_dg, nstate); + stiffness.build_1D_volume_operator(fe_system,quad1D); + + // volume integration by parts + dealii::FullMatrix vol_int_parts(n_dofs_1D); + vol_int_parts.add(1.0, stiffness.oneD_vol_operator); + vol_int_parts.Tadd(1.0, stiffness.oneD_vol_operator); + + // compute surface integral + dealii::FullMatrix face_int_parts(n_dofs_1D); + dealii::QGauss<0> face_quad1D (poly_degree+1); + PHiLiP::OPERATOR::face_integral_basis face_int(nstate, poly_degree, 1); + face_int.build_1D_surface_operator(fe_system, face_quad1D); + PHiLiP::OPERATOR::basis_functions face_basis(nstate, poly_degree, 1); + face_basis.build_1D_surface_operator(fe_system, face_quad1D); + + const unsigned int n_face_quad_pts = face_quad1D.size(); + for(unsigned int iface=0; iface< dealii::GeometryInfo<1>::faces_per_cell; iface++){ + const dealii::Tensor<1,1,real> unit_normal = dealii::GeometryInfo<1>::unit_normal_vector[iface]; + for(unsigned int itest=0; itestmax_dif_int_parts) + max_dif_int_parts = std::abs(face_int_parts[idof][idof2] - vol_int_parts[idof][idof2]); + } + } + + PHiLiP::OPERATOR::lifting_operator lifting(nstate, poly_degree, 1); + lifting.build_1D_volume_operator(fe_system, quad1D); + lifting.build_1D_surface_operator(fe_system, face_quad1D); + std::array,2> surface_int_from_lift; + for(unsigned int iface=0; iface<2; iface++){ + surface_int_from_lift[iface].reinit(n_dofs_1D, n_face_quad_pts); + lifting.oneD_vol_operator.mmult(surface_int_from_lift[iface], lifting.oneD_surf_operator[iface]); + } + for(unsigned int iface=0; iface<2; iface++){ + for(unsigned int idof=0; idofmax_dif_surf_int) + max_dif_surf_int = std::abs(face_int.oneD_surf_operator[iface][iquad][idof] - surface_int_from_lift[iface][idof][iquad]); + } + } + } + PHiLiP::OPERATOR::lifting_operator_FR lifting_FR(nstate, poly_degree, 1, FR_enum::cPlus); + lifting_FR.build_1D_volume_operator(fe_system, quad1D); + lifting_FR.build_1D_surface_operator(fe_system, face_quad1D); + std::array,2> surface_int_from_lift_FR; + for(unsigned int iface=0; iface<2; iface++){ + surface_int_from_lift_FR[iface].reinit(n_dofs_1D, n_face_quad_pts); + lifting_FR.oneD_vol_operator.mmult(surface_int_from_lift_FR[iface], lifting_FR.oneD_surf_operator[iface]); + } + for(unsigned int iface=0; iface<2; iface++){ + for(unsigned int idof=0; idofmax_dif_surf_int) + max_dif_surf_int_FR = std::abs(face_int.oneD_surf_operator[iface][iquad][idof] - surface_int_from_lift_FR[iface][idof][iquad]); + } + } + } + + dealii::FullMatrix face_int_parts_dim(n_dofs); + face_int_parts_dim = face_int.tensor_product_state(nstate, face_int_parts, lifting.oneD_vol_operator, lifting.oneD_vol_operator); + dealii::FullMatrix vol_int_parts_dim(n_dofs); + dealii::FullMatrix stiffness_dim(n_dofs); + stiffness_dim = stiffness.tensor_product_state(nstate, stiffness.oneD_vol_operator, lifting.oneD_vol_operator, lifting.oneD_vol_operator); + vol_int_parts_dim.add(1.0, stiffness_dim); + vol_int_parts_dim.Tadd(1.0, stiffness_dim); + for(unsigned int idof=0; idofmax_dif_int_parts_dim) + max_dif_int_parts_dim = std::abs(face_int_parts_dim[idof][idof2] - vol_int_parts_dim[idof][idof2]); + } + } + }//end of poly_degree loop + + const double max_dif_int_parts_mpi= (dealii::Utilities::MPI::max(max_dif_int_parts, MPI_COMM_WORLD)); + const double max_dif_int_parts_dim_mpi= (dealii::Utilities::MPI::max(max_dif_int_parts_dim, MPI_COMM_WORLD)); + const double max_dif_surf_int_mpi= (dealii::Utilities::MPI::max(max_dif_surf_int, MPI_COMM_WORLD)); + const double max_dif_surf_int_mpi_FR= (dealii::Utilities::MPI::max(max_dif_surf_int_FR, MPI_COMM_WORLD)); + if(max_dif_int_parts_mpi >1e-11){ + pcout<<" Surface operator not satisfy integration by parts !"<1e-11){ + pcout<<" Surface operator tensor product not satisfy integration by parts !"<1e-11){ + pcout<<" Surface lifting operator not correct !"<1e-11){ + pcout<<" Surface lifting FR operator not correct !"< +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "operators/operators.h" + +const double TOLERANCE = 1E-6; +using namespace std; + + + +int main (int argc, char * argv[]) +{ + + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 1; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + all_parameters_new.nstate = nstate; + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + using FR_enum = Parameters::AllParameters::Flux_Reconstruction; + all_parameters_new.flux_reconstruction_type = FR_enum::cHU; + + bool equiv = true; + bool sum_fact = true; + for(unsigned int poly_degree=2; poly_degree<4; poly_degree++){ + + const unsigned int n_dofs = nstate * pow(poly_degree+1,dim); + dealii::QGauss vol_quad_dim (poly_degree+1); + const dealii::FE_DGQ fe_dim(poly_degree); + const dealii::FESystem fe_system_dim(fe_dim, nstate); + + dealii::QGauss<1> quad_1D (poly_degree+1); + const dealii::FE_DGQ<1> fe(poly_degree); + const dealii::FESystem<1,1> fe_system(fe, nstate); + PHiLiP::OPERATOR::basis_functions basis_1D(nstate, poly_degree, 1); + basis_1D.build_1D_volume_operator(fe, quad_1D); + basis_1D.build_1D_gradient_operator(fe, quad_1D); + dealii::FullMatrix basis_dim(n_dofs); + basis_dim = basis_1D.tensor_product(basis_1D.oneD_grad_operator, basis_1D.oneD_vol_operator,basis_1D.oneD_vol_operator); + + for(unsigned int idof=0; idof qpoint = vol_quad_dim.point(iquad); + if(fe_system_dim.shape_grad_component(idof,qpoint,0)[0] != basis_dim[iquad][idof]) + equiv = false; + } + } + if(dim >= 2){ + basis_dim = basis_1D.tensor_product(basis_1D.oneD_vol_operator, basis_1D.oneD_grad_operator,basis_1D.oneD_vol_operator); + for(unsigned int idof=0; idof qpoint = vol_quad_dim.point(iquad); + if(fe_system_dim.shape_grad_component(idof,qpoint,0)[1] != basis_dim[iquad][idof]) + equiv = false; + } + } + } + if(dim >= 3){ + basis_dim = basis_1D.tensor_product(basis_1D.oneD_vol_operator,basis_1D.oneD_vol_operator, basis_1D.oneD_grad_operator); + for(unsigned int idof=0; idof qpoint = vol_quad_dim.point(iquad); + if(fe_system_dim.shape_grad_component(idof,qpoint,0)[2] != basis_dim[iquad][idof]) + equiv = false; + } + } + } + + std::vector sol_hat(n_dofs); + for(unsigned int idof=0; idof (rand()) / ( static_cast (RAND_MAX/(30-1e-8))); + sol_hat[idof] = sqrt( 1e-8 + static_cast (rand()) / ( static_cast (RAND_MAX/(30-1e-8))) ); + } + std::vector sol_dim(n_dofs); + for(unsigned int idof=0; idof sol_sum_fact(n_dofs); + if(dim==1) + basis_1D.matrix_vector_mult(sol_hat, sol_sum_fact, basis_1D.oneD_grad_operator, basis_1D.oneD_vol_operator, basis_1D.oneD_vol_operator); + if(dim==2) + basis_1D.matrix_vector_mult(sol_hat, sol_sum_fact, basis_1D.oneD_vol_operator, basis_1D.oneD_grad_operator, basis_1D.oneD_vol_operator); + if(dim==3) + basis_1D.matrix_vector_mult(sol_hat, sol_sum_fact, basis_1D.oneD_vol_operator, basis_1D.oneD_vol_operator, basis_1D.oneD_grad_operator); + + + for(unsigned int idof=0; idof1e-12){ + sum_fact = false; + pcout<<"sum fact wrong "< +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "operators/operators.h" + +const double TOLERANCE = 1E-6; +using namespace std; + +int main (int argc, char * argv[]) +{ + dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + using real = double; + using namespace PHiLiP; + std::cout << std::setprecision(std::numeric_limits::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + const int nstate = 2; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + all_parameters_new.nstate = nstate; + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + using FR_enum = Parameters::AllParameters::Flux_Reconstruction; + all_parameters_new.flux_reconstruction_type = FR_enum::cHU; + // all_parameters_new.overintegration = 2; + // const unsigned int overint= all_parameters_new.overintegration; + // all_parameters_new.use_collocated_nodes = true; + + // double skew_sym = 0.0; + double M_K_HU =0.0; + for(unsigned int poly_degree=2; poly_degree<6; poly_degree++){ + double left = 0.0; + double right = 1.0; + const bool colorize = true; + const unsigned int igrid= 2; + + //Generate a standard grid +#if PHILIP_DIM==1 // dealii::parallel::distributed::Triangulation does not work for 1D + using Triangulation = dealii::Triangulation; + std::shared_ptr grid = std::make_shared( + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#else + using Triangulation = dealii::parallel::distributed::Triangulation; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); +#endif + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(igrid); + + const unsigned int n_dofs = nstate * pow(poly_degree+1,dim); + // dealii::QGaussLobatto vol_quad_GLL (poly_degree+1+overint); + dealii::QGaussLobatto vol_quad_GLL (poly_degree+1); + const std::vector &quad_weights = vol_quad_GLL.get_weights (); + const dealii::FE_DGQ fe_dim(poly_degree); + const dealii::FESystem fe_system_dim(fe_dim, nstate); + + PHiLiP::OPERATOR::local_mass mass_matrix(nstate, poly_degree, 1); + dealii::QGauss<1> quad1D (poly_degree+1); + const dealii::FE_DGQ<1> fe_dg(poly_degree); + const dealii::FESystem<1,1> fe_system(fe_dg, nstate); + mass_matrix.build_1D_volume_operator(fe_system,quad1D); + dealii::FullMatrix mass_dim(n_dofs); + mass_dim = mass_matrix.tensor_product_state(nstate, + mass_matrix.oneD_vol_operator, + mass_matrix.oneD_vol_operator,mass_matrix.oneD_vol_operator); + + PHiLiP::OPERATOR::local_Flux_Reconstruction_operator local_FR(nstate, poly_degree, 1, FR_enum::cHU); + local_FR.build_1D_volume_operator(fe_system,quad1D); + dealii::FullMatrix FR_dim(n_dofs); + FR_dim = local_FR.build_dim_Flux_Reconstruction_operator(mass_matrix.oneD_vol_operator, nstate, n_dofs); + + for(unsigned int idof=0; idof 1e-12) + M_K_HU = std::abs(quad_weights[idof] - sum); + } + else{ + if(std::abs(sum) > 1e-12) + if(std::abs(sum) > M_K_HU) + M_K_HU = std::abs(sum); + } + } + } + }//end of poly_degree loop + + if(M_K_HU > 1e-15){ + pcout<<" KHU does not recover Collocated GLL M+K mass matrix with exact integration !"< +#include +#include +#include +#include +#include +#include +//#include +#include + +#include + +#include "testing/tests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +// Finally, we take our exact solution from the library as well as volume_quadrature +// and additional tools. +#include +#include +#include +#include + +#include "parameters/all_parameters.h" +#include "parameters/parameters.h" +#include "dg/dg.h" +#include +#include +#include "dg/dg_factory.hpp" +#include "operators/operators.h" +//#include + +const double TOLERANCE = 1E-6; +using namespace std; +//namespace PHiLiP { + +template +class CurvManifold: public dealii::ChartManifold { + virtual dealii::Point pull_back(const dealii::Point &space_point) const override; ///< See dealii::Manifold. + virtual dealii::Point push_forward(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + virtual dealii::DerivativeForm<1,dim,dim> push_forward_gradient(const dealii::Point &chart_point) const override; ///< See dealii::Manifold. + + virtual std::unique_ptr > clone() const override; ///< See dealii::Manifold. +}; + +template +dealii::Point CurvManifold::pull_back(const dealii::Point &space_point) const +{ + using namespace PHiLiP; + const double pi = atan(1)*4.0; + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim function(dim); + dealii::FullMatrix derivative(dim); + double beta =1.0/10.0; + double alpha =1.0/10.0; + int flag =0; + while(flag != dim){ + if(dim==2){ + function[0] = x_ref[0] - x_phys[0] +beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function[1] = x_ref[1] - x_phys[1] +beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function[0] = x_ref[0] - x_phys[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function[1] = x_ref[1] - x_phys[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function[2] = x_ref[2] - x_phys[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + + + if(dim==2){ + derivative[0][0] = 1.0 - beta* pi/2.0 * std::sin(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + derivative[0][1] = - beta*3.0 *pi/2.0 * std::cos(pi/2.0*x_ref[0])*std::sin(3.0*pi/2.0*x_ref[1]); + + derivative[1][0] = beta*2.0*pi*std::cos(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + derivative[1][1] = 1.0 -beta*pi/2.0*std::sin(2.0*pi*(x_ref[0]))*std::sin(pi/2.0*x_ref[1]); + } + else{ + derivative[0][0] = 1.0; + derivative[0][1] = - alpha*pi*std::sin(pi*x_ref[1]); + derivative[0][2] = - alpha*pi*std::sin(pi*x_ref[2]); + + derivative[1][0] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[0]); + derivative[1][1] = 1.0 -alpha*exp(1.0-x_ref[1])*(std::sin(pi*x_ref[0])+std::sin(pi*x_ref[2])); + derivative[1][2] = alpha*pi*exp(1.0-x_ref[1])*std::cos(pi*x_ref[2]); + derivative[2][0] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[0]); + derivative[2][1] = 1.0/10.0*pi*std::cos(2.0*pi*x_ref[1]); + derivative[2][2] = 1.0; + } + + dealii::FullMatrix Jacobian_inv(dim); + Jacobian_inv.invert(derivative); + dealii::Vector Newton_Step(dim); + Jacobian_inv.vmult(Newton_Step, function); + for(int idim=0; idim function_check(dim); + if(dim==2){ + function_check[0] = x_ref[0] + beta*std::cos(pi/2.0*x_ref[0])*std::cos(3.0*pi/2.0*x_ref[1]); + function_check[1] = x_ref[1] + beta*std::sin(2.0*pi*(x_ref[0]))*std::cos(pi/2.0*x_ref[1]); + } + else{ + function_check[0] = x_ref[0] +alpha*(std::cos(pi * x_ref[2]) + std::cos(pi * x_ref[1])); + function_check[1] = x_ref[1] +alpha*exp(1.0-x_ref[1])*(std::sin(pi * x_ref[0]) + std::sin(pi* x_ref[2])); + function_check[2] = x_ref[2] +1.0/20.0*( std::sin(2.0 * pi * x_ref[0]) + std::sin(2.0 * pi * x_ref[1])); + } + std::vector error(dim); + for(int idim=0; idim 1e-13) { + std::cout << "Large error " << error[0] << std::endl; + for(int idim=0;idim +dealii::Point CurvManifold::push_forward(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + + dealii::Point x_ref; + dealii::Point x_phys; + for(int idim=0; idim (x_phys); // Trigonometric +} + +template +dealii::DerivativeForm<1,dim,dim> CurvManifold::push_forward_gradient(const dealii::Point &chart_point) const +{ + const double pi = atan(1)*4.0; + dealii::DerivativeForm<1, dim, dim> dphys_dref; + double beta = 1.0/10.0; + double alpha = 1.0/10.0; + dealii::Point x_ref; + for(int idim=0; idim +std::unique_ptr > CurvManifold::clone() const +{ + return std::make_unique>(); +} + +template +static dealii::Point warp (const dealii::Point &p) +{ + const double pi = atan(1)*4.0; + dealii::Point q = p; + + double beta =1.0/10.0; + double alpha =1.0/10.0; + if (dim == 2){ + q[dim-2] =p[dim-2] + beta*std::cos(pi/2.0 * p[dim-2]) * std::cos(3.0 * pi/2.0 * p[dim-1]); + q[dim-1] =p[dim-1] + beta*std::sin(2.0 * pi * (p[dim-2])) * std::cos(pi /2.0 * p[dim-1]); + } + if(dim==3){ + q[0] =p[0] + alpha*(std::cos(pi * p[2]) + std::cos(pi * p[1])); + q[1] =p[1] + alpha*exp(1.0-p[1])*(std::sin(pi * p[0]) + std::sin(pi* p[2])); + q[2] =p[2] + 1.0/20.0*( std::sin(2.0 * pi * p[0]) + std::sin(2.0 * pi * p[1])); + } + + return q; +} + +/**************************** + * End of Curvilinear Grid + * ***************************/ + +template +void compute_inverse_mass_matrix( + std::shared_ptr < PHiLiP::OPERATOR::OperatorsBase > &operators, + const std::array,PHILIP_DIM> &mapping_support_points, + const unsigned int n_metric_dofs, + const unsigned int n_quad_pts, const unsigned int n_dofs_cell, + const unsigned int poly_degree, const unsigned int grid_degree, + const std::vector &quad_weights, + dealii::FullMatrix &mass_inv) +{ + std::vector determinant_Jacobian(n_quad_pts); + operators->build_local_vol_determinant_Jac(grid_degree, poly_degree, n_quad_pts, n_metric_dofs, mapping_support_points, determinant_Jacobian); + + std::vector JxW(n_quad_pts); + for(unsigned int iquad=0; iquad local_mass_matrix(n_dofs_cell); + operators->build_local_Mass_Matrix(JxW, n_dofs_cell, n_quad_pts, poly_degree, local_mass_matrix); + + //For flux reconstruction + dealii::FullMatrix Flux_Reconstruction_operator(n_dofs_cell); + operators->build_local_Flux_Reconstruction_operator(local_mass_matrix, n_dofs_cell, poly_degree, Flux_Reconstruction_operator); + for (unsigned int itest=0; itest +void compute_weighted_inverse_mass_matrix(std::shared_ptr < PHiLiP::OPERATOR::OperatorsBase > &operators, + const std::array,PHILIP_DIM> &mapping_support_points, const unsigned int n_metric_dofs, + const unsigned int n_quad_pts, const unsigned int n_dofs_cell, + const unsigned int poly_degree, const unsigned int grid_degree, + const std::vector &quad_weights, + dealii::FullMatrix &mass_inv) +{ + std::vector determinant_Jacobian(n_quad_pts); + operators->build_local_vol_determinant_Jac(grid_degree, poly_degree, n_quad_pts, n_metric_dofs, mapping_support_points, determinant_Jacobian); + + std::vector W_J_inv(n_quad_pts); + for(unsigned int iquad=0; iquad local_mass_matrix(n_dofs_cell); + operators->build_local_Mass_Matrix(W_J_inv, n_dofs_cell, n_quad_pts, poly_degree, local_mass_matrix); + // For flux reconstruction + dealii::FullMatrix Flux_Reconstruction_operator(n_dofs_cell); + operators->build_local_Flux_Reconstruction_operator(local_mass_matrix, n_dofs_cell, poly_degree, Flux_Reconstruction_operator); + for (unsigned int itest=0; itest::digits10 + 1) << std::scientific; + const int dim = PHILIP_DIM; + dealii::ParameterHandler parameter_handler; + PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); + dealii::ConditionalOStream pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD)==0); + + PHiLiP::Parameters::AllParameters all_parameters_new; + all_parameters_new.parse_parameters (parameter_handler); + + // all_parameters_new.use_collocated_nodes=true; + all_parameters_new.use_curvilinear_split_form=true; + all_parameters_new.flux_reconstruction_type = Parameters::AllParameters::Flux_Reconstruction::cPlus; + + // unsigned int poly_degree = 3; + double left = 0.0; + double right = 1.0; + const bool colorize = true; + dealii::ConvergenceTable convergence_table; + const unsigned int igrid_start = 0; + const unsigned int n_grids = 1; + // setup time + // time_t tstart=0, tend=0, tstart_weight=0, tend_weight=0; + clock_t time_normal, time_weighted; + + for(unsigned int poly_degree = 6; poly_degree<7; poly_degree++){ + unsigned int grid_degree = poly_degree; + for(unsigned int igrid=igrid_start; igrid; + std::shared_ptr grid = std::make_shared( + MPI_COMM_WORLD, + typename dealii::Triangulation::MeshSmoothing( + dealii::Triangulation::smoothing_on_refinement | + dealii::Triangulation::smoothing_on_coarsening)); + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(igrid); + pcout<<" made grid for Index"<, *grid); + + // Assign a manifold to have curved geometry + const CurvManifold curv_manifold; + unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true + grid->reset_all_manifolds(); + grid->set_all_manifold_ids(manifold_id); + grid->set_manifold ( manifold_id, curv_manifold ); + //"END COMMENT" TO NOT WARP GRID + + // setup operator + // OPERATOR::OperatorsBase operators(&all_parameters_new, nstate, poly_degree, poly_degree, grid_degree); + // OPERATOR::OperatorsBaseState operators(&all_parameters_new, poly_degree, poly_degree); + // setup DG + // std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, grid); + std::shared_ptr < PHiLiP::DGBase > dg = PHiLiP::DGFactory::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid); + dg->allocate_system (); + + dealii::IndexSet locally_owned_dofs; + dealii::IndexSet ghost_dofs; + dealii::IndexSet locally_relevant_dofs; + locally_owned_dofs = dg->dof_handler.locally_owned_dofs(); + dealii::DoFTools::extract_locally_relevant_dofs(dg->dof_handler, ghost_dofs); + locally_relevant_dofs = ghost_dofs; + ghost_dofs.subtract_set(locally_owned_dofs); + + // setup metric and solve + const unsigned int max_dofs_per_cell = dg->dof_handler.get_fe_collection().max_dofs_per_cell(); + std::vector current_dofs_indices(max_dofs_per_cell); + const unsigned int n_dofs_cell = dg->operators->fe_collection_basis[poly_degree].dofs_per_cell; + const unsigned int n_quad_pts = dg->operators->volume_quadrature_collection[poly_degree].size(); + + const dealii::FESystem &fe_metric = (dg->high_order_grid->fe_system); + const unsigned int n_metric_dofs = fe_metric.dofs_per_cell; + auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active(); + + //loop over cells and do normal inv + pcout<<"time to do normal"<dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + // pcout<<"grid degree "< current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + for(int idim=0; idim vol_GLL(grid_degree +1); + for (unsigned int igrid_node = 0; igrid_node< n_metric_dofs/dim; ++igrid_node) { + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + mapping_support_points[istate][igrid_node] += val * fe_metric.shape_value_component(idof,vol_GLL.point(igrid_node),istate); + } + } + const std::vector &quad_weights = dg->operators->volume_quadrature_collection[poly_degree].get_weights(); + + //build ESFR mass matrix and invert regularly + dealii::FullMatrix mass_inv(n_dofs_cell); + time_normal = clock(); + compute_inverse_mass_matrix(dg->operators, mapping_support_points, n_metric_dofs/dim, n_quad_pts, n_dofs_cell, poly_degree, grid_degree, quad_weights, mass_inv); + time_normal = clock()-time_normal; + + }//end of cell loop + + // tend = time(0); + // time_normal = clock()-time_normal; + + pcout<<"time to do weighted"<high_order_grid->dof_handler_grid.begin_active(); + //loop over cells and do weight inv + // tstart_weight = time(0); + time_weighted = clock(); + for (auto current_cell = dg->dof_handler.begin_active(); current_cell!=dg->dof_handler.end(); ++current_cell, ++metric_cell) { + if (!current_cell->is_locally_owned()) continue; + + // pcout<<"grid degree "< current_metric_dofs_indices(n_metric_dofs); + metric_cell->get_dof_indices (current_metric_dofs_indices); + std::array,dim> mapping_support_points; + for(int idim=0; idim vol_GLL(grid_degree +1); + for (unsigned int igrid_node = 0; igrid_node< n_metric_dofs/dim; ++igrid_node) { + for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) { + const real val = (dg->high_order_grid->volume_nodes[current_metric_dofs_indices[idof]]); + const unsigned int istate = fe_metric.system_to_component_index(idof).first; + mapping_support_points[istate][igrid_node] += val * fe_metric.shape_value_component(idof,vol_GLL.point(igrid_node),istate); + } + } + const std::vector &quad_weights = dg->operators->volume_quadrature_collection[poly_degree].get_weights(); + + //do weight-adjusted inverse ESFR mass matrix + dealii::FullMatrix mass_inv(n_dofs_cell); + time_weighted = clock(); + compute_weighted_inverse_mass_matrix(dg->operators, mapping_support_points, n_metric_dofs/dim, n_quad_pts, n_dofs_cell, poly_degree, grid_degree, quad_weights, mass_inv); + time_weighted = clock() - time_weighted; + + }//end of cell loop + + // tend_weight = time(0); + // time_weighted = clock() - time_weighted; + }//end grid refinement loop + }//end poly degree loop + + // pcout<<"Normal Mass inv took "<::digits10 + 1) << std::scientific; const int dim = PHILIP_DIM; - const int nstate = 2; + const int nstate = 1; dealii::ParameterHandler parameter_handler; PHiLiP::Parameters::AllParameters::declare_parameters (parameter_handler); @@ -82,18 +79,17 @@ int main (int argc, char * argv[]) using FR_enum = Parameters::AllParameters::Flux_Reconstruction; all_parameters_new.flux_reconstruction_type = FR_enum::cHU; - // all_parameters_new.use_collocated_nodes=true; - all_parameters_new.overintegration = 2; + // all_parameters_new.use_collocated_nodes=true; + all_parameters_new.overintegration = 0; double left = 0.0; double right = 1.0; const bool colorize = true; - const unsigned int igrid= 2; - + const unsigned int igrid= 0; + const bool use_chebyshev = false; //Generate a standard grid - #if PHILIP_DIM==1 // dealii::parallel::distributed::Triangulation does not work for 1D using Triangulation = dealii::Triangulation; std::shared_ptr grid = std::make_shared( @@ -108,53 +104,76 @@ int main (int argc, char * argv[]) dealii::Triangulation::smoothing_on_refinement | dealii::Triangulation::smoothing_on_coarsening)); #endif - dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); - grid->refine_global(igrid); + dealii::GridGenerator::hyper_cube (*grid, left, right, colorize); + grid->refine_global(igrid); double max_dif_int_parts = 0.0; - for(unsigned int poly_degree=2; poly_degree<6; poly_degree++){ - - OPERATOR::OperatorBase operators(&all_parameters_new, poly_degree, poly_degree, poly_degree); + // for(unsigned int poly_degree=2; poly_degree<6; poly_degree++){ + for(unsigned int poly_degree=2; poly_degree<3; poly_degree++){ + // OPERATOR::OperatorsBase operators(&all_parameters_new, nstate, poly_degree, poly_degree, poly_degree); + OPERATOR::OperatorsBaseState operators(&all_parameters_new, poly_degree, poly_degree); const unsigned int n_dofs = operators.fe_collection_basis[poly_degree].dofs_per_cell; const unsigned int n_dofs_flux = operators.fe_collection_flux_basis[poly_degree].dofs_per_cell; const unsigned int n_quad_pts = operators.volume_quadrature_collection[poly_degree].size(); std::vector> vol_int_parts(dim); std::vector> face_int_parts(dim); + for(int idim=0; idim qpoint = operators.volume_quadrature_collection[poly_degree].point(iquad); + value += operators.basis_at_vol_cubature[poly_degree][iquad][itest] + * operators.basis_at_vol_cubature[poly_degree][iquad][idof] + * operators.volume_quadrature_collection[poly_degree].weight(iquad) + / (1.0/std::sqrt(qpoint[idim]*(1.0-qpoint[idim]))) + * ((2.0*qpoint[idim]-1.0)/(pow(qpoint[idim]*(1.0-qpoint[idim]), 3.0/2.0)*2.0)); } if(istate_test == istate_dof){ - unsigned int dof_index = idof + n_dofs_flux * istate_dof; - vol_int_parts[idim][itest][dof_index] += value; - vol_int_parts[idim][itest][dof_index] += operators.local_flux_basis_stiffness[poly_degree][istate_dof][idim][ishape_test][idof]; + // unsigned int dof_index = idof + n_dofs_flux * istate_dof; + vol_int_parts[idim][itest][idof] += value; + // vol_int_parts[idim][itest][dof_index] += operators.local_flux_basis_stiffness[poly_degree][istate_dof][idim][ishape_test][idof]; } } } } -// for(unsigned int itest=0; itest qpoint = operators.volume_quadrature_collection[poly_degree].point(iquad); + test += operators.volume_quadrature_collection[poly_degree].weight(iquad) + / (1.0/std::sqrt(qpoint[idim]*(1.0-qpoint[idim]))) + * ((2.0*qpoint[idim]-1.0)/(pow(qpoint[idim]*(1.0-qpoint[idim]), 3.0/2.0)*2.0)); + } } + pcout<<" THE TEST "<::faces_per_cell; iface++){ const dealii::Tensor<1,dim,real> unit_normal = dealii::GeometryInfo::unit_normal_vector[iface]; @@ -163,17 +182,27 @@ int main (int argc, char * argv[]) if(unit_normal[idim] != 0) jdim = idim; } -// pcout<<"face "<1e-7){ pcout<<" Surface operator not satisfy integration by parts !"<