From 7c67d584ac2ef81f41ab66e3d0ec3aa9accfbdc0 Mon Sep 17 00:00:00 2001 From: Romain Mottier Date: Fri, 9 May 2025 01:58:44 +0200 Subject: [PATCH 01/12] update --- apps/CMakeLists.txt | 10 ++++++++++ apps/unfitted_HHO/CMakeLists.txt | 5 +++++ apps/unfitted_HHO/src/unfitted_HHO.cpp | 6 ++++++ apps/unfitted_HHO/src/unfitted_HHO.cpp~ | 5 +++++ apps/wave_propagation/CMakeLists.txt | 5 +++++ apps/wave_propagation/src/wave_propagation.cpp | 11 +++++++++++ 6 files changed, 42 insertions(+) create mode 100644 apps/unfitted_HHO/CMakeLists.txt create mode 100644 apps/unfitted_HHO/src/unfitted_HHO.cpp create mode 100644 apps/unfitted_HHO/src/unfitted_HHO.cpp~ create mode 100644 apps/wave_propagation/CMakeLists.txt create mode 100644 apps/wave_propagation/src/wave_propagation.cpp diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index e3871658..3783f0d2 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -113,3 +113,13 @@ if (BUILD_APP_VEM_2D) add_subdirectory(vem2d) endif() + +option(BUILD_APP_UNFITTED_HHO "Build unfitted_HHO application" ON) +if (BUILD_APP_UNFITTED_HHO) + add_subdirectory(unfitted_HHO) +endif() + +option(BUILD_APP_WAVE_PROPAGATION "Build wave_propagation application" ON) +if (BUILD_APP_WAVE_PROPAGATION) + add_subdirectory(wave_propagation) +endif() diff --git a/apps/unfitted_HHO/CMakeLists.txt b/apps/unfitted_HHO/CMakeLists.txt new file mode 100644 index 00000000..46a19e9f --- /dev/null +++ b/apps/unfitted_HHO/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LINK_LIBS diskpp) + +add_executable(unfitted_HHO src/unfitted_HHO.cpp) +target_link_libraries(unfitted_HHO ${LINK_LIBS}) +install(TARGETS unfitted_HHO RUNTIME DESTINATION bin) diff --git a/apps/unfitted_HHO/src/unfitted_HHO.cpp b/apps/unfitted_HHO/src/unfitted_HHO.cpp new file mode 100644 index 00000000..fa8e2dfb --- /dev/null +++ b/apps/unfitted_HHO/src/unfitted_HHO.cpp @@ -0,0 +1,6 @@ +#include +#include +#include "diskpp/loaders/loader.hpp" + +int main(int argc, char **argv) { +} diff --git a/apps/unfitted_HHO/src/unfitted_HHO.cpp~ b/apps/unfitted_HHO/src/unfitted_HHO.cpp~ new file mode 100644 index 00000000..d55dbe25 --- /dev/null +++ b/apps/unfitted_HHO/src/unfitted_HHO.cpp~ @@ -0,0 +1,5 @@ +#include +#include +#include "diskpp/loaders/loader.hpp" +int main(int argc, char **argv) { +} diff --git a/apps/wave_propagation/CMakeLists.txt b/apps/wave_propagation/CMakeLists.txt new file mode 100644 index 00000000..c24869be --- /dev/null +++ b/apps/wave_propagation/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LINK_LIBS diskpp) + +add_executable(wave_propagation src/wave_propagation.cpp) +target_link_libraries(wave_propagation ${LINK_LIBS}) +install(TARGETS wave_propagation RUNTIME DESTINATION bin) diff --git a/apps/wave_propagation/src/wave_propagation.cpp b/apps/wave_propagation/src/wave_propagation.cpp new file mode 100644 index 00000000..0a35123e --- /dev/null +++ b/apps/wave_propagation/src/wave_propagation.cpp @@ -0,0 +1,11 @@ +#include +#include +#include "diskpp/loaders/loader.hpp" + +int main(int argc, char **argv) { +} + + + + + From 581d92422efbc18066c4e75c27e8d93b4b9250ca Mon Sep 17 00:00:00 2001 From: Romain Mottier Date: Fri, 9 May 2025 02:02:35 +0200 Subject: [PATCH 02/12] update --- .../wave_propagation/src/wave_propagation.cpp | 121 ++++++++++++++++-- 1 file changed, 110 insertions(+), 11 deletions(-) diff --git a/apps/wave_propagation/src/wave_propagation.cpp b/apps/wave_propagation/src/wave_propagation.cpp index 0a35123e..9f6dd014 100644 --- a/apps/wave_propagation/src/wave_propagation.cpp +++ b/apps/wave_propagation/src/wave_propagation.cpp @@ -1,11 +1,110 @@ -#include -#include -#include "diskpp/loaders/loader.hpp" - -int main(int argc, char **argv) { -} - - - - - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace Eigen; + +#include "timecounter.h" +#include "methods/hho" +#include "geometry/geometry.hpp" +#include "boundary_conditions/boundary_conditions.hpp" +#include "output/silo.hpp" + +// application common sources +#include "../common/display_settings.hpp" +#include "../common/fitted_geometry_builders.hpp" +#include "../common/linear_solver.hpp" +#include "../common/acoustic_material_data.hpp" +#include "../common/elastic_material_data.hpp" +#include "../common/scal_vec_analytic_functions.hpp" +#include "../common/preprocessor.hpp" +#include "../common/postprocessor.hpp" + +// RK schemes +#include "../common/dirk_hho_scheme.hpp" +#include "../common/dirk_butcher_tableau.hpp" +#include "../common/erk_butcher_tableau.hpp" +#include "../common/erk_hho_scheme.hpp" +#include "../common/erk_coupling_hho_scheme.hpp" + +// Prototypes: +// Computation of an empirical CFL criteria +#include "Prototypes/CFL/EAcoustic_CFL.hpp" // CFl - Acoustic +#include "Prototypes/CFL/EElasticity_CFL.hpp" // CFl - Linear Elasticity +#include "Prototypes/CFL/EHHOFirstOrderCFL.hpp" // CFl - Elasto-Acoustic Coupling +// Stability study & Spectral radius computation: +#include "Prototypes/Stability_Study/EAcoustic_stability.hpp" // Acoustic +#include "Prototypes/Stability_Study/EElastic_stability.hpp" // Linear Elasticity +#include "Prototypes/Stability_Study/EHHOFirstOrder_stability.hpp" // Elasto-Acoustic Coupling +// Convergence test on sinusoidal analytical solution - Debug Implicit Direct Solver!!!! +#include "Prototypes/Conv_Test/IAcoustic_conv_test.hpp" // Implicit Acoustic +#include "Prototypes/Conv_Test/IElastic_conv_test.hpp" // Implicit Elastic +#include "Prototypes/Conv_Test/IHHOFirstOrder.hpp" // Implicit Coupling +#include "Prototypes/Conv_Test/IHHOFirstOrder_conv_tests.hpp" // Explicit Coupling +#include "Prototypes/Conv_Test/EHHOFirstOrder.hpp" // Explicit Coupling +#include "Prototypes/Conv_Test/EHHOFirstOrder_conv_tests.hpp" // Explicit Coupling +// Pulses for comparison with Gar6more +#include "Prototypes/Pulses/HeterogeneousIHHOFirstOrder.hpp" // Implicit Pulse (adimensional) +#include "Prototypes/Pulses/HeterogeneousEHHOFirstOrder.hpp" // Explicit Pulse (adimensional) +#include "Prototypes/Pulses/ConicWavesIHHOFirstOrder.hpp" // Implicit Pulse (geophysic) +#include "Prototypes/Pulses/ConicWavesEHHOFirstOrder.hpp" // Implicit Pulse (geophysic) +// Sedimentary Basin +#include "Prototypes/Basin/BassinIHHOFirstOrder.hpp" // Implicit Sedimentary Basin +#include "Prototypes/Basin/Test_Laurent.hpp" // Implicit Sedimentary Basin +// #include "Prototypes/Basin/BassinEHHOFirstOrder.hpp" // Explicit Sedimentary Basin + +int main(int argc, char **argv){ + +// CFL tables: + // EAcoustic_CFL(argc, argv); + // EElasticity_CFL(argc, argv); + // EHHOFirstOrderCFL(argc, argv); + +// Stability study & Spectral radius computation: + // EAcoustic_stability(argc, argv); + // EElastic_stability(argc, argv); + // EHHOFirstOrder_stability(argc, argv); + +// Convergence test: + // IAcoustic_conv_test(argc, argv); + // IElastic_conv_test(argc, argv); + // IHHOFirstOrder(argc, argv); + // IHHOFirstOrder_conv_tests(argc, argv); + // EHHOFirstOrder(argc, argv); + // EHHOFirstOrder_conv_tests(argc, argv); + +// Pulse: + // HeterogeneousIHHOFirstOrder(argc, argv); + // HeterogeneousEHHOFirstOrder(argc, argv); + ConicWavesIHHOFirstOrder(argc, argv); + // ConicWavesEHHOFirstOrder(argc, argv); + +// Bassin sédimentaire: + // BassinIHHOFirstOrder(argc, argv); + // Test_Laurent(argc, argv); + // BassinEHHOFirstOrder(argc, argv); Not working + +} + + + + From a0e009add16d59d356470b261f352402b37251e0 Mon Sep 17 00:00:00 2001 From: Romain Mottier Date: Fri, 9 May 2025 10:06:25 +0200 Subject: [PATCH 03/12] update --- CMakeLists.txt | 4 + apps/wave_propagation/CMakeLists.txt | 3 +- apps/wave_propagation/src/CMakeLists.txt | 2 + .../src/common/CMakeLists.txt | 35 + .../src/common/acoustic_material_data.hpp | 91 + .../common/acoustic_one_field_assembler.hpp | 643 +++ .../common/acoustic_two_fields_assembler.hpp | 734 ++++ .../src/common/assembly_index.hpp | 49 + .../src/common/assembly_index_bis.hpp | 44 + .../common/deprecated/one_field_assembler.hpp | 260 ++ .../one_field_vectorial_assembler.hpp | 263 ++ .../three_fields_vectorial_assembler.hpp | 451 +++ .../deprecated/two_fields_assembler.hpp | 355 ++ .../src/common/dirk_butcher_tableau.hpp | 204 + .../src/common/dirk_hho_scheme.hpp | 132 + .../src/common/display_settings.hpp | 28 + .../src/common/elastic_material_data.hpp | 107 + .../elastoacoustic_four_fields_assembler.hpp | 1751 +++++++++ .../elastoacoustic_two_fields_assembler.hpp | 1181 ++++++ .../elastodynamic_one_field_assembler.hpp | 562 +++ .../elastodynamic_three_fields_assembler.hpp | 908 +++++ .../elastodynamic_two_fields_assembler.hpp | 879 +++++ .../src/common/erk_butcher_tableau.hpp | 253 ++ .../src/common/erk_coupling_hho_scheme.hpp | 476 +++ .../src/common/erk_hho_scheme.hpp | 290 ++ .../src/common/fitted_geometry_builders.hpp | 953 +++++ .../src/common/linear_solver.hpp | 339 ++ .../src/common/lsrk_butcher_tableau.hpp | 79 + .../src/common/postprocessor.hpp | 3449 +++++++++++++++++ .../src/common/preprocessor.hpp | 457 +++ .../src/common/scal_analytic_functions.hpp | 471 +++ .../common/scal_vec_analytic_functions.hpp | 941 +++++ .../src/common/sourceterm.hpp | 226 ++ .../src/common/sourceterm2.hpp | 271 ++ .../src/common/ssprk_hho_scheme.hpp | 329 ++ .../src/common/ssprk_shu_osher_tableau.hpp | 312 ++ .../src/common/vec_analytic_functions.hpp | 325 ++ .../wave_propagation/src/wave_propagation.cpp | 74 +- 38 files changed, 17893 insertions(+), 38 deletions(-) create mode 100644 apps/wave_propagation/src/CMakeLists.txt create mode 100644 apps/wave_propagation/src/common/CMakeLists.txt create mode 100644 apps/wave_propagation/src/common/acoustic_material_data.hpp create mode 100644 apps/wave_propagation/src/common/acoustic_one_field_assembler.hpp create mode 100644 apps/wave_propagation/src/common/acoustic_two_fields_assembler.hpp create mode 100644 apps/wave_propagation/src/common/assembly_index.hpp create mode 100644 apps/wave_propagation/src/common/assembly_index_bis.hpp create mode 100644 apps/wave_propagation/src/common/deprecated/one_field_assembler.hpp create mode 100644 apps/wave_propagation/src/common/deprecated/one_field_vectorial_assembler.hpp create mode 100644 apps/wave_propagation/src/common/deprecated/three_fields_vectorial_assembler.hpp create mode 100644 apps/wave_propagation/src/common/deprecated/two_fields_assembler.hpp create mode 100644 apps/wave_propagation/src/common/dirk_butcher_tableau.hpp create mode 100644 apps/wave_propagation/src/common/dirk_hho_scheme.hpp create mode 100644 apps/wave_propagation/src/common/display_settings.hpp create mode 100644 apps/wave_propagation/src/common/elastic_material_data.hpp create mode 100644 apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp create mode 100644 apps/wave_propagation/src/common/elastoacoustic_two_fields_assembler.hpp create mode 100644 apps/wave_propagation/src/common/elastodynamic_one_field_assembler.hpp create mode 100644 apps/wave_propagation/src/common/elastodynamic_three_fields_assembler.hpp create mode 100644 apps/wave_propagation/src/common/elastodynamic_two_fields_assembler.hpp create mode 100644 apps/wave_propagation/src/common/erk_butcher_tableau.hpp create mode 100644 apps/wave_propagation/src/common/erk_coupling_hho_scheme.hpp create mode 100644 apps/wave_propagation/src/common/erk_hho_scheme.hpp create mode 100644 apps/wave_propagation/src/common/fitted_geometry_builders.hpp create mode 100644 apps/wave_propagation/src/common/linear_solver.hpp create mode 100644 apps/wave_propagation/src/common/lsrk_butcher_tableau.hpp create mode 100644 apps/wave_propagation/src/common/postprocessor.hpp create mode 100644 apps/wave_propagation/src/common/preprocessor.hpp create mode 100644 apps/wave_propagation/src/common/scal_analytic_functions.hpp create mode 100644 apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp create mode 100644 apps/wave_propagation/src/common/sourceterm.hpp create mode 100644 apps/wave_propagation/src/common/sourceterm2.hpp create mode 100644 apps/wave_propagation/src/common/ssprk_hho_scheme.hpp create mode 100644 apps/wave_propagation/src/common/ssprk_shu_osher_tableau.hpp create mode 100644 apps/wave_propagation/src/common/vec_analytic_functions.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5563ca25..134420e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,8 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") endif() endif() +find_package(Spectra REQUIRED) + ###################################################################### ## Eigen3 #add_subdirectory(contrib/eigen) @@ -279,3 +281,5 @@ set(CPACK_DEBIAN_PACKAGE_SECTION "science") set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6,libgcc1,libstdc++6") include(CPack) + + diff --git a/apps/wave_propagation/CMakeLists.txt b/apps/wave_propagation/CMakeLists.txt index c24869be..688ddf5c 100644 --- a/apps/wave_propagation/CMakeLists.txt +++ b/apps/wave_propagation/CMakeLists.txt @@ -1,5 +1,6 @@ set(LINK_LIBS diskpp) add_executable(wave_propagation src/wave_propagation.cpp) -target_link_libraries(wave_propagation ${LINK_LIBS}) +target_link_libraries(wave_propagation ${LINK_LIBS} Spectra::Spectra) + install(TARGETS wave_propagation RUNTIME DESTINATION bin) diff --git a/apps/wave_propagation/src/CMakeLists.txt b/apps/wave_propagation/src/CMakeLists.txt new file mode 100644 index 00000000..24fdd91b --- /dev/null +++ b/apps/wave_propagation/src/CMakeLists.txt @@ -0,0 +1,2 @@ + +add_subdirectory(common) diff --git a/apps/wave_propagation/src/common/CMakeLists.txt b/apps/wave_propagation/src/common/CMakeLists.txt new file mode 100644 index 00000000..ed499c7d --- /dev/null +++ b/apps/wave_propagation/src/common/CMakeLists.txt @@ -0,0 +1,35 @@ + +set(fitted_waves_sources ${fitted_waves_sources} + #${CMAKE_CURRENT_SOURCE_DIR}/fitted_geometry_builders.cpp +PARENT_SCOPE) + +set(fitted_waves_headers ${fitted_waves_headers} + ${CMAKE_CURRENT_SOURCE_DIR}/display_settings.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/preprocessor.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/postprocessor.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/acoustic_material_data.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/elastic_material_data.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/scal_analytic_functions.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/vec_analytic_functions.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/scal_vec_analytic_functions.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/fitted_geometry_builders.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/assembly_index.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/acoustic_one_field_assembler.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/acoustic_two_fields_assembler.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/elastodynamic_one_field_assembler.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/elastodynamic_two_fields_assembler.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/elastodynamic_three_fields_assembler.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/elastoacoustic_two_fields_assembler.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/elastoacoustic_four_fields_assembler.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/fitted_geometry_builders.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/linear_solver.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/dirk_hho_scheme.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/erk_hho_scheme.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/ssprk_hho_scheme.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/dirk_butcher_tableau.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/erk_butcher_tableau.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/ssprk_shu_osher_tableau.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/lsrk_butcher_tableau.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/sourceterm.hpp +PARENT_SCOPE) + diff --git a/apps/wave_propagation/src/common/acoustic_material_data.hpp b/apps/wave_propagation/src/common/acoustic_material_data.hpp new file mode 100644 index 00000000..9b54ee8b --- /dev/null +++ b/apps/wave_propagation/src/common/acoustic_material_data.hpp @@ -0,0 +1,91 @@ +// +// acoustic_material_data.hpp +// acoustics +// +// Created by Omar Durán on 4/14/20. +// + +#pragma once +#ifndef acoustic_material_data_hpp +#define acoustic_material_data_hpp + +#include + +template +class acoustic_material_data { + + /// Fluid density + T m_rho; + + /// Compressional P-wave velocity + T m_vp; + +public: + + /// Default constructor + acoustic_material_data(T rho, T vp){ + m_rho = rho; + m_vp = vp; + } + + /// Copy constructor + acoustic_material_data(const acoustic_material_data & other){ + m_rho = other.m_rho; + m_vp = other.m_vp; + } + + /// Assignement constructor + const acoustic_material_data & operator=(const acoustic_material_data & other){ + + // check for self-assignment + if(&other == this){ + return *this; + } + + m_rho = other.m_rho; + m_vp = other.m_vp; + return *this; + + } + + /// Desconstructor + virtual ~acoustic_material_data(){ + + } + + /// Print class attributes + virtual void Print(std::ostream &out = std::cout) const{ + out << "\n density = " << m_rho; + out << "\n p-wave velocity = " << m_vp; + } + + /// Print class attributes + friend std::ostream & operator<<( std::ostream& out, const acoustic_material_data & material ){ + material.Print(out); + return out; + } + + void Set_rho(T rho) + { + m_rho = rho; + } + + T rho() + { + return m_rho; + } + + + void Set_vp(T vp) + { + m_vp = vp; + } + + T vp() + { + return m_vp; + } + +}; + +#endif /* acoustic_material_data_hpp */ diff --git a/apps/wave_propagation/src/common/acoustic_one_field_assembler.hpp b/apps/wave_propagation/src/common/acoustic_one_field_assembler.hpp new file mode 100644 index 00000000..5813419c --- /dev/null +++ b/apps/wave_propagation/src/common/acoustic_one_field_assembler.hpp @@ -0,0 +1,643 @@ +// +// acoustic_one_field_assembler.hpp +// acoustics +// +// Created by Omar Durán on 4/14/20. +// + +#pragma once +#ifndef acoustic_one_field_assembler_hpp +#define acoustic_one_field_assembler_hpp + +#include "diskpp/bases/bases.hpp" +#include "diskpp/methods/hho" +#include "../common/assembly_index.hpp" +#include "../common/acoustic_material_data.hpp" + +#ifdef HAVE_INTEL_TBB +#include +#endif + +template +class acoustic_one_field_assembler +{ + + + typedef disk::BoundaryConditions boundary_type; + using T = typename Mesh::coordinate_type; + + std::vector m_compress_indexes; + std::vector m_expand_indexes; + + disk::hho_degree_info m_hho_di; + boundary_type m_bnd; + std::vector< Triplet > m_triplets; + std::vector< Triplet > m_mass_triplets; + std::vector< acoustic_material_data > m_material; + std::vector< size_t > m_elements_with_bc_eges; + + std::vector< std::pair > m_f_l_indexes; + + size_t m_n_edges; + size_t m_n_essential_edges; + bool m_hho_stabilization_Q; + +public: + + SparseMatrix LHS; + Matrix RHS; + SparseMatrix MASS; + + acoustic_one_field_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const boundary_type& bnd) + : m_hho_di(hho_di), m_bnd(bnd), m_hho_stabilization_Q(true) + { + + auto is_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return bnd.is_dirichlet_face(fc_id); + }; + + m_n_edges = msh.faces_size(); + m_n_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_dirichlet); + + m_compress_indexes.resize( m_n_edges ); + m_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + size_t compressed_offset = 0; + for (size_t i = 0; i < m_n_edges; i++) + { + auto fc = *std::next(msh.faces_begin(), i); + if ( !is_dirichlet(fc) ) + { + m_compress_indexes.at(i) = compressed_offset; + m_expand_indexes.at(compressed_offset) = i; + compressed_offset++; + } + } + + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + size_t system_size = n_cbs * msh.cells_size() + n_fbs * (m_n_edges - m_n_essential_edges); + + LHS = SparseMatrix( system_size, system_size ); + RHS = Matrix::Zero( system_size ); + MASS = SparseMatrix( system_size, system_size ); + + classify_cells(msh); + expand_triplet(msh); + } + + void scatter_data(const std::pair & dest_indexes, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + size_t first_ind = dest_indexes.first; + size_t last_ind = dest_indexes.second; + size_t l = 0; + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ){ + m_triplets[first_ind+l] = Triplet(asm_map[i], asm_map[j], lhs(i,j)); + l++; + } + } + } + + size_t cell_nnz = (last_ind - first_ind); + assert( (l-1) == cell_nnz ); + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_bc_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( !asm_map[j].assemble() ) + RHS(int(asm_map[i])) -= lhs(i,j) * dirichlet_data(j); + + } + } + + } + + void scatter_rhs_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& rhs) + { + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == rhs.rows()); + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_mass_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& mass_matrix) + { + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == mass_matrix.rows() && asm_map.size() == mass_matrix.cols() ); + + for (size_t i = 0; i < mass_matrix.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < mass_matrix.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_mass_triplets.push_back( Triplet(asm_map[i], asm_map[j], mass_matrix(i,j)) ); + } + } + + } + + void assemble(const Mesh& msh, std::function rhs_fun){ + + LHS.setZero(); + RHS.setZero(); + #ifdef HAVE_INTEL_TBB + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh,&rhs_fun] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix laplacian_operator_loc = this->laplacian_operator(cell_ind, msh, cell); + auto cell_basis = make_scalar_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, rhs_fun); + this->scatter_data(m_f_l_indexes[cell_ind], msh, cell, laplacian_operator_loc, f_loc); + } + ); + #else + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix laplacian_operator_loc = laplacian_operator(cell_ind, msh, cell); + auto cell_basis = make_scalar_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, rhs_fun); + + scatter_data(m_f_l_indexes[cell_ind], msh, cell, laplacian_operator_loc, f_loc); + } + #endif + + finalize(); + } + + void apply_bc(const Mesh& msh, T scale = T(1.0)){ + + #ifdef HAVE_INTEL_TBB + size_t n_cells = m_elements_with_bc_eges.size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh,&scale] (size_t & i){ + size_t cell_ind = m_elements_with_bc_eges[i]; + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix laplacian_operator_loc = laplacian_operator(cell_ind, msh, cell); + laplacian_operator_loc *= scale; + scatter_bc_data(msh, cell, laplacian_operator_loc); + } + ); + #else + auto storage = msh.backend_storage(); + for (auto& cell_ind : m_elements_with_bc_eges) + { + auto& cell = storage->surfaces[cell_ind]; + Matrix laplacian_operator_loc = laplacian_operator(cell_ind, msh, cell); + laplacian_operator_loc *= scale; + scatter_bc_data(msh, cell, laplacian_operator_loc); + } + #endif + + } + + void assemble_rhs(const Mesh& msh, std::function rhs_fun){ + + RHS.setZero(); + #ifdef HAVE_INTEL_TBB + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh,&rhs_fun] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = make_scalar_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, rhs_fun); + this->scatter_rhs_data(msh, cell, f_loc); + } + ); + #else + auto contribute = [this,&msh,&rhs_fun] (const typename Mesh::cell_type& cell){ + auto cell_basis = make_scalar_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, rhs_fun); + this->scatter_rhs_data(msh, cell, f_loc); + }; + + for (auto& cell : msh){ + contribute(cell); + } + #endif + } + + void assemble_mass(const Mesh& msh){ + + MASS.setZero(); + size_t cell_ind = 0; + for (auto& cell : msh) + { + Matrix mass_matrix = mass_operator(cell_ind,msh,cell); + scatter_mass_data(msh, cell, mass_matrix); + cell_ind++; + } + finalize_mass(); + } + + Matrix laplacian_operator(size_t & cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell){ + + auto reconstruction_operator = make_scalar_hho_laplacian(msh, cell, m_hho_di); + Matrix R_operator = reconstruction_operator.second; + + + Matrix S_operator; + if(m_hho_stabilization_Q) + { + auto stabilization_operator = make_scalar_hho_stabilization(msh, cell, reconstruction_operator.first, m_hho_di); + S_operator = stabilization_operator; + }else{ + auto stabilization_operator = make_scalar_hdg_stabilization(msh, cell, m_hho_di); + S_operator = stabilization_operator; + } + acoustic_material_data & material = m_material[cell_ind]; + return (1.0/material.rho())*(R_operator + S_operator); + } + + Matrix mass_operator(size_t & cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell){ + + acoustic_material_data & material = m_material[cell_ind]; + auto scal_basis = disk::make_scalar_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix mass_matrix = disk::make_mass_matrix(msh, cell, scal_basis); + mass_matrix *= (1.0/(material.rho()*material.vp()*material.vp())); + return mass_matrix; + } + + void classify_cells(const Mesh& msh){ + + m_elements_with_bc_eges.clear(); + size_t cell_ind = 0; + for (auto& cell : msh) + { + auto face_list = faces(msh, cell); + for (size_t face_i = 0; face_i < face_list.size(); face_i++) + { + auto fc = face_list[face_i]; + auto fc_id = msh.lookup(fc); + bool is_dirichlet_Q = m_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + m_elements_with_bc_eges.push_back(cell_ind); + break; + } + } + cell_ind++; + } + } + + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function scal_fun){ + + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + size_t n_dof = n_cbs * msh.cells_size() + n_fbs * (m_n_edges - m_n_essential_edges); + x_glob = Matrix::Zero(n_dof); + for (auto& cell : msh) + { + Matrix x_proj_dof = project_function(msh, cell, m_hho_di.cell_degree(), scal_fun); + scatter_cell_dof_data(msh, cell, x_glob, x_proj_dof); + } + } + + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function scal_fun){ + + for (auto& cell : msh) + { + auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + auto face = fcs[i]; + auto fc_id = msh.lookup(face); + bool is_dirichlet_Q = m_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + continue; + } + Matrix x_proj_dof = project_function(msh, face, m_hho_di.face_degree(), scal_fun); + scatter_face_dof_data(msh, face, x_glob, x_proj_dof); + } + } + } + + void expand_triplet(const Mesh& msh){ + + size_t n_cells = msh.cells_size(); + m_f_l_indexes.reserve(n_cells); + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + size_t first_ind = 0; + size_t last_ind = 0; + for (auto& cell : msh) + { + auto fcs = faces(msh, cell); + last_ind = 0; + for (size_t i = 0; i < fcs.size(); i++) + { + auto face = fcs[i]; + auto fc_id = msh.lookup(face); + bool is_dirichlet_Q = m_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + continue; + } + last_ind += n_fbs; + } + last_ind = first_ind + n_cbs*n_cbs + 2.0*n_cbs*last_ind + last_ind*last_ind; + m_f_l_indexes.push_back(std::make_pair(first_ind,last_ind-1)); + first_ind = last_ind; + } + + // expanding global triplets + m_triplets.resize(last_ind); + } + + void clear(void) + { + m_elements_with_bc_eges.clear(); + m_f_l_indexes.clear(); + m_triplets.clear(); + m_mass_triplets.clear(); + } + + void finalize(void) + { + LHS.setFromTriplets( m_triplets.begin(), m_triplets.end() ); + m_triplets.clear(); + } + + void finalize_mass(void) + { + MASS.setFromTriplets( m_mass_triplets.begin(), m_mass_triplets.end() ); + m_mass_triplets.clear(); + } + + Matrix + gather_dof_data( const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& x_glob) const + { + auto num_faces = howmany_faces(msh, cl); + auto cell_ofs = disk::priv::offset(msh, cl); + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + Matrix x_local(n_cbs + num_faces * n_fbs ); + x_local.block(0, 0, n_cbs, 1) = x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) + { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_bnd.is_dirichlet_face( face_id)) + { + auto fb = disk::make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); + Matrix mass = make_mass_matrix(msh, fc, fb, m_hho_di.face_degree()); + auto velocity = m_bnd.dirichlet_boundary_func(face_id); + Matrix rhs = make_rhs(msh, fc, fb, velocity, m_hho_di.face_degree()); + x_local.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else + { + auto face_ofs = disk::priv::offset(msh, fc); + auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; + x_local.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); + } + } + return x_local; + } + + void + scatter_cell_dof_data( const Mesh& msh, const typename Mesh::cell_type& cell, + Matrix& x_glob, Matrix x_proj_dof) const + { + auto cell_ofs = disk::priv::offset(msh, cell); + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1) = x_proj_dof; + } + + void + scatter_face_dof_data( const Mesh& msh, const typename Mesh::face_type& face, + Matrix& x_glob, Matrix x_proj_dof) const + { + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(),Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + size_t n_cells = msh.cells_size(); + auto face_offset = disk::priv::offset(msh, face); + auto glob_offset = n_cbs * n_cells + m_compress_indexes.at(face_offset)*n_fbs; + x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; + } + + void load_material_data(const Mesh& msh){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + T rho = 1.0; + T vp = 1.0; + acoustic_material_data material(rho,vp); + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + m_material.push_back(material); + } + } + + void load_material_data(const Mesh& msh, acoustic_material_data & material){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + m_material.push_back(material); + } + } + + void load_material_data(const Mesh& msh, std::function(const typename Mesh::point_type& )> acoustic_mat_fun){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + for (auto& cell : msh) + { + auto bar = barycenter(msh, cell); + std::vector mat_data = acoustic_mat_fun(bar); + T rho = mat_data[0]; + T vp = mat_data[1]; + acoustic_material_data material(rho,vp); + m_material.push_back(material); + } + } + + void set_hdg_stabilization(){ + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) + { + m_hho_stabilization_Q = false; + std::cout << "Proceeding with HDG stabilization cell degree is higher than face degree." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + }else{ + std::cout << "Proceeding with HHO stabilization cell and face degree are equal." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + } + } + void set_hho_stabilization(){ + m_hho_stabilization_Q = true; + } + + boundary_type & get_bc_conditions(){ + return m_bnd; + } + + std::vector< acoustic_material_data > & get_material_data(){ + return m_material; + } + + size_t get_n_face_dof(){ + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + size_t n_face_dof = (m_n_edges - m_n_essential_edges) * n_fbs; + return n_face_dof; + } + + size_t get_n_cell_basis(){ + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(),Mesh::dimension); + return n_cbs; + } + + size_t get_n_face_basis(){ + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + return n_fbs; + } + + std::vector< std::pair > & get_f_l_indexes(){ + return m_f_l_indexes; + } + + std::vector< Triplet > & get_triplets(){ + return m_triplets; + } + + size_t get_cell_basis_data(){ + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(),Mesh::dimension); + return n_cbs; + } + +}; + +#endif /* acoustic_one_field_assembler_hpp */ diff --git a/apps/wave_propagation/src/common/acoustic_two_fields_assembler.hpp b/apps/wave_propagation/src/common/acoustic_two_fields_assembler.hpp new file mode 100644 index 00000000..67665f17 --- /dev/null +++ b/apps/wave_propagation/src/common/acoustic_two_fields_assembler.hpp @@ -0,0 +1,734 @@ +// +// acoustic_two_fields_assembler.hpp +// acoustics +// +// Created by Omar Durán on 4/21/20. +// + +#pragma once +#ifndef acoustic_two_fields_assembler_hpp +#define acoustic_two_fields_assembler_hpp + +#include "diskpp/bases/bases.hpp" +#include "diskpp/methods/hho" +#include "../common/assembly_index.hpp" +#include "../common/acoustic_material_data.hpp" + +#ifdef HAVE_INTEL_TBB +#include +#endif + +template +class acoustic_two_fields_assembler +{ + + typedef disk::BoundaryConditions boundary_type; + using T = typename Mesh::coordinate_type; + + std::vector m_compress_indexes; + std::vector m_expand_indexes; + + disk::hho_degree_info m_hho_di; + boundary_type m_bnd; + std::vector< Triplet > m_triplets; + std::vector< Triplet > m_mass_triplets; + std::vector< acoustic_material_data > m_material; + std::vector< size_t > m_elements_with_bc_eges; + + size_t m_n_edges; + size_t m_n_essential_edges; + bool m_hho_stabilization_Q; + bool m_scaled_stabilization_Q; + +public: + + SparseMatrix LHS; + Matrix RHS; + SparseMatrix MASS; + + acoustic_two_fields_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const boundary_type& bnd) + : m_hho_di(hho_di), m_bnd(bnd), m_hho_stabilization_Q(true), m_scaled_stabilization_Q(false) + { + + auto is_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return bnd.is_dirichlet_face(fc_id); + }; + + m_n_edges = msh.faces_size(); + m_n_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_dirichlet); + + m_compress_indexes.resize( m_n_edges ); + m_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + size_t compressed_offset = 0; + for (size_t i = 0; i < m_n_edges; i++) + { + auto fc = *std::next(msh.faces_begin(), i); + if ( !is_dirichlet(fc) ) + { + m_compress_indexes.at(i) = compressed_offset; + m_expand_indexes.at(compressed_offset) = i; + compressed_offset++; + } + } + + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + size_t system_size = n_cbs * msh.cells_size() + n_fbs * (m_n_edges - m_n_essential_edges); + + LHS = SparseMatrix( system_size, system_size ); + RHS = Matrix::Zero( system_size ); + MASS = SparseMatrix( system_size, system_size ); + + classify_cells(msh); + } + + void scatter_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + auto fcs = faces(msh, cl); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + } + } + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(size_t(asm_map[i])) += rhs(i); + } + + } + + void scatter_bc_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs) + { + + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + auto fcs = faces(msh, cl); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( !asm_map[j].assemble() ) + RHS(int(asm_map[i])) -= lhs(i,j) * dirichlet_data(j); + + } + } + + } + + void scatter_rhs_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& rhs) + { + + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == rhs.rows()); + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_mass_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& mass_matrix) + { + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == mass_matrix.rows() && asm_map.size() == mass_matrix.cols() ); + + for (size_t i = 0; i < mass_matrix.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < mass_matrix.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_mass_triplets.push_back( Triplet(asm_map[i], asm_map[j], mass_matrix(i,j)) ); + } + } + + } + + void assemble(const Mesh& msh, std::function rhs_fun){ + + LHS.setZero(); + RHS.setZero(); + size_t cell_ind = 0; + for (auto& cell : msh) + { + Matrix f_loc = mixed_rhs(msh, cell, rhs_fun); + Matrix mixed_operator_loc = mixed_operator(cell_ind, msh, cell); + scatter_data(msh, cell, mixed_operator_loc, f_loc); + cell_ind++; + } + finalize(); + } + + Matrix mixed_operator(size_t & cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell){ + acoustic_material_data & material = m_material[cell_ind]; + auto reconstruction_operator = mixed_scalar_reconstruction(msh, cell); + Matrix R_operator = reconstruction_operator.second; + auto n_rows = R_operator.rows(); + auto n_cols = R_operator.cols(); + + Matrix S_operator = Matrix::Zero(n_rows, n_cols); + if(m_hho_stabilization_Q) + { + auto stabilization_operator = make_scalar_hho_stabilization(msh, cell, reconstruction_operator.first, m_hho_di, m_scaled_stabilization_Q); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + }else{ + auto stabilization_operator = make_scalar_hdg_stabilization(msh, cell, m_hho_di, m_scaled_stabilization_Q); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + } + + T rho = material.rho(); + T vp = material.vp(); + return R_operator + ((1.0)/(vp*rho))*S_operator; + } + + void apply_bc(const Mesh& msh){ + + #ifdef HAVE_INTEL_TBB + size_t n_cells = m_elements_with_bc_eges.size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh] (size_t & i){ + size_t cell_ind = m_elements_with_bc_eges[i]; + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix mixed_operator_loc = mixed_operator(cell_ind, msh, cell); + scatter_bc_data(msh, cell, mixed_operator_loc); + } + ); + #else + auto storage = msh.backend_storage(); + for (auto& cell_ind : m_elements_with_bc_eges) + { + auto& cell = storage->surfaces[cell_ind]; + Matrix mixed_operator_loc = mixed_operator(cell_ind, msh, cell); + scatter_bc_data(msh, cell, mixed_operator_loc); + } + #endif + + } + + void assemble_rhs(const Mesh& msh, std::function & rhs_fun, size_t di = 0){ + + RHS.setZero(); + + #ifdef HAVE_INTEL_TBB + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh,&rhs_fun,&di] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix f_loc = this->mixed_rhs(msh, cell, rhs_fun,di); + this->scatter_rhs_data(msh, cell, f_loc); + } + ); + #else + auto contribute = [this,&msh,&rhs_fun,&di] (const typename Mesh::cell_type& cell){ + Matrix f_loc = this->mixed_rhs(msh, cell, rhs_fun,di); + this->scatter_rhs_data(msh, cell, f_loc); + }; + + for (auto& cell : msh){ + contribute(cell); + } + #endif + } + + void assemble_mass(const Mesh& msh, bool add_scalar_mass_Q = true){ + + MASS.setZero(); + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix mass_matrix = mass_operator(cell_ind, msh, cell, add_scalar_mass_Q); + scatter_mass_data(msh, cell, mass_matrix); + } + finalize_mass(); + } + + Matrix mass_operator(size_t & cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell, bool add_scalar_mass_Q = true){ + + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + + acoustic_material_data & material = m_material[cell_ind]; + Matrix mass_matrix = Matrix::Zero(n_cbs, n_cbs); + + auto recdeg = m_hho_di.reconstruction_degree(); + auto rec_basis = make_scalar_monomial_basis(msh, cell, recdeg); + auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension); + + Matrix mass_matrix_q_full = make_stiffness_matrix(msh, cell, rec_basis); + Matrix mass_matrix_q = Matrix::Zero(rbs-1, rbs-1); + mass_matrix_q = mass_matrix_q_full.block(1, 1, rbs-1, rbs-1); + mass_matrix_q *= material.rho(); + mass_matrix.block(0, 0, n_vec_cbs, n_vec_cbs) = mass_matrix_q; + + if (add_scalar_mass_Q) { + auto scal_basis = disk::make_scalar_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix mass_matrix_v = disk::make_mass_matrix(msh, cell, scal_basis); + mass_matrix_v *= (1.0/(material.rho()*material.vp()*material.vp())); + mass_matrix.block(n_vec_cbs, n_vec_cbs, n_scal_cbs, n_scal_cbs) = mass_matrix_v; + } + + return mass_matrix; + } + + void classify_cells(const Mesh& msh){ + + size_t cell_ind = 0; + for (auto& cell : msh) + { + auto face_list = faces(msh, cell); + for (size_t face_i = 0; face_i < face_list.size(); face_i++) + { + auto fc = face_list[face_i]; + auto fc_id = msh.lookup(fc); + bool is_dirichlet_Q = m_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + m_elements_with_bc_eges.push_back(cell_ind); + break; + } + } + cell_ind++; + } + } + + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function scal_fun, std::function(const typename Mesh::point_type& )> vec_fun){ + size_t n_dof = MASS.rows(); + x_glob = Matrix::Zero(n_dof); + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + for (auto& cell : msh) + { + + Matrix x_proj_vec_dof = project_vec_function(msh, cell, vec_fun); + Matrix x_proj_sca_dof = project_function(msh, cell, m_hho_di.cell_degree(), scal_fun); + + Matrix x_proj_dof = Matrix::Zero(n_cbs); + x_proj_dof.block(0, 0, n_vec_cbs, 1) = x_proj_vec_dof; + x_proj_dof.block(n_vec_cbs, 0, n_scal_cbs, 1) = x_proj_sca_dof; + scatter_cell_dof_data(msh, cell, x_glob, x_proj_dof); + } + } + + Matrix project_vec_function(const Mesh& msh, const typename Mesh::cell_type& cell, + std::function(const typename Mesh::point_type& )> vec_fun){ + + auto recdeg = m_hho_di.reconstruction_degree(); + auto rec_basis = make_scalar_monomial_basis(msh, cell, recdeg); + auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension); + Matrix mass_matrix_q_full = make_stiffness_matrix(msh, cell, rec_basis); + Matrix mass_matrix_q = Matrix::Zero(rbs-1, rbs-1); + mass_matrix_q = mass_matrix_q_full.block(1, 1, rbs-1, rbs-1); + + Matrix rhs = Matrix::Zero(rbs-1); + Matrix f_vec = Matrix::Zero(1, 2); + const auto qps = integrate(msh, cell, 2*recdeg); + for (auto& qp : qps) + { + auto dphi = rec_basis.eval_gradients(qp.point()); + std::vector flux = vec_fun(qp.point()); + f_vec(0,0) = flux[0]; + f_vec(0,1) = flux[1]; + for (size_t i = 0; i < rbs-1; i++){ + Matrix phi_i = dphi.block(i+1, 0, 1, 2).transpose(); + rhs(i,0) = rhs(i,0) + (qp.weight() * f_vec*phi_i)(0,0); + } + } + Matrix x_dof = mass_matrix_q.llt().solve(rhs); + return x_dof; + } + + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function scal_fun){ + + for (auto& cell : msh) + { + auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + auto face = fcs[i]; + auto fc_id = msh.lookup(face); + bool is_dirichlet_Q = m_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + continue; + } + Matrix x_proj_dof = project_function(msh, face, m_hho_di.face_degree(), scal_fun); + scatter_face_dof_data(msh, face, x_glob, x_proj_dof); + } + } + } + + void finalize(void) + { + LHS.setFromTriplets( m_triplets.begin(), m_triplets.end() ); + m_triplets.clear(); + } + + void finalize_mass(void) + { + MASS.setFromTriplets( m_mass_triplets.begin(), m_mass_triplets.end() ); + m_mass_triplets.clear(); + } + + Matrix + gather_dof_data( const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& x_glob) const + { + auto num_faces = howmany_faces(msh, cl); + auto cell_ofs = disk::priv::offset(msh, cl); + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + Matrix x_el(n_cbs + num_faces * n_fbs ); + x_el.block(0, 0, n_cbs, 1) = x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) + { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_bnd.is_dirichlet_face( face_id)) + { + auto fb = disk::make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); + Matrix mass = make_mass_matrix(msh, fc, fb, m_hho_di.face_degree()); + auto velocity = m_bnd.dirichlet_boundary_func(face_id); + Matrix rhs = make_rhs(msh, fc, fb, velocity, m_hho_di.face_degree()); + x_el.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else + { + auto face_ofs = disk::priv::offset(msh, fc); + auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; + x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); + } + } + return x_el; + } + + void scatter_cell_dof_data( const Mesh& msh, const typename Mesh::cell_type& cell, + Matrix& x_glob, Matrix &x_proj_dof) const + { + auto cell_ofs = disk::priv::offset(msh, cell); + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1) = x_proj_dof; + } + + void scatter_face_dof_data( const Mesh& msh, const typename Mesh::face_type& face, + Matrix& x_glob, Matrix &x_proj_dof) const + { + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + size_t n_cells = msh.cells_size(); + auto face_offset = disk::priv::offset(msh, face); + auto glob_offset = n_cbs * n_cells + m_compress_indexes.at(face_offset)*n_fbs; + x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; + } + + std::pair< Matrix, + Matrix > + mixed_scalar_reconstruction(const Mesh& msh, const typename Mesh::cell_type& cell) + { + using T = typename Mesh::coordinate_type; + typedef Matrix matrix_type; + typedef Matrix vector_type; + + const size_t DIM = Mesh::dimension; + + const auto recdeg = m_hho_di.reconstruction_degree(); + const auto celdeg = m_hho_di.cell_degree(); + const auto facdeg = m_hho_di.face_degree(); + + auto cb = make_scalar_monomial_basis(msh, cell, recdeg); + + const auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension); + const auto cbs = disk::scalar_basis_size(celdeg, Mesh::dimension); + const auto fbs = disk::scalar_basis_size(facdeg, Mesh::dimension - 1); + + const auto num_faces = howmany_faces(msh, cell); + + const matrix_type stiff = make_stiffness_matrix(msh, cell, cb); + matrix_type gr_lhs = matrix_type::Zero(rbs-1, rbs-1); + matrix_type gr_rhs = matrix_type::Zero(rbs-1, cbs + num_faces*fbs); + + gr_lhs = stiff.block(1, 1, rbs-1, rbs-1); + gr_rhs.block(0, 0, rbs-1, cbs) = stiff.block(1, 0, rbs-1, cbs); + + const auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + const auto fc = fcs[i]; + const auto n = normal(msh, cell, fc); + auto fb = make_scalar_monomial_basis(msh, fc, facdeg); + + auto qps_f = integrate(msh, fc, recdeg - 1 + std::max(facdeg,celdeg)); + for (auto& qp : qps_f) + { + vector_type c_phi_tmp = cb.eval_functions(qp.point()); + vector_type c_phi = c_phi_tmp.head(cbs); + Matrix c_dphi_tmp = cb.eval_gradients(qp.point()); + Matrix c_dphi = c_dphi_tmp.block(1, 0, rbs-1, DIM); + vector_type f_phi = fb.eval_functions(qp.point()); + gr_rhs.block(0, cbs+i*fbs, rbs-1, fbs) += qp.weight() * (c_dphi * n) * f_phi.transpose(); + gr_rhs.block(0, 0, rbs-1, cbs) -= qp.weight() * (c_dphi * n) * c_phi.transpose(); + } + } + + auto vec_cell_size = gr_lhs.cols(); + auto nrows = gr_rhs.cols()+vec_cell_size; + auto ncols = gr_rhs.cols()+vec_cell_size; + + // Shrinking data + matrix_type data_mixed = matrix_type::Zero(nrows,ncols); + data_mixed.block(0, vec_cell_size, vec_cell_size, ncols-vec_cell_size) = -gr_rhs; + data_mixed.block(vec_cell_size, 0, nrows-vec_cell_size, vec_cell_size) = gr_rhs.transpose(); + + matrix_type oper = gr_lhs.llt().solve(gr_rhs); + return std::make_pair(oper, data_mixed); + } + + Matrix + mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function & rhs_fun, size_t di = 0) + { + const auto recdeg = m_hho_di.reconstruction_degree(); + const auto celdeg = m_hho_di.cell_degree(); + const auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension) - 1; + const auto cbs = disk::scalar_basis_size(celdeg, Mesh::dimension) + rbs; + auto cell_basis = make_scalar_monomial_basis(msh, cell, celdeg); + using T = typename Mesh::coordinate_type; + + Matrix ret_loc = Matrix::Zero(cell_basis.size()); + Matrix ret = Matrix::Zero(cbs); + + const auto qps = integrate(msh, cell, 2 * (celdeg + di)); + + for (auto& qp : qps) + { + const auto phi = cell_basis.eval_functions(qp.point()); + const auto qp_f = disk::priv::inner_product(qp.weight(), rhs_fun(qp.point())); + ret_loc += disk::priv::outer_product(phi, qp_f); + } + ret.block(rbs,0,cell_basis.size(),1) = ret_loc; + return ret; + } + + void load_material_data(const Mesh& msh){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + T rho = 1.0; + T vp = 1.0; + acoustic_material_data material(rho,vp); + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + m_material.push_back(material); + } + } + + void load_material_data(const Mesh& msh, acoustic_material_data material){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + m_material.push_back(material); + } + } + + void load_material_data(const Mesh& msh, std::function(const typename Mesh::point_type& )> acoustic_mat_fun){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + for (auto& cell : msh) + { + auto bar = barycenter(msh, cell); + std::vector mat_data = acoustic_mat_fun(bar); + T rho = mat_data[0]; + T vp = mat_data[1]; + acoustic_material_data material(rho,vp); + m_material.push_back(material); + } + } + + void set_hdg_stabilization(){ + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) + { + m_hho_stabilization_Q = false; + std::cout << "Proceeding with HDG stabilization cell degree is higher than face degree." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + }else{ + std::cout << "Proceeding with HHO stabilization cell and face degree are equal." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + } + } + + void set_hho_stabilization(){ + m_hho_stabilization_Q = true; + } + + void set_scaled_stabilization(){ + m_scaled_stabilization_Q = true; + } + + boundary_type & get_bc_conditions(){ + return m_bnd; + } + + std::vector< acoustic_material_data > & get_material_data(){ + return m_material; + } + + size_t get_n_face_dof(){ + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + size_t n_face_dof = (m_n_edges - m_n_essential_edges) * n_fbs; + return n_face_dof; + } + + size_t get_n_faces(){ + return m_n_edges - m_n_essential_edges; + } + + size_t get_face_basis_data(){ + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + return n_fbs; + } + + size_t get_cell_basis_data(){ + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + return n_cbs; + } + +}; + +#endif /* acoustic_two_fields_assembler_hpp */ diff --git a/apps/wave_propagation/src/common/assembly_index.hpp b/apps/wave_propagation/src/common/assembly_index.hpp new file mode 100644 index 00000000..4da8c62d --- /dev/null +++ b/apps/wave_propagation/src/common/assembly_index.hpp @@ -0,0 +1,49 @@ +// +// assembly_index.hpp +// acoustics +// +// Created by Omar Durán on 5/6/20. +// + +#pragma once +#ifndef assembly_index_hpp +#define assembly_index_hpp + +#include + +class assembly_index +{ + size_t idx; + bool assem; + +public: + assembly_index(size_t i, bool as) + : idx(i), assem(as) + {} + + operator size_t() const + { + if (!assem) + throw std::logic_error("Invalid assembly_index"); + + return idx; + } + + bool assemble() const + { + return assem; + } + + size_t vidx() const + { + return idx; + } + + friend std::ostream& operator<<(std::ostream& os, const assembly_index& as) + { + os << "(" << as.idx << "," << as.assem << ")"; + return os; + } +}; + +#endif /* assembly_index_hpp */ diff --git a/apps/wave_propagation/src/common/assembly_index_bis.hpp b/apps/wave_propagation/src/common/assembly_index_bis.hpp new file mode 100644 index 00000000..6accf7c9 --- /dev/null +++ b/apps/wave_propagation/src/common/assembly_index_bis.hpp @@ -0,0 +1,44 @@ +// +// assembly_index.hpp +// acoustics +// +// Created by Omar Durán on 5/6/20. +// + +#pragma once +#ifndef assembly_index_hpp +#define assembly_index_hpp + +#include + +class assembly_index +{ + size_t idx; + bool assem; + +public: + assembly_index(size_t i, bool as) + : idx(i), assem(as) + {} + + operator size_t() const + { + if (!assem) + throw std::logic_error("Invalid assembly_index"); + + return idx; + } + + bool assemble() const + { + return assem; + } + + friend std::ostream& operator<<(std::ostream& os, const assembly_index& as) + { + os << "(" << as.idx << "," << as.assem << ")"; + return os; + } +}; + +#endif /* assembly_index_hpp */ diff --git a/apps/wave_propagation/src/common/deprecated/one_field_assembler.hpp b/apps/wave_propagation/src/common/deprecated/one_field_assembler.hpp new file mode 100644 index 00000000..d5985600 --- /dev/null +++ b/apps/wave_propagation/src/common/deprecated/one_field_assembler.hpp @@ -0,0 +1,260 @@ +// +// one_field_assembler.hpp +// acoustics +// +// Created by Omar Durán on 4/10/20. +// + +#pragma once +#ifndef one_field_assembler_hpp +#define one_field_assembler_hpp + +#include "diskpp/bases/bases.hpp" +#include "diskpp/methods/hho" + +template +class one_field_assembler +{ + + + typedef disk::BoundaryConditions boundary_type; + using T = typename Mesh::coordinate_type; + + std::vector m_compress_indexes; + std::vector m_expand_indexes; + + disk::hho_degree_info m_hho_di; + boundary_type m_bnd; + std::vector< Triplet > m_triplets; + + size_t m_n_edges; + size_t m_n_essential_edges; + bool m_hho_stabilization_Q; + + class assembly_index + { + size_t idx; + bool assem; + + public: + assembly_index(size_t i, bool as) + : idx(i), assem(as) + {} + + operator size_t() const + { + if (!assem) + throw std::logic_error("Invalid assembly_index"); + + return idx; + } + + bool assemble() const + { + return assem; + } + + friend std::ostream& operator<<(std::ostream& os, const assembly_index& as) + { + os << "(" << as.idx << "," << as.assem << ")"; + return os; + } + }; + +public: + + SparseMatrix LHS; + Matrix RHS; + + one_field_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const boundary_type& bnd) + : m_hho_di(hho_di), m_bnd(bnd), m_hho_stabilization_Q(true) + { + + auto is_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return bnd.is_dirichlet_face(fc_id); + }; + + m_n_edges = msh.faces_size(); + m_n_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_dirichlet); + + m_compress_indexes.resize( m_n_edges ); + m_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + size_t compressed_offset = 0; + for (size_t i = 0; i < m_n_edges; i++) + { + auto fc = *std::next(msh.faces_begin(), i); + if ( !is_dirichlet(fc) ) + { + m_compress_indexes.at(i) = compressed_offset; + m_expand_indexes.at(compressed_offset) = i; + compressed_offset++; + } + } + + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + size_t system_size = n_cbs * msh.cells_size() + n_fbs * (m_n_edges - m_n_essential_edges); + + LHS = SparseMatrix( system_size, system_size ); + RHS = Matrix::Zero( system_size ); + } + + void scatter_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + else + RHS(asm_map[i]) -= lhs(i,j) * dirichlet_data(j); + } + } + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(asm_map[i]) += rhs(i); + } + + } // + + void assemble(const Mesh& msh, std::function rhs_fun){ + + for (auto& cell : msh) + { + auto reconstruction_operator = make_scalar_hho_laplacian(msh, cell, m_hho_di); + Matrix R_operator = reconstruction_operator.second; + + + Matrix S_operator; + if(m_hho_stabilization_Q) + { + auto stabilization_operator = make_scalar_hho_stabilization(msh, cell, reconstruction_operator.first, m_hho_di); + S_operator = stabilization_operator; + }else{ + auto stabilization_operator = make_scalar_hdg_stabilization(msh, cell, m_hho_di); + S_operator = stabilization_operator; + } + + Matrix laplacian_operator_loc = R_operator + S_operator; + auto cell_basis = make_scalar_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, rhs_fun); + + scatter_data(msh, cell, laplacian_operator_loc, f_loc); + } + finalize(); + } + + void finalize(void) + { + LHS.setFromTriplets( m_triplets.begin(), m_triplets.end() ); + m_triplets.clear(); + } + + Matrix + gather_dof_data( const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& x_glob) const + { + auto num_faces = howmany_faces(msh, cl); + auto cell_ofs = disk::priv::offset(msh, cl); + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + Matrix x_el(n_cbs + num_faces * n_fbs ); + x_el.block(0, 0, n_cbs, 1) = x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) + { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_bnd.is_dirichlet_face( face_id)) + { + auto fb = disk::make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); + Matrix mass = make_mass_matrix(msh, fc, fb, m_hho_di.face_degree()); + auto velocity = m_bnd.dirichlet_boundary_func(face_id); + Matrix rhs = make_rhs(msh, fc, fb, velocity, m_hho_di.face_degree()); + x_el.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else + { + auto face_ofs = disk::priv::offset(msh, fc); + auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; + x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); + } + } + return x_el; + } + + void set_hdg_stabilization(){ + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) + { + m_hho_stabilization_Q = false; + std::cout << "Proceeding with HDG stabilization cell degree is higher than face degree." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + }else{ + std::cout << "Proceeding with HHO stabilization cell and face degree are equal." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + } + } + void set_hho_stabilization(){ + m_hho_stabilization_Q = true; + } +}; + +#endif /* one_field_assembler_hpp */ diff --git a/apps/wave_propagation/src/common/deprecated/one_field_vectorial_assembler.hpp b/apps/wave_propagation/src/common/deprecated/one_field_vectorial_assembler.hpp new file mode 100644 index 00000000..164a97e9 --- /dev/null +++ b/apps/wave_propagation/src/common/deprecated/one_field_vectorial_assembler.hpp @@ -0,0 +1,263 @@ +// +// one_field_vectorial_assembler.hpp +// acoustics +// +// Created by Omar Durán on 4/11/20. +// + +#pragma once +#ifndef one_field_vectorial_assembler_hpp +#define one_field_vectorial_assembler_hpp + +#include "diskpp/bases/bases.hpp" +#include "diskpp/methods/hho" + +template +class one_field_vectorial_assembler +{ + + + typedef disk::BoundaryConditions boundary_type; + using T = typename Mesh::coordinate_type; + + std::vector m_compress_indexes; + std::vector m_expand_indexes; + + disk::hho_degree_info m_hho_di; + boundary_type m_bnd; + std::vector< Triplet > m_triplets; + + size_t m_n_edges; + size_t m_n_essential_edges; + bool m_hho_stabilization_Q; + + class assembly_index + { + size_t idx; + bool assem; + + public: + assembly_index(size_t i, bool as) + : idx(i), assem(as) + {} + + operator size_t() const + { + if (!assem) + throw std::logic_error("Invalid assembly_index"); + + return idx; + } + + bool assemble() const + { + return assem; + } + + friend std::ostream& operator<<(std::ostream& os, const assembly_index& as) + { + os << "(" << as.idx << "," << as.assem << ")"; + return os; + } + }; + +public: + + SparseMatrix LHS; + Matrix RHS; + + one_field_vectorial_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const boundary_type& bnd) + : m_hho_di(hho_di), m_bnd(bnd), m_hho_stabilization_Q(true) + { + + auto is_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return bnd.is_dirichlet_face(fc_id); + }; + + m_n_edges = msh.faces_size(); + m_n_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_dirichlet); + + m_compress_indexes.resize( m_n_edges ); + m_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + size_t compressed_offset = 0; + for (size_t i = 0; i < m_n_edges; i++) + { + auto fc = *std::next(msh.faces_begin(), i); + if ( !is_dirichlet(fc) ) + { + m_compress_indexes.at(i) = compressed_offset; + m_expand_indexes.at(compressed_offset) = i; + compressed_offset++; + } + } + + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + size_t system_size = n_cbs * msh.cells_size() + n_fbs * (m_n_edges - m_n_essential_edges); + + LHS = SparseMatrix( system_size, system_size ); + RHS = Matrix::Zero( system_size ); + } + + void scatter_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + else + RHS(asm_map[i]) -= lhs(i,j) * dirichlet_data(j); + } + } + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(asm_map[i]) += rhs(i); + } + + } // + + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ + + for (auto& cell : msh) + { + auto reconstruction_operator = make_matrix_symmetric_gradrec(msh, cell, m_hho_di); + auto rec_for_stab = make_vector_hho_symmetric_laplacian(msh, cell, m_hho_di); + auto divergence_operator = make_hho_divergence_reconstruction(msh, cell, m_hho_di); + + Matrix R_operator = reconstruction_operator.second; + + + Matrix S_operator; + if(m_hho_stabilization_Q) + { + auto stabilization_operator = make_vector_hho_stabilization(msh, cell, rec_for_stab.first, m_hho_di); + S_operator = stabilization_operator; + }else{ + auto stabilization_operator = make_vector_hdg_stabilization(msh, cell, m_hho_di); + S_operator = stabilization_operator; + } + + Matrix vectorial_laplacian_operator_loc = 2.0*(R_operator + S_operator)+divergence_operator.second; + auto cell_basis = make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, rhs_fun); + + scatter_data(msh, cell, vectorial_laplacian_operator_loc, f_loc); + } + finalize(); + } + + void finalize(void) + { + LHS.setFromTriplets( m_triplets.begin(), m_triplets.end() ); + m_triplets.clear(); + } + + Matrix + gather_dof_data( const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& x_glob) const + { + auto num_faces = howmany_faces(msh, cl); + auto cell_ofs = disk::priv::offset(msh, cl); + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + Matrix x_el(n_cbs + num_faces * n_fbs ); + x_el.block(0, 0, n_cbs, 1) = x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) + { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_bnd.is_dirichlet_face( face_id)) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(face_id); + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + x_el.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else + { + auto face_ofs = disk::priv::offset(msh, fc); + auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; + x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); + } + } + return x_el; + } + + void set_hdg_stabilization(){ + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) + { + m_hho_stabilization_Q = false; + std::cout << "Proceeding with HDG stabilization cell degree is higher than face degree." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + }else{ + std::cout << "Proceeding with HHO stabilization cell and face degree are equal." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + } + } + void set_hho_stabilization(){ + m_hho_stabilization_Q = true; + } +}; + +#endif /* one_field_vectorial_assembler_hpp */ diff --git a/apps/wave_propagation/src/common/deprecated/three_fields_vectorial_assembler.hpp b/apps/wave_propagation/src/common/deprecated/three_fields_vectorial_assembler.hpp new file mode 100644 index 00000000..c24bd4c7 --- /dev/null +++ b/apps/wave_propagation/src/common/deprecated/three_fields_vectorial_assembler.hpp @@ -0,0 +1,451 @@ +// +// three_fields_vectorial_assembler.hpp +// acoustics +// +// Created by Omar Durán on 4/12/20. +// + +#pragma once +#ifndef three_fields_vectorial_assembler_hpp +#define three_fields_vectorial_assembler_hpp + +#include "diskpp/bases/bases.hpp" +#include "diskpp/methods/hho" + +template +class three_fields_vectorial_assembler +{ + + + typedef disk::BoundaryConditions boundary_type; + using T = typename Mesh::coordinate_type; + + std::vector m_compress_indexes; + std::vector m_expand_indexes; + + disk::hho_degree_info m_hho_di; + boundary_type m_bnd; + std::vector< Triplet > m_triplets; + + size_t m_n_edges; + size_t m_n_essential_edges; + bool m_hho_stabilization_Q; + + class assembly_index + { + size_t idx; + bool assem; + + public: + assembly_index(size_t i, bool as) + : idx(i), assem(as) + {} + + operator size_t() const + { + if (!assem) + throw std::logic_error("Invalid assembly_index"); + + return idx; + } + + bool assemble() const + { + return assem; + } + + friend std::ostream& operator<<(std::ostream& os, const assembly_index& as) + { + os << "(" << as.idx << "," << as.assem << ")"; + return os; + } + }; + +public: + + SparseMatrix LHS; + Matrix RHS; + + three_fields_vectorial_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const boundary_type& bnd) + : m_hho_di(hho_di), m_bnd(bnd), m_hho_stabilization_Q(true) + { + + auto is_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return bnd.is_dirichlet_face(fc_id); + }; + + m_n_edges = msh.faces_size(); + m_n_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_dirichlet); + + m_compress_indexes.resize( m_n_edges ); + m_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + size_t compressed_offset = 0; + for (size_t i = 0; i < m_n_edges; i++) + { + auto fc = *std::next(msh.faces_begin(), i); + if ( !is_dirichlet(fc) ) + { + m_compress_indexes.at(i) = compressed_offset; + m_expand_indexes.at(compressed_offset) = i; + compressed_offset++; + } + } + + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + size_t system_size = n_cbs * msh.cells_size() + n_fbs * (m_n_edges - m_n_essential_edges); + + LHS = SparseMatrix( system_size, system_size ); + RHS = Matrix::Zero( system_size ); + } + + void scatter_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + else + RHS(asm_map[i]) -= lhs(i,j) * dirichlet_data(j); + } + } + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(asm_map[i]) += rhs(i); + } + + } + + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ + + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + for (auto& cell : msh) + { + auto reconstruction_operator = strain_tensor_reconstruction(msh, cell); + Matrix R_operator = reconstruction_operator.second; + auto n_rows = R_operator.rows(); + auto n_cols = R_operator.cols(); + + // Weak hydrostatic component + auto divergence_operator = div_vector_reconstruction(msh, cell); + Matrix D_operator = divergence_operator.second; + + Matrix S_operator = Matrix::Zero(n_rows, n_cols); + if(m_hho_stabilization_Q) + { + auto rec_for_stab = make_vector_hho_symmetric_laplacian(msh, cell, m_hho_di); + auto stabilization_operator = make_vector_hho_stabilization(msh, cell, rec_for_stab.first, m_hho_di); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + }else{ + auto stabilization_operator = make_vector_hdg_stabilization(msh, cell, m_hho_di); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + } + + // For the sake of clarity ... + T lambda, mu; + lambda = 1.0; + mu = 1.0; + + R_operator.block(0, 0, n_ten_cbs, n_ten_cbs) *= (1.0/(2.0*mu)); + D_operator.block(0, 0, n_sca_cbs, n_sca_cbs) *= (1.0/(lambda)); + + Matrix mixed_elastic_hho_operator = R_operator + D_operator + 2.0*mu*S_operator; + Matrix f_loc = mixed_rhs(msh, cell, rhs_fun); + + scatter_data(msh, cell, mixed_elastic_hho_operator, f_loc); + } + finalize(); + } + + void finalize(void) + { + LHS.setFromTriplets( m_triplets.begin(), m_triplets.end() ); + m_triplets.clear(); + } + + Matrix + gather_dof_data( const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& x_glob) const + { + auto num_faces = howmany_faces(msh, cl); + auto cell_ofs = disk::priv::offset(msh, cl); + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + Matrix x_el(n_vec_cbs + num_faces * n_fbs ); + x_el.block(0, 0, n_vec_cbs, 1) = x_glob.block(cell_ofs * n_cbs + n_ten_cbs + n_sca_cbs, 0, n_vec_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) + { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_bnd.is_dirichlet_face( face_id)) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(face_id); + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + x_el.block(n_vec_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else + { + auto face_ofs = disk::priv::offset(msh, fc); + auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; + x_el.block(n_vec_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); + } + } + return x_el; + } + + std::pair< Matrix, + Matrix > + strain_tensor_reconstruction(const Mesh& msh, const typename Mesh::cell_type& cell) + { + + using T = typename Mesh::coordinate_type; + typedef Matrix matrix_type; + + const size_t N = Mesh::dimension; + + auto graddeg = m_hho_di.grad_degree(); + auto celdeg = m_hho_di.cell_degree(); + auto facdeg = m_hho_di.face_degree(); + + auto ten_b = make_sym_matrix_monomial_basis(msh, cell, graddeg); + auto vec_b = make_vector_monomial_basis(msh, cell, celdeg); + + auto ten_bs = disk::sym_matrix_basis_size(graddeg, Mesh::dimension, Mesh::dimension); + auto sca_bs = disk::scalar_basis_size(facdeg, Mesh::dimension); + auto vec_bs = disk::vector_basis_size(celdeg, Mesh::dimension, Mesh::dimension); + auto fbs = disk::vector_basis_size(facdeg, Mesh::dimension - 1, Mesh::dimension); + + auto num_faces = howmany_faces(msh, cell); + + matrix_type gr_lhs = matrix_type::Zero(ten_bs, ten_bs); + matrix_type gr_rhs = matrix_type::Zero(ten_bs, vec_bs + num_faces * fbs); + + const auto qps = integrate(msh, cell, 2 * graddeg); + + size_t dec = 0; + if (N == 3) + dec = 6; + else if (N == 2) + dec = 3; + else + std::logic_error("Expected 3 >= dim > 1"); + + for (auto& qp : qps) + { + const auto gphi = ten_b.eval_functions(qp.point()); + + for (size_t j = 0; j < ten_bs; j++) + { + + auto qp_gphi_j = disk::priv::inner_product(qp.weight(), gphi[j]); + for (size_t i = j; i < ten_bs; i += dec){ + gr_lhs(i, j) += disk::priv::inner_product(gphi[i], qp_gphi_j); + } + } + } + + // upper part + for (size_t j = 0; j < ten_bs; j++) + for (size_t i = 0; i < j; i++) + gr_lhs(i, j) = gr_lhs(j, i); + + // compute rhs + if (celdeg > 0) + { + const auto qpc = integrate(msh, cell, graddeg + celdeg - 1); + for (auto& qp : qpc) + { + const auto gphi = ten_b.eval_functions(qp.point()); + const auto dphi = vec_b.eval_sgradients(qp.point()); + const auto qp_dphi = disk::priv::inner_product(qp.weight(), dphi); + + gr_rhs.block(0, 0, ten_bs, vec_bs) += disk::priv::outer_product(gphi, qp_dphi); + + } // end qp + } + + const auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + const auto fc = fcs[i]; + const auto n = normal(msh, cell, fc); + const auto fb = make_vector_monomial_basis(msh, fc, facdeg); + + const auto qps_f = integrate(msh, fc, graddeg + std::max(celdeg, facdeg)); + for (auto& qp : qps_f) + { + const auto gphi = ten_b.eval_functions(qp.point()); + const auto cphi = vec_b.eval_functions(qp.point()); + const auto fphi = fb.eval_functions(qp.point()); + + const auto qp_gphi_n = disk::priv::inner_product(gphi, disk::priv::inner_product(qp.weight(), n)); + gr_rhs.block(0, vec_bs + i * fbs, ten_bs, fbs) += disk::priv::outer_product(qp_gphi_n, fphi); + gr_rhs.block(0, 0, ten_bs, vec_bs) -= disk::priv::outer_product(qp_gphi_n, cphi); + } + } + + auto n_rows = gr_rhs.cols() + ten_bs + sca_bs; + auto n_cols = gr_rhs.cols() + ten_bs + sca_bs; + + // Shrinking data + matrix_type data_mixed = matrix_type::Zero(n_rows,n_cols); + data_mixed.block(0, 0, ten_bs, ten_bs) = gr_lhs; + data_mixed.block(0, (ten_bs + sca_bs), ten_bs, n_cols-(ten_bs + sca_bs)) = -gr_rhs; + data_mixed.block((ten_bs + sca_bs), 0, n_rows-(ten_bs + sca_bs), ten_bs) = gr_rhs.transpose(); + + matrix_type oper = gr_lhs.llt().solve(gr_rhs); + return std::make_pair(oper, data_mixed); + } + + std::pair< Matrix, + Matrix > + div_vector_reconstruction(const Mesh& msh, const typename Mesh::cell_type& cell) + { + using T = typename Mesh::coordinate_type; + typedef Matrix matrix_type; + + auto graddeg = m_hho_di.grad_degree(); + auto facedeg = m_hho_di.face_degree(); + auto ten_bs = disk::sym_matrix_basis_size(graddeg, Mesh::dimension, Mesh::dimension); + auto sca_bs = disk::scalar_basis_size(facedeg, Mesh::dimension); + + auto cbas_s = make_scalar_monomial_basis(msh, cell, m_hho_di.face_degree()); + auto dr_lhs = make_mass_matrix(msh, cell, cbas_s); + auto dr_rhs = make_hho_divergence_reconstruction_rhs(msh, cell, m_hho_di); + + assert( dr_lhs.rows() == sca_bs && dr_lhs.cols() == sca_bs ); + + // Shrinking data + auto n_rows = dr_rhs.cols() + ten_bs + sca_bs; + auto n_cols = dr_rhs.cols() + ten_bs + sca_bs; + matrix_type data_mixed = matrix_type::Zero(n_rows,n_cols); + data_mixed.block(ten_bs, ten_bs, sca_bs, sca_bs) = dr_lhs; + data_mixed.block(ten_bs, (ten_bs + sca_bs), sca_bs, n_cols-(ten_bs + sca_bs)) = -dr_rhs; + data_mixed.block((ten_bs + sca_bs), ten_bs, n_rows-(ten_bs + sca_bs), sca_bs) = dr_rhs.transpose(); + + matrix_type oper = dr_lhs.ldlt().solve(dr_rhs); + return std::make_pair(oper, data_mixed); + } + + Matrix + mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> rhs_fun, size_t di = 0) + { + auto recdeg = m_hho_di.grad_degree(); + auto celdeg = m_hho_di.cell_degree(); + auto facdeg = m_hho_di.face_degree(); + + auto ten_bs = disk::sym_matrix_basis_size(recdeg, Mesh::dimension, Mesh::dimension); + auto sca_bs = disk::scalar_basis_size(facdeg, Mesh::dimension); + auto vec_bs = disk::vector_basis_size(celdeg, Mesh::dimension, Mesh::dimension); + size_t n_cbs = ten_bs + sca_bs + vec_bs; + auto cell_basis = make_vector_monomial_basis(msh, cell, celdeg); + using T = typename Mesh::coordinate_type; + + Matrix ret_loc = Matrix::Zero(cell_basis.size()); + Matrix ret = Matrix::Zero(n_cbs); + + const auto qps = integrate(msh, cell, 2 * (celdeg + di)); + + for (auto& qp : qps) + { + const auto phi = cell_basis.eval_functions(qp.point()); + const auto qp_f = disk::priv::inner_product(qp.weight(), rhs_fun(qp.point())); + ret_loc += disk::priv::outer_product(phi, qp_f); + } + ret.block(ten_bs + sca_bs,0,vec_bs,1) = ret_loc; + return ret; + } + + void set_hdg_stabilization(){ + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) + { + m_hho_stabilization_Q = false; + std::cout << "Proceeding with HDG stabilization cell degree is higher than face degree." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + }else{ + std::cout << "Proceeding with HHO stabilization cell and face degree are equal." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + } + } + void set_hho_stabilization(){ + m_hho_stabilization_Q = true; + } +}; + +#endif /* three_fields_vectorial_assembler_hpp */ diff --git a/apps/wave_propagation/src/common/deprecated/two_fields_assembler.hpp b/apps/wave_propagation/src/common/deprecated/two_fields_assembler.hpp new file mode 100644 index 00000000..997df4f8 --- /dev/null +++ b/apps/wave_propagation/src/common/deprecated/two_fields_assembler.hpp @@ -0,0 +1,355 @@ +// +// two_fields_assembler.hpp +// acoustics +// +// Created by Omar Durán on 4/10/20. +// + +#ifndef two_fields_assembler_hpp +#define two_fields_assembler_hpp + +#include "diskpp/bases/bases.hpp" +#include "diskpp/methods/hho" + +template +class two_fields_assembler +{ + + + typedef disk::BoundaryConditions boundary_type; + using T = typename Mesh::coordinate_type; + + std::vector m_compress_indexes; + std::vector m_expand_indexes; + + disk::hho_degree_info m_hho_di; + boundary_type m_bnd; + std::vector< Triplet > m_triplets; + + size_t m_n_edges; + size_t m_n_essential_edges; + bool m_hho_stabilization_Q; + + class assembly_index + { + size_t idx; + bool assem; + + public: + assembly_index(size_t i, bool as) + : idx(i), assem(as) + {} + + operator size_t() const + { + if (!assem) + throw std::logic_error("Invalid assembly_index"); + + return idx; + } + + bool assemble() const + { + return assem; + } + + friend std::ostream& operator<<(std::ostream& os, const assembly_index& as) + { + os << "(" << as.idx << "," << as.assem << ")"; + return os; + } + }; + +public: + + SparseMatrix LHS; + Matrix RHS; + + two_fields_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const boundary_type& bnd) + : m_hho_di(hho_di), m_bnd(bnd), m_hho_stabilization_Q(true) + { + + auto is_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return bnd.is_dirichlet_face(fc_id); + }; + + m_n_edges = msh.faces_size(); + m_n_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_dirichlet); + + m_compress_indexes.resize( m_n_edges ); + m_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + size_t compressed_offset = 0; + for (size_t i = 0; i < m_n_edges; i++) + { + auto fc = *std::next(msh.faces_begin(), i); + if ( !is_dirichlet(fc) ) + { + m_compress_indexes.at(i) = compressed_offset; + m_expand_indexes.at(compressed_offset) = i; + compressed_offset++; + } + } + + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + size_t system_size = n_cbs * msh.cells_size() + n_fbs * (m_n_edges - m_n_essential_edges); + + LHS = SparseMatrix( system_size, system_size ); + RHS = Matrix::Zero( system_size ); + } + + void scatter_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + else + RHS(asm_map[i]) -= lhs(i,j) * dirichlet_data(j); + } + } + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(asm_map[i]) += rhs(i); + } + + } + + void assemble(const Mesh& msh, std::function rhs_fun){ + + for (auto& cell : msh) + { + auto reconstruction_operator = mixed_scalar_reconstruction(msh, cell); + Matrix R_operator = reconstruction_operator.second; + auto n_rows = R_operator.rows(); + auto n_cols = R_operator.cols(); + + Matrix S_operator = Matrix::Zero(n_rows, n_cols); + if(m_hho_stabilization_Q) + { + auto stabilization_operator = make_scalar_hho_stabilization(msh, cell, reconstruction_operator.first, m_hho_di); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + }else{ + auto stabilization_operator = make_scalar_hdg_stabilization(msh, cell, m_hho_di); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + } + + Matrix mixed_operator_loc = R_operator + S_operator; + Matrix f_loc = mixed_rhs(msh, cell, rhs_fun); + + scatter_data(msh, cell, mixed_operator_loc, f_loc); + } + finalize(); + } + + void finalize(void) + { + LHS.setFromTriplets( m_triplets.begin(), m_triplets.end() ); + m_triplets.clear(); + } + + Matrix + gather_dof_data( const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& x_glob) const + { + auto num_faces = howmany_faces(msh, cl); + auto cell_ofs = disk::priv::offset(msh, cl); + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + Matrix x_el(n_cbs + num_faces * n_fbs ); + x_el.block(0, 0, n_cbs, 1) = x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) + { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_bnd.is_dirichlet_face( face_id)) + { + auto fb = disk::make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); + Matrix mass = make_mass_matrix(msh, fc, fb, m_hho_di.face_degree()); + auto velocity = m_bnd.dirichlet_boundary_func(face_id); + Matrix rhs = make_rhs(msh, fc, fb, velocity, m_hho_di.face_degree()); + x_el.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else + { + auto face_ofs = disk::priv::offset(msh, fc); + auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; + x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); + } + } + return x_el; + } + + std::pair< Matrix, + Matrix > + mixed_scalar_reconstruction(const Mesh& msh, const typename Mesh::cell_type& cell) + { + using T = typename Mesh::coordinate_type; + typedef Matrix matrix_type; + typedef Matrix vector_type; + + const size_t DIM = Mesh::dimension; + + const auto recdeg = m_hho_di.reconstruction_degree(); + const auto celdeg = m_hho_di.cell_degree(); + const auto facdeg = m_hho_di.face_degree(); + + auto cb = make_scalar_monomial_basis(msh, cell, recdeg); + + const auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension); + const auto cbs = disk::scalar_basis_size(celdeg, Mesh::dimension); + const auto fbs = disk::scalar_basis_size(facdeg, Mesh::dimension - 1); + + const auto num_faces = howmany_faces(msh, cell); + + const matrix_type stiff = make_stiffness_matrix(msh, cell, cb); + matrix_type gr_lhs = matrix_type::Zero(rbs-1, rbs-1); + matrix_type gr_rhs = matrix_type::Zero(rbs-1, cbs + num_faces*fbs); + + gr_lhs = stiff.block(1, 1, rbs-1, rbs-1); + gr_rhs.block(0, 0, rbs-1, cbs) = stiff.block(1, 0, rbs-1, cbs); + + const auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + const auto fc = fcs[i]; + const auto n = normal(msh, cell, fc); + auto fb = make_scalar_monomial_basis(msh, fc, facdeg); + + auto qps_f = integrate(msh, fc, recdeg - 1 + std::max(facdeg,celdeg)); + for (auto& qp : qps_f) + { + vector_type c_phi_tmp = cb.eval_functions(qp.point()); + vector_type c_phi = c_phi_tmp.head(cbs); + Matrix c_dphi_tmp = cb.eval_gradients(qp.point()); + Matrix c_dphi = c_dphi_tmp.block(1, 0, rbs-1, DIM); + vector_type f_phi = fb.eval_functions(qp.point()); + gr_rhs.block(0, cbs+i*fbs, rbs-1, fbs) += qp.weight() * (c_dphi * n) * f_phi.transpose(); + gr_rhs.block(0, 0, rbs-1, cbs) -= qp.weight() * (c_dphi * n) * c_phi.transpose(); + } + } + + auto vec_cell_size = gr_lhs.cols(); + auto nrows = gr_rhs.cols()+vec_cell_size; + auto ncols = gr_rhs.cols()+vec_cell_size; + + // Shrinking data + matrix_type data_mixed = matrix_type::Zero(nrows,ncols); + data_mixed.block(0, 0, vec_cell_size, vec_cell_size) = gr_lhs; + data_mixed.block(0, vec_cell_size, vec_cell_size, ncols-vec_cell_size) = -gr_rhs; + data_mixed.block(vec_cell_size, 0, nrows-vec_cell_size, vec_cell_size) = gr_rhs.transpose(); + + matrix_type oper = gr_lhs.llt().solve(gr_rhs); + return std::make_pair(oper, data_mixed); + } + + Matrix + mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function rhs_fun, size_t di = 0) + { + const auto recdeg = m_hho_di.reconstruction_degree(); + const auto celdeg = m_hho_di.cell_degree(); + const auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension) - 1; + const auto cbs = disk::scalar_basis_size(celdeg, Mesh::dimension) + rbs; + auto cell_basis = make_scalar_monomial_basis(msh, cell, celdeg); + using T = typename Mesh::coordinate_type; + + Matrix ret_loc = Matrix::Zero(cell_basis.size()); + Matrix ret = Matrix::Zero(cbs); + + const auto qps = integrate(msh, cell, 2 * (celdeg + di)); + + for (auto& qp : qps) + { + const auto phi = cell_basis.eval_functions(qp.point()); + const auto qp_f = disk::priv::inner_product(qp.weight(), rhs_fun(qp.point())); + ret_loc += disk::priv::outer_product(phi, qp_f); + } + ret.block(rbs,0,cell_basis.size(),1) = ret_loc; + return ret; + } + + void set_hdg_stabilization(){ + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) + { + m_hho_stabilization_Q = false; + std::cout << "Proceeding with HDG stabilization cell degree is higher than face degree." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + }else{ + std::cout << "Proceeding with HHO stabilization cell and face degree are equal." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + } + } + void set_hho_stabilization(){ + m_hho_stabilization_Q = true; + } +}; + +#endif /* two_fields_assembler_hpp */ diff --git a/apps/wave_propagation/src/common/dirk_butcher_tableau.hpp b/apps/wave_propagation/src/common/dirk_butcher_tableau.hpp new file mode 100644 index 00000000..fae49b61 --- /dev/null +++ b/apps/wave_propagation/src/common/dirk_butcher_tableau.hpp @@ -0,0 +1,204 @@ +// +// dirk_butcher_tableau.hpp +// acoustics +// +// Created by Omar Durán on 4/21/20. +// + +#pragma once +#ifndef dirk_butcher_tableau_hpp +#define dirk_butcher_tableau_hpp + +#include + +class dirk_butcher_tableau +{ + public: + + static void dirk_tables(int s, Matrix &a, Matrix &b, Matrix &c){ + + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, 1); + c = Matrix::Zero(s, 1); + + switch (s) { // Implicit midpoint DIRK(1, 2) or SDIRK(1, 2) + case 1: + { + a(0,0) = 0.5; + b(0,0) = 1.0; + c(0,0) = 0.5; + } + break; + case 2: + { + // https://www.jstor.org/stable/pdf/43692558.pdf?refreqid=excelsior%3A6b91257ea1427dcb8b00a78353c96ef4 + // Construction Of High-order symplectic Runge-Kutta Methods + // SDIRK(2, 2) + a(0,0) = 0.25; + a(1,0) = 0.5; + a(1,1) = 0.25; + + b(0,0) = 0.5; + b(1,0) = 0.5; + + c(0,0) = 1.0/4.0; + c(1,0) = 3.0/4.0; + + } + break; + case 3: + { +// // DIRK(3, 4) + a(0,0) = 0.956262348020; + a(1,0) = -0.676995728936; + a(1,1) = 1.092920059741; + a(2,0) = 4.171447220367; + a(2,1) = -5.550750999686; + a(2,2) = 1.189651889660; + + b(0,0) = 0.228230955547; + b(1,0) = 0.706961029433; + b(2,0) = 0.064808015020; + + c(0,0) = 0.956262348020; + c(1,0) = 0.415924330804; + c(2,0) = -0.189651889660; + + } + break; + default: + { + std::cout << "Error:: Method not implemented." << std::endl; + } + break; + } + + } + + static void odirk_tables(int s, Matrix &a, Matrix &b, Matrix &c){ + + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, 1); + c = Matrix::Zero(s, 1); + + // Optimized diagonally implicit Runge-Kutta schemes for time-dependent wave propagation problems + switch (s) { + case 1: + { + a(0,0) = 0.5; + b(0,0) = 1.0; + c(0,0) = 0.5; + } + break; + case 2: + { + a(0,0) = 0.780078125000; + a(1,0) = -0.595072059507; + a(1,1) = 0.797536029754; + + b(0,0) = 0.515112081837; + b(1,0) = 0.484887918163; + + c(0,0) = 0.780078125; + c(1,0) = 0.202463970246; + + + + } + break; + case 3: + { + + a(0,0) = 0.956262348020; + a(1,0) = -0.676995728936; + a(1,1) = 1.092920059741; + a(2,0) = 4.171447220367; + a(2,1) = -5.550750999686; + a(2,2) = 1.189651889660; + + b(0,0) = 0.228230955547; + b(1,0) = 0.706961029433; + b(2,0) = 0.064808015020; + + c(0,0) = 0.956262348020; + c(1,0) = 0.415924330804; + c(2,0) = -0.189651889660; + + } + break; + default: + { + std::cout << "Error:: Method not implemented." << std::endl; + } + break; + } + + } + + static void sdirk_tables(int s, Matrix &a, Matrix &b, Matrix &c){ + + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, 1); + c = Matrix::Zero(s, 1); + + // A−stable SDIRK method + switch (s) { // Implicit midpoint (1, 2) + case 1: + { + a(0,0) = 0.5; + b(0,0) = 1.0; + c(0,0) = 0.5; + } + break; + case 2: + { + // The only 2-stages A-stable SDIRK scheme of order 3 has been given by Crouzeix + // Crouzeix/LDD-A2(2, 3) + double gamma = 1.0/std::sqrt(3.0); + a(0,0) = 0.5 + 0.5*gamma; + a(1,0) = -1.0*gamma; + a(1,1) = 0.5 + 0.5*gamma; + + b(0,0) = 0.5; + b(1,0) = 0.5; + + c(0,0) = 0.5 + 0.5*gamma; + c(1,0) = 0.5 - 0.5*gamma; + + } + break; + case 3: + { + + // Crouzeix & Raviart (3, 4) + double gamma = (1.0/std::sqrt(3.0))*std::cos(M_PI/18.0)+0.5; + double delta = 1.0/(6.0*(2.0*gamma-1.0)*(2.0*gamma-1.0)); + a(0,0) = gamma; + a(1,0) = (1.0/2.0)-gamma; + a(1,1) = gamma; + a(2,0) = 2.0*gamma; + a(2,1) = 1.0-4.0*gamma; + a(2,2) = gamma; + + b(0,0) = delta; + b(1,0) = 1.0-2.0*delta; + b(2,0) = delta; + + c(0,0) = gamma; + c(1,0) = 1.0/2.0; + c(2,0) = 1.0-gamma; + + } + break; + default: + { + std::cout << "Error:: Method not implemented." << std::endl; + } + break; + } + + } + +}; + +#endif /* dirk_butcher_tableau_hpp */ diff --git a/apps/wave_propagation/src/common/dirk_hho_scheme.hpp b/apps/wave_propagation/src/common/dirk_hho_scheme.hpp new file mode 100644 index 00000000..cceb8a16 --- /dev/null +++ b/apps/wave_propagation/src/common/dirk_hho_scheme.hpp @@ -0,0 +1,132 @@ +// +// dirk_hho_scheme.hpp +// acoustics +// +// Created by Omar Durán on 4/21/20. +// + +#ifndef dirk_hho_scheme_hpp +#define dirk_hho_scheme_hpp + +#include +#include +#include +#include "../common/linear_solver.hpp" + +template +class dirk_hho_scheme { + + private: + + T m_scale; + SparseMatrix m_Mg; + SparseMatrix m_Kg; + Matrix m_Fg; + linear_solver m_analysis; + std::vector> m_cell_basis_data; + size_t m_n_f_dof; + bool m_global_sc_Q; + bool m_iteraive_solver_Q; + + public: + + dirk_hho_scheme(SparseMatrix & Kg, Matrix & Fg, SparseMatrix & Mg){ + + m_Mg = Mg; + m_Kg = Kg; + m_Fg = Fg; + m_scale = 0.0; + m_global_sc_Q = false; + m_iteraive_solver_Q = false; + } + + dirk_hho_scheme(SparseMatrix & Kg, Matrix & Fg, SparseMatrix & Mg, T scale){ + m_Mg = Mg; + m_Kg = Kg; + m_Fg = Fg; + m_scale = scale; + m_global_sc_Q = false; + m_iteraive_solver_Q = false; + } + + void set_static_condensation_data(std::pair cell_basis_data, size_t n_f_dof){ + std::vector> vec_cell_basis_data(1); + vec_cell_basis_data[0] = cell_basis_data; + m_cell_basis_data = vec_cell_basis_data; + m_n_f_dof = n_f_dof; + m_global_sc_Q = true; + } + + void set_static_condensation_data(std::vector> cell_basis_data, size_t n_f_dof){ + m_cell_basis_data = cell_basis_data; + m_n_f_dof = n_f_dof; + m_global_sc_Q = true; + } + + void condense_equations() { + SparseMatrix K = m_Mg + m_scale * m_Kg; + m_analysis.set_Kg(K,m_n_f_dof); + m_analysis.condense_equations(m_cell_basis_data); + } + + void ComposeMatrix() { + if(m_global_sc_Q) + condense_equations(); + else{ + SparseMatrix K = m_Mg + m_scale * m_Kg; + m_analysis.set_Kg(K); + } + } + + void setIterativeSolver() { + m_iteraive_solver_Q = true; + m_analysis.set_iterative_solver(false, 1.0e-2); + } + + void DecomposeMatrix() { + m_analysis.factorize(); + } + + linear_solver & DirkAnalysis() { + return m_analysis; + } + + SparseMatrix & Mg(){ + return m_Mg; + } + + SparseMatrix & Kg(){ + return m_Kg; + } + + Matrix & Fg(){ + return m_Fg; + } + + void SetScale(T & scale){ + m_scale = scale; + } + + void SetFg(Matrix & Fg) { + m_Fg = Fg; + } + + void irk_weight(Matrix & y, Matrix & k, T dt, T a, bool is_sdirk_Q){ + + m_Fg -= Kg()*y; + if (is_sdirk_Q) + k = DirkAnalysis().solve(m_Fg); + else { + T scale = a * dt; + SetScale(scale); + ComposeMatrix(); + if (m_iteraive_solver_Q) + DirkAnalysis().set_iterative_solver(); + DecomposeMatrix(); + k = DirkAnalysis().solve(m_Fg); + } + } + +}; + +#endif /* dirk_hho_scheme_hpp */ diff --git a/apps/wave_propagation/src/common/display_settings.hpp b/apps/wave_propagation/src/common/display_settings.hpp new file mode 100644 index 00000000..b7098676 --- /dev/null +++ b/apps/wave_propagation/src/common/display_settings.hpp @@ -0,0 +1,28 @@ +// +// display_settings.cpp +// acoustics +// +// Created by Omar Durán on 4/8/20. +// + +#include + +std::ostream& bold(std::ostream& os) { os << "\x1b[1m"; return os; } +std::ostream& nobold(std::ostream& os) { os << "\x1b[21m"; return os; } + +std::ostream& underline(std::ostream& os) { os << "\x1b[4m"; return os; } +std::ostream& nounderline(std::ostream& os) { os << "\x1b[24m"; return os; } + +std::ostream& blink(std::ostream& os) { os << "\x1b[5m"; return os; } +std::ostream& noblink(std::ostream& os) { os << "\x1b[25m"; return os; } + +std::ostream& reset(std::ostream& os) { os << "\x1b[0m"; return os; } +std::ostream& erase_line(std::ostream& os) { os << "\x1b[0K"; return os; } + +std::ostream& red(std::ostream& os) { os << "\x1b[31m"; return os; } +std::ostream& green(std::ostream& os) { os << "\x1b[32m"; return os; } +std::ostream& yellow(std::ostream& os) { os << "\x1b[33m"; return os; } +std::ostream& blue(std::ostream& os) { os << "\x1b[34m"; return os; } +std::ostream& magenta(std::ostream& os) { os << "\x1b[35m"; return os; } +std::ostream& cyan(std::ostream& os) { os << "\x1b[36m"; return os; } +std::ostream& nocolor(std::ostream& os) { os << "\x1b[39m"; return os; } diff --git a/apps/wave_propagation/src/common/elastic_material_data.hpp b/apps/wave_propagation/src/common/elastic_material_data.hpp new file mode 100644 index 00000000..8d97a26b --- /dev/null +++ b/apps/wave_propagation/src/common/elastic_material_data.hpp @@ -0,0 +1,107 @@ +// +// elastic_material_data.hpp +// acoustics +// +// Created by Omar Durán on 4/14/20. +// + +#ifndef elastic_material_data_hpp +#define elastic_material_data_hpp + +#include + +template +class elastic_material_data { + + /// Fluid density + T m_rho; + + /// Compressional P-wave velocity + T m_vp; + + /// Shear S-wave velocity + T m_vs; + +public: + + /// Default constructor + elastic_material_data(T rho, T vp, T vs){ + m_rho = rho; + m_vp = vp; + m_vs = vs; + } + + /// Copy constructor + elastic_material_data(const elastic_material_data & other){ + m_rho = other.m_rho; + m_vp = other.m_vp; + m_vs = other.m_vs; + } + + /// Assignement constructor + const elastic_material_data & operator=(const elastic_material_data & other){ + + // check for self-assignment + if(&other == this){ + return *this; + } + + m_rho = other.m_rho; + m_vp = other.m_vp; + m_vs = other.m_vs; + return *this; + + } + + /// Desconstructor + virtual ~elastic_material_data(){ + + } + + /// Print class attributes + virtual void Print(std::ostream &out = std::cout) const{ + out << "\n density = " << m_rho; + out << "\n p-wave velocity = " << m_vp; + out << "\n s-wave velocity = " << m_vs; + } + + /// Print class attributes + friend std::ostream & operator<<( std::ostream& out, const elastic_material_data & material ){ + material.Print(out); + return out; + } + + void Set_rho(T rho) + { + m_rho = rho; + } + + T rho() + { + return m_rho; + } + + + void Set_vp(T vp) + { + m_vp = vp; + } + + T vp() + { + return m_vp; + } + + void Set_vs(T vs) + { + m_vs = vs; + } + + T vs() + { + return m_vs; + } + +}; + +#endif /* elastic_material_data_hpp */ diff --git a/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp b/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp new file mode 100644 index 00000000..5e69f8f1 --- /dev/null +++ b/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp @@ -0,0 +1,1751 @@ +// +// elastoacoustic_four_fields_assembler.hpp +// acoustics +// +// Created by Omar Durán on 9/7/20. +// + + +#pragma once +#ifndef elastoacoustic_four_fields_assembler_hpp +#define elastoacoustic_four_fields_assembler_hpp + +#include "diskpp/bases/bases.hpp" +#include "diskpp/methods/hho" +#include "../common/assembly_index.hpp" +#include "../common/acoustic_material_data.hpp" +#include "../common/elastic_material_data.hpp" +#include + +#ifdef HAVE_INTEL_TBB +#include +#endif + +template +class elastoacoustic_four_fields_assembler +{ + + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + using T = typename Mesh::coordinate_type; + + std::vector m_e_compress_indexes; + std::vector m_e_expand_indexes; + + std::vector m_a_compress_indexes; + std::vector m_a_expand_indexes; + + disk::hho_degree_info m_hho_di; + e_boundary_type m_e_bnd; + a_boundary_type m_a_bnd; + std::vector< Triplet > m_triplets; + std::vector< Triplet > m_triplets_stab; + std::vector< Triplet > m_c_triplets; + std::vector< Triplet > m_mass_triplets; + std::map> m_e_material; + std::map> m_a_material; + std::map m_e_cell_index; + std::map m_a_cell_index; + std::vector< size_t > m_e_elements_with_bc_eges; + std::vector< size_t > m_a_elements_with_bc_eges; + std::map> m_interface_cell_indexes; + + size_t m_n_elastic_cells; + size_t m_n_acoustic_cells; + + size_t n_e_edges; + size_t n_a_edges; + + size_t m_n_edges; + size_t m_n_essential_edges; + size_t m_n_elastic_cell_dof; + size_t m_n_acoustic_cell_dof; + size_t m_n_elastic_face_dof; + size_t m_n_acoustic_face_dof; + bool m_hho_stabilization_Q; + bool m_scaled_stabilization_Q; + +public: + + SparseMatrix LHS; + SparseMatrix LHS_STAB; + Matrix RHS; + SparseMatrix MASS; + SparseMatrix COUPLING; + + elastoacoustic_four_fields_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const e_boundary_type& e_bnd, const a_boundary_type& a_bnd, std::map> & e_material, std::map> & a_material) + : m_hho_di(hho_di), m_e_bnd(e_bnd), m_a_bnd(a_bnd), m_e_material(e_material), m_a_material(a_material), m_hho_stabilization_Q(true), m_scaled_stabilization_Q(false) + { + + auto storage = msh.backend_storage(); + auto is_e_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return e_bnd.is_dirichlet_face(fc_id); + }; + + auto is_a_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return a_bnd.is_dirichlet_face(fc_id); + }; + + size_t n_e_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_e_dirichlet); + size_t n_a_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_a_dirichlet); + + std::set e_egdes; + for (auto &chunk : m_e_material) { + size_t cell_i = chunk.first; + auto& cell = storage->surfaces[cell_i]; + auto cell_faces = faces(msh,cell); + for (auto &face : cell_faces) { + if (!is_e_dirichlet(face)) { + auto fc_id = msh.lookup(face); + e_egdes.insert(fc_id); + } + } + } + n_e_edges = e_egdes.size(); + std::set a_egdes; + for (auto &chunk : m_a_material) { + size_t cell_i = chunk.first; + auto& cell = storage->surfaces[cell_i]; + auto cell_faces = faces(msh,cell); + for (auto &face : cell_faces) { + if (!is_a_dirichlet(face)) { + auto fc_id = msh.lookup(face); + a_egdes.insert(fc_id); + } + } + } + n_a_edges = a_egdes.size(); + + m_n_edges = msh.faces_size(); + m_n_essential_edges = n_e_essential_edges + n_a_essential_edges; + + m_e_compress_indexes.resize( m_n_edges ); + m_e_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + m_a_compress_indexes.resize( m_n_edges ); + m_a_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + size_t e_compressed_offset = 0; + for (auto face_id : e_egdes) { + m_e_compress_indexes.at(face_id) = e_compressed_offset; + m_e_expand_indexes.at(e_compressed_offset) = face_id; + e_compressed_offset++; + } + size_t a_compressed_offset = 0; + for (auto face_id : a_egdes) { + m_a_compress_indexes.at(face_id) = a_compressed_offset; + m_a_expand_indexes.at(a_compressed_offset) = face_id; + a_compressed_offset++; + } + + size_t n_cbs = get_e_cell_basis_data(); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + size_t n_s_cbs = get_a_cell_basis_data(); + size_t n_s_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + m_n_elastic_cell_dof = (n_cbs * m_e_material.size()); + m_n_acoustic_cell_dof = (n_s_cbs * m_a_material.size()); + + m_n_elastic_face_dof = (n_fbs * n_e_edges); + m_n_acoustic_face_dof = (n_s_fbs * n_a_edges); + size_t system_size = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_n_acoustic_face_dof; + + LHS = SparseMatrix( system_size, system_size ); + LHS_STAB = SparseMatrix( system_size, system_size ); //OPTIONAL + RHS = Matrix::Zero( system_size ); + MASS = SparseMatrix( system_size, system_size ); + COUPLING = SparseMatrix( system_size, system_size ); + classify_cells(msh); + build_cells_maps(); + } + + void scatter_e_data_stab(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = get_e_cell_basis_data(); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_LHS_offset = e_cell_ind * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; + bool dirichlet = m_e_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets_stab.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + } + } + + } + + + void scatter_e_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = get_e_cell_basis_data(); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_LHS_offset = e_cell_ind * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; + bool dirichlet = m_e_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + } + } + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(asm_map[i].vidx()) += rhs(i); + } + + } + + void scatter_a_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = get_a_cell_basis_data(); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; + + bool dirichlet = m_a_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + } + } + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(asm_map[i].vidx()) += rhs(i); + } + + } + + void scatter_a_data_stab(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = get_a_cell_basis_data(); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; + + bool dirichlet = m_a_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets_stab.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + } + } + } + + void scatter_e_mass_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& mass_matrix) + { + + size_t n_cbs = get_e_cell_basis_data(); + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_LHS_offset = e_cell_ind * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == mass_matrix.rows() && asm_map.size() == mass_matrix.cols() ); + + for (size_t i = 0; i < mass_matrix.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < mass_matrix.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_mass_triplets.push_back( Triplet(asm_map[i], asm_map[j], mass_matrix(i,j)) ); + } + } + + } + + void scatter_a_mass_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& mass_matrix) + { + size_t n_cbs = get_a_cell_basis_data(); + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == mass_matrix.rows() && asm_map.size() == mass_matrix.cols() ); + + for (size_t i = 0; i < mass_matrix.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < mass_matrix.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_mass_triplets.push_back( Triplet(asm_map[i], asm_map[j], mass_matrix(i,j)) ); + } + } + + } + + void scatter_ea_interface_data(const Mesh& msh, const typename Mesh::face_type& face, const Matrix& interface_matrix) { + + auto vfbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + auto sfbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + std::vector asm_map_e, asm_map_a; + asm_map_e.reserve(vfbs); + asm_map_a.reserve(sfbs); + auto fc_id = msh.lookup(face); + + auto e_face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*vfbs; + bool e_dirichlet = m_e_bnd.is_dirichlet_face(fc_id); + for (size_t i = 0; i < vfbs; i++){ + asm_map_e.push_back( assembly_index(e_face_LHS_offset+i, !e_dirichlet) ); + } + + auto a_face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*sfbs; + bool a_dirichlet = m_a_bnd.is_dirichlet_face(fc_id); + for (size_t i = 0; i < sfbs; i++){ + asm_map_a.push_back( assembly_index(a_face_LHS_offset+i, !a_dirichlet) ); + } + + assert( asm_map_e.size() == interface_matrix.rows() && asm_map_a.size() == interface_matrix.cols() ); + + for (size_t i = 0; i < interface_matrix.rows(); i++) { + for (size_t j = 0; j < interface_matrix.cols(); j++) { + m_c_triplets.push_back( Triplet(asm_map_e[i].vidx(), asm_map_a[j].vidx(), interface_matrix(i,j)) ); + m_c_triplets.push_back( Triplet(asm_map_a[j].vidx(), asm_map_e[i].vidx(), - interface_matrix(i,j)) ); + } + } + + } + + void scatter_e_rhs_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& rhs) { + + size_t n_cbs = get_e_cell_basis_data(); + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_LHS_offset = e_cell_ind * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == rhs.rows() ); + + for (size_t i = 0; i < rhs.rows(); i++) { + if (!asm_map[i].assemble()) + continue; + RHS(asm_map[i].vidx()) += rhs(i); + } + + } + + void scatter_a_rhs_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& rhs) + { + size_t n_cbs = get_a_cell_basis_data(); + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == rhs.rows()); + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(asm_map[i].vidx()) += rhs(i); + } + + } + + void scatter_e_bc_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs) + { + + auto fcs = faces(msh, cl); + size_t n_cbs = get_e_cell_basis_data(); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_LHS_offset = e_cell_ind * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; + + bool dirichlet = m_e_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_e_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( !asm_map[j].assemble() ) + RHS(asm_map[i].vidx()) -= lhs(i,j) * dirichlet_data(j); + } + } + + } + + void scatter_a_bc_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = get_a_cell_basis_data(); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; + + bool dirichlet = m_a_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_a_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( !asm_map[j].assemble() ) + RHS(asm_map[i].vidx()) -= lhs(i,j) * dirichlet_data(j); + + } + } + + } + + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun, bool explicit_scheme){ + + auto storage = msh.backend_storage(); + LHS.setZero(); + RHS.setZero(); + + // elastic block + for (auto e_chunk : m_e_material) { + size_t e_cell_ind = m_e_cell_index[e_chunk.first]; + auto& cell = storage->surfaces[e_chunk.first]; + Matrix mixed_operator_loc = e_mixed_operator(e_chunk.second,msh,cell,explicit_scheme); + Matrix f_loc = e_mixed_rhs(msh, cell, e_rhs_fun); + scatter_e_data(e_cell_ind, msh, cell, mixed_operator_loc, f_loc); + } + + // acoustic block + for (auto a_chunk : m_a_material) { + size_t a_cell_ind = m_a_cell_index[a_chunk.first]; + auto& cell = storage->surfaces[a_chunk.first]; + Matrix mixed_operator_loc = a_mixed_operator(a_chunk.second, msh, cell,explicit_scheme); + Matrix f_loc = a_mixed_rhs(msh, cell, a_rhs_fun); + scatter_a_data(a_cell_ind, msh, cell, mixed_operator_loc, f_loc); + } + finalize(); + } + + + void assemble_coupling_terms(const Mesh& msh){ + + auto storage = msh.backend_storage(); + COUPLING.setZero(); + // coupling blocks + for (auto chunk : m_interface_cell_indexes) { + auto& face = storage->edges[chunk.first]; + auto& e_cell = storage->surfaces[chunk.second.first]; + auto& a_cell = storage->surfaces[chunk.second.second]; + Matrix interface_operator_loc = e_interface_operator(msh, face, e_cell, a_cell); + scatter_ea_interface_data(msh, face, interface_operator_loc); + } + finalize_coupling(); + } + + void assemble_mass(const Mesh& msh, bool add_vector_mass_Q = true){ + + auto storage = msh.backend_storage(); + MASS.setZero(); + + // elastic block + for (auto e_chunk : m_e_material) { + size_t e_cell_ind = m_e_cell_index[e_chunk.first]; + auto& cell = storage->surfaces[e_chunk.first]; + elastic_material_data material = e_chunk.second; + Matrix mass_matrix = e_mass_operator(material, msh, cell, add_vector_mass_Q); + scatter_e_mass_data(e_cell_ind,msh, cell, mass_matrix); + } + + // acoustic block + for (auto a_chunk : m_a_material) { + size_t a_cell_ind = m_a_cell_index[a_chunk.first]; + auto& cell = storage->surfaces[a_chunk.first]; + acoustic_material_data material = a_chunk.second; + Matrix mass_matrix = a_mass_operator(material, msh, cell); + scatter_a_mass_data(a_cell_ind, msh, cell, mass_matrix); + } + + finalize_mass(); + } + + void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun, bool explicit_scheme){ + + RHS.setZero(); + #ifdef HAVE_INTEL_TBB2 + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh,&rhs_fun] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, rhs_fun); + this->scatter_rhs_data(msh, cell, f_loc); + } + ); + #else + auto storage = msh.backend_storage(); + for (auto e_chunk : m_e_material) { + size_t e_cell_ind = m_e_cell_index[e_chunk.first]; + auto& cell = storage->surfaces[e_chunk.first]; + Matrix f_loc = e_mixed_rhs(msh, cell, e_rhs_fun); + scatter_e_rhs_data(e_cell_ind, msh, cell, f_loc); + } + + for (auto a_chunk : m_a_material) { + size_t a_cell_ind = m_a_cell_index[a_chunk.first]; + auto& cell = storage->surfaces[a_chunk.first]; + Matrix f_loc = a_mixed_rhs(msh, cell, a_rhs_fun); + scatter_a_rhs_data(a_cell_ind, msh, cell, f_loc); + } + + #endif + apply_bc(msh, explicit_scheme); + } + + void apply_bc(const Mesh& msh, bool explicit_scheme){ + + #ifdef HAVE_INTEL_TBB2 + size_t n_cells = m_elements_with_bc_eges.size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh] (size_t & i){ + size_t cell_ind = m_elements_with_bc_eges[i]; + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix laplacian_operator_loc = laplacian_operator(cell_ind, msh, cell); + scatter_bc_data(msh, cell, laplacian_operator_loc); + } + ); + #else + auto storage = msh.backend_storage(); + for (auto& cell_ind : m_e_elements_with_bc_eges) + { + auto& cell = storage->surfaces[cell_ind]; + size_t e_cell_ind = m_e_cell_index[cell_ind]; + elastic_material_data e_mat = m_e_material.find(cell_ind)->second; + Matrix mixed_operator_loc = e_mixed_operator(e_mat,msh,cell,explicit_scheme); + scatter_e_bc_data(e_cell_ind, msh, cell, mixed_operator_loc); + } + + for (auto& cell_ind : m_a_elements_with_bc_eges) + { + auto& cell = storage->surfaces[cell_ind]; + size_t a_cell_ind = m_a_cell_index[cell_ind]; + acoustic_material_data a_mat = m_a_material.find(cell_ind)->second; + Matrix mixed_operator_loc = a_mixed_operator(a_mat, msh, cell, explicit_scheme); + scatter_a_bc_data(a_cell_ind, msh, cell, mixed_operator_loc); + } + + #endif + + } + + Matrix e_mixed_operator(elastic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell, bool explicit_scheme){ + + T rho = material.rho(); + T vp = material.vp(); + T vs = material.vs(); + T mu = rho * vs * vs; + T lambda = rho * vp * vp - 2*mu; + + auto reconstruction_operator = strain_tensor_reconstruction(msh, cell); + Matrix R_operator = reconstruction_operator.second; + auto n_rows = R_operator.rows(); + auto n_cols = R_operator.cols(); + Matrix S_operator = Matrix::Zero(n_rows, n_cols); + + if(explicit_scheme) { + auto stabilization_operator = make_vector_hdg_stabilization(msh, cell, m_hho_di, m_scaled_stabilization_Q); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + } + else { + if(m_hho_stabilization_Q) { + auto rec_for_stab = make_vector_hho_symmetric_laplacian(msh, cell, m_hho_di); + auto stabilization_operator = make_vector_hho_stabilization(msh, cell, rec_for_stab.first, m_hho_di, m_scaled_stabilization_Q); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + } + else { + auto stabilization_operator = make_vector_hdg_stabilization(msh, cell, m_hho_di, m_scaled_stabilization_Q); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + } + } + + // // COEF SPECTRAL RADIUS + T equal_order_eta = 1.50; + T mixed_order_eta = 0.95; + + T coef = 1.0; + T eta = coef * equal_order_eta; + + return R_operator + eta*(rho*vs)*S_operator; + } + + Matrix + symmetric_tensor_mass_matrix(const Mesh& msh, const typename Mesh::cell_type& cell) { + + size_t dim = Mesh::dimension; + auto gradeg = m_hho_di.grad_degree(); + auto ten_b = make_sym_matrix_monomial_basis(msh, cell, gradeg); + auto ten_bs = disk::sym_matrix_basis_size(gradeg, dim, dim); + Matrix mass_matrix = Matrix::Zero(ten_bs, ten_bs); + + auto qps = integrate(msh, cell, 2 * gradeg); + + // number of tensor components + size_t dec = 0; + if (dim == 3) + dec = 6; + else if (dim == 2) + dec = 3; + else + std::logic_error("Expected 3 >= dim > 1"); + + for (auto& qp : qps) + { + auto phi = ten_b.eval_functions(qp.point()); + + for (size_t j = 0; j < ten_bs; j++) + { + + auto qp_phi_j = disk::priv::inner_product(qp.weight(), phi[j]); + for (size_t i = j; i < ten_bs; i += dec){ + mass_matrix(i, j) += disk::priv::inner_product(phi[i], qp_phi_j); + } + } + } + + for (size_t j = 0; j < ten_bs; j++){ + for (size_t i = 0; i < j; i++){ + mass_matrix(i, j) = mass_matrix(j, i); + } + } + + return mass_matrix; + } + + Matrix + symmetric_tensor_trace_mass_matrix(const Mesh& msh, const typename Mesh::cell_type& cell) { + + size_t dim = Mesh::dimension; + auto gradeg = m_hho_di.grad_degree(); + auto ten_b = make_sym_matrix_monomial_basis(msh, cell, gradeg); + auto ten_bs = disk::sym_matrix_basis_size(gradeg, dim, dim); + Matrix mass_matrix = Matrix::Zero(ten_bs, ten_bs); + + auto qps = integrate(msh, cell, 2 * gradeg); + + // number of tensor components + size_t dec = 0; + if (dim == 3) + dec = 6; + else if (dim == 2) + dec = 3; + else + std::logic_error("Expected 3 >= dim > 1"); + + for (auto& qp : qps) { + + auto phi = ten_b.eval_functions(qp.point()); + + for (size_t j = 0; j < ten_bs; j++) { + auto identity = phi[j]; + identity.setZero(); + for(size_t d = 0; d < dim; d++) + identity(d,d) = 1.0; + + auto trace = phi[j].trace(); + auto trace_phi_j = disk::priv::inner_product(phi[j].trace(), identity); + auto qp_phi_j = disk::priv::inner_product(qp.weight(), trace_phi_j); + for (size_t i = 0; i < ten_bs; i ++) + mass_matrix(i, j) += disk::priv::inner_product(phi[i], qp_phi_j); + + } + } + + return mass_matrix; + } + + Matrix + e_mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> & rhs_fun, size_t di = 0) + { + auto recdeg = m_hho_di.grad_degree(); + auto celdeg = m_hho_di.cell_degree(); + auto facdeg = m_hho_di.face_degree(); + + auto ten_bs = disk::sym_matrix_basis_size(recdeg, Mesh::dimension, Mesh::dimension); + auto vec_bs = disk::vector_basis_size(celdeg, Mesh::dimension, Mesh::dimension); + size_t n_cbs = ten_bs + vec_bs; + auto cell_basis = make_vector_monomial_basis(msh, cell, celdeg); + using T = typename Mesh::coordinate_type; + + Matrix ret_loc = Matrix::Zero(cell_basis.size()); + Matrix ret = Matrix::Zero(n_cbs); + + const auto qps = integrate(msh, cell, 2 * (celdeg + di)); + + for (auto& qp : qps) + { + const auto phi = cell_basis.eval_functions(qp.point()); + const auto qp_f = disk::priv::inner_product(qp.weight(), rhs_fun(qp.point())); + ret_loc += disk::priv::outer_product(phi, qp_f); + } + ret.block(ten_bs,0,vec_bs,1) = ret_loc; + return ret; + } + + Matrix e_mass_operator(elastic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell, bool add_vector_mass_Q = true){ + + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + + T rho = material.rho(); + T vp = material.vp(); + T vs = material.vs(); + T mu = rho * vs * vs; + T lambda = rho * vp * vp - 2*mu; + + Matrix mass_matrix = Matrix::Zero(n_cbs, n_cbs); + + // Symmetric stress tensor mass block + + // Stress tensor + Matrix mass_matrix_sigma = symmetric_tensor_mass_matrix(msh, cell); + + // Tensor trace + Matrix mass_matrix_trace_sigma = symmetric_tensor_trace_mass_matrix(msh, cell); + + // Constitutive relationship inverse + mass_matrix_trace_sigma *= (lambda/(2.0*mu+2.0*lambda)); + mass_matrix_sigma -= mass_matrix_trace_sigma; + mass_matrix_sigma *= (1.0/(2.0*mu)); + mass_matrix.block(0, 0, n_ten_cbs, n_ten_cbs) = mass_matrix_sigma; + + if (add_vector_mass_Q) { + // vector velocity mass mass block + auto vec_basis = disk::make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix mass_matrix_v = disk::make_mass_matrix(msh, cell, vec_basis); + mass_matrix_v *= rho; + mass_matrix.block(n_ten_cbs, n_ten_cbs, n_vec_cbs, n_vec_cbs) = mass_matrix_v; + } + + return mass_matrix; + } + + Matrix a_mass_operator(acoustic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell, bool add_scalar_mass_Q = true){ + + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + + Matrix mass_matrix = Matrix::Zero(n_cbs, n_cbs); + + auto recdeg = m_hho_di.reconstruction_degree(); + auto rec_basis = make_scalar_monomial_basis(msh, cell, recdeg); + auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension); + + Matrix mass_matrix_q_full = make_stiffness_matrix(msh, cell, rec_basis); + Matrix mass_matrix_q = Matrix::Zero(rbs-1, rbs-1); + mass_matrix_q = mass_matrix_q_full.block(1, 1, rbs-1, rbs-1); + mass_matrix_q *= material.rho(); + mass_matrix.block(0, 0, n_vec_cbs, n_vec_cbs) = mass_matrix_q; + + if (add_scalar_mass_Q) { + auto scal_basis = disk::make_scalar_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix mass_matrix_v = disk::make_mass_matrix(msh, cell, scal_basis); + mass_matrix_v *= (1.0/(material.rho()*material.vp()*material.vp())); + mass_matrix.block(n_vec_cbs, n_vec_cbs, n_scal_cbs, n_scal_cbs) = mass_matrix_v; + } + + return mass_matrix; + } + + std::pair< Matrix, + Matrix > + strain_tensor_reconstruction(const Mesh& msh, const typename Mesh::cell_type& cell) { + + using T = typename Mesh::coordinate_type; + typedef Matrix matrix_type; + + const size_t N = Mesh::dimension; + + auto graddeg = m_hho_di.grad_degree(); + auto celdeg = m_hho_di.cell_degree(); + auto facdeg = m_hho_di.face_degree(); + + auto ten_b = make_sym_matrix_monomial_basis(msh, cell, graddeg); + auto vec_b = make_vector_monomial_basis(msh, cell, celdeg); + + auto ten_bs = disk::sym_matrix_basis_size(graddeg, Mesh::dimension, Mesh::dimension); + auto vec_bs = disk::vector_basis_size(celdeg, Mesh::dimension, Mesh::dimension); + auto fbs = disk::vector_basis_size(facdeg, Mesh::dimension - 1, Mesh::dimension); + + auto num_faces = howmany_faces(msh, cell); + + matrix_type gr_lhs = matrix_type::Zero(ten_bs, ten_bs); + matrix_type gr_rhs = matrix_type::Zero(ten_bs, vec_bs + num_faces * fbs); + + const auto qps = integrate(msh, cell, 2 * graddeg); + + size_t dec = 0; + if (N == 3) + dec = 6; + else if (N == 2) + dec = 3; + else + std::logic_error("Expected 3 >= dim > 1"); + + for (auto& qp : qps) { + const auto gphi = ten_b.eval_functions(qp.point()); + for (size_t j = 0; j < ten_bs; j++) { + auto qp_gphi_j = disk::priv::inner_product(qp.weight(), gphi[j]); + for (size_t i = j; i < ten_bs; i += dec) { + gr_lhs(i, j) += disk::priv::inner_product(gphi[i], qp_gphi_j); + } + } + } + + for (size_t j = 0; j < ten_bs; j++) + for (size_t i = 0; i < j; i++) + gr_lhs(i, j) = gr_lhs(j, i); + + if (celdeg > 0) { + const auto qpc = integrate(msh, cell, graddeg + celdeg - 1); + for (auto& qp : qpc) { + const auto gphi = ten_b.eval_functions(qp.point()); + const auto dphi = vec_b.eval_sgradients(qp.point()); + const auto qp_dphi = disk::priv::inner_product(qp.weight(), dphi); + gr_rhs.block(0, 0, ten_bs, vec_bs) += disk::priv::outer_product(gphi, qp_dphi); + } + } + + const auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) { + const auto fc = fcs[i]; + const auto n = normal(msh, cell, fc); + const auto fb = make_vector_monomial_basis(msh, fc, facdeg); + const auto qps_f = integrate(msh, fc, graddeg + std::max(celdeg, facdeg)); + for (auto& qp : qps_f) { + const auto gphi = ten_b.eval_functions(qp.point()); + const auto cphi = vec_b.eval_functions(qp.point()); + const auto fphi = fb.eval_functions(qp.point()); + const auto qp_gphi_n = disk::priv::inner_product(gphi, disk::priv::inner_product(qp.weight(), n)); + gr_rhs.block(0, vec_bs + i * fbs, ten_bs, fbs) += disk::priv::outer_product(qp_gphi_n, fphi); + gr_rhs.block(0, 0, ten_bs, vec_bs) -= disk::priv::outer_product(qp_gphi_n, cphi); + } + } + + auto n_rows = gr_rhs.cols() + ten_bs; + auto n_cols = gr_rhs.cols() + ten_bs; + + // Shrinking data + matrix_type data_mixed = matrix_type::Zero(n_rows,n_cols); + data_mixed.block(0, (ten_bs), ten_bs, n_cols-(ten_bs)) = -gr_rhs; + data_mixed.block((ten_bs), 0, n_rows-(ten_bs), ten_bs) = gr_rhs.transpose(); + + matrix_type oper = gr_lhs.llt().solve(gr_rhs); + return std::make_pair(oper, data_mixed); + } + + Matrix a_mixed_operator(acoustic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell, bool explicit_scheme){ + + auto reconstruction_operator = mixed_scalar_reconstruction(msh, cell); + Matrix R_operator = reconstruction_operator.second; + auto n_rows = R_operator.rows(); + auto n_cols = R_operator.cols(); + + Matrix S_operator = Matrix::Zero(n_rows, n_cols); + if(explicit_scheme) { + auto stabilization_operator = make_scalar_hdg_stabilization(msh, cell, m_hho_di, m_scaled_stabilization_Q); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + } + else { + if (m_hho_stabilization_Q) { + auto stabilization_operator = make_scalar_hho_stabilization(msh, cell, reconstruction_operator.first, m_hho_di, m_scaled_stabilization_Q); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + } + else { + auto stabilization_operator = make_scalar_hdg_stabilization(msh, cell, m_hho_di, m_scaled_stabilization_Q); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + } + } + + // COEF SPECTRAL RADIUS + T equal_order_eta = 0.8; + T mixed_order_eta = 0.4; + + + T coef = 1.0; + T eta = coef * equal_order_eta; + + T rho = material.rho(); + T vp = material.vp(); + + return R_operator + (eta/(vp*rho))*S_operator; + } + + std::pair< Matrix, + Matrix > + mixed_scalar_reconstruction(const Mesh& msh, const typename Mesh::cell_type& cell) + { + using T = typename Mesh::coordinate_type; + typedef Matrix matrix_type; + typedef Matrix vector_type; + + const size_t DIM = Mesh::dimension; + + const auto recdeg = m_hho_di.reconstruction_degree(); + const auto celdeg = m_hho_di.cell_degree(); + const auto facdeg = m_hho_di.face_degree(); + + auto cb = make_scalar_monomial_basis(msh, cell, recdeg); + + const auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension); + const auto cbs = disk::scalar_basis_size(celdeg, Mesh::dimension); + const auto fbs = disk::scalar_basis_size(facdeg, Mesh::dimension - 1); + + const auto num_faces = howmany_faces(msh, cell); + + const matrix_type stiff = make_stiffness_matrix(msh, cell, cb); + matrix_type gr_lhs = matrix_type::Zero(rbs-1, rbs-1); + matrix_type gr_rhs = matrix_type::Zero(rbs-1, cbs + num_faces*fbs); + + gr_lhs = stiff.block(1, 1, rbs-1, rbs-1); + gr_rhs.block(0, 0, rbs-1, cbs) = stiff.block(1, 0, rbs-1, cbs); + + const auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + const auto fc = fcs[i]; + const auto n = normal(msh, cell, fc); + auto fb = make_scalar_monomial_basis(msh, fc, facdeg); + + auto qps_f = integrate(msh, fc, recdeg - 1 + std::max(facdeg,celdeg)); + for (auto& qp : qps_f) + { + vector_type c_phi_tmp = cb.eval_functions(qp.point()); + vector_type c_phi = c_phi_tmp.head(cbs); + Matrix c_dphi_tmp = cb.eval_gradients(qp.point()); + Matrix c_dphi = c_dphi_tmp.block(1, 0, rbs-1, DIM); + vector_type f_phi = fb.eval_functions(qp.point()); + gr_rhs.block(0, cbs+i*fbs, rbs-1, fbs) += qp.weight() * (c_dphi * n) * f_phi.transpose(); + gr_rhs.block(0, 0, rbs-1, cbs) -= qp.weight() * (c_dphi * n) * c_phi.transpose(); + } + } + + auto vec_cell_size = gr_lhs.cols(); + auto nrows = gr_rhs.cols()+vec_cell_size; + auto ncols = gr_rhs.cols()+vec_cell_size; + + // Shrinking data + matrix_type data_mixed = matrix_type::Zero(nrows,ncols); + data_mixed.block(0, vec_cell_size, vec_cell_size, ncols-vec_cell_size) = -gr_rhs; + data_mixed.block(vec_cell_size, 0, nrows-vec_cell_size, vec_cell_size) = gr_rhs.transpose(); + + matrix_type oper = gr_lhs.llt().solve(gr_rhs); + return std::make_pair(oper, data_mixed); + } + + Matrix + a_mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function & rhs_fun, size_t di = 0) + { + const auto recdeg = m_hho_di.reconstruction_degree(); + const auto celdeg = m_hho_di.cell_degree(); + const auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension) - 1; + const auto cbs = disk::scalar_basis_size(celdeg, Mesh::dimension) + rbs; + auto cell_basis = make_scalar_monomial_basis(msh, cell, celdeg); + using T = typename Mesh::coordinate_type; + + Matrix ret_loc = Matrix::Zero(cell_basis.size()); + Matrix ret = Matrix::Zero(cbs); + + const auto qps = integrate(msh, cell, 2 * (celdeg + di)); + + for (auto& qp : qps) + { + const auto phi = cell_basis.eval_functions(qp.point()); + const auto qp_f = disk::priv::inner_product(qp.weight(), rhs_fun(qp.point())); + ret_loc += disk::priv::outer_product(phi, qp_f); + } + ret.block(rbs,0,cell_basis.size(),1) = ret_loc; + return ret; + } + + Matrix e_interface_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell){ + + Matrix interface_operator; + auto facdeg = m_hho_di.face_degree(); + auto vfbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + auto sfbs = disk::scalar_basis_size(facdeg, Mesh::dimension - 1); + + interface_operator = Matrix::Zero(vfbs, sfbs); + + auto vfb = make_vector_monomial_basis(msh, face, facdeg); + auto sfb = make_scalar_monomial_basis(msh, face, facdeg); + const auto qps = integrate(msh, face, facdeg); + const auto n = disk::normal(msh, e_cell, face); + for (auto& qp : qps) { + const auto v_f_phi = vfb.eval_functions(qp.point()); + const auto s_f_phi = sfb.eval_functions(qp.point()); + assert(v_f_phi.rows() == vfbs); + assert(s_f_phi.rows() == sfbs); + const auto n_dot_v_f_phi = disk::priv::inner_product(v_f_phi,disk::priv::inner_product(qp.weight(), n)); + const auto result = -1.0*disk::priv::outer_product(n_dot_v_f_phi, s_f_phi); + interface_operator += result; + } + return interface_operator; + } + + Matrix e_neumman_bc_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell, std::function a_vel_fun){ + + Matrix neumann_operator; + auto facdeg = m_hho_di.face_degree(); + auto vfbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + neumann_operator = Matrix::Zero(vfbs, 1); + + auto vfb = make_vector_monomial_basis(msh, face, facdeg); + auto sfb = make_scalar_monomial_basis(msh, face, facdeg); + const auto qps = integrate(msh, face, facdeg); + const auto n = disk::normal(msh, e_cell, face); + for (auto& qp : qps) + { + const auto v_f_phi = vfb.eval_functions(qp.point()); + const auto s_f_phi = sfb.eval_functions(qp.point()); + + assert(v_f_phi.rows() == vfbs); + const auto n_dot_v_f_phi = disk::priv::inner_product(v_f_phi,disk::priv::inner_product(qp.weight(), n)); + const auto result = disk::priv::outer_product(n_dot_v_f_phi, a_vel_fun(qp.point())); + neumann_operator += result; + + } + return neumann_operator; + } + + Matrix a_neumman_bc_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell, std::function(const typename Mesh::point_type& )> e_vel_fun){ + + Matrix neumann_operator; + auto facdeg = m_hho_di.face_degree(); + auto sfbs = disk::scalar_basis_size(facdeg, Mesh::dimension - 1); + + neumann_operator = Matrix::Zero(sfbs, 1); + + auto vfb = make_vector_monomial_basis(msh, face, facdeg); + auto sfb = make_scalar_monomial_basis(msh, face, facdeg); + const auto qps = integrate(msh, face, facdeg); + const auto n = disk::normal(msh, a_cell, face); + for (auto& qp : qps) + { + const auto v_f_phi = vfb.eval_functions(qp.point()); + const auto s_f_phi = sfb.eval_functions(qp.point()); + + assert(s_f_phi.rows() == sfbs); + const auto n_dot_v_f = disk::priv::inner_product(e_vel_fun(qp.point()),disk::priv::inner_product(qp.weight(), n)); + const auto result = disk::priv::inner_product(n_dot_v_f, s_f_phi); + neumann_operator += result; + } + return neumann_operator; + } + + void classify_cells(const Mesh& msh){ + + m_e_elements_with_bc_eges.clear(); + for (auto& cell : msh) + { + auto cell_ind = msh.lookup(cell); + auto face_list = faces(msh, cell); + for (size_t face_i = 0; face_i < face_list.size(); face_i++) + { + auto fc = face_list[face_i]; + auto fc_id = msh.lookup(fc); + bool is_dirichlet_Q = m_e_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + m_e_elements_with_bc_eges.push_back(cell_ind); + break; + } + } + } + + m_a_elements_with_bc_eges.clear(); + for (auto& cell : msh) + { + typename Mesh::point_type bar = barycenter(msh, cell); + if (bar.x() < 0) { + continue; + } + + auto cell_ind = msh.lookup(cell); + auto face_list = faces(msh, cell); + for (size_t face_i = 0; face_i < face_list.size(); face_i++) + { + auto fc = face_list[face_i]; + auto fc_id = msh.lookup(fc); + bool is_dirichlet_Q = m_a_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + m_a_elements_with_bc_eges.push_back(cell_ind); + break; + } + } + } + } + + void build_cells_maps(){ + + // elastic data + size_t e_cell_ind = 0; + for (auto chunk : m_e_material) { + m_e_cell_index.insert(std::make_pair(chunk.first,e_cell_ind)); + e_cell_ind++; + } + m_n_elastic_cells = e_cell_ind; + + // acoustic data + size_t a_cell_ind = 0; + for (auto chunk : m_a_material) { + m_a_cell_index.insert(std::make_pair(chunk.first,a_cell_ind)); + a_cell_ind++; + } + m_n_acoustic_cells = a_cell_ind; + + } + + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> v_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::function v_s_fun, std::function(const typename Mesh::point_type& )> flux_s_fun){ + + auto storage = msh.backend_storage(); + size_t n_dof = MASS.rows(); + x_glob = Matrix::Zero(n_dof); + + // elastic block + + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_e_cbs = n_ten_cbs + n_vec_cbs; + + for (auto e_chunk : m_e_material) { + size_t e_cell_ind = m_e_cell_index[e_chunk.first]; + auto& cell = storage->surfaces[e_chunk.first]; + + Matrix x_proj_ten_dof = project_ten_function(msh, cell, flux_fun); + Matrix x_proj_vec_dof = project_function(msh, cell, m_hho_di.cell_degree(), v_fun); + + Matrix x_proj_dof = Matrix::Zero(n_e_cbs); + x_proj_dof.block(0, 0, n_ten_cbs, 1) = x_proj_ten_dof; + x_proj_dof.block(n_ten_cbs, 0, n_vec_cbs, 1) = x_proj_vec_dof; + scatter_e_cell_dof_data(e_cell_ind, msh, cell, x_glob, x_proj_dof); + } + + // acoustic block + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_v_s_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_a_cbs = n_v_s_cbs + n_scal_cbs; + for (auto a_chunk : m_a_material) { + size_t a_cell_ind = m_a_cell_index[a_chunk.first]; + auto& cell = storage->surfaces[a_chunk.first]; + + Matrix x_proj_vec_dof = project_vec_function(msh, cell, flux_s_fun); + Matrix x_proj_sca_dof = project_function(msh, cell, m_hho_di.cell_degree(), v_s_fun); + + Matrix x_proj_dof = Matrix::Zero(n_a_cbs); + x_proj_dof.block(0, 0, n_v_s_cbs, 1) = x_proj_vec_dof; + x_proj_dof.block(n_v_s_cbs, 0, n_scal_cbs, 1) = x_proj_sca_dof; + + scatter_a_cell_dof_data(a_cell_ind, msh, cell, x_glob, x_proj_dof); + } + + } + + Matrix project_vec_function(const Mesh& msh, const typename Mesh::cell_type& cell, + std::function(const typename Mesh::point_type& )> vec_fun){ + + auto recdeg = m_hho_di.reconstruction_degree(); + auto rec_basis = make_scalar_monomial_basis(msh, cell, recdeg); + auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension); + Matrix mass_matrix_q_full = make_stiffness_matrix(msh, cell, rec_basis); + Matrix mass_matrix_q = Matrix::Zero(rbs-1, rbs-1); + mass_matrix_q = mass_matrix_q_full.block(1, 1, rbs-1, rbs-1); + + Matrix rhs = Matrix::Zero(rbs-1); + Matrix f_vec = Matrix::Zero(1, 2); + const auto qps = integrate(msh, cell, 2*recdeg); + for (auto& qp : qps) { + auto dphi = rec_basis.eval_gradients(qp.point()); + f_vec(0,0) = vec_fun(qp.point())[0]; + f_vec(0,1) = vec_fun(qp.point())[1]; + for (size_t i = 0; i < rbs-1; i++){ + Matrix phi_i = dphi.block(i+1, 0, 1, 2).transpose(); + rhs(i,0) = rhs(i,0) + (qp.weight() * f_vec*phi_i)(0,0); + } + } + Matrix x_dof = mass_matrix_q.llt().solve(rhs); + return x_dof; + } + + Matrix project_ten_function(const Mesh& msh, const typename Mesh::cell_type& cell, + std::function(const typename Mesh::point_type& )> ten_fun){ + + Matrix mass_matrix = symmetric_tensor_mass_matrix(msh, cell); + size_t dim = Mesh::dimension; + auto gradeg = m_hho_di.grad_degree(); + auto ten_bs = disk::sym_matrix_basis_size(gradeg, dim, dim); + auto ten_b = make_sym_matrix_monomial_basis(msh, cell, gradeg); + Matrix rhs = Matrix::Zero(ten_bs); + + const auto qps = integrate(msh, cell, 2 * gradeg); + for (auto& qp : qps) + { + auto phi = ten_b.eval_functions(qp.point()); + static_matrix sigma = ten_fun(qp.point()); + for (size_t i = 0; i < ten_bs; i++){ + auto qp_phi_i = disk::priv::inner_product(qp.weight(), phi[i]); + rhs(i,0) += disk::priv::inner_product(qp_phi_i,sigma); + } + } + Matrix x_dof = mass_matrix.llt().solve(rhs); + return x_dof; + } + + void + scatter_e_cell_dof_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell, + Matrix& x_glob, Matrix x_proj_dof) const + { + size_t n_cbs = get_e_cell_basis_data(); + auto cell_ofs = e_cell_ind * n_cbs; + x_glob.block(cell_ofs, 0, n_cbs, 1) = x_proj_dof; + } + + void + scatter_a_cell_dof_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell, + Matrix& x_glob, Matrix x_proj_dof) const + { + size_t n_cbs = get_a_cell_basis_data(); + auto cell_ofs = a_cell_ind * n_cbs + m_n_elastic_cell_dof; + x_glob.block(cell_ofs, 0, n_cbs, 1) = x_proj_dof; + } + + + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function scal_fun){ + + auto storage = msh.backend_storage(); + + // elastic block + for (auto e_chunk : m_e_material) { + auto& cell = storage->surfaces[e_chunk.first]; + auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + auto face = fcs[i]; + auto fc_id = msh.lookup(face); + bool is_dirichlet_Q = m_e_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + continue; + } + Matrix x_proj_dof = project_function(msh, face, m_hho_di.face_degree(), vec_fun); + scatter_e_face_dof_data(msh, face, x_glob, x_proj_dof); + } + } + + // acoustic block + for (auto a_chunk : m_a_material) { + auto& cell = storage->surfaces[a_chunk.first]; + auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + auto face = fcs[i]; + auto fc_id = msh.lookup(face); + bool is_dirichlet_Q = m_a_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + continue; + } + Matrix x_proj_dof = project_function(msh, face, m_hho_di.face_degree(), scal_fun); + scatter_a_face_dof_data(msh, face, x_glob, x_proj_dof); + } + } + } + + void + scatter_e_face_dof_data( const Mesh& msh, const typename Mesh::face_type& face, + Matrix& x_glob, Matrix x_proj_dof) const + { + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + auto fc_id = msh.lookup(face); + auto glob_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; + x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; + } + + void + scatter_a_face_dof_data( const Mesh& msh, const typename Mesh::face_type& face, + Matrix& x_glob, Matrix x_proj_dof) const + { + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + auto fc_id = msh.lookup(face); + auto glob_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; + x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; + + } + + Matrix + gather_e_dof_data(size_t cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& x_glob) const { + + auto e_cell_ind = m_e_cell_index.find(cell_ind)->second; + auto num_faces = howmany_faces(msh, cl); + size_t n_cbs = get_e_cell_basis_data(); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + Matrix x_el(n_cbs + num_faces * n_fbs ); + x_el.block(0, 0, n_cbs, 1) = x_glob.block(e_cell_ind * n_cbs, 0, n_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_e_bnd.is_dirichlet_face( face_id)) { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_e_bnd.dirichlet_boundary_func(face_id); + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + x_el.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else { + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; + x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(face_LHS_offset, 0, n_fbs, 1); + } + } + return x_el; + } + + Matrix + gather_a_dof_data(size_t cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& x_glob) const + { + auto a_cell_ind = m_a_cell_index.find(cell_ind)->second; + auto num_faces = howmany_faces(msh, cl); + size_t n_cbs = get_a_cell_basis_data(); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + Matrix x_local(n_cbs + num_faces * n_fbs ); + x_local.block(0, 0, n_cbs, 1) = x_glob.block(a_cell_ind * n_cbs + m_n_elastic_cell_dof, 0, n_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) + { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_a_bnd.is_dirichlet_face( face_id)) + { + auto fb = disk::make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); + Matrix mass = make_mass_matrix(msh, fc, fb, m_hho_di.face_degree()); + auto velocity = m_a_bnd.dirichlet_boundary_func(face_id); + Matrix rhs = make_rhs(msh, fc, fb, velocity, m_hho_di.face_degree()); + x_local.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else + { + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; + x_local.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(face_LHS_offset, 0, n_fbs, 1); + } + } + return x_local; + } + + void finalize() + { + LHS.setFromTriplets( m_triplets.begin(), m_triplets.end() ); + m_triplets.clear(); + LHS_STAB.setFromTriplets( m_triplets_stab.begin(), m_triplets_stab.end() ); + m_triplets_stab.clear(); + } + + void finalize_mass() + { + MASS.setFromTriplets( m_mass_triplets.begin(), m_mass_triplets.end() ); + m_mass_triplets.clear(); + } + + void finalize_coupling() + { + COUPLING.setFromTriplets( m_c_triplets.begin(), m_c_triplets.end() ); + m_c_triplets.clear(); + } + + void set_coupling_stabilization() { + m_hho_stabilization_Q = false; + } + + void set_hdg_stabilization() { + // std::cout << bold << red << " SUMMARY: " << reset << std::endl; + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) { + m_hho_stabilization_Q = false; + } + else{ + m_hho_stabilization_Q = true; + } + } + + void set_interface_cell_indexes(std::map> & interface_cell_indexes){ + m_interface_cell_indexes = interface_cell_indexes; + } + + void set_hho_stabilization(){ + m_hho_stabilization_Q = true; + } + + void set_scaled_stabilization(){ + m_scaled_stabilization_Q = true; + } + + e_boundary_type & get_e_bc_conditions(){ + return m_e_bnd; + } + + a_boundary_type & get_a_bc_conditions(){ + return m_a_bnd; + } + + std::map> & get_e_material_data(){ + return m_e_material; + } + + std::map> & get_a_material_data(){ + return m_a_material; + } + + size_t get_a_n_cells_dof() const{ + return m_n_acoustic_cell_dof; + } + + size_t get_e_n_cells_dof() const { + return m_n_elastic_cell_dof; + } + + size_t get_n_face_dof() const { + size_t n_face_dof = m_n_elastic_face_dof + m_n_acoustic_face_dof; + return n_face_dof; + } + + size_t get_e_face_dof() const { + return m_n_elastic_face_dof; + } + + size_t get_a_face_dof() const { + return m_n_acoustic_face_dof; + } + + size_t get_e_cell_basis_data() const { + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + return n_cbs; + } + + size_t get_a_cell_basis_data() const { + size_t n_vel_scal_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_cbs = n_vel_scal_cbs + n_scal_cbs; + return n_cbs; + } + + size_t get_cell_basis_data(){ + + // Elastic cell basis + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs1 = n_ten_cbs + n_vec_cbs; + + // Acoustic cell basis + size_t n_vel_scal_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_cbs2 = n_vel_scal_cbs + n_scal_cbs; + + size_t n_cbs = n_cbs1 + n_cbs2; + + return n_cbs; + } + + size_t get_n_faces() { + return m_n_edges - m_n_essential_edges; + } + + size_t get_face_basis_data() { + size_t n_fbs1 = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + size_t n_fbs2 = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + size_t n_fbs = n_fbs1 + n_fbs2; + return n_fbs; + } + + size_t get_e_face_basis_data() { + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + return n_fbs; + } + + size_t get_a_face_basis_data() { + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + return n_fbs; + } + + size_t get_acoustic_cells() { + return m_n_acoustic_cells; + } + + size_t get_elastic_cells() { + return m_n_elastic_cells; + } + + size_t get_elastic_faces() { + return n_e_edges; + } + + size_t get_acoustic_faces() { + return n_a_edges; + } + + std::map> get_interfaces() { + return m_interface_cell_indexes; + } + + std::vector get_e_compress() { + return m_e_compress_indexes; + } + + std::vector get_a_compress() { + return m_a_compress_indexes; + } + + std::vector get_e_expand() { + return m_e_expand_indexes; + } + + std::vector get_a_expand() { + return m_a_expand_indexes; + } + + std::pair Scc_block_dimension(){ + + // Elastic block + auto graddeg = m_hho_di.grad_degree(); + auto ten_bs = disk::sym_matrix_basis_size(graddeg, Mesh::dimension, Mesh::dimension)*m_n_elastic_cells; + + // Acoustic block + auto recdeg = m_hho_di.reconstruction_degree(); + auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension); + auto vec_cell_size = (rbs-1)*m_n_acoustic_cells; + + return std::make_pair(ten_bs, vec_cell_size); + + } + +}; + +#endif /* elastoacoustic_four_fields_assembler_hpp */ diff --git a/apps/wave_propagation/src/common/elastoacoustic_two_fields_assembler.hpp b/apps/wave_propagation/src/common/elastoacoustic_two_fields_assembler.hpp new file mode 100644 index 00000000..d3ff2cae --- /dev/null +++ b/apps/wave_propagation/src/common/elastoacoustic_two_fields_assembler.hpp @@ -0,0 +1,1181 @@ +// +// elastoacoustic_two_fields_assembler.hpp +// acoustics +// +// Created by Omar Durán on 6/3/20. +// + +#pragma once +#ifndef elastoacoustic_two_fields_assembler_hpp +#define elastoacoustic_two_fields_assembler_hpp + +#include "diskpp/bases/bases.hpp" +#include "diskpp/methods/hho" +#include "../common/assembly_index.hpp" +#include "../common/acoustic_material_data.hpp" +#include "../common/elastic_material_data.hpp" +#include + +#ifdef HAVE_INTEL_TBB +#include +#endif + +template +class elastoacoustic_two_fields_assembler +{ + + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + using T = typename Mesh::coordinate_type; + + std::vector m_e_compress_indexes; + std::vector m_e_expand_indexes; + + std::vector m_a_compress_indexes; + std::vector m_a_expand_indexes; + + disk::hho_degree_info m_hho_di; + e_boundary_type m_e_bnd; + a_boundary_type m_a_bnd; + std::vector< Triplet > m_triplets; + std::vector< Triplet > m_c_triplets; + std::vector< Triplet > m_mass_triplets; + std::map> m_e_material; + std::map> m_a_material; + std::map m_e_cell_index; + std::map m_a_cell_index; + std::vector< size_t > m_e_elements_with_bc_eges; + std::vector< size_t > m_a_elements_with_bc_eges; + std::map> m_interface_cell_indexes; + +public: + + size_t m_n_edges; + size_t m_n_essential_edges; + bool m_hho_stabilization_Q; + size_t m_n_elastic_cell_dof; + size_t m_n_acoustic_cell_dof; + size_t m_n_elastic_face_dof; + size_t m_n_acoustic_face_dof; + + SparseMatrix LHS; + Matrix RHS; + SparseMatrix MASS; + SparseMatrix COUPLING; + + elastoacoustic_two_fields_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const e_boundary_type& e_bnd, const a_boundary_type& a_bnd, std::map> & e_material, std::map> & a_material) + : m_hho_di(hho_di), m_e_bnd(e_bnd), m_a_bnd(a_bnd), m_e_material(e_material), m_a_material(a_material), m_hho_stabilization_Q(true) + { + + auto storage = msh.backend_storage(); + auto is_e_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return e_bnd.is_dirichlet_face(fc_id); + }; + + auto is_a_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return a_bnd.is_dirichlet_face(fc_id); + }; + + size_t n_e_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_e_dirichlet); + size_t n_a_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_a_dirichlet); + + + std::set e_egdes; + for (auto &chunk : m_e_material) { + size_t cell_i = chunk.first; + auto& cell = storage->surfaces[cell_i]; + auto cell_faces = faces(msh,cell); + for (auto &face : cell_faces) { + if (!is_e_dirichlet(face)) { + auto fc_id = msh.lookup(face); + e_egdes.insert(fc_id); + } + } + } + size_t n_e_edges = e_egdes.size(); + + std::set a_egdes; + for (auto &chunk : m_a_material) { + size_t cell_i = chunk.first; + auto& cell = storage->surfaces[cell_i]; + auto cell_faces = faces(msh,cell); + for (auto &face : cell_faces) { + if (!is_a_dirichlet(face)) { + auto fc_id = msh.lookup(face); + a_egdes.insert(fc_id); + } + } + } + size_t n_a_edges = a_egdes.size(); + + m_n_edges = msh.faces_size(); + m_n_essential_edges = n_e_essential_edges + n_a_essential_edges; + + m_e_compress_indexes.resize( m_n_edges ); + m_e_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + m_a_compress_indexes.resize( m_n_edges ); + m_a_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + + + size_t e_compressed_offset = 0; + for (auto face_id : e_egdes) + { + m_e_compress_indexes.at(face_id) = e_compressed_offset; + m_e_expand_indexes.at(e_compressed_offset) = face_id; + e_compressed_offset++; + } + + size_t a_compressed_offset = 0; + for (auto face_id : a_egdes) + { + m_a_compress_indexes.at(face_id) = a_compressed_offset; + m_a_expand_indexes.at(a_compressed_offset) = face_id; + a_compressed_offset++; + } + + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + size_t n_s_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_s_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + m_n_elastic_cell_dof = (n_cbs * m_e_material.size()); + m_n_acoustic_cell_dof = (n_s_cbs * m_a_material.size()); + + m_n_elastic_face_dof = (n_fbs * n_e_edges); + m_n_acoustic_face_dof = (n_s_fbs * n_a_edges); + size_t system_size = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_n_acoustic_face_dof; + + LHS = SparseMatrix( system_size, system_size ); + RHS = Matrix::Zero( system_size ); + MASS = SparseMatrix( system_size, system_size ); + COUPLING = SparseMatrix( system_size, system_size ); + + classify_cells(msh); + build_cells_maps(); + } + + void scatter_e_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_LHS_offset = e_cell_ind * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; + bool dirichlet = m_e_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + } + } + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_a_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; + + bool dirichlet = m_a_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + } + } + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_e_mass_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& mass_matrix) + { + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_LHS_offset = e_cell_ind * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == mass_matrix.rows() && asm_map.size() == mass_matrix.cols() ); + + for (size_t i = 0; i < mass_matrix.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < mass_matrix.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_mass_triplets.push_back( Triplet(asm_map[i], asm_map[j], mass_matrix(i,j)) ); + } + } + + } + + void scatter_a_mass_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& mass_matrix) + { + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == mass_matrix.rows() && asm_map.size() == mass_matrix.cols() ); + + for (size_t i = 0; i < mass_matrix.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < mass_matrix.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_mass_triplets.push_back( Triplet(asm_map[i], asm_map[j], mass_matrix(i,j)) ); + } + } + + } + + void scatter_ea_interface_data(const Mesh& msh, const typename Mesh::face_type& face, + const Matrix& interface_matrix) + { + auto vfbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + auto sfbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + std::vector asm_map_e, asm_map_a; + asm_map_e.reserve(vfbs); + asm_map_a.reserve(sfbs); + + auto fc_id = msh.lookup(face); + + auto e_face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*vfbs; + bool e_dirichlet = m_e_bnd.is_dirichlet_face(fc_id); + for (size_t i = 0; i < vfbs; i++){ + asm_map_e.push_back( assembly_index(e_face_LHS_offset+i, !e_dirichlet) ); + } + + auto a_face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*sfbs; + bool a_dirichlet = m_a_bnd.is_dirichlet_face(fc_id); + for (size_t i = 0; i < sfbs; i++){ + asm_map_a.push_back( assembly_index(a_face_LHS_offset+i, !a_dirichlet) ); + } + + assert( asm_map_e.size() == interface_matrix.rows() && asm_map_a.size() == interface_matrix.cols() ); + + for (size_t i = 0; i < interface_matrix.rows(); i++) + { + for (size_t j = 0; j < interface_matrix.cols(); j++) + { + m_c_triplets.push_back( Triplet(asm_map_e[i], asm_map_a[j], interface_matrix(i,j)) ); + m_c_triplets.push_back( Triplet(asm_map_a[j], asm_map_e[i], - interface_matrix(i,j)) ); + } + } + + } + + void scatter_e_interface_neumann_data(const Mesh& msh, const typename Mesh::face_type& face, + const Matrix& interface_bc_data) + { + auto vfbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + std::vector asm_map_e; + asm_map_e.reserve(vfbs); + + auto fc_id = msh.lookup(face); + + auto e_face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*vfbs; + bool e_dirichlet = m_e_bnd.is_dirichlet_face(fc_id); + for (size_t i = 0; i < vfbs; i++){ + asm_map_e.push_back( assembly_index(e_face_LHS_offset+i, !e_dirichlet) ); + } + + assert( asm_map_e.size() == interface_bc_data.rows()); + + for (size_t i = 0; i < interface_bc_data.rows(); i++) + { + if (!asm_map_e[i].assemble()) + continue; + RHS(int(asm_map_e[i])) += interface_bc_data(i,0); + } + + } + + + void scatter_a_interface_neumann_data(const Mesh& msh, const typename Mesh::face_type& face, + const Matrix& interface_bc_data) + { + + auto sfbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + std::vector asm_map_a; + asm_map_a.reserve(sfbs); + + auto fc_id = msh.lookup(face); + + auto a_face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*sfbs; + bool a_dirichlet = m_a_bnd.is_dirichlet_face(fc_id); + for (size_t i = 0; i < sfbs; i++){ + asm_map_a.push_back( assembly_index(a_face_LHS_offset+i, !a_dirichlet) ); + } + + assert( asm_map_a.size() == interface_bc_data.rows() ); + + for (size_t i = 0; i < interface_bc_data.rows(); i++) + { + if (!asm_map_a[i].assemble()) + continue; + RHS(int(asm_map_a[i])) += interface_bc_data(i,0); + } + + } + + void scatter_e_rhs_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& rhs) + { + + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_LHS_offset = e_cell_ind * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == rhs.rows() ); + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_a_rhs_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& rhs) + { + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == rhs.rows()); + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_e_bc_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs) + { + + auto fcs = faces(msh, cl); + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_LHS_offset = e_cell_ind * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; + + bool dirichlet = m_e_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_e_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( !asm_map[j].assemble() ) + RHS(int(asm_map[i])) -= lhs(i,j) * dirichlet_data(j); + } + } + + } + + void scatter_a_bc_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; + + bool dirichlet = m_a_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_a_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( !asm_map[j].assemble() ) + RHS(int(asm_map[i])) -= lhs(i,j) * dirichlet_data(j); + + } + } + + } + + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun){ + + auto storage = msh.backend_storage(); + LHS.setZero(); + RHS.setZero(); + + // elastic block + for (auto e_chunk : m_e_material) { + size_t e_cell_ind = m_e_cell_index[e_chunk.first]; + auto& cell = storage->surfaces[e_chunk.first]; + Matrix vectorial_laplacian_operator_loc = e_laplacian_operator(e_chunk.second,msh,cell); + auto cell_basis = make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, e_rhs_fun); + scatter_e_data(e_cell_ind, msh, cell, vectorial_laplacian_operator_loc, f_loc); + } + + // acoustic block + for (auto a_chunk : m_a_material) { + size_t a_cell_ind = m_a_cell_index[a_chunk.first]; + auto& cell = storage->surfaces[a_chunk.first]; + + Matrix laplacian_operator_loc = a_laplacian_operator(a_chunk.second, msh, cell); + auto cell_basis = make_scalar_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, a_rhs_fun); + scatter_a_data(a_cell_ind, msh, cell, laplacian_operator_loc, f_loc); + } + finalize(); + } + + + void assemble_coupling_terms(const Mesh& msh){ + + auto storage = msh.backend_storage(); + COUPLING.setZero(); + // coupling blocks + for (auto chunk : m_interface_cell_indexes) { + auto& face = storage->edges[chunk.first]; + auto& e_cell = storage->surfaces[chunk.second.first]; + auto& a_cell = storage->surfaces[chunk.second.second]; + Matrix interface_operator_loc = e_interface_operator(msh, face, e_cell, a_cell); + scatter_ea_interface_data(msh, face, interface_operator_loc); + } + finalize_coupling(); + } + + void apply_bc_conditions_on_interface(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_vel_fun, std::function a_vel_fun){ + + auto storage = msh.backend_storage(); + // Applying transmission conditions as neumann data for the case of uncoupled problems + for (auto chunk : m_interface_cell_indexes) { + auto& face = storage->edges[chunk.first]; + auto& e_cell = storage->surfaces[chunk.second.first]; + auto& a_cell = storage->surfaces[chunk.second.second]; + + Matrix e_neumann_operator_loc = e_neumman_bc_operator(msh, face, e_cell, a_cell, a_vel_fun); + scatter_e_interface_neumann_data(msh, face, e_neumann_operator_loc); + + Matrix a_neumann_operator_loc = a_neumman_bc_operator(msh, face, e_cell, a_cell, e_vel_fun); + scatter_a_interface_neumann_data(msh, face, a_neumann_operator_loc); + + } + } + + void assemble_mass(const Mesh& msh){ + + auto storage = msh.backend_storage(); + MASS.setZero(); + + // elastic block + for (auto e_chunk : m_e_material) { + size_t e_cell_ind = m_e_cell_index[e_chunk.first]; + auto& cell = storage->surfaces[e_chunk.first]; + Matrix mass_matrix = e_mass_operator(e_chunk.second,msh, cell); + scatter_e_mass_data(e_cell_ind,msh, cell, mass_matrix); + } + + // acoustic block + for (auto a_chunk : m_a_material) { + size_t a_cell_ind = m_a_cell_index[a_chunk.first]; + auto& cell = storage->surfaces[a_chunk.first]; + Matrix mass_matrix = a_mass_operator(a_chunk.second,msh, cell); + scatter_a_mass_data(a_cell_ind,msh, cell, mass_matrix); + } + + finalize_mass(); + } + + void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun){ + + RHS.setZero(); + #ifdef HAVE_INTEL_TBB2 + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh,&rhs_fun] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, rhs_fun); + this->scatter_rhs_data(msh, cell, f_loc); + } + ); + #else + auto storage = msh.backend_storage(); + for (auto e_chunk : m_e_material) { + size_t e_cell_ind = m_e_cell_index[e_chunk.first]; + auto& cell = storage->surfaces[e_chunk.first]; + auto cell_basis = make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, e_rhs_fun); + scatter_e_rhs_data(e_cell_ind, msh, cell, f_loc); + } + + for (auto a_chunk : m_a_material) { + size_t a_cell_ind = m_a_cell_index[a_chunk.first]; + auto& cell = storage->surfaces[a_chunk.first]; + auto cell_basis = make_scalar_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, a_rhs_fun); + scatter_a_rhs_data(a_cell_ind, msh, cell, f_loc); + } + + #endif + apply_bc(msh); + } + + void apply_bc(const Mesh& msh){ + + #ifdef HAVE_INTEL_TBB2 + size_t n_cells = m_elements_with_bc_eges.size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh] (size_t & i){ + size_t cell_ind = m_elements_with_bc_eges[i]; + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix laplacian_operator_loc = laplacian_operator(cell_ind, msh, cell); + scatter_bc_data(msh, cell, laplacian_operator_loc); + } + ); + #else + auto storage = msh.backend_storage(); + for (auto& cell_ind : m_e_elements_with_bc_eges) + { + auto& cell = storage->surfaces[cell_ind]; + elastic_material_data e_mat = m_e_material.find(cell_ind)->second; + Matrix vectorial_laplacian_operator_loc = e_laplacian_operator(e_mat,msh,cell); + scatter_e_bc_data(cell_ind, msh, cell, vectorial_laplacian_operator_loc); + } + + for (auto& cell_ind : m_a_elements_with_bc_eges) + { + auto& cell = storage->surfaces[cell_ind]; + acoustic_material_data a_mat = m_a_material.find(cell_ind)->second; + Matrix laplacian_operator_loc = a_laplacian_operator(a_mat, msh, cell); + scatter_a_bc_data(cell_ind, msh, cell, laplacian_operator_loc); + } + + #endif + + } + + Matrix e_mass_operator(elastic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell){ + auto vec_basis = disk::make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix mass_matrix = disk::make_mass_matrix(msh, cell, vec_basis); + mass_matrix *= (material.rho()); + return mass_matrix; + } + + Matrix a_mass_operator(acoustic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell){ + + auto scal_basis = disk::make_scalar_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix mass_matrix = disk::make_mass_matrix(msh, cell, scal_basis); + mass_matrix *= (1.0/(material.rho()*material.vp()*material.vp())); + return mass_matrix; + } + + + Matrix e_laplacian_operator(elastic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell){ + + T mu = material.rho()*material.vs()*material.vs(); + T lambda = material.rho()*material.vp()*material.vp() - 2.0*mu; + auto reconstruction_operator = make_matrix_symmetric_gradrec(msh, cell, m_hho_di); + auto rec_for_stab = make_vector_hho_symmetric_laplacian(msh, cell, m_hho_di); + auto divergence_operator = make_hho_divergence_reconstruction(msh, cell, m_hho_di); + + Matrix R_operator = reconstruction_operator.second; + Matrix S_operator; + if(m_hho_stabilization_Q) + { + auto stabilization_operator = make_vector_hho_stabilization(msh, cell, rec_for_stab.first, m_hho_di); + S_operator = stabilization_operator; + }else{ + auto stabilization_operator = make_vector_hdg_stabilization(msh, cell, m_hho_di); + S_operator = stabilization_operator; + } + return 2.0 * mu * (R_operator + S_operator) + lambda * divergence_operator.second; + } + + Matrix a_laplacian_operator(acoustic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell){ + + auto reconstruction_operator = make_scalar_hho_laplacian(msh, cell, m_hho_di); + Matrix R_operator = reconstruction_operator.second; + + Matrix S_operator; + if(m_hho_stabilization_Q) + { + auto stabilization_operator = make_scalar_hho_stabilization(msh, cell, reconstruction_operator.first, m_hho_di); + S_operator = stabilization_operator; + }else{ + auto stabilization_operator = make_scalar_hdg_stabilization(msh, cell, m_hho_di); + S_operator = stabilization_operator; + } + return (1.0/material.rho())*(R_operator + S_operator); + } + + Matrix e_interface_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell){ + + Matrix interface_operator; + auto facdeg = m_hho_di.face_degree(); + auto vfbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + auto sfbs = disk::scalar_basis_size(facdeg, Mesh::dimension - 1); + + interface_operator = Matrix::Zero(vfbs, sfbs); + + auto vfb = make_vector_monomial_basis(msh, face, facdeg); + auto sfb = make_scalar_monomial_basis(msh, face, facdeg); + const auto qps = integrate(msh, face, facdeg); + const auto n = disk::normal(msh, e_cell, face); + for (auto& qp : qps) + { + const auto v_f_phi = vfb.eval_functions(qp.point()); + const auto s_f_phi = sfb.eval_functions(qp.point()); + + assert(v_f_phi.rows() == vfbs); + assert(s_f_phi.rows() == sfbs); + const auto n_dot_v_f_phi = disk::priv::inner_product(v_f_phi,disk::priv::inner_product(qp.weight(), n)); + const auto result = -1.0*disk::priv::outer_product(n_dot_v_f_phi, s_f_phi); + interface_operator += result; + } + return interface_operator; + } + + Matrix e_neumman_bc_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell, std::function a_vel_fun){ + + Matrix neumann_operator; + auto facdeg = m_hho_di.face_degree(); + auto vfbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + neumann_operator = Matrix::Zero(vfbs, 1); + + auto vfb = make_vector_monomial_basis(msh, face, facdeg); + auto sfb = make_scalar_monomial_basis(msh, face, facdeg); + const auto qps = integrate(msh, face, facdeg); + const auto n = disk::normal(msh, e_cell, face); + for (auto& qp : qps) + { + const auto v_f_phi = vfb.eval_functions(qp.point()); + const auto s_f_phi = sfb.eval_functions(qp.point()); + + assert(v_f_phi.rows() == vfbs); + const auto n_dot_v_f_phi = disk::priv::inner_product(v_f_phi,disk::priv::inner_product(qp.weight(), n)); + const auto result = disk::priv::outer_product(n_dot_v_f_phi, a_vel_fun(qp.point())); + neumann_operator += result; + + } + return neumann_operator; + } + + Matrix a_neumman_bc_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell, std::function(const typename Mesh::point_type& )> e_vel_fun){ + + Matrix neumann_operator; + auto facdeg = m_hho_di.face_degree(); + auto sfbs = disk::scalar_basis_size(facdeg, Mesh::dimension - 1); + + neumann_operator = Matrix::Zero(sfbs, 1); + + auto vfb = make_vector_monomial_basis(msh, face, facdeg); + auto sfb = make_scalar_monomial_basis(msh, face, facdeg); + const auto qps = integrate(msh, face, facdeg); + const auto n = disk::normal(msh, a_cell, face); + for (auto& qp : qps) + { + const auto v_f_phi = vfb.eval_functions(qp.point()); + const auto s_f_phi = sfb.eval_functions(qp.point()); + + assert(s_f_phi.rows() == sfbs); + const auto n_dot_v_f = disk::priv::inner_product(e_vel_fun(qp.point()),disk::priv::inner_product(qp.weight(), n)); + const auto result = disk::priv::inner_product(n_dot_v_f, s_f_phi); + neumann_operator += result; + } + return neumann_operator; + } + + void classify_cells(const Mesh& msh){ + + m_e_elements_with_bc_eges.clear(); + for (auto& cell : msh) + { + auto cell_ind = msh.lookup(cell); + auto face_list = faces(msh, cell); + for (size_t face_i = 0; face_i < face_list.size(); face_i++) + { + auto fc = face_list[face_i]; + auto fc_id = msh.lookup(fc); + bool is_dirichlet_Q = m_e_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + m_e_elements_with_bc_eges.push_back(cell_ind); + break; + } + } + } + + m_a_elements_with_bc_eges.clear(); + for (auto& cell : msh) + { + typename Mesh::point_type bar = barycenter(msh, cell); + if (bar.x() < 0) { + continue; + } + + auto cell_ind = msh.lookup(cell); + auto face_list = faces(msh, cell); + for (size_t face_i = 0; face_i < face_list.size(); face_i++) + { + auto fc = face_list[face_i]; + auto fc_id = msh.lookup(fc); + bool is_dirichlet_Q = m_a_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + m_a_elements_with_bc_eges.push_back(cell_ind); + break; + } + } + } + } + + void build_cells_maps(){ + + // elastic data + size_t e_cell_ind = 0; + for (auto chunk : m_e_material) { + m_e_cell_index.insert(std::make_pair(chunk.first,e_cell_ind)); + e_cell_ind++; + } + + // acoustic data + size_t a_cell_ind = 0; + for (auto chunk : m_a_material) { + m_a_cell_index.insert(std::make_pair(chunk.first,a_cell_ind)); + a_cell_ind++; + } + } + + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function scal_fun){ + + auto storage = msh.backend_storage(); + size_t n_dof = MASS.rows(); + x_glob = Matrix::Zero(n_dof); + + // elastic block + for (auto e_chunk : m_e_material) { + size_t e_cell_ind = m_e_cell_index[e_chunk.first]; + auto& cell = storage->surfaces[e_chunk.first]; + Matrix x_proj_dof = project_function(msh, cell, m_hho_di.cell_degree(), vec_fun); + scatter_e_cell_dof_data(e_cell_ind, msh, cell, x_glob, x_proj_dof); + } + + // acoustic block + for (auto a_chunk : m_a_material) { + size_t a_cell_ind = m_a_cell_index[a_chunk.first]; + auto& cell = storage->surfaces[a_chunk.first]; + Matrix x_proj_dof = project_function(msh, cell, m_hho_di.cell_degree(), scal_fun); + scatter_a_cell_dof_data(a_cell_ind, msh, cell, x_glob, x_proj_dof); + } + + } + + void + scatter_e_cell_dof_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell, + Matrix& x_glob, Matrix x_proj_dof) const + { + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + auto cell_ofs = e_cell_ind * n_cbs; + x_glob.block(cell_ofs, 0, n_cbs, 1) = x_proj_dof; + } + + void + scatter_a_cell_dof_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell, + Matrix& x_glob, Matrix x_proj_dof) const + { + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + auto cell_ofs = a_cell_ind * n_cbs + m_n_elastic_cell_dof; + x_glob.block(cell_ofs, 0, n_cbs, 1) = x_proj_dof; + } + + + + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function scal_fun){ + + auto storage = msh.backend_storage(); + + // elastic block + for (auto e_chunk : m_e_material) { + auto& cell = storage->surfaces[e_chunk.first]; + auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + auto face = fcs[i]; + auto fc_id = msh.lookup(face); + bool is_dirichlet_Q = m_e_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + continue; + } + Matrix x_proj_dof = project_function(msh, face, m_hho_di.face_degree(), vec_fun); + scatter_e_face_dof_data(msh, face, x_glob, x_proj_dof); + } + } + + // acoustic block + for (auto a_chunk : m_a_material) { + auto& cell = storage->surfaces[a_chunk.first]; + auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + auto face = fcs[i]; + auto fc_id = msh.lookup(face); + bool is_dirichlet_Q = m_a_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + continue; + } + Matrix x_proj_dof = project_function(msh, face, m_hho_di.face_degree(), scal_fun); + scatter_a_face_dof_data(msh, face, x_glob, x_proj_dof); + } + } + } + + void + scatter_e_face_dof_data( const Mesh& msh, const typename Mesh::face_type& face, + Matrix& x_glob, Matrix x_proj_dof) const + { + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + auto fc_id = msh.lookup(face); + auto glob_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; + x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; + } + + void + scatter_a_face_dof_data( const Mesh& msh, const typename Mesh::face_type& face, + Matrix& x_glob, Matrix x_proj_dof) const + { + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + auto fc_id = msh.lookup(face); + auto glob_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; + x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; + + } + + Matrix + gather_e_dof_data(size_t cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& x_glob) const + { + auto e_cell_ind = m_e_cell_index.find(cell_ind)->second; + auto num_faces = howmany_faces(msh, cl); + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + Matrix x_el(n_cbs + num_faces * n_fbs ); + x_el.block(0, 0, n_cbs, 1) = x_glob.block(e_cell_ind * n_cbs, 0, n_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) + { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_e_bnd.is_dirichlet_face( face_id)) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_e_bnd.dirichlet_boundary_func(face_id); + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + x_el.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else + { + + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; + x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(face_LHS_offset, 0, n_fbs, 1); + } + } + return x_el; + } + + Matrix + gather_a_dof_data(size_t cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& x_glob) const + { + auto a_cell_ind = m_a_cell_index.find(cell_ind)->second; + auto num_faces = howmany_faces(msh, cl); + size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + Matrix x_local(n_cbs + num_faces * n_fbs ); + x_local.block(0, 0, n_cbs, 1) = x_glob.block(a_cell_ind * n_cbs + m_n_elastic_cell_dof, 0, n_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) + { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_a_bnd.is_dirichlet_face( face_id)) + { + auto fb = disk::make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); + Matrix mass = make_mass_matrix(msh, fc, fb, m_hho_di.face_degree()); + auto velocity = m_a_bnd.dirichlet_boundary_func(face_id); + Matrix rhs = make_rhs(msh, fc, fb, velocity, m_hho_di.face_degree()); + x_local.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else + { + auto fc_id = msh.lookup(fc); + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; + x_local.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(face_LHS_offset, 0, n_fbs, 1); + } + } + return x_local; + } + + void finalize() + { + LHS.setFromTriplets( m_triplets.begin(), m_triplets.end() ); + m_triplets.clear(); + } + + void finalize_mass() + { + MASS.setFromTriplets( m_mass_triplets.begin(), m_mass_triplets.end() ); + m_mass_triplets.clear(); + } + + void finalize_coupling() + { + COUPLING.setFromTriplets( m_c_triplets.begin(), m_c_triplets.end() ); + m_c_triplets.clear(); + } + + void set_hdg_stabilization(){ + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) + { + m_hho_stabilization_Q = false; + std::cout << "Proceeding with HDG stabilization cell degree is higher than face degree." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + }else{ + std::cout << "Proceeding with HHO stabilization cell and face degree are equal." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + } + } + + void set_interface_cell_indexes(std::map> & interface_cell_indexes){ + m_interface_cell_indexes = interface_cell_indexes; + } + + void set_hho_stabilization(){ + m_hho_stabilization_Q = true; + } + + e_boundary_type & get_e_bc_conditions(){ + return m_e_bnd; + } + + a_boundary_type & get_a_bc_conditions(){ + return m_a_bnd; + } + + std::map> & get_e_material_data(){ + return m_e_material; + } + + std::map> & get_a_material_data(){ + return m_a_material; + } + + size_t get_a_n_cells_dof(){ + return m_n_acoustic_cell_dof; + } + + size_t get_e_n_cells_dof(){ + return m_n_elastic_cell_dof; + } + + size_t get_n_face_dof(){ + size_t n_face_dof = m_n_elastic_face_dof + m_n_acoustic_face_dof; + return n_face_dof; + } + + size_t get_e_cell_basis_data(){ + size_t n_v_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + return n_v_cbs; + } + + size_t get_a_cell_basis_data(){ + size_t n_s_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + return n_s_cbs; + } + +}; + +#endif /* elastoacoustic_two_fields_assembler_hpp */ diff --git a/apps/wave_propagation/src/common/elastodynamic_one_field_assembler.hpp b/apps/wave_propagation/src/common/elastodynamic_one_field_assembler.hpp new file mode 100644 index 00000000..36714493 --- /dev/null +++ b/apps/wave_propagation/src/common/elastodynamic_one_field_assembler.hpp @@ -0,0 +1,562 @@ +// +// elastodynamic_one_field_assembler.hpp +// acoustics +// +// Created by Omar Durán on 4/14/20. +// + +#pragma once +#ifndef elastodynamic_one_field_assembler_hpp +#define elastodynamic_one_field_assembler_hpp + +#include "diskpp/bases/bases.hpp" +#include "diskpp/methods/hho" +#include "../common/assembly_index.hpp" +#include "../common/elastic_material_data.hpp" + +#ifdef HAVE_INTEL_TBB +#include +#endif + +template +class elastodynamic_one_field_assembler +{ + + typedef disk::BoundaryConditions boundary_type; + using T = typename Mesh::coordinate_type; + + std::vector m_compress_indexes; + std::vector m_expand_indexes; + + disk::hho_degree_info m_hho_di; + boundary_type m_bnd; + std::vector< Triplet > m_triplets; + std::vector< Triplet > m_mass_triplets; + std::vector< elastic_material_data > m_material; + std::vector< size_t > m_elements_with_bc_eges; + + size_t m_n_edges; + size_t m_n_essential_edges; + bool m_hho_stabilization_Q; + +public: + + SparseMatrix LHS; + Matrix RHS; + SparseMatrix MASS; + + elastodynamic_one_field_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const boundary_type& bnd) + : m_hho_di(hho_di), m_bnd(bnd), m_hho_stabilization_Q(true) + { + + auto is_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return bnd.is_dirichlet_face(fc_id); + }; + + m_n_edges = msh.faces_size(); + m_n_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_dirichlet); + + m_compress_indexes.resize( m_n_edges ); + m_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + size_t compressed_offset = 0; + for (size_t i = 0; i < m_n_edges; i++) + { + auto fc = *std::next(msh.faces_begin(), i); + if ( !is_dirichlet(fc) ) + { + m_compress_indexes.at(i) = compressed_offset; + m_expand_indexes.at(compressed_offset) = i; + compressed_offset++; + } + } + + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + size_t system_size = n_cbs * msh.cells_size() + n_fbs * (m_n_edges - m_n_essential_edges); + + LHS = SparseMatrix( system_size, system_size ); + RHS = Matrix::Zero( system_size ); + MASS = SparseMatrix( system_size, system_size ); + + classify_cells(msh); + } + + void scatter_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + } + } + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_bc_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs) + { + + auto fcs = faces(msh, cl); + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( !asm_map[j].assemble() ) + RHS(int(asm_map[i])) -= lhs(i,j) * dirichlet_data(j); + } + } + + } + + void scatter_rhs_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& rhs) + { + + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == rhs.rows() ); + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_mass_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& mass_matrix) + { + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == mass_matrix.rows() && asm_map.size() == mass_matrix.cols() ); + + for (size_t i = 0; i < mass_matrix.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < mass_matrix.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_mass_triplets.push_back( Triplet(asm_map[i], asm_map[j], mass_matrix(i,j)) ); + } + } + + } + + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ + + LHS.setZero(); + RHS.setZero(); + size_t cell_ind = 0; + for (auto& cell : msh) + { + Matrix vectorial_laplacian_operator_loc = laplacian_operator(cell_ind,msh,cell); + auto cell_basis = make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, rhs_fun); + scatter_data(msh, cell, vectorial_laplacian_operator_loc, f_loc); + cell_ind++; + } + finalize(); + } + + void apply_bc(const Mesh& msh, T scale = T(1.0)){ + + auto storage = msh.backend_storage(); + #ifdef HAVE_INTEL_TBB2 + size_t n_cells = m_elements_with_bc_eges.size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh,&storage] (size_t & i){ + size_t cell_ind = m_elements_with_bc_eges[i]; + auto& cell = storage->surfaces[cell_ind]; + Matrix laplacian_operator_loc = laplacian_operator(cell_ind, msh, cell); + laplacian_operator_loc *= scale; + scatter_bc_data(msh, cell, laplacian_operator_loc); + } + ); + #else + for (auto& cell_ind : m_elements_with_bc_eges) + { + auto& cell = storage->surfaces[cell_ind]; + Matrix laplacian_operator_loc = laplacian_operator(cell_ind, msh, cell); + laplacian_operator_loc *= scale; + scatter_bc_data(msh, cell, laplacian_operator_loc); + } + #endif + + } + + void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun, T scale = T(1.0)){ + + RHS.setZero(); + #ifdef HAVE_INTEL_TBB2 + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh,&rhs_fun] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, rhs_fun); + this->scatter_rhs_data(msh, cell, f_loc); + } + ); + #else + auto contribute = [this,&msh,&rhs_fun] (const typename Mesh::cell_type& cell){ + auto cell_basis = make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix f_loc = make_rhs(msh, cell, cell_basis, rhs_fun); + this->scatter_rhs_data(msh, cell, f_loc); + }; + + for (auto& cell : msh){ + contribute(cell); + } + #endif + apply_bc(msh,scale); + } + + void assemble_mass(const Mesh& msh){ + + MASS.setZero(); + size_t cell_ind = 0; + for (auto& cell : msh) + { + Matrix mass_matrix = mass_operator(cell_ind,msh, cell); + scatter_mass_data(msh, cell, mass_matrix); + cell_ind++; + } + finalize_mass(); + } + + Matrix laplacian_operator(size_t & cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell){ + + elastic_material_data & material = m_material[cell_ind]; + T mu = material.rho()*material.vs()*material.vs(); + T lambda = material.rho()*material.vp()*material.vp() - 2.0*mu; + auto reconstruction_operator = make_matrix_symmetric_gradrec(msh, cell, m_hho_di); + auto rec_for_stab = make_vector_hho_symmetric_laplacian(msh, cell, m_hho_di); + auto divergence_operator = make_hho_divergence_reconstruction(msh, cell, m_hho_di); + + Matrix R_operator = reconstruction_operator.second; + Matrix S_operator; + if(m_hho_stabilization_Q) + { + auto stabilization_operator = make_vector_hho_stabilization(msh, cell, rec_for_stab.first, m_hho_di); + S_operator = stabilization_operator; + }else{ + auto stabilization_operator = make_vector_hdg_stabilization(msh, cell, m_hho_di); + S_operator = stabilization_operator; + } + return 2.0 * mu * (R_operator + S_operator) + lambda * divergence_operator.second; + } + + Matrix mass_operator(size_t & cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell){ + + elastic_material_data & material = m_material[cell_ind]; + auto vec_basis = disk::make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix mass_matrix = disk::make_mass_matrix(msh, cell, vec_basis); + mass_matrix *= (material.rho()); + return mass_matrix; + } + + void classify_cells(const Mesh& msh){ + + m_elements_with_bc_eges.clear(); + size_t cell_ind = 0; + for (auto& cell : msh) + { + auto face_list = faces(msh, cell); + for (size_t face_i = 0; face_i < face_list.size(); face_i++) + { + auto fc = face_list[face_i]; + auto fc_id = msh.lookup(fc); + bool is_dirichlet_Q = m_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + m_elements_with_bc_eges.push_back(cell_ind); + break; + } + } + cell_ind++; + } + } + + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun){ + size_t n_dof = MASS.rows(); + x_glob = Matrix::Zero(n_dof); + for (auto& cell : msh) + { + Matrix x_proj_dof = project_function(msh, cell, m_hho_di.cell_degree(), vec_fun); + scatter_cell_dof_data(msh, cell, x_glob, x_proj_dof); + } + } + + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun){ + + for (auto& cell : msh) + { + auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + auto face = fcs[i]; + auto fc_id = msh.lookup(face); + bool is_dirichlet_Q = m_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + continue; + } + Matrix x_proj_dof = project_function(msh, face, m_hho_di.face_degree(), vec_fun); + scatter_face_dof_data(msh, face, x_glob, x_proj_dof); + } + } + } + + void finalize(void) + { + LHS.setFromTriplets( m_triplets.begin(), m_triplets.end() ); + m_triplets.clear(); + } + + void finalize_mass(void) + { + MASS.setFromTriplets( m_mass_triplets.begin(), m_mass_triplets.end() ); + m_mass_triplets.clear(); + } + + Matrix + gather_dof_data( const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& x_glob) const + { + auto num_faces = howmany_faces(msh, cl); + auto cell_ofs = disk::priv::offset(msh, cl); + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + Matrix x_el(n_cbs + num_faces * n_fbs ); + x_el.block(0, 0, n_cbs, 1) = x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) + { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_bnd.is_dirichlet_face( face_id)) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(face_id); + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + x_el.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else + { + auto face_ofs = disk::priv::offset(msh, fc); + auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; + x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); + } + } + return x_el; + } + + void + scatter_cell_dof_data( const Mesh& msh, const typename Mesh::cell_type& cell, + Matrix& x_glob, Matrix x_proj_dof) const + { + auto cell_ofs = disk::priv::offset(msh, cell); + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1) = x_proj_dof; + } + + void + scatter_face_dof_data( const Mesh& msh, const typename Mesh::face_type& face, + Matrix& x_glob, Matrix x_proj_dof) const + { + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + size_t n_cells = msh.cells_size(); + auto face_offset = disk::priv::offset(msh, face); + auto glob_offset = n_cbs * n_cells + m_compress_indexes.at(face_offset)*n_fbs; + x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; + } + + void load_material_data(const Mesh& msh, elastic_material_data material){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + m_material.push_back(material); + } + } + + void load_material_data(const Mesh& msh, std::function(const typename Mesh::point_type& )> elastic_mat_fun){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + for (auto& cell : msh) + { + auto bar = barycenter(msh, cell); + std::vector mat_data = elastic_mat_fun(bar); + T rho = mat_data[0]; + T vp = mat_data[1]; + T vs = mat_data[2]; + elastic_material_data material(rho,vp,vs); + m_material.push_back(material); + } + } + + void load_material_data(const Mesh& msh){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + T rho = 1.0; + T vp = std::sqrt(3.0); + T vs = 1.0; + elastic_material_data material(rho,vp,vs); + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + m_material.push_back(material); + } + } + + void set_hdg_stabilization(){ + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) + { + m_hho_stabilization_Q = false; + std::cout << "Proceeding with HDG stabilization cell degree is higher than face degree." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + }else{ + std::cout << "Proceeding with HHO stabilization cell and face degree are equal." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + } + } + + void set_hho_stabilization(){ + m_hho_stabilization_Q = true; + } + + boundary_type & get_bc_conditions(){ + return m_bnd; + } + + std::vector< elastic_material_data > & get_material_data(){ + return m_material; + } + + size_t get_n_face_dof(){ + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + size_t n_face_dof = (m_n_edges - m_n_essential_edges) * n_fbs; + return n_face_dof; + } + + size_t get_cell_basis_data(){ + size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + return n_cbs; + } + +}; + +#endif /* elastodynamic_one_field_assembler_hpp */ diff --git a/apps/wave_propagation/src/common/elastodynamic_three_fields_assembler.hpp b/apps/wave_propagation/src/common/elastodynamic_three_fields_assembler.hpp new file mode 100644 index 00000000..68029dae --- /dev/null +++ b/apps/wave_propagation/src/common/elastodynamic_three_fields_assembler.hpp @@ -0,0 +1,908 @@ +// +// elastodynamic_three_fields_assembler.hpp +// acoustics +// +// Created by Omar Durán on 4/23/20. +// + +#pragma once +#ifndef elastodynamic_three_fields_assembler_hpp +#define elastodynamic_three_fields_assembler_hpp + +#include "diskpp/bases/bases.hpp" +#include "diskpp/methods/hho" +#include "../common/assembly_index.hpp" +#include "../common/elastic_material_data.hpp" + +#ifdef HAVE_INTEL_TBB +#include +#endif + +template +class elastodynamic_three_fields_assembler +{ + + + typedef disk::BoundaryConditions boundary_type; + using T = typename Mesh::coordinate_type; + + std::vector m_compress_indexes; + std::vector m_expand_indexes; + + disk::hho_degree_info m_hho_di; + boundary_type m_bnd; + std::vector< Triplet > m_triplets; + std::vector< Triplet > m_mass_triplets; + std::vector< elastic_material_data > m_material; + std::vector< size_t > m_elements_with_bc_eges; + + size_t m_n_edges; + size_t m_n_essential_edges; + bool m_hho_stabilization_Q; + bool m_scaled_stabilization_Q; + +public: + + SparseMatrix LHS; + Matrix RHS; + SparseMatrix MASS; + + elastodynamic_three_fields_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const boundary_type& bnd) + : m_hho_di(hho_di), m_bnd(bnd), m_hho_stabilization_Q(true), m_scaled_stabilization_Q(false) + { + + auto is_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return bnd.is_dirichlet_face(fc_id); + }; + + m_n_edges = msh.faces_size(); + m_n_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_dirichlet); + + m_compress_indexes.resize( m_n_edges ); + m_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + size_t compressed_offset = 0; + for (size_t i = 0; i < m_n_edges; i++) + { + auto fc = *std::next(msh.faces_begin(), i); + if ( !is_dirichlet(fc) ) + { + m_compress_indexes.at(i) = compressed_offset; + m_expand_indexes.at(compressed_offset) = i; + compressed_offset++; + } + } + + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + size_t system_size = n_cbs * msh.cells_size() + n_fbs * (m_n_edges - m_n_essential_edges); + + LHS = SparseMatrix( system_size, system_size ); + RHS = Matrix::Zero( system_size ); + MASS = SparseMatrix( system_size, system_size ); + + classify_cells(msh); + } + + void scatter_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + } + } + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_bc_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs) + { + auto fcs = faces(msh, cl); + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( !asm_map[j].assemble() ) + RHS(int(asm_map[i])) -= lhs(i,j) * dirichlet_data(j); + } + } + + } + + void scatter_rhs_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& rhs) + { + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == rhs.rows()); + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_mass_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& mass_matrix) + { + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == mass_matrix.rows() && asm_map.size() == mass_matrix.cols() ); + + for (size_t i = 0; i < mass_matrix.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < mass_matrix.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_mass_triplets.push_back( Triplet(asm_map[i], asm_map[j], mass_matrix(i,j)) ); + } + } + } + + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ + + LHS.setZero(); + RHS.setZero(); + size_t cell_ind = 0; + for (auto& cell : msh) + { + Matrix mixed_operator_loc = mixed_operator(cell_ind,msh,cell); + Matrix f_loc = mixed_rhs(msh, cell, rhs_fun); + scatter_data(msh, cell, mixed_operator_loc, f_loc); + cell_ind++; + } + finalize(); + } + + void apply_bc(const Mesh& msh){ + + #ifdef HAVE_INTEL_TBB + size_t n_cells = m_elements_with_bc_eges.size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh] (size_t & i){ + size_t cell_ind = m_elements_with_bc_eges[i]; + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix mixed_operator_loc = mixed_operator(cell_ind, msh, cell); + scatter_bc_data(msh, cell, mixed_operator_loc); + } + ); + #else + auto storage = msh.backend_storage(); + for (auto& cell_ind : m_elements_with_bc_eges) + { + auto& cell = storage->surfaces[cell_ind]; + Matrix mixed_operator_loc = mixed_operator(cell_ind, msh, cell); + scatter_bc_data(msh, cell, mixed_operator_loc); + } + #endif + + } + + void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ + + RHS.setZero(); + + #ifdef HAVE_INTEL_TBB + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh,&rhs_fun] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix f_loc = this->mixed_rhs(msh, cell, rhs_fun); + this->scatter_rhs_data(msh, cell, f_loc); + } + ); + #else + auto contribute = [this,&msh,&rhs_fun] (const typename Mesh::cell_type& cell){ + Matrix f_loc = this->mixed_rhs(msh, cell, rhs_fun); + this->scatter_rhs_data(msh, cell, f_loc); + }; + + for (auto& cell : msh){ + contribute(cell); + } + #endif + apply_bc(msh); + } + + void assemble_mass(const Mesh& msh, bool add_vector_mass_Q = true){ + + MASS.setZero(); + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix mass_matrix = mass_operator(cell_ind, msh, cell, add_vector_mass_Q); + scatter_mass_data(msh, cell, mass_matrix); + } + finalize_mass(); + } + + Matrix mixed_operator(size_t & cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell){ + + elastic_material_data & material = m_material[cell_ind]; + T rho = material.rho(); + T vs = material.vs(); + + auto reconstruction_operator = strain_tensor_reconstruction(msh, cell); + Matrix R_operator = reconstruction_operator.second; + auto n_rows = R_operator.rows(); + auto n_cols = R_operator.cols(); + + // Weak hydrostatic component + auto divergence_operator = div_vector_reconstruction(msh, cell); + Matrix D_operator = divergence_operator.second; + + Matrix S_operator = Matrix::Zero(n_rows, n_cols); + if(m_hho_stabilization_Q) + { + auto rec_for_stab = make_vector_hho_symmetric_laplacian(msh, cell, m_hho_di); + auto stabilization_operator = make_vector_hho_stabilization(msh, cell, rec_for_stab.first, m_hho_di, m_scaled_stabilization_Q); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + }else{ + auto stabilization_operator = make_vector_hdg_stabilization(msh, cell, m_hho_di, m_scaled_stabilization_Q); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + } + + return R_operator + D_operator + (rho*vs)*S_operator; + } + + Matrix + symmetric_tensor_mass_matrix(const Mesh& msh, const typename Mesh::cell_type& cell) + { + + size_t dim = Mesh::dimension; + auto gradeg = m_hho_di.grad_degree(); + auto ten_b = make_sym_matrix_monomial_basis(msh, cell, gradeg); + auto ten_bs = disk::sym_matrix_basis_size(gradeg, dim, dim); + Matrix mass_matrix = Matrix::Zero(ten_bs, ten_bs); + + auto qps = integrate(msh, cell, 2 * gradeg); + + // number of tensor components + size_t dec = 0; + if (dim == 3) + dec = 6; + else if (dim == 2) + dec = 3; + else + std::logic_error("Expected 3 >= dim > 1"); + + for (auto& qp : qps) + { + auto phi = ten_b.eval_functions(qp.point()); + + for (size_t j = 0; j < ten_bs; j++) + { + + auto qp_phi_j = disk::priv::inner_product(qp.weight(), phi[j]); + for (size_t i = j; i < ten_bs; i += dec){ + mass_matrix(i, j) += disk::priv::inner_product(phi[i], qp_phi_j); + } + } + } + + for (size_t j = 0; j < ten_bs; j++){ + for (size_t i = 0; i < j; i++){ + mass_matrix(i, j) = mass_matrix(j, i); + } + } + + return mass_matrix; + } + + Matrix mass_operator(size_t & cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell, bool add_vector_mass_Q = true){ + + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + + elastic_material_data & material = m_material[cell_ind]; + T rho = material.rho(); + T vp = material.vp(); + T vs = material.vs(); + T mu = rho * vs * vs; + T lamda = rho * vp * vp - 2*mu; + + Matrix mass_matrix = Matrix::Zero(n_cbs, n_cbs); + + // Symmetric tensor mass block + Matrix mass_matrix_sigma = symmetric_tensor_mass_matrix(msh, cell); + mass_matrix_sigma *= (1.0/(2.0*mu)); + mass_matrix.block(0, 0, n_ten_cbs, n_ten_cbs) = mass_matrix_sigma; + + // scalar hydrostatic component mass mass block + auto scal_basis = make_scalar_monomial_basis(msh, cell, m_hho_di.face_degree()); + Matrix mass_matrix_sigma_v = make_mass_matrix(msh, cell, scal_basis); + mass_matrix_sigma_v *= (1.0/(lamda)); + mass_matrix.block(n_ten_cbs, n_ten_cbs, n_sca_cbs, n_sca_cbs) = mass_matrix_sigma_v; + + if (add_vector_mass_Q) { + // vector velocity mass mass block + auto vec_basis = disk::make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix mass_matrix_v = disk::make_mass_matrix(msh, cell, vec_basis); + mass_matrix_v *= rho; + mass_matrix.block(n_ten_cbs+n_sca_cbs, n_ten_cbs+n_sca_cbs, n_vec_cbs, n_vec_cbs) = mass_matrix_v; + } + + return mass_matrix; + } + + void classify_cells(const Mesh& msh){ + + m_elements_with_bc_eges.clear(); + size_t cell_ind = 0; + for (auto& cell : msh) + { + auto face_list = faces(msh, cell); + for (size_t face_i = 0; face_i < face_list.size(); face_i++) + { + auto fc = face_list[face_i]; + auto fc_id = msh.lookup(fc); + bool is_dirichlet_Q = m_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + m_elements_with_bc_eges.push_back(cell_ind); + break; + } + } + cell_ind++; + } + } + + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> ten_fun){ + size_t n_dof = MASS.rows(); + x_glob = Matrix::Zero(n_dof); + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + for (auto& cell : msh) + { + Matrix x_proj_ten_dof = project_ten_function(msh, cell, ten_fun); + Matrix x_proj_sca_dof = project_hydrostatic_function(msh, cell, ten_fun); + Matrix x_proj_vec_dof = project_function(msh, cell, m_hho_di.cell_degree(), vec_fun); + + Matrix x_proj_dof = Matrix::Zero(n_cbs); + x_proj_dof.block(0, 0, n_ten_cbs, 1) = x_proj_ten_dof; + x_proj_dof.block(n_ten_cbs, 0, n_sca_cbs, 1) = x_proj_sca_dof; + x_proj_dof.block(n_ten_cbs+n_sca_cbs, 0, n_vec_cbs, 1) = x_proj_vec_dof; + scatter_cell_dof_data(msh, cell, x_glob, x_proj_dof); + } + } + + Matrix project_ten_function(const Mesh& msh, const typename Mesh::cell_type& cell, + std::function(const typename Mesh::point_type& )> ten_fun){ + + Matrix mass_matrix = symmetric_tensor_mass_matrix(msh, cell); + size_t dim = Mesh::dimension; + auto gradeg = m_hho_di.grad_degree(); + auto ten_bs = disk::sym_matrix_basis_size(gradeg, dim, dim); + auto ten_b = make_sym_matrix_monomial_basis(msh, cell, gradeg); + Matrix rhs = Matrix::Zero(ten_bs); + + const auto qps = integrate(msh, cell, 2 * gradeg); + for (auto& qp : qps) + { + auto phi = ten_b.eval_functions(qp.point()); + static_matrix sigma = ten_fun(qp.point()); + T trace = 0.0; + for (size_t d = 0; d < dim; d++){ + trace += sigma(d,d); + } + static_matrix sigma_s = sigma - (trace)*static_matrix::Identity(); + for (size_t i = 0; i < ten_bs; i++){ + auto qp_phi_i = disk::priv::inner_product(qp.weight(), phi[i]); + rhs(i,0) += disk::priv::inner_product(qp_phi_i,sigma_s); + } + } + Matrix x_dof = mass_matrix.llt().solve(rhs); + return x_dof; + } + + Matrix project_hydrostatic_function(const Mesh& msh, const typename Mesh::cell_type& cell, + std::function(const typename Mesh::point_type& )> ten_fun){ + + size_t dim = Mesh::dimension; + auto facedeg = m_hho_di.face_degree(); + size_t sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), dim); + auto sca_basis = make_scalar_monomial_basis(msh, cell, facedeg); + Matrix mass_matrix = make_mass_matrix(msh, cell, sca_basis); + + Matrix rhs = Matrix::Zero(sca_cbs); + const auto qps = integrate(msh, cell, (2*facedeg+1)); + for (auto& qp : qps) + { + auto phi = sca_basis.eval_functions(qp.point()); + static_matrix sigma = ten_fun(qp.point()); + T trace = 0.0; + for (size_t d = 0; d < dim; d++){ + trace += sigma(d,d); + } + trace *= qp.weight(); + for (size_t i = 0; i < sca_cbs; i++){ + rhs(i,0) += disk::priv::inner_product(phi[i], trace);; + } + } + Matrix x_dof = mass_matrix.llt().solve(rhs); + return x_dof; + } + + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun){ + + for (auto& cell : msh) + { + auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + auto face = fcs[i]; + auto fc_id = msh.lookup(face); + bool is_dirichlet_Q = m_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + continue; + } + Matrix x_proj_dof = project_function(msh, face, m_hho_di.face_degree(), vec_fun); + scatter_face_dof_data(msh, face, x_glob, x_proj_dof); + } + } + } + + void finalize(void) + { + LHS.setFromTriplets( m_triplets.begin(), m_triplets.end() ); + m_triplets.clear(); + } + + void finalize_mass(void) + { + MASS.setFromTriplets( m_mass_triplets.begin(), m_mass_triplets.end() ); + m_mass_triplets.clear(); + } + + Matrix + gather_dof_data( const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& x_glob) const + { + auto num_faces = howmany_faces(msh, cl); + auto cell_ofs = disk::priv::offset(msh, cl); + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + size_t n_dof = n_cbs + num_faces * n_fbs; + + Matrix x_el(n_dof); + x_el.block(0, 0, n_cbs, 1) = x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) + { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_bnd.is_dirichlet_face( face_id)) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(face_id); + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + x_el.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else + { + auto face_ofs = disk::priv::offset(msh, fc); + auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; + x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); + } + } + return x_el; + } + + void scatter_cell_dof_data( const Mesh& msh, const typename Mesh::cell_type& cell, + Matrix& x_glob, Matrix & x_proj_dof) const + { + auto cell_ofs = disk::priv::offset(msh, cell); + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1) = x_proj_dof; + } + + void scatter_face_dof_data( const Mesh& msh, const typename Mesh::face_type& face, + Matrix& x_glob, Matrix & x_proj_dof) const + { + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + size_t n_cells = msh.cells_size(); + auto face_offset = disk::priv::offset(msh, face); + auto glob_offset = n_cbs * n_cells + m_compress_indexes.at(face_offset)*n_fbs; + x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; + } + + std::pair< Matrix, + Matrix > + strain_tensor_reconstruction(const Mesh& msh, const typename Mesh::cell_type& cell) + { + + using T = typename Mesh::coordinate_type; + typedef Matrix matrix_type; + + const size_t N = Mesh::dimension; + + auto graddeg = m_hho_di.grad_degree(); + auto celdeg = m_hho_di.cell_degree(); + auto facdeg = m_hho_di.face_degree(); + + auto ten_b = make_sym_matrix_monomial_basis(msh, cell, graddeg); + auto vec_b = make_vector_monomial_basis(msh, cell, celdeg); + + auto ten_bs = disk::sym_matrix_basis_size(graddeg, Mesh::dimension, Mesh::dimension); + auto sca_bs = disk::scalar_basis_size(facdeg, Mesh::dimension); + auto vec_bs = disk::vector_basis_size(celdeg, Mesh::dimension, Mesh::dimension); + auto fbs = disk::vector_basis_size(facdeg, Mesh::dimension - 1, Mesh::dimension); + + auto num_faces = howmany_faces(msh, cell); + + matrix_type gr_lhs = matrix_type::Zero(ten_bs, ten_bs); + matrix_type gr_rhs = matrix_type::Zero(ten_bs, vec_bs + num_faces * fbs); + + const auto qps = integrate(msh, cell, 2 * graddeg); + + size_t dec = 0; + if (N == 3) + dec = 6; + else if (N == 2) + dec = 3; + else + std::logic_error("Expected 3 >= dim > 1"); + + for (auto& qp : qps) + { + const auto gphi = ten_b.eval_functions(qp.point()); + + for (size_t j = 0; j < ten_bs; j++) + { + + auto qp_gphi_j = disk::priv::inner_product(qp.weight(), gphi[j]); + for (size_t i = j; i < ten_bs; i += dec){ + gr_lhs(i, j) += disk::priv::inner_product(gphi[i], qp_gphi_j); + } + } + } + + for (size_t j = 0; j < ten_bs; j++) + for (size_t i = 0; i < j; i++) + gr_lhs(i, j) = gr_lhs(j, i); + + if (celdeg > 0) + { + const auto qpc = integrate(msh, cell, graddeg + celdeg - 1); + for (auto& qp : qpc) + { + const auto gphi = ten_b.eval_functions(qp.point()); + const auto dphi = vec_b.eval_sgradients(qp.point()); + const auto qp_dphi = disk::priv::inner_product(qp.weight(), dphi); + + gr_rhs.block(0, 0, ten_bs, vec_bs) += disk::priv::outer_product(gphi, qp_dphi); + + } + } + + const auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + const auto fc = fcs[i]; + const auto n = normal(msh, cell, fc); + const auto fb = make_vector_monomial_basis(msh, fc, facdeg); + + const auto qps_f = integrate(msh, fc, graddeg + std::max(celdeg, facdeg)); + for (auto& qp : qps_f) + { + const auto gphi = ten_b.eval_functions(qp.point()); + const auto cphi = vec_b.eval_functions(qp.point()); + const auto fphi = fb.eval_functions(qp.point()); + + const auto qp_gphi_n = disk::priv::inner_product(gphi, disk::priv::inner_product(qp.weight(), n)); + gr_rhs.block(0, vec_bs + i * fbs, ten_bs, fbs) += disk::priv::outer_product(qp_gphi_n, fphi); + gr_rhs.block(0, 0, ten_bs, vec_bs) -= disk::priv::outer_product(qp_gphi_n, cphi); + } + } + + auto n_rows = gr_rhs.cols() + ten_bs + sca_bs; + auto n_cols = gr_rhs.cols() + ten_bs + sca_bs; + + // Shrinking data + matrix_type data_mixed = matrix_type::Zero(n_rows,n_cols); + data_mixed.block(0, (ten_bs + sca_bs), ten_bs, n_cols-(ten_bs + sca_bs)) = -gr_rhs; + data_mixed.block((ten_bs + sca_bs), 0, n_rows-(ten_bs + sca_bs), ten_bs) = gr_rhs.transpose(); + + matrix_type oper = gr_lhs.llt().solve(gr_rhs); + return std::make_pair(oper, data_mixed); + } + + std::pair< Matrix, + Matrix > + div_vector_reconstruction(const Mesh& msh, const typename Mesh::cell_type& cell) + { + using T = typename Mesh::coordinate_type; + typedef Matrix matrix_type; + + auto graddeg = m_hho_di.grad_degree(); + auto facedeg = m_hho_di.face_degree(); + auto ten_bs = disk::sym_matrix_basis_size(graddeg, Mesh::dimension, Mesh::dimension); + auto sca_bs = disk::scalar_basis_size(facedeg, Mesh::dimension); + + auto cbas_s = make_scalar_monomial_basis(msh, cell, m_hho_di.face_degree()); + auto dr_lhs = make_mass_matrix(msh, cell, cbas_s); + auto dr_rhs = make_hho_divergence_reconstruction_rhs(msh, cell, m_hho_di); + + assert( dr_lhs.rows() == sca_bs && dr_lhs.cols() == sca_bs ); + + // Shrinking data + auto n_rows = dr_rhs.cols() + ten_bs + sca_bs; + auto n_cols = dr_rhs.cols() + ten_bs + sca_bs; + matrix_type data_mixed = matrix_type::Zero(n_rows,n_cols); + data_mixed.block(ten_bs, (ten_bs + sca_bs), sca_bs, n_cols-(ten_bs + sca_bs)) = -dr_rhs; + data_mixed.block((ten_bs + sca_bs), ten_bs, n_rows-(ten_bs + sca_bs), sca_bs) = dr_rhs.transpose(); + + matrix_type oper = dr_lhs.ldlt().solve(dr_rhs); + return std::make_pair(oper, data_mixed); + } + + Matrix + mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> & rhs_fun, size_t di = 0) + { + auto recdeg = m_hho_di.grad_degree(); + auto celdeg = m_hho_di.cell_degree(); + auto facdeg = m_hho_di.face_degree(); + + auto ten_bs = disk::sym_matrix_basis_size(recdeg, Mesh::dimension, Mesh::dimension); + auto sca_bs = disk::scalar_basis_size(facdeg, Mesh::dimension); + auto vec_bs = disk::vector_basis_size(celdeg, Mesh::dimension, Mesh::dimension); + size_t n_cbs = ten_bs + sca_bs + vec_bs; + auto cell_basis = make_vector_monomial_basis(msh, cell, celdeg); + using T = typename Mesh::coordinate_type; + + Matrix ret_loc = Matrix::Zero(cell_basis.size()); + Matrix ret = Matrix::Zero(n_cbs); + + const auto qps = integrate(msh, cell, 2 * (celdeg + di)); + + for (auto& qp : qps) + { + const auto phi = cell_basis.eval_functions(qp.point()); + const auto qp_f = disk::priv::inner_product(qp.weight(), rhs_fun(qp.point())); + ret_loc += disk::priv::outer_product(phi, qp_f); + } + ret.block(ten_bs + sca_bs,0,vec_bs,1) = ret_loc; + return ret; + } + + void load_material_data(const Mesh& msh, elastic_material_data material){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + m_material.push_back(material); + } + } + + void load_material_data(const Mesh& msh, std::function(const typename Mesh::point_type& )> elastic_mat_fun){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + for (auto& cell : msh) + { + auto bar = barycenter(msh, cell); + std::vector mat_data = elastic_mat_fun(bar); + T rho = mat_data[0]; + T vp = mat_data[1]; + T vs = mat_data[2]; + elastic_material_data material(rho,vp,vs); + m_material.push_back(material); + } + } + + void load_material_data(const Mesh& msh){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + T rho = 1.0; + T vp = sqrt(3.0); + T vs = 1.0; + elastic_material_data material(rho,vp,vs); + size_t cell_i = 0; + for (auto& cell : msh) + { + m_material.push_back(material); + cell_i++; + } + } + + void set_hdg_stabilization(){ + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) + { + m_hho_stabilization_Q = false; + std::cout << "Proceeding with HDG stabilization cell degree is higher than face degree." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + }else{ + std::cout << "Proceeding with HHO stabilization cell and face degree are equal." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + } + } + + void set_hho_stabilization(){ + m_hho_stabilization_Q = true; + } + + void set_scaled_stabilization(){ + m_scaled_stabilization_Q = true; + } + + boundary_type & get_bc_conditions(){ + return m_bnd; + } + + std::vector< elastic_material_data > & get_material_data(){ + return m_material; + } + + size_t get_n_face_dof(){ + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + size_t n_face_dof = (m_n_edges - m_n_essential_edges) * n_fbs; + return n_face_dof; + } + + size_t get_n_faces(){ + return m_n_edges - m_n_essential_edges; + } + + size_t get_face_basis_data(){ + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + return n_fbs; + } + + size_t get_cell_basis_data(){ + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; + return n_cbs; + } +}; + +#endif /* elastodynamic_three_fields_assembler_hpp */ diff --git a/apps/wave_propagation/src/common/elastodynamic_two_fields_assembler.hpp b/apps/wave_propagation/src/common/elastodynamic_two_fields_assembler.hpp new file mode 100644 index 00000000..45d21099 --- /dev/null +++ b/apps/wave_propagation/src/common/elastodynamic_two_fields_assembler.hpp @@ -0,0 +1,879 @@ +// +// elastodynamic_two_fields_assembler.hpp +// elastodynamics +// +// Created by Omar Durán on 4/25/20. +// + +#pragma once +#ifndef elastodynamic_two_fields_assembler_hpp +#define elastodynamic_two_fields_assembler_hpp + +#include "diskpp/bases/bases.hpp" +#include "diskpp/methods/hho" +#include "../common/assembly_index.hpp" +#include "../common/elastic_material_data.hpp" + +#ifdef HAVE_INTEL_TBB +#include +#endif + +template +class elastodynamic_two_fields_assembler +{ + + + typedef disk::BoundaryConditions boundary_type; + using T = typename Mesh::coordinate_type; + + std::vector m_compress_indexes; + std::vector m_expand_indexes; + + disk::hho_degree_info m_hho_di; + boundary_type m_bnd; + std::vector< Triplet > m_triplets; + std::vector< Triplet > m_mass_triplets; + std::vector< elastic_material_data > m_material; + std::vector< size_t > m_elements_with_bc_eges; + + size_t m_n_edges; + size_t m_n_essential_edges; + bool m_hho_stabilization_Q; + bool m_scaled_stabilization_Q; + +public: + + SparseMatrix LHS; + Matrix RHS; + SparseMatrix MASS; + + elastodynamic_two_fields_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const boundary_type& bnd) + : m_hho_di(hho_di), m_bnd(bnd), m_hho_stabilization_Q(true), m_scaled_stabilization_Q(false) + { + + auto is_dirichlet = [&](const typename Mesh::face& fc) -> bool { + + auto fc_id = msh.lookup(fc); + return bnd.is_dirichlet_face(fc_id); + }; + + m_n_edges = msh.faces_size(); + m_n_essential_edges = std::count_if(msh.faces_begin(), msh.faces_end(), is_dirichlet); + + m_compress_indexes.resize( m_n_edges ); + m_expand_indexes.resize( m_n_edges - m_n_essential_edges ); + + size_t compressed_offset = 0; + for (size_t i = 0; i < m_n_edges; i++) + { + auto fc = *std::next(msh.faces_begin(), i); + if ( !is_dirichlet(fc) ) + { + m_compress_indexes.at(i) = compressed_offset; + m_expand_indexes.at(compressed_offset) = i; + compressed_offset++; + } + } + + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + + size_t system_size = n_cbs * msh.cells_size() + n_fbs * (m_n_edges - m_n_essential_edges); + + LHS = SparseMatrix( system_size, system_size ); + RHS = Matrix::Zero( system_size ); + MASS = SparseMatrix( system_size, system_size ); + + classify_cells(msh); + } + + void scatter_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs, + const Matrix& rhs) + { + auto fcs = faces(msh, cl); + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + } + } + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_bc_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& lhs) + { + auto fcs = faces(msh, cl); + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + std::vector asm_map; + asm_map.reserve(n_cbs + n_fbs*fcs.size()); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); + for (size_t face_i = 0; face_i < fcs.size(); face_i++) + { + auto fc = fcs[face_i]; + auto face_offset = disk::priv::offset(msh, fc); + auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; + + auto fc_id = msh.lookup(fc); + bool dirichlet = m_bnd.is_dirichlet_face(fc_id); + + for (size_t i = 0; i < n_fbs; i++) + asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + + if (dirichlet) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(fc_id); + + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + + } + + assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + + for (size_t i = 0; i < lhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < lhs.cols(); j++) + { + if ( !asm_map[j].assemble() ) + RHS(int(asm_map[i])) -= lhs(i,j) * dirichlet_data(j); + } + } + + } + + void scatter_rhs_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& rhs) + { + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == rhs.rows()); + + for (size_t i = 0; i < rhs.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + RHS(int(asm_map[i])) += rhs(i); + } + + } + + void scatter_mass_data(const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& mass_matrix) + { + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + std::vector asm_map; + asm_map.reserve(n_cbs); + + auto cell_offset = disk::priv::offset(msh, cl); + auto cell_LHS_offset = cell_offset * n_cbs; + + for (size_t i = 0; i < n_cbs; i++) + asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + + assert( asm_map.size() == mass_matrix.rows() && asm_map.size() == mass_matrix.cols() ); + + for (size_t i = 0; i < mass_matrix.rows(); i++) + { + if (!asm_map[i].assemble()) + continue; + + for (size_t j = 0; j < mass_matrix.cols(); j++) + { + if ( asm_map[j].assemble() ) + m_mass_triplets.push_back( Triplet(asm_map[i], asm_map[j], mass_matrix(i,j)) ); + } + } + } + + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ + + LHS.setZero(); + RHS.setZero(); + size_t cell_ind = 0; + for (auto& cell : msh) + { + Matrix mixed_operator_loc = mixed_operator(cell_ind,msh,cell); + Matrix f_loc = mixed_rhs(msh, cell, rhs_fun); + scatter_data(msh, cell, mixed_operator_loc, f_loc); + cell_ind++; + } + finalize(); + } + + void apply_bc(const Mesh& msh){ + + #ifdef HAVE_INTEL_TBB + size_t n_cells = m_elements_with_bc_eges.size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh] (size_t & i){ + size_t cell_ind = m_elements_with_bc_eges[i]; + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix mixed_operator_loc = mixed_operator(cell_ind, msh, cell); + scatter_bc_data(msh, cell, mixed_operator_loc); + } + ); + #else + auto storage = msh.backend_storage(); + for (auto& cell_ind : m_elements_with_bc_eges) + { + auto& cell = storage->surfaces[cell_ind]; + Matrix mixed_operator_loc = mixed_operator(cell_ind, msh, cell); + scatter_bc_data(msh, cell, mixed_operator_loc); + } + #endif + + } + + void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ + + RHS.setZero(); + + #ifdef HAVE_INTEL_TBB + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh,&rhs_fun] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix f_loc = this->mixed_rhs(msh, cell, rhs_fun); + this->scatter_rhs_data(msh, cell, f_loc); + } + ); + #else + auto contribute = [this,&msh,&rhs_fun] (const typename Mesh::cell_type& cell){ + Matrix f_loc = this->mixed_rhs(msh, cell, rhs_fun); + this->scatter_rhs_data(msh, cell, f_loc); + }; + + for (auto& cell : msh){ + contribute(cell); + } + #endif + apply_bc(msh); + } + + void assemble_mass(const Mesh& msh, bool add_vector_mass_Q = true){ + + MASS.setZero(); + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix mass_matrix = mass_operator(cell_ind, msh, cell, add_vector_mass_Q); + scatter_mass_data(msh, cell, mass_matrix); + } + finalize_mass(); + } + + Matrix mixed_operator(size_t & cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell){ + + elastic_material_data & material = m_material[cell_ind]; + T rho = material.rho(); + T vp = material.vp(); + T vs = material.vs(); + T mu = rho * vs * vs; + T lambda = rho * vp * vp - 2*mu; + + auto reconstruction_operator = strain_tensor_reconstruction(msh, cell); + Matrix R_operator = reconstruction_operator.second; + auto n_rows = R_operator.rows(); + auto n_cols = R_operator.cols(); + + Matrix S_operator = Matrix::Zero(n_rows, n_cols); + if(m_hho_stabilization_Q) + { + auto rec_for_stab = make_vector_hho_symmetric_laplacian(msh, cell, m_hho_di); + auto stabilization_operator = make_vector_hho_stabilization(msh, cell, rec_for_stab.first, m_hho_di, m_scaled_stabilization_Q); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + }else{ + auto stabilization_operator = make_vector_hdg_stabilization(msh, cell, m_hho_di, m_scaled_stabilization_Q); + auto n_s_rows = stabilization_operator.rows(); + auto n_s_cols = stabilization_operator.cols(); + S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; + } + + return R_operator + (rho*vs)*S_operator; + } + + Matrix + symmetric_tensor_mass_matrix(const Mesh& msh, const typename Mesh::cell_type& cell) + { + + size_t dim = Mesh::dimension; + auto gradeg = m_hho_di.grad_degree(); + auto ten_b = make_sym_matrix_monomial_basis(msh, cell, gradeg); + auto ten_bs = disk::sym_matrix_basis_size(gradeg, dim, dim); + Matrix mass_matrix = Matrix::Zero(ten_bs, ten_bs); + + auto qps = integrate(msh, cell, 2 * gradeg); + + // number of tensor components + size_t dec = 0; + if (dim == 3) + dec = 6; + else if (dim == 2) + dec = 3; + else + std::logic_error("Expected 3 >= dim > 1"); + + for (auto& qp : qps) + { + auto phi = ten_b.eval_functions(qp.point()); + + for (size_t j = 0; j < ten_bs; j++) + { + + auto qp_phi_j = disk::priv::inner_product(qp.weight(), phi[j]); + for (size_t i = j; i < ten_bs; i += dec){ + mass_matrix(i, j) += disk::priv::inner_product(phi[i], qp_phi_j); + } + } + } + + for (size_t j = 0; j < ten_bs; j++){ + for (size_t i = 0; i < j; i++){ + mass_matrix(i, j) = mass_matrix(j, i); + } + } + + return mass_matrix; + } + + Matrix + symmetric_tensor_trace_mass_matrix(const Mesh& msh, const typename Mesh::cell_type& cell) + { + + size_t dim = Mesh::dimension; + auto gradeg = m_hho_di.grad_degree(); + auto ten_b = make_sym_matrix_monomial_basis(msh, cell, gradeg); + auto ten_bs = disk::sym_matrix_basis_size(gradeg, dim, dim); + Matrix mass_matrix = Matrix::Zero(ten_bs, ten_bs); + + auto qps = integrate(msh, cell, 2 * gradeg); + + // number of tensor components + size_t dec = 0; + if (dim == 3) + dec = 6; + else if (dim == 2) + dec = 3; + else + std::logic_error("Expected 3 >= dim > 1"); + + for (auto& qp : qps) + { + auto phi = ten_b.eval_functions(qp.point()); + + for (size_t j = 0; j < ten_bs; j++) + { + auto identity = phi[j]; + identity.setZero(); + for(size_t d = 0; d < dim; d++){ + identity(d,d) = 1.0; + } + auto trace = phi[j].trace(); + auto trace_phi_j = disk::priv::inner_product(phi[j].trace(), identity); + auto qp_phi_j = disk::priv::inner_product(qp.weight(), trace_phi_j); + for (size_t i = 0; i < ten_bs; i ++){ + mass_matrix(i, j) += disk::priv::inner_product(phi[i], qp_phi_j); + } + } + } + + return mass_matrix; + } + + Matrix mass_operator(size_t & cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell, bool add_vector_mass_Q = true){ + + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + + elastic_material_data & material = m_material[cell_ind]; + T rho = material.rho(); + T vp = material.vp(); + T vs = material.vs(); + T mu = rho * vs * vs; + T lambda = rho * vp * vp - 2*mu; + + Matrix mass_matrix = Matrix::Zero(n_cbs, n_cbs); + + // Symmetric stress tensor mass block + + // Stress tensor + Matrix mass_matrix_sigma = symmetric_tensor_mass_matrix(msh, cell); + + // Tensor trace + Matrix mass_matrix_trace_sigma = symmetric_tensor_trace_mass_matrix(msh, cell); + + // Constitutive relationship inverse + mass_matrix_trace_sigma *= (lambda/(2.0*mu+2.0*lambda)); + mass_matrix_sigma -= mass_matrix_trace_sigma; + mass_matrix_sigma *= (1.0/(2.0*mu)); + mass_matrix.block(0, 0, n_ten_cbs, n_ten_cbs) = mass_matrix_sigma; + + if (add_vector_mass_Q) { + // vector velocity mass mass block + auto vec_basis = disk::make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); + Matrix mass_matrix_v = disk::make_mass_matrix(msh, cell, vec_basis); + mass_matrix_v *= rho; + mass_matrix.block(n_ten_cbs, n_ten_cbs, n_vec_cbs, n_vec_cbs) = mass_matrix_v; + } + + return mass_matrix; + } + + void classify_cells(const Mesh& msh){ + + m_elements_with_bc_eges.clear(); + size_t cell_ind = 0; + for (auto& cell : msh) + { + auto face_list = faces(msh, cell); + for (size_t face_i = 0; face_i < face_list.size(); face_i++) + { + auto fc = face_list[face_i]; + auto fc_id = msh.lookup(fc); + bool is_dirichlet_Q = m_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + m_elements_with_bc_eges.push_back(cell_ind); + break; + } + } + cell_ind++; + } + } + + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> ten_fun){ + size_t n_dof = MASS.rows(); + x_glob = Matrix::Zero(n_dof); + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + for (auto& cell : msh) + { + Matrix x_proj_ten_dof = project_ten_function(msh, cell, ten_fun); + Matrix x_proj_vec_dof = project_function(msh, cell, m_hho_di.cell_degree(), vec_fun); + + Matrix x_proj_dof = Matrix::Zero(n_cbs); + x_proj_dof.block(0, 0, n_ten_cbs, 1) = x_proj_ten_dof; + x_proj_dof.block(n_ten_cbs, 0, n_vec_cbs, 1) = x_proj_vec_dof; + scatter_cell_dof_data(msh, cell, x_glob, x_proj_dof); + } + } + + Matrix project_ten_function(const Mesh& msh, const typename Mesh::cell_type& cell, + std::function(const typename Mesh::point_type& )> ten_fun){ + + Matrix mass_matrix = symmetric_tensor_mass_matrix(msh, cell); + size_t dim = Mesh::dimension; + auto gradeg = m_hho_di.grad_degree(); + auto ten_bs = disk::sym_matrix_basis_size(gradeg, dim, dim); + auto ten_b = make_sym_matrix_monomial_basis(msh, cell, gradeg); + Matrix rhs = Matrix::Zero(ten_bs); + + const auto qps = integrate(msh, cell, 2 * gradeg); + for (auto& qp : qps) + { + auto phi = ten_b.eval_functions(qp.point()); + static_matrix sigma = ten_fun(qp.point()); + for (size_t i = 0; i < ten_bs; i++){ + auto qp_phi_i = disk::priv::inner_product(qp.weight(), phi[i]); + rhs(i,0) += disk::priv::inner_product(qp_phi_i,sigma); + } + } + Matrix x_dof = mass_matrix.llt().solve(rhs); + return x_dof; + } + + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun){ + + for (auto& cell : msh) + { + auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) + { + auto face = fcs[i]; + auto fc_id = msh.lookup(face); + bool is_dirichlet_Q = m_bnd.is_dirichlet_face(fc_id); + if (is_dirichlet_Q) + { + continue; + } + Matrix x_proj_dof = project_function(msh, face, m_hho_di.face_degree(), vec_fun); + scatter_face_dof_data(msh, face, x_glob, x_proj_dof); + } + } + } + + void finalize(void) + { + LHS.setFromTriplets( m_triplets.begin(), m_triplets.end() ); + m_triplets.clear(); + } + + void finalize_mass(void) + { + MASS.setFromTriplets( m_mass_triplets.begin(), m_mass_triplets.end() ); + m_mass_triplets.clear(); + } + + Matrix + gather_dof_data( const Mesh& msh, const typename Mesh::cell_type& cl, + const Matrix& x_glob) const + { + auto num_faces = howmany_faces(msh, cl); + auto cell_ofs = disk::priv::offset(msh, cl); + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + size_t n_dof = n_cbs + num_faces * n_fbs; + + Matrix x_el(n_dof); + x_el.block(0, 0, n_cbs, 1) = x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1); + auto fcs = faces(msh, cl); + for (size_t i = 0; i < fcs.size(); i++) + { + auto fc = fcs[i]; + auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); + if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + const auto face_id = eid.second; + + if (m_bnd.is_dirichlet_face( face_id)) + { + auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); + auto dirichlet_fun = m_bnd.dirichlet_boundary_func(face_id); + Matrix mass = make_mass_matrix(msh, fc, fb); + Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); + x_el.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); + } + else + { + auto face_ofs = disk::priv::offset(msh, fc); + auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; + x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); + } + } + return x_el; + } + + void scatter_cell_dof_data( const Mesh& msh, const typename Mesh::cell_type& cell, + Matrix& x_glob, Matrix & x_proj_dof) const + { + auto cell_ofs = disk::priv::offset(msh, cell); + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1) = x_proj_dof; + } + + void scatter_face_dof_data( const Mesh& msh, const typename Mesh::face_type& face, + Matrix& x_glob, Matrix & x_proj_dof) const + { + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + size_t n_cells = msh.cells_size(); + auto face_offset = disk::priv::offset(msh, face); + auto glob_offset = n_cbs * n_cells + m_compress_indexes.at(face_offset)*n_fbs; + x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; + } + + std::pair< Matrix, + Matrix > + strain_tensor_reconstruction(const Mesh& msh, const typename Mesh::cell_type& cell) { + + using T = typename Mesh::coordinate_type; + typedef Matrix matrix_type; + + const size_t N = Mesh::dimension; + + auto graddeg = m_hho_di.grad_degree(); + auto celdeg = m_hho_di.cell_degree(); + auto facdeg = m_hho_di.face_degree(); + + auto ten_b = make_sym_matrix_monomial_basis(msh, cell, graddeg); + auto vec_b = make_vector_monomial_basis(msh, cell, celdeg); + + auto ten_bs = disk::sym_matrix_basis_size(graddeg, Mesh::dimension, Mesh::dimension); + auto vec_bs = disk::vector_basis_size(celdeg, Mesh::dimension, Mesh::dimension); + auto fbs = disk::vector_basis_size(facdeg, Mesh::dimension - 1, Mesh::dimension); + + auto num_faces = howmany_faces(msh, cell); + + matrix_type gr_lhs = matrix_type::Zero(ten_bs, ten_bs); + matrix_type gr_rhs = matrix_type::Zero(ten_bs, vec_bs + num_faces * fbs); + + const auto qps = integrate(msh, cell, 2 * graddeg); + + size_t dec = 0; + if (N == 3) + dec = 6; + else if (N == 2) + dec = 3; + else + std::logic_error("Expected 3 >= dim > 1"); + + for (auto& qp : qps) { + const auto gphi = ten_b.eval_functions(qp.point()); + for (size_t j = 0; j < ten_bs; j++) { + auto qp_gphi_j = disk::priv::inner_product(qp.weight(), gphi[j]); + for (size_t i = j; i < ten_bs; i += dec){ + gr_lhs(i, j) += disk::priv::inner_product(gphi[i], qp_gphi_j); + } + } + } + + for (size_t j = 0; j < ten_bs; j++) + for (size_t i = 0; i < j; i++) + gr_lhs(i, j) = gr_lhs(j, i); + if (celdeg > 0) { + const auto qpc = integrate(msh, cell, graddeg + celdeg - 1); + for (auto& qp : qpc) { + const auto gphi = ten_b.eval_functions(qp.point()); + const auto dphi = vec_b.eval_sgradients(qp.point()); + const auto qp_dphi = disk::priv::inner_product(qp.weight(), dphi); + gr_rhs.block(0, 0, ten_bs, vec_bs) += disk::priv::outer_product(gphi, qp_dphi); + } + } + + const auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) { + const auto fc = fcs[i]; + const auto n = normal(msh, cell, fc); + const auto fcs = faces(msh, cell); + for (size_t i = 0; i < fcs.size(); i++) { + const auto fc = fcs[i]; + const auto n = normal(msh, cell, fc); + const auto fb = make_vector_monomial_basis(msh, fc, facdeg); + const auto qps_f = integrate(msh, fc, graddeg + std::max(celdeg, facdeg)); + for (auto& qp : qps_f) { + const auto gphi = ten_b.eval_functions(qp.point()); + const auto cphi = vec_b.eval_functions(qp.point()); + const auto fphi = fb.eval_functions(qp.point()); + const auto qp_gphi_n = disk::priv::inner_product(gphi,disk::priv::inner_product(qp.weight(), n)); + gr_rhs.block(0, vec_bs + i * fbs, ten_bs, fbs) += disk::priv::outer_product(qp_gphi_n, fphi); + gr_rhs.block(0, 0, ten_bs, vec_bs) -= disk::priv::outer_product(qp_gphi_n, cphi); + } + } + const auto fb = make_vector_monomial_basis(msh, fc, facdeg); + + const auto qps_f = integrate(msh, fc, graddeg + std::max(celdeg, facdeg)); + for (auto& qp : qps_f) { + const auto gphi = ten_b.eval_functions(qp.point()); + const auto cphi = vec_b.eval_functions(qp.point()); + const auto fphi = fb.eval_functions(qp.point()); + const auto qp_gphi_n = disk::priv::inner_product(gphi, disk::priv::inner_product(qp.weight(), n)); + gr_rhs.block(0, vec_bs + i * fbs, ten_bs, fbs) += disk::priv::outer_product(qp_gphi_n, fphi); + gr_rhs.block(0, 0, ten_bs, vec_bs) -= disk::priv::outer_product(qp_gphi_n, cphi); + } + } + + auto n_rows = gr_rhs.cols() + ten_bs; + auto n_cols = gr_rhs.cols() + ten_bs; + + // Shrinking data + matrix_type data_mixed = matrix_type::Zero(n_rows,n_cols); + data_mixed.block(0, (ten_bs), ten_bs, n_cols-(ten_bs)) = -gr_rhs; + data_mixed.block((ten_bs), 0, n_rows-(ten_bs), ten_bs) = gr_rhs.transpose(); + + matrix_type oper = gr_lhs.llt().solve(gr_rhs); + return std::make_pair(oper, data_mixed); + } + + Matrix + mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> & rhs_fun, size_t di = 0) + { + auto recdeg = m_hho_di.grad_degree(); + auto celdeg = m_hho_di.cell_degree(); + auto facdeg = m_hho_di.face_degree(); + + auto ten_bs = disk::sym_matrix_basis_size(recdeg, Mesh::dimension, Mesh::dimension); + auto vec_bs = disk::vector_basis_size(celdeg, Mesh::dimension, Mesh::dimension); + size_t n_cbs = ten_bs + vec_bs; + auto cell_basis = make_vector_monomial_basis(msh, cell, celdeg); + using T = typename Mesh::coordinate_type; + + Matrix ret_loc = Matrix::Zero(cell_basis.size()); + Matrix ret = Matrix::Zero(n_cbs); + + const auto qps = integrate(msh, cell, 2 * (celdeg + di)); + + for (auto& qp : qps) + { + const auto phi = cell_basis.eval_functions(qp.point()); + const auto qp_f = disk::priv::inner_product(qp.weight(), rhs_fun(qp.point())); + ret_loc += disk::priv::outer_product(phi, qp_f); + } + ret.block(ten_bs,0,vec_bs,1) = ret_loc; + return ret; + } + + void load_material_data(const Mesh& msh, elastic_material_data material){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + m_material.push_back(material); + } + } + + void load_material_data(const Mesh& msh, std::function(const typename Mesh::point_type& )> elastic_mat_fun){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + for (auto& cell : msh) + { + auto bar = barycenter(msh, cell); + std::vector mat_data = elastic_mat_fun(bar); + T rho = mat_data[0]; + T vp = mat_data[1]; + T vs = mat_data[2]; + elastic_material_data material(rho,vp,vs); + m_material.push_back(material); + } + } + + void load_material_data(const Mesh& msh){ + m_material.clear(); + m_material.reserve(msh.cells_size()); + T rho = 1.0; + T vp = sqrt(3.0); + T vs = 1.0; + elastic_material_data material(rho,vp,vs); + size_t cell_i = 0; + for (auto& cell : msh) + { + m_material.push_back(material); + cell_i++; + } + } + + void set_hdg_stabilization(){ + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) + { + m_hho_stabilization_Q = false; + std::cout << "Proceeding with HDG stabilization cell degree is higher than face degree." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + }else{ + std::cout << "Proceeding with HHO stabilization cell and face degree are equal." << std::endl; + std::cout << "cell degree = " << m_hho_di.cell_degree() << std::endl; + std::cout << "face degree = " << m_hho_di.face_degree() << std::endl; + } + } + + void set_hho_stabilization(){ + m_hho_stabilization_Q = true; + } + + void set_scaled_stabilization(){ + m_scaled_stabilization_Q = true; + } + + boundary_type & get_bc_conditions(){ + return m_bnd; + } + + std::vector< elastic_material_data > & get_material_data(){ + return m_material; + } + + size_t get_n_face_dof(){ + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + size_t n_face_dof = (m_n_edges - m_n_essential_edges) * n_fbs; + return n_face_dof; + } + + size_t get_n_faces(){ + return m_n_edges - m_n_essential_edges; + } + + size_t get_face_basis_data(){ + size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + return n_fbs; + } + + size_t get_cell_basis_data(){ + size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t n_cbs = n_ten_cbs + n_vec_cbs; + return n_cbs; + } +}; + +#endif /* elastodynamic_two_fields_assembler_hpp */ diff --git a/apps/wave_propagation/src/common/erk_butcher_tableau.hpp b/apps/wave_propagation/src/common/erk_butcher_tableau.hpp new file mode 100644 index 00000000..699d01b4 --- /dev/null +++ b/apps/wave_propagation/src/common/erk_butcher_tableau.hpp @@ -0,0 +1,253 @@ +// +// erk_butcher_tableau.hpp +// acoustics +// +// Created by Omar Durán on 5/8/20. +// + +#pragma once +#ifndef erk_butcher_tableau_hpp +#define erk_butcher_tableau_hpp + +#include + +class erk_butcher_tableau +{ + public: + + static void erk_tables(int s, Matrix &a, Matrix &b, Matrix &c){ + + // Mathematical Aspects of Discontinuous Galerkin Methods + // Authors: Di Pietro, Daniele Antonio, Ern, Alexandre + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, 1); + c = Matrix::Zero(s, 1); + + switch (s) { + case 1: + { + a(0,0) = 0.0; + b(0,0) = 1.0; + c(0,0) = 0.0; + } + break; + case 2: + { +// a(0,0) = 0.0; +// a(1,0) = 1.0; +// a(1,1) = 0.0; +// +// b(0,0) = 0.5; +// b(1,0) = 0.5; +// +// c(0,0) = 0.0; +// c(1,0) = 1.0; + + a(0,0) = 0.0; + a(1,0) = 0.5; + a(1,1) = 0.0; + + b(0,0) = 0.0; + b(1,0) = 1.0; + + c(0,0) = 0.0; + c(1,0) = 0.5; + + } + break; + case 3: + { + +// a(0,0) = 0.0; +// a(1,0) = 1.0/3.0; +// a(1,1) = 0.0; +// a(2,0) = 0.0; +// a(2,1) = 2.0/3.0; +// a(2,2) = 0.0; +// +// b(0,0) = 1.0/4.0; +// b(1,0) = 0.0; +// b(2,0) = 3.0/4.0; +// +// c(0,0) = 0.0; +// c(1,0) = 1.0/3.0; +// c(2,0) = 2.0/3.0; + + a(0,0) = 0.0; + a(1,0) = 1.0/2.0; + a(1,1) = 0.0; + a(2,0) = -1.0; + a(2,1) = 2.0; + a(2,2) = 0.0; + + b(0,0) = 1.0/6.0; + b(1,0) = 2.0/3.0; + b(2,0) = 1.0/6.0; + + c(0,0) = 0.0; + c(1,0) = 1.0/2.0; + c(2,0) = 1.0; + + } + break; + case 4: + { + + a(0,0) = 0.0; + a(1,0) = 1.0/2.0; + a(2,0) = 0.0; + a(3,0) = 0.0; + a(1,1) = 0.0; + a(2,1) = 1.0/2.0; + a(3,1) = 0.0; + a(2,2) = 0.0; + a(3,2) = 1.0; + a(3,3) = 0.0; + + b(0,0) = 1.0/6.0; + b(1,0) = 1.0/3.0; + b(2,0) = 1.0/3.0; + b(3,0) = 1.0/6.0; + + c(0,0) = 0.0; + c(1,0) = 1.0/2.0; + c(2,0) = 1.0/2.0; + c(3,0) = 1.0; + + } + break; + default: + { + std::cout << "Error:: Method not implemented." << std::endl; + } + break; + } + + } + + static void ssprk_tables(int s, Matrix &a, Matrix &b, Matrix &c){ + + // A New Class of Optimal High-Order Strong-Stability-Preserving Time Discretization Methods + // Authors: Raymond J. Spiteri and Steven J. Ruuth + // Apendix B + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, 1); + c = Matrix::Zero(s, 1); + + switch (s) { + case 1: // Order 1 + { + a(0,0) = 0.0; + b(0,0) = 1.0; + c(0,0) = 0.0; + } + break; + case 2: // Order 1 + { + a(0,0) = 0.0; + a(1,0) = 0.5; + a(1,1) = 0.0; + + b(0,0) = 0.5; + b(1,0) = 0.5; + + c(0,0) = 0.0; + c(1,0) = 0.5; + + + } + break; + case 3: // Order 2 + { + + a(0,0) = 0.0; + a(1,0) = 0.5; + a(1,1) = 0.0; + a(2,0) = 0.5; + a(2,1) = 0.5; + a(2,2) = 0.0; + + b(0,0) = 1.0/3.0; + b(1,0) = 1.0/3.0; + b(2,0) = 1.0/3.0; + + c(0,0) = 0.0; + c(1,0) = 1.0/2.0; + c(2,0) = 1.0; + + + } + break; + case 4: // Order 3 + { + + a(0,0) = 0.0; + a(1,0) = 1.0/2.0; + a(2,0) = 1.0/2.0; + a(3,0) = 1.0/6.0; + a(1,1) = 0.0; + a(2,1) = 1.0/2.0; + a(3,1) = 1.0/6.0; + a(2,2) = 0.0; + a(3,2) = 1.0/6.0; + a(3,3) = 0.0; + + b(0,0) = 1.0/6.0; + b(1,0) = 1.0/6.0; + b(2,0) = 1.0/6.0; + b(3,0) = 1.0/2.0; + + c(0,0) = 0.0; + c(1,0) = 1.0/2.0; + c(2,0) = 1.0; + c(3,0) = 1.0/2.0; + + } + break; + case 5: // Order 4 + { + + a(0,0) = 0.0; + a(1,0) = 0.39175222700392; + a(2,0) = 0.21766909633821; + a(3,0) = 0.08269208670950; + a(4,0) = 0.06796628370320; + + a(1,1) = 0.0; + a(2,1) = 0.36841059262959; + a(3,1) = 0.13995850206999; + a(4,1) = 0.11503469844438; + + a(2,2) = 0.0; + a(3,2) = 0.2518917742473; + a(4,2) = 0.20703489864929; + + a(3,3) = 0.0; + a(4,3) = 0.54497475021237; + + b(0,0) = 0.14681187618661; + b(1,0) = 0.24848290924556; + b(2,0) = 0.10425883036650; + b(3,0) = 0.27443890091960; + b(4,0) = 0.22600748319395; + + c(0,0) = 0.0; + c(1,0) = 0.39175222700392; + c(2,0) = 0.58607968896779; + c(3,0) = 0.47454236302687; + c(4,0) = 0.93501063100924; + + } + break; + default: + { + std::cout << "Error:: Method not implemented." << std::endl; + } + break; + } + + } + +}; + +#endif /* erk_butcher_tableau_hpp */ diff --git a/apps/wave_propagation/src/common/erk_coupling_hho_scheme.hpp b/apps/wave_propagation/src/common/erk_coupling_hho_scheme.hpp new file mode 100644 index 00000000..718a843b --- /dev/null +++ b/apps/wave_propagation/src/common/erk_coupling_hho_scheme.hpp @@ -0,0 +1,476 @@ +#ifndef erk_coupling_hho_scheme_hpp +#define erk_coupling_hho_scheme_hpp + +#include +#include +#include +#include +#include "../common/assembly_index.hpp" +#include // Pour std::setw + + +template +class erk_coupling_hho_scheme +{ + private: + + SparseMatrix m_Mc; + SparseMatrix m_Kcc; + SparseMatrix m_Kcf; + SparseMatrix m_Kfc; + SparseMatrix m_Sff; + SparseMatrix m_Scc; + SparseMatrix m_Mc_inv; + SparseMatrix m_Sff_inv; + SparseMatrix m_inv_Sff; + SparseMatrix m_Cg; + + Matrix m_Fc; + + #ifdef HAVE_INTEL_MKL + PardisoLDLT> m_analysis_f; + #else + SimplicialLDLT> m_analysis_f; + #endif + + ConjugateGradient> m_analysis_cg; + + size_t m_n_ec_dof; + size_t m_n_ac_dof; + size_t m_n_c_dof; + size_t m_n_ef_dof; + size_t m_n_af_dof; + size_t m_n_f_dof; + + bool m_sff_is_block_diagonal_Q; + bool m_iterative_solver_Q; + + public: + + erk_coupling_hho_scheme(SparseMatrix & Kg, Matrix & Fg, SparseMatrix & Mg, SparseMatrix & Cg, size_t elastic_cell_dofs, size_t acoustic_cell_dofs, size_t e_face_dofs, size_t a_face_dofs){ + + m_n_ec_dof = elastic_cell_dofs; + m_n_ac_dof = acoustic_cell_dofs; + // m_n_c_dof = m_n_ec_dof + m_n_ac_dof; + m_n_ef_dof = e_face_dofs; + m_n_af_dof = a_face_dofs; + m_n_f_dof = e_face_dofs + a_face_dofs; + m_n_c_dof = Kg.rows() - m_n_f_dof; + + m_Mc = Mg.block( 0, 0, m_n_c_dof, m_n_c_dof); + m_Kcc = Kg.block( 0, 0, m_n_c_dof, m_n_c_dof); + m_Kcf = Kg.block( 0, m_n_c_dof, m_n_c_dof, m_n_f_dof); + m_Kfc = Kg.block(m_n_c_dof, 0, m_n_f_dof, m_n_c_dof); + m_Sff = Kg.block(m_n_c_dof, m_n_c_dof, m_n_f_dof, m_n_f_dof); + + m_Cg = Cg.block(m_n_c_dof, m_n_c_dof, m_n_f_dof, m_n_f_dof); + + m_Fc = Fg.block(0, 0, m_n_c_dof, 1); + + m_sff_is_block_diagonal_Q = true; + m_iterative_solver_Q = false; + + } + + void Mcc_inverse(size_t e_cells, size_t a_cells, size_t e_cbs, size_t a_cbs) { + + size_t nnz_cc = e_cbs*e_cbs*e_cells + a_cbs*a_cbs*a_cells; + std::vector< Triplet > triplets_cc; + triplets_cc.resize(nnz_cc); + m_Mc_inv = SparseMatrix(m_n_c_dof, m_n_c_dof); + + #ifdef HAVE_INTEL_TBB + + tbb::parallel_for(size_t(0), size_t(e_cells), size_t(1), + [this,&triplets_cc,&e_cbs] (size_t & cell_ind) { + + size_t stride_eq = cell_ind * e_cbs; + size_t stride_l = cell_ind * e_cbs * e_cbs; + + SparseMatrix m_Mc_loc = m_Mc.block(stride_eq, stride_eq, e_cbs, e_cbs); + SparseLU> analysis_cc; + analysis_cc.analyzePattern(m_Mc_loc); + analysis_cc.factorize(m_Mc_loc); + Matrix m_Mc_inv_loc = analysis_cc.solve(Matrix::Identity(e_cbs, e_cbs)); + + size_t l = 0; + for (size_t i = 0; i < m_Mc_inv_loc.rows(); i++) { + for (size_t j = 0; j < m_Mc_inv_loc.cols(); j++) { + triplets_cc[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, m_Mc_inv_loc(i,j)); + l++; + } + } + }); + tbb::parallel_for(size_t(0), size_t(a_cells), size_t(1), + [this,&triplets_cc,&a_cbs,&e_cbs,&e_cells] (size_t & cell_ind) { + + size_t stride_eq = cell_ind*a_cbs + e_cells*e_cbs; + size_t stride_l = cell_ind*a_cbs*a_cbs + e_cells*e_cbs*e_cbs; + + SparseMatrix m_Mc_loc = m_Mc.block(stride_eq, stride_eq, a_cbs, a_cbs); + SparseLU> analysis_cc; + analysis_cc.analyzePattern(m_Mc_loc); + analysis_cc.factorize(m_Mc_loc); + Matrix m_Mc_inv_loc = analysis_cc.solve(Matrix::Identity(a_cbs, a_cbs)); + + size_t l = 0; + for (size_t i = 0; i < m_Mc_inv_loc.rows(); i++) { + for (size_t j = 0; j < m_Mc_inv_loc.cols(); j++) { + triplets_cc[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, m_Mc_inv_loc(i,j)); + l++; + } + } + }); + + #else + + for (size_t cell_ind = 0; cell_ind < e_cells; cell_ind++) { + size_t stride_eq = cell_ind * e_cbs; + size_t stride_l = cell_ind * e_cbs * e_cbs; + + SparseMatrix m_Mc_loc = m_Mc.block(stride_eq, stride_eq, e_cbs, e_cbs); + SparseLU> analysis_cc; + analysis_cc.analyzePattern(m_Mc_loc); + analysis_cc.factorize(m_Mc_loc); + Matrix m_Mc_inv_loc = analysis_cc.solve(Matrix::Identity(e_cbs, e_cbs)); + + size_t l = 0; + for (size_t i = 0; i < m_Mc_inv_loc.rows(); i++) { + for (size_t j = 0; j < m_Mc_inv_loc.cols(); j++) { + triplets_cc[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, m_Mc_inv_loc(i,j)); + l++; + } + } + } + for (size_t cell_ind = 0; cell_ind < a_cells; cell_ind++) { + size_t stride_eq = cell_ind*a_cbs + e_cells*e_cbs; + size_t stride_l = cell_ind*a_cbs*a_cbs + e_cells*e_cbs*e_cbs; + + SparseMatrix m_Mc_loc = m_Mc.block(stride_eq, stride_eq, a_cbs, a_cbs); + SparseLU> analysis_cc; + analysis_cc.analyzePattern(m_Mc_loc); + analysis_cc.factorize(m_Mc_loc); + Matrix m_Mc_inv_loc = analysis_cc.solve(Matrix::Identity(a_cbs, a_cbs)); + + size_t l = 0; + for (size_t i = 0; i < m_Mc_inv_loc.rows(); i++) { + for (size_t j = 0; j < m_Mc_inv_loc.cols(); j++) { + triplets_cc[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, m_Mc_inv_loc(i,j)); + l++; + } + } + } + + #endif + + m_Mc_inv.setFromTriplets(triplets_cc.begin(), triplets_cc.end()); + triplets_cc.clear(); + return; + + } + + + void Sff_inverse(size_t e_faces, size_t a_faces, size_t e_fbs, size_t a_fbs, std::vector e_compress, std::vector a_compress, std::set elastic_internal_faces, std::set acoustic_internal_faces, std::set interfaces_index) { + + size_t n_interfaces = interfaces_index.size(); // Number of interfaces + size_t nnz_ff = e_fbs*e_fbs*e_faces + a_fbs*a_fbs*a_faces + 2*e_fbs*a_fbs*n_interfaces; // Number of nonzeros + std::vector< Triplet > triplets_ff; + triplets_ff.resize(nnz_ff); + m_Sff_inv = SparseMatrix(m_n_f_dof, m_n_f_dof); // size: number of faces x number of faces + + // Inversion of elastic stabilization + for (size_t face_ind = 0; face_ind < e_faces; face_ind++) { + // std::cout << "Elastic face: " << face_ind << std::endl << std::endl; + size_t stride_eq = face_ind * e_fbs; + size_t stride_l = face_ind * e_fbs * e_fbs; + SparseMatrix S_ff_loc = m_Sff.block(stride_eq, stride_eq, e_fbs, e_fbs); + SparseLU> analysis_ff; + analysis_ff.analyzePattern(S_ff_loc); + analysis_ff.factorize(S_ff_loc); + Matrix S_ff_inv_loc = analysis_ff.solve(Matrix::Identity(e_fbs, e_fbs)); + size_t l = 0; + for (size_t i = 0; i < S_ff_inv_loc.rows(); i++) { + for (size_t j = 0; j < S_ff_inv_loc.cols(); j++) { + triplets_ff[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, S_ff_inv_loc(i,j)); + l++; + } + } + } + + // Inversion of acoustic stabilization + for (size_t face_ind = 0; face_ind < a_faces; face_ind++) { + // std::cout << "Acoutic face: " << e_faces + face_ind << std::endl << std::endl; + size_t stride_eq = e_faces*e_fbs + face_ind*a_fbs ; + size_t stride_l = e_faces*e_fbs*e_fbs + face_ind*a_fbs*a_fbs; + SparseMatrix S_ff_loc = m_Sff.block(stride_eq, stride_eq, a_fbs, a_fbs); + SparseLU> analysis_ff; + analysis_ff.analyzePattern(S_ff_loc); + analysis_ff.factorize(S_ff_loc); + Matrix S_ff_inv_loc = analysis_ff.solve(Matrix::Identity(a_fbs, a_fbs)); + size_t l = 0; + for (size_t i = 0; i < S_ff_inv_loc.rows(); i++) { + for (size_t j = 0; j < S_ff_inv_loc.cols(); j++) { + triplets_ff[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, S_ff_inv_loc(i,j)); + l++; + } + } + } + + // Inversion of coupling terms + size_t cpt = 0; + for (auto face : interfaces_index) { // Parcours des interfaces + size_t e_face_LHS_offset = e_compress.at(face)*e_fbs; // Indice de la face elastique + size_t a_face_LHS_offset = e_faces*e_fbs + a_compress.at(face)*a_fbs; // Indice de la face acoustique + // std::cout << "Interface: " << face << std::endl; + // std::cout << "Elastic interface: " << e_compress.at(face) << std::endl; + // std::cout << "Acoustic interface: " << e_faces + a_compress.at(face) << std::endl << std::endl; + size_t fbs = e_fbs + a_fbs; + size_t e_stride_l = e_compress.at(face)*e_fbs*e_fbs; + size_t a_stride_l = e_faces*e_fbs*e_fbs + a_compress.at(face)*a_fbs*a_fbs; + size_t i_stride_l = e_faces*e_fbs*e_fbs + a_faces*a_fbs*a_fbs + 2*cpt*a_fbs*e_fbs; + + // Extraction du bloc stabilisation local + Matrix dense_SC_ff(fbs, fbs); + SparseMatrix elastic_stab = m_Sff.block(e_face_LHS_offset, e_face_LHS_offset, e_fbs, e_fbs); + SparseMatrix acoustic_stab = m_Sff.block(a_face_LHS_offset, a_face_LHS_offset, a_fbs, a_fbs); + dense_SC_ff.block(0, 0, e_fbs, e_fbs) = elastic_stab; + dense_SC_ff.block(e_fbs, e_fbs, a_fbs, a_fbs) = acoustic_stab; + + // Extraction du bloc coupling + SparseMatrix coupling_ela = m_Cg.block(e_face_LHS_offset, a_face_LHS_offset, e_fbs, a_fbs); + SparseMatrix coupling_acou = m_Cg.block(a_face_LHS_offset, e_face_LHS_offset, a_fbs, e_fbs); + dense_SC_ff.block(0, e_fbs, e_fbs, a_fbs) = coupling_ela; + dense_SC_ff.block(e_fbs, 0, a_fbs, e_fbs) = coupling_acou; + + // Inversion + SparseMatrix SC_ff_loc = dense_SC_ff.sparseView(); + SparseLU> analysis_ff; + analysis_ff.analyzePattern(SC_ff_loc); + analysis_ff.factorize(SC_ff_loc); + Matrix SC_ff_inv_loc = analysis_ff.solve(Matrix::Identity(fbs, fbs)); + + size_t l = 0; + for (size_t i = 0; i < e_fbs; i++) { + for (size_t j = 0; j < e_fbs; j++) { + triplets_ff[e_stride_l+l] = Triplet(e_face_LHS_offset+i, e_face_LHS_offset+j, SC_ff_inv_loc(i,j)); + l++; + } + } + l = 0; + for (size_t i = 0; i < a_fbs; i++) { + for (size_t j = 0; j < a_fbs; j++) { + triplets_ff[a_stride_l+l] = Triplet(a_face_LHS_offset+i, a_face_LHS_offset+j, SC_ff_inv_loc(e_fbs+i,e_fbs+j)); + l++; + } + } + l = 0; + // Upper right bloc + for (size_t i = 0; i < e_fbs; i++) { + for (size_t j = 0; j < a_fbs; j++) { + triplets_ff[i_stride_l+l] = Triplet(e_face_LHS_offset+i, a_face_LHS_offset+j, SC_ff_inv_loc(i,e_fbs+j)); + l++; + } + } + // Lower left bloc + for (size_t i = 0; i < a_fbs; i++) { + for (size_t j = 0; j < e_fbs; j++) { + triplets_ff[i_stride_l+l] = Triplet(a_face_LHS_offset+i, e_face_LHS_offset+j, SC_ff_inv_loc(e_fbs+i,j)); + l++; + } + } + cpt++; + } + + m_Sff_inv.setFromTriplets(triplets_ff.begin(), triplets_ff.end()); + triplets_ff.clear(); + return; + + } + + + void inverse_Sff() { + + // Bi CG + Eigen::BiCGSTAB> solverBiCG; + solverBiCG.compute(m_Sff); + if (solverBiCG.info() != Eigen::Success) + std::cout << "Error: Matrix decomposition failed, the matrix may not be invertible"; + Eigen::SparseMatrix identity(m_Sff.rows(), m_Sff.cols()); + identity.setIdentity(); + m_inv_Sff = solverBiCG.solve(identity); + if (solverBiCG.info() != Eigen::Success) + std::cout << "Error: Solving the system failed, the matrix may not be invertible"; + + return; + + } + + void setIterativeSolver(T tolerance = 1.0e-11){ + m_iterative_solver_Q = true; + m_analysis_cg.setTolerance(tolerance); + } + + void DecomposeFaceTerm(){ + + if (m_iterative_solver_Q) { + m_analysis_cg.compute(m_Sff); + m_analysis_cg.setMaxIterations(m_Sff.rows()); + } + + else { + m_analysis_f.analyzePattern(m_Sff); + m_analysis_f.factorize(m_Sff); + } + m_sff_is_block_diagonal_Q = false; + } + + void refresh_faces_unknowns(Matrix & x) { + + Matrix x_c_dof = x.block(0, 0, m_n_c_dof, 1); + + // Faces update from cells data + Matrix RHSf = Kfc()*x_c_dof; + if (m_sff_is_block_diagonal_Q) { + x.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_Sff_inv * RHSf; + } + else { + inverse_Sff(); + x.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_inv_Sff * RHSf; + } + } + + void erk_weight(Matrix & y, Matrix & k){ + + k=y; + Matrix y_c_dof = y.block(0, 0, m_n_c_dof, 1); + Matrix y_f_dof = y.block(m_n_c_dof, 0, m_n_f_dof, 1); + + // Cells update + Matrix RHSc = Fc() - Kcc()*y_c_dof - Kcf()*y_f_dof; + Matrix k_c_dof = m_Mc_inv * RHSc; + k.block(0, 0, m_n_c_dof, 1) = k_c_dof; + + // Faces update + Matrix RHSf = Kfc()*k_c_dof ; + // To comment to test eta = 0 + if (m_sff_is_block_diagonal_Q) { + k.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_Sff_inv * RHSf; + } + else { + k.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_inv_Sff * RHSf; + } + } + + #ifdef HAVE_INTEL_MKL + PardisoLDLT> & FacesAnalysis(){ + return m_analysis_f; + } + #else + SimplicialLDLT> & FacesAnalysis(){ + return m_analysis_f; + } + #endif + + SparseMatrix & Mc(){ + return m_Mc; + } + + SparseMatrix & Kcc(){ + return m_Kcc; + } + + SparseMatrix & Kcf(){ + return m_Kcf; + } + + SparseMatrix & Kfc(){ + return m_Kfc; + } + + SparseMatrix & Sff(){ + return m_Sff; + } + + Matrix & Fc(){ + return m_Fc; + } + + void SetFg(Matrix & Fg){ + m_Fc = Fg.block(0, 0, m_n_c_dof, 1); + } + + void compute_eigenvalues(std::ostream & simulation_log = std::cout){ + + SparseMatrix A_SCHUR = m_Kcc - m_Kcf*m_Sff_inv*m_Kfc; + SparseMatrix A = A_SCHUR.transpose()*m_Mc_inv*A_SCHUR; + Spectra::SparseSymMatProd opA(A); + Spectra::SparseCholesky opB(m_Mc); + Spectra::SymGEigsSolver, Spectra::SparseCholesky, Spectra::GEigsMode::Cholesky> eigs(opA, opB, 1, 10); + // Initialize and compute + eigs.init(); + eigs.compute(Spectra::SortRule::LargestMagn); + std::cout << std::endl << bold << red << " Computation of the eigenvalues: " << reset; + std::cout << std::endl << bold << cyan << " State of the computation: " << reset; + bool debug = true; + if (debug) { + if(eigs.info() == Spectra::CompInfo::Successful) + std::cout << cyan << bold << "Successful\n"; + if(eigs.info() == Spectra::CompInfo::NotComputed) + std::cout << cyan << bold << "NotComputed\n"; + if(eigs.info() == Spectra::CompInfo::NotConverging) + std::cout << cyan << bold << "NotConverging\n"; + if(eigs.info() == Spectra::CompInfo::NumericalIssue) + std::cout << cyan << bold << "NumericalIssue\n"; + } + eigs.eigenvalues(); + std::cout << bold << cyan << " Eigenvalue found: " << reset << cyan << eigs.eigenvalues() << std::endl << std::endl; + simulation_log << "Eigenvalue found: " << eigs.eigenvalues() << std::endl; + + } + + void compute_eigenvalues_bis(SparseMatrix LHS_STAB, std::pair block_dimension, std::ostream & simulation_log = std::cout){ + + auto ten_bs = block_dimension.first; // Elastic block + auto vec_cell_size = block_dimension.second; // Acoustic block + SparseMatrix m_Scc = LHS_STAB.block(0,0, m_n_c_dof, m_n_c_dof); // Stabilisation + + SparseMatrix Delta = m_Kcf*m_Sff_inv*m_Kfc; + SparseMatrix A_SCHUR = m_Kcc - Delta; + SparseMatrix S_SCHUR = m_Scc - Delta; + SparseMatrix A = A_SCHUR.transpose()*m_Mc_inv*A_SCHUR - S_SCHUR.transpose()*m_Mc_inv*S_SCHUR; + Spectra::SparseSymMatProd opA(A); + Spectra::SparseCholesky opB(m_Mc); + Spectra::SymGEigsSolver, Spectra::SparseCholesky, Spectra::GEigsMode::Cholesky> eigs(opA, opB, 1, 10); + // Initialize and compute + eigs.init(); + eigs.compute(Spectra::SortRule::LargestMagn); + bool debug = true; + if (debug) { + if(eigs.info() == Spectra::CompInfo::Successful) + std::cout << "Successful\n"; + if(eigs.info() == Spectra::CompInfo::NotComputed) + std::cout << "NotComputed\n"; + if(eigs.info() == Spectra::CompInfo::NotConverging) + std::cout << "NotConverging\n"; + if(eigs.info() == Spectra::CompInfo::NumericalIssue) + std::cout << "NumericalIssue\n"; + } + eigs.eigenvalues(); + std::cout << std::endl; + std::cout << bold << red << " Eigenvalue found: " << reset << eigs.eigenvalues(); + simulation_log << "Eigenvalue found: " << eigs.eigenvalues() << std::endl; + + } + +// Delta = A_{TF} A_{FF}^{-1} A_{FT} +// A' = A_{TT}-Delta +// S'=S_{TT}-Delta + +// Pb spectral pour A'MA' - S'MS' + +}; + + + + +#endif /* erk_hho_scheme_hpp */ diff --git a/apps/wave_propagation/src/common/erk_hho_scheme.hpp b/apps/wave_propagation/src/common/erk_hho_scheme.hpp new file mode 100644 index 00000000..ee6d4720 --- /dev/null +++ b/apps/wave_propagation/src/common/erk_hho_scheme.hpp @@ -0,0 +1,290 @@ +// +// erk_hho_scheme.hpp +// acoustics +// +// Created by Omar Durán on 5/8/20. +// + +#ifndef erk_hho_scheme_hpp +#define erk_hho_scheme_hpp + +#include +#include +#include + +template +class erk_hho_scheme +{ + private: + + SparseMatrix m_Mc; + SparseMatrix m_Kcc; + SparseMatrix m_Kcf; + SparseMatrix m_Kfc; + SparseMatrix m_Sff; + SparseMatrix m_Mc_inv; + SparseMatrix m_Sff_inv; + Matrix m_Fc; + + #ifdef HAVE_INTEL_MKL + PardisoLDLT> m_analysis_f; + #else + SimplicialLDLT> m_analysis_f; + #endif + + ConjugateGradient> m_analysis_cg; + + size_t m_n_c_dof; + size_t m_n_f_dof; + bool m_sff_is_block_diagonal_Q; + bool m_iterative_solver_Q; + + public: + + erk_hho_scheme(SparseMatrix & Kg, Matrix & Fg, SparseMatrix & Mg, size_t n_f_dof){ + + + m_n_c_dof = Kg.rows() - n_f_dof; + m_n_f_dof = n_f_dof; + + // Building blocks + m_Mc = Mg.block(0, 0, m_n_c_dof, m_n_c_dof); + m_Kcc = Kg.block(0, 0, m_n_c_dof, m_n_c_dof); + m_Kcf = Kg.block(0, m_n_c_dof, m_n_c_dof, n_f_dof); + m_Kfc = Kg.block(m_n_c_dof,0, n_f_dof, m_n_c_dof); + m_Sff = Kg.block(m_n_c_dof,m_n_c_dof, n_f_dof, n_f_dof); + m_Fc = Fg.block(0, 0, m_n_c_dof, 1); + m_sff_is_block_diagonal_Q = false; + m_iterative_solver_Q = false; + } + + void setIterativeSolver(T tolerance = 1.0e-11){ + m_iterative_solver_Q = true; + m_analysis_cg.setTolerance(tolerance); + } + + void DecomposeFaceTerm(){ + + if (m_iterative_solver_Q) { + m_analysis_cg.compute(m_Sff); + m_analysis_cg.setMaxIterations(m_Sff.rows()); + }else{ + m_analysis_f.analyzePattern(m_Sff); + m_analysis_f.factorize(m_Sff); + } + m_sff_is_block_diagonal_Q = false; + } + + + #ifdef HAVE_INTEL_MKL + PardisoLDLT> & FacesAnalysis(){ + return m_analysis_f; + } + #else + SimplicialLDLT> & FacesAnalysis(){ + return m_analysis_f; + } + #endif + + SparseMatrix & Mc(){ + return m_Mc; + } + + SparseMatrix & Kcc(){ + return m_Kcc; + } + + SparseMatrix & Kcf(){ + return m_Kcf; + } + + SparseMatrix & Kfc(){ + return m_Kfc; + } + + SparseMatrix & Sff(){ + return m_Sff; + } + + Matrix & Fc(){ + return m_Fc; + } + + void SetFg(Matrix & Fg){ + m_Fc = Fg.block(0, 0, m_n_c_dof, 1); + } + + void Kcc_inverse(std::pair cell_basis_data){ + + size_t n_cells = cell_basis_data.first; + size_t n_cbs = cell_basis_data.second; + size_t nnz_cc = n_cbs*n_cbs*n_cells; + std::vector< Triplet > triplets_cc; + triplets_cc.resize(nnz_cc); + m_Mc_inv = SparseMatrix( m_n_c_dof, m_n_c_dof ); + #ifdef HAVE_INTEL_TBB + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&triplets_cc,&n_cbs] (size_t & cell_ind){ + + size_t stride_eq = cell_ind * n_cbs; + size_t stride_l = cell_ind * n_cbs * n_cbs; + + SparseMatrix m_Mc_loc = m_Mc.block(stride_eq, stride_eq, n_cbs, n_cbs); + SparseLU> analysis_cc; + analysis_cc.analyzePattern(m_Mc_loc); + analysis_cc.factorize(m_Mc_loc); + Matrix m_Mc_inv_loc = analysis_cc.solve(Matrix::Identity(n_cbs, n_cbs)); + + size_t l = 0; + for (size_t i = 0; i < m_Mc_inv_loc.rows(); i++) + { + for (size_t j = 0; j < m_Mc_inv_loc.cols(); j++) + { + triplets_cc[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, m_Mc_inv_loc(i,j)); + l++; + } + } + } + ); + #else + + for (size_t cell_ind = 0; cell_ind < n_cells; cell_ind++) + { + size_t stride_eq = cell_ind * n_cbs; + size_t stride_l = cell_ind * n_cbs * n_cbs; + + SparseMatrix m_Mc_loc = m_Mc.block(stride_eq, stride_eq, n_cbs, n_cbs); + SparseLU> analysis_cc; + analysis_cc.analyzePattern(m_Mc_loc); + analysis_cc.factorize(m_Mc_loc); + Matrix m_Mc_inv_loc = analysis_cc.solve(Matrix::Identity(n_cbs, n_cbs)); + + size_t l = 0; + for (size_t i = 0; i < m_Mc_inv_loc.rows(); i++) + { + for (size_t j = 0; j < m_Mc_inv_loc.cols(); j++) + { + triplets_cc[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, m_Mc_inv_loc(i,j)); + l++; + } + } + + } + #endif + m_Mc_inv.setFromTriplets( triplets_cc.begin(), triplets_cc.end() ); + triplets_cc.clear(); + return; + + } + + void Sff_inverse(std::pair face_basis_data){ + + size_t n_faces = face_basis_data.first; + size_t n_fbs = face_basis_data.second; + size_t nnz_ff = n_fbs*n_fbs*n_faces; + std::vector< Triplet > triplets_ff; + triplets_ff.resize(nnz_ff); + m_Sff_inv = SparseMatrix( m_n_f_dof, m_n_f_dof ); + #ifdef HAVE_INTEL_TBB + tbb::parallel_for(size_t(0), size_t(n_faces), size_t(1), + [this,&triplets_ff,&n_fbs] (size_t & face_ind){ + + size_t stride_eq = face_ind * n_fbs; + size_t stride_l = face_ind * n_fbs * n_fbs; + + SparseMatrix S_ff_loc = m_Sff.block(stride_eq, stride_eq, n_fbs, n_fbs); + SparseLU> analysis_ff; + analysis_ff.analyzePattern(S_ff_loc); + analysis_ff.factorize(S_ff_loc); + Matrix S_ff_inv_loc = analysis_ff.solve(Matrix::Identity(n_fbs, n_fbs)); + + size_t l = 0; + for (size_t i = 0; i < S_ff_inv_loc.rows(); i++) + { + for (size_t j = 0; j < S_ff_inv_loc.cols(); j++) + { + triplets_ff[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, S_ff_inv_loc(i,j)); + l++; + } + } + } + ); + #else + + for (size_t face_ind = 0; face_ind < n_faces; face_ind++) + { + size_t stride_eq = face_ind * n_fbs; + size_t stride_l = face_ind * n_fbs * n_fbs; + + SparseMatrix S_ff_loc = m_Sff.block(stride_eq, stride_eq, n_fbs, n_fbs); + SparseLU> analysis_ff; + analysis_ff.analyzePattern(S_ff_loc); + analysis_ff.factorize(S_ff_loc); + Matrix S_ff_inv_loc = analysis_ff.solve(Matrix::Identity(n_fbs, n_fbs)); + size_t l = 0; + for (size_t i = 0; i < S_ff_inv_loc.rows(); i++) + { + for (size_t j = 0; j < S_ff_inv_loc.cols(); j++) + { + triplets_ff[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, S_ff_inv_loc(i,j)); + l++; + } + } + + } + #endif + m_Sff_inv.setFromTriplets( triplets_ff.begin(), triplets_ff.end() ); + triplets_ff.clear(); + m_sff_is_block_diagonal_Q = true; + return; + + } + + void refresh_faces_unknowns(Matrix & x){ + + Matrix x_c_dof = x.block(0, 0, m_n_c_dof, 1); + + // Faces update from cells data + Matrix RHSf = Kfc()*x_c_dof; + if (m_sff_is_block_diagonal_Q) { + x.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_Sff_inv * RHSf; + }else{ + if (m_iterative_solver_Q) { + x.block(m_n_c_dof, 0, m_n_f_dof, 1) = -m_analysis_cg.solve(RHSf); // new state + }else{ + x.block(m_n_c_dof, 0, m_n_f_dof, 1) = -FacesAnalysis().solve(RHSf); // new state + } + } + + } + + void erk_weight(Matrix & y, Matrix & k){ + + k=y; + Matrix y_c_dof = y.block(0, 0, m_n_c_dof, 1); + Matrix y_f_dof = y.block(m_n_c_dof, 0, m_n_f_dof, 1); + + // Cells update + Matrix RHSc = Fc() - Kcc()*y_c_dof - Kcf()*y_f_dof; + Matrix k_c_dof = m_Mc_inv * RHSc; + k.block(0, 0, m_n_c_dof, 1) = k_c_dof; + + // Faces update + Matrix RHSf = Kfc()*k_c_dof; + if (m_sff_is_block_diagonal_Q) { + k.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_Sff_inv * RHSf; + }else{ + if (m_iterative_solver_Q) { + k.block(m_n_c_dof, 0, m_n_f_dof, 1) = -m_analysis_cg.solve(RHSf); // new state + std::cout << "Number of iterations (CG): " << m_analysis_cg.iterations() << std::endl; + std::cout << "Estimated error: " << m_analysis_cg.error() << std::endl; + }else{ + k.block(m_n_c_dof, 0, m_n_f_dof, 1) = -FacesAnalysis().solve(RHSf); // new state + } + } + + } + +}; + +#endif /* erk_hho_scheme_hpp */ diff --git a/apps/wave_propagation/src/common/fitted_geometry_builders.hpp b/apps/wave_propagation/src/common/fitted_geometry_builders.hpp new file mode 100644 index 00000000..859913fc --- /dev/null +++ b/apps/wave_propagation/src/common/fitted_geometry_builders.hpp @@ -0,0 +1,953 @@ +// +// fitted_geometry_builder.hpp +// acoustics +// +// + +#pragma once +#ifndef fitted_geometry_builder_hpp +#define fitted_geometry_builder_hpp + +#include +#include +#include +#include +#include +#include +#include +#include "diskpp/geometry/geometry.hpp" +#include + + +template +class fitted_geometry_builder { + +protected: + + std::string m_log_file = "mesh_log.txt"; + + size_t m_dimension = 0; + + size_t m_n_elements = 0; + +public: + + fitted_geometry_builder() { + + } + + // set the log file name + void set_log_file(std::string log_file) { + m_log_file = log_file; + } + + // get the geometry dimension + size_t get_dimension() { + return m_dimension; + } + + // get the number of elements + size_t get_n_elements() { + return m_n_elements; + } + + // build the mesh + virtual bool build_mesh() = 0; + + // move generated mesh data to an external mesh storage + virtual void move_to_mesh_storage(MESH& msh) = 0; + + // Print in log file relevant mesh information + virtual void print_log_file() = 0; + + virtual ~ fitted_geometry_builder() { + + } + +}; + +template +class cartesian_2d_mesh_builder : public fitted_geometry_builder> +{ + typedef disk::generic_mesh mesh_type; + typedef typename mesh_type::point_type point_type; + typedef typename mesh_type::node_type node_type; + typedef typename mesh_type::edge_type edge_type; + typedef typename mesh_type::surface_type surface_type; + + struct polygon_2d + { + std::vector m_member_nodes; + std::set> m_member_edges; + bool operator<(const polygon_2d & other) { + return m_member_nodes < other.m_member_nodes; + } + }; + + std::vector points; + std::vector vertices; + std::vector> facets; + std::vector> skeleton_edges; + std::vector> boundary_edges; + std::vector polygons; + + + T m_lx = 0.0; + T m_ly = 0.0; + + T m_x_t = 0.0; + T m_y_t = 0.0; + + size_t m_nx = 0; + size_t m_ny = 0; + + void reserve_storage(){ + size_t n_points = (m_nx + 1) * (m_ny + 1); + points.reserve(n_points); + vertices.reserve(n_points); + + size_t n_edges = 2*m_nx*m_ny + m_nx + m_ny; + size_t n_skel_edges = 2*m_nx*m_ny + m_nx + m_ny; + size_t n_bc_edges = n_edges - n_skel_edges; + skeleton_edges.reserve(n_skel_edges); + boundary_edges.reserve(n_bc_edges); + + size_t n_polygons = m_nx * m_ny; + polygons.reserve(n_polygons); + } + + void validate_edge(std::array & edge){ + assert(edge[0] != edge[1]); + if (edge[0] > edge[1]){ + std::swap(edge[0], edge[1]); + } + } + +public: + + cartesian_2d_mesh_builder(T lx, T ly, size_t nx, size_t ny) : fitted_geometry_builder() + { + m_lx = lx; + m_ly = ly; + m_nx = nx; + m_ny = ny; + fitted_geometry_builder::m_dimension = 2; + } + + // uniform refinement x-direction + void refine_mesh_x_direction(size_t n_refinements){ + for (unsigned int i = 0; i < n_refinements; i++) { + m_nx *= 2; + } + } + + // uniform refinement y-direction + void refine_mesh_y_direction(size_t n_refinements){ + for (unsigned int i = 0; i < n_refinements; i++) { + m_ny *= 2; + } + } + + // uniform refinement + void refine_mesh(size_t n_refinements){ + refine_mesh_x_direction(n_refinements); + refine_mesh_y_direction(n_refinements); + } + + // build the mesh + bool build_mesh(){ + + reserve_storage(); + + std::vector range_x(m_nx+1,0.0); + T dx = m_lx/T(m_nx); + for (unsigned int i = 0; i <= m_nx; i++) { + range_x[i] = i*dx; + } + + std::vector range_y(m_ny+1,0.0); + T dy = m_ly/T(m_ny); + for (unsigned int i = 0; i <= m_ny; i++) { + range_y[i] = i*dy; + } + + size_t node_id = 0; + for (unsigned int j = 0; j <= m_ny; j++) { + T yv = range_y[j] + m_y_t; + for (unsigned int i = 0; i <= m_nx; i++) { + T xv = range_x[i] + m_x_t; + point_type point(xv, yv); + points.push_back(point); + vertices.push_back(node_type(point_identifier<2>(node_id))); + node_id++; + } + } + + size_t edge_id = 0; + for (size_t j = 0; j < m_ny; j++) { + for (size_t i = 0; i < m_nx; i++) { + + size_t id_0 = i + j * (m_nx + 1); + size_t id_1 = id_0 + 1; + size_t id_2 = i + (m_nx + 1) + 1 + j* (m_nx + 1); + size_t id_3 = id_2 - 1; + + // Adding edges: Cases to avoid edge duplicity + if (i==0 && j==0) { + + std::array e0 = {id_0,id_1}; + validate_edge(e0); + facets.push_back( e0 ); + boundary_edges.push_back( e0 ); + edge_id++; + + std::array e1 = {id_1,id_2}; + validate_edge(e1); + facets.push_back( e1 ); + if(j == m_ny - 1) boundary_edges.push_back( e1 ); + edge_id++; + + std::array e2 = {id_2,id_3}; + validate_edge(e2); + facets.push_back( e2 ); + edge_id++; + + std::array e3 = {id_3,id_0}; + validate_edge(e3); + facets.push_back( e3 ); + boundary_edges.push_back( e3 ); + edge_id++; + } + + if ((i>0 && i < m_nx) && j==0) { + std::array e0 = {id_0,id_1}; + validate_edge(e0); + facets.push_back( e0 ); + boundary_edges.push_back( e0 ); + edge_id++; + + std::array e1 = {id_1,id_2}; + validate_edge(e1); + facets.push_back( e1 ); + if(i == m_nx - 1) boundary_edges.push_back( e1 ); + edge_id++; + + std::array e2 = {id_2,id_3}; + validate_edge(e2); + facets.push_back( e2 ); + if(j == m_ny - 1) boundary_edges.push_back( e2 ); + edge_id++; + } + if (i==0 && j>0) { + + std::array e1 = {id_1,id_2}; + validate_edge(e1); + facets.push_back( e1 ); + edge_id++; + + std::array e2 = {id_2,id_3}; + validate_edge(e2); + facets.push_back( e2 ); + if(j == m_ny - 1) boundary_edges.push_back( e2 ); + edge_id++; + + std::array e3 = {id_3,id_0}; + validate_edge(e3); + boundary_edges.push_back( e3 ); + facets.push_back( e3 ); + edge_id++; + } + + if (i>0 && j>0) { + + std::array e1 = {id_1,id_2}; + validate_edge(e1); + facets.push_back( e1 ); + if(i == m_nx - 1) boundary_edges.push_back( e1 ); + edge_id++; + + std::array e2 = {id_2,id_3}; + validate_edge(e2); + facets.push_back( e2 ); + if(j == m_ny - 1) boundary_edges.push_back( e2 ); + edge_id++; + + } + } + } + + size_t surface_id = 0; + for (size_t j = 0; j < m_ny; j++) { + for (size_t i = 0; i < m_nx; i++) { + + size_t id_0 = i + j * (m_nx + 1); + size_t id_1 = id_0 + 1; + size_t id_2 = i + (m_nx + 1) + 1 + j* (m_nx + 1); + size_t id_3 = id_2 - 1; + + polygon_2d polygon; + polygon.m_member_nodes = {id_0,id_1,id_2,id_3}; + std::array e0 = {id_0,id_1}; + validate_edge(e0); + std::array e1 = {id_1,id_2}; + validate_edge(e1); + std::array e2 = {id_2,id_3}; + validate_edge(e2); + std::array e3 = {id_3,id_0}; + validate_edge(e3); + + polygon.m_member_edges = {e0,e1,e2,e3}; + polygons.push_back( polygon ); + surface_id++; + + } + } + + // std::cout << bold << red << std::endl << std::endl; + // std::cout << "Debug mesh" << std::endl; + // std::cout << reset << "Points: " << vertices.size() << std::endl; + // std::cout << reset << "Polygons: " << polygons.size() << std::endl; + // std::cout << reset << "Boundaries: " << boundary_edges.size() << std::endl; + // std::cout << reset << "Facets: " << facets.size() << std::endl; + return true; + } + + void move_to_mesh_storage(mesh_type& msh){ + + auto storage = msh.backend_storage(); + storage->points = std::move(points); + storage->nodes = std::move(vertices); + + std::vector edges; + edges.reserve(facets.size()); + for (size_t i = 0; i < facets.size(); i++) + { + assert(facets[i][0] < facets[i][1]); + auto node1 = typename node_type::id_type(facets[i][0]); + auto node2 = typename node_type::id_type(facets[i][1]); + + auto e = edge_type{{node1, node2}}; + + e.set_point_ids(facets[i].begin(), facets[i].end()); + edges.push_back(e); + } + std::sort(edges.begin(), edges.end()); + + storage->boundary_info.resize(edges.size()); + for (size_t i = 0; i < boundary_edges.size(); i++) + { + assert(boundary_edges[i][0] < boundary_edges[i][1]); + auto node1 = typename node_type::id_type(boundary_edges[i][0]); + auto node2 = typename node_type::id_type(boundary_edges[i][1]); + + auto e = edge_type{{node1, node2}}; + + auto position = find_element_id(edges.begin(), edges.end(), e); + + if (position.first == false) + { + std::cout << "Bad bug at " << __FILE__ << "(" + << __LINE__ << ")" << std::endl; + return; + } + + disk::bnd_info bi{0, true}; + storage->boundary_info.at(position.second) = bi; + } + + storage->edges = std::move(edges); + + std::vector surfaces; + surfaces.reserve( polygons.size() ); + + for (auto& p : polygons) + { + std::vector surface_edges; + for (auto& e : p.m_member_edges) + { + assert(e[0] < e[1]); + auto n1 = typename node_type::id_type(e[0]); + auto n2 = typename node_type::id_type(e[1]); + + edge_type edge{{n1, n2}}; + auto edge_id = find_element_id(storage->edges.begin(), + storage->edges.end(), edge); + if (!edge_id.first) + { + std::cout << "Bad bug at " << __FILE__ << "(" + << __LINE__ << ")" << std::endl; + return; + } + + surface_edges.push_back(edge_id.second); + } + auto surface = surface_type(surface_edges); + surface.set_point_ids(p.m_member_nodes.begin(), p.m_member_nodes.end()); + surfaces.push_back( surface ); + } + + std::sort(surfaces.begin(), surfaces.end()); + storage->surfaces = std::move(surfaces); + + } + + void set_translation_data(T x_t, T y_t){ + m_x_t = x_t; + m_y_t = y_t; + } + + size_t get_nx(){ + return m_nx; + } + + size_t get_ny(){ + return m_ny; + } + + // Print in log file relevant mesh information + void print_log_file(){ + fitted_geometry_builder::m_n_elements = polygons.size(); + std::ofstream file; + file.open (fitted_geometry_builder::m_log_file.c_str()); + file << "Number of surfaces : " << polygons.size() << std::endl; + file << "Number of skeleton edges : " << skeleton_edges.size() << std::endl; + file << "Number of boundary edges : " << boundary_edges.size() << std::endl; + file << "Number of vertices : " << vertices.size() << std::endl; + file.close(); + } + +}; + + +template +class polygon_2d_mesh_reader : + +public fitted_geometry_builder> { + + typedef disk::generic_mesh mesh_type; + typedef typename mesh_type::point_type point_type; + typedef typename mesh_type::node_type node_type; + typedef typename mesh_type::edge_type edge_type; + typedef typename mesh_type::surface_type surface_type; + +public: + + struct polygon_2d { + std::vector m_member_nodes; + std::set> m_member_edges; + int m_material; + bool m_elastic_material; + + bool operator<(const polygon_2d & other) { + return m_member_nodes < other.m_member_nodes; + } + }; + + // struct FaceInfo { + // size_t face_id; + // size_t cell1_id = -1; + // size_t cell2_id = -1; + // }; + + std::vector points; + std::vector vertices; + std::vector> facets; + std::vector> interfaces; + std::vector> skeleton_edges; + std::vector> boundary_edges; + std::vector polygons; + // std::vector faces; + std::string poly_mesh_file; + std::set bc_points; + // FaceInfo face_info; + // face_info.face_id = edge_id.second; + // if (face_info.cell1_id == -1) { + // face_info.cell1_id == compteur; + // } + // else { + // face_info.cell2_id == compteur; + // } + // faces.push_back(face_info); + void clear_storage() { + points.clear(); + vertices.clear(); + skeleton_edges.clear(); + boundary_edges.clear(); + polygons.clear(); + bc_points.clear(); + } + + void reserve_storage(){ + + std::ifstream input; + input.open(poly_mesh_file.c_str()); + + size_t n_points, n_polygons, n_bc_curves, n_bc_edges, n_edges; + if (input.is_open()) { + std::string line; + std::getline(input, line); + std::stringstream(line) >> n_points >> n_polygons >> n_bc_curves; + for(size_t id = 0; id < n_points; id++){ + if(std::getline(input, line)){ + + } + else{ + break; + } + } + + n_edges = 0; + n_bc_edges = 0; + size_t n_polygon_vertices; + for(size_t surface_id=0; surface_id < n_polygons; surface_id++) + { + if(std::getline(input, line)){ + std::stringstream(line) >> n_polygon_vertices; + n_edges += n_polygon_vertices; + } + else{ + break; + } + } + + bc_points.clear(); + size_t bc_point_id; + for(size_t bc_id=0; bc_id < n_bc_curves; bc_id++) + { + if(std::getline(input, line)){ + std::stringstream input_line(line); + while(!input_line.eof()){ + input_line >> bc_point_id; + bc_point_id--; + bc_points.insert(bc_point_id); + } + } + else{ + break; + } + } + n_bc_edges = bc_points.size(); + + points.reserve(n_points); + vertices.reserve(n_points); + + size_t n_skel_edges = n_edges - n_bc_edges; + skeleton_edges.reserve(n_skel_edges); + boundary_edges.reserve(n_bc_edges); + polygons.reserve(n_polygons); + + } + } + + void validate_edge(std::array & edge){ + assert(edge[0] != edge[1]); + if (edge[0] > edge[1]){ + std::swap(edge[0], edge[1]); + } + } + + polygon_2d_mesh_reader() : fitted_geometry_builder() + { + fitted_geometry_builder::m_dimension = 2; + } + + void set_poly_mesh_file(std::string mesh_file){ + poly_mesh_file = mesh_file; + } + + // build the mesh + bool build_mesh(){ + + clear_storage(); + reserve_storage(); + + std::ifstream input; + input.open(poly_mesh_file.c_str()); + + size_t n_points, n_polygons, n_bc_curves; + if (input.is_open()) { + std::string line; + std::getline(input, line); + std::stringstream(line) >> n_points >> n_polygons >> n_bc_curves; + + T xv, yv; + for(size_t id = 0; id < n_points; id++){ + if(std::getline(input, line)){ + std::stringstream(line) >> xv >> yv; + point_type point(xv, yv); + points.push_back(point); + vertices.push_back(node_type(point_identifier<2>(id))); + } + else{ + break; + } + } + + size_t n_polygon_vertices, id; + for(size_t surface_id=0; surface_id < n_polygons; surface_id++) { + + if(std::getline(input, line)){ + std::stringstream input_line(line); + input_line >> n_polygon_vertices; + + polygon_2d polygon; + std::vector member_nodes; + for (size_t i = 0; i < n_polygon_vertices; i++) { + input_line >> id; + id--; + member_nodes.push_back(id); + } + polygon.m_member_nodes = member_nodes; + assert(member_nodes.size() == n_polygon_vertices); + + std::set< std::array > member_edges; + std::array edge; + for (size_t i = 0; i < member_nodes.size(); i++) { + + if (i == n_polygon_vertices - 1) { + edge = {member_nodes[i],member_nodes[0]}; + } + + else { + edge = {member_nodes[i],member_nodes[i+1]}; + } + + validate_edge(edge); + facets.push_back( edge ); + member_edges.insert(edge); + + bool is_bc_point_l_Q = bc_points.find(edge.at(0)) != bc_points.end(); + bool is_bc_point_r_Q = bc_points.find(edge.at(1)) != bc_points.end(); + if (is_bc_point_l_Q && is_bc_point_r_Q) { + boundary_edges.push_back( edge ); + } + } + + polygon.m_member_edges = member_edges; + + polygons.push_back( polygon ); + + } + + else { + break; + } + } + } + + // Duplicated facets are eliminated + std::sort( facets.begin(), facets.end() ); + facets.erase( std::unique( facets.begin(), facets.end() ), facets.end() ); + + // std::cout << bold << red << std::endl << std::endl; + // std::cout << "Debug mesh" << std::endl; + // std::cout << reset << "Points: " << vertices.size() << std::endl; + // std::cout << reset << "Polygons: " << polygons.size() << std::endl; + // std::cout << reset << "Boundaries: " << boundary_edges.size() << std::endl; + // std::cout << reset << "Facets: " << facets.size() << std::endl; + + return true; + } + + // build the mesh + bool build_bassin(){ + + clear_storage(); + reserve_storage(); + + std::ifstream input; + input.open(poly_mesh_file.c_str()); + + size_t n_points, n_polygons, n_bc_curves; + if (input.is_open()) { + std::string line; + std::getline(input, line); + std::stringstream(line) >> n_points >> n_polygons >> n_bc_curves; + + T xv, yv; + for(size_t id = 0; id < n_points; id++){ + if(std::getline(input, line)){ + std::stringstream(line) >> xv >> yv; + point_type point(xv, yv); + points.push_back(point); + vertices.push_back(node_type(point_identifier<2>(id))); + } + else{ + break; + } + } + + size_t n_polygon_vertices, id; + for(size_t surface_id=0; surface_id < n_polygons; surface_id++) { + + if(std::getline(input, line)){ + std::stringstream input_line(line); + input_line >> n_polygon_vertices; + + polygon_2d polygon; + std::vector member_nodes; + int material; + for (size_t i = 0; i < n_polygon_vertices; i++) { + input_line >> id; + id--; + member_nodes.push_back(id); + } + polygon.m_member_nodes = member_nodes; + assert(member_nodes.size() == n_polygon_vertices); + + // FaceInfo face_info; + std::set< std::array > member_edges; + std::array edge; + for (size_t i = 0; i < member_nodes.size(); i++) { + + if (i == n_polygon_vertices - 1) { + edge = {member_nodes[i],member_nodes[0]}; + } + + else { + edge = {member_nodes[i],member_nodes[i+1]}; + } + + validate_edge(edge); + facets.push_back( edge ); + member_edges.insert(edge); + + + bool is_bc_point_l_Q = bc_points.find(edge.at(0)) != bc_points.end(); + bool is_bc_point_r_Q = bc_points.find(edge.at(1)) != bc_points.end(); + if (is_bc_point_l_Q && is_bc_point_r_Q) { + boundary_edges.push_back( edge ); + } + } + + polygon.m_member_edges = member_edges; + polygons.push_back( polygon ); + + } + else { + break; + } + } + + + for(size_t bord=0; bord < 4; bord++) { + if(std::getline(input, line)){ + std::stringstream input_line(line); + } + } + + + for(size_t polygon=0; polygon < n_polygons; polygon++) { + size_t material; + if(std::getline(input, line)){ + std::stringstream input_line(line); + input_line >> material; + } + polygons[polygon].m_material = material; + } + + + } + + // Duplicated facets are eliminated + std::sort( facets.begin(), facets.end() ); + facets.erase( std::unique( facets.begin(), facets.end() ), facets.end() ); + + // std::cout << bold << red << std::endl << std::endl; + // std::cout << "Debug mesh" << std::endl; + // std::cout << reset << "Points: " << vertices.size() << std::endl; + // std::cout << reset << "Polygons: " << polygons.size() << std::endl; + // std::cout << reset << "Boundaries: " << boundary_edges.size() << std::endl; + // std::cout << reset << "Facets: " << facets.size() << std::endl; + + return true; + } + + + void move_to_mesh_storage(mesh_type& msh){ + + auto storage = msh.backend_storage(); + storage->points = std::move(points); + storage->nodes = std::move(vertices); + + std::vector edges; + edges.reserve(facets.size()); + for (size_t i = 0; i < facets.size(); i++) { + assert(facets[i][0] < facets[i][1]); + auto node1 = typename node_type::id_type(facets[i][0]); + auto node2 = typename node_type::id_type(facets[i][1]); + + auto e = edge_type{{node1, node2}}; + + e.set_point_ids(facets[i].begin(), facets[i].end()); + edges.push_back(e); + } + std::sort(edges.begin(), edges.end()); + + storage->boundary_info.resize(edges.size()); + for (size_t i = 0; i < boundary_edges.size(); i++) { + assert(boundary_edges[i][0] < boundary_edges[i][1]); + auto node1 = typename node_type::id_type(boundary_edges[i][0]); + auto node2 = typename node_type::id_type(boundary_edges[i][1]); + auto e = edge_type{{node1, node2}}; + auto position = find_element_id(edges.begin(), edges.end(), e); + if (position.first == false) { + std::cout << "Bad bug at " << __FILE__ << "(" + << __LINE__ << ")" << std::endl; + return; + } + disk::bnd_info bi{0, true}; + storage->boundary_info.at(position.second) = bi; + } + + storage->edges = std::move(edges); + + std::vector surfaces; + surfaces.reserve( polygons.size() ); + + std::vector materials; + materials.reserve( polygons.size() ); + + int compteur = 0; + for (auto& p : polygons) { + compteur = compteur + 1; + std::vector surface_edges; + for (auto& e : p.m_member_edges) { + assert(e[0] < e[1]); + auto n1 = typename node_type::id_type(e[0]); + auto n2 = typename node_type::id_type(e[1]); + + edge_type edge{{n1, n2}}; + auto edge_id = find_element_id(storage->edges.begin(), + storage->edges.end(), edge); + if (!edge_id.first) + { + std::cout << "Bad bug at " << __FILE__ << "(" + << __LINE__ << ")" << std::endl; + return; + } + + surface_edges.push_back(edge_id.second); + + + } + auto surface = surface_type(surface_edges); + surface.set_point_ids(p.m_member_nodes.begin(), p.m_member_nodes.end()); + surfaces.push_back( surface ); + materials.push_back(p.m_material); + } + + ////////////////////////////// Trie pour les matériaux + std::vector> pairedVec; + for (size_t i = 0; i < surfaces.size(); ++i) { + pairedVec.push_back(std::make_pair(surfaces[i], materials[i])); + } + // Trier les paires en fonction des valeurs (les surfaces dans ce cas) + std::sort(pairedVec.begin(), pairedVec.end(), [](const auto& left, const auto& right) { + return left.first < right.first; + }); + // Réorganiser le vecteur material en fonction des indices triés + std::vector sortedMaterial; + for (const auto& pair : pairedVec) { + sortedMaterial.push_back(pair.second); + } + // Mettre à jour le vecteur material + for (size_t i = 0; i < surfaces.size(); ++i) { + polygons[i].m_material = sortedMaterial[i]; + if (polygons[i].m_material == 1 || polygons[i].m_material == 2) { + polygons[i].m_elastic_material = true; + } + else { + polygons[i].m_elastic_material = false; + } + } + ////////////////////////////////////////////////// + + std::sort(surfaces.begin(), surfaces.end()); + storage->surfaces = std::move(surfaces); + + } + + // Print in log file relevant mesh information + void print_log_file(){ + fitted_geometry_builder::m_n_elements = polygons.size(); + std::ofstream file; + file.open (fitted_geometry_builder::m_log_file.c_str()); + file << "Number of polygons : " << polygons.size() << std::endl; + file << "Number of skeleton edges : " << skeleton_edges.size() << std::endl; + file << "Number of boundary edges : " << boundary_edges.size() << std::endl; + file << "Number of vertices : " << vertices.size() << std::endl; + file.close(); + } + + const std::vector& getPoints() const { + return points; + } + + const std::vector& getVertices() const { + return vertices; + } + + const std::vector>& getFacets() const { + return facets; + } + + const std::vector>& getSkeletonEdges() const { + return skeleton_edges; + } + + const std::vector>& getBoundaryEdges() const { + return boundary_edges; + } + + const std::vector& getPolygons() const { + return polygons; + } + + // Définissez la fonction remove_duplicate_points comme membre de la classe + void remove_duplicate_points() { + std::unordered_map point_mapping; // Map old point indices to new point indices + std::vector unique_points; // Unique points + + for (size_t i = 0; i < points.size(); ++i) { + if (point_mapping.find(i) == point_mapping.end()) { + // This is a new unique point + point_mapping[i] = unique_points.size(); + unique_points.push_back(points[i]); + } + } + + // Update cell and face data with unique point indices + for (auto& polygon : polygons) { + for (size_t i = 0; i < polygon.m_member_nodes.size(); ++i) { + size_t old_point_index = polygon.m_member_nodes[i]; + polygon.m_member_nodes[i] = point_mapping[old_point_index]; + } + + std::set> updated_edges; + for (const auto& edge : polygon.m_member_edges) { + size_t old_point1 = edge[0]; + size_t old_point2 = edge[1]; + size_t new_point1 = point_mapping[old_point1]; + size_t new_point2 = point_mapping[old_point2]; + updated_edges.insert({new_point1, new_point2}); + } + polygon.m_member_edges = updated_edges; + } + + // Update the internal mesh_reader data with the unique points + points = unique_points; + + // Update the vertices + vertices.clear(); + for (size_t i = 0; i < unique_points.size(); ++i) { + vertices.push_back(node_type()); + } + } + +}; + +#endif /* fitted_geometry_builder_hpp */ + + + diff --git a/apps/wave_propagation/src/common/linear_solver.hpp b/apps/wave_propagation/src/common/linear_solver.hpp new file mode 100644 index 00000000..7e254815 --- /dev/null +++ b/apps/wave_propagation/src/common/linear_solver.hpp @@ -0,0 +1,339 @@ +// +// linear_solver.hpp +// acoustics +// +// Created by Omar Durán on 5/2/20. +// + +#pragma once +#ifndef linear_solver_hpp +#define linear_solver_hpp + +#include "diskpp/solvers/solver.hpp" + +#ifdef HAVE_INTEL_TBB +#include +#endif + +template +class linear_solver +{ + + private: + + SparseMatrix m_Kcc; + SparseMatrix m_Kcf; + SparseMatrix m_Kfc; + SparseMatrix m_Kff; + Matrix m_Fc; + Matrix m_Ff; + + SparseMatrix m_Kcc_inv; + SparseMatrix m_K; + Matrix m_F; + + #ifdef HAVE_INTEL_MKL + PardisoLU> m_analysis; + #else + SparseLU> m_analysis; + #endif + + #ifdef HAVE_INTEL_MKL + PardisoLDLT> m_symm_analysis; + #else + SimplicialLDLT> m_symm_analysis; + #endif + + ConjugateGradient> m_analysis_cg; + BiCGSTAB,IncompleteLUT> m_analysis_bi_cg; + + size_t m_n_c_dof; + size_t m_n_f_dof; + bool m_global_sc_Q; + bool m_is_decomposed_Q; + std::pair m_iterative_solver_Q; + T m_tolerance; + + + void DecomposeK(){ + if (!m_iterative_solver_Q.first) { + if (m_iterative_solver_Q.second) { + m_symm_analysis.analyzePattern(m_K); + m_symm_analysis.factorize(m_K); + } + else{ + m_analysis.analyzePattern(m_K); + m_analysis.factorize(m_K); + } + } + } + + Matrix solve_global(Matrix & Fg){ + if (m_iterative_solver_Q.first) { + if (m_iterative_solver_Q.second) { + Matrix x_dof = m_analysis_cg.solve(Fg); + std::cout << "Number of iterations (CG): " << m_analysis_cg.iterations() << std::endl; + std::cout << "Estimated error: " << m_analysis_cg.error() << std::endl; + return x_dof; + } + else { + Matrix x_dof = m_analysis_bi_cg.solve(Fg); + std::cout << "Number of iterations (BiCG): " << m_analysis_bi_cg.iterations() << std::endl; + std::cout << "Estimated error: " << m_analysis_bi_cg.error() << std::endl; + return x_dof; + } + } + else { + if (m_iterative_solver_Q.second) { + return m_symm_analysis.solve(Fg); + }else{ + return m_analysis.solve(Fg); + } + } + } + + void scatter_segments(Matrix & Fg){ + assert(m_n_c_dof + m_n_f_dof == Fg.rows()); + m_Fc = Fg.block(0, 0, m_n_c_dof, 1); + m_Ff = Fg.block(m_n_c_dof, 0, m_n_f_dof, 1); + } + + Matrix solve_sc(Matrix & Fg){ + + // Split vector into cells and faces dofs + scatter_segments(Fg); + + // Condense vector + Matrix delta_c = m_Kcc_inv*m_Fc; + m_F = m_Ff - m_Kfc*delta_c; + + // face linear solver step + Matrix x_n_f_dof; + if (m_iterative_solver_Q.first) { + if (m_iterative_solver_Q.second) { + x_n_f_dof = m_analysis_cg.solve(m_F); + std::cout << "Number of iterations (CG): " << m_analysis_cg.iterations() << std::endl; + std::cout << "Estimated error: " << m_analysis_cg.error() << std::endl; + } + else { + // std::cout << "HERE" << std::endl; + x_n_f_dof = m_analysis_bi_cg.solve(m_F); + std::cout << bold << cyan << " Iterative solver for stage s: " << reset << std::endl; + std::cout << yellow << bold << " Number of iterations (BiCG): " << m_analysis_bi_cg.iterations() << std::endl; + std::cout << yellow << bold << " Estimated error: " << m_analysis_bi_cg.error() << std::endl; + } + } + else { + if (m_iterative_solver_Q.second) { + x_n_f_dof = m_symm_analysis.solve(m_F); + } + else { + x_n_f_dof = m_analysis.solve(m_F); + } + } + + + Matrix Kcf_x_f_dof = m_Kcf*x_n_f_dof; + Matrix delta_f = m_Kcc_inv*Kcf_x_f_dof; + Matrix x_n_c_dof = delta_c - delta_f; + + // Composing global solution + Matrix x_dof = Matrix::Zero(m_n_c_dof+m_n_f_dof,1); + x_dof.block(0, 0, m_n_c_dof, 1) = x_n_c_dof; + x_dof.block(m_n_c_dof, 0, m_n_f_dof, 1) = x_n_f_dof; + return x_dof; + + } + + void scatter_blocks(SparseMatrix & Kg){ + + m_n_c_dof = Kg.rows() - m_n_f_dof; + + // scattering matrix blocks + m_Kcc = Kg.block(0, 0, m_n_c_dof, m_n_c_dof); + m_Kcf = Kg.block(0, m_n_c_dof, m_n_c_dof, m_n_f_dof); + m_Kfc = Kg.block(m_n_c_dof,0, m_n_f_dof, m_n_c_dof); + m_Kff = Kg.block(m_n_c_dof,m_n_c_dof, m_n_f_dof, m_n_f_dof); + m_is_decomposed_Q = false; + } + + public: + + linear_solver() : m_global_sc_Q(false), m_is_decomposed_Q(false) { + m_iterative_solver_Q = std::make_pair(false,false); + } + + linear_solver(SparseMatrix & Kg) : m_K(Kg), m_global_sc_Q(false), m_is_decomposed_Q(false) { + m_iterative_solver_Q = std::make_pair(false,false); + } + + linear_solver(SparseMatrix & Kg, size_t n_f_dof) : + m_n_f_dof(n_f_dof), + m_global_sc_Q(true), + m_is_decomposed_Q(false) { + scatter_blocks(Kg); + } + + void set_Kg(SparseMatrix & Kg){ + m_global_sc_Q = false; + m_K = Kg; + } + + void set_Kg(SparseMatrix & Kg, size_t n_f_dof){ + m_global_sc_Q = true; + m_n_f_dof = n_f_dof; + scatter_blocks(Kg); + } + + void set_direct_solver(bool symmetric_matrix_Q = false){ + m_iterative_solver_Q = std::make_pair(false,symmetric_matrix_Q); + } + + void set_iterative_solver(bool symmetric_matrix_Q = false, T tolerance = 1.0e-11){ + m_iterative_solver_Q = std::make_pair(true, symmetric_matrix_Q); + m_is_decomposed_Q = true; + m_tolerance = tolerance; + } + + SparseMatrix & Kcc(){ + return m_Kcc; + } + + SparseMatrix & Kcf(){ + return m_Kcf; + } + + SparseMatrix & Kfc(){ + return m_Kfc; + } + + Matrix & Fc(){ + return m_Fc; + } + + void condense_equations(std::vector> vec_cell_basis_data){ + + if (!m_global_sc_Q) { + return; + } + + size_t nnz_cc = 0; + for (auto chunk : vec_cell_basis_data) { + nnz_cc += chunk.second*chunk.second*chunk.first; + } + std::vector< Triplet > triplets_cc; + triplets_cc.resize(nnz_cc); + m_Kcc_inv = SparseMatrix( m_n_c_dof, m_n_c_dof ); + #ifdef HAVE_INTEL_TBB + size_t stride_n_block_eq = 0; + size_t stride_n_block_l = 0; + for (auto chunk : vec_cell_basis_data) { + size_t n_cells = chunk.first; + size_t n_cbs = chunk.second; + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&triplets_cc,&n_cbs,&stride_n_block_eq,&stride_n_block_l] (size_t & cell_ind){ + + size_t stride_eq = cell_ind * n_cbs + stride_n_block_eq; + size_t stride_l = cell_ind * n_cbs * n_cbs + stride_n_block_l; + + SparseMatrix K_cc_loc = m_Kcc.block(stride_eq, stride_eq, n_cbs, n_cbs); + SparseLU> analysis_cc; + analysis_cc.analyzePattern(K_cc_loc); + analysis_cc.factorize(K_cc_loc); + Matrix K_cc_inv_loc = analysis_cc.solve(Matrix::Identity(n_cbs, n_cbs)); + + size_t l = 0; + for (size_t i = 0; i < K_cc_inv_loc.rows(); i++) + { + for (size_t j = 0; j < K_cc_inv_loc.cols(); j++) + { + triplets_cc[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, K_cc_inv_loc(i,j)); + l++; + } + } + } + ); + stride_n_block_eq += n_cells * n_cbs; + stride_n_block_l += n_cells * n_cbs * n_cbs; + } + #else + + size_t stride_n_block_eq = 0; + size_t stride_n_block_l = 0; + for (auto chunk : vec_cell_basis_data) { + size_t n_cells = chunk.first; + size_t n_cbs = chunk.second; + for (size_t cell_ind = 0; cell_ind < n_cells; cell_ind++) { + + size_t stride_eq = cell_ind * n_cbs + stride_n_block_eq; + size_t stride_l = cell_ind * n_cbs * n_cbs + stride_n_block_l; + + SparseMatrix K_cc_loc = m_Kcc.block(stride_eq, stride_eq, n_cbs, n_cbs); + SparseLU> analysis_cc; + analysis_cc.analyzePattern(K_cc_loc); + analysis_cc.factorize(K_cc_loc); + Matrix K_cc_inv_loc = analysis_cc.solve(Matrix::Identity(n_cbs, n_cbs)); + + size_t l = 0; + for (size_t i = 0; i < K_cc_inv_loc.rows(); i++) { + for (size_t j = 0; j < K_cc_inv_loc.cols(); j++) { + triplets_cc[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, K_cc_inv_loc(i,j)); + l++; + } + } + + } + stride_n_block_eq += n_cells * n_cbs; + stride_n_block_l += n_cells * n_cbs * n_cbs; + } + #endif + + m_Kcc_inv.setFromTriplets( triplets_cc.begin(), triplets_cc.end() ); + triplets_cc.clear(); + m_K = m_Kff - m_Kfc*m_Kcc_inv*m_Kcf; + m_is_decomposed_Q = false; + return; + + } + + void condense_equations(std::pair cell_basis_data){ + std::vector> vec_cell_basis_data(1); + vec_cell_basis_data[0] = cell_basis_data; + condense_equations(vec_cell_basis_data); + } + + void factorize(){ + if (m_is_decomposed_Q) { + if (m_iterative_solver_Q.first) { + if (m_iterative_solver_Q.second) { + m_analysis_cg.compute(m_K); + m_analysis_cg.setTolerance(m_tolerance); + m_analysis_cg.setMaxIterations(m_K.rows()); + }else{ + m_analysis_bi_cg.compute(m_K); + m_analysis_bi_cg.setTolerance(m_tolerance); + m_analysis_bi_cg.setMaxIterations(m_K.rows()); + } + } + return; + } + DecomposeK(); + m_is_decomposed_Q = true; + } + + size_t n_equations(){ + size_t n_equations = m_K.rows(); + return n_equations; + } + + Matrix solve(Matrix & Fg){ + if (m_global_sc_Q) + return solve_sc(Fg); + else + return solve_global(Fg); + } + + +}; + +#endif /* linear_solver_hpp */ diff --git a/apps/wave_propagation/src/common/lsrk_butcher_tableau.hpp b/apps/wave_propagation/src/common/lsrk_butcher_tableau.hpp new file mode 100644 index 00000000..a019f86a --- /dev/null +++ b/apps/wave_propagation/src/common/lsrk_butcher_tableau.hpp @@ -0,0 +1,79 @@ +// +// lsrk_butcher_tableau.hpp +// acoustics +// +// Created by Omar Durán on 4/25/20. +// + +#ifndef lsrk_butcher_tableau_hpp +#define lsrk_butcher_tableau_hpp + +#include + +class lsrk_butcher_tableau +{ + public: + + static void lsrk_tables(int s, Matrix &a, Matrix &b, Matrix &c){ + + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, 1); + c = Matrix::Zero(s, 1); + + + // Nodal Discontinuous Galerkin Methods + // Fourth-order 2n-storage Runge- Kutta schemes + switch (s) { + case 1: + { + a(0,0) = 0.0; + b(0,0) = 1.0; + c(0,0) = 1.0; + } + break; + case 2: + { + a(0,0) = 1.0/3.0; + a(1,0) = 3.0/4.0; + a(1,1) = 1.0/4.0; + + b(0,0) = 3.0/4.0; + b(1,0) = 1.0/4.0; + + c(0,0) = 1.0/3.0; + c(1,0) = 1.0; + + } + break; + case 3: + { + + a(0,0) = 1.0; + a(1,0) = -1.0/12.0; + a(1,1) = 5.0/12.0; + a(2,0) = 0.0; + a(2,1) = 3.0/4.0; + a(2,2) = 1.0/4.0; + + b(0,0) = 0.0; + b(1,0) = 3.0/4.0; + b(2,0) = 3.0/4.0; + + c(0,0) = 1.0; + c(1,0) = 1.0/3.0; + c(2,0) = 1.0; + + } + break; + default: + { + std::cout << "Error:: Method not implemented." << std::endl; + } + break; + } + + } + +}; + +#endif /* lsrk_butcher_tableau_hpp */ diff --git a/apps/wave_propagation/src/common/postprocessor.hpp b/apps/wave_propagation/src/common/postprocessor.hpp new file mode 100644 index 00000000..b978e673 --- /dev/null +++ b/apps/wave_propagation/src/common/postprocessor.hpp @@ -0,0 +1,3449 @@ + // +// postprocessor.hpp +// acoustics +// +// Created by Omar Durán on 4/10/20. +// + +#pragma once +#ifndef postprocessor_hpp +#define postprocessor_hpp + +#include +#include "../common/acoustic_one_field_assembler.hpp" +#include "../common/acoustic_two_fields_assembler.hpp" +#include "../common/elastodynamic_one_field_assembler.hpp" +#include "../common/elastodynamic_two_fields_assembler.hpp" +#include "../common/elastodynamic_three_fields_assembler.hpp" +#include "../common/elastoacoustic_two_fields_assembler.hpp" +#include "../common/elastoacoustic_four_fields_assembler.hpp" +#include "diskpp/bases/bases.hpp" + +#ifdef HAVE_INTEL_TBB +#include +#endif + +// using namespace priv; +// namespace priv +// { +template +class postprocessor { + +public: + + // FIND CELLS & PICK CELLS & MESH QUALITY + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + static std::set find_cells(typename Mesh::point_type & pt, Mesh & msh, bool verbose_Q = false) { + + using RealType = double; + auto norm = [](const typename Mesh::point_type& a, const typename Mesh::point_type& b ) -> RealType { + RealType dx = (b.x() - a.x()); + RealType dy = (b.y() - a.y()); + RealType norm = std::sqrt(dx*dx + dy*dy); + return norm; + }; + + // find minimum distance to the requested point + size_t np = msh.points_size(); + std::vector distances(np); + + size_t ip = 0; + for (auto& point : msh.backend_storage()->points) { + RealType dist = norm(pt,point); + distances[ip] = dist; + ip++; + } + + size_t index = std::min_element(distances.begin(),distances.end()) - distances.begin(); + if(verbose_Q){ + RealType min_dist = *std::min_element(distances.begin(), distances.end()); + typename Mesh::point_type nearest_point = msh.backend_storage()->points.at(index); + } + + std::set cell_indexes; + size_t cell_i = 0; + for (auto& cell : msh) { + auto points = cell.point_ids(); + size_t n_p = points.size(); + for (size_t l = 0; l < n_p; l++) { + auto pt_id = points[l]; + if (index == pt_id) + cell_indexes.insert(cell_i); + } + cell_i++; + } + + if(verbose_Q){ + // std::cout << "Detected cells indexes : " << std::endl; + for(auto index : cell_indexes){ + // std::cout << index << std::endl; + } + } + + return cell_indexes; + } + + static std::set find_elastic_cells(typename Mesh::point_type & pt, Mesh & msh, bool verbose_Q = false) { + + using RealType = double; + auto norm = [](const typename Mesh::point_type& a, const typename Mesh::point_type& b) -> RealType { + RealType dx = (b.x() - a.x()); + RealType dy = (b.y() - a.y()); + return std::sqrt(dx * dx + dy * dy); + }; + + // Trouver le point du maillage le plus proche + size_t np = msh.points_size(); + std::vector distances(np); + + size_t ip = 0; + for (auto& point : msh.backend_storage()->points) { + distances[ip] = norm(pt, point); + ip++; + } + + size_t index = std::min_element(distances.begin(), distances.end()) - distances.begin(); + + if (verbose_Q) { + RealType min_dist = *std::min_element(distances.begin(), distances.end()); + typename Mesh::point_type nearest_point = msh.backend_storage()->points.at(index); + } + + std::set cell_indexes; + size_t cell_i = 0; + for (auto& cell : msh) { + auto points = cell.point_ids(); + size_t n_p = points.size(); + + for (size_t l = 0; l < n_p; l++) { + if (index == points[l]) { + auto bar = barycenter(msh, cell); + if (bar.y() <= 0.0) + cell_indexes.insert(cell_i); + } + } + cell_i++; + } + return cell_indexes; + } + + static std::set find_acoustic_cells(typename Mesh::point_type & pt, Mesh & msh, bool verbose_Q = false) { + + using RealType = double; + auto norm = [](const typename Mesh::point_type& a, const typename Mesh::point_type& b) -> RealType { + RealType dx = (b.x() - a.x()); + RealType dy = (b.y() - a.y()); + return std::sqrt(dx * dx + dy * dy); + }; + + // Trouver le point du maillage le plus proche + size_t np = msh.points_size(); + std::vector distances(np); + + size_t ip = 0; + for (auto& point : msh.backend_storage()->points) { + distances[ip] = norm(pt, point); + ip++; + } + + size_t index = std::min_element(distances.begin(), distances.end()) - distances.begin(); + + if (verbose_Q) { + RealType min_dist = *std::min_element(distances.begin(), distances.end()); + typename Mesh::point_type nearest_point = msh.backend_storage()->points.at(index); + } + + std::set cell_indexes; + size_t cell_i = 0; + for (auto& cell : msh) { + auto points = cell.point_ids(); + size_t n_p = points.size(); + + for (size_t l = 0; l < n_p; l++) { + if (index == points[l]) { + auto bar = barycenter(msh, cell); + if (bar.y() >= 0) + cell_indexes.insert(cell_i); + } + } + cell_i++; + } + + return cell_indexes; + } + + static void mesh_quality(Mesh & msh, elastoacoustic_four_fields_assembler & assembler,std::ostream & mesh_file = std::cout){ + + using RealType = double; + auto dim = Mesh::dimension; + + RealType o_to_ten = 0.0; + RealType ten_to_twenty = 0.0; + RealType twenty_to_thirty = 0.0; + RealType thirty_to_forty = 0.0; + RealType forty_to_fifty = 0.0; + RealType fifty_to_sixty = 0.0; + RealType sixty_to_seventy = 0.0; + RealType seventy_to_eighty = 0.0; + RealType eighty_to_ninety = 0.0; + RealType ninety_to_hundred = 0.0; + + // Determination h + RealType h = 10.0; + auto storage = msh.backend_storage(); + for (auto& e_chunk : assembler.get_e_material_data()) { + auto& cell = storage->surfaces[e_chunk.first]; + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + for (auto& a_chunk : assembler.get_a_material_data()) { + auto& cell = storage->surfaces[a_chunk.first]; + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + // Determination of small edges + RealType nb_faces = 0.0; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++){ + const auto face = *face_it; + auto pts = points(msh, face); + RealType longueur = (pts[1] - pts[0]).to_vector().norm(); + if (longueur <= 1.e-1*h) { + o_to_ten++; + } else if (longueur <= 2e-1*h) { + ten_to_twenty++; + } else if (longueur <= 3e-1*h) { + twenty_to_thirty++; + } else if (longueur <= 4e-1*h) { + thirty_to_forty++; + } else if (longueur <= 5e-1*h) { + forty_to_fifty++; + } else if (longueur <= 6e-1*h) { + fifty_to_sixty++; + } else if (longueur <= 7e-1*h) { + sixty_to_seventy++; + } else if (longueur <= 8e-1*h) { + seventy_to_eighty++; + } else if (longueur <= 9e-1*h) { + eighty_to_ninety++; + } else { + ninety_to_hundred++; + } + nb_faces++; + } + // Number of faces + mesh_file << "Number of faces: " << nb_faces << std::endl<< std::endl; + + mesh_file << " ratio <= 10% : " << " " << o_to_ten << std::endl; + mesh_file << "10% < ratio <= 20% : " << " " << ten_to_twenty << std::endl; + mesh_file << "20% < ratio <= 30% : " << " " << twenty_to_thirty << std::endl; + mesh_file << "30% < ratio <= 40% : " << " " << thirty_to_forty << std::endl; + mesh_file << "40% < ratio <= 50% : " << " " << forty_to_fifty << std::endl; + mesh_file << "50% < ratio <= 60% : " << " " << fifty_to_sixty << std::endl; + mesh_file << "60% < ratio <= 70% : " << " " << sixty_to_seventy << std::endl; + mesh_file << "70% < ratio <= 80% : " << " " << seventy_to_eighty << std::endl; + mesh_file << "80% < ratio <= 90% : " << " " << eighty_to_ninety << std::endl; + mesh_file << "90% < ratio <= 100%: " << " " << ninety_to_hundred << std::endl; + + RealType prct_o_to_ten = o_to_ten/nb_faces; + RealType prct_ten_to_twenty = ten_to_twenty/nb_faces; + RealType prct_twenty_to_thirty = twenty_to_thirty/nb_faces; + RealType prct_thirty_to_forty = thirty_to_forty/nb_faces; + RealType prct_forty_to_fifty = forty_to_fifty/nb_faces; + RealType prct_fifty_to_sixty = fifty_to_sixty/nb_faces; + RealType prct_sixty_to_seventy = sixty_to_seventy/nb_faces; + RealType prct_seventy_to_eighty = seventy_to_eighty/nb_faces; + RealType prct_eighty_to_ninety = eighty_to_ninety/nb_faces; + RealType prct_ninety_to_hundred = ninety_to_hundred/nb_faces; + + // Percentage of faces + mesh_file << "Percentage: " << std::endl; + mesh_file << " ratio <= 10% : " << " " << prct_o_to_ten << std::endl; + mesh_file << "10% < ratio <= 20% : " << " " << prct_ten_to_twenty << std::endl; + mesh_file << "20% < ratio <= 30% : " << " " << prct_twenty_to_thirty << std::endl; + mesh_file << "30% < ratio <= 40% : " << " " << prct_thirty_to_forty << std::endl; + mesh_file << "40% < ratio <= 50% : " << " " << prct_forty_to_fifty << std::endl; + mesh_file << "50% < ratio <= 60% : " << " " << prct_fifty_to_sixty << std::endl; + mesh_file << "60% < ratio <= 70% : " << " " << prct_sixty_to_seventy << std::endl; + mesh_file << "70% < ratio <= 80% : " << " " << prct_seventy_to_eighty << std::endl; + mesh_file << "80% < ratio <= 90% : " << " " << prct_eighty_to_ninety << std::endl; + mesh_file << "90% < ratio <= 100%: " << " " << prct_ninety_to_hundred << std::endl; + RealType total = prct_o_to_ten + prct_ten_to_twenty + prct_twenty_to_thirty + prct_thirty_to_forty + prct_forty_to_fifty + prct_fifty_to_sixty + prct_sixty_to_seventy + prct_seventy_to_eighty + prct_eighty_to_ninety + prct_ninety_to_hundred; + mesh_file << " TOTAL: " << " " << total << std::endl << std::endl; + + } + + static size_t pick_cell(typename Mesh::point_type & pt, Mesh & msh, std::set & cell_indexes, bool verbose_Q = false){ + + using RealType = double; + + auto triangle_member_Q = [] (typename Mesh::point_type & p, typename Mesh::point_type & p0, typename Mesh::point_type & p1, typename Mesh::point_type & p2) { + RealType dx = p.x()-p2.x(); + RealType dy = p.y()-p2.y(); + RealType dx21 = p2.x()-p1.x(); + RealType dy12 = p1.y()-p2.y(); + RealType d = dy12*(p0.x()-p2.x()) + dx21*(p0.y()-p2.y()); + RealType s = dy12*dx + dx21*dy; + RealType t = (p2.y()-p0.y())*dx + (p0.x()-p2.x())*dy; + if (d < 0.0) { + return s<=0.0 && t<=0.0 && s+t>=d; + } + return s>=0 && t>=0 && s+t<=d; + }; + + size_t n_cells = cell_indexes.size(); + if (n_cells == 1) { + size_t first_index = *cell_indexes.begin(); + return first_index; + } + bool is_member_Q = false; + for(auto index : cell_indexes){ + auto& cell = msh.backend_storage()->surfaces[index]; + auto bar = barycenter(msh, cell); + auto points = cell.point_ids(); + size_t n_p = points.size(); + + // building teselation + std::vector> triangles(n_p); + for (size_t l = 0; l < n_p; l++) { + std::vector chunk(3); + if( l == n_p - 1){ + chunk[0] = msh.backend_storage()->points.at(points[l]); + chunk[1] = msh.backend_storage()->points.at(points[0]); + chunk[2] = bar; + } + else { + chunk[0] = msh.backend_storage()->points.at(points[l]); + chunk[1] = msh.backend_storage()->points.at(points[l+1]); + chunk[2] = bar; + } + triangles[l] = chunk; + } + // check whether the point is memeber of any triangle + for (auto triangle : triangles) { + is_member_Q = triangle_member_Q(pt,triangle[0],triangle[1],triangle[2]); + if (is_member_Q) { + // std::cout << "Detected cell index = " << index << std::endl; + return index; + } + } + + } + + if(!is_member_Q){ + if(verbose_Q){ + std::cout << "Point is not member of cells set. Returning cell_indexes[0] " << std::endl; + } + size_t first_index = *cell_indexes.begin(); + return first_index; + } + + return -1; + } + + // COMPUTE ERRORS UNCOUPLED PROBLEM + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + /// Compute L2 and H1 errors for one field approximation + static void compute_errors_one_field(Mesh & msh, disk::hho_degree_info & hho_di, acoustic_one_field_assembler & assembler, Matrix & x_dof,std::function scal_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + size_t cell_dof = disk::scalar_basis_size(hho_di.cell_degree(), dim); + + RealType scalar_l2_error = 0.0; + RealType flux_l2_error = 0.0; + size_t cell_i = 0; + RealType h = 10.0; + for (auto& cell : msh) + { + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + + Matrix scalar_cell_dof = x_dof.block(cell_i*cell_dof, 0, cell_dof, 1); + + // scalar evaluation + { + auto cell_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix mass = make_mass_matrix(msh, cell, cell_basis, hho_di.cell_degree()); + Matrix rhs = make_rhs(msh, cell, cell_basis, scal_fun); + Matrix real_dofs = mass.llt().solve(rhs); + Matrix diff = real_dofs - scalar_cell_dof; + scalar_l2_error += diff.dot(mass*diff); + + } + + // flux evaluation + { + auto int_rule = integrate(msh, cell, 2*(hho_di.cell_degree()+1)); + auto rec_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + auto gr = make_scalar_hho_laplacian(msh, cell, hho_di); + Matrix all_dofs = assembler.gather_dof_data(msh, cell, x_dof); + Matrix recdofs = gr.first * all_dofs; + + // Error integrals + for (auto & point_pair : int_rule) { + + RealType omega = point_pair.weight(); + auto t_dphi = rec_basis.eval_gradients( point_pair.point() ); + Matrix grad_uh = Matrix::Zero(); + + for (size_t i = 1; i < t_dphi.rows(); i++){ + grad_uh = grad_uh + recdofs(i-1)*t_dphi.block(i, 0, 1, 2); + } + + Matrix grad_u_exact = Matrix::Zero(); + grad_u_exact(0,0) = flux_fun(point_pair.point())[0]; + grad_u_exact(0,1) = flux_fun(point_pair.point())[1]; + flux_l2_error += omega * (grad_u_exact - grad_uh).dot(grad_u_exact - grad_uh); + + } + } + + cell_i++; + } + tc.toc(); + std::cout << bold << cyan << "Error completed: " << tc << " seconds" << reset << std::endl; + error_file << "Characteristic h size = " << std::setprecision(16) << h << std::endl; + error_file << "L2-norm error = " << std::setprecision(16) << std::sqrt(scalar_l2_error) << std::endl; + error_file << "H1-norm error = " << std::setprecision(16) << std::sqrt(flux_l2_error) << std::endl; + error_file << std::endl; + error_file.flush(); + + + } + + /// Compute L2 and H1 errors for two fields approximation + static void compute_errors_two_fields(Mesh & msh, disk::hho_degree_info & hho_di, acoustic_two_fields_assembler & assembler, Matrix & x_dof,std::function scal_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout, bool recons_error_Q = false){ + + timecounter tc; + tc.tic(); + + using RealType = double; + size_t n_scal_dof = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_dof = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t cell_dof = n_scal_dof + n_vec_dof; + + RealType scalar_l2_error = 0.0; + RealType flux_l2_error = 0.0; + size_t cell_i = 0; + RealType h = 10.0; + for (auto& cell : msh) + { + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + + // scalar evaluation + if(recons_error_Q){ + auto rec_cell_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + auto gr = make_scalar_hho_laplacian(msh, cell, hho_di); + Matrix all_dofs = assembler.gather_dof_data(msh, cell, x_dof); + size_t n_cell_dof = all_dofs.rows() - n_vec_dof; + + Matrix cell_dofs = all_dofs.block(n_vec_dof, 0, n_cell_dof, 1); + Matrix rec_scalar_cell_dof = gr.first * cell_dofs; + + size_t n_rbs = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension); + Matrix rec_scalar_dof = Matrix::Zero(n_rbs, 1); + + rec_scalar_dof(0, 0) = cell_dofs(0, 0); // The constant is the same. + rec_scalar_dof.block(1, 0, n_rbs-1, 1) = rec_scalar_cell_dof; + + + Matrix mass = make_mass_matrix(msh, cell, rec_cell_basis, hho_di.reconstruction_degree()); + Matrix rhs = make_rhs(msh, cell, rec_cell_basis, scal_fun, 1); + Matrix real_dofs = mass.llt().solve(rhs); + Matrix diff = real_dofs - rec_scalar_dof; + scalar_l2_error += diff.dot(mass*diff); + }else{ + auto cell_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix scalar_cell_dof = x_dof.block(cell_i*cell_dof+n_vec_dof, 0, n_scal_dof, 1); + Matrix mass = make_mass_matrix(msh, cell, cell_basis, hho_di.cell_degree()); + Matrix rhs = make_rhs(msh, cell, cell_basis, scal_fun); + Matrix real_dofs = mass.llt().solve(rhs); + + Matrix diff = real_dofs - scalar_cell_dof; + scalar_l2_error += diff.dot(mass*diff); + } + + // flux evaluation + { + auto int_rule = integrate(msh, cell, 2*(hho_di.cell_degree()+1)); + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + Matrix flux_cell_dof = x_dof.block(cell_i*cell_dof, 0, n_vec_dof, 1); + + // Error integrals + for (auto & point_pair : int_rule) { + + RealType omega = point_pair.weight(); + auto t_dphi = cell_basis.eval_gradients( point_pair.point() ); + + Matrix grad_uh = Matrix::Zero(); + for (size_t i = 1; i < t_dphi.rows(); i++){ + grad_uh = grad_uh + flux_cell_dof(i-1)*t_dphi.block(i, 0, 1, 2); + } + + Matrix grad_u_exact = Matrix::Zero(); + grad_u_exact(0,0) = flux_fun(point_pair.point())[0]; + grad_u_exact(0,1) = flux_fun(point_pair.point())[1]; + flux_l2_error += omega * (grad_u_exact - grad_uh).dot(grad_u_exact - grad_uh); + + } + } + + cell_i++; + } + tc.toc(); + + std::cout << bold << cyan << "Error completed: " << tc << " seconds" << reset << std::endl; + error_file << "Characteristic h size = " << std::setprecision(16) << h << std::endl; + error_file << "L2-norm error = " << std::setprecision(16) << std::sqrt(scalar_l2_error) << std::endl; + error_file << "H1-norm error = " << std::setprecision(16) << std::sqrt(flux_l2_error) << std::endl; + error_file << std::endl; + error_file.flush(); + + } + + /// Compute L2 and H1 errors for one field vectorial approximation + static void compute_errors_one_field_vectorial(Mesh & msh, disk::hho_degree_info & hho_di, elastodynamic_one_field_assembler & assembler, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + size_t cell_dof = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + + RealType vector_l2_error = 0.0; + RealType flux_l2_error = 0.0; + RealType h = 10.0; + size_t cell_ind = 0; + for (auto& cell : msh) + { + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + + Matrix vec_cell_dof = x_dof.block(cell_ind*cell_dof, 0, cell_dof, 1); + + // scalar evaluation + { + auto cell_basis = disk::make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix mass = make_mass_matrix(msh, cell, cell_basis, hho_di.cell_degree()); + Matrix rhs = make_rhs(msh, cell, cell_basis, vec_fun); + Matrix real_dofs = mass.llt().solve(rhs); + Matrix diff = real_dofs - vec_cell_dof; + vector_l2_error += diff.dot(mass*diff); + + } + + elastic_material_data material = assembler.get_material_data()[cell_ind]; + RealType mu = material.rho()*material.vs()*material.vs(); + RealType lambda = material.rho()*material.vp()*material.vp() - 2.0*mu; + + // flux evaluation + { + auto int_rule = integrate(msh, cell, 2*(hho_di.cell_degree()+1)); + Matrix all_dofs = assembler.gather_dof_data(msh, cell, x_dof); + + auto sgr = make_vector_hho_symmetric_laplacian(msh, cell, hho_di); + dynamic_vector GTu = sgr.first * all_dofs; + + auto dr = make_hho_divergence_reconstruction(msh, cell, hho_di); + dynamic_vector divu = dr.first * all_dofs; + + auto cbas_v = disk::make_vector_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + auto cbas_s = disk::make_scalar_monomial_basis(msh, cell, hho_di.face_degree()); + + auto rec_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + + // Error integrals + for (auto & point_pair : int_rule) { + + RealType omega = point_pair.weight(); + + auto t_dphi = rec_basis.eval_gradients( point_pair.point() ); + auto gphi = cbas_v.eval_sgradients(point_pair.point()); + auto epsilon = disk::eval(GTu, gphi, dim); + auto divphi = cbas_s.eval_functions(point_pair.point()); + auto trace_epsilon = disk::eval(divu, divphi); + auto sigma = 2.0 * mu * epsilon + lambda * trace_epsilon * static_matrix::Identity(); + auto flux_diff = (flux_fun(point_pair.point()) - sigma).eval(); + flux_l2_error += omega * flux_diff.squaredNorm(); + + } + } + + cell_ind++; + } + tc.toc(); + std::cout << bold << cyan << "Error completed: " << tc << " seconds" << reset << std::endl; + error_file << "Characteristic h size = " << std::setprecision(16) << h << std::endl; + error_file << "L2-norm error = " << std::setprecision(16) << std::sqrt(vector_l2_error) << std::endl; + error_file << "H1-norm error = " << std::setprecision(16) << std::sqrt(flux_l2_error) << std::endl; + error_file << std::endl; + error_file.flush(); + + + } + + /// Compute L2 and H1 errors for two fields vectorial approximation + static void compute_errors_two_fields_vectorial(Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), dim, dim); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + size_t cell_dof = n_ten_cbs + n_vec_cbs; + + RealType vector_l2_error = 0.0; + RealType flux_l2_error = 0.0; + size_t cell_i = 0; + RealType h = 10.0; + for (auto& cell : msh) + { + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + + Matrix vec_cell_dof = x_dof.block(cell_i*cell_dof+n_ten_cbs, 0, n_vec_cbs, 1); + + // vector evaluation + { + auto cell_basis = disk::make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix mass = make_mass_matrix(msh, cell, cell_basis, hho_di.cell_degree()); + Matrix rhs = make_rhs(msh, cell, cell_basis, vec_fun); + Matrix real_dofs = mass.llt().solve(rhs); + Matrix diff = real_dofs - vec_cell_dof; + vector_l2_error += diff.dot(mass*diff); + + } + + + // tensor evaluation + { + auto int_rule = integrate(msh, cell, 2*(hho_di.cell_degree()+1)); + + auto ten_basis = make_sym_matrix_monomial_basis(msh, cell, hho_di.grad_degree()); + Matrix ten_x_cell_dof = x_dof.block(cell_i*cell_dof, 0, n_ten_cbs, 1); + + // Error integrals + for (auto & point_pair : int_rule) { + + RealType omega = point_pair.weight(); + + auto t_ten_phi = ten_basis.eval_functions( point_pair.point() ); + assert(t_ten_phi.size() == ten_basis.size()); + auto sigma_h = disk::eval(ten_x_cell_dof, t_ten_phi); + + auto flux_diff = (flux_fun(point_pair.point()) - sigma_h).eval(); + flux_l2_error += omega * flux_diff.squaredNorm(); + + } + + } + + cell_i++; + } + tc.toc(); + std::cout << bold << cyan << "Error completed: " << tc << " seconds" << reset << std::endl; + error_file << "Characteristic h size = " << std::setprecision(16) << h << std::endl; + error_file << "L2-norm error = " << std::setprecision(16) << std::sqrt(vector_l2_error) << std::endl; + error_file << "H1-norm error = " << std::setprecision(16) << std::sqrt(flux_l2_error) << std::endl; + error_file << std::endl; + error_file.flush(); + + } + + /// Compute L2 and H1 errors for three fields vectorial approximation + static void compute_errors_three_fields_vectorial(Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), dim, dim); + size_t n_sca_cbs = disk::scalar_basis_size(hho_di.face_degree(), dim); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + size_t cell_dof = n_ten_cbs + n_sca_cbs + n_vec_cbs; + + RealType vector_l2_error = 0.0; + RealType flux_l2_error = 0.0; + size_t cell_i = 0; + RealType h = 10.0; + for (auto& cell : msh) + { + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + + Matrix vec_cell_dof = x_dof.block(cell_i*cell_dof+n_ten_cbs+n_sca_cbs, 0, n_vec_cbs, 1); + + // vector evaluation + { + auto cell_basis = disk::make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix mass = make_mass_matrix(msh, cell, cell_basis, hho_di.cell_degree()); + Matrix rhs = make_rhs(msh, cell, cell_basis, vec_fun); + Matrix real_dofs = mass.llt().solve(rhs); + Matrix diff = real_dofs - vec_cell_dof; + vector_l2_error += diff.dot(mass*diff); + + } + + // tensor evaluation + { + auto int_rule = integrate(msh, cell, 2*(hho_di.cell_degree()+1)); + + auto ten_basis = make_sym_matrix_monomial_basis(msh, cell, hho_di.grad_degree()); + Matrix ten_x_cell_dof = x_dof.block(cell_i*cell_dof, 0, n_ten_cbs, 1); + + auto sca_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.face_degree()); + Matrix sigma_v_x_cell_dof = x_dof.block(cell_i*cell_dof+n_ten_cbs, 0, n_sca_cbs, 1); + + // Error integrals + for (auto & point_pair : int_rule) { + + RealType omega = point_pair.weight(); + + auto t_ten_phi = ten_basis.eval_functions( point_pair.point() ); + assert(t_ten_phi.size() == ten_basis.size()); + auto sigma_h = disk::eval(ten_x_cell_dof, t_ten_phi); + + auto t_sca_phi = sca_basis.eval_functions( point_pair.point() ); + assert(t_sca_phi.size() == sca_basis.size()); + auto sigma_v_h = disk::eval(sigma_v_x_cell_dof, t_sca_phi); + + sigma_h += sigma_v_h * static_matrix::Identity(); + + auto flux_diff = (flux_fun(point_pair.point()) - sigma_h).eval(); + flux_l2_error += omega * flux_diff.squaredNorm(); + + } + + } + + cell_i++; + } + tc.toc(); + std::cout << bold << cyan << "Error completed: " << tc << " seconds" << reset << std::endl; + error_file << "Characteristic h size = " << std::setprecision(16) << h << std::endl; + error_file << "L2-norm error = " << std::setprecision(16) << std::sqrt(vector_l2_error) << std::endl; + error_file << "H1-norm error = " << std::setprecision(16) << std::sqrt(flux_l2_error) << std::endl; + error_file << std::endl; + error_file.flush(); + + } + + // COMPUTE ENERGY UNCOUPLED PROBLEM + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + /// Compute the discrete acoustic energy for one field approximation + static double compute_acoustic_energy_one_field(Mesh & msh, disk::hho_degree_info & hho_di, acoustic_one_field_assembler & assembler, double & time, Matrix & p_dof, Matrix & v_dof, std::ostream & energy_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + size_t cell_dof = disk::scalar_basis_size(hho_di.cell_degree(), dim); + + std::vector energy_vec(msh.cells_size()); + #ifdef HAVE_INTEL_TBB + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [&msh,&assembler,&energy_vec,&p_dof,&v_dof,&cell_dof] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix mass_matrix = assembler.mass_operator(cell_ind, msh, cell); + Matrix cell_alpha_dof_n_v = v_dof.block(cell_ind*cell_dof, 0, cell_dof, 1); + Matrix cell_mass_tested = mass_matrix * cell_alpha_dof_n_v; + Matrix term_1 = cell_alpha_dof_n_v.transpose() * cell_mass_tested; + + energy_vec[cell_ind] = term_1(0,0); + + Matrix laplacian_loc = assembler.laplacian_operator(cell_ind, msh, cell); + Matrix cell_p_dofs = assembler.gather_dof_data(msh, cell, p_dof); + Matrix cell_stiff_tested = laplacian_loc * cell_p_dofs; + Matrix term_2 = cell_p_dofs.transpose() * cell_stiff_tested; + + energy_vec[cell_ind] += term_2(0,0); + } + ); + #else + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + + Matrix mass_matrix = assembler.mass_operator(cell_ind, msh, cell); + Matrix cell_alpha_dof_n_v = v_dof.block(cell_ind*cell_dof, 0, cell_dof, 1); + Matrix cell_mass_tested = mass_matrix * cell_alpha_dof_n_v; + Matrix term_1 = cell_alpha_dof_n_v.transpose() * cell_mass_tested; + + energy_vec[cell_ind] = term_1(0,0); + + Matrix laplacian_loc = assembler.laplacian_operator(cell_ind, msh, cell); + Matrix cell_p_dofs = assembler.gather_dof_data(msh, cell, p_dof); + Matrix cell_stiff_tested = laplacian_loc * cell_p_dofs; + Matrix term_2 = cell_p_dofs.transpose() * cell_stiff_tested; + + energy_vec[cell_ind] += term_2(0,0); + + } + #endif + + RealType energy_h = std::accumulate(energy_vec.begin(), energy_vec.end(),0.0); + energy_h *= 0.5; + + tc.toc(); + std::cout << bold << cyan << "Energy completed: " << tc << " seconds" << reset << std::endl; + energy_file << time << " " << std::setprecision(16) << energy_h << std::endl; + return energy_h; + } + + /// Compute the discrete acoustic energy for one field approximation + static double compute_acoustic_energy_two_fields(Mesh & msh, disk::hho_degree_info & hho_di, acoustic_two_fields_assembler & assembler, double & time, Matrix & x_dof, std::ostream & energy_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + size_t n_scal_cbs = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_cbs = n_scal_cbs + n_vec_cbs; + + std::vector energy_vec(msh.cells_size()); + #ifdef HAVE_INTEL_TBB + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [&msh,&assembler,&energy_vec,&x_dof,&n_cbs] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix mass_matrix = assembler.mass_operator(cell_ind, msh, cell); + Matrix cell_dof = x_dof.block(cell_ind*n_cbs, 0, n_cbs, 1); + Matrix cell_mass_tested = mass_matrix * cell_dof; + Matrix term = cell_dof.transpose() * cell_mass_tested; + energy_vec[cell_ind] = term(0,0); + } + ); + #else + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + + Matrix mass_matrix = assembler.mass_operator(cell_ind, msh, cell); + Matrix cell_dof = x_dof.block(cell_ind*n_cbs, 0, n_cbs, 1); + Matrix cell_mass_tested = mass_matrix * cell_dof; + Matrix term = cell_dof.transpose() * cell_mass_tested; + + energy_vec[cell_ind] = term(0,0); + + } + #endif + + RealType energy_h = std::accumulate(energy_vec.begin(), energy_vec.end(),0.0); + energy_h *= 0.5; + + tc.toc(); + std::cout << bold << cyan << "Energy completed: " << tc << " seconds" << reset << std::endl; + energy_file << time << " " << std::setprecision(16) << energy_h << std::endl; + + return energy_h; + } + + /// Compute the discrete elastic energy for one field approximation + static double compute_elastic_energy_one_field(Mesh & msh, disk::hho_degree_info & hho_di, elastodynamic_one_field_assembler & assembler, double & time, Matrix & u_dof, Matrix & v_dof, std::ostream & energy_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + size_t cell_dof = disk::vector_basis_size(hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + + std::vector energy_vec(msh.cells_size()); + #ifdef HAVE_INTEL_TBB + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [&msh,&assembler,&energy_vec,&u_dof,&v_dof,&cell_dof] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix mass_matrix = assembler.mass_operator(cell_ind, msh, cell); + Matrix cell_alpha_dof_n_v = v_dof.block(cell_ind*cell_dof, 0, cell_dof, 1); + Matrix cell_mass_tested = mass_matrix * cell_alpha_dof_n_v; + Matrix term_1 = cell_alpha_dof_n_v.transpose() * cell_mass_tested; + + energy_vec[cell_ind] = term_1(0,0); + + Matrix laplacian_loc = assembler.laplacian_operator(cell_ind, msh, cell); + Matrix cell_p_dofs = assembler.gather_dof_data(msh, cell, u_dof); + Matrix cell_stiff_tested = laplacian_loc * cell_p_dofs; + Matrix term_2 = cell_p_dofs.transpose() * cell_stiff_tested; + + energy_vec[cell_ind] += term_2(0,0); + } + ); + #else + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + + Matrix mass_matrix = assembler.mass_operator(cell_ind, msh, cell); + Matrix cell_alpha_dof_n_v = v_dof.block(cell_ind*cell_dof, 0, cell_dof, 1); + Matrix cell_mass_tested = mass_matrix * cell_alpha_dof_n_v; + Matrix term_1 = cell_alpha_dof_n_v.transpose() * cell_mass_tested; + + energy_vec[cell_ind] = term_1(0,0); + + Matrix laplacian_loc = assembler.laplacian_operator(cell_ind, msh, cell); + Matrix cell_u_dofs = assembler.gather_dof_data(msh, cell, u_dof); + Matrix cell_stiff_tested = laplacian_loc * cell_u_dofs; + Matrix term_2 = cell_u_dofs.transpose() * cell_stiff_tested; + + energy_vec[cell_ind] += term_2(0,0); + + } + #endif + + RealType energy_h = std::accumulate(energy_vec.begin(), energy_vec.end(),0.0); + energy_h *= 0.5; + + tc.toc(); + std::cout << bold << cyan << "Energy completed: " << tc << " seconds" << reset << std::endl; + energy_file << time << " " << std::setprecision(16) << energy_h << std::endl; + return energy_h; + } + + /// Compute the discrete elastic energy for two fields approximation + static double compute_elastic_energy_two_fields(Mesh & msh, disk::hho_degree_info & hho_di, elastodynamic_two_fields_assembler & assembler, double & time, Matrix & x_dof, std::ostream & energy_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + + std::vector energy_vec(msh.cells_size()); + #ifdef HAVE_INTEL_TBB + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [&msh,&assembler,&energy_vec,&x_dof,&n_ten_cbs,&n_vec_cbs] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix mass_matrix = assembler.mass_operator(cell_ind, msh, cell); + Matrix x_dof_loc = assembler.gather_dof_data(msh, cell, x_dof); + + Matrix mass_matrix_v = mass_matrix.block(n_ten_cbs, n_ten_cbs, n_vec_cbs, n_vec_cbs); + Matrix v_dof = x_dof_loc.block(n_ten_cbs, 0, n_vec_cbs, 1); + Matrix v_mass_tested = mass_matrix_v * v_dof; + Matrix term_1 = v_dof.transpose() * v_mass_tested; + energy_vec[cell_ind] = term_1(0,0); + + Matrix mass_matrix_stress = mass_matrix.block(0, 0, n_ten_cbs, n_ten_cbs); + Matrix sigma_dof = x_dof_loc.block(0, 0, n_ten_cbs, 1); + Matrix epsilon_mass = mass_matrix_stress * sigma_dof; + Matrix term_2 = sigma_dof.transpose() * epsilon_mass; + energy_vec[cell_ind] += term_2(0,0); + } + ); + #else + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + + Matrix mass_matrix = assembler.mass_operator(cell_ind, msh, cell); + Matrix x_dof_loc = assembler.gather_dof_data(msh, cell, x_dof); + + Matrix mass_matrix_v = mass_matrix.block(n_ten_cbs, n_ten_cbs, n_vec_cbs, n_vec_cbs); + Matrix v_dof = x_dof_loc.block(n_ten_cbs, 0, n_vec_cbs, 1); + Matrix v_mass_tested = mass_matrix_v * v_dof; + Matrix term_1 = v_dof.transpose() * v_mass_tested; + energy_vec[cell_ind] = term_1(0,0); + + Matrix mass_matrix_stress = mass_matrix.block(0, 0, n_ten_cbs, n_ten_cbs); + Matrix sigma_dof = x_dof_loc.block(0, 0, n_ten_cbs, 1); + Matrix epsilon_mass = mass_matrix_stress * sigma_dof; + Matrix term_2 = sigma_dof.transpose() * epsilon_mass; + energy_vec[cell_ind] += term_2(0,0); + + } + #endif + + RealType energy_h = std::accumulate(energy_vec.begin(), energy_vec.end(),0.0); + energy_h *= 0.5; + + tc.toc(); + std::cout << bold << cyan << "Energy completed: " << tc << " seconds" << reset << std::endl; + energy_file << time << " " << std::setprecision(16) << energy_h << std::endl; + return energy_h; + } + + /// Compute the discrete elastic energy for three field approximation + static double compute_elastic_energy_three_fields(Mesh & msh, disk::hho_degree_info & hho_di, elastodynamic_three_fields_assembler & assembler, double & time, Matrix & x_dof, std::ostream & energy_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_sca_cbs = disk::scalar_basis_size(hho_di.face_degree(), Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + + std::vector energy_vec(msh.cells_size()); + #ifdef HAVE_INTEL_TBB + size_t n_cells = msh.cells_size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [&msh,&assembler,&energy_vec,&x_dof,&n_ten_cbs,&n_sca_cbs,&n_vec_cbs] (size_t & cell_ind){ + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix mass_matrix = assembler.mass_operator(cell_ind, msh, cell); + Matrix x_dof_loc = assembler.gather_dof_data(msh, cell, x_dof); + + Matrix mass_matrix_v = mass_matrix.block(n_ten_cbs + n_sca_cbs, n_ten_cbs + n_sca_cbs, n_vec_cbs, n_vec_cbs); + Matrix v_dof = x_dof_loc.block(n_ten_cbs + n_sca_cbs, 0, n_vec_cbs, 1); + Matrix v_mass_tested = mass_matrix_v * v_dof; + Matrix term_1 = v_dof.transpose() * v_mass_tested; + energy_vec[cell_ind] = term_1(0,0); + + Matrix mass_matrix_stress = mass_matrix.block(0, 0, n_ten_cbs + n_sca_cbs, n_ten_cbs + n_sca_cbs); + Matrix sigma_dof = x_dof_loc.block(0, 0, n_ten_cbs + n_sca_cbs, 1); + Matrix epsilon_mass = mass_matrix_stress * sigma_dof; + Matrix term_2 = sigma_dof.transpose() * epsilon_mass; + energy_vec[cell_ind] += term_2(0,0); + } + ); + #else + for (size_t cell_ind = 0; cell_ind < msh.cells_size(); cell_ind++) + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + + Matrix mass_matrix = assembler.mass_operator(cell_ind, msh, cell); + Matrix x_dof_loc = assembler.gather_dof_data(msh, cell, x_dof); + + Matrix mass_matrix_v = mass_matrix.block(n_ten_cbs + n_sca_cbs, n_ten_cbs + n_sca_cbs, n_vec_cbs, n_vec_cbs); + Matrix v_dof = x_dof_loc.block(n_ten_cbs + n_sca_cbs, 0, n_vec_cbs, 1); + Matrix v_mass_tested = mass_matrix_v * v_dof; + Matrix term_1 = v_dof.transpose() * v_mass_tested; + energy_vec[cell_ind] = term_1(0,0); + + Matrix mass_matrix_stress = mass_matrix.block(0, 0, n_ten_cbs + n_sca_cbs, n_ten_cbs + n_sca_cbs); + Matrix sigma_dof = x_dof_loc.block(0, 0, n_ten_cbs + n_sca_cbs, 1); + Matrix epsilon_mass = mass_matrix_stress * sigma_dof; + Matrix term_2 = sigma_dof.transpose() * epsilon_mass; + energy_vec[cell_ind] += term_2(0,0); + + } + #endif + + RealType energy_h = std::accumulate(energy_vec.begin(), energy_vec.end(),0.0); + energy_h *= 0.5; + + tc.toc(); + std::cout << bold << cyan << "Energy completed: " << tc << " seconds" << reset << std::endl; + energy_file << time << " " << std::setprecision(16) << energy_h << std::endl; + return energy_h; + } + + // SENSORS UNCOUPLED PROBELM + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + /// Record data at provided point for one field approximation + static void record_data_acoustic_one_field(size_t it, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::ostream & seismogram_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + size_t cell_dof = disk::scalar_basis_size(hho_di.cell_degree(), dim); + + RealType vh = 0.0; + + typename Mesh::point_type pt = pt_cell_index.first; + + if(pt_cell_index.second == -1){ + std::set cell_indexes = find_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + seismogram_file << "\"Time\"" << "," << "\"vh\"" << std::endl; + } + + { + size_t cell_ind = pt_cell_index.second; + // scalar evaluation + { + Matrix scalar_cell_dof = x_dof.block(cell_ind*cell_dof, 0, cell_dof, 1); + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + auto t_phi = cell_basis.eval_functions( pt ); + vh = scalar_cell_dof.dot( t_phi ); + } + + } + tc.toc(); + std::cout << bold << cyan << "Value recorded: " << tc << " seconds" << reset << std::endl; + seismogram_file << it << "," << std::setprecision(16) << vh << std::endl; + seismogram_file.flush(); + + } + + /// Record velocity data at provided point for one field approximation + static void record_velocity_data_acoustic_one_field(size_t it, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, acoustic_one_field_assembler & assembler, Matrix & x_dof, std::ostream & seismogram_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + size_t cell_dof = disk::scalar_basis_size(hho_di.cell_degree(), dim); + + Matrix vh = Matrix::Zero(2, 1); + + typename Mesh::point_type pt = pt_cell_index.first; + + if(pt_cell_index.second == -1){ + std::set cell_indexes = find_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + seismogram_file << "\"Time\"" << "," << "\"vhx\"" << "," << "\"vhy\"" << std::endl; + } + + { + size_t cell_ind = pt_cell_index.second; + // reconstructed velocity evaluation + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto rec_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + auto gr = make_scalar_hho_laplacian(msh, cell, hho_di); + Matrix all_dofs = assembler.gather_dof_data(msh, cell, x_dof); + Matrix recdofs = gr.first * all_dofs; + + auto t_dphi = rec_basis.eval_gradients( pt ); + Matrix grad_uh = Matrix::Zero(); + + for (size_t i = 1; i < t_dphi.rows(); i++){ + grad_uh = grad_uh + recdofs(i-1)*t_dphi.block(i, 0, 1, 2); + } + + RealType rho = assembler.get_material_data()[cell_ind].rho(); + vh = (1.0/rho)*(grad_uh); + } + + } + tc.toc(); + std::cout << bold << cyan << "Value recorded: " << tc << " seconds" << reset << std::endl; + seismogram_file << it << "," << std::setprecision(16) << vh(0,0) << "," << std::setprecision(16) << vh(1,0) << std::endl; + seismogram_file.flush(); + + } + + /// Record data at provided point for two fields approximation + static void record_data_acoustic_two_fields(size_t it, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::ostream & seismogram_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + size_t n_scal_dof = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_dof = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t cell_dof = n_scal_dof + n_vec_dof; + + RealType vh = 0.0; + + typename Mesh::point_type pt = pt_cell_index.first; + + if(pt_cell_index.second == -1){ + std::set cell_indexes = find_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + seismogram_file << "\"Time\"" << "," << "\"vh\"" << std::endl; + } + + { + size_t cell_ind = pt_cell_index.second; + // scalar evaluation + { + + Matrix scalar_cell_dof = x_dof.block(cell_ind*cell_dof+n_vec_dof, 0, n_scal_dof, 1); + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + auto t_phi = cell_basis.eval_functions( pt ); + vh = scalar_cell_dof.dot( t_phi ); + } + } + tc.toc(); + std::cout << bold << cyan << "Value recorded: " << tc << " seconds" << reset << std::endl; + seismogram_file << it << "," << std::setprecision(16) << vh << std::endl; + seismogram_file.flush(); + + } + + /// Record data at provided point for one field vectorial approximation + static void record_data_elastic_one_field(size_t it, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::ostream & seismogram_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + size_t cell_dof = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + + Matrix vh = Matrix::Zero(2, 1); + + typename Mesh::point_type pt = pt_cell_index.first; + + if(pt_cell_index.second == -1){ + std::set cell_indexes = find_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + seismogram_file << "\"Time\"" << "," << "\"vhx\"" << "," << "\"vhy\"" << std::endl; + } + + { + size_t cell_ind = pt_cell_index.second; + // vector evaluation + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(cell_ind*cell_dof, 0, cell_dof, 1); + auto t_phi = cell_basis.eval_functions( pt ); + assert(t_phi.rows() == cell_basis.size()); + vh = disk::eval(vec_x_cell_dof, t_phi); + } + } + tc.toc(); + std::cout << bold << cyan << "Value recorded: " << tc << " seconds" << reset << std::endl; + seismogram_file << it << "," << std::setprecision(16) << vh(0,0) << "," << std::setprecision(16) << vh(1,0) << std::endl; + seismogram_file.flush(); + + } + + /// Record data at provided point for two fields vectorial approximation + static void record_data_elastic_two_fields(size_t it, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::ostream & seismogram_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), dim, dim); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + size_t cell_dof = n_ten_cbs + n_vec_cbs; + + Matrix vh = Matrix::Zero(2, 1); + + typename Mesh::point_type pt = pt_cell_index.first; + + if(pt_cell_index.second == -1){ + std::set cell_indexes = find_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + seismogram_file << "\"Time\"" << "," << "\"vhx\"" << "," << "\"vhy\"" << std::endl; + } + + { + size_t cell_ind = pt_cell_index.second; + // vector evaluation + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(cell_ind*cell_dof + n_ten_cbs , 0, n_vec_cbs, 1); + auto t_phi = cell_basis.eval_functions( pt ); + assert(t_phi.rows() == cell_basis.size()); + vh = disk::eval(vec_x_cell_dof, t_phi); + } + + } + tc.toc(); + std::cout << bold << cyan << "Value recorded: " << tc << " seconds" << reset << std::endl; + seismogram_file << it << "," << std::setprecision(16) << vh(0,0) << "," << std::setprecision(16) << vh(1,0) << std::endl; + seismogram_file.flush(); + + } + + /// Record data at provided point for three fields vectorial approximation + static void record_data_elastic_three_fields(size_t it, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::ostream & seismogram_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), dim, dim); + size_t n_sca_cbs = disk::scalar_basis_size(hho_di.face_degree(), dim); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + size_t cell_dof = n_ten_cbs + n_sca_cbs + n_vec_cbs; + + Matrix vh = Matrix::Zero(2, 1); + + typename Mesh::point_type pt = pt_cell_index.first; + + if(pt_cell_index.second == -1){ + std::set cell_indexes = find_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + seismogram_file << "\"Time\"" << "," << "\"vhx\"" << "," << "\"vhy\"" << std::endl; + } + + { + size_t cell_ind = pt_cell_index.second; + // vector evaluation + { + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(cell_ind*cell_dof + n_ten_cbs + n_sca_cbs, 0, n_vec_cbs, 1); + auto t_phi = cell_basis.eval_functions( pt ); + assert(t_phi.rows() == cell_basis.size()); + vh = disk::eval(vec_x_cell_dof, t_phi); + } + + } + tc.toc(); + std::cout << bold << cyan << "Value recorded: " << tc << " seconds" << reset << std::endl; + seismogram_file << it << "," << std::setprecision(16) << vh(0,0) << "," << std::setprecision(16) << vh(1,0) << std::endl; + seismogram_file.flush(); + + } + + // WRITE SILO UNCOUPLED PROBLEM + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + // Write a silo file for one field approximation + static void write_silo_one_field(std::string silo_file_name, size_t it, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, + std::function scal_fun, bool cell_centered_Q){ + + timecounter tc; + tc.tic(); + + auto dim = Mesh::dimension; + auto num_cells = msh.cells_size(); + auto num_points = msh.points_size(); + using RealType = double; + std::vector exact_u, approx_u; + size_t cell_dof = disk::scalar_basis_size(hho_di.cell_degree(), dim); + + if (cell_centered_Q) { + exact_u.reserve( num_cells ); + approx_u.reserve( num_cells ); + + size_t cell_i = 0; + for (auto& cell : msh) + { + auto bar = barycenter(msh, cell); + exact_u.push_back( scal_fun(bar) ); + + // scalar evaluation + { + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix scalar_cell_dof = x_dof.block(cell_i*cell_dof, 0, cell_dof, 1); + auto t_phi = cell_basis.eval_functions( bar ); + RealType uh = scalar_cell_dof.dot( t_phi ); + approx_u.push_back(uh); + } + cell_i++; + } + + }else{ + + exact_u.reserve( num_points ); + approx_u.reserve( num_points ); + + // scan for selected cells, common cells are discardable + std::map point_to_cell; + size_t cell_i = 0; + for (auto& cell : msh) + { + auto points = cell.point_ids(); + size_t n_p = points.size(); + for (size_t l = 0; l < n_p; l++) + { + auto pt_id = points[l]; + point_to_cell[pt_id] = cell_i; + } + cell_i++; + } + + for (auto& pt_id : point_to_cell) + { + auto bar = *std::next(msh.points_begin(), pt_id.first); + exact_u.push_back( scal_fun(bar) ); + + cell_i = pt_id.second; + auto cell = *std::next(msh.cells_begin(), cell_i); + // scalar evaluation + { + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix scalar_cell_dof = x_dof.block(cell_i*cell_dof, 0, cell_dof, 1); + auto t_phi = cell_basis.eval_functions( bar ); + RealType uh = scalar_cell_dof.dot( t_phi ); + approx_u.push_back(uh); + } + } + + } + + disk::silo_database silo; + silo_file_name += std::to_string(it) + ".silo"; + silo.create(silo_file_name.c_str()); + silo.add_mesh(msh, "mesh"); + if (cell_centered_Q) { + disk::silo_zonal_variable v_silo("v", exact_u); + disk::silo_zonal_variable vh_silo("vh", approx_u); + silo.add_variable("mesh", v_silo); + silo.add_variable("mesh", vh_silo); + }else{ + disk::silo_nodal_variable v_silo("v", exact_u); + disk::silo_nodal_variable vh_silo("vh", approx_u); + silo.add_variable("mesh", v_silo); + silo.add_variable("mesh", vh_silo); + } + + silo.close(); + tc.toc(); + std::cout << std::endl; + std::cout << bold << cyan << "Silo file rendered in : " << tc << " seconds" << reset << std::endl; + } + + // Write a silo file for two fields approximation + static void write_silo_two_fields(std::string silo_file_name, size_t it, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, + std::function scal_fun, std::function(const typename Mesh::point_type& )> flux_fun, bool cell_centered_Q){ + + timecounter tc; + tc.tic(); + + auto num_cells = msh.cells_size(); + auto num_points = msh.points_size(); + using RealType = double; + std::vector exact_u, approx_u; + std::vector exact_dux, exact_duy, approx_dux, approx_duy; + + size_t n_scal_dof = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_dof = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t cell_dof = n_scal_dof + n_vec_dof; + + if (cell_centered_Q) { + exact_u.reserve( num_cells ); + approx_u.reserve( num_cells ); + exact_dux.reserve( num_cells ); + exact_duy.reserve( num_cells ); + approx_dux.reserve( num_cells ); + approx_duy.reserve( num_cells ); + + size_t cell_i = 0; + for (auto& cell : msh) + { + auto bar = barycenter(msh, cell); + exact_u.push_back( scal_fun(bar) ); + exact_dux.push_back( flux_fun(bar)[0] ); + exact_duy.push_back( flux_fun(bar)[1] ); + + // scalar evaluation + { + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix scalar_cell_dof = x_dof.block(cell_i*cell_dof+n_vec_dof, 0, n_scal_dof, 1); + auto t_phi = cell_basis.eval_functions( bar ); + RealType uh = scalar_cell_dof.dot( t_phi ); + approx_u.push_back(uh); + } + + // flux evaluation + { + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + Matrix flux_cell_dof = x_dof.block(cell_i*cell_dof, 0, n_vec_dof, 1); + auto t_dphi = cell_basis.eval_gradients( bar ); + + Matrix grad_uh = Matrix::Zero(); + for (size_t i = 1; i < t_dphi.rows(); i++){ + grad_uh = grad_uh + flux_cell_dof(i-1)*t_dphi.block(i, 0, 1, 2); + } + + approx_dux.push_back(grad_uh(0,0)); + approx_duy.push_back(grad_uh(0,1)); + } + + cell_i++; + } + + }else{ + + exact_u.reserve( num_points ); + approx_u.reserve( num_points ); + exact_dux.reserve( num_points ); + exact_duy.reserve( num_points ); + approx_dux.reserve( num_points ); + approx_duy.reserve( num_points ); + + // scan for selected cells, common cells are discardable + std::map point_to_cell; + size_t cell_i = 0; + for (auto& cell : msh) + { + auto points = cell.point_ids(); + size_t n_p = points.size(); + for (size_t l = 0; l < n_p; l++) + { + auto pt_id = points[l]; + point_to_cell[pt_id] = cell_i; + } + cell_i++; + } + + for (auto& pt_id : point_to_cell) + { + auto bar = *std::next(msh.points_begin(), pt_id.first); + cell_i = pt_id.second; + auto cell = *std::next(msh.cells_begin(), cell_i); + + exact_u.push_back( scal_fun(bar) ); + exact_dux.push_back( flux_fun(bar)[0] ); + exact_duy.push_back( flux_fun(bar)[1] ); + + // scalar evaluation + { + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix scalar_cell_dof = x_dof.block(cell_i*cell_dof+n_vec_dof, 0, n_scal_dof, 1); + auto t_phi = cell_basis.eval_functions( bar ); + RealType uh = scalar_cell_dof.dot( t_phi ); + approx_u.push_back(uh); + } + + // flux evaluation + { + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + Matrix flux_cell_dof = x_dof.block(cell_i*cell_dof, 0, n_vec_dof, 1); + auto t_dphi = cell_basis.eval_gradients( bar ); + + Matrix grad_uh = Matrix::Zero(); + for (size_t i = 1; i < t_dphi.rows(); i++){ + grad_uh = grad_uh + flux_cell_dof(i-1)*t_dphi.block(i, 0, 1, 2); + } + + approx_dux.push_back(grad_uh(0,0)); + approx_duy.push_back(grad_uh(0,1)); + } + } + + } + + disk::silo_database silo; + silo_file_name += std::to_string(it) + ".silo"; + silo.create(silo_file_name.c_str()); + silo.add_mesh(msh, "mesh"); + if (cell_centered_Q) { + disk::silo_zonal_variable v_silo("v", exact_u); + disk::silo_zonal_variable qx_silo("qx", exact_dux); + disk::silo_zonal_variable qy_silo("qy", exact_duy); + disk::silo_zonal_variable vh_silo("vh", approx_u); + disk::silo_zonal_variable qhx_silo("qhx", approx_dux); + disk::silo_zonal_variable qhy_silo("qhy", approx_duy); + silo.add_variable("mesh", v_silo); + silo.add_variable("mesh", qx_silo); + silo.add_variable("mesh", qy_silo); + silo.add_variable("mesh", vh_silo); + silo.add_variable("mesh", qhx_silo); + silo.add_variable("mesh", qhy_silo); + }else{ + disk::silo_nodal_variable v_silo("v", exact_u); + disk::silo_nodal_variable qx_silo("qx", exact_dux); + disk::silo_nodal_variable qy_silo("qy", exact_duy); + disk::silo_nodal_variable vh_silo("vh", approx_u); + disk::silo_nodal_variable qhx_silo("qhx", approx_dux); + disk::silo_nodal_variable qhy_silo("qhy", approx_duy); + silo.add_variable("mesh", v_silo); + silo.add_variable("mesh", qx_silo); + silo.add_variable("mesh", qy_silo); + silo.add_variable("mesh", vh_silo); + silo.add_variable("mesh", qhx_silo); + silo.add_variable("mesh", qhy_silo); + } + + silo.close(); + tc.toc(); + std::cout << std::endl; + std::cout << bold << cyan << "Silo file rendered in : " << tc << " seconds" << reset << std::endl; + } + + // Write a silo file for one field vectorial approximation + static void write_silo_one_field_vectorial(std::string silo_file_name, size_t it, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, + std::function(const typename Mesh::point_type& )> vec_fun, bool cell_centered_Q){ + + timecounter tc; + tc.tic(); + + auto dim = Mesh::dimension; + auto num_cells = msh.cells_size(); + auto num_points = msh.points_size(); + using RealType = double; + std::vector exact_ux, exact_uy, approx_ux, approx_uy; + size_t cell_dof = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + + if (cell_centered_Q) { + exact_ux.reserve( num_cells ); + exact_uy.reserve( num_cells ); + approx_ux.reserve( num_cells ); + approx_uy.reserve( num_cells ); + + size_t cell_i = 0; + for (auto& cell : msh) + { + auto bar = barycenter(msh, cell); + exact_ux.push_back( vec_fun(bar)(0,0) ); + exact_uy.push_back( vec_fun(bar)(1,0) ); + + // vector evaluation + { + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(cell_i*cell_dof, 0, cell_dof, 1); + auto t_phi = cell_basis.eval_functions( bar ); + assert(t_phi.rows() == cell_basis.size()); + auto uh = disk::eval(vec_x_cell_dof, t_phi); + approx_ux.push_back(uh(0,0)); + approx_uy.push_back(uh(1,0)); + } + cell_i++; + } + + }else{ + + exact_ux.reserve( num_points ); + exact_uy.reserve( num_points ); + approx_ux.reserve( num_points ); + approx_uy.reserve( num_points ); + + // scan for selected cells, common cells are discardable + std::map point_to_cell; + size_t cell_i = 0; + for (auto& cell : msh) + { + auto points = cell.point_ids(); + size_t n_p = points.size(); + for (size_t l = 0; l < n_p; l++) + { + auto pt_id = points[l]; + point_to_cell[pt_id] = cell_i; + } + cell_i++; + } + + for (auto& pt_id : point_to_cell) + { + auto bar = *std::next(msh.points_begin(), pt_id.first); + cell_i = pt_id.second; + auto cell = *std::next(msh.cells_begin(), cell_i); + + exact_ux.push_back( vec_fun(bar)(0,0) ); + exact_uy.push_back( vec_fun(bar)(1,0) ); + + // vector evaluation + { + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(cell_i*cell_dof, 0, cell_dof, 1); + auto t_phi = cell_basis.eval_functions( bar ); + assert(t_phi.rows() == cell_basis.size()); + auto uh = disk::eval(vec_x_cell_dof, t_phi); + approx_ux.push_back(uh(0,0)); + approx_uy.push_back(uh(1,0)); + } + } + + } + + disk::silo_database silo; + silo_file_name += std::to_string(it) + ".silo"; + silo.create(silo_file_name.c_str()); + silo.add_mesh(msh, "mesh"); + if (cell_centered_Q) { + disk::silo_zonal_variable vx_silo("vx", exact_ux); + disk::silo_zonal_variable vy_silo("vy", exact_uy); + disk::silo_zonal_variable vhx_silo("vhx", approx_ux); + disk::silo_zonal_variable vhy_silo("vhy", approx_uy); + silo.add_variable("mesh", vx_silo); + silo.add_variable("mesh", vy_silo); + silo.add_variable("mesh", vhx_silo); + silo.add_variable("mesh", vhy_silo); + }else{ + disk::silo_nodal_variable vx_silo("vx", exact_ux); + disk::silo_nodal_variable vy_silo("vy", exact_uy); + disk::silo_nodal_variable vhx_silo("vhx", approx_ux); + disk::silo_nodal_variable vhy_silo("vhy", approx_uy); + silo.add_variable("mesh", vx_silo); + silo.add_variable("mesh", vy_silo); + silo.add_variable("mesh", vhx_silo); + silo.add_variable("mesh", vhy_silo); + } + + silo.close(); + tc.toc(); + std::cout << std::endl; + std::cout << bold << cyan << "Silo file rendered in : " << tc << " seconds" << reset << std::endl; + } + + // Write a silo file for two fields vectorial approximation + static void write_silo_two_fields_vectorial(std::string silo_file_name, size_t it, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof,std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, bool cell_centered_Q){ + + timecounter tc; + tc.tic(); + + auto dim = Mesh::dimension; + auto num_cells = msh.cells_size(); + auto num_points = msh.points_size(); + using RealType = double; + std::vector exact_ux, exact_uy, approx_ux, approx_uy; + std::vector exact_sxx, exact_sxy, exact_syy; + std::vector approx_sxx, approx_sxy, approx_syy; + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), dim, dim); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + size_t cell_dof = n_ten_cbs + n_vec_cbs; + + if (cell_centered_Q) { + exact_ux.reserve( num_cells ); + exact_uy.reserve( num_cells ); + approx_ux.reserve( num_cells ); + approx_uy.reserve( num_cells ); + + exact_sxx.reserve( num_cells ); + exact_sxy.reserve( num_cells ); + exact_syy.reserve( num_cells ); + approx_sxx.reserve( num_cells ); + approx_sxy.reserve( num_cells ); + approx_syy.reserve( num_cells ); + + size_t cell_i = 0; + for (auto& cell : msh) + { + auto bar = barycenter(msh, cell); + exact_ux.push_back( vec_fun(bar)(0,0) ); + exact_uy.push_back( vec_fun(bar)(1,0) ); + + exact_sxx.push_back( flux_fun(bar)(0,0) ); + exact_sxy.push_back( flux_fun(bar)(0,1) ); + exact_syy.push_back( flux_fun(bar)(1,1) ); + + // vector evaluation + { + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(cell_i*cell_dof + n_ten_cbs, 0, n_vec_cbs, 1); + auto t_phi = cell_basis.eval_functions( bar ); + assert(t_phi.rows() == cell_basis.size()); + auto uh = disk::eval(vec_x_cell_dof, t_phi); + approx_ux.push_back(uh(0,0)); + approx_uy.push_back(uh(1,0)); + } + + // tensor evaluation + { + auto ten_basis = make_sym_matrix_monomial_basis(msh, cell, hho_di.grad_degree()); + Matrix ten_x_cell_dof = x_dof.block(cell_i*cell_dof, 0, n_ten_cbs, 1); + + auto t_ten_phi = ten_basis.eval_functions( bar ); + assert(t_ten_phi.size() == ten_basis.size()); + auto sigma_h = disk::eval(ten_x_cell_dof, t_ten_phi); + + approx_sxx.push_back(sigma_h(0,0)); + approx_sxy.push_back(sigma_h(0,1)); + approx_syy.push_back(sigma_h(1,1)); + } + + cell_i++; + } + + }else{ + + exact_ux.reserve( num_points ); + exact_uy.reserve( num_points ); + approx_ux.reserve( num_points ); + approx_uy.reserve( num_points ); + + exact_sxx.reserve( num_points ); + exact_sxy.reserve( num_points ); + exact_syy.reserve( num_points ); + approx_sxx.reserve( num_points ); + approx_sxy.reserve( num_points ); + approx_syy.reserve( num_points ); + + // scan for selected cells, common cells are discardable + std::map point_to_cell; + size_t cell_i = 0; + for (auto& cell : msh) + { + auto points = cell.point_ids(); + size_t n_p = points.size(); + for (size_t l = 0; l < n_p; l++) + { + auto pt_id = points[l]; + point_to_cell[pt_id] = cell_i; + } + cell_i++; + } + + for (auto& pt_id : point_to_cell) + { + auto bar = *std::next(msh.points_begin(), pt_id.first); + cell_i = pt_id.second; + auto cell = *std::next(msh.cells_begin(), cell_i); + + exact_ux.push_back( vec_fun(bar)(0,0) ); + exact_uy.push_back( vec_fun(bar)(1,0) ); + + exact_sxx.push_back( flux_fun(bar)(0,0) ); + exact_sxy.push_back( flux_fun(bar)(0,1) ); + exact_syy.push_back( flux_fun(bar)(1,1) ); + + // vector evaluation + { + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(cell_i*cell_dof + n_ten_cbs, 0, n_vec_cbs, 1); + auto t_phi = cell_basis.eval_functions( bar ); + assert(t_phi.rows() == cell_basis.size()); + auto uh = disk::eval(vec_x_cell_dof, t_phi); + approx_ux.push_back(uh(0,0)); + approx_uy.push_back(uh(1,0)); + } + + // tensor evaluation + { + auto ten_basis = make_sym_matrix_monomial_basis(msh, cell, hho_di.grad_degree()); + Matrix ten_x_cell_dof = x_dof.block(cell_i*cell_dof, 0, n_ten_cbs, 1); + + auto t_ten_phi = ten_basis.eval_functions( bar ); + assert(t_ten_phi.size() == ten_basis.size()); + auto sigma_h = disk::eval(ten_x_cell_dof, t_ten_phi); + + approx_sxx.push_back(sigma_h(0,0)); + approx_sxy.push_back(sigma_h(0,1)); + approx_syy.push_back(sigma_h(1,1)); + } + + } + + } + + disk::silo_database silo; + silo_file_name += std::to_string(it) + ".silo"; + silo.create(silo_file_name.c_str()); + silo.add_mesh(msh, "mesh"); + if (cell_centered_Q) { + disk::silo_zonal_variable vx_silo("vx", exact_ux); + disk::silo_zonal_variable vy_silo("vy", exact_uy); + disk::silo_zonal_variable vhx_silo("vhx", approx_ux); + disk::silo_zonal_variable vhy_silo("vhy", approx_uy); + + disk::silo_nodal_variable sxx_silo("sxx", exact_sxx); + disk::silo_nodal_variable sxy_silo("sxy", exact_sxy); + disk::silo_nodal_variable syy_silo("syy", exact_syy); + disk::silo_nodal_variable shxx_silo("shxx", approx_sxx); + disk::silo_nodal_variable shxy_silo("shxy", approx_sxy); + disk::silo_nodal_variable shyy_silo("shyy", approx_syy); + + silo.add_variable("mesh", vx_silo); + silo.add_variable("mesh", vy_silo); + silo.add_variable("mesh", vhx_silo); + silo.add_variable("mesh", vhy_silo); + silo.add_variable("mesh", sxx_silo); + silo.add_variable("mesh", sxy_silo); + silo.add_variable("mesh", syy_silo); + silo.add_variable("mesh", shxx_silo); + silo.add_variable("mesh", shxy_silo); + silo.add_variable("mesh", shyy_silo); + }else{ + disk::silo_nodal_variable vx_silo("vx", exact_ux); + disk::silo_nodal_variable vy_silo("vy", exact_uy); + disk::silo_nodal_variable vhx_silo("vhx", approx_ux); + disk::silo_nodal_variable vhy_silo("vhy", approx_uy); + + disk::silo_nodal_variable sxx_silo("sxx", exact_sxx); + disk::silo_nodal_variable sxy_silo("sxy", exact_sxy); + disk::silo_nodal_variable syy_silo("syy", exact_syy); + disk::silo_nodal_variable shxx_silo("shxx", approx_sxx); + disk::silo_nodal_variable shxy_silo("shxy", approx_sxy); + disk::silo_nodal_variable shyy_silo("shyy", approx_syy); + + silo.add_variable("mesh", vx_silo); + silo.add_variable("mesh", vy_silo); + silo.add_variable("mesh", vhx_silo); + silo.add_variable("mesh", vhy_silo); + silo.add_variable("mesh", sxx_silo); + silo.add_variable("mesh", sxy_silo); + silo.add_variable("mesh", syy_silo); + silo.add_variable("mesh", shxx_silo); + silo.add_variable("mesh", shxy_silo); + silo.add_variable("mesh", shyy_silo); + + } + + silo.close(); + tc.toc(); + std::cout << std::endl; + std::cout << bold << cyan << "Silo file rendered in : " << tc << " seconds" << reset << std::endl; + } + + // Write a silo file for three fields vectorial approximation + static void write_silo_three_fields_vectorial(std::string silo_file_name, size_t it, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof,std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, bool cell_centered_Q){ + + timecounter tc; + tc.tic(); + + auto dim = Mesh::dimension; + auto num_cells = msh.cells_size(); + auto num_points = msh.points_size(); + using RealType = double; + std::vector exact_ux, exact_uy, approx_ux, approx_uy; + std::vector exact_sxx, exact_sxy, exact_syy; + std::vector approx_sxx, approx_sxy, approx_syy; + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), dim, dim); + size_t n_sca_cbs = disk::scalar_basis_size(hho_di.face_degree(), dim); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + size_t cell_dof = n_ten_cbs + n_sca_cbs + n_vec_cbs; + + if (cell_centered_Q) { + exact_ux.reserve( num_cells ); + exact_uy.reserve( num_cells ); + approx_ux.reserve( num_cells ); + approx_uy.reserve( num_cells ); + + exact_sxx.reserve( num_cells ); + exact_sxy.reserve( num_cells ); + exact_syy.reserve( num_cells ); + approx_sxx.reserve( num_cells ); + approx_sxy.reserve( num_cells ); + approx_syy.reserve( num_cells ); + + size_t cell_i = 0; + for (auto& cell : msh) + { + auto bar = barycenter(msh, cell); + exact_ux.push_back( vec_fun(bar)(0,0) ); + exact_uy.push_back( vec_fun(bar)(1,0) ); + + exact_sxx.push_back( flux_fun(bar)(0,0) ); + exact_sxy.push_back( flux_fun(bar)(0,1) ); + exact_syy.push_back( flux_fun(bar)(1,1) ); + + // vector evaluation + { + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(cell_i*cell_dof + n_ten_cbs + n_sca_cbs, 0, n_vec_cbs, 1); + auto t_phi = cell_basis.eval_functions( bar ); + assert(t_phi.rows() == cell_basis.size()); + auto uh = disk::eval(vec_x_cell_dof, t_phi); + approx_ux.push_back(uh(0,0)); + approx_uy.push_back(uh(1,0)); + } + + // tensor evaluation + { + auto ten_basis = make_sym_matrix_monomial_basis(msh, cell, hho_di.grad_degree()); + Matrix ten_x_cell_dof = x_dof.block(cell_i*cell_dof, 0, n_ten_cbs, 1); + + auto sca_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.face_degree()); + Matrix sigma_v_x_cell_dof = x_dof.block(cell_i*cell_dof+n_ten_cbs, 0, n_sca_cbs, 1); + + auto t_ten_phi = ten_basis.eval_functions( bar ); + assert(t_ten_phi.size() == ten_basis.size()); + auto sigma_h = disk::eval(ten_x_cell_dof, t_ten_phi); + + auto t_sca_phi = sca_basis.eval_functions( bar ); + assert(t_sca_phi.size() == sca_basis.size()); + auto sigma_v_h = disk::eval(sigma_v_x_cell_dof, t_sca_phi); + + sigma_h += sigma_v_h * static_matrix::Identity(); + + approx_sxx.push_back(sigma_h(0,0)); + approx_sxy.push_back(sigma_h(0,1)); + approx_syy.push_back(sigma_h(1,1)); + } + + cell_i++; + } + + }else{ + + exact_ux.reserve( num_points ); + exact_uy.reserve( num_points ); + approx_ux.reserve( num_points ); + approx_uy.reserve( num_points ); + + exact_sxx.reserve( num_points ); + exact_sxy.reserve( num_points ); + exact_syy.reserve( num_points ); + approx_sxx.reserve( num_points ); + approx_sxy.reserve( num_points ); + approx_syy.reserve( num_points ); + + // scan for selected cells, common cells are discardable + std::map point_to_cell; + size_t cell_i = 0; + for (auto& cell : msh) + { + auto points = cell.point_ids(); + size_t n_p = points.size(); + for (size_t l = 0; l < n_p; l++) + { + auto pt_id = points[l]; + point_to_cell[pt_id] = cell_i; + } + cell_i++; + } + + for (auto& pt_id : point_to_cell) + { + auto bar = *std::next(msh.points_begin(), pt_id.first); + cell_i = pt_id.second; + auto cell = *std::next(msh.cells_begin(), cell_i); + + exact_ux.push_back( vec_fun(bar)(0,0) ); + exact_uy.push_back( vec_fun(bar)(1,0) ); + + exact_sxx.push_back( flux_fun(bar)(0,0) ); + exact_sxy.push_back( flux_fun(bar)(0,1) ); + exact_syy.push_back( flux_fun(bar)(1,1) ); + + // vector evaluation + { + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(cell_i*cell_dof + n_ten_cbs + n_sca_cbs, 0, n_vec_cbs, 1); + auto t_phi = cell_basis.eval_functions( bar ); + assert(t_phi.rows() == cell_basis.size()); + auto uh = disk::eval(vec_x_cell_dof, t_phi); + approx_ux.push_back(uh(0,0)); + approx_uy.push_back(uh(1,0)); + } + + // tensor evaluation + { + auto ten_basis = make_sym_matrix_monomial_basis(msh, cell, hho_di.grad_degree()); + Matrix ten_x_cell_dof = x_dof.block(cell_i*cell_dof, 0, n_ten_cbs, 1); + + auto sca_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.face_degree()); + Matrix sigma_v_x_cell_dof = x_dof.block(cell_i*cell_dof+n_ten_cbs, 0, n_sca_cbs, 1); + + auto t_ten_phi = ten_basis.eval_functions( bar ); + assert(t_ten_phi.size() == ten_basis.size()); + auto sigma_h = disk::eval(ten_x_cell_dof, t_ten_phi); + + auto t_sca_phi = sca_basis.eval_functions( bar ); + assert(t_sca_phi.size() == sca_basis.size()); + auto sigma_v_h = disk::eval(sigma_v_x_cell_dof, t_sca_phi); + + sigma_h += sigma_v_h * static_matrix::Identity(); + + approx_sxx.push_back(sigma_h(0,0)); + approx_sxy.push_back(sigma_h(0,1)); + approx_syy.push_back(sigma_h(1,1)); + } + + } + + } + + disk::silo_database silo; + silo_file_name += std::to_string(it) + ".silo"; + silo.create(silo_file_name.c_str()); + silo.add_mesh(msh, "mesh"); + if (cell_centered_Q) { + disk::silo_zonal_variable vx_silo("vx", exact_ux); + disk::silo_zonal_variable vy_silo("vy", exact_uy); + disk::silo_zonal_variable vhx_silo("vhx", approx_ux); + disk::silo_zonal_variable vhy_silo("vhy", approx_uy); + + disk::silo_nodal_variable sxx_silo("sxx", exact_sxx); + disk::silo_nodal_variable sxy_silo("sxy", exact_sxy); + disk::silo_nodal_variable syy_silo("syy", exact_syy); + disk::silo_nodal_variable shxx_silo("shxx", approx_sxx); + disk::silo_nodal_variable shxy_silo("shxy", approx_sxy); + disk::silo_nodal_variable shyy_silo("shyy", approx_syy); + + silo.add_variable("mesh", vx_silo); + silo.add_variable("mesh", vy_silo); + silo.add_variable("mesh", vhx_silo); + silo.add_variable("mesh", vhy_silo); + silo.add_variable("mesh", sxx_silo); + silo.add_variable("mesh", sxy_silo); + silo.add_variable("mesh", syy_silo); + silo.add_variable("mesh", shxx_silo); + silo.add_variable("mesh", shxy_silo); + silo.add_variable("mesh", shyy_silo); + }else{ + disk::silo_nodal_variable vx_silo("vx", exact_ux); + disk::silo_nodal_variable vy_silo("vy", exact_uy); + disk::silo_nodal_variable vhx_silo("vhx", approx_ux); + disk::silo_nodal_variable vhy_silo("vhy", approx_uy); + + disk::silo_nodal_variable sxx_silo("sxx", exact_sxx); + disk::silo_nodal_variable sxy_silo("sxy", exact_sxy); + disk::silo_nodal_variable syy_silo("syy", exact_syy); + disk::silo_nodal_variable shxx_silo("shxx", approx_sxx); + disk::silo_nodal_variable shxy_silo("shxy", approx_sxy); + disk::silo_nodal_variable shyy_silo("shyy", approx_syy); + + silo.add_variable("mesh", vx_silo); + silo.add_variable("mesh", vy_silo); + silo.add_variable("mesh", vhx_silo); + silo.add_variable("mesh", vhy_silo); + silo.add_variable("mesh", sxx_silo); + silo.add_variable("mesh", sxy_silo); + silo.add_variable("mesh", syy_silo); + silo.add_variable("mesh", shxx_silo); + silo.add_variable("mesh", shxy_silo); + silo.add_variable("mesh", shyy_silo); + + } + + silo.close(); + tc.toc(); + std::cout << std::endl; + std::cout << bold << cyan << "Silo file rendered in : " << tc << " seconds" << reset << std::endl; + } + + // Write a silo file with acoustic properties as zonal variables + static void write_silo_acoustic_property_map(std::string silo_file_name, Mesh & msh, std::vector< acoustic_material_data > & material){ + + timecounter tc; + tc.tic(); + + auto num_cells = msh.cells_size(); + std::vector rho_data, vp_data; + vp_data.reserve( num_cells ); + rho_data.reserve( num_cells ); + + for (size_t cell_id = 0; cell_id < num_cells; cell_id++) + { + acoustic_material_data acoustic_data = material[cell_id]; + rho_data.push_back( acoustic_data.rho() ); + vp_data.push_back( acoustic_data.vp() ); + } + + disk::silo_database silo; + silo_file_name += ".silo"; + silo.create(silo_file_name.c_str()); + silo.add_mesh(msh, "mesh"); + disk::silo_zonal_variable rho_silo("rho", rho_data); + disk::silo_zonal_variable vp_silo("vp", vp_data); + silo.add_variable("mesh", rho_silo); + silo.add_variable("mesh", vp_silo); + + silo.close(); + tc.toc(); + std::cout << std::endl; + std::cout << bold << cyan << "Properties file rendered in : " << tc << " seconds" << reset << std::endl; + } + + // Write a silo file with elastic properties as zonal variables + static void write_silo_elastic_property_map(std::string silo_file_name, Mesh & msh, std::vector< elastic_material_data > & material){ + + timecounter tc; + tc.tic(); + + auto num_cells = msh.cells_size(); + std::vector rho_data, vp_data, vs_data; + rho_data.reserve( num_cells ); + vp_data.reserve( num_cells ); + vs_data.reserve( num_cells ); + + for (size_t cell_id = 0; cell_id < num_cells; cell_id++) { + elastic_material_data elastic_data = material[cell_id]; + rho_data.push_back( elastic_data.rho() ); + vp_data.push_back( elastic_data.vp() ); + vs_data.push_back( elastic_data.vs() ); + } + + disk::silo_database silo; + silo_file_name += ".silo"; + silo.create(silo_file_name.c_str()); + silo.add_mesh(msh, "mesh"); + disk::silo_zonal_variable rho_silo("rho", rho_data); + disk::silo_zonal_variable vp_silo("vp", vp_data); + disk::silo_zonal_variable vs_silo("vs", vs_data); + silo.add_variable("mesh", rho_silo); + silo.add_variable("mesh", vp_silo); + silo.add_variable("mesh", vs_silo); + + silo.close(); + tc.toc(); + std::cout << std::endl; + std::cout << bold << cyan << "Properties file rendered in : " << tc << " seconds" << reset << std::endl; + } + + // COUPLING POSTPROCESS UNCOUPLED PROBLEM + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + /// Compute errors + static void compute_errors_two_fields_elastoacoustic(Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_two_fields_assembler & assembler, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> sigma_fun,std::function scal_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + + RealType scalar_l2_error = 0.0; + RealType flux_l2_error = 0.0; + RealType vector_l2_error = 0.0; + RealType sigma_l2_error = 0.0; + RealType h = 10.0; + size_t e_cell_dof = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + size_t a_cell_dof = disk::scalar_basis_size(hho_di.cell_degree(), dim); + auto storage = msh.backend_storage(); + + size_t e_cell_ind = 0; + for (auto& e_chunk : assembler.get_e_material_data()) { + + auto& cell = storage->surfaces[e_chunk.first]; + + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + + Matrix vec_cell_dof = x_dof.block(e_cell_ind*e_cell_dof, 0, e_cell_dof, 1); + + // scalar evaluation + { + auto cell_basis = disk::make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix mass = make_mass_matrix(msh, cell, cell_basis, hho_di.cell_degree()); + Matrix rhs = make_rhs(msh, cell, cell_basis, vec_fun); + Matrix real_dofs = mass.llt().solve(rhs); + Matrix diff = real_dofs - vec_cell_dof; + vector_l2_error += diff.dot(mass*diff); + + } + + elastic_material_data material = e_chunk.second; + RealType mu = material.rho()*material.vs()*material.vs(); + RealType lambda = material.rho()*material.vp()*material.vp() - 2.0*mu; + + // sigma evaluation + { + auto int_rule = integrate(msh, cell, 2*(hho_di.cell_degree()+1)); + Matrix all_dofs = assembler.gather_e_dof_data(e_cell_ind, msh, cell, x_dof); + + auto sgr = make_vector_hho_symmetric_laplacian(msh, cell, hho_di); + dynamic_vector GTu = sgr.first * all_dofs; + + auto dr = make_hho_divergence_reconstruction(msh, cell, hho_di); + dynamic_vector divu = dr.first * all_dofs; + + auto cbas_v = disk::make_vector_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + auto cbas_s = disk::make_scalar_monomial_basis(msh, cell, hho_di.face_degree()); + + auto rec_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + + // Error integrals + for (auto & point_pair : int_rule) { + + RealType omega = point_pair.weight(); + + auto t_dphi = rec_basis.eval_gradients( point_pair.point() ); + auto gphi = cbas_v.eval_sgradients(point_pair.point()); + auto epsilon = disk::eval(GTu, gphi, dim); + auto divphi = cbas_s.eval_functions(point_pair.point()); + auto trace_epsilon = disk::eval(divu, divphi); + auto sigma = 2.0 * mu * epsilon + lambda * trace_epsilon * static_matrix::Identity(); + auto flux_diff = (sigma_fun(point_pair.point()) - sigma).eval(); + sigma_l2_error += omega * flux_diff.squaredNorm(); + + } + } + + e_cell_ind++; + } + + size_t n_elastic_cell_dof = assembler.get_e_material_data().size() * e_cell_dof; + size_t a_cell_ind = 0; + for (auto& a_chunk : assembler.get_a_material_data()) { + + auto& cell = storage->surfaces[a_chunk.first]; + + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + + Matrix scalar_cell_dof = x_dof.block(a_cell_ind*a_cell_dof+n_elastic_cell_dof, 0, a_cell_dof, 1); + + // scalar evaluation + { + auto cell_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix mass = make_mass_matrix(msh, cell, cell_basis, hho_di.cell_degree()); + Matrix rhs = make_rhs(msh, cell, cell_basis, scal_fun); + Matrix real_dofs = mass.llt().solve(rhs); + Matrix diff = real_dofs - scalar_cell_dof; + scalar_l2_error += diff.dot(mass*diff); + + } + + // flux evaluation + { + auto int_rule = integrate(msh, cell, 2*(hho_di.cell_degree()+1)); + auto rec_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + auto gr = make_scalar_hho_laplacian(msh, cell, hho_di); + Matrix all_dofs = assembler.gather_a_dof_data(a_cell_ind, msh, cell, x_dof); + Matrix recdofs = gr.first * all_dofs; + + // Error integrals + for (auto & point_pair : int_rule) { + + RealType omega = point_pair.weight(); + auto t_dphi = rec_basis.eval_gradients( point_pair.point() ); + Matrix grad_uh = Matrix::Zero(); + + for (size_t i = 1; i < t_dphi.rows(); i++){ + grad_uh = grad_uh + recdofs(i-1)*t_dphi.block(i, 0, 1, 2); + } + + Matrix grad_u_exact = flux_fun(point_pair.point()); + flux_l2_error += omega * (grad_u_exact - grad_uh).dot(grad_u_exact - grad_uh); + + } + } + a_cell_ind++; + } + + tc.toc(); + std::cout << bold << cyan << "Error completed: " << tc << " seconds" << reset << std::endl; + error_file << "Characteristic h size = " << h << std::endl; + error_file << "Elastic region : " << std::endl; + error_file << "L2-norm error = " << std::setprecision(16) << std::sqrt(vector_l2_error) << std::endl; + error_file << "H1-norm error = " << std::setprecision(16) << std::sqrt(sigma_l2_error) << std::endl; + error_file << "Acoustic region : " << std::endl; + error_file << "L2-norm error = " << std::setprecision(16) << std::sqrt(scalar_l2_error) << std::endl; + error_file << "H1-norm error = " << std::setprecision(16) << std::sqrt(flux_l2_error) << std::endl; + error_file << std::endl; + error_file.flush(); + } + + static void compute_errors_four_fields_elastoacoustic(Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> sigma_fun,std::function scal_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + + RealType scalar_l2_error = 0.0; + RealType flux_l2_error = 0.0; + RealType vector_l2_error = 0.0; + RealType sigma_l2_error = 0.0; + RealType h = 10.0; + + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t e_cell_dof = n_ten_cbs + n_vec_cbs; + + size_t n_vel_scal_cbs = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_scal_cbs = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t a_cell_dof = n_vel_scal_cbs + n_scal_cbs; + + auto storage = msh.backend_storage(); + size_t e_cell_ind = 0; + for (auto& e_chunk : assembler.get_e_material_data()) { + auto& cell = storage->surfaces[e_chunk.first]; + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + Matrix vec_cell_dof = x_dof.block(e_cell_ind*e_cell_dof+n_ten_cbs, 0, n_vec_cbs, 1); + + // scalar evaluation + { + auto cell_basis = disk::make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix mass = make_mass_matrix(msh, cell, cell_basis, hho_di.cell_degree()); + Matrix rhs = make_rhs(msh, cell, cell_basis, vec_fun); + Matrix real_dofs = mass.llt().solve(rhs); + Matrix diff = real_dofs - vec_cell_dof; + vector_l2_error += diff.dot(mass*diff); + + } + + elastic_material_data material = e_chunk.second; + RealType mu = material.rho()*material.vs()*material.vs(); + RealType lambda = material.rho()*material.vp()*material.vp() - 2.0*mu; + + + // tensor evaluation + { + auto int_rule = integrate(msh, cell, 2*(hho_di.cell_degree()+1)); + + auto ten_basis = make_sym_matrix_monomial_basis(msh, cell, hho_di.grad_degree()); + Matrix ten_x_cell_dof = x_dof.block(e_cell_ind*e_cell_dof, 0, n_ten_cbs, 1); + + // Error integrals + for (auto & point_pair : int_rule) { + + RealType omega = point_pair.weight(); + + auto t_ten_phi = ten_basis.eval_functions( point_pair.point() ); + assert(t_ten_phi.size() == ten_basis.size()); + auto sigma_h = disk::eval(ten_x_cell_dof, t_ten_phi); + + auto flux_diff = (sigma_fun(point_pair.point()) - sigma_h).eval(); + sigma_l2_error += omega * flux_diff.squaredNorm(); + + } + + } + + e_cell_ind++; + } + + size_t n_elastic_cell_dof = assembler.get_e_material_data().size() * e_cell_dof; + size_t a_cell_ind = 0; + for (auto& a_chunk : assembler.get_a_material_data()) { + + auto& cell = storage->surfaces[a_chunk.first]; + + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + + Matrix scalar_cell_dof = x_dof.block(a_cell_ind*a_cell_dof+n_elastic_cell_dof+n_vel_scal_cbs, 0, n_scal_cbs, 1); + + // scalar evaluation + { + auto cell_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix mass = make_mass_matrix(msh, cell, cell_basis, hho_di.cell_degree()); + Matrix rhs = make_rhs(msh, cell, cell_basis, scal_fun); + Matrix real_dofs = mass.llt().solve(rhs); + Matrix diff = real_dofs - scalar_cell_dof; + scalar_l2_error += diff.dot(mass*diff); + + } + + // flux evaluation + { + auto int_rule = integrate(msh, cell, 2*(hho_di.cell_degree()+1)); + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + Matrix flux_cell_dof = x_dof.block(a_cell_ind*a_cell_dof+n_elastic_cell_dof, 0, n_vel_scal_cbs, 1); + + // Error integrals + for (auto & point_pair : int_rule) { + + RealType omega = point_pair.weight(); + auto t_dphi = cell_basis.eval_gradients( point_pair.point() ); + + Matrix grad_uh = Matrix::Zero(); + for (size_t i = 1; i < t_dphi.rows(); i++){ + grad_uh = grad_uh + flux_cell_dof(i-1)*t_dphi.block(i, 0, 1, 2); + } + + Matrix grad_u_exact = Matrix::Zero(); + grad_u_exact(0,0) = flux_fun(point_pair.point())[0]; + grad_u_exact(0,1) = flux_fun(point_pair.point())[1]; + flux_l2_error += omega * (grad_u_exact - grad_uh).dot(grad_u_exact - grad_uh); + + } + } + a_cell_ind++; + } + + tc.toc(); + // std::cout << bold << red << " ERROR COMPLETED: " << tc << " seconds" << reset << std::endl; + error_file << "Characteristic h size = " << h << std::endl; + error_file << "Elastic region : " << std::endl; + error_file << "L2-norm error = " << std::setprecision(16) << std::sqrt(vector_l2_error) << std::endl; + error_file << "H1-norm error = " << std::setprecision(16) << std::sqrt(sigma_l2_error) << std::endl; + error_file << "Acoustic region : " << std::endl; + error_file << "L2-norm error = " << std::setprecision(16) << std::sqrt(scalar_l2_error) << std::endl; + error_file << "H1-norm error = " << std::setprecision(16) << std::sqrt(flux_l2_error) << std::endl; + error_file << std::endl; + error_file.flush(); + } + + static void compute_errors_four_fields_elastoacoustic_energy_norm(Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> sigma_fun,std::function scal_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + + RealType dg_acoutic_l2_error = 0.0; + RealType dg_elastic_l2_error = 0.0; + RealType h = 10.0; + + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.face_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t e_cell_dof = n_ten_cbs + n_vec_cbs; + + size_t n_vel_scal_cbs = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_scal_cbs = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t a_cell_dof = n_vel_scal_cbs + n_scal_cbs; + + auto storage = msh.backend_storage(); + + // Elastic dG unknowns + size_t e_cell_ind = 0; + for (auto& e_chunk : assembler.get_e_material_data()) { + + auto& cell = storage->surfaces[e_chunk.first]; + + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + + { // tensor evaluation + Matrix ten_x_cell_dof = x_dof.block(e_cell_ind*e_cell_dof, 0, n_ten_cbs, 1); + auto ten_basis = make_sym_matrix_monomial_basis(msh, cell, hho_di.face_degree()); + Matrix mass = make_mass_matrix(msh, cell, ten_basis, hho_di.face_degree()); + Matrix rhs = make_rhs(msh, cell, ten_basis, sigma_fun); + Matrix real_dofs = mass.llt().solve(rhs); + Matrix diff = real_dofs - ten_x_cell_dof; + dg_elastic_l2_error += diff.dot(mass*diff); + } + + e_cell_ind++; + } + + size_t n_elastic_cell_dof = assembler.get_e_material_data().size() * e_cell_dof; + + // Acoustic dG unknowns + size_t a_cell_ind = 0; + for (auto& a_chunk : assembler.get_a_material_data()) { + + auto& cell = storage->surfaces[a_chunk.first]; + + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + + + { // Vectorial evaluation + Matrix flux_cell_dof = x_dof.block(a_cell_ind*a_cell_dof+n_elastic_cell_dof, 0, n_vel_scal_cbs, 1); + Matrix real_dofs = flux_cell_dof; + + auto recdeg = hho_di.reconstruction_degree(); + auto rec_basis = make_scalar_monomial_basis(msh, cell, recdeg); + auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension); + Matrix mass_matrix_q_full = make_stiffness_matrix(msh, cell, rec_basis); + Matrix mass_matrix_q = Matrix::Zero(rbs-1, rbs-1); + mass_matrix_q = mass_matrix_q_full.block(1, 1, rbs-1, rbs-1); + + Matrix rhs = Matrix::Zero(rbs-1); + Matrix f_vec = Matrix::Zero(1, 2); + const auto qps = integrate(msh, cell, 2*recdeg); + for (auto& qp : qps) { + auto dphi = rec_basis.eval_gradients(qp.point()); + f_vec(0,0) = flux_fun(qp.point())[0]; + f_vec(0,1) = flux_fun(qp.point())[1]; + for (size_t i = 0; i < rbs-1; i++){ + Matrix phi_i = dphi.block(i+1, 0, 1, 2).transpose(); + rhs(i,0) = rhs(i,0) + (qp.weight() * f_vec*phi_i)(0,0); + } + } + real_dofs = mass_matrix_q.llt().solve(rhs); + + // std::cout << "flux_cell_dof = " << flux_cell_dof.size() << std::endl; + // auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + // std::cout << "cell_basis = " << cell_basis.size() << std::endl; + // Matrix mass = make_mass_matrix(msh, cell, cell_basis, hho_di.face_degree()); + // std::cout << "mass = " << mass_matrix_q.size() << std::endl; + // Matrix rhs = make_rhs(msh, cell, cell_basis, flux_fun); + // std::cout << "rhs = " << rhs.size() << std::endl; + // Matrix real_dofs = mass.llt().solve(rhs); + // std::cout << "real_dofs = " << real_dofs.size() << std::endl; + Matrix diff = real_dofs - flux_cell_dof; + // std::cout << "diff = " << diff.size() << std::endl; + dg_acoutic_l2_error += diff.dot(mass_matrix_q*diff); + // std::cout << std::endl; + + } + + a_cell_ind++; + } + + tc.toc(); + error_file << "L2 errors of dG unknowns: " << std::endl; + error_file << "Acoustic region : " << std::setprecision(16) << std::sqrt(dg_acoutic_l2_error) << std::endl; + error_file << "Elastic region : " << std::setprecision(16) << std::sqrt(dg_elastic_l2_error) << std::endl; + error_file << std::endl; + error_file.flush(); + } + + /// Compute energy + static double compute_elasto_acoustic_energy_four_field(Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, double & time, Matrix & x_dof, std::ostream & energy_file = std::cout) { + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + + // Elastic basis functions + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(),Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(), Mesh::dimension, Mesh::dimension); + size_t e_cell_dof = n_ten_cbs + n_vec_cbs; + + // Acoustic basis functions + size_t n_vel_scal_cbs = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension) - 1; + size_t n_scal_cbs = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t a_cell_dof = n_vel_scal_cbs + n_scal_cbs; + + + auto storage = msh.backend_storage(); + std::vector elastic_energy_vec(msh.cells_size()); + std::vector acoustic_energy_vec(msh.cells_size()); + + // Computation of the elastic energy + size_t e_cell_ind = 0; + + //Loop on elastic elements + for (auto& e_chunk : assembler.get_e_material_data()) { + auto& cell = storage->surfaces[e_chunk.first]; + + Matrix mass_matrix = assembler.e_mass_operator(e_chunk.second, msh, cell); + Matrix x_dof_loc = assembler.gather_e_dof_data(e_chunk.first, msh, cell, x_dof); + + // Evaluation of the L2 norm of the velocity (vectorial component) + Matrix mass_matrix_v = mass_matrix.block(n_ten_cbs, n_ten_cbs, n_vec_cbs, n_vec_cbs); + Matrix vec_cell_dof = x_dof_loc.block(n_ten_cbs, 0, n_vec_cbs, 1); + Matrix v_mass_tested = mass_matrix_v * vec_cell_dof; + Matrix term_1 = vec_cell_dof.transpose() * v_mass_tested; + elastic_energy_vec[e_cell_ind] = term_1(0,0); + + // Evaluation of the L2 norm of the strain tensor + Matrix mass_sigma = mass_matrix.block(0, 0, n_ten_cbs, n_ten_cbs); + Matrix sigma_dof = x_dof_loc.block(0, 0, n_ten_cbs, 1); + Matrix epsilon_mass = mass_sigma * sigma_dof; + Matrix term_2 = sigma_dof.transpose() * epsilon_mass; + elastic_energy_vec[e_cell_ind] += term_2(0,0); + + e_cell_ind++; + + } + + // // Computation of the acoustic energy + size_t a_cell_ind = 0; + + // Loop on acoustic elements + for (auto& a_chunk : assembler.get_a_material_data()) { + auto& cell = storage->surfaces[a_chunk.first]; + + Matrix mass_matrix = assembler.a_mass_operator(a_chunk.second, msh, cell); + Matrix x_dof_loc = assembler.gather_a_dof_data(a_chunk.first, msh, cell, x_dof); + + // Evaluation of the L2 norm of the pressure (scalar component) + Matrix mass_matrix_p = mass_matrix.block(n_vel_scal_cbs, n_vel_scal_cbs, n_scal_cbs, n_scal_cbs); + Matrix p_cell_dof = x_dof_loc.block(n_vel_scal_cbs, 0, n_scal_cbs, 1); + Matrix p_cell_mass_tested = mass_matrix_p * p_cell_dof; + Matrix term_3 = p_cell_dof.transpose() * p_cell_mass_tested; + acoustic_energy_vec[a_cell_ind] = term_3(0,0); + + // Evaluation of the L2 norm of the acoustic velocity (vectorial component) + Matrix mass_matrix_v = mass_matrix.block(0, 0, n_vel_scal_cbs, n_vel_scal_cbs); + Matrix v_cell_dof = x_dof_loc.block(0, 0, n_vel_scal_cbs, 1); + Matrix v_cell_mass_tested = mass_matrix_v * v_cell_dof; + Matrix term_4 = v_cell_dof.transpose() * v_cell_mass_tested; + acoustic_energy_vec[a_cell_ind] += term_4(0,0); + + a_cell_ind++; + } + + RealType elastic_energy_h = std::accumulate(elastic_energy_vec.begin(), elastic_energy_vec.end(), 0.0); + RealType acoustic_energy_h = std::accumulate(acoustic_energy_vec.begin(), acoustic_energy_vec.end(), 0.0); + elastic_energy_h *= 0.5; + acoustic_energy_h *= 0.5; + RealType total_energy = elastic_energy_h + acoustic_energy_h; + tc.toc(); + + // std::cout << bold << cyan << " Energy completed: " << tc << " seconds" << reset; + energy_file << time << " " << std::setprecision(16) + << elastic_energy_h << " " + << acoustic_energy_h << " " << total_energy << std::endl; + + return total_energy; + } + + static double compute_elasto_acoustic_energy_four_field_bassin(polygon_2d_mesh_reader mesh_builder, Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, double & time, Matrix & x_dof, std::ostream & energy_file = std::cout) { + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + + // Elastic basis functions + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(),Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(), Mesh::dimension, Mesh::dimension); + size_t e_cell_dof = n_ten_cbs + n_vec_cbs; + + // Acoustic basis functions + size_t n_vel_scal_cbs = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension) - 1; + size_t n_scal_cbs = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t a_cell_dof = n_vel_scal_cbs + n_scal_cbs; + + auto storage = msh.backend_storage(); + std::vector elastic_energy_vec(msh.cells_size()); + std::vector socle_energy_vec(msh.cells_size()); + std::vector sediment_energy_vec(msh.cells_size()); + std::vector acoustic_energy_vec(msh.cells_size()); + + // Computation of the elastic energy + size_t e_cell_ind = 0; + + //Loop on elastic elements + for (auto& e_chunk : assembler.get_e_material_data()) { + auto& cell = storage->surfaces[e_chunk.first]; + Matrix mass_matrix = assembler.e_mass_operator(e_chunk.second, msh, cell); + Matrix x_dof_loc = assembler.gather_e_dof_data(e_chunk.first, msh, cell, x_dof); + + // Evaluation of the L2 norm of the velocity (vectorial component) + Matrix mass_matrix_v = mass_matrix.block(n_ten_cbs, n_ten_cbs, n_vec_cbs, n_vec_cbs); + Matrix vec_cell_dof = x_dof_loc.block(n_ten_cbs, 0, n_vec_cbs, 1); + Matrix v_mass_tested = mass_matrix_v * vec_cell_dof; + Matrix term_1 = vec_cell_dof.transpose() * v_mass_tested; + elastic_energy_vec[e_cell_ind] = term_1(0,0); + + // Evaluation of the L2 norm of the strain tensor + Matrix mass_sigma = mass_matrix.block(0, 0, n_ten_cbs, n_ten_cbs); + Matrix sigma_dof = x_dof_loc.block(0, 0, n_ten_cbs, 1); + Matrix epsilon_mass = mass_sigma * sigma_dof; + Matrix term_2 = sigma_dof.transpose() * epsilon_mass; + if (mesh_builder.polygons[e_chunk.first].m_material == 1) { + socle_energy_vec[e_cell_ind] = term_1(0,0) + term_2(0,0); + } + if (mesh_builder.polygons[e_chunk.first].m_material == 2) { + sediment_energy_vec[e_cell_ind] = term_1(0,0) + term_2(0,0); + } + elastic_energy_vec[e_cell_ind] += term_2(0,0); + + e_cell_ind++; + + } + + // // Computation of the acoustic energy + size_t a_cell_ind = 0; + + // Loop on acoustic elements + for (auto& a_chunk : assembler.get_a_material_data()) { + auto& cell = storage->surfaces[a_chunk.first]; + + Matrix mass_matrix = assembler.a_mass_operator(a_chunk.second, msh, cell); + Matrix x_dof_loc = assembler.gather_a_dof_data(a_chunk.first, msh, cell, x_dof); + + // Evaluation of the L2 norm of the pressure (scalar component) + Matrix mass_matrix_p = mass_matrix.block(n_vel_scal_cbs, n_vel_scal_cbs, n_scal_cbs, n_scal_cbs); + Matrix p_cell_dof = x_dof_loc.block(n_vel_scal_cbs, 0, n_scal_cbs, 1); + Matrix p_cell_mass_tested = mass_matrix_p * p_cell_dof; + Matrix term_3 = p_cell_dof.transpose() * p_cell_mass_tested; + acoustic_energy_vec[a_cell_ind] = term_3(0,0); + + // Evaluation of the L2 norm of the acoustic velocity (vectorial component) + Matrix mass_matrix_v = mass_matrix.block(0, 0, n_vel_scal_cbs, n_vel_scal_cbs); + Matrix v_cell_dof = x_dof_loc.block(0, 0, n_vel_scal_cbs, 1); + Matrix v_cell_mass_tested = mass_matrix_v * v_cell_dof; + Matrix term_4 = v_cell_dof.transpose() * v_cell_mass_tested; + acoustic_energy_vec[a_cell_ind] += term_4(0,0); + + a_cell_ind++; + } + + RealType socle_energy_h = std::accumulate(socle_energy_vec.begin(), socle_energy_vec.end(), 0.0); + RealType sediment_energy_h = std::accumulate(sediment_energy_vec.begin(), sediment_energy_vec.end(), 0.0); + RealType elastic_energy_h = std::accumulate(elastic_energy_vec.begin(), elastic_energy_vec.end(), 0.0); + RealType acoustic_energy_h = std::accumulate(acoustic_energy_vec.begin(), acoustic_energy_vec.end(), 0.0); + socle_energy_h *= 0.5; + sediment_energy_h *= 0.5; + elastic_energy_h *= 0.5; + acoustic_energy_h *= 0.5; + RealType total_energy = elastic_energy_h + acoustic_energy_h; + tc.toc(); + + // std::cout << bold << cyan << " Energy completed: " << tc << " seconds" << reset; + energy_file << time << " " << std::setprecision(16) + << socle_energy_h << " " + << sediment_energy_h << " " + << elastic_energy_h << " " + << acoustic_energy_h << " " << total_energy << std::endl; + + return total_energy; + + } + + // Write silo file + static void write_silo_two_fields_elastoacoustic(std::string silo_file_name, size_t it, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::map> & e_material, std::map> & a_material, bool cell_centered_Q){ + + timecounter tc; + tc.tic(); + + auto dim = Mesh::dimension; + auto num_cells = msh.cells_size(); + auto num_points = msh.points_size(); + using RealType = double; + std::vector approx_ux, approx_uy; + std::vector approx_u; + size_t e_cell_dof = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + size_t a_cell_dof = disk::scalar_basis_size(hho_di.cell_degree(), dim); + auto storage = msh.backend_storage(); + + if (cell_centered_Q) { + approx_ux.resize( num_cells ); + approx_uy.resize( num_cells ); + approx_u.resize( num_cells ); + + size_t e_cell_ind = 0; + for (auto& e_chunk : e_material) { + + auto& cell = storage->surfaces[e_chunk.first]; + auto bar = barycenter(msh, cell); + approx_u.at(e_chunk.first) =( 0.0/ 0.0); + + // vector evaluation + { + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(e_cell_ind*e_cell_dof, 0, e_cell_dof, 1); + auto t_phi = cell_basis.eval_functions( bar ); + assert(t_phi.rows() == cell_basis.size()); + auto uh = disk::eval(vec_x_cell_dof, t_phi); + approx_ux.at(e_chunk.first) = (uh(0,0)); + approx_uy.at(e_chunk.first) = (uh(1,0)); + } + e_cell_ind++; + } + + size_t n_elastic_cell_dof = e_material.size() * e_cell_dof; + size_t a_cell_ind = 0; + for (auto& a_chunk : a_material) { + + auto& cell = storage->surfaces[a_chunk.first]; + auto bar = barycenter(msh, cell); + approx_ux.at(a_chunk.first) = ( 0.0/0.0 ); + approx_uy.at(a_chunk.first) = ( 0.0/0.0 ); + + // scalar evaluation + { + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix scalar_cell_dof = x_dof.block(a_cell_ind*a_cell_dof + n_elastic_cell_dof, 0, a_cell_dof, 1); + auto t_phi = cell_basis.eval_functions( bar ); + RealType uh = scalar_cell_dof.dot( t_phi ); + approx_u.at(a_chunk.first) = (uh); + } + a_cell_ind++; + } + + + }else{ + + // Filling with nan (It is weird but useful in Paraview) + approx_ux.resize( num_points , 0.0/ 0.0); + approx_uy.resize( num_points , 0.0/ 0.0); + approx_u.resize( num_points , 0.0/ 0.0); + + std::map e_cell_index; + std::map a_cell_index; + + // elastic data + size_t e_cell_ind = 0; + for (auto chunk : e_material) { + e_cell_index.insert(std::make_pair(chunk.first,e_cell_ind)); + e_cell_ind++; + } + + // acoustic data + size_t a_cell_ind = 0; + for (auto chunk : a_material) { + a_cell_index.insert(std::make_pair(chunk.first,a_cell_ind)); + a_cell_ind++; + } + + for (auto& e_chunk : e_material) { + + auto& cell = storage->surfaces[e_chunk.first]; + size_t e_cell_ind = e_cell_index[e_chunk.first]; + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(e_cell_ind*e_cell_dof, 0, e_cell_dof, 1); + + auto points = cell.point_ids(); + size_t n_p = points.size(); + for (size_t l = 0; l < n_p; l++) + { + auto pt_id = points[l]; + auto pt_coord = *std::next(msh.points_begin(), pt_id); + // vector evaluation + { + auto t_phi = cell_basis.eval_functions( pt_coord ); + assert(t_phi.rows() == cell_basis.size()); + auto uh = disk::eval(vec_x_cell_dof, t_phi); + approx_ux.at(pt_id) = uh(0,0); + approx_uy.at(pt_id) = uh(1,0); + } + } + } + + size_t n_elastic_cell_dof = e_material.size() * e_cell_dof; + for (auto& a_chunk : a_material) { + + auto& cell = storage->surfaces[a_chunk.first]; + size_t a_cell_ind = a_cell_index[a_chunk.first]; + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix scalar_cell_dof = x_dof.block(a_cell_ind*a_cell_dof + n_elastic_cell_dof, 0, a_cell_dof, 1); + + auto points = cell.point_ids(); + size_t n_p = points.size(); + for (size_t l = 0; l < n_p; l++) + { + auto pt_id = points[l]; + auto pt_coord = *std::next(msh.points_begin(), pt_id); + // scalar evaluation + { + auto t_phi = cell_basis.eval_functions( pt_coord ); + RealType uh = scalar_cell_dof.dot( t_phi ); + approx_u.at(pt_id) = uh; + } + } + } + + } + + disk::silo_database silo; + silo_file_name += std::to_string(it) + ".silo"; + silo.create(silo_file_name.c_str()); + silo.add_mesh(msh, "mesh"); + if (cell_centered_Q) { + disk::silo_zonal_variable vhx_silo("vhx", approx_ux); + disk::silo_zonal_variable vhy_silo("vhy", approx_uy); + disk::silo_zonal_variable vh_silo("vh", approx_u); + silo.add_variable("mesh", vhx_silo); + silo.add_variable("mesh", vhy_silo); + silo.add_variable("mesh", vh_silo); + }else{ + disk::silo_nodal_variable vhx_silo("vhx", approx_ux); + disk::silo_nodal_variable vhy_silo("vhy", approx_uy); + disk::silo_nodal_variable vh_silo("vh", approx_u); + silo.add_variable("mesh", vhx_silo); + silo.add_variable("mesh", vhy_silo); + silo.add_variable("mesh", vh_silo); + } + + silo.close(); + tc.toc(); + std::cout << std::endl; + std::cout << bold << cyan << "Silo file rendered in : " << tc << " seconds" << reset << std::endl; + } + + static void write_silo_four_fields_elastoacoustic(std::string silo_file_name, size_t it, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::map> & e_material, std::map> & a_material, bool cell_centered_Q) { + + timecounter tc; + tc.tic(); + + auto dim = Mesh::dimension; + auto num_cells = msh.cells_size(); + auto num_points = msh.points_size(); + + using RealType = double; + std::vector approx_ux, approx_uy, approx_uy_bis; + std::vector approx_u; + + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(), Mesh::dimension, Mesh::dimension); + size_t e_cell_dof = n_ten_cbs + n_vec_cbs; + size_t n_vel_scal_cbs = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension) -1; + size_t n_scal_cbs = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t a_cell_dof = n_vel_scal_cbs + n_scal_cbs; + + auto storage = msh.backend_storage(); + + if (cell_centered_Q) { + approx_ux.resize(num_cells); + approx_uy.resize(num_cells); + approx_uy_bis.resize(num_cells); + approx_u.resize (num_cells); + + size_t e_cell_ind = 0; + for (auto& e_chunk : e_material) { + + auto& cell = storage->surfaces[e_chunk.first]; + auto bar = barycenter(msh, cell); + approx_u.at(e_chunk.first) = (0.0/0.0); + + // vector evaluation + { + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(e_cell_ind*e_cell_dof + + n_ten_cbs, 0, n_vec_cbs, 1); + auto t_phi = cell_basis.eval_functions( bar ); + assert(t_phi.rows() == cell_basis.size()); + auto uh = disk::eval(vec_x_cell_dof, t_phi); + approx_ux.at(e_chunk.first) = (uh(0,0)); + approx_uy.at(e_chunk.first) = (uh(1,0)); + approx_uy_bis.at(e_chunk.first) = (uh(1,0)); + } + e_cell_ind++; + } + + size_t n_elastic_cell_dof = e_material.size() * e_cell_dof; + size_t a_cell_ind = 0; + for (auto& a_chunk : a_material) { + + auto& cell = storage->surfaces[a_chunk.first]; + auto bar = barycenter(msh, cell); + approx_ux.at(a_chunk.first) = (0.0/0.0); + approx_uy.at(a_chunk.first) = (0.0/0.0); + approx_uy_bis.at(a_chunk.first) = (0.0/0.0); + + // scalar evaluation + { + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix scalar_cell_dof = x_dof.block(a_cell_ind*a_cell_dof + + n_vel_scal_cbs + + n_elastic_cell_dof, 0, + n_scal_cbs, 1); + auto t_phi = cell_basis.eval_functions( bar ); + RealType uh = scalar_cell_dof.dot( t_phi ); + approx_u.at(a_chunk.first) = (uh); + } + a_cell_ind++; + } + } + + else { + + // Filling with nan (It is weird but useful in Paraview) + approx_ux.resize(num_points,0.0/0.0); + approx_uy.resize(num_points,0.0/0.0); + approx_uy_bis.resize(num_points,0.0/0.0); + approx_u.resize(num_points,0.0/0.0); + + std::map e_cell_index; + std::map a_cell_index; + size_t e_cell_ind = 0; + for (auto chunk : e_material) { + e_cell_index.insert(std::make_pair(chunk.first,e_cell_ind)); + e_cell_ind++; + } + + // acoustic data + size_t a_cell_ind = 0; + for (auto chunk : a_material) { + a_cell_index.insert(std::make_pair(chunk.first,a_cell_ind)); + a_cell_ind++; + } + + for (auto& e_chunk : e_material) { + + auto& cell = storage->surfaces[e_chunk.first]; + size_t e_cell_ind = e_cell_index[e_chunk.first]; + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix vec_x_cell_dof = x_dof.block(e_cell_ind*e_cell_dof + + n_ten_cbs, 0, n_vec_cbs, 1); + + auto points = cell.point_ids(); + size_t n_p = points.size(); + // problème sur cette boucle + for (size_t l = 0; l < n_p; l++) { + auto pt_id = points[l]; + auto pt_coord = *std::next(msh.points_begin(), pt_id); + + // vector evaluation + { + auto t_phi = cell_basis.eval_functions(pt_coord); + assert(t_phi.rows() == cell_basis.size()); + auto uh = disk::eval(vec_x_cell_dof, t_phi); + + approx_ux.at(pt_id) = uh(0,0); + approx_uy.at(pt_id) = uh(1,0); + approx_uy_bis.at(pt_id) = std::sqrt( std::abs(uh(0,0))*std::abs(uh(0,0)) + + std::abs(uh(1,0))*std::abs(uh(1,0)) ); + } + } + } + + size_t n_elastic_cell_dof = e_material.size() * e_cell_dof; + for (auto& a_chunk : a_material) { + auto& cell = storage->surfaces[a_chunk.first]; + size_t a_cell_ind = a_cell_index[a_chunk.first]; + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix scalar_cell_dof = x_dof.block(a_cell_ind*a_cell_dof + + n_vel_scal_cbs + n_elastic_cell_dof, + 0, n_scal_cbs, 1); + + auto points = cell.point_ids(); + size_t n_p = points.size(); + // std::cout << n_p < vhx_silo("vhx", approx_ux); + disk::silo_zonal_variable vhy_silo("vhy", approx_uy); + disk::silo_zonal_variable vhy_bis_silo("norm_v", approx_uy_bis); + disk::silo_zonal_variable vh_silo("vh", approx_u); + silo.add_variable("mesh", vhx_silo); + silo.add_variable("mesh", vhy_silo); + silo.add_variable("mesh", vhy_bis_silo); + silo.add_variable("mesh", vh_silo); + } + else { + disk::silo_nodal_variable vhx_silo("vhx", approx_ux); + disk::silo_nodal_variable vhy_silo("vhy", approx_uy); + disk::silo_nodal_variable vhy_bis_silo("norm_v", approx_uy_bis); + disk::silo_nodal_variable vh_silo("vh", approx_u); + silo.add_variable("mesh", vhx_silo); + silo.add_variable("mesh", vhy_silo); + silo.add_variable("mesh", vhy_bis_silo); + silo.add_variable("mesh", vh_silo); + } + + silo.close(); + tc.toc(); + // std::cout << " "; + // std::cout << bold << cyan << "Silo file rendered in : " << tc << " seconds" << reset + // << std::endl; + + } + + /// Record acoustic data + static void record_acoustic_data_elasto_acoustic_four_fields( size_t it, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, Matrix & x_dof, bool e_side_Q, std::ostream & seismogram_file = std::cout) { + + using RealType = double; + auto dim = Mesh::dimension; + + // Basis + size_t n_vel_scal_cbs = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_scal_cbs = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t a_n_cbs = n_vel_scal_cbs + n_scal_cbs; + size_t a_n_cell_dof = assembler.get_a_n_cells_dof(); + + RealType vh = 0.0; + + typename Mesh::point_type pt = pt_cell_index.first; + + // FIND CELL + if (pt_cell_index.second == -1){ + std::set cell_indexes = find_acoustic_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + seismogram_file << "\"Time\"" << "," << "\"vh\"" << std::endl; + } + + size_t cell_ind = pt_cell_index.second; + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix all_dofs = assembler.gather_a_dof_data(cell_ind, msh, cell, x_dof); + Matrix scalar_cell_dof = all_dofs.block(n_vel_scal_cbs,0,n_scal_cbs,1); + auto t_phi = cell_basis.eval_functions( pt ); + vh = scalar_cell_dof.dot( t_phi ); + + seismogram_file << it << "," << std::setprecision(16) << vh << std::endl; + seismogram_file.flush(); + + } + + /// Record elastic data + static void record_elastic_data_elasto_acoustic_four_fields( size_t it, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, Matrix & x_dof, bool e_side_Q, std::ostream & seismogram_file = std::cout) { + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t e_n_cbs = n_ten_cbs + n_vec_cbs; + size_t e_n_cell_dof = assembler.get_e_n_cells_dof(); + + Matrix eh = Matrix::Zero(2, 2); + + typename Mesh::point_type pt = pt_cell_index.first; + if (pt_cell_index.second == -1){ + std::set cell_indexes = find_elastic_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + seismogram_file << "\"Time\"" << "," << "\"Sxx\"" << "," << "\"Sxy\"" << "," << "\"Syy\"" << std::endl; + } + size_t cell_ind = pt_cell_index.second; + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + + // stress tensor evaluation + size_t ten_dofs = disk::sym_matrix_basis_size(hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + auto ten_basis = make_sym_matrix_monomial_basis(msh, cell, hho_di.grad_degree()); + Matrix all_dofs = assembler.gather_e_dof_data(cell_ind, msh, cell, x_dof); + Matrix ten_x_cell_dof = all_dofs.block(0, 0, ten_dofs, 1); + auto t_phi = ten_basis.eval_functions(pt); + eh = disk::eval(ten_x_cell_dof, t_phi); + + tc.toc(); + seismogram_file << it << "," << std::setprecision(16) << eh(0,0) << "," << std::setprecision(16) << eh(0,1) << "," << std::setprecision(16) << eh(1,1) << std::endl; + seismogram_file.flush(); + + } + + /// Record velocity + static void record_velocity_data_elasto_acoustic_two_fields(size_t it, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_two_fields_assembler & assembler, Matrix & u_dof, Matrix & v_dof, bool e_side_Q, std::ostream & seismogram_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + + Matrix vh = Matrix::Zero(2, 1); + + typename Mesh::point_type pt = pt_cell_index.first; + if(pt_cell_index.second == -1){ + std::set cell_indexes = find_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + seismogram_file << "\"Time\"" << "," << "\"vhx\"" << "," << "\"vhy\"" << std::endl; + } + + { + size_t cell_ind = pt_cell_index.second; + + + if(e_side_Q){// vector evaluation + + size_t cell_dof = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix all_dofs = assembler.gather_e_dof_data(cell_ind, msh, cell, v_dof); + Matrix vec_x_cell_dof = all_dofs.block(0, 0, cell_dof, 1); + auto t_phi = cell_basis.eval_functions( pt ); + assert(t_phi.rows() == cell_basis.size()); + vh = disk::eval(vec_x_cell_dof, t_phi); + } + else + {// reconstructed velocity evaluation + + size_t cell_dof = disk::scalar_basis_size(hho_di.cell_degree(), dim); + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto rec_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + auto gr = make_scalar_hho_laplacian(msh, cell, hho_di); + Matrix all_dofs = assembler.gather_a_dof_data(cell_ind, msh, cell, u_dof); + Matrix recdofs = gr.first * all_dofs; + + auto t_dphi = rec_basis.eval_gradients( pt ); + Matrix grad_uh = Matrix::Zero(); + + for (size_t i = 1; i < t_dphi.rows(); i++){ + grad_uh = grad_uh + recdofs(i-1)*t_dphi.block(i, 0, 1, 2); + } + acoustic_material_data a_mat = assembler.get_a_material_data().find(cell_ind)->second; + RealType rho = a_mat.rho(); + vh = (1.0/rho)*(grad_uh); + } + + } + tc.toc(); + std::cout << bold << cyan << "Value recorded: " << tc << " seconds" << reset << std::endl; + seismogram_file << it << "," << std::setprecision(16) << vh(0,0) << "," << std::setprecision(16) << vh(1,0) << std::endl; + seismogram_file.flush(); + + } + + static void record_velocity_data_elasto_acoustic_four_fields(size_t it, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, Matrix & x_dof, bool e_side_Q, std::ostream & seismogram_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t e_n_cbs = n_ten_cbs + n_vec_cbs; + size_t n_vel_scal_cbs = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_scal_cbs = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t a_n_cbs = n_vel_scal_cbs + n_scal_cbs; + size_t e_n_cell_dof = assembler.get_e_n_cells_dof(); + size_t a_n_cell_dof = assembler.get_a_n_cells_dof(); + Matrix vh = Matrix::Zero(2, 1); + + typename Mesh::point_type pt = pt_cell_index.first; + + if (e_side_Q) { + // FIND CELL + if (pt_cell_index.second == -1){ + std::set cell_indexes = find_elastic_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + seismogram_file << "\"Time\"" << "," << "\"vhx\"" << "," << "\"vhy\"" << std::endl; + } + // RECORD DATA + size_t cell_ind = pt_cell_index.second; + size_t cell_dof = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = make_vector_monomial_basis(msh, cell, hho_di.cell_degree()); + Matrix all_dofs = assembler.gather_e_dof_data(cell_ind, msh, cell, x_dof); + Matrix vec_x_cell_dof = all_dofs.block(0 + n_ten_cbs, 0, cell_dof, 1); + auto t_phi = cell_basis.eval_functions(pt); + assert(t_phi.rows() == cell_basis.size()); + vh = disk::eval(vec_x_cell_dof, t_phi); + } + else { + // FIND CELL + if (pt_cell_index.second == -1){ + std::set cell_indexes = find_acoustic_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + seismogram_file << "\"Time\"" << "," << "\"vhx\"" << "," << "\"vhy\"" << std::endl; + } + // RECORD DATA + size_t cell_ind = pt_cell_index.second; + size_t cell_dof = disk::vector_basis_size(hho_di.cell_degree(), dim, dim); + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = make_scalar_monomial_basis(msh, cell, hho_di.reconstruction_degree()); + Matrix all_dofs = assembler.gather_a_dof_data(cell_ind, msh, cell, x_dof); + Matrix flux_cell_dof = all_dofs.block(0, 0, cell_dof, 1); + auto t_dphi = cell_basis.eval_gradients( pt ); + Matrix flux_uh = Matrix::Zero(); + for (size_t i = 1; i < t_dphi.rows(); i++) + flux_uh = flux_uh + flux_cell_dof(i-1)*t_dphi.block(i, 0, 1, 2); + vh = flux_uh; + } + + tc.toc(); + seismogram_file << it << "," << std::setprecision(16) << vh(0,0) << "," << std::setprecision(16) << vh(1,0) << std::endl; + seismogram_file.flush(); + } + + /// Record interface data + static void record_acoustic_pressure_coupling_data_elasto_acoustic_four_fields(size_t it, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, Matrix & x_dof, bool e_side_Q, std::set interface_face_indexes, std::ostream & seismogram_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + + size_t n_vel_scal_cbs = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t n_scal_cbs = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t a_n_cbs = n_vel_scal_cbs + n_scal_cbs; + size_t a_n_fbs = disk::scalar_basis_size(hho_di.face_degree(), Mesh::dimension - 1); + RealType vh = 0.0; + + typename Mesh::point_type pt = pt_cell_index.first; + typename Mesh::face_type fb; + + // FIND FACE + if (pt_cell_index.second == -1) { + seismogram_file << "\"Time\"" << "," << "\"vh\"" << std::endl; + std::set cell_indexes = find_acoustic_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + } + auto& cell = msh.backend_storage()->surfaces[pt_cell_index.second]; + auto cell_faces = faces(msh, cell); + for (auto face : cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) + fb = face; + } + + auto fc_id = msh.lookup(fb); + auto face_basis = make_scalar_monomial_basis(msh, fb, hho_di.face_degree()); + Matrix all_dofs = assembler.gather_a_dof_data(pt_cell_index.second, msh, cell, x_dof); + Matrix face_dofs = all_dofs.block(a_n_cbs, 0, a_n_fbs, 1); + auto t_phi = face_basis.eval_functions(pt); + vh = face_dofs.dot(t_phi); + + seismogram_file << it << "," << std::setprecision(16) << vh << std::endl; + seismogram_file.flush(); + + } + + static void record_elastic_velocity_coupling_data_elasto_acoustic_four_fields(size_t it, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, Matrix & x_dof, bool e_side_Q, std::set interface_face_indexes, std::ostream & seismogram_file = std::cout){ + + timecounter tc; + tc.tic(); + + using RealType = double; + auto dim = Mesh::dimension; + + size_t n_ten_cbs = disk::sym_matrix_basis_size(hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + size_t n_vec_cbs = disk::vector_basis_size(hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); + size_t e_n_cbs = n_ten_cbs + n_vec_cbs; + size_t e_n_cell_dof = assembler.get_e_n_cells_dof(); + size_t e_n_fbs = disk::vector_basis_size(hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + Matrix vh = Matrix::Zero(2, 1); + + typename Mesh::point_type pt = pt_cell_index.first; + typename Mesh::face_type fb; + + // FIND FACE + if (pt_cell_index.second == -1) { + seismogram_file << "\"Time\"" << "," << "\"vhx\"" << "," << "\"vhy\"" << std::endl; + std::set cell_indexes = find_elastic_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + } + auto& cell = msh.backend_storage()->surfaces[pt_cell_index.second]; + auto cell_faces = faces(msh, cell); + for (auto face : cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) + fb = face; + } + + // RECORD DATA + auto fc_id = msh.lookup(fb); + auto face_basis = make_vector_monomial_basis(msh, fb, hho_di.face_degree()); + Matrix all_dofs = assembler.gather_e_dof_data(pt_cell_index.second, msh, cell, x_dof); + Matrix face_dofs = all_dofs.block(e_n_cbs, 0, e_n_fbs, 1); + auto t_phi = face_basis.eval_functions(pt); + vh = disk::eval(face_dofs, t_phi); + + seismogram_file << it << "," << std::setprecision(16) << vh(0,0) << "," << std::setprecision(16) << vh(1,0) << std::endl; + seismogram_file.flush(); + + } + +}; + + + +#endif /* postprocessor_hpp */ + diff --git a/apps/wave_propagation/src/common/preprocessor.hpp b/apps/wave_propagation/src/common/preprocessor.hpp new file mode 100644 index 00000000..7a2cec59 --- /dev/null +++ b/apps/wave_propagation/src/common/preprocessor.hpp @@ -0,0 +1,457 @@ +// +// preprocessor.hpp +// acoustics +// +// Created by Omar Durán on 4/10/20. +// + +#pragma once +#ifndef preprocessor_hpp +#define preprocessor_hpp + +#include +#include "../../../../contrib/sol2/include/sol/sol.hpp" + + +class simulation_data { + +public: + + size_t m_k_degree; + + size_t m_n_divs; + + bool m_hdg_stabilization_Q; + + bool m_scaled_stabilization_Q; + + bool m_sc_Q; + + size_t m_nt_divs; + + bool m_render_silo_files_Q; + + bool m_report_energy_Q; + + bool m_iterative_solver_Q; + + bool m_polygonal_mesh_Q; + + size_t m_exact_functions; + + simulation_data() : m_k_degree(2), m_n_divs(2), m_hdg_stabilization_Q(false), + m_scaled_stabilization_Q(false), m_sc_Q(false), m_nt_divs(0), + m_render_silo_files_Q(true), m_report_energy_Q(false), + m_iterative_solver_Q(true), m_polygonal_mesh_Q(false), m_exact_functions(1) { + + } + + simulation_data(const simulation_data & other){ + + m_k_degree = other.m_k_degree; + m_n_divs = other.m_n_divs; + m_hdg_stabilization_Q = other.m_hdg_stabilization_Q; + m_scaled_stabilization_Q = other.m_scaled_stabilization_Q; + m_sc_Q = other.m_sc_Q; + m_nt_divs = other.m_nt_divs; + m_render_silo_files_Q = other.m_render_silo_files_Q; + m_report_energy_Q = other.m_report_energy_Q; + m_iterative_solver_Q = other.m_iterative_solver_Q; + m_polygonal_mesh_Q = other.m_polygonal_mesh_Q; + m_exact_functions = other.m_exact_functions; + } + + const simulation_data & operator=(const simulation_data & other){ + + // check for self-assignment + if(&other == this){ + return *this; + } + + m_k_degree = other.m_k_degree; + m_n_divs = other.m_n_divs; + m_hdg_stabilization_Q = other.m_hdg_stabilization_Q; + m_scaled_stabilization_Q = other.m_scaled_stabilization_Q; + m_sc_Q = other.m_sc_Q; + m_nt_divs = other.m_nt_divs; + m_render_silo_files_Q = other.m_render_silo_files_Q; + m_report_energy_Q = other.m_report_energy_Q; + m_iterative_solver_Q = other.m_iterative_solver_Q; + m_polygonal_mesh_Q = other.m_polygonal_mesh_Q; + m_exact_functions = other.m_exact_functions; + return *this; + } + + ~simulation_data(){ + } + + void write_simulation_data(std::ostream & simulation_log = std::cout){ + simulation_log << " Input parameters:" << std::endl; + simulation_log << " Iterative solver: " << m_iterative_solver_Q << std::endl; + simulation_log << " HHO setting: " << std::endl; + simulation_log << " - Polynomial degree -k: " << m_k_degree << " (Face unknowns)" << std::endl; + simulation_log << " - Stabilization type -s: " << m_hdg_stabilization_Q << " (Equal-order=0, Mixed-order=1)" << std::endl; + simulation_log << " - Scaled stabilization -r: " << m_scaled_stabilization_Q << " (O(1)=0, O(1/h)=1)" << std::endl; + simulation_log << " - Static condensation -c: " << m_sc_Q << std::endl; + simulation_log << " Mesh:" << "- Refinement level -l : " << m_n_divs << std::endl; + simulation_log << " Time refinement level -n : " << m_nt_divs << std::endl; + }; + + void print_simulation_data(){ + + std::cout << std::endl << " "; + std::cout << bold << red << "SIMULATION PARAMETERS : " << reset; + + std::cout << bold << cyan << std::endl; + std::cout << " "; + std::cout << bold << "Iterative solver : " << m_iterative_solver_Q << reset; + + std::cout << bold << cyan << std::endl; + std::cout << " "; + std::cout << bold << "HHO setting : " << reset; + std::cout << yellow; + std::cout << bold << " - Polynomial degree -k : " << m_k_degree << " (Face unknowns)" + << std::endl; + std::cout << " "; + std::cout << " - Stabilization type -s : " << m_hdg_stabilization_Q + << " (Equal-order=0, Mixed-order=1)" << std::endl; + std::cout << " "; + std::cout << " - Scaled stabilization -r : " << m_scaled_stabilization_Q + << " (O(1)=0, O(1/h)=1)" << std::endl; + std::cout << " "; + std::cout << " - Static condensation -c : " << m_sc_Q; + + std::cout << bold << cyan << std::endl; + std::cout << " "; + std::cout << bold << "Mesh :" << reset; + std::cout << yellow; + std::cout << bold << " - Polygonal mesh -p : " << m_polygonal_mesh_Q << std::endl; + std::cout << " "; + std::cout << " - Refinement level -l : " << m_n_divs << std::endl; + + std::cout << bold << cyan; + std::cout << " "; + std::cout << bold << "Time refinement level -n : " << m_nt_divs << reset; + + std::cout << bold << cyan << std::endl; + std::cout << " "; + std::cout << bold << "Post process :" << reset; + std::cout << yellow; + std::cout << bold << " - Silo files -f : " << m_render_silo_files_Q << std::endl; + std::cout << " "; + std::cout << bold << " - Energy file -e : " << m_report_energy_Q << reset; + + std::cout << std::endl << std::endl; + + } + +}; + +class preprocessor { + +public: + + + + static void PrintHelp() + { + std::cout << + "-k : Face polynomial degree: default 0\n" + "-l : Number of uniform space refinements: default 0\n" + "-s <0-1>: Stabilization type 0 -> HHO, 1 -> HDG-like: default 0 \n" + "-r <0-1>: Scaled stabilization 0 -> without, 1 -> with: default 0 \n" + "-n : Number of uniform time refinements: default 0\n" + "-f <0-1>: Write silo files: default 0\n" + "-e <0-1>: Report (time,energy) pairs: default 0\n" + "-c <0-1>: Static Condensation (implicit schemes): default 0 \n" + "-help: Show help\n"; + exit(1); + } + + static simulation_data process_args(int argc, char** argv) + { + const char* const short_opts = "k:p:l:s:r:n:c:f:e:"; + const option long_opts[] = { + {"degree", required_argument, nullptr, 'k'}, + {"poly_mesh", required_argument, nullptr, 'p'}, + {"xref", required_argument, nullptr, 'l'}, + {"stab", required_argument, nullptr, 's'}, + {"scal", required_argument, nullptr, 'r'}, + {"tref", required_argument, nullptr, 'n'}, + {"c", optional_argument, nullptr, 'c'}, + {"file", optional_argument, nullptr, 'f'}, + {"energy", optional_argument, nullptr, 'e'}, + {"help", no_argument, nullptr, 'h'}, + {nullptr, no_argument, nullptr, 0} + }; + + size_t k_degree = 0; + size_t n_divs = 0; + size_t nt_divs = 0; + size_t poly_mesh = 0; + bool hdg_Q = false; + bool scaled_Q = false; + bool sc_Q = false; + bool silo_files_Q = true; + bool report_energy_Q = true; + + while (true) + { + const auto opt = getopt_long(argc, argv, short_opts, long_opts, nullptr); + + if (-1 == opt) + break; + + switch (opt) + { + case 'k': + k_degree = std::stoi(optarg); + break; + + case 'p': + poly_mesh = std::stoi(optarg); + break; + + case 'l': + n_divs = std::stoi(optarg); + break; + + case 's': + hdg_Q = std::stoi(optarg); + break; + + case 'r': + scaled_Q = std::stoi(optarg); + break; + + case 'n': + nt_divs = std::stoi(optarg); + break; + + case 'c': + sc_Q = std::stoi(optarg); + break; + + case 'f': + silo_files_Q = std::stoi(optarg); + break; + + case 'e': + report_energy_Q = std::stoi(optarg); + break; + + + case 'h': // -h or --help + case '?': // Unrecognized option + default: + preprocessor::PrintHelp(); + break; + } + } + + // populating simulation data + simulation_data sim_data; + sim_data.m_k_degree = k_degree; + sim_data.m_polygonal_mesh_Q = poly_mesh; + sim_data.m_n_divs = n_divs; + sim_data.m_hdg_stabilization_Q = hdg_Q; + sim_data.m_scaled_stabilization_Q = scaled_Q; + sim_data.m_sc_Q = sc_Q; + sim_data.m_nt_divs = nt_divs; + sim_data.m_render_silo_files_Q = silo_files_Q; + sim_data.m_report_energy_Q = report_energy_Q; + return sim_data; + } + + static void PrintTestHelp() + { + std::cout << + "-k : Maximum Face polynomial degree: default 0\n" + "-l : Maximum Number of uniform space refinements: default 0\n" + "-s <0-1>: Stabilization type 0 -> HHO, 1 -> HDG-like: default 0 \n" + "-r <0-1>: Scaled stabilization 0 -> without, 1 -> with: default 0 \n" + "-q <0-1>: Quadratic function type 0 -> non-polynomial, 1 -> quadratic: default 0 \n" + "-f <0-1>: Write silo files : default 0\n" + "-c <0-1>: Static Condensation: default 0 \n" + "-help: Show help\n"; + exit(1); + } + + static simulation_data process_convergence_test_args(int argc, char** argv) + { + const char* const short_opts = "k:l:s:r:c:q:f:"; + const option long_opts[] = { + {"degree", required_argument, nullptr, 'k'}, + {"xref", required_argument, nullptr, 'l'}, + {"stab", required_argument, nullptr, 's'}, + {"scal", required_argument, nullptr, 'r'}, + {"file", optional_argument, nullptr, 'f'}, + {"qfunc", optional_argument, nullptr, 'q'}, + {"cond", optional_argument, nullptr, 'c'}, + {"help", no_argument, nullptr, 'h'}, + {nullptr, no_argument, nullptr, 0} + }; + + size_t k_degree = 0; + size_t n_divs = 0; + bool hdg_Q = false; + bool scaled_Q = false; + bool sc_Q = false; + bool quadratic_func_Q = false; + bool silo_files_Q = false; + + while (true) + { + const auto opt = getopt_long(argc, argv, short_opts, long_opts, nullptr); + + if (-1 == opt) + break; + + switch (opt) + { + case 'k': + k_degree = std::stoi(optarg); + break; + + case 'l': + n_divs = std::stoi(optarg); + break; + + case 's': + hdg_Q = std::stoi(optarg); + break; + + case 'r': + scaled_Q = std::stoi(optarg); + break; + + case 'c': + sc_Q = std::stoi(optarg); + break; + + case 'q': + quadratic_func_Q = std::stoi(optarg); + break; + + case 'f': + silo_files_Q = std::stoi(optarg); + break; + + case 'h': // -h or --help + case '?': // Unrecognized option + default: + preprocessor::PrintTestHelp(); + break; + } + } + + // populating simulation data + simulation_data sim_data; + sim_data.m_k_degree = k_degree; + sim_data.m_n_divs = n_divs; + sim_data.m_hdg_stabilization_Q = hdg_Q; + sim_data.m_scaled_stabilization_Q = scaled_Q; + sim_data.m_sc_Q = sc_Q; + sim_data.m_render_silo_files_Q = silo_files_Q; + return sim_data; + } + + static simulation_data process_convergence_test_lua_file(char** argv) + { + + sol::state lua; + lua.open_libraries(sol::lib::math, sol::lib::base); + + // expected input tables + lua["config"] = lua.create_table(); + + std::string lua_file = argv[3]; + auto r = lua.do_file(lua_file); + if ( !r.valid() ){ + PrintConvergeceTestExample(); + } + + // populating simulation data + simulation_data sim_data; + sim_data.m_k_degree = lua["config"]["max_k_deg"].get_or(0); + sim_data.m_n_divs = lua["config"]["max_l_ref"].get_or(0); + sim_data.m_hdg_stabilization_Q = lua["config"]["stab_type"].get_or(0); + sim_data.m_scaled_stabilization_Q = lua["config"]["stab_scal"].get_or(0); + sim_data.m_sc_Q = lua["config"]["stat_cond"].get_or(0); + sim_data.m_render_silo_files_Q = lua["config"]["silo_output"].get_or(0); + sim_data.m_iterative_solver_Q = lua["config"]["iter_solv"].get_or(0); + sim_data.m_exact_functions = lua["config"]["exac_func"].get_or(0); + sim_data.m_polygonal_mesh_Q = lua["config"]["poly_mesh"].get_or(0); + return sim_data; + } + + static void PrintConvergeceTestExample() + { + std::cout << "Please specify a lua configuration file like this: " << std::endl; + std::cout << + "config.max_k_deg = 4 -- : Maximum face polynomial degree: default 0\n" + "config.max_l_ref = 4 -- : Maximum number of uniform spatial refinements: default 0\n" + "config.stab_type = 0 -- <0-1>: Stabilization type 0 (HHO), 1 (HDG-like): default 0\n" + "config.stab_scal = 1 -- <0-1>: Stabilization scaling 0 O(1), 1 O(1/h_{f}): default 0\n" + "config.stat_cond = 1 -- <0-1>: Static condensation: default 0\n" + "config.iter_solv = 0 -- <0-1>: Iterative solver : default 0\n" + "config.exac_func = 0 -- <0-1>: Manufactured function type 0 (non-polynomial), 1 (quadratic): default 0\n" + "config.poly_mesh = 0 -- <0-1>: Use of polynoal meshes : default 0\n" + "config.silo_output = 0 -- <0-1>: Write silo files : default 0\n"; + exit(1); + throw std::invalid_argument("Program will stop."); + } + + static simulation_data process_acoustics_lua_file(char** argv) + { + + sol::state lua; + lua.open_libraries(sol::lib::math, sol::lib::base); + + // expected input tables + lua["config"] = lua.create_table(); + + std::string lua_file = argv[3]; + auto r = lua.do_file(lua_file); + if ( !r.valid() ){ + PrintSimulationExample(); + } + + // populating simulation data + simulation_data sim_data; + sim_data.m_k_degree = lua["config"]["fac_k_deg"].get_or(0); + sim_data.m_n_divs = lua["config"]["num_l_ref"].get_or(0); + sim_data.m_nt_divs = lua["config"]["num_t_ref"].get_or(0); + sim_data.m_hdg_stabilization_Q = lua["config"]["stab_type"].get_or(0); + sim_data.m_scaled_stabilization_Q = lua["config"]["stab_scal"].get_or(0); + sim_data.m_sc_Q = lua["config"]["stat_cond"].get_or(0); + sim_data.m_render_silo_files_Q = lua["config"]["silo_output"].get_or(0); + sim_data.m_iterative_solver_Q = lua["config"]["iter_solv"].get_or(0); + sim_data.m_polygonal_mesh_Q = lua["config"]["poly_mesh"].get_or(0); + sim_data.m_exact_functions = lua["config"]["exac_func"].get_or(0); + sim_data.m_report_energy_Q = lua["config"]["writ_ener"].get_or(0); + return sim_data; + } + + static void PrintSimulationExample() + { + std::cout << "Please specify a lua configuration file like this: " << std::endl; + std::cout << + "config.fac_k_deg = 3 -- : Face polynomial degree: default 0\n" + "config.num_l_ref = 3 -- : Number of uniform spatial refinements: default 0\n" + "config.num_t_ref = 7 -- : Number of uniform time refinements: default 0\n" + "config.stab_type = 1 -- <0-1>: Stabilization type 0 (HHO), 1 (HDG-like): default 0\n" + "config.stab_scal = 0 -- <0-1>: Stabilization scaling 0 O(1), 1 O(1/h_{f}): default 0\n" + "config.stat_cond = 1 -- <0-1>: Static condensation: default 0\n" + "config.iter_solv = 0 -- <0-1>: Iterative solver : default 0\n" + "config.poly_mesh = 0 -- <0-1>: Use of polynoal meshes : default 0\n" + "config.exac_func = 0 -- <0-2>: Exact function type {0,1,2} : default 0\n" + "config.writ_ener = 1 -- <0-1>: Report energy at each time value : default 0\n" + "config.silo_output = 0 -- <0-1>: Write silo files : default 0\n"; + exit(1); + throw std::invalid_argument("Program will stop."); + } + +}; + +#endif /* preprocessor_hpp */ diff --git a/apps/wave_propagation/src/common/scal_analytic_functions.hpp b/apps/wave_propagation/src/common/scal_analytic_functions.hpp new file mode 100644 index 00000000..aa6281d4 --- /dev/null +++ b/apps/wave_propagation/src/common/scal_analytic_functions.hpp @@ -0,0 +1,471 @@ +// +// scal_analytic_functions.hpp +// acoustics +// +// Created by Omar Durán on 4/9/20. +// + +#pragma once +#ifndef scal_analytic_functions_hpp +#define scal_analytic_functions_hpp + +#define contrast 3.0 +#define n_terms 200 + +class scal_analytic_functions { + +public: + + /// Enumerate defining the function type + enum EFunctionType { EFunctionNonPolynomial = 0, EFunctionQuadraticInTime = 1, + EFunctionQuadraticInSpace = 2, EFunctionQuadraticInSpaceTime = 3, + EFunctionInhomogeneousInSpace = 4, Fluid_pulse = 5}; + + + scal_analytic_functions(){ + m_function_type = EFunctionNonPolynomial; + } + + ~scal_analytic_functions(){ + } + + void set_function_type(EFunctionType function_type){ + m_function_type = function_type; + } + + std::function::point_type& )> Evaluate_u(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return (1.0/(std::sqrt(2.0)*M_PI))*std::sin(std::sqrt(2.0)*M_PI*t) * std::sin(M_PI*pt.x()) * std::sin(M_PI*pt.y()); + }; + } + break; + case EFunctionQuadraticInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return (1 - pt.x())*pt.x()*(1 - pt.y())*pt.y()*std::sin(std::sqrt(2.0)*M_PI*t); + }; + } + break; + case EFunctionQuadraticInTime: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return t*t*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + }; + } + break; + case EFunctionQuadraticInSpaceTime: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return t*t*(1 - pt.x())*pt.x()*(1 - pt.y())*pt.y(); + }; + } + break; + case EFunctionInhomogeneousInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + + size_t n = n_terms; + double x,y,c1,c2; + c1 = contrast; + c2 = 1.0; + x = pt.x(); + y = pt.y(); + + double p = 0.0; + double c = 1.0; + for (int k = 0; k <= n; k++) { + + if (x < 0.5) { + double plvp, plvm; + plvp = (1.0/100.0)*exp(-(20.0*((k+x-c1*t)-0.2))*(20.0*((k+x-c1*t)-0.2))); + plvm = (1.0/100.0)*exp(-(20.0*((k-x-c1*t)-0.2))*(20.0*((k-x-c1*t)-0.2))); + p+=c*(plvp-plvm); + }else{ + double pr; + pr = (1.0/100.0)*exp(-(20.0*(((c1/c2)*(x-0.5)+0.5+k-c1*t)-0.2))*(20.0*(((c1/c2)*(x-0.5)+0.5+k-c1*t)-0.2))); + p+=((2.0*c1)/(c2+c1))*c*pr; + } + c*=(c2-c1)/(c2+c1); + } + return p; + }; + } + break; + default: + { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + } + + } + + std::function::point_type& )> Evaluate_v(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return std::cos(std::sqrt(2.0)*M_PI*t) * std::sin(M_PI*pt.x()) * std::sin(M_PI*pt.y()); + }; + } + break; + case EFunctionQuadraticInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return std::sqrt(2.0)*M_PI*(1 - pt.x())*pt.x()*(1 - pt.y())*pt.y()*std::cos(std::sqrt(2.0)*M_PI*t); + }; + } + break; + case EFunctionQuadraticInTime: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return 2.0*t*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + }; + } + break; + case EFunctionQuadraticInSpaceTime: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return 2.0*t*(1 - pt.x())*pt.x()*(1 - pt.y())*pt.y(); + }; + } + break; + case EFunctionInhomogeneousInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + + size_t n = n_terms; + double x,y,c1,c2; + c1 = contrast; + c2 = 1.0; + x = pt.x(); + y = pt.y(); + + double v = 0.0; + double c = 1.0; + for (int k = 0; k <= n; k++) { + + if (x < 0.5) { + double vlvp, vlvm; + vlvp = (8.0*c1)* exp(-(20.0*((k+x-c1*t)-0.2))*(20.0*((k+x-c1*t)-0.2)))*((k+x-c1*t)-0.2); + vlvm = (8.0*c1)* exp(-(20.0*((k-x-c1*t)-0.2))*(20.0*((k-x-c1*t)-0.2)))*((k-x-c1*t)-0.2); + v+=c*(vlvp-vlvm); + }else{ + double vl; + vl = (8.0*c1)*exp(-(20.0*(((c1/c2)*(x-0.5)+0.5+k-c1*t)-0.2))*(20.0*(((c1/c2)*(x-0.5)+0.5+k-c1*t)-0.2)))*(((c1/c2)*(x-0.5)+0.5+k-c1*t)-0.2); + v+=((2.0*c1)/(c2+c1))*c*vl; + } + c*=(c2-c1)/(c2+c1); + } + return v; + }; + } + break; + default: + { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + } + + } + + std::function::point_type& )> Evaluate_a(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return -std::sqrt(2.0) * M_PI * std::sin(std::sqrt(2.0)*M_PI*t) * std::sin(M_PI*pt.x()) * std::sin(M_PI*pt.y()); + }; + } + break; + case EFunctionQuadraticInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return -2*M_PI*M_PI*(1 - pt.x())*pt.x()*(1 - pt.y())*pt.y()*std::sin(std::sqrt(2)*M_PI*t); + }; + } + break; + case EFunctionQuadraticInTime: + { + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 2.0*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + }; + } + break; + case EFunctionQuadraticInSpaceTime: + { + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 2.0*(1 - pt.x())*pt.x()*(1 - pt.y())*pt.y(); + }; + } + break; + case EFunctionInhomogeneousInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + + size_t n = n_terms; + double x,y,c1,c2; + c1 = contrast; + c2 = 1.0; + x = pt.x(); + y = pt.y(); + + double a = 0.0; + double c = 1.0; + for (int k = 0; k <= n; k++) { + + if (x < 0.5) { + double alvp, alvm, xip, xim; + xip=((k+x-c1*t)-0.2); + alvp = (8.0*c1*c1)* exp(-(20.0*((k+x-c1*t)-0.2))*(20.0*((k+x-c1*t)-0.2)))*(800.0*xip*xip-1.0); + + xim=((k-x-c1*t)-0.2); + alvm = (8.0*c1*c1)* exp(-(20.0*((k-x-c1*t)-0.2))*(20.0*((k-x-c1*t)-0.2)))*(800.0*xim*xim-1.0); + a+=c*(alvp-alvm); + }else{ + double al, xi; + xi= (((c1/c2)*(x-0.5)+0.5+k-c1*t)-0.2); + al = (8.0*c1*c1)*exp(-(20.0*(((c1/c2)*(x-0.5)+0.5+k-c1*t)-0.2))*(20.0*(((c1/c2)*(x-0.5)+0.5+k-c1*t)-0.2)))*(800.0*xi*xi-1.0); + a+=((2.0*c1)/(c2+c1))*c*al; + } + c*=(c2-c1)/(c2+c1); + } + return a; + }; + } + break; + default: + { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + } + + } + + std::function::point_type& )> Evaluate_f(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: + { + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + case EFunctionQuadraticInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + f = 2*(x - x*x + y - M_PI*M_PI*(-1 + x)*x*(-1 + y)*y - y*y)*std::sin(std::sqrt(2.0)*M_PI*t); + return f; + }; + } + break; + case EFunctionQuadraticInTime: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return 2.0*(1.0 + M_PI*M_PI*t*t)*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + }; + } + break; + case EFunctionQuadraticInSpaceTime: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + f = 2.0*((-1.0 + x)*x*(-1.0 + y)*y + t*t*(x - x*x + y - y*y)); + return f; + }; + } + break; + case EFunctionInhomogeneousInSpace: + { + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + case Fluid_pulse: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x, y, xc, yc, tau, freq, Ricker, alpha, sigma, sigma2, sigma3, eps, f; + + // Source term ponctuel + x = pt.x(); y = pt.y(); + xc = 0.5; yc = 0.5; + + if (x==xc && y==yc) { + + tau = 0.4; + freq = 5.0; + alpha = - M_PI*M_PI * freq*freq; + + if ( t < 0.5*tau ) { + sigma = alpha*(t-tau)*(t-tau); + Ricker = 2.0 * alpha * (1+2*sigma) * exp(sigma); + } + else { + Ricker = 0; + } + + sigma = M_PI*freq*(t-tau); + sigma2 = sigma*sigma; + sigma3 = M_PI*freq; + + f = -4.0*sigma*sigma3*exp(-sigma2)-2.0*sigma*sigma3*Ricker; + + return f; + } + + else { + f = 0; + return f; + } + + return f; + + }; + } + default: + { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + } + + } + + + std::function(const typename disk::generic_mesh::point_type& )> Evaluate_q(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector flux(2); + flux[0] = (std::sin(std::sqrt(2)*M_PI*t)*std::cos(M_PI*x)*std::sin(M_PI*y))/std::sqrt(2.0); + flux[1] = (std::sin(std::sqrt(2)*M_PI*t)*std::sin(M_PI*x)*std::cos(M_PI*y))/std::sqrt(2.0); + return flux; + }; + } + break; + case EFunctionQuadraticInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector flux(2); + flux[0] = (1 - x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) - x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + flux[1] = (1 - x)*x*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) - (1 - x)*x*y*std::sin(std::sqrt(2.0)*M_PI*t); + return flux; + }; + } + break; + case EFunctionQuadraticInTime: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector flux(2); + flux[0] = M_PI*t*t*std::cos(M_PI*x)*std::sin(M_PI*y); + flux[1] = M_PI*t*t*std::sin(M_PI*x)*std::cos(M_PI*y); + return flux; + }; + } + break; + case EFunctionQuadraticInSpaceTime: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector flux(2); + flux[0] = t*t*(1 - x)*(1 - y)*y - t*t*x*(1 - y)*y; + flux[1] = t*t*(1 - x)*x*(1 - y) - t*t*(1 - x)*x*y; + return flux; + }; + } + break; + case EFunctionInhomogeneousInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> std::vector { + + size_t n = n_terms; + double x,y,c1,c2; + c1 = contrast; + c2 = 1.0; + x = pt.x(); + y = pt.y(); + + double qx = 0.0; + double c = 1.0; + for (int k = 0; k <= n; k++) { + + if (x < 0.5) { + double qxlvp, qxlvm; + qxlvp = -(8.0)* exp(-(20.0*((k-x-c1*t)-0.2))*(20.0*((k-x-c1*t)-0.2)))*((k-x-c1*t)-0.2); + qxlvm = -(8.0)* exp(-(20.0*((k+x-c1*t)-0.2))*(20.0*((k+x-c1*t)-0.2)))*((k+x-c1*t)-0.2); + qx+=c1*c1*c*(qxlvp+qxlvm); + }else{ + double qxl; + qxl = -(8.0*(c1/c2))*exp(-(20.0*(((c1/c2)*(x-0.5)+0.5+k-c1*t)-0.2))*(20.0*(((c1/c2)*(x-0.5)+0.5+k-c1*t)-0.2)))*(((c1/c2)*(x-0.5)+0.5+k-c1*t)-0.2); + qx+=c2*c2*((2.0*c1)/(c2+c1))*c*qxl; + } + c*=(c2-c1)/(c2+c1); + } + + std::vector flux(2); + flux[0] = qx; + flux[1] = 0.0; + return flux; + }; + } + break; + default: + { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> std::vector { + std::vector f; + return f; + }; + } + break; + } + + } + + private: + + EFunctionType m_function_type; + +}; + +#endif /* scal_analytic_functions_hpp */ diff --git a/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp b/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp new file mode 100644 index 00000000..9c134a0b --- /dev/null +++ b/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp @@ -0,0 +1,941 @@ + +#pragma once +#ifndef scal_vec_analytic_functions_hpp +#define scal_vec_analytic_functions_hpp + +class scal_vec_analytic_functions { + +public: + + /// Enumerate defining the function type + enum EFunctionType { EFunctionNonPolynomial = 0, + EFunctionQuadraticInTime = 1, + EFunctionQuadraticInSpace = 2, + reproduction_acoustic = 3, + reproduction_elastic = 4, + EFunctionNonPolynomial_paper = 5 }; + + scal_vec_analytic_functions() { + m_function_type = EFunctionNonPolynomial; + } + + ~scal_vec_analytic_functions() { + } + + void set_function_type(EFunctionType function_type) { + m_function_type = function_type; + } + + std::function + (const typename disk::generic_mesh::point_type& )> Evaluate_u(double & t) { + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,ux,uy; + x = pt.x(); + y = pt.y(); + ux = x*x*std::sin(M_PI*y)*std::cos((M_PI*x)/2.)*std::cos(std::sqrt(2.0)*M_PI*t); + uy = x*x*std::sin(M_PI*y)*std::cos((M_PI*x)/2.)*std::cos(std::sqrt(2.0)*M_PI*t); + static_vector u{ux,uy}; + return u; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,ux,uy; + x = pt.x(); + y = pt.y(); + ux = x*t*t*std::sin(M_PI*x)*std::sin(M_PI*y); + uy = x*t*t*std::sin(M_PI*x)*std::sin(M_PI*y); + static_vector u{ux,uy}; + return u; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,ux,uy; + x = pt.x(); + y = pt.y(); + ux = (1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + uy = (1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + static_vector u{ux,uy}; + return u; + }; + } + break; + + case reproduction_elastic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,ux,uy; + x = pt.x(); + y = pt.y(); + ux = -t*t*std::cos(M_PI*y)*std::sin(M_PI*x); + uy = t*t*std::cos(M_PI*x)*std::sin(M_PI*y); + static_vector u{ux,uy}; + return u; + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,ux,uy, w, theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + ux = x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); + uy = x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); + static_vector u{ux,uy}; + return u; + }; + } + + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + static_vector u; + return u; + }; + } + break; + } + + } + + std::function + (const typename disk::generic_mesh::point_type& )> Evaluate_v(double & t){ + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,vx,vy; + x = pt.x(); + y = pt.y(); + vx = -(std::sqrt(2.0)*M_PI*x*x*std::cos((M_PI*x)/2.)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*y)); + vy = -(std::sqrt(2.0)*M_PI*x*x*std::cos((M_PI*x)/2.)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*y)); + static_vector v{vx,vy}; + return v; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,vx,vy; + x = pt.x(); + y = pt.y(); + vx = 2.0*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); + vy = 2.0*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); + static_vector v{vx,vy}; + return v; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,vx,vy; + x = pt.x(); + y = pt.y(); + vx = std::sqrt(2.0)*M_PI*(1 + x)*x*x*(1 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); + vy = std::sqrt(2.0)*M_PI*(1 + x)*x*x*(1 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); + static_vector v{vx,vy}; + return v; + }; + } + break; + + case reproduction_elastic:{ + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,vx,vy; + x = pt.x(); + y = pt.y(); + vx = -2*t*std::cos(M_PI*y)*std::sin(M_PI*x); + vy = 2*t*std::cos(M_PI*x)*std::sin(M_PI*y); + static_vector v{vx,vy}; + return v; + }; + } +break; + + case EFunctionNonPolynomial_paper:{ + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,vx,vy,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + vx = -(theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos((M_PI*w*x)/2.)); + vy = -(theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos((M_PI*w*x)/2.)); + static_vector v{vx,vy}; + return v; + }; + } + + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y; + x = pt.x(); + y = pt.y(); + static_vector v; + return v; + }; + } + break; + + } + + } + + std::function + (const typename disk::generic_mesh::point_type& )> Evaluate_a(double & t){ + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,ax,ay; + x = pt.x(); + y = pt.y(); + ax = -2*M_PI*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y); + ay = -2*M_PI*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y); + static_vector a{ax,ay}; + return a; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,ax,ay; + x = pt.x(); + y = pt.y(); + ax = 2.0*x*std::sin(M_PI*x)*std::sin(M_PI*y); + ay = 2.0*x*std::sin(M_PI*x)*std::sin(M_PI*y); + static_vector a{ax,ay}; + return a; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,ax,ay; + x = pt.x(); + y = pt.y(); + ax = -2*M_PI*M_PI*(1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + ay = -2*M_PI*M_PI*(1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + static_vector a{ax,ay}; + return a; + }; + } + break; + + case reproduction_elastic:{ + return [](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,ax,ay; + x = pt.x(); + y = pt.y(); + ax = -2*std::cos(M_PI*y)*std::sin(M_PI*x); + ay = 2*std::cos(M_PI*x)*std::sin(M_PI*y); + static_vector a{ax,ay}; + return a; + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,ax,ay,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + ax = -theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); + ay = -theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); + static_vector a{ax,ay}; + return a; + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + static_vector f; + return f; + }; + } + break; + + } + + } + + std::function + (const typename disk::generic_mesh::point_type& )> Evaluate_f(double & t){ + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,fx,fy; + x = pt.x(); + y = pt.y(); + fx = -(std::cos(std::sqrt(2.0)*M_PI*t)*(-4*M_PI*x*std::sin((M_PI*x)/2.)*(M_PI*x*std::cos(M_PI*y) + 6*std::sin(M_PI*y)) + std::cos((M_PI*x)/2.)*(16*M_PI*x*std::cos(M_PI*y) + (24 + M_PI*M_PI*x*x)*std::sin(M_PI*y))))/4.0; + fy = (std::cos(std::sqrt(2.0)*M_PI*t)*(4*M_PI*x*std::sin((M_PI*x)/2.)*(M_PI*x*std::cos(M_PI*y) + 2*std::sin(M_PI*y)) + std::cos((M_PI*x)/2.)*(-16*M_PI*x*std::cos(M_PI*y) + (-8 + 5*M_PI*M_PI*x*x)*std::sin(M_PI*y))))/4.; + static_vector f{fx,fy}; + return f; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,fx,fy; + x = pt.x(); + y = pt.y(); + fx = -2 * ( M_PI*t*t*std::cos(M_PI*x)*( M_PI*x*std::cos(M_PI*y) + 3*std::sin(M_PI*y) ) + + std::sin(M_PI*x)*(M_PI*t*t*std::cos(M_PI*y) - (1+2*M_PI*M_PI*t*t)*x*std::sin(M_PI*y))); + fy = (1 + M_PI*M_PI*t*t)*x*std::cos(M_PI*(x - y)) - (1+3*M_PI*M_PI*t*t)*x*std::cos(M_PI*(x+y)) + - 2*M_PI*t*t*std::sin(M_PI*(x+y)); + static_vector f{fx,fy}; + return f; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,fx,fy; + x = pt.x(); + y = pt.y(); + fx = 2 * ( x * (-2+(-2+x)*x) -3*y -x*(5+x*(-6+M_PI*M_PI*(1+x)))*y + + (3+x*(9+M_PI*M_PI*x*(1+x)))*y*y)*std::sin(std::sqrt(2.0)*M_PI*t); + fy = 2 * ( x*x*(6 + M_PI*M_PI*(-1 + y))*y + (-1 + y)*y + x*x*x*(3 + M_PI*M_PI*(-1 + y)*y) + + x*(-2 + y + 3*y*y))*std::sin(std::sqrt(2.0)*M_PI*t); + static_vector f{fx,fy}; + return f; + }; + } + break; + + case reproduction_elastic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,fx,fy; + x = pt.x(); + y = pt.y(); + fx = -2*(1 + M_PI*M_PI*t*t)*std::cos(M_PI*y)*std::sin(M_PI*x); + fy = 2*(1 + M_PI*M_PI*t*t)*std::cos(M_PI*x)*std::sin(M_PI*y); + static_vector f{fx,fy}; + return f; + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,fx,fy,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + + fx = - theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0) + + M_PI*M_PI*w*w*x*x*std::sin(M_PI*w*x/2)*std::cos(theta*t)*std::cos(M_PI*w*y) + + 7*M_PI*M_PI*w*w*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*cos(M_PI*w*x/2)/4.0 + + 6*M_PI*w*x*std::sin(M_PI*w*x/2)*std::sin(M_PI*w*y)*std::cos(theta*t) + - 4*M_PI*w*x*std::cos(theta*t)*std::cos(M_PI*w*x/2)*std::cos(M_PI*w*y) + - 6*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2); + + fy = - theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0) + + M_PI*M_PI*w*w*x*x*std::sin(M_PI*w*x/2)*std::cos(theta*t)*std::cos(M_PI*w*y) + + 13*M_PI*M_PI*w*w*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*cos(M_PI*w*x/2)/4.0 + + 2*M_PI*w*x*std::sin(M_PI*w*x/2)*std::sin(M_PI*w*y)*std::cos(theta*t) + - 4*M_PI*w*x*std::cos(theta*t)*std::cos(M_PI*w*x/2)*std::cos(M_PI*w*y) + - 2*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2); + static_vector f{fx,fy}; + return f; + }; + } + break; + + default: + { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + static_vector f; + return f; + }; + } + break; + } + + } + + + std::function + (const typename disk::generic_mesh::point_type& )> Evaluate_sigma(double & t){ + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + sigma(0,0) = M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::cos(M_PI*y) + 4*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - + M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y) + + (4*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y))/2.0; + + sigma(0,1) = M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::cos(M_PI*y) + 2*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - + (M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y))/2.; + sigma(1,0) = sigma(0,1); + + sigma(1,1) = 3*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::cos(M_PI*y) + + (4*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y))/2.; + return sigma; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + sigma(0,0) = t*t*(M_PI*x*std::cos(M_PI*y)*std::sin(M_PI*x) + + 3*(M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y)); + + sigma(0,1) = t*t*(M_PI*x*std::cos(M_PI*y)*std::sin(M_PI*x) + + (M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y)); + + sigma(1,0) = sigma(0,1); + + sigma(1,1) = t*t*(3*M_PI*x*std::cos(M_PI*y)*std::sin(M_PI*x) + + (M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y)); + return sigma; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + sigma(0,0) = 2*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + 4*x*(1+x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + (2*x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) + - 2*x*x*(1 + x)*y*std::sin(std::sqrt(2.0)*M_PI*t))/2.0 + + (2*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + 4*x*(1 + x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t))/2.0; + + sigma(0,1) = x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) + - x*x*(1 + x)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + 2*x*(1 + x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + + sigma(1,0) = sigma(0,1); + + sigma(1,1) = 2*x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) + - 2*x*x*(1 + x)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + (2*x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) + - 2*x*x*(1 + x)*y*std::sin(std::sqrt(2.0)*M_PI*t))/2.0 + + (2*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + 4*x*(1 + x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t))/2.0; + return sigma; + }; + } + break; + + case reproduction_elastic: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + sigma(0,0) = -2*M_PI*t*t*std::cos(M_PI*x)*std::cos(M_PI*y); + sigma(1,1) = 2*M_PI*t*t*std::cos(M_PI*x)*std::cos(M_PI*y); + return sigma; + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_matrix { + double x,y,w,theta; + x = pt.x(); + y = pt.y(); + + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + + static_matrix sigma = static_matrix::Zero(2,2); + sigma(0,0) = - 3.0*M_PI*w*x*x*std::sin(M_PI*w*x/2.0)*std::sin(M_PI*w*y)*std::cos(theta*t)/2.0 + + M_PI*w*x*x*std::cos(theta*t)*std::cos(M_PI*w*x/2.0)*std::cos(M_PI*w*y) + + 6.0*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0); + + sigma(0,1) = - M_PI*w*x*x*std::sin(M_PI*w*x/2.0)*std::sin(M_PI*w*y)*std::cos(theta*t)/2.0 + + M_PI*w*x*x*std::cos(theta*t)*std::cos(M_PI*w*x/2.0)*std::cos(M_PI*w*y) + + 2.0*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0); + + sigma(1,0) = sigma(0,1); + + sigma(1,1) = - M_PI*w*x*x*std::sin(M_PI*w*x/2.0)*std::sin(M_PI*w*y)*std::cos(theta*t)/2.0 + + 3*M_PI*w*x*x*std::cos(theta*t)*std::cos(M_PI*w*x/2.0)*std::cos(M_PI*w*y) + + 2.0*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0); + return sigma; + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) + -> static_matrix { + static_matrix sigma(2,2); + return sigma; + }; + } + break; + } + + } + + std::function::point_type& )> Evaluate_s_u(double & t) { + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return x*x*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return t*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return (1 - x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + }; + } + break; + + case reproduction_acoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return t*t*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,w,theta; + x = pt.x(); + y = pt.y(); + + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + + return x*x*std::sin(theta*t)*std::sin(w*M_PI*x)*std::sin(w*M_PI*y); + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + } + + } + + std::function::point_type& )> Evaluate_s_v(double & t){ + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return std::sqrt(2.0)*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return 2*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return std::sqrt(2.0)*M_PI*(1 - x)*x*x*(1 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); + }; + } + break; + + case reproduction_acoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return 2.0*t*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + return theta*x*x*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)*std::cos(theta*t); + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + } + + } + + std::function::point_type& )> Evaluate_s_a(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return -2*M_PI*M_PI*x*x*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return 2*x*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return -2*M_PI*M_PI*(1 - x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + }; + } + break; + + case reproduction_acoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return 2.0*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + return -theta*theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y); + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + } + + } + + std::function::point_type& )> Evaluate_s_f(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + f = -2*std::sin(std::sqrt(2.0)*M_PI*t)*(2*M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y); + return f; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + f = 2*(-(M_PI*t*t*std::cos(M_PI*x)) + (1 + M_PI*M_PI*t*t)*x*std::sin(M_PI*x))*std::sin(M_PI*y); + return f; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + f = 2*((-1 + y)*y - 3*x*(-1 + y)*y + x*x*x*(-1 - M_PI*M_PI*(-1 + y)*y) + + x*x*(1 + M_PI*M_PI*(-1 + y)*y))*std::sin(std::sqrt(2.0)*M_PI*t); + return f; + }; + } + break; + + case reproduction_acoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + return 2.0*(1.0 + M_PI*M_PI*t*t)*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + f = - theta*theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y) + + 2*M_PI*M_PI*theta*w*w*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)/theta + - 4*M_PI*theta*w*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos(M_PI*w*x)/theta + - 2*theta*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)/theta; + return f; + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + } + + } + + + std::function + (const typename disk::generic_mesh::point_type& )> Evaluate_s_q(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,qx,qy; + x = pt.x(); + y = pt.y(); + qx = M_PI*x*x*std::cos(M_PI*x)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*y) + 2*x*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); + qy = M_PI*x*x*std::cos(M_PI*y)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x); + static_vector q{qx,qy}; + return q; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,qx,qy; + x = pt.x(); + y = pt.y(); + std::vector flux(2); + qx = M_PI*t*t*x*std::cos(M_PI*x)*std::sin(M_PI*y) + t*t*std::sin(M_PI*x)*std::sin(M_PI*y); + qy = M_PI*t*t*x*std::cos(M_PI*y)*std::sin(M_PI*x); + static_vector q{qx,qy}; + return q; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,qx,qy; + x = pt.x(); + y = pt.y(); + std::vector flux(2); + qx = 2*(1 - x)*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + - x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + qy = (1 - x)*x*x*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) + - (1 - x)*x*x*y*std::sin(std::sqrt(2.0)*M_PI*t); + static_vector q{qx,qy}; + return q; + }; + } + break; + + case reproduction_acoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,qx,qy; + x = pt.x(); + y = pt.y(); + qx = M_PI*t*t*std::cos(M_PI*x)*std::sin(M_PI*y); + qy = M_PI*t*t*std::sin(M_PI*x)*std::cos(M_PI*y); + static_vector q{qx,qy}; + return q; + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> static_vector { + double x,y,qx,qy,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + qx = M_PI*theta*w*x*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos(M_PI*w*x)/theta + 2*theta*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)/theta; + qy = M_PI*theta*w*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::cos(M_PI*w*y)/theta; + static_vector q{qx,qy}; + return q; + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) + -> static_vector{ + static_vector f{0,0}; + return f; + }; + } + break; + } + + } + +private: + + EFunctionType m_function_type; + +}; + +#endif /* scal_vec_analytic_functions_hpp */ diff --git a/apps/wave_propagation/src/common/sourceterm.hpp b/apps/wave_propagation/src/common/sourceterm.hpp new file mode 100644 index 00000000..0c637c2a --- /dev/null +++ b/apps/wave_propagation/src/common/sourceterm.hpp @@ -0,0 +1,226 @@ + +#pragma once +#ifndef source_term_hpp +#define source_term_hpp + +#include +#include "../common/acoustic_one_field_assembler.hpp" +#include "../common/acoustic_two_fields_assembler.hpp" +#include "../common/elastodynamic_one_field_assembler.hpp" +#include "../common/elastodynamic_two_fields_assembler.hpp" +#include "../common/elastodynamic_three_fields_assembler.hpp" +#include "../common/elastoacoustic_two_fields_assembler.hpp" +#include "../common/elastoacoustic_four_fields_assembler.hpp" + +#ifdef HAVE_INTEL_TBB +#include +#endif + +template +class source_term { + +public: + + /// Find the cells associated to the requested point + static std::set find_cells(typename Mesh::point_type & pt, Mesh & msh, bool verbose_Q = false){ + + using RealType = double; + auto norm = [](const typename Mesh::point_type& a, const typename Mesh::point_type& b ) -> RealType { + RealType dx = (b.x() - a.x()); + RealType dy = (b.y() - a.y()); + RealType norm = std::sqrt(dx*dx + dy*dy); + return norm; + }; + + // find minimum distance to the requested point + size_t np = msh.points_size(); + std::vector distances(np); + + size_t ip = 0; + for (auto& point : msh.backend_storage()->points) + { + RealType dist = norm(pt,point); + distances[ip] = dist; + ip++; + } + + size_t index = std::min_element(distances.begin(),distances.end()) - distances.begin(); + if(verbose_Q){ + RealType min_dist = *std::min_element(distances.begin(), distances.end()); + typename Mesh::point_type nearest_point = msh.backend_storage()->points.at(index); + std::cout << "Nearest point detected : " << std::endl; + std::cout << " x = " << nearest_point.x() << std::endl; + std::cout << " y = " << nearest_point.y() << std::endl; + std::cout << "Distance = " << min_dist << std::endl; + std::cout << "Global index = " << index << std::endl; + } + + std::set cell_indexes; + size_t cell_i = 0; + for (auto& cell : msh) + { + auto points = cell.point_ids(); + size_t n_p = points.size(); + for (size_t l = 0; l < n_p; l++) + { + auto pt_id = points[l]; + if(index == pt_id){ + cell_indexes.insert(cell_i); + } + } + cell_i++; + } + + if(verbose_Q){ + std::cout << "Detected cells indexes : " << std::endl; + for(auto index : cell_indexes){ + std::cout << index << std::endl; + } + } + + return cell_indexes; + } + + /// Pick the cell that contains the requested point + static size_t pick_cell(typename Mesh::point_type & pt, Mesh & msh, std::set & cell_indexes, bool verbose_Q = false){ + + using RealType = double; + + auto triangle_member_Q = [] (typename Mesh::point_type & p, typename Mesh::point_type & p0, typename Mesh::point_type & p1, typename Mesh::point_type & p2) + { + RealType dx = p.x()-p2.x(); + RealType dy = p.y()-p2.y(); + RealType dx21 = p2.x()-p1.x(); + RealType dy12 = p1.y()-p2.y(); + RealType d = dy12*(p0.x()-p2.x()) + dx21*(p0.y()-p2.y()); + RealType s = dy12*dx + dx21*dy; + RealType t = (p2.y()-p0.y())*dx + (p0.x()-p2.x())*dy; + if (d < 0.0) { + return s<=0.0 && t<=0.0 && s+t>=d; + } + return s>=0 && t>=0 && s+t<=d; + }; + + size_t n_cells = cell_indexes.size(); + if (n_cells == 1) { + size_t first_index = *cell_indexes.begin(); + return first_index; + } + bool is_member_Q = false; + for(auto index : cell_indexes){ + auto& cell = msh.backend_storage()->surfaces[index]; + auto bar = barycenter(msh, cell); + auto points = cell.point_ids(); + size_t n_p = points.size(); + + // building teselation + std::vector> triangles(n_p); + for (size_t l = 0; l < n_p; l++) + { + + std::vector chunk(3); + if( l == n_p - 1){ + chunk[0] = msh.backend_storage()->points.at(points[l]); + chunk[1] = msh.backend_storage()->points.at(points[0]); + chunk[2] = bar; + }else{ + chunk[0] = msh.backend_storage()->points.at(points[l]); + chunk[1] = msh.backend_storage()->points.at(points[l+1]); + chunk[2] = bar; + } + triangles[l] = chunk; + } + + // check whether the point is memeber of any triangle + for (auto triangle : triangles) { + is_member_Q = triangle_member_Q(pt,triangle[0],triangle[1],triangle[2]); + if (is_member_Q) { + std::cout << "Detected cell index = " << index << std::endl; + return index; + } + } + + } + + if(!is_member_Q){ + if(verbose_Q){ + std::cout << "Point is not member of cells set. Returning cell_indexes[0] " << std::endl; + } + size_t first_index = *cell_indexes.begin(); + return first_index; + } + + return -1; + } + + static double ricker_fluid(size_t it, double dt){ + + using RealType = double; + RealType tau, freq, Ricker, Ricker_fl, alpha, sigma, sigmabis, sigma2, sigma3, tn; + + tn = it * dt; + tau = 0.4; + freq = 5.0; + alpha = - M_PI*M_PI * freq*freq; + + if ( tn < 2.5*tau ) { + sigma = alpha*(tn-tau)*(tn-tau); + Ricker = 2.0 * alpha * (1+2*sigma) * exp(sigma); + sigmabis = M_PI*freq*(tn-tau); + sigma2 = sigmabis*sigmabis; + sigma3 = M_PI*freq; + Ricker_fl = -4.0*sigmabis*sigma3*exp(-sigma2)-2.0*sigmabis*sigma3*Ricker; + } + else Ricker_fl = 0.0; + + std::cout << Ricker_fl << std::endl; + + return Ricker_fl; + } + + // Punctual Source + static Matrix punctual_source(size_t it, double dt, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof){ + + using RealType = double; + + auto dim = Mesh::dimension; + size_t n_scal_dof = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_dof = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t cell_dof = n_scal_dof + n_vec_dof; + + typename Mesh::point_type pt = pt_cell_index.first; + + if(pt_cell_index.second == -1){ + std::set cell_indexes = find_cells(pt, msh, true); + size_t cell_index = pick_cell(pt, msh, cell_indexes, true); + assert(cell_index != -1); + pt_cell_index.second = cell_index; + } + + { + size_t cell_ind = pt_cell_index.second; + // scalar evaluation + { + Matrix scalar_cell_dof = x_dof.block(cell_ind*cell_dof+n_vec_dof, 0, n_scal_dof, 1); + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + auto t_phi = cell_basis.eval_functions( pt ); + std::cout << cell_ind << std::endl; + + for (int i = scalar_cell_dof.size()-1; i < scalar_cell_dof.size(); i++) { + scalar_cell_dof(i) = scalar_cell_dof(i) - t_phi(i)*ricker_fluid(it,dt); + } + + x_dof.block(cell_ind*cell_dof+n_vec_dof, 0, n_scal_dof, 1) = scalar_cell_dof; + } + } + + + + return x_dof; + } + +}; + + +#endif /* postprocessor_hpp */ diff --git a/apps/wave_propagation/src/common/sourceterm2.hpp b/apps/wave_propagation/src/common/sourceterm2.hpp new file mode 100644 index 00000000..9e643b75 --- /dev/null +++ b/apps/wave_propagation/src/common/sourceterm2.hpp @@ -0,0 +1,271 @@ + +#pragma once +#ifndef source_term_hpp +#define source_term_hpp + +#include +#include "../common/acoustic_one_field_assembler.hpp" +#include "../common/acoustic_two_fields_assembler.hpp" +#include "../common/elastodynamic_one_field_assembler.hpp" +#include "../common/elastodynamic_two_fields_assembler.hpp" +#include "../common/elastodynamic_three_fields_assembler.hpp" +#include "../common/elastoacoustic_two_fields_assembler.hpp" +#include "../common/elastoacoustic_four_fields_assembler.hpp" + +#ifdef HAVE_INTEL_TBB +#include +#endif + +template +class source_term { + +public: + + using RealType = double; + + // find distances to the requested point + static std::vector make_distances(typename Mesh::point_type & pt, Mesh & msh, bool verbose_Q = false) { + + auto norm = [](const typename Mesh::point_type& a, const typename Mesh::point_type& b ) -> RealType { + RealType dx = (b.x() - a.x()); + RealType dy = (b.y() - a.y()); + RealType norm = std::sqrt(dx*dx + dy*dy); + return norm; + }; + + size_t np = msh.points_size(); + std::vector distances(np); + + size_t ip = 0; + for (auto& point : msh.backend_storage()->points) + { + RealType dist = norm(pt,point); + distances[ip] = dist; + ip++; + } + + return distances; + } + + // find minimum distances to the requested point + static RealType min_distance(std::vector distances, bool verbose_Q = false) { + RealType min_dist; + if(verbose_Q){ + min_dist = *std::min_element(distances.begin(), distances.end()); + } + return min_dist; + } + + /// Find the cells associated to the requested point + static std::set find_cells_source(typename Mesh::point_type & pt, Mesh & msh, bool verbose_Q = false){ + + std::vector distances = make_distances(pt, msh, true); + size_t index = std::min_element(distances.begin(),distances.end()) - distances.begin(); + if(verbose_Q){ + RealType min_dist = *std::min_element(distances.begin(), distances.end()); + typename Mesh::point_type nearest_point = msh.backend_storage()->points.at(index); + std::cout << "Nearest point detected : " << std::endl; + std::cout << " x = " << nearest_point.x() << std::endl; + std::cout << " y = " << nearest_point.y() << std::endl; + std::cout << "Distance = " << min_dist << std::endl; + std::cout << "Global index = " << index << std::endl; + } + + std::set cell_indexes; + + size_t cell_i = 0; + for (auto& cell : msh) + { + auto points = cell.point_ids(); + size_t n_p = points.size(); + for (size_t l = 0; l < n_p; l++) + { + auto pt_id = points[l]; + if(index == pt_id){ + cell_indexes.insert(cell_i); + } + } + cell_i++; + } + + if(verbose_Q){ + std::cout << "Detected cells indexes : " << std::endl; + for(auto index : cell_indexes){ + std::cout << index << std::endl; + } + } + + return cell_indexes; + + } + + /// Pick the cell that contains the requested point + static std::vector pick_cell_source(typename Mesh::point_type & pt, Mesh & msh, std::set & cell_indexes, bool verbose_Q = false){ + + std::vector distances = make_distances(pt, msh, true); + + if (min_distance(distances, true) == 0.0) { + std::vector cells_sources(4); + int i = 0; + for (auto cells : cell_indexes) { + cells_sources[i] = cells; + i++; + } + std::cout << "Pas de problème quand on est sur un point du maillage" << std::endl; + std::cout << "Quand on est au milieu d'une maille à implémenter" << std::endl; + return cells_sources; + } + + else { + std::vector cells_sources(1); + auto triangle_member_Q = [] (typename Mesh::point_type & p, typename Mesh::point_type & p0, typename Mesh::point_type & p1, typename Mesh::point_type & p2) + { + RealType dx = p.x()-p2.x(); + RealType dy = p.y()-p2.y(); + RealType dx21 = p2.x()-p1.x(); + RealType dy12 = p1.y()-p2.y(); + RealType d = dy12*(p0.x()-p2.x()) + dx21*(p0.y()-p2.y()); + RealType s = dy12*dx + dx21*dy; + RealType t = (p2.y()-p0.y())*dx + (p0.x()-p2.x())*dy; + if (d < 0.0) { + return s<=0.0 && t<=0.0 && s+t>=d; + } + return s>=0 && t>=0 && s+t<=d; + }; + std::cout << "Problème laaaaaaa" << std::endl; + size_t n_cells = cell_indexes.size(); + if (n_cells == 1) { + size_t first_index = *cell_indexes.begin(); + cells_sources[0] = first_index; + return cells_sources; + } + bool is_member_Q = false; + for(auto index : cell_indexes){ + auto& cell = msh.backend_storage()->surfaces[index]; + auto bar = barycenter(msh, cell); + auto points = cell.point_ids(); + size_t n_p = points.size(); + + // building teselation + std::vector> triangles(n_p); + for (size_t l = 0; l < n_p; l++) + { + + std::vector chunk(3); + if( l == n_p - 1){ + chunk[0] = msh.backend_storage()->points.at(points[l]); + chunk[1] = msh.backend_storage()->points.at(points[0]); + chunk[2] = bar; + }else{ + chunk[0] = msh.backend_storage()->points.at(points[l]); + chunk[1] = msh.backend_storage()->points.at(points[l+1]); + chunk[2] = bar; + } + triangles[l] = chunk; + } + + // check whether the point is memeber of any triangle + int j = 0; + for (auto triangle : triangles) { + is_member_Q = triangle_member_Q(pt,triangle[0],triangle[1],triangle[2]); + if (is_member_Q) { + std::cout << "Detected cell index = " << index << std::endl; + cells_sources[j] = index; + return cells_sources; + } + j++; + } + + } + + if(!is_member_Q){ + if(verbose_Q){ + std::cout << "Point is not member of cells set. Returning cell_indexes[0] " << std::endl; + } + size_t first_index = *cell_indexes.begin(); + cells_sources[0] = first_index; + return cells_sources; + } + + return cells_sources; + + } + } + + // Punctual Source + static Matrix punctual_source(size_t it, double dt, std::pair & pt_cell_index, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof){ + + auto dim = Mesh::dimension; + size_t n_scal_dof = disk::scalar_basis_size(hho_di.cell_degree(), Mesh::dimension); + size_t n_vec_dof = disk::scalar_basis_size(hho_di.reconstruction_degree(), Mesh::dimension)-1; + size_t cell_dof = n_scal_dof + n_vec_dof; + + typename Mesh::point_type pt = pt_cell_index.first; + + std::vector cells_index; + std::set cell_indexes; + + if(pt_cell_index.second == -1){ + cell_indexes = find_cells_source(pt, msh, true); + cells_index = pick_cell_source(pt, msh, cell_indexes, true); + std::cout << cells_index.size() << std::endl; + assert(cells_index[0] != -1); + pt_cell_index.second = cells_index[0]; + } + + if (cells_index.size() == 4) { + std::cout << "source sur un point du maillage" << std::endl; + } + + else { + size_t cell_ind = pt_cell_index.second; + // scalar evaluation + { + + std::cout << "source sur un point du maillage" << std::endl; + Matrix scalar_cell_dof = x_dof.block(cell_ind*cell_dof+n_vec_dof, 0, n_scal_dof, 1); + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + auto cell_basis = disk::make_scalar_monomial_basis(msh, cell, hho_di.cell_degree()); + auto t_phi = cell_basis.eval_functions( pt ); + std::cout << cell_ind << std::endl; + + for (int i = scalar_cell_dof.size()-1; i < scalar_cell_dof.size(); i++) { + scalar_cell_dof(i) = scalar_cell_dof(i) - t_phi(i)*ricker_fluid(it,dt); + } + + x_dof.block(cell_ind*cell_dof+n_vec_dof, 0, n_scal_dof, 1) = scalar_cell_dof; + } + } + + return x_dof; + + } + + static RealType ricker_fluid(size_t it, RealType dt){ + + RealType tau, freq, Ricker, Ricker_fl, alpha, sigma, sigmabis, sigma2, sigma3, tn; + + tn = it * dt; + tau = 0.4; + freq = 5.0; + alpha = - M_PI*M_PI * freq*freq; + + if ( tn < 2.5*tau ) { + sigma = alpha*(tn-tau)*(tn-tau); + Ricker = 2.0 * alpha * (1+2*sigma) * exp(sigma); + sigmabis = M_PI*freq*(tn-tau); + sigma2 = sigmabis*sigmabis; + sigma3 = M_PI*freq; + Ricker_fl = -4.0*sigmabis*sigma3*exp(-sigma2)-2.0*sigmabis*sigma3*Ricker; + } + else Ricker_fl = 0.0; + + std::cout << Ricker_fl << std::endl; + + return Ricker_fl; + } + +}; + + +#endif /* postprocessor_hpp */ diff --git a/apps/wave_propagation/src/common/ssprk_hho_scheme.hpp b/apps/wave_propagation/src/common/ssprk_hho_scheme.hpp new file mode 100644 index 00000000..dfef4b51 --- /dev/null +++ b/apps/wave_propagation/src/common/ssprk_hho_scheme.hpp @@ -0,0 +1,329 @@ +// +// ssprk_hho_scheme.hpp +// acoustics +// +// Created by Omar Durán on 4/21/20. +// + +#pragma once +#ifndef ssprk_hho_scheme_hpp +#define ssprk_hho_scheme_hpp + +#include +#include +#include + +template +class ssprk_hho_scheme +{ + private: + + SparseMatrix m_Mc; + SparseMatrix m_Kcc; + SparseMatrix m_Kcf; + SparseMatrix m_Kfc; + SparseMatrix m_Sff; + SparseMatrix m_Mc_inv; + SparseMatrix m_Sff_inv; + Matrix m_Fc; + + #ifdef HAVE_INTEL_MKL + PardisoLDLT> m_analysis_f; + #else + SimplicialLDLT> m_analysis_f; + #endif + + ConjugateGradient> m_analysis_cg; + + size_t m_n_c_dof; + size_t m_n_f_dof; + bool m_sff_is_block_diagonal_Q; + bool m_iterative_solver_Q; + + public: + + ssprk_hho_scheme(SparseMatrix & Kg, Matrix & Fg, SparseMatrix & Mg, size_t n_f_dof){ + + + m_n_c_dof = Kg.rows() - n_f_dof; + m_n_f_dof = n_f_dof; + + // Building blocks + m_Mc = Mg.block(0, 0, m_n_c_dof, m_n_c_dof); + m_Kcc = Kg.block(0, 0, m_n_c_dof, m_n_c_dof); + m_Kcf = Kg.block(0, m_n_c_dof, m_n_c_dof, n_f_dof); + m_Kfc = Kg.block(m_n_c_dof,0, n_f_dof, m_n_c_dof); + m_Sff = Kg.block(m_n_c_dof,m_n_c_dof, n_f_dof, n_f_dof); + m_Fc = Fg.block(0, 0, m_n_c_dof, 1); + m_sff_is_block_diagonal_Q = false; + m_iterative_solver_Q = false; + } + + void setIterativeSolver(T tolerance = 1.0e-11){ + m_iterative_solver_Q = true; + m_analysis_cg.setTolerance(tolerance); + } + + void DecomposeFaceTerm(){ + + if (m_iterative_solver_Q) { + m_analysis_cg.compute(m_Sff); + m_analysis_cg.setMaxIterations(m_Sff.rows()); + }else{ + m_analysis_f.analyzePattern(m_Sff); + m_analysis_f.factorize(m_Sff); + } + m_sff_is_block_diagonal_Q = false; + } + + + #ifdef HAVE_INTEL_MKL + PardisoLDLT> & FacesAnalysis(){ + return m_analysis_f; + } + #else + SimplicialLDLT> & FacesAnalysis(){ + return m_analysis_f; + } + #endif + + SparseMatrix & Mc(){ + return m_Mc; + } + + SparseMatrix & Kcc(){ + return m_Kcc; + } + + SparseMatrix & Kcf(){ + return m_Kcf; + } + + SparseMatrix & Kfc(){ + return m_Kfc; + } + + SparseMatrix & Sff(){ + return m_Sff; + } + + Matrix & Fc(){ + return m_Fc; + } + + void SetFg(Matrix & Fg){ + m_Fc = Fg.block(0, 0, m_n_c_dof, 1); + } + + void Kcc_inverse(std::pair cell_basis_data){ + + size_t n_cells = cell_basis_data.first; + size_t n_cbs = cell_basis_data.second; + size_t nnz_cc = n_cbs*n_cbs*n_cells; + std::vector< Triplet > triplets_cc; + triplets_cc.resize(nnz_cc); + m_Mc_inv = SparseMatrix( m_n_c_dof, m_n_c_dof ); + #ifdef HAVE_INTEL_TBB + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&triplets_cc,&n_cbs] (size_t & cell_ind){ + + size_t stride_eq = cell_ind * n_cbs; + size_t stride_l = cell_ind * n_cbs * n_cbs; + + SparseMatrix m_Mc_loc = m_Mc.block(stride_eq, stride_eq, n_cbs, n_cbs); + SparseLU> analysis_cc; + analysis_cc.analyzePattern(m_Mc_loc); + analysis_cc.factorize(m_Mc_loc); + Matrix m_Mc_inv_loc = analysis_cc.solve(Matrix::Identity(n_cbs, n_cbs)); + + size_t l = 0; + for (size_t i = 0; i < m_Mc_inv_loc.rows(); i++) + { + for (size_t j = 0; j < m_Mc_inv_loc.cols(); j++) + { + triplets_cc[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, m_Mc_inv_loc(i,j)); + l++; + } + } + } + ); + #else + + for (size_t cell_ind = 0; cell_ind < n_cells; cell_ind++) + { + size_t stride_eq = cell_ind * n_cbs; + size_t stride_l = cell_ind * n_cbs * n_cbs; + + SparseMatrix m_Mc_loc = m_Mc.block(stride_eq, stride_eq, n_cbs, n_cbs); + SparseLU> analysis_cc; + analysis_cc.analyzePattern(m_Mc_loc); + analysis_cc.factorize(m_Mc_loc); + Matrix m_Mc_inv_loc = analysis_cc.solve(Matrix::Identity(n_cbs, n_cbs)); + + size_t l = 0; + for (size_t i = 0; i < m_Mc_inv_loc.rows(); i++) + { + for (size_t j = 0; j < m_Mc_inv_loc.cols(); j++) + { + triplets_cc[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, m_Mc_inv_loc(i,j)); + l++; + } + } + + } + #endif + m_Mc_inv.setFromTriplets( triplets_cc.begin(), triplets_cc.end() ); + triplets_cc.clear(); + return; + + } + + void Sff_inverse(std::pair face_basis_data){ + + size_t n_faces = face_basis_data.first; + size_t n_fbs = face_basis_data.second; + size_t nnz_ff = n_fbs*n_fbs*n_faces; + std::vector< Triplet > triplets_ff; + triplets_ff.resize(nnz_ff); + m_Sff_inv = SparseMatrix( m_n_f_dof, m_n_f_dof ); + #ifdef HAVE_INTEL_TBB + tbb::parallel_for(size_t(0), size_t(n_faces), size_t(1), + [this,&triplets_ff,&n_fbs] (size_t & face_ind){ + + size_t stride_eq = face_ind * n_fbs; + size_t stride_l = face_ind * n_fbs * n_fbs; + + SparseMatrix S_ff_loc = m_Sff.block(stride_eq, stride_eq, n_fbs, n_fbs); + SparseLU> analysis_ff; + analysis_ff.analyzePattern(S_ff_loc); + analysis_ff.factorize(S_ff_loc); + Matrix S_ff_inv_loc = analysis_ff.solve(Matrix::Identity(n_fbs, n_fbs)); + + size_t l = 0; + for (size_t i = 0; i < S_ff_inv_loc.rows(); i++) + { + for (size_t j = 0; j < S_ff_inv_loc.cols(); j++) + { + triplets_ff[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, S_ff_inv_loc(i,j)); + l++; + } + } + } + ); + #else + + for (size_t face_ind = 0; face_ind < n_faces; face_ind++) + { + size_t stride_eq = face_ind * n_fbs; + size_t stride_l = face_ind * n_fbs * n_fbs; + + SparseMatrix S_ff_loc = m_Sff.block(stride_eq, stride_eq, n_fbs, n_fbs); + SparseLU> analysis_ff; + analysis_ff.analyzePattern(S_ff_loc); + analysis_ff.factorize(S_ff_loc); + Matrix S_ff_inv_loc = analysis_ff.solve(Matrix::Identity(n_fbs, n_fbs)); + size_t l = 0; + for (size_t i = 0; i < S_ff_inv_loc.rows(); i++) + { + for (size_t j = 0; j < S_ff_inv_loc.cols(); j++) + { + triplets_ff[stride_l+l] = Triplet(stride_eq+i, stride_eq+j, S_ff_inv_loc(i,j)); + l++; + } + } + + } + #endif + m_Sff_inv.setFromTriplets( triplets_ff.begin(), triplets_ff.end() ); + triplets_ff.clear(); + m_sff_is_block_diagonal_Q = true; + return; + + } + + void refresh_faces_unknowns(Matrix & x){ + + Matrix x_c_dof = x.block(0, 0, m_n_c_dof, 1); + + // Faces update from cells data + Matrix RHSf = Kfc()*x_c_dof; + if (m_sff_is_block_diagonal_Q) { + x.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_Sff_inv * RHSf; + }else{ + if (m_iterative_solver_Q) { + x.block(m_n_c_dof, 0, m_n_f_dof, 1) = -m_analysis_cg.solve(RHSf); // new state + }else{ + x.block(m_n_c_dof, 0, m_n_f_dof, 1) = -FacesAnalysis().solve(RHSf); // new state + } + } + + } + + void ssprk_weight(Matrix & x_dof, Matrix & x_dof_n, T dt, T a, T b){ + + x_dof_n = x_dof; + Matrix x_c_dof = x_dof.block(0, 0, m_n_c_dof, 1); + Matrix x_f_dof = x_dof.block(m_n_c_dof, 0, m_n_f_dof, 1); + +// // Faces update (last state) +// { +// Matrix RHSf = Kfc()*x_c_dof; +// x_f_dof = -FacesAnalysis().solve(RHSf); +// } + + // Cells update + Matrix RHSc = Fc() - Kcc()*x_c_dof - Kcf()*x_f_dof; + Matrix delta_x_c_dof = m_Mc_inv * RHSc; + Matrix x_n_c_dof = a * x_c_dof + b * dt * delta_x_c_dof; // new state + x_dof_n.block(0, 0, m_n_c_dof, 1) = x_n_c_dof; + + // Faces update + Matrix RHSf = Kfc()*x_n_c_dof; + if (m_sff_is_block_diagonal_Q) { + x_dof_n.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_Sff_inv * RHSf; + }else{ + if (m_iterative_solver_Q) { + x_dof_n.block(m_n_c_dof, 0, m_n_f_dof, 1) = -m_analysis_cg.solve(RHSf); // new state + std::cout << "Number of iterations (CG): " << m_analysis_cg.iterations() << std::endl; + std::cout << "Estimated error: " << m_analysis_cg.error() << std::endl; + }else{ + x_dof_n.block(m_n_c_dof, 0, m_n_f_dof, 1) = -FacesAnalysis().solve(RHSf); // new state + } + } + +// // Faces update +// Matrix RHSf = Kfc()*x_n_c_dof; +// Matrix x_n_f_dof = -FacesAnalysis().solve(RHSf); // new state +// +// // Composing global solution +// x_dof_n = x_dof; +// x_dof_n.block(0, 0, m_n_c_dof, 1) = x_n_c_dof; +// x_dof_n.block(m_n_c_dof, 0, m_n_f_dof, 1) = x_n_f_dof; + + } + + void ssprk_step(int s, Matrix &alpha, Matrix &beta, T & dt, Matrix & x_dof_n_m, Matrix & x_dof_n){ + + size_t n_dof = x_dof_n_m.rows(); + Matrix ys = Matrix::Zero(n_dof, s+1); + + Matrix yn, ysi, yj; + ys.block(0, 0, n_dof, 1) = x_dof_n_m; + for (int i = 0; i < s; i++) { + + ysi = Matrix::Zero(n_dof, 1); + for (int j = 0; j <= i; j++) { + yn = ys.block(0, j, n_dof, 1); + ssprk_weight(yn, yj, dt, alpha(i,j), beta(i,j)); + ysi += yj; + } + ys.block(0, i+1, n_dof, 1) = ysi; + } + + x_dof_n = ys.block(0, s, n_dof, 1); + + } + +}; + +#endif /* ssprk_hho_scheme_hpp */ diff --git a/apps/wave_propagation/src/common/ssprk_shu_osher_tableau.hpp b/apps/wave_propagation/src/common/ssprk_shu_osher_tableau.hpp new file mode 100644 index 00000000..b71b042f --- /dev/null +++ b/apps/wave_propagation/src/common/ssprk_shu_osher_tableau.hpp @@ -0,0 +1,312 @@ +// +// ssprk_shu_osher_tableau.hpp +// acoustics +// +// Created by Omar Durán on 4/21/20. +// + +#pragma once +#ifndef ssprk_shu_osher_tableau_hpp +#define ssprk_shu_osher_tableau_hpp + +#include + +class ssprk_shu_osher_tableau +{ + public: + + static void ossprk_tables(int s, Matrix &a, Matrix &b){ + + // Optimal Strong-Stability-Preserving Runge-Kutta Time Discretizations for Discontinuous Galerkin Methods + switch (s) { + case 1: + { + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + a(0,0) = 1.0; + b(0,0) = 1.0; + } + break; + case 2: + { + // DG book (Alexandre) + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + a(0,0) = 1.0; + a(1,0) = 1.0/2.0; + a(1,1) = 1.0/2.0; + + b(0,0) = 1.0; + b(1,1) = 1.0/2.0; + + } + break; + case 3: + { + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + a(0,0) = 1.0; + a(1,0) = 0.087353119859156; + a(1,1) = 0.912646880140844; + a(2,0) = 0.344956917166841; + a(2,1) = 0.0; + a(2,2) = 0.655043082833159; + + b(0,0) = 0.528005024856522; + b(1,0) = 0.0; + b(1,1) = 0.481882138633993; + b(2,0) = 0.022826837460491; + b(2,1) = 0.0; + b(2,2) = 0.345866039233415; + + + } + break; + case 4: + { + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + a(0,0) = 1.0; + a(1,0) = 0.522361915162541; + a(1,1) = 0.477638084837459; + a(2,0) = 0.368530939472566; + a(2,1) = 0.0; + a(2,2) = 0.631469060527434; + a(3,0) = 0.334082932462285; + a(3,1) = 0.006966183666289; + a(3,2) = 0.0; + a(3,3) = 0.658950883871426; + + b(0,0) = 0.594057152884440; + b(1,0) = 0.0; + b(1,1) = 0.283744320787718; + b(2,0) = 0.000000038023030; + b(2,1) = 0.0; + b(2,2) = 0.375128712231540; + b(3,0) = 0.116941419604231; + b(3,1) = 0.004138311235266; + b(3,2) = 0.0; + b(3,3) = 0.391454485963345; + } + break; + case 5: + { + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + a(0,0) = 1.0; + a(1,0) = 0.261216512493821; + a(1,1) = 0.738783487506179; + a(2,0) = 0.623613752757655; + a(2,1) = 0.0; + a(2,2) = 0.376386247242345; + a(3,0) = 0.444745181201454; + a(3,1) = 0.120932584902288; + a(3,2) = 0.0; + a(3,3) = 0.434322233896258; + a(4,0) = 0.213357715199957; + a(4,1) = 0.209928473023448; + a(4,2) = 0.063353148180384; + a(4,3) = 0.0; + a(4,4) = 0.513360663596212; + + b(0,0) = 0.605491839566400; + b(1,0) = 0.0; + b(1,1) = 0.447327372891397; + b(2,0) = 0.000000844149769; + b(2,1) = 0.0; + b(2,2) = 0.227898801230261; + b(3,0) = 0.002856233144485; + b(3,1) = 0.073223693296006; + b(3,2) = 0.0; + b(3,3) = 0.262978568366434; + b(4,0) = 0.002362549760441; + b(4,1) = 0.127109977308333; + b(4,2) = 0.038359814234063; + b(4,3) = 0.0; + b(4,4) = 0.310835692561898; + } + break; + default: + { + std::cout << "Error:: Method not implemented." << std::endl; + } + break; + } + + } + + static void new_ossprk_tables(int s, Matrix &a, Matrix &b){ + + // NEW OPTIMAL SSPRK TIME DISCRETIZATION M (s,s) + switch (s) { + case 1: + { + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + a(0,0) = 1.0; + b(0,0) = 1.0; + } + break; + case 2: + { + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + a(0,0) = 1.0; + a(1,0) = 1.0/2.0; + a(1,1) = 1.0/2.0; + + b(0,0) = 1.0; + b(1,0) = 0.0; + b(1,1) = 1.0/2.0; + + } + break; + case 3: + { + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + + a(0,0) = 1.0; + a(1,0) = 3.0/4.0; + a(1,1) = 1.0/4.0; + a(2,0) = 1.0/3.0; + a(2,1) = 0.0; + a(2,2) = 2.0/3.0; + + b(0,0) = 1.0; + b(1,0) = 0.0; + b(1,1) = 1.0/4.0; + b(2,0) = 0.0; + b(2,1) = 0.0; + b(2,2) = 2.0/3.0; + + } + break; + default: + { + std::cout << "Error:: Method not implemented." << std::endl; + } + break; + } + + } + + static void new_ossprk_s_p_one_tables(int s, Matrix &a, Matrix &b){ + + // NEW OPTIMAL SSPRK TIME DISCRETIZATION M (s+1,s) + switch (s) { + case 1: + { + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + a(0,0) = 1.0; + b(0,0) = 1.0; + } + break; + case 2: + { + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + a(0,0) = 1.0; + a(1,1) = 1.0; + + b(0,0) = 1.0/2.0; + b(1,1) = 1.0/2.0; + + } + break; + case 3: + { + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + + a(0,0) = 1.0; + a(1,0) = 0.0; + a(1,1) = 1.0; + a(2,0) = 1.0/3.0; + a(2,1) = 0.0; + a(2,2) = 2.0/3.0; + + b(0,0) = 1.0/2.0; + b(1,1) = 1.0/2.0; + b(2,2) = 1.0/3.0; + + + } + break; + case 4: + { + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + a(0,0) = 1.0; + a(1,0) = 0.0; + a(1,1) = 1.0; + a(2,0) = 2.0/3.0; + a(2,1) = 0.0; + a(2,2) = 1.0/3.0; + a(3,0) = 0.0; + a(3,1) = 0.0; + a(3,2) = 0.0; + a(3,3) = 1.0; + + b(0,0) = 1.0/2.0; + b(1,0) = 0.0; + b(1,1) = 1.0/2.0; + b(2,0) = 0.0; + b(2,1) = 0.0; + b(2,2) = 1.0/6.0; + b(3,0) = 0.0; + b(3,1) = 0.0; + b(3,2) = 0.0; + b(3,3) = 1.0/2.0; + } + break; + case 5: + { + a = Matrix::Zero(s, s); + b = Matrix::Zero(s, s); + a(0,0) = 1.0; + a(1,0) = 0.44437049406734; + a(1,1) = 0.55562950593266; + a(2,0) = 0.62010185138540; + a(2,1) = 0.0; + a(2,2) = 0.37989814861460; + a(3,0) = 0.17807995410773; + a(3,1) = 0.0; + a(3,2) = 0.0; + a(3,3) = 0.82192004589227; + a(4,0) = 0.00683325884039; + a(4,1) = 0.0; + a(4,2) = 0.51723167208978; + a(4,3) = 0.12759831133288; + a(4,4) = 0.34833675773694; + + b(0,0) = 0.39175222700392; + b(1,0) = 0.0; + b(1,1) = 0.36841059262959; + b(2,0) = 0.0; + b(2,1) = 0.0; + b(2,2) = 0.25189177424738; + b(3,0) = 0.0; + b(3,1) = 0.0; + b(3,2) = 0.0; + b(3,3) = 0.54497475021237; + b(4,0) = 0.0; + b(4,1) = 0.0; + b(4,2) = 0.0; + b(4,3) = 0.08460416338212; + b(4,4) = 0.22600748319395; + } + break; + default: + { + std::cout << "Error:: Method not implemented." << std::endl; + } + break; + } + + } + +}; + +#endif /* ssprk_shu_osher_tableau_hpp */ diff --git a/apps/wave_propagation/src/common/vec_analytic_functions.hpp b/apps/wave_propagation/src/common/vec_analytic_functions.hpp new file mode 100644 index 00000000..648ce2b1 --- /dev/null +++ b/apps/wave_propagation/src/common/vec_analytic_functions.hpp @@ -0,0 +1,325 @@ +// +// vec_analytic_functions.hpp +// acoustics +// +// Created by Omar Durán on 4/14/20. +// + +#pragma once +#ifndef vec_analytic_functions_hpp +#define vec_analytic_functions_hpp + +#include + +class vec_analytic_functions +{ + public: + + /// Enumerate defining the function type + enum EFunctionType { EFunctionNonPolynomial = 0, EFunctionQuadraticInTime = 1, EFunctionQuadraticInSpace = 2}; + + + vec_analytic_functions(){ + m_function_type = EFunctionNonPolynomial; + } + + ~vec_analytic_functions(){ + + } + + void set_function_type(EFunctionType function_type){ + m_function_type = function_type; + } + + std::function(const typename disk::generic_mesh::point_type& )> Evaluate_u(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,ux,uy; + x = pt.x(); + y = pt.y(); + ux = -std::cos(M_PI*y)*std::sin(std::sqrt(2)*M_PI*t)*std::sin(M_PI*x); + uy = std::cos(M_PI*x)*std::sin(std::sqrt(2)*M_PI*t)*std::sin(M_PI*y); + static_vector u{ux,uy}; + return u; + }; + } + break; + case EFunctionQuadraticInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,ux,uy; + x = pt.x(); + y = pt.y(); + ux = (1.0 - x)*x*(1.0 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + uy = (1.0 - x)*x*(1.0 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + static_vector u{ux,uy}; + return u; + }; + } + break; + case EFunctionQuadraticInTime: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,ux,uy; + x = pt.x(); + y = pt.y(); + ux = -t*t*std::cos(M_PI*y)*std::sin(M_PI*x); + uy = t*t*std::cos(M_PI*x)*std::sin(M_PI*y); + static_vector u{ux,uy}; + return u; + }; + } + break; + default: + { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> static_vector { + static_vector u; + return u; + }; + } + break; + } + + } + + std::function(const typename disk::generic_mesh::point_type& )> Evaluate_v(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,vx,vy; + x = pt.x(); + y = pt.y(); + vx = -(std::sqrt(2)*M_PI*std::cos(std::sqrt(2)*M_PI*t)*std::cos(M_PI*y)*std::sin(M_PI*x)); + vy = std::sqrt(2)*M_PI*std::cos(std::sqrt(2)*M_PI*t)*std::cos(M_PI*x)*std::sin(M_PI*y); + static_vector v{vx,vy}; + return v; + }; + } + break; + case EFunctionQuadraticInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + + double x,y,vx,vy; + x = pt.x(); + y = pt.y(); + vx = std::sqrt(2.0)*M_PI*(1.0 - x)*x*(1.0 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); + vy = std::sqrt(2.0)*M_PI*(1.0 - x)*x*(1.0 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); + static_vector v{vx,vy}; + return v; + }; + } + break; + case EFunctionQuadraticInTime: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,vx,vy; + x = pt.x(); + y = pt.y(); + vx = -2*t*std::cos(M_PI*y)*std::sin(M_PI*x); + vy = 2*t*std::cos(M_PI*x)*std::sin(M_PI*y); + static_vector v{vx,vy}; + return v; + }; + } + break; + default: + { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y; + x = pt.x(); + y = pt.y(); + static_vector v; + return v; + }; + } + break; + } + + } + + std::function(const typename disk::generic_mesh::point_type& )> Evaluate_a(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,ax,ay; + x = pt.x(); + y = pt.y(); + ax = 2*M_PI*M_PI*std::cos(M_PI*y)*std::sin(std::sqrt(2)*M_PI*t)*std::sin(M_PI*x); + ay = -2*M_PI*M_PI*std::cos(M_PI*x)*std::sin(std::sqrt(2)*M_PI*t)*std::sin(M_PI*y); + static_vector a{ax,ay}; + return a; + }; + } + break; + case EFunctionQuadraticInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,ax,ay; + x = pt.x(); + y = pt.y(); + ax = -2.0*M_PI*M_PI*(1.0 - x)*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + ay = -2.0*M_PI*M_PI*(1.0 - x)*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + static_vector a{ax,ay}; + return a; + }; + } + break; + case EFunctionQuadraticInTime: + { + return [](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,ax,ay; + x = pt.x(); + y = pt.y(); + ax = -2*std::cos(M_PI*y)*std::sin(M_PI*x); + ay = 2*std::cos(M_PI*x)*std::sin(M_PI*y); + static_vector a{ax,ay}; + return a; + }; + } + break; + default: + { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> static_vector { + static_vector f; + return f; + }; + } + break; + } + + } + + std::function(const typename disk::generic_mesh::point_type& )> Evaluate_f(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: + { + return [](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y; + x = pt.x(); + y = pt.y(); + static_vector f{0,0}; + return f; + }; + } + break; + case EFunctionQuadraticInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,fx,fy; + x = pt.x(); + y = pt.y(); + fx = -2.0*(1.0 + (-3.0 + x)*x - 5.0*y + (4.0 - M_PI*M_PI*(-1.0 + x))*x*y + (3.0 + M_PI*M_PI*(-1.0 + x)*x)*y*y)*std::sin(std::sqrt(2.0)*M_PI*t); + fy = -2*(1 + (-3 + y)*y + x*(-5 + (4 - M_PI*M_PI*(-1 + y))*y) + x*x*(3 + M_PI*M_PI*(-1 + y)*y))*std::sin(std::sqrt(2.0)*M_PI*t); + static_vector f{fx,fy}; + return f; + }; + } + break; + case EFunctionQuadraticInTime: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + double x,y,fx,fy; + x = pt.x(); + y = pt.y(); + fx = -2*(1 + M_PI*M_PI*t*t)*std::cos(M_PI*y)*std::sin(M_PI*x); + fy = 2*(1 + M_PI*M_PI*t*t)*std::cos(M_PI*x)*std::sin(M_PI*y); + static_vector f{fx,fy}; + return f; + }; + } + break; + default: + { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> static_vector { + static_vector f; + return f; + }; + } + break; + } + + } + + + std::function(const typename disk::generic_mesh::point_type& )> Evaluate_sigma(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + sigma(0,0) = -2*M_PI*std::cos(M_PI*x)*std::cos(M_PI*y)*std::sin(std::sqrt(2)*M_PI*t); + sigma(1,1) = 2*M_PI*std::cos(M_PI*x)*std::cos(M_PI*y)*std::sin(std::sqrt(2)*M_PI*t); + return sigma; + }; + } + break; + case EFunctionQuadraticInSpace: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + sigma(0,0) = 2*(1 - x)*(1 - y)*y*std::sin(std::sqrt(2)*M_PI*t) - 2*x*(1 - y)*y*std::sin(std::sqrt(2)*M_PI*t) + + (2*(1 - x)*x*(1 - y)*std::sin(std::sqrt(2)*M_PI*t) - 2*(1 - x)*x*y*std::sin(std::sqrt(2)*M_PI*t))/2. + + (2*(1 - x)*(1 - y)*y*std::sin(std::sqrt(2)*M_PI*t) - 2*x*(1 - y)*y*std::sin(std::sqrt(2)*M_PI*t))/2.; + sigma(0,1) = (1 - x)*x*(1 - y)*std::sin(std::sqrt(2)*M_PI*t) - (1 - x)*x*y*std::sin(std::sqrt(2)*M_PI*t) + (1 - x)*(1 - y)*y*std::sin(std::sqrt(2)*M_PI*t) - + x*(1 - y)*y*std::sin(std::sqrt(2)*M_PI*t); + sigma(1,0) = sigma(0,1); + sigma(1,1) = 2*(1 - x)*x*(1 - y)*std::sin(std::sqrt(2)*M_PI*t) - 2*(1 - x)*x*y*std::sin(std::sqrt(2)*M_PI*t) + + (2*(1 - x)*x*(1 - y)*std::sin(std::sqrt(2)*M_PI*t) - 2*(1 - x)*x*y*std::sin(std::sqrt(2)*M_PI*t))/2. + + (2*(1 - x)*(1 - y)*y*std::sin(std::sqrt(2)*M_PI*t) - 2*x*(1 - y)*y*std::sin(std::sqrt(2)*M_PI*t))/2.; + return sigma; + }; + } + break; + case EFunctionQuadraticInTime: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + sigma(0,0) = -2*M_PI*t*t*std::cos(M_PI*x)*std::cos(M_PI*y); + sigma(1,1) = 2*M_PI*t*t*std::cos(M_PI*x)*std::cos(M_PI*y); + return sigma; + }; + } + break; + default: + { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> static_matrix { + static_matrix sigma(2,2); + return sigma; + }; + } + break; + } + + } + + private: + + EFunctionType m_function_type; + +}; + +#endif /* vec_analytic_functions_hpp */ diff --git a/apps/wave_propagation/src/wave_propagation.cpp b/apps/wave_propagation/src/wave_propagation.cpp index 9f6dd014..c57c3c21 100644 --- a/apps/wave_propagation/src/wave_propagation.cpp +++ b/apps/wave_propagation/src/wave_propagation.cpp @@ -23,53 +23,53 @@ #include using namespace Eigen; -#include "timecounter.h" -#include "methods/hho" -#include "geometry/geometry.hpp" -#include "boundary_conditions/boundary_conditions.hpp" -#include "output/silo.hpp" +#include "diskpp/common/timecounter.hpp" +#include "diskpp/methods/hho" +#include "diskpp/geometry/geometry.hpp" +#include "diskpp/boundary_conditions/boundary_conditions.hpp" +#include "diskpp/output/silo.hpp" // application common sources -#include "../common/display_settings.hpp" -#include "../common/fitted_geometry_builders.hpp" -#include "../common/linear_solver.hpp" -#include "../common/acoustic_material_data.hpp" -#include "../common/elastic_material_data.hpp" -#include "../common/scal_vec_analytic_functions.hpp" -#include "../common/preprocessor.hpp" -#include "../common/postprocessor.hpp" +#include "common/display_settings.hpp" +#include "common/fitted_geometry_builders.hpp" +// #include "common/linear_solver.hpp" +// #include "common/acoustic_material_data.hpp" +// #include "common/elastic_material_data.hpp" +// #include "common/scal_vec_analytic_functions.hpp" +// #include "common/preprocessor.hpp" +// #include "common/postprocessor.hpp" // RK schemes -#include "../common/dirk_hho_scheme.hpp" -#include "../common/dirk_butcher_tableau.hpp" -#include "../common/erk_butcher_tableau.hpp" -#include "../common/erk_hho_scheme.hpp" -#include "../common/erk_coupling_hho_scheme.hpp" +// #include "../common/dirk_hho_scheme.hpp" +// #include "../common/dirk_butcher_tableau.hpp" +// #include "../common/erk_butcher_tableau.hpp" +// #include "../common/erk_hho_scheme.hpp" +// #include "../common/erk_coupling_hho_scheme.hpp" // Prototypes: // Computation of an empirical CFL criteria -#include "Prototypes/CFL/EAcoustic_CFL.hpp" // CFl - Acoustic -#include "Prototypes/CFL/EElasticity_CFL.hpp" // CFl - Linear Elasticity -#include "Prototypes/CFL/EHHOFirstOrderCFL.hpp" // CFl - Elasto-Acoustic Coupling +// #include "Prototypes/CFL/EAcoustic_CFL.hpp" // CFl - Acoustic +// #include "Prototypes/CFL/EElasticity_CFL.hpp" // CFl - Linear Elasticity +// #include "Prototypes/CFL/EHHOFirstOrderCFL.hpp" // CFl - Elasto-Acoustic Coupling // Stability study & Spectral radius computation: -#include "Prototypes/Stability_Study/EAcoustic_stability.hpp" // Acoustic -#include "Prototypes/Stability_Study/EElastic_stability.hpp" // Linear Elasticity -#include "Prototypes/Stability_Study/EHHOFirstOrder_stability.hpp" // Elasto-Acoustic Coupling +// #include "Prototypes/Stability_Study/EAcoustic_stability.hpp" // Acoustic +// #include "Prototypes/Stability_Study/EElastic_stability.hpp" // Linear Elasticity +// #include "Prototypes/Stability_Study/EHHOFirstOrder_stability.hpp" // Elasto-Acoustic Coupling // Convergence test on sinusoidal analytical solution - Debug Implicit Direct Solver!!!! -#include "Prototypes/Conv_Test/IAcoustic_conv_test.hpp" // Implicit Acoustic -#include "Prototypes/Conv_Test/IElastic_conv_test.hpp" // Implicit Elastic -#include "Prototypes/Conv_Test/IHHOFirstOrder.hpp" // Implicit Coupling -#include "Prototypes/Conv_Test/IHHOFirstOrder_conv_tests.hpp" // Explicit Coupling -#include "Prototypes/Conv_Test/EHHOFirstOrder.hpp" // Explicit Coupling -#include "Prototypes/Conv_Test/EHHOFirstOrder_conv_tests.hpp" // Explicit Coupling +// #include "Prototypes/Conv_Test/IAcoustic_conv_test.hpp" // Implicit Acoustic +// #include "Prototypes/Conv_Test/IElastic_conv_test.hpp" // Implicit Elastic +// #include "Prototypes/Conv_Test/IHHOFirstOrder.hpp" // Implicit Coupling +// #include "Prototypes/Conv_Test/IHHOFirstOrder_conv_tests.hpp" // Explicit Coupling +// #include "Prototypes/Conv_Test/EHHOFirstOrder.hpp" // Explicit Coupling +// #include "Prototypes/Conv_Test/EHHOFirstOrder_conv_tests.hpp" // Explicit Coupling // Pulses for comparison with Gar6more -#include "Prototypes/Pulses/HeterogeneousIHHOFirstOrder.hpp" // Implicit Pulse (adimensional) -#include "Prototypes/Pulses/HeterogeneousEHHOFirstOrder.hpp" // Explicit Pulse (adimensional) -#include "Prototypes/Pulses/ConicWavesIHHOFirstOrder.hpp" // Implicit Pulse (geophysic) -#include "Prototypes/Pulses/ConicWavesEHHOFirstOrder.hpp" // Implicit Pulse (geophysic) +// #include "Prototypes/Pulses/HeterogeneousIHHOFirstOrder.hpp" // Implicit Pulse (adimensional) +// #include "Prototypes/Pulses/HeterogeneousEHHOFirstOrder.hpp" // Explicit Pulse (adimensional) +// #include "Prototypes/Pulses/ConicWavesIHHOFirstOrder.hpp" // Implicit Pulse (geophysic) +// #include "Prototypes/Pulses/ConicWavesEHHOFirstOrder.hpp" // Implicit Pulse (geophysic) // Sedimentary Basin -#include "Prototypes/Basin/BassinIHHOFirstOrder.hpp" // Implicit Sedimentary Basin -#include "Prototypes/Basin/Test_Laurent.hpp" // Implicit Sedimentary Basin +// #include "Prototypes/Basin/BassinIHHOFirstOrder.hpp" // Implicit Sedimentary Basin +// #include "Prototypes/Basin/Test_Laurent.hpp" // Implicit Sedimentary Basin // #include "Prototypes/Basin/BassinEHHOFirstOrder.hpp" // Explicit Sedimentary Basin int main(int argc, char **argv){ @@ -95,7 +95,7 @@ int main(int argc, char **argv){ // Pulse: // HeterogeneousIHHOFirstOrder(argc, argv); // HeterogeneousEHHOFirstOrder(argc, argv); - ConicWavesIHHOFirstOrder(argc, argv); + // ConicWavesIHHOFirstOrder(argc, argv); // ConicWavesEHHOFirstOrder(argc, argv); // Bassin sédimentaire: From 89de597b5faf671e22d6f099a0d3e010446d280b Mon Sep 17 00:00:00 2001 From: Romain Mottier Date: Mon, 9 Jun 2025 10:57:15 +0200 Subject: [PATCH 04/12] level_set functions added --- apps/unfitted_HHO/src/unfitted_HHO.cpp | 5 +- .../wave_propagation/src/wave_propagation.cpp | 4 +- libdiskpp/include/diskpp/mesh/cut_mesh.hpp | 6 + libdiskpp/include/diskpp/mesh/level_set.hpp | 204 ++++++++++++++++++ 4 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 libdiskpp/include/diskpp/mesh/cut_mesh.hpp create mode 100644 libdiskpp/include/diskpp/mesh/level_set.hpp diff --git a/apps/unfitted_HHO/src/unfitted_HHO.cpp b/apps/unfitted_HHO/src/unfitted_HHO.cpp index fa8e2dfb..cd60b681 100644 --- a/apps/unfitted_HHO/src/unfitted_HHO.cpp +++ b/apps/unfitted_HHO/src/unfitted_HHO.cpp @@ -1,6 +1,9 @@ #include #include #include "diskpp/loaders/loader.hpp" +#include "diskpp/mesh/cut_mesh.hpp" -int main(int argc, char **argv) { +int main(int argc, char **argv) { + + } diff --git a/apps/wave_propagation/src/wave_propagation.cpp b/apps/wave_propagation/src/wave_propagation.cpp index c57c3c21..f2679ea6 100644 --- a/apps/wave_propagation/src/wave_propagation.cpp +++ b/apps/wave_propagation/src/wave_propagation.cpp @@ -30,8 +30,8 @@ using namespace Eigen; #include "diskpp/output/silo.hpp" // application common sources -#include "common/display_settings.hpp" -#include "common/fitted_geometry_builders.hpp" +// #include "common/display_settings.hpp" +// #include "common/fitted_geometry_builders.hpp" // #include "common/linear_solver.hpp" // #include "common/acoustic_material_data.hpp" // #include "common/elastic_material_data.hpp" diff --git a/libdiskpp/include/diskpp/mesh/cut_mesh.hpp b/libdiskpp/include/diskpp/mesh/cut_mesh.hpp new file mode 100644 index 00000000..73af58a7 --- /dev/null +++ b/libdiskpp/include/diskpp/mesh/cut_mesh.hpp @@ -0,0 +1,6 @@ + +#pragma once + +#include "mesh.hpp" +#include "level_set.hpp" +#include "mesh_storage.hpp" diff --git a/libdiskpp/include/diskpp/mesh/level_set.hpp b/libdiskpp/include/diskpp/mesh/level_set.hpp new file mode 100644 index 00000000..99f2f3f1 --- /dev/null +++ b/libdiskpp/include/diskpp/mesh/level_set.hpp @@ -0,0 +1,204 @@ +/* + * /\ Guillaume Delay 2018,2019 + * /__\ guillaume.delay@enpc.fr + * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS + * /\ /\ + * /__\ /__\ This is ProtoN, a library for fast Prototyping of + * /_\/_\/_\/_\ Numerical methods. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * If you use this code or parts of it for scientific publications, you + * are required to cite it as following: + * + * Implementation of Discontinuous Skeletal methods on arbitrary-dimensional, + * polytopal meshes using generic programming. + * M. Cicuttin, D. A. Di Pietro, A. Ern. + * Journal of Computational and Applied Mathematics. + * DOI: 10.1016/j.cam.2017.09.017 + */ + + +template +struct level_set { + public: + virtual T operator()(const disk::point& pt) const { + } + + virtual Eigen::Matrix gradient(const disk::point& pt) const { + } + + Eigen::Matrix normal(const disk::point& pt) const { + Eigen::Matrix ret; + ret = gradient(pt); + return ret/ret.norm(); + } +}; + +template +struct circle_level_set: public level_set +{ + T radius, alpha, beta; + + circle_level_set(T r, T a, T b) : radius(r), alpha(a), beta(b) { + } + + T operator()(const disk::point& pt) const { + auto x = pt.x(); + auto y = pt.y(); + return (x-alpha)*(x-alpha) + (y-beta)*(y-beta) - radius*radius; + } + + Eigen::Matrix gradient(const disk::point& pt) const { + Eigen::Matrix ret; + ret(0) = 2*pt.x() - 2*alpha; + ret(1) = 2*pt.y() - 2*beta; + return ret; + } +}; + +template +struct line_level_set: public level_set +{ + T cut_y; + + line_level_set(T cy) + : cut_y(cy) + {} + + T operator()(const disk::point& pt) const + { + auto x = pt.x(); + auto y = pt.y(); + + return y - cut_y; + } + + Eigen::Matrix gradient(const disk::point& pt) const { + Eigen::Matrix ret; + ret(0) = 0; + ret(1) = 1; + return ret; + } +}; + + + +template +struct square_level_set: public level_set +{ + public: + T y_top, y_bot, x_left, x_right; + + square_level_set(T yt, T yb, T xl, T xr) + : y_top(yt), y_bot(yb), x_left(xl), x_right(xr) + {} + + T operator()(const disk::point& pt) const + { + auto x = pt.x(); + auto y = pt.y(); + + T in = 1; + if(x > x_left && x < x_right && y > y_bot && y < y_top) + in = 1; + else + in = -1; + + T dist_x = std::min( abs(x-x_left), abs(x-x_right)); + T dist_y = std::min( abs(y-y_bot), abs(y-y_top)); + + + return - in * std::min(dist_x , dist_y); + } + + Eigen::Matrix gradient(const disk::point& pt) const + { + Eigen::Matrix ret; + + + auto x = pt.x(); + auto y = pt.y(); + + T dist = abs(x - x_left); + ret(0) = -1; + ret(1) = 0; + + if(abs(x - x_right) < dist ) + { + dist = abs(x - x_right); + ret(0) = 1; + ret(1) = 0; + } + if(abs(y - y_bot) < dist ) + { + dist = abs(y - y_bot); + ret(0) = 0; + ret(1) = -1; + } + if(abs(y - y_top) < dist) + { + ret(0) = 0; + ret(1) = 1; + } + + return ret; + } +}; + + + +template +struct flower_level_set: public level_set +{ + T radius, alpha, beta, a; + size_t N; + + flower_level_set(T r, T al, T b, size_t N_, T a_) + : radius(r), alpha(al), beta(b), N(N_), a(a_) + {} + + T operator()(const disk::point& pt) const + { + auto x = pt.x(); + auto y = pt.y(); + + T theta; + if(x == alpha && y < beta) + theta = - M_PI / 2.0; + else if(x == alpha && y >= beta) + theta = M_PI / 2.0; + else + theta = atan((y-beta)/(x-alpha)); + + if(x < alpha) + theta = theta + M_PI; + + return (x-alpha)*(x-alpha) + (y-beta)*(y-beta) - radius*radius + - a * std::cos(N*theta); + } + + Eigen::Matrix gradient(const disk::point& pt) const + { + Eigen::Matrix ret; + auto X = pt.x() - alpha; + auto Y = pt.y() - beta; + + T theta; + if(X == 0 && Y < 0) + theta = - M_PI / 2.0; + else if(X == 0 && Y >= 0) + theta = M_PI / 2.0; + else + theta = atan( Y / X ); + + if(pt.x() < alpha) + theta = theta + M_PI; + + ret(0) = 2*X - a * N * std::sin(N * theta) * Y / (X*X + Y*Y); + ret(1) = 2*Y + a * N * std::sin(N * theta) * X / (X*X + Y*Y); + return ret; + } +}; From d05914d5680fad92bae42a2bf7fbac8066de8843 Mon Sep 17 00:00:00 2001 From: Matteo Cicuttin Date: Wed, 11 Jun 2025 11:35:01 +0200 Subject: [PATCH 05/12] Fixed Spectra for wave_propagation --- .gitmodules | 3 +++ CMakeLists.txt | 3 +-- apps/wave_propagation/CMakeLists.txt | 2 +- libdiskpp/contrib/spectra | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) create mode 160000 libdiskpp/contrib/spectra diff --git a/.gitmodules b/.gitmodules index 7cc3ee6f..4ead0631 100644 --- a/.gitmodules +++ b/.gitmodules @@ -21,3 +21,6 @@ [submodule "libdiskpp/contrib/matplotplusplus"] path = libdiskpp/contrib/matplotplusplus url = https://github.com/alandefreitas/matplotplusplus/ +[submodule "libdiskpp/contrib/spectra"] + path = libdiskpp/contrib/spectra + url = git@github.com:yixuan/spectra.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 134420e2..b7cd6344 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,13 +68,12 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") endif() endif() -find_package(Spectra REQUIRED) - ###################################################################### ## Eigen3 #add_subdirectory(contrib/eigen) find_package(Eigen3 REQUIRED) set(LINK_LIBS ${LINK_LIBS} Eigen3::Eigen) +include_directories(libdiskpp/contrib/spectra/include) ###################################################################### ## ~jburkardt code diff --git a/apps/wave_propagation/CMakeLists.txt b/apps/wave_propagation/CMakeLists.txt index 688ddf5c..11a89fc4 100644 --- a/apps/wave_propagation/CMakeLists.txt +++ b/apps/wave_propagation/CMakeLists.txt @@ -1,6 +1,6 @@ set(LINK_LIBS diskpp) add_executable(wave_propagation src/wave_propagation.cpp) -target_link_libraries(wave_propagation ${LINK_LIBS} Spectra::Spectra) +target_link_libraries(wave_propagation ${LINK_LIBS}) install(TARGETS wave_propagation RUNTIME DESTINATION bin) diff --git a/libdiskpp/contrib/spectra b/libdiskpp/contrib/spectra new file mode 160000 index 00000000..a29f37fe --- /dev/null +++ b/libdiskpp/contrib/spectra @@ -0,0 +1 @@ +Subproject commit a29f37fe3ed1c2895b07b449fcb8f09bc0940e40 From d62995dea5c468486a062894ccfa3f53e97600aa Mon Sep 17 00:00:00 2001 From: Matteo Cicuttin Date: Wed, 11 Jun 2025 11:46:20 +0200 Subject: [PATCH 06/12] fixed modules --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 4ead0631..20ce0a42 100644 --- a/.gitmodules +++ b/.gitmodules @@ -23,4 +23,4 @@ url = https://github.com/alandefreitas/matplotplusplus/ [submodule "libdiskpp/contrib/spectra"] path = libdiskpp/contrib/spectra - url = git@github.com:yixuan/spectra.git + url = https://github.com/yixuan/spectra.git From ab2ae4a0d3096bd796ef4d475653119cd53d80fc Mon Sep 17 00:00:00 2001 From: Romain Mottier Date: Wed, 11 Jun 2025 16:59:27 +0200 Subject: [PATCH 07/12] Integration of Wave_Propagation app in last Diskpp version --- .../common/acoustic_one_field_assembler.hpp | 20 +- .../common/acoustic_two_fields_assembler.hpp | 20 +- .../common/deprecated/one_field_assembler.hpp | 8 +- .../one_field_vectorial_assembler.hpp | 8 +- .../three_fields_vectorial_assembler.hpp | 8 +- .../deprecated/two_fields_assembler.hpp | 8 +- .../elastoacoustic_four_fields_assembler.hpp | 42 +- .../elastoacoustic_two_fields_assembler.hpp | 12 +- .../elastodynamic_one_field_assembler.hpp | 28 +- .../elastodynamic_three_fields_assembler.hpp | 40 +- .../elastodynamic_two_fields_assembler.hpp | 34 +- .../src/common/fitted_geometry_builders.hpp | 39 +- .../src/common/postprocessor.hpp | 40 +- .../common/scal_vec_analytic_functions.hpp | 156 +- .../acoustic/AcousticIHHOFirstOrder.hpp | 306 ++ .../src/prototypes/acoustic/EAcoustic_CFL.hpp | 398 +++ .../acoustic/EAcoustic_stability.hpp | 379 ++ .../acoustic/IAcoustic_conv_test.hpp | 391 +++ .../prototypes/acoustics_old/CMakeLists.txt | 17 + .../Acoustic_Conv_Test/EHHOFirstOrder.hpp | 233 ++ .../Acoustic_Conv_Test/IHHOFirstOrder.hpp | 249 ++ .../Acoustic_Conv_Test/IHHOSecondOrder.hpp | 222 ++ .../EllipticOneFieldConvergenceTest.hpp | 183 + .../EllipticTwoFieldsConvergenceTest.hpp | 189 + .../HeterogeneousGar6more2DIHHOFirstOrder.hpp | 254 ++ ...HeterogeneousGar6more2DIHHOSecondOrder.hpp | 242 ++ .../HeterogeneousEHHOFirstOrder.hpp | 210 ++ .../HeterogeneousIHHOFirstOrder.hpp | 232 ++ .../HeterogeneousIHHOSecondOrder.hpp | 228 ++ .../HeterogeneousPulseEHHOFirstOrder.hpp | 270 ++ .../HeterogeneousPulseIHHOFirstOrder.hpp | 337 ++ .../HeterogeneousPulseIHHOFirstOrder2.hpp | 347 ++ .../HeterogeneousPulseIHHOSecondOrder.hpp | 302 ++ .../Prototypes/prototype_selector.hpp | 78 + .../prototypes/acoustics_old/acoustics.cpp | 158 + .../input_files/acoustics_simulation.lua | 13 + .../acoustics_simulation_2d_pulse.lua | 14 + .../input_files/acoustics_test.lua | 19 + .../input_files/elliptic_convergence_test.lua | 15 + .../coupling/Basin/BassinEHHOFirstOrder.hpp | 423 +++ .../coupling/Basin/BassinIHHOFirstOrder.hpp | 519 +++ .../src/prototypes/coupling/Basin/Test.hpp | 484 +++ .../coupling/CFL/EHHOFirstOrderCFL.hpp | 439 +++ .../CFL/HeterogeneousEHHOFirstOrderCFL.hpp | 470 +++ .../coupling/Conv_Tests/EHHOFirstOrder.hpp | 426 +++ .../Conv_Tests/EHHOFirstOrder_conv_tests.hpp | 373 ++ .../coupling/Conv_Tests/IHHOFirstOrder.hpp | 443 +++ .../Conv_Tests/IHHOFirstOrder_conv_tests.hpp | 358 ++ .../coupling/EHHOFirstOrder_stability.hpp | 434 +++ ...HeterogeneousGar6more2DIHHOSecondOrder.hpp | 314 ++ .../prototypes/coupling/IHHOSecondOrder.hpp | 301 ++ .../Pulse/ConicWavesEHHOFirstOrder.hpp | 490 +++ .../Pulse/ConicWavesIHHOFirstOrder.hpp | 531 +++ .../Pulse/HeterogeneousEHHOFirstOrder.hpp | 530 +++ .../Pulse/HeterogeneousIHHOFirstOrder.hpp | 680 ++++ .../coupling/Pulse/IPulseEfficiency.hpp | 328 ++ .../prototypes/elastic/EElastic_stability.hpp | 405 +++ .../prototypes/elastic/EElasticity_CFL.hpp | 397 +++ .../elastic/ElasticIHHOFirstOrder.hpp | 308 ++ .../prototypes/elastic/IElastic_conv_test.hpp | 397 +++ .../elastodynamics_old/CMakeLists.txt | 2 + .../elastodynamics_old/elastodynamics.cpp | 3122 +++++++++++++++++ .../src/prototypes/postpro/parser_bassin.py | 134 + .../prototypes/postpro/parser_gmsh_diskpp.py | 109 + .../parser_gmsh_unstructured_simplices.py | 109 + .../wave_propagation/src/wave_propagation.cpp | 73 +- .../boundary_conditions.hpp | 8 + .../diskpp/geometry/geometry_generic.hpp | 8 + libdiskpp/include/diskpp/mesh/mesh.hpp | 15 + .../scalar_stabilization.hpp | 20 +- .../vector_stabilization.hpp | 10 +- 71 files changed, 18123 insertions(+), 286 deletions(-) create mode 100644 apps/wave_propagation/src/prototypes/acoustic/AcousticIHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustic/EAcoustic_CFL.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustic/EAcoustic_stability.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustic/IAcoustic_conv_test.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/CMakeLists.txt create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/EHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/IHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/IHHOSecondOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Elliptic_Conv_Test/EllipticOneFieldConvergenceTest.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Elliptic_Conv_Test/EllipticTwoFieldsConvergenceTest.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Gar6more_2D/HeterogeneousGar6more2DIHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Gar6more_2D/HeterogeneousGar6more2DIHHOSecondOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous/HeterogeneousEHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous/HeterogeneousIHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous/HeterogeneousIHHOSecondOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseEHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOFirstOrder2.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOSecondOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/prototype_selector.hpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/acoustics.cpp create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/input_files/acoustics_simulation.lua create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/input_files/acoustics_simulation_2d_pulse.lua create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/input_files/acoustics_test.lua create mode 100644 apps/wave_propagation/src/prototypes/acoustics_old/input_files/elliptic_convergence_test.lua create mode 100644 apps/wave_propagation/src/prototypes/coupling/Basin/BassinEHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/Basin/BassinIHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/Basin/Test.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/CFL/EHHOFirstOrderCFL.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/CFL/HeterogeneousEHHOFirstOrderCFL.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/Conv_Tests/EHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/Conv_Tests/EHHOFirstOrder_conv_tests.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder_conv_tests.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/EHHOFirstOrder_stability.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/HeterogeneousGar6more2DIHHOSecondOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/IHHOSecondOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesEHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/Pulse/HeterogeneousEHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/Pulse/HeterogeneousIHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/Pulse/IPulseEfficiency.hpp create mode 100644 apps/wave_propagation/src/prototypes/elastic/EElastic_stability.hpp create mode 100644 apps/wave_propagation/src/prototypes/elastic/EElasticity_CFL.hpp create mode 100644 apps/wave_propagation/src/prototypes/elastic/ElasticIHHOFirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/elastic/IElastic_conv_test.hpp create mode 100644 apps/wave_propagation/src/prototypes/elastodynamics_old/CMakeLists.txt create mode 100644 apps/wave_propagation/src/prototypes/elastodynamics_old/elastodynamics.cpp create mode 100644 apps/wave_propagation/src/prototypes/postpro/parser_bassin.py create mode 100644 apps/wave_propagation/src/prototypes/postpro/parser_gmsh_diskpp.py create mode 100644 apps/wave_propagation/src/prototypes/postpro/parser_gmsh_unstructured_simplices.py diff --git a/apps/wave_propagation/src/common/acoustic_one_field_assembler.hpp b/apps/wave_propagation/src/common/acoustic_one_field_assembler.hpp index 5813419c..621f62d7 100644 --- a/apps/wave_propagation/src/common/acoustic_one_field_assembler.hpp +++ b/apps/wave_propagation/src/common/acoustic_one_field_assembler.hpp @@ -99,7 +99,7 @@ class acoustic_one_field_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -108,7 +108,7 @@ class acoustic_one_field_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -159,7 +159,7 @@ class acoustic_one_field_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -169,7 +169,7 @@ class acoustic_one_field_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -214,7 +214,7 @@ class acoustic_one_field_assembler std::vector asm_map; asm_map.reserve(n_cbs); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -238,7 +238,7 @@ class acoustic_one_field_assembler std::vector asm_map; asm_map.reserve(n_cbs); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -496,7 +496,7 @@ class acoustic_one_field_assembler const Matrix& x_glob) const { auto num_faces = howmany_faces(msh, cl); - auto cell_ofs = disk::priv::offset(msh, cl); + auto cell_ofs = disk::offset(msh, cl); size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); @@ -520,7 +520,7 @@ class acoustic_one_field_assembler } else { - auto face_ofs = disk::priv::offset(msh, fc); + auto face_ofs = disk::offset(msh, fc); auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; x_local.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); } @@ -532,7 +532,7 @@ class acoustic_one_field_assembler scatter_cell_dof_data( const Mesh& msh, const typename Mesh::cell_type& cell, Matrix& x_glob, Matrix x_proj_dof) const { - auto cell_ofs = disk::priv::offset(msh, cell); + auto cell_ofs = disk::offset(msh, cell); size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1) = x_proj_dof; } @@ -544,7 +544,7 @@ class acoustic_one_field_assembler size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(),Mesh::dimension); size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); size_t n_cells = msh.cells_size(); - auto face_offset = disk::priv::offset(msh, face); + auto face_offset = disk::offset(msh, face); auto glob_offset = n_cbs * n_cells + m_compress_indexes.at(face_offset)*n_fbs; x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; } diff --git a/apps/wave_propagation/src/common/acoustic_two_fields_assembler.hpp b/apps/wave_propagation/src/common/acoustic_two_fields_assembler.hpp index 67665f17..07eff3b5 100644 --- a/apps/wave_propagation/src/common/acoustic_two_fields_assembler.hpp +++ b/apps/wave_propagation/src/common/acoustic_two_fields_assembler.hpp @@ -101,7 +101,7 @@ class acoustic_two_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -111,7 +111,7 @@ class acoustic_two_fields_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -156,7 +156,7 @@ class acoustic_two_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -166,7 +166,7 @@ class acoustic_two_fields_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -214,7 +214,7 @@ class acoustic_two_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -240,7 +240,7 @@ class acoustic_two_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -498,7 +498,7 @@ class acoustic_two_fields_assembler const Matrix& x_glob) const { auto num_faces = howmany_faces(msh, cl); - auto cell_ofs = disk::priv::offset(msh, cl); + auto cell_ofs = disk::offset(msh, cl); size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; size_t n_cbs = n_scal_cbs + n_vec_cbs; @@ -524,7 +524,7 @@ class acoustic_two_fields_assembler } else { - auto face_ofs = disk::priv::offset(msh, fc); + auto face_ofs = disk::offset(msh, fc); auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); } @@ -535,7 +535,7 @@ class acoustic_two_fields_assembler void scatter_cell_dof_data( const Mesh& msh, const typename Mesh::cell_type& cell, Matrix& x_glob, Matrix &x_proj_dof) const { - auto cell_ofs = disk::priv::offset(msh, cell); + auto cell_ofs = disk::offset(msh, cell); size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; size_t n_cbs = n_scal_cbs + n_vec_cbs; @@ -550,7 +550,7 @@ class acoustic_two_fields_assembler size_t n_cbs = n_scal_cbs + n_vec_cbs; size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); size_t n_cells = msh.cells_size(); - auto face_offset = disk::priv::offset(msh, face); + auto face_offset = disk::offset(msh, face); auto glob_offset = n_cbs * n_cells + m_compress_indexes.at(face_offset)*n_fbs; x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; } diff --git a/apps/wave_propagation/src/common/deprecated/one_field_assembler.hpp b/apps/wave_propagation/src/common/deprecated/one_field_assembler.hpp index d5985600..7d041992 100644 --- a/apps/wave_propagation/src/common/deprecated/one_field_assembler.hpp +++ b/apps/wave_propagation/src/common/deprecated/one_field_assembler.hpp @@ -113,7 +113,7 @@ class one_field_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -123,7 +123,7 @@ class one_field_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -207,7 +207,7 @@ class one_field_assembler const Matrix& x_glob) const { auto num_faces = howmany_faces(msh, cl); - auto cell_ofs = disk::priv::offset(msh, cl); + auto cell_ofs = disk::offset(msh, cl); size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); @@ -231,7 +231,7 @@ class one_field_assembler } else { - auto face_ofs = disk::priv::offset(msh, fc); + auto face_ofs = disk::offset(msh, fc); auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); } diff --git a/apps/wave_propagation/src/common/deprecated/one_field_vectorial_assembler.hpp b/apps/wave_propagation/src/common/deprecated/one_field_vectorial_assembler.hpp index 164a97e9..8aa34f73 100644 --- a/apps/wave_propagation/src/common/deprecated/one_field_vectorial_assembler.hpp +++ b/apps/wave_propagation/src/common/deprecated/one_field_vectorial_assembler.hpp @@ -113,7 +113,7 @@ class one_field_vectorial_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -123,7 +123,7 @@ class one_field_vectorial_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -210,7 +210,7 @@ class one_field_vectorial_assembler const Matrix& x_glob) const { auto num_faces = howmany_faces(msh, cl); - auto cell_ofs = disk::priv::offset(msh, cl); + auto cell_ofs = disk::offset(msh, cl); size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); @@ -234,7 +234,7 @@ class one_field_vectorial_assembler } else { - auto face_ofs = disk::priv::offset(msh, fc); + auto face_ofs = disk::offset(msh, fc); auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); } diff --git a/apps/wave_propagation/src/common/deprecated/three_fields_vectorial_assembler.hpp b/apps/wave_propagation/src/common/deprecated/three_fields_vectorial_assembler.hpp index c24bd4c7..e8476aed 100644 --- a/apps/wave_propagation/src/common/deprecated/three_fields_vectorial_assembler.hpp +++ b/apps/wave_propagation/src/common/deprecated/three_fields_vectorial_assembler.hpp @@ -119,7 +119,7 @@ class three_fields_vectorial_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -129,7 +129,7 @@ class three_fields_vectorial_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -232,7 +232,7 @@ class three_fields_vectorial_assembler const Matrix& x_glob) const { auto num_faces = howmany_faces(msh, cl); - auto cell_ofs = disk::priv::offset(msh, cl); + auto cell_ofs = disk::offset(msh, cl); size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); @@ -259,7 +259,7 @@ class three_fields_vectorial_assembler } else { - auto face_ofs = disk::priv::offset(msh, fc); + auto face_ofs = disk::offset(msh, fc); auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; x_el.block(n_vec_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); } diff --git a/apps/wave_propagation/src/common/deprecated/two_fields_assembler.hpp b/apps/wave_propagation/src/common/deprecated/two_fields_assembler.hpp index 997df4f8..2e16c089 100644 --- a/apps/wave_propagation/src/common/deprecated/two_fields_assembler.hpp +++ b/apps/wave_propagation/src/common/deprecated/two_fields_assembler.hpp @@ -116,7 +116,7 @@ class two_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -126,7 +126,7 @@ class two_fields_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -214,7 +214,7 @@ class two_fields_assembler const Matrix& x_glob) const { auto num_faces = howmany_faces(msh, cl); - auto cell_ofs = disk::priv::offset(msh, cl); + auto cell_ofs = disk::offset(msh, cl); size_t n_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); @@ -238,7 +238,7 @@ class two_fields_assembler } else { - auto face_ofs = disk::priv::offset(msh, fc); + auto face_ofs = disk::offset(msh, fc); auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); } diff --git a/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp b/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp index 5e69f8f1..b9656d3a 100644 --- a/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp +++ b/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp @@ -594,7 +594,7 @@ class elastoacoustic_four_fields_assembler } - void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun, bool explicit_scheme){ + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun, bool explicit_scheme){ auto storage = msh.backend_storage(); LHS.setZero(); @@ -662,7 +662,7 @@ class elastoacoustic_four_fields_assembler finalize_mass(); } - void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun, bool explicit_scheme){ + void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun, bool explicit_scheme){ RHS.setZero(); #ifdef HAVE_INTEL_TBB2 @@ -745,8 +745,8 @@ class elastoacoustic_four_fields_assembler auto n_cols = R_operator.cols(); Matrix S_operator = Matrix::Zero(n_rows, n_cols); - if(explicit_scheme) { - auto stabilization_operator = make_vector_hdg_stabilization(msh, cell, m_hho_di, m_scaled_stabilization_Q); + if (explicit_scheme) { + auto stabilization_operator = make_vector_hdg_stabilization(msh, cell, m_hho_di, false, m_scaled_stabilization_Q); auto n_s_rows = stabilization_operator.rows(); auto n_s_cols = stabilization_operator.cols(); S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; @@ -760,7 +760,7 @@ class elastoacoustic_four_fields_assembler S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; } else { - auto stabilization_operator = make_vector_hdg_stabilization(msh, cell, m_hho_di, m_scaled_stabilization_Q); + auto stabilization_operator = make_vector_hdg_stabilization(msh, cell, m_hho_di, false, m_scaled_stabilization_Q); auto n_s_rows = stabilization_operator.rows(); auto n_s_cols = stabilization_operator.cols(); S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; @@ -863,7 +863,7 @@ class elastoacoustic_four_fields_assembler } Matrix - e_mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> & rhs_fun, size_t di = 0) + e_mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> & rhs_fun, size_t di = 0) { auto recdeg = m_hho_di.grad_degree(); auto celdeg = m_hho_di.cell_degree(); @@ -1053,7 +1053,7 @@ class elastoacoustic_four_fields_assembler Matrix S_operator = Matrix::Zero(n_rows, n_cols); if(explicit_scheme) { - auto stabilization_operator = make_scalar_hdg_stabilization(msh, cell, m_hho_di, m_scaled_stabilization_Q); + auto stabilization_operator = make_scalar_hdg_stabilization(msh, cell, m_hho_di, false, m_scaled_stabilization_Q); auto n_s_rows = stabilization_operator.rows(); auto n_s_cols = stabilization_operator.cols(); S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; @@ -1066,7 +1066,7 @@ class elastoacoustic_four_fields_assembler S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; } else { - auto stabilization_operator = make_scalar_hdg_stabilization(msh, cell, m_hho_di, m_scaled_stabilization_Q); + auto stabilization_operator = make_scalar_hdg_stabilization(msh, cell, m_hho_di, false, m_scaled_stabilization_Q); auto n_s_rows = stabilization_operator.rows(); auto n_s_cols = stabilization_operator.cols(); S_operator.block(n_rows-n_s_rows, n_cols-n_s_cols, n_s_rows, n_s_cols) = stabilization_operator; @@ -1192,8 +1192,9 @@ class elastoacoustic_four_fields_assembler const auto s_f_phi = sfb.eval_functions(qp.point()); assert(v_f_phi.rows() == vfbs); assert(s_f_phi.rows() == sfbs); - const auto n_dot_v_f_phi = disk::priv::inner_product(v_f_phi,disk::priv::inner_product(qp.weight(), n)); - const auto result = -1.0*disk::priv::outer_product(n_dot_v_f_phi, s_f_phi); + auto q_n = disk::priv::inner_product(qp.weight(), n); + const auto n_dot_v_f_phi = disk::priv::inner_product(v_f_phi,q_n); + const auto result = (-1.0*disk::priv::outer_product(n_dot_v_f_phi, s_f_phi)).eval(); interface_operator += result; } return interface_operator; @@ -1225,7 +1226,7 @@ class elastoacoustic_four_fields_assembler return neumann_operator; } - Matrix a_neumman_bc_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell, std::function(const typename Mesh::point_type& )> e_vel_fun){ + Matrix a_neumman_bc_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell, std::function(const typename Mesh::point_type& )> e_vel_fun){ Matrix neumann_operator; auto facdeg = m_hho_di.face_degree(); @@ -1314,7 +1315,7 @@ class elastoacoustic_four_fields_assembler } - void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> v_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::function v_s_fun, std::function(const typename Mesh::point_type& )> flux_s_fun){ + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> v_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::function v_s_fun, std::function(const typename Mesh::point_type& )> flux_s_fun){ auto storage = msh.backend_storage(); size_t n_dof = MASS.rows(); @@ -1360,7 +1361,7 @@ class elastoacoustic_four_fields_assembler } Matrix project_vec_function(const Mesh& msh, const typename Mesh::cell_type& cell, - std::function(const typename Mesh::point_type& )> vec_fun){ + std::function(const typename Mesh::point_type& )> vec_fun){ auto recdeg = m_hho_di.reconstruction_degree(); auto rec_basis = make_scalar_monomial_basis(msh, cell, recdeg); @@ -1386,7 +1387,7 @@ class elastoacoustic_four_fields_assembler } Matrix project_ten_function(const Mesh& msh, const typename Mesh::cell_type& cell, - std::function(const typename Mesh::point_type& )> ten_fun){ + std::function(const typename Mesh::point_type& )> ten_fun){ Matrix mass_matrix = symmetric_tensor_mass_matrix(msh, cell); size_t dim = Mesh::dimension; @@ -1399,7 +1400,7 @@ class elastoacoustic_four_fields_assembler for (auto& qp : qps) { auto phi = ten_b.eval_functions(qp.point()); - static_matrix sigma = ten_fun(qp.point()); + disk::static_matrix sigma = ten_fun(qp.point()); for (size_t i = 0; i < ten_bs; i++){ auto qp_phi_i = disk::priv::inner_product(qp.weight(), phi[i]); rhs(i,0) += disk::priv::inner_product(qp_phi_i,sigma); @@ -1428,7 +1429,7 @@ class elastoacoustic_four_fields_assembler } - void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function scal_fun){ + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function scal_fun){ auto storage = msh.backend_storage(); @@ -1585,13 +1586,10 @@ class elastoacoustic_four_fields_assembler } void set_hdg_stabilization() { - // std::cout << bold << red << " SUMMARY: " << reset << std::endl; - if(m_hho_di.cell_degree() > m_hho_di.face_degree()) { - m_hho_stabilization_Q = false; - } - else{ + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) + m_hho_stabilization_Q = false; + else m_hho_stabilization_Q = true; - } } void set_interface_cell_indexes(std::map> & interface_cell_indexes){ diff --git a/apps/wave_propagation/src/common/elastoacoustic_two_fields_assembler.hpp b/apps/wave_propagation/src/common/elastoacoustic_two_fields_assembler.hpp index d3ff2cae..017a2f46 100644 --- a/apps/wave_propagation/src/common/elastoacoustic_two_fields_assembler.hpp +++ b/apps/wave_propagation/src/common/elastoacoustic_two_fields_assembler.hpp @@ -567,7 +567,7 @@ class elastoacoustic_two_fields_assembler } - void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun){ + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun){ auto storage = msh.backend_storage(); LHS.setZero(); @@ -612,7 +612,7 @@ class elastoacoustic_two_fields_assembler finalize_coupling(); } - void apply_bc_conditions_on_interface(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_vel_fun, std::function a_vel_fun){ + void apply_bc_conditions_on_interface(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_vel_fun, std::function a_vel_fun){ auto storage = msh.backend_storage(); // Applying transmission conditions as neumann data for the case of uncoupled problems @@ -654,7 +654,7 @@ class elastoacoustic_two_fields_assembler finalize_mass(); } - void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun){ + void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun){ RHS.setZero(); #ifdef HAVE_INTEL_TBB2 @@ -830,7 +830,7 @@ class elastoacoustic_two_fields_assembler return neumann_operator; } - Matrix a_neumman_bc_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell, std::function(const typename Mesh::point_type& )> e_vel_fun){ + Matrix a_neumman_bc_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell, std::function(const typename Mesh::point_type& )> e_vel_fun){ Matrix neumann_operator; auto facdeg = m_hho_di.face_degree(); @@ -916,7 +916,7 @@ class elastoacoustic_two_fields_assembler } } - void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function scal_fun){ + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function scal_fun){ auto storage = msh.backend_storage(); size_t n_dof = MASS.rows(); @@ -960,7 +960,7 @@ class elastoacoustic_two_fields_assembler - void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function scal_fun){ + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function scal_fun){ auto storage = msh.backend_storage(); diff --git a/apps/wave_propagation/src/common/elastodynamic_one_field_assembler.hpp b/apps/wave_propagation/src/common/elastodynamic_one_field_assembler.hpp index 36714493..19f9a0be 100644 --- a/apps/wave_propagation/src/common/elastodynamic_one_field_assembler.hpp +++ b/apps/wave_propagation/src/common/elastodynamic_one_field_assembler.hpp @@ -95,7 +95,7 @@ class elastodynamic_one_field_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -104,7 +104,7 @@ class elastodynamic_one_field_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -147,7 +147,7 @@ class elastodynamic_one_field_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -157,7 +157,7 @@ class elastodynamic_one_field_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -202,7 +202,7 @@ class elastodynamic_one_field_assembler std::vector asm_map; asm_map.reserve(n_cbs); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -226,7 +226,7 @@ class elastodynamic_one_field_assembler std::vector asm_map; asm_map.reserve(n_cbs); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -248,7 +248,7 @@ class elastodynamic_one_field_assembler } - void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type&)> rhs_fun){ LHS.setZero(); RHS.setZero(); @@ -290,7 +290,7 @@ class elastodynamic_one_field_assembler } - void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun, T scale = T(1.0)){ + void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun, T scale = T(1.0)){ RHS.setZero(); #ifdef HAVE_INTEL_TBB2 @@ -383,7 +383,7 @@ class elastodynamic_one_field_assembler } } - void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun){ + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun){ size_t n_dof = MASS.rows(); x_glob = Matrix::Zero(n_dof); for (auto& cell : msh) @@ -393,7 +393,7 @@ class elastodynamic_one_field_assembler } } - void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun){ + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun){ for (auto& cell : msh) { @@ -430,7 +430,7 @@ class elastodynamic_one_field_assembler const Matrix& x_glob) const { auto num_faces = howmany_faces(msh, cl); - auto cell_ofs = disk::priv::offset(msh, cl); + auto cell_ofs = disk::offset(msh, cl); size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); @@ -454,7 +454,7 @@ class elastodynamic_one_field_assembler } else { - auto face_ofs = disk::priv::offset(msh, fc); + auto face_ofs = disk::offset(msh, fc); auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); } @@ -466,7 +466,7 @@ class elastodynamic_one_field_assembler scatter_cell_dof_data( const Mesh& msh, const typename Mesh::cell_type& cell, Matrix& x_glob, Matrix x_proj_dof) const { - auto cell_ofs = disk::priv::offset(msh, cell); + auto cell_ofs = disk::offset(msh, cell); size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); x_glob.block(cell_ofs * n_cbs, 0, n_cbs, 1) = x_proj_dof; } @@ -478,7 +478,7 @@ class elastodynamic_one_field_assembler size_t n_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); size_t n_cells = msh.cells_size(); - auto face_offset = disk::priv::offset(msh, face); + auto face_offset = disk::offset(msh, face); auto glob_offset = n_cbs * n_cells + m_compress_indexes.at(face_offset)*n_fbs; x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; } diff --git a/apps/wave_propagation/src/common/elastodynamic_three_fields_assembler.hpp b/apps/wave_propagation/src/common/elastodynamic_three_fields_assembler.hpp index 68029dae..0b2051df 100644 --- a/apps/wave_propagation/src/common/elastodynamic_three_fields_assembler.hpp +++ b/apps/wave_propagation/src/common/elastodynamic_three_fields_assembler.hpp @@ -103,7 +103,7 @@ class elastodynamic_three_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -112,7 +112,7 @@ class elastodynamic_three_fields_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -158,7 +158,7 @@ class elastodynamic_three_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -168,7 +168,7 @@ class elastodynamic_three_fields_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -215,7 +215,7 @@ class elastodynamic_three_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -242,7 +242,7 @@ class elastodynamic_three_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -263,7 +263,7 @@ class elastodynamic_three_fields_assembler } } - void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ LHS.setZero(); RHS.setZero(); @@ -302,7 +302,7 @@ class elastodynamic_three_fields_assembler } - void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ + void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ RHS.setZero(); @@ -477,7 +477,7 @@ class elastodynamic_three_fields_assembler } } - void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> ten_fun){ + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> ten_fun){ size_t n_dof = MASS.rows(); x_glob = Matrix::Zero(n_dof); size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); @@ -499,7 +499,7 @@ class elastodynamic_three_fields_assembler } Matrix project_ten_function(const Mesh& msh, const typename Mesh::cell_type& cell, - std::function(const typename Mesh::point_type& )> ten_fun){ + std::function(const typename Mesh::point_type& )> ten_fun){ Matrix mass_matrix = symmetric_tensor_mass_matrix(msh, cell); size_t dim = Mesh::dimension; @@ -512,12 +512,12 @@ class elastodynamic_three_fields_assembler for (auto& qp : qps) { auto phi = ten_b.eval_functions(qp.point()); - static_matrix sigma = ten_fun(qp.point()); + disk::static_matrix sigma = ten_fun(qp.point()); T trace = 0.0; for (size_t d = 0; d < dim; d++){ trace += sigma(d,d); } - static_matrix sigma_s = sigma - (trace)*static_matrix::Identity(); + disk::static_matrix sigma_s = sigma - (trace)*disk::static_matrix::Identity(); for (size_t i = 0; i < ten_bs; i++){ auto qp_phi_i = disk::priv::inner_product(qp.weight(), phi[i]); rhs(i,0) += disk::priv::inner_product(qp_phi_i,sigma_s); @@ -528,7 +528,7 @@ class elastodynamic_three_fields_assembler } Matrix project_hydrostatic_function(const Mesh& msh, const typename Mesh::cell_type& cell, - std::function(const typename Mesh::point_type& )> ten_fun){ + std::function(const typename Mesh::point_type& )> ten_fun){ size_t dim = Mesh::dimension; auto facedeg = m_hho_di.face_degree(); @@ -541,7 +541,7 @@ class elastodynamic_three_fields_assembler for (auto& qp : qps) { auto phi = sca_basis.eval_functions(qp.point()); - static_matrix sigma = ten_fun(qp.point()); + disk::static_matrix sigma = ten_fun(qp.point()); T trace = 0.0; for (size_t d = 0; d < dim; d++){ trace += sigma(d,d); @@ -555,7 +555,7 @@ class elastodynamic_three_fields_assembler return x_dof; } - void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun){ + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun){ for (auto& cell : msh) { @@ -592,7 +592,7 @@ class elastodynamic_three_fields_assembler const Matrix& x_glob) const { auto num_faces = howmany_faces(msh, cl); - auto cell_ofs = disk::priv::offset(msh, cl); + auto cell_ofs = disk::offset(msh, cl); size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); @@ -620,7 +620,7 @@ class elastodynamic_three_fields_assembler } else { - auto face_ofs = disk::priv::offset(msh, fc); + auto face_ofs = disk::offset(msh, fc); auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); } @@ -631,7 +631,7 @@ class elastodynamic_three_fields_assembler void scatter_cell_dof_data( const Mesh& msh, const typename Mesh::cell_type& cell, Matrix& x_glob, Matrix & x_proj_dof) const { - auto cell_ofs = disk::priv::offset(msh, cell); + auto cell_ofs = disk::offset(msh, cell); size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); size_t n_sca_cbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension); size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); @@ -648,7 +648,7 @@ class elastodynamic_three_fields_assembler size_t n_cbs = n_ten_cbs + n_sca_cbs + n_vec_cbs; size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); size_t n_cells = msh.cells_size(); - auto face_offset = disk::priv::offset(msh, face); + auto face_offset = disk::offset(msh, face); auto glob_offset = n_cbs * n_cells + m_compress_indexes.at(face_offset)*n_fbs; x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; } @@ -784,7 +784,7 @@ class elastodynamic_three_fields_assembler } Matrix - mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> & rhs_fun, size_t di = 0) + mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> & rhs_fun, size_t di = 0) { auto recdeg = m_hho_di.grad_degree(); auto celdeg = m_hho_di.cell_degree(); diff --git a/apps/wave_propagation/src/common/elastodynamic_two_fields_assembler.hpp b/apps/wave_propagation/src/common/elastodynamic_two_fields_assembler.hpp index 45d21099..cd427618 100644 --- a/apps/wave_propagation/src/common/elastodynamic_two_fields_assembler.hpp +++ b/apps/wave_propagation/src/common/elastodynamic_two_fields_assembler.hpp @@ -101,7 +101,7 @@ class elastodynamic_two_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -110,7 +110,7 @@ class elastodynamic_two_fields_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -155,7 +155,7 @@ class elastodynamic_two_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -165,7 +165,7 @@ class elastodynamic_two_fields_assembler for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; - auto face_offset = disk::priv::offset(msh, fc); + auto face_offset = disk::offset(msh, fc); auto face_LHS_offset = n_cbs * msh.cells_size() + m_compress_indexes.at(face_offset)*n_fbs; auto fc_id = msh.lookup(fc); @@ -211,7 +211,7 @@ class elastodynamic_two_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -237,7 +237,7 @@ class elastodynamic_two_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs); - auto cell_offset = disk::priv::offset(msh, cl); + auto cell_offset = disk::offset(msh, cl); auto cell_LHS_offset = cell_offset * n_cbs; for (size_t i = 0; i < n_cbs; i++) @@ -258,7 +258,7 @@ class elastodynamic_two_fields_assembler } } - void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ LHS.setZero(); RHS.setZero(); @@ -297,7 +297,7 @@ class elastodynamic_two_fields_assembler } - void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ + void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> rhs_fun){ RHS.setZero(); @@ -517,7 +517,7 @@ class elastodynamic_two_fields_assembler } } - void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> ten_fun){ + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> ten_fun){ size_t n_dof = MASS.rows(); x_glob = Matrix::Zero(n_dof); size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); @@ -536,7 +536,7 @@ class elastodynamic_two_fields_assembler } Matrix project_ten_function(const Mesh& msh, const typename Mesh::cell_type& cell, - std::function(const typename Mesh::point_type& )> ten_fun){ + std::function(const typename Mesh::point_type& )> ten_fun){ Matrix mass_matrix = symmetric_tensor_mass_matrix(msh, cell); size_t dim = Mesh::dimension; @@ -549,7 +549,7 @@ class elastodynamic_two_fields_assembler for (auto& qp : qps) { auto phi = ten_b.eval_functions(qp.point()); - static_matrix sigma = ten_fun(qp.point()); + disk::static_matrix sigma = ten_fun(qp.point()); for (size_t i = 0; i < ten_bs; i++){ auto qp_phi_i = disk::priv::inner_product(qp.weight(), phi[i]); rhs(i,0) += disk::priv::inner_product(qp_phi_i,sigma); @@ -559,7 +559,7 @@ class elastodynamic_two_fields_assembler return x_dof; } - void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun){ + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun){ for (auto& cell : msh) { @@ -596,7 +596,7 @@ class elastodynamic_two_fields_assembler const Matrix& x_glob) const { auto num_faces = howmany_faces(msh, cl); - auto cell_ofs = disk::priv::offset(msh, cl); + auto cell_ofs = disk::offset(msh, cl); size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); size_t n_cbs = n_ten_cbs + n_vec_cbs; @@ -623,7 +623,7 @@ class elastodynamic_two_fields_assembler } else { - auto face_ofs = disk::priv::offset(msh, fc); + auto face_ofs = disk::offset(msh, fc); auto global_ofs = n_cbs * msh.cells_size() + m_compress_indexes.at(face_ofs)*n_fbs; x_el.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(global_ofs, 0, n_fbs, 1); } @@ -634,7 +634,7 @@ class elastodynamic_two_fields_assembler void scatter_cell_dof_data( const Mesh& msh, const typename Mesh::cell_type& cell, Matrix& x_glob, Matrix & x_proj_dof) const { - auto cell_ofs = disk::priv::offset(msh, cell); + auto cell_ofs = disk::offset(msh, cell); size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); size_t n_cbs = n_ten_cbs + n_vec_cbs; @@ -649,7 +649,7 @@ class elastodynamic_two_fields_assembler size_t n_cbs = n_ten_cbs + n_vec_cbs; size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); size_t n_cells = msh.cells_size(); - auto face_offset = disk::priv::offset(msh, face); + auto face_offset = disk::offset(msh, face); auto glob_offset = n_cbs * n_cells + m_compress_indexes.at(face_offset)*n_fbs; x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; } @@ -757,7 +757,7 @@ class elastodynamic_two_fields_assembler } Matrix - mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> & rhs_fun, size_t di = 0) + mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> & rhs_fun, size_t di = 0) { auto recdeg = m_hho_di.grad_degree(); auto celdeg = m_hho_di.cell_degree(); diff --git a/apps/wave_propagation/src/common/fitted_geometry_builders.hpp b/apps/wave_propagation/src/common/fitted_geometry_builders.hpp index 859913fc..699e0a4f 100644 --- a/apps/wave_propagation/src/common/fitted_geometry_builders.hpp +++ b/apps/wave_propagation/src/common/fitted_geometry_builders.hpp @@ -178,7 +178,7 @@ class cartesian_2d_mesh_builder : public fitted_geometry_builder(node_id))); + vertices.push_back(node_type(disk::point_identifier<2>(node_id))); node_id++; } } @@ -326,10 +326,11 @@ class cartesian_2d_mesh_builder : public fitted_geometry_builderboundary_info.at(position.second) = bi; } @@ -369,7 +370,7 @@ class cartesian_2d_mesh_builder : public fitted_geometry_builderedges.begin(), storage->edges.end(), edge); if (!edge_id.first) @@ -456,18 +457,9 @@ public fitted_geometry_builder> { std::vector> skeleton_edges; std::vector> boundary_edges; std::vector polygons; - // std::vector faces; std::string poly_mesh_file; std::set bc_points; - // FaceInfo face_info; - // face_info.face_id = edge_id.second; - // if (face_info.cell1_id == -1) { - // face_info.cell1_id == compteur; - // } - // else { - // face_info.cell2_id == compteur; - // } - // faces.push_back(face_info); + void clear_storage() { points.clear(); vertices.clear(); @@ -576,7 +568,7 @@ public fitted_geometry_builder> { std::stringstream(line) >> xv >> yv; point_type point(xv, yv); points.push_back(point); - vertices.push_back(node_type(point_identifier<2>(id))); + vertices.push_back(node_type(disk::point_identifier<2>(id))); } else{ break; @@ -670,7 +662,7 @@ public fitted_geometry_builder> { std::stringstream(line) >> xv >> yv; point_type point(xv, yv); points.push_back(point); - vertices.push_back(node_type(point_identifier<2>(id))); + vertices.push_back(node_type(disk::point_identifier<2>(id))); } else{ break; @@ -763,7 +755,6 @@ public fitted_geometry_builder> { return true; } - void move_to_mesh_storage(mesh_type& msh){ auto storage = msh.backend_storage(); @@ -777,9 +768,9 @@ public fitted_geometry_builder> { auto node1 = typename node_type::id_type(facets[i][0]); auto node2 = typename node_type::id_type(facets[i][1]); - auto e = edge_type{{node1, node2}}; + auto e = edge_type(node1, node2); - e.set_point_ids(facets[i].begin(), facets[i].end()); + // e.set_point_ids(facets[i].begin(), facets[i].end()); edges.push_back(e); } std::sort(edges.begin(), edges.end()); @@ -789,14 +780,14 @@ public fitted_geometry_builder> { assert(boundary_edges[i][0] < boundary_edges[i][1]); auto node1 = typename node_type::id_type(boundary_edges[i][0]); auto node2 = typename node_type::id_type(boundary_edges[i][1]); - auto e = edge_type{{node1, node2}}; + auto e = edge_type(node1, node2); auto position = find_element_id(edges.begin(), edges.end(), e); if (position.first == false) { std::cout << "Bad bug at " << __FILE__ << "(" << __LINE__ << ")" << std::endl; return; } - disk::bnd_info bi{0, true}; + disk::boundary_descriptor bi{0, true}; storage->boundary_info.at(position.second) = bi; } @@ -817,7 +808,7 @@ public fitted_geometry_builder> { auto n1 = typename node_type::id_type(e[0]); auto n2 = typename node_type::id_type(e[1]); - edge_type edge{{n1, n2}}; + edge_type edge(n1, n2); auto edge_id = find_element_id(storage->edges.begin(), storage->edges.end(), edge); if (!edge_id.first) diff --git a/apps/wave_propagation/src/common/postprocessor.hpp b/apps/wave_propagation/src/common/postprocessor.hpp index b978e673..3ce396a1 100644 --- a/apps/wave_propagation/src/common/postprocessor.hpp +++ b/apps/wave_propagation/src/common/postprocessor.hpp @@ -23,9 +23,7 @@ #include #endif -// using namespace priv; -// namespace priv -// { + template class postprocessor { @@ -519,7 +517,7 @@ class postprocessor { } /// Compute L2 and H1 errors for one field vectorial approximation - static void compute_errors_one_field_vectorial(Mesh & msh, disk::hho_degree_info & hho_di, elastodynamic_one_field_assembler & assembler, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + static void compute_errors_one_field_vectorial(Mesh & msh, disk::hho_degree_info & hho_di, elastodynamic_one_field_assembler & assembler, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ timecounter tc; tc.tic(); @@ -562,10 +560,10 @@ class postprocessor { Matrix all_dofs = assembler.gather_dof_data(msh, cell, x_dof); auto sgr = make_vector_hho_symmetric_laplacian(msh, cell, hho_di); - dynamic_vector GTu = sgr.first * all_dofs; + disk::dynamic_vector GTu = sgr.first * all_dofs; auto dr = make_hho_divergence_reconstruction(msh, cell, hho_di); - dynamic_vector divu = dr.first * all_dofs; + disk::dynamic_vector divu = dr.first * all_dofs; auto cbas_v = disk::make_vector_monomial_basis(msh, cell, hho_di.reconstruction_degree()); auto cbas_s = disk::make_scalar_monomial_basis(msh, cell, hho_di.face_degree()); @@ -582,7 +580,7 @@ class postprocessor { auto epsilon = disk::eval(GTu, gphi, dim); auto divphi = cbas_s.eval_functions(point_pair.point()); auto trace_epsilon = disk::eval(divu, divphi); - auto sigma = 2.0 * mu * epsilon + lambda * trace_epsilon * static_matrix::Identity(); + auto sigma = 2.0 * mu * epsilon + lambda * trace_epsilon * disk::static_matrix::Identity(); auto flux_diff = (flux_fun(point_pair.point()) - sigma).eval(); flux_l2_error += omega * flux_diff.squaredNorm(); @@ -603,7 +601,7 @@ class postprocessor { } /// Compute L2 and H1 errors for two fields vectorial approximation - static void compute_errors_two_fields_vectorial(Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + static void compute_errors_two_fields_vectorial(Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ timecounter tc; tc.tic(); @@ -675,7 +673,7 @@ class postprocessor { } /// Compute L2 and H1 errors for three fields vectorial approximation - static void compute_errors_three_fields_vectorial(Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + static void compute_errors_three_fields_vectorial(Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ timecounter tc; tc.tic(); @@ -734,7 +732,7 @@ class postprocessor { assert(t_sca_phi.size() == sca_basis.size()); auto sigma_v_h = disk::eval(sigma_v_x_cell_dof, t_sca_phi); - sigma_h += sigma_v_h * static_matrix::Identity(); + sigma_h += sigma_v_h * disk::static_matrix::Identity(); auto flux_diff = (flux_fun(point_pair.point()) - sigma_h).eval(); flux_l2_error += omega * flux_diff.squaredNorm(); @@ -1590,7 +1588,7 @@ class postprocessor { // Write a silo file for one field vectorial approximation static void write_silo_one_field_vectorial(std::string silo_file_name, size_t it, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof, - std::function(const typename Mesh::point_type& )> vec_fun, bool cell_centered_Q){ + std::function(const typename Mesh::point_type& )> vec_fun, bool cell_centered_Q){ timecounter tc; tc.tic(); @@ -1704,7 +1702,7 @@ class postprocessor { } // Write a silo file for two fields vectorial approximation - static void write_silo_two_fields_vectorial(std::string silo_file_name, size_t it, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof,std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, bool cell_centered_Q){ + static void write_silo_two_fields_vectorial(std::string silo_file_name, size_t it, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof,std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, bool cell_centered_Q){ timecounter tc; tc.tic(); @@ -1903,7 +1901,7 @@ class postprocessor { } // Write a silo file for three fields vectorial approximation - static void write_silo_three_fields_vectorial(std::string silo_file_name, size_t it, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof,std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, bool cell_centered_Q){ + static void write_silo_three_fields_vectorial(std::string silo_file_name, size_t it, Mesh & msh, disk::hho_degree_info & hho_di, Matrix & x_dof,std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> flux_fun, bool cell_centered_Q){ timecounter tc; tc.tic(); @@ -1971,7 +1969,7 @@ class postprocessor { assert(t_sca_phi.size() == sca_basis.size()); auto sigma_v_h = disk::eval(sigma_v_x_cell_dof, t_sca_phi); - sigma_h += sigma_v_h * static_matrix::Identity(); + sigma_h += sigma_v_h * disk::static_matrix::Identity(); approx_sxx.push_back(sigma_h(0,0)); approx_sxy.push_back(sigma_h(0,1)); @@ -2050,7 +2048,7 @@ class postprocessor { assert(t_sca_phi.size() == sca_basis.size()); auto sigma_v_h = disk::eval(sigma_v_x_cell_dof, t_sca_phi); - sigma_h += sigma_v_h * static_matrix::Identity(); + sigma_h += sigma_v_h * disk::static_matrix::Identity(); approx_sxx.push_back(sigma_h(0,0)); approx_sxy.push_back(sigma_h(0,1)); @@ -2194,7 +2192,7 @@ class postprocessor { //////////////////////////////////////////////////////////////////////////////// /// Compute errors - static void compute_errors_two_fields_elastoacoustic(Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_two_fields_assembler & assembler, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> sigma_fun,std::function scal_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + static void compute_errors_two_fields_elastoacoustic(Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_two_fields_assembler & assembler, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> sigma_fun,std::function scal_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ timecounter tc; tc.tic(); @@ -2244,10 +2242,10 @@ class postprocessor { Matrix all_dofs = assembler.gather_e_dof_data(e_cell_ind, msh, cell, x_dof); auto sgr = make_vector_hho_symmetric_laplacian(msh, cell, hho_di); - dynamic_vector GTu = sgr.first * all_dofs; + disk::dynamic_vector GTu = sgr.first * all_dofs; auto dr = make_hho_divergence_reconstruction(msh, cell, hho_di); - dynamic_vector divu = dr.first * all_dofs; + disk::dynamic_vector divu = dr.first * all_dofs; auto cbas_v = disk::make_vector_monomial_basis(msh, cell, hho_di.reconstruction_degree()); auto cbas_s = disk::make_scalar_monomial_basis(msh, cell, hho_di.face_degree()); @@ -2264,7 +2262,7 @@ class postprocessor { auto epsilon = disk::eval(GTu, gphi, dim); auto divphi = cbas_s.eval_functions(point_pair.point()); auto trace_epsilon = disk::eval(divu, divphi); - auto sigma = 2.0 * mu * epsilon + lambda * trace_epsilon * static_matrix::Identity(); + auto sigma = 2.0 * mu * epsilon + lambda * trace_epsilon * disk::static_matrix::Identity(); auto flux_diff = (sigma_fun(point_pair.point()) - sigma).eval(); sigma_l2_error += omega * flux_diff.squaredNorm(); @@ -2338,7 +2336,7 @@ class postprocessor { error_file.flush(); } - static void compute_errors_four_fields_elastoacoustic(Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> sigma_fun,std::function scal_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + static void compute_errors_four_fields_elastoacoustic(Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> sigma_fun,std::function scal_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ timecounter tc; tc.tic(); @@ -2476,7 +2474,7 @@ class postprocessor { error_file.flush(); } - static void compute_errors_four_fields_elastoacoustic_energy_norm(Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> sigma_fun,std::function scal_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ + static void compute_errors_four_fields_elastoacoustic_energy_norm(Mesh & msh, disk::hho_degree_info & hho_di, elastoacoustic_four_fields_assembler & assembler, Matrix & x_dof, std::function(const typename Mesh::point_type& )> vec_fun, std::function(const typename Mesh::point_type& )> sigma_fun,std::function scal_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::ostream & error_file = std::cout){ timecounter tc; tc.tic(); diff --git a/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp b/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp index 9c134a0b..2ab45f97 100644 --- a/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp +++ b/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp @@ -26,20 +26,20 @@ class scal_vec_analytic_functions { m_function_type = function_type; } - std::function + std::function (const typename disk::generic_mesh::point_type& )> Evaluate_u(double & t) { switch (m_function_type) { case EFunctionNonPolynomial: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,ux,uy; x = pt.x(); y = pt.y(); ux = x*x*std::sin(M_PI*y)*std::cos((M_PI*x)/2.)*std::cos(std::sqrt(2.0)*M_PI*t); uy = x*x*std::sin(M_PI*y)*std::cos((M_PI*x)/2.)*std::cos(std::sqrt(2.0)*M_PI*t); - static_vector u{ux,uy}; + disk::static_vector u{ux,uy}; return u; }; } @@ -47,13 +47,13 @@ class scal_vec_analytic_functions { case EFunctionQuadraticInTime: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,ux,uy; x = pt.x(); y = pt.y(); ux = x*t*t*std::sin(M_PI*x)*std::sin(M_PI*y); uy = x*t*t*std::sin(M_PI*x)*std::sin(M_PI*y); - static_vector u{ux,uy}; + disk::static_vector u{ux,uy}; return u; }; } @@ -61,33 +61,33 @@ class scal_vec_analytic_functions { case EFunctionQuadraticInSpace: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,ux,uy; x = pt.x(); y = pt.y(); ux = (1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); uy = (1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); - static_vector u{ux,uy}; + disk::static_vector u{ux,uy}; return u; }; } break; case reproduction_elastic: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { double x,y,ux,uy; x = pt.x(); y = pt.y(); ux = -t*t*std::cos(M_PI*y)*std::sin(M_PI*x); uy = t*t*std::cos(M_PI*x)*std::sin(M_PI*y); - static_vector u{ux,uy}; + disk::static_vector u{ux,uy}; return u; }; } break; case EFunctionNonPolynomial_paper: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { double x,y,ux,uy, w, theta; x = pt.x(); y = pt.y(); @@ -97,7 +97,7 @@ class scal_vec_analytic_functions { // theta = std::sqrt(2)*M_PI; ux = x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); uy = x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); - static_vector u{ux,uy}; + disk::static_vector u{ux,uy}; return u; }; } @@ -107,8 +107,8 @@ class scal_vec_analytic_functions { default: { std::cout << " Function not implemented " << std::endl; return [](const typename disk::generic_mesh::point_type& pt) - -> static_vector { - static_vector u; + -> disk::static_vector { + disk::static_vector u; return u; }; } @@ -117,20 +117,20 @@ class scal_vec_analytic_functions { } - std::function + std::function (const typename disk::generic_mesh::point_type& )> Evaluate_v(double & t){ switch (m_function_type) { case EFunctionNonPolynomial: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,vx,vy; x = pt.x(); y = pt.y(); vx = -(std::sqrt(2.0)*M_PI*x*x*std::cos((M_PI*x)/2.)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*y)); vy = -(std::sqrt(2.0)*M_PI*x*x*std::cos((M_PI*x)/2.)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*y)); - static_vector v{vx,vy}; + disk::static_vector v{vx,vy}; return v; }; } @@ -138,13 +138,13 @@ class scal_vec_analytic_functions { case EFunctionQuadraticInTime: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,vx,vy; x = pt.x(); y = pt.y(); vx = 2.0*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); vy = 2.0*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); - static_vector v{vx,vy}; + disk::static_vector v{vx,vy}; return v; }; } @@ -152,33 +152,33 @@ class scal_vec_analytic_functions { case EFunctionQuadraticInSpace: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,vx,vy; x = pt.x(); y = pt.y(); vx = std::sqrt(2.0)*M_PI*(1 + x)*x*x*(1 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); vy = std::sqrt(2.0)*M_PI*(1 + x)*x*x*(1 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); - static_vector v{vx,vy}; + disk::static_vector v{vx,vy}; return v; }; } break; case reproduction_elastic:{ - return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { double x,y,vx,vy; x = pt.x(); y = pt.y(); vx = -2*t*std::cos(M_PI*y)*std::sin(M_PI*x); vy = 2*t*std::cos(M_PI*x)*std::sin(M_PI*y); - static_vector v{vx,vy}; + disk::static_vector v{vx,vy}; return v; }; } break; case EFunctionNonPolynomial_paper:{ - return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { double x,y,vx,vy,w,theta; x = pt.x(); y = pt.y(); @@ -188,7 +188,7 @@ break; // theta = std::sqrt(2)*M_PI; vx = -(theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos((M_PI*w*x)/2.)); vy = -(theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos((M_PI*w*x)/2.)); - static_vector v{vx,vy}; + disk::static_vector v{vx,vy}; return v; }; } @@ -198,11 +198,11 @@ break; default: { std::cout << " Function not implemented " << std::endl; return [](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y; x = pt.x(); y = pt.y(); - static_vector v; + disk::static_vector v; return v; }; } @@ -212,20 +212,20 @@ break; } - std::function + std::function (const typename disk::generic_mesh::point_type& )> Evaluate_a(double & t){ switch (m_function_type) { case EFunctionNonPolynomial: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,ax,ay; x = pt.x(); y = pt.y(); ax = -2*M_PI*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y); ay = -2*M_PI*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y); - static_vector a{ax,ay}; + disk::static_vector a{ax,ay}; return a; }; } @@ -233,13 +233,13 @@ break; case EFunctionQuadraticInTime: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,ax,ay; x = pt.x(); y = pt.y(); ax = 2.0*x*std::sin(M_PI*x)*std::sin(M_PI*y); ay = 2.0*x*std::sin(M_PI*x)*std::sin(M_PI*y); - static_vector a{ax,ay}; + disk::static_vector a{ax,ay}; return a; }; } @@ -247,26 +247,26 @@ break; case EFunctionQuadraticInSpace: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,ax,ay; x = pt.x(); y = pt.y(); ax = -2*M_PI*M_PI*(1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); ay = -2*M_PI*M_PI*(1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); - static_vector a{ax,ay}; + disk::static_vector a{ax,ay}; return a; }; } break; case reproduction_elastic:{ - return [](const typename disk::generic_mesh::point_type& pt) -> static_vector { + return [](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { double x,y,ax,ay; x = pt.x(); y = pt.y(); ax = -2*std::cos(M_PI*y)*std::sin(M_PI*x); ay = 2*std::cos(M_PI*x)*std::sin(M_PI*y); - static_vector a{ax,ay}; + disk::static_vector a{ax,ay}; return a; }; } @@ -274,7 +274,7 @@ break; case EFunctionNonPolynomial_paper: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,ax,ay,w,theta; x = pt.x(); y = pt.y(); @@ -284,7 +284,7 @@ break; // theta = std::sqrt(2)*M_PI; ax = -theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); ay = -theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); - static_vector a{ax,ay}; + disk::static_vector a{ax,ay}; return a; }; } @@ -293,8 +293,8 @@ break; default: { std::cout << " Function not implemented " << std::endl; return [](const typename disk::generic_mesh::point_type& pt) - -> static_vector { - static_vector f; + -> disk::static_vector { + disk::static_vector f; return f; }; } @@ -304,20 +304,20 @@ break; } - std::function + std::function (const typename disk::generic_mesh::point_type& )> Evaluate_f(double & t){ switch (m_function_type) { case EFunctionNonPolynomial: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,fx,fy; x = pt.x(); y = pt.y(); fx = -(std::cos(std::sqrt(2.0)*M_PI*t)*(-4*M_PI*x*std::sin((M_PI*x)/2.)*(M_PI*x*std::cos(M_PI*y) + 6*std::sin(M_PI*y)) + std::cos((M_PI*x)/2.)*(16*M_PI*x*std::cos(M_PI*y) + (24 + M_PI*M_PI*x*x)*std::sin(M_PI*y))))/4.0; fy = (std::cos(std::sqrt(2.0)*M_PI*t)*(4*M_PI*x*std::sin((M_PI*x)/2.)*(M_PI*x*std::cos(M_PI*y) + 2*std::sin(M_PI*y)) + std::cos((M_PI*x)/2.)*(-16*M_PI*x*std::cos(M_PI*y) + (-8 + 5*M_PI*M_PI*x*x)*std::sin(M_PI*y))))/4.; - static_vector f{fx,fy}; + disk::static_vector f{fx,fy}; return f; }; } @@ -325,7 +325,7 @@ break; case EFunctionQuadraticInTime: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,fx,fy; x = pt.x(); y = pt.y(); @@ -333,7 +333,7 @@ break; std::sin(M_PI*x)*(M_PI*t*t*std::cos(M_PI*y) - (1+2*M_PI*M_PI*t*t)*x*std::sin(M_PI*y))); fy = (1 + M_PI*M_PI*t*t)*x*std::cos(M_PI*(x - y)) - (1+3*M_PI*M_PI*t*t)*x*std::cos(M_PI*(x+y)) - 2*M_PI*t*t*std::sin(M_PI*(x+y)); - static_vector f{fx,fy}; + disk::static_vector f{fx,fy}; return f; }; } @@ -341,7 +341,7 @@ break; case EFunctionQuadraticInSpace: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,fx,fy; x = pt.x(); y = pt.y(); @@ -349,20 +349,20 @@ break; + (3+x*(9+M_PI*M_PI*x*(1+x)))*y*y)*std::sin(std::sqrt(2.0)*M_PI*t); fy = 2 * ( x*x*(6 + M_PI*M_PI*(-1 + y))*y + (-1 + y)*y + x*x*x*(3 + M_PI*M_PI*(-1 + y)*y) + x*(-2 + y + 3*y*y))*std::sin(std::sqrt(2.0)*M_PI*t); - static_vector f{fx,fy}; + disk::static_vector f{fx,fy}; return f; }; } break; case reproduction_elastic: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { double x,y,fx,fy; x = pt.x(); y = pt.y(); fx = -2*(1 + M_PI*M_PI*t*t)*std::cos(M_PI*y)*std::sin(M_PI*x); fy = 2*(1 + M_PI*M_PI*t*t)*std::cos(M_PI*x)*std::sin(M_PI*y); - static_vector f{fx,fy}; + disk::static_vector f{fx,fy}; return f; }; } @@ -370,7 +370,7 @@ break; case EFunctionNonPolynomial_paper: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,fx,fy,w,theta; x = pt.x(); y = pt.y(); @@ -392,7 +392,7 @@ break; + 2*M_PI*w*x*std::sin(M_PI*w*x/2)*std::sin(M_PI*w*y)*std::cos(theta*t) - 4*M_PI*w*x*std::cos(theta*t)*std::cos(M_PI*w*x/2)*std::cos(M_PI*w*y) - 2*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2); - static_vector f{fx,fy}; + disk::static_vector f{fx,fy}; return f; }; } @@ -402,8 +402,8 @@ break; { std::cout << " Function not implemented " << std::endl; return [](const typename disk::generic_mesh::point_type& pt) - -> static_vector { - static_vector f; + -> disk::static_vector { + disk::static_vector f; return f; }; } @@ -413,18 +413,18 @@ break; } - std::function + std::function (const typename disk::generic_mesh::point_type& )> Evaluate_sigma(double & t){ switch (m_function_type) { case EFunctionNonPolynomial: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_matrix { + -> disk::static_matrix { double x,y; x = pt.x(); y = pt.y(); - static_matrix sigma = static_matrix::Zero(2,2); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); sigma(0,0) = M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::cos(M_PI*y) + 4*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y) + (4*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y))/2.0; @@ -442,11 +442,11 @@ break; case EFunctionQuadraticInTime: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_matrix { + -> disk::static_matrix { double x,y; x = pt.x(); y = pt.y(); - static_matrix sigma = static_matrix::Zero(2,2); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); sigma(0,0) = t*t*(M_PI*x*std::cos(M_PI*y)*std::sin(M_PI*x) + 3*(M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y)); @@ -464,11 +464,11 @@ break; case EFunctionQuadraticInSpace: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_matrix { + -> disk::static_matrix { double x,y; x = pt.x(); y = pt.y(); - static_matrix sigma = static_matrix::Zero(2,2); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); sigma(0,0) = 2*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + 4*x*(1+x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + (2*x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) @@ -496,11 +496,11 @@ break; case reproduction_elastic: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> static_matrix { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_matrix { double x,y; x = pt.x(); y = pt.y(); - static_matrix sigma = static_matrix::Zero(2,2); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); sigma(0,0) = -2*M_PI*t*t*std::cos(M_PI*x)*std::cos(M_PI*y); sigma(1,1) = 2*M_PI*t*t*std::cos(M_PI*x)*std::cos(M_PI*y); return sigma; @@ -510,7 +510,7 @@ break; case EFunctionNonPolynomial_paper: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_matrix { + -> disk::static_matrix { double x,y,w,theta; x = pt.x(); y = pt.y(); @@ -520,7 +520,7 @@ break; // w = 5.0; // theta = std::sqrt(2)*M_PI; - static_matrix sigma = static_matrix::Zero(2,2); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); sigma(0,0) = - 3.0*M_PI*w*x*x*std::sin(M_PI*w*x/2.0)*std::sin(M_PI*w*y)*std::cos(theta*t)/2.0 + M_PI*w*x*x*std::cos(theta*t)*std::cos(M_PI*w*x/2.0)*std::cos(M_PI*w*y) + 6.0*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0); @@ -542,8 +542,8 @@ break; default: { std::cout << " Function not implemented " << std::endl; return [](const typename disk::generic_mesh::point_type& pt) - -> static_matrix { - static_matrix sigma(2,2); + -> disk::static_matrix { + disk::static_matrix sigma(2,2); return sigma; }; } @@ -838,19 +838,19 @@ break; } - std::function + std::function (const typename disk::generic_mesh::point_type& )> Evaluate_s_q(double & t){ switch (m_function_type) { case EFunctionNonPolynomial: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,qx,qy; x = pt.x(); y = pt.y(); qx = M_PI*x*x*std::cos(M_PI*x)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*y) + 2*x*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); qy = M_PI*x*x*std::cos(M_PI*y)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x); - static_vector q{qx,qy}; + disk::static_vector q{qx,qy}; return q; }; } @@ -858,14 +858,14 @@ break; case EFunctionQuadraticInTime: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,qx,qy; x = pt.x(); y = pt.y(); std::vector flux(2); qx = M_PI*t*t*x*std::cos(M_PI*x)*std::sin(M_PI*y) + t*t*std::sin(M_PI*x)*std::sin(M_PI*y); qy = M_PI*t*t*x*std::cos(M_PI*y)*std::sin(M_PI*x); - static_vector q{qx,qy}; + disk::static_vector q{qx,qy}; return q; }; } @@ -873,7 +873,7 @@ break; case EFunctionQuadraticInSpace: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,qx,qy; x = pt.x(); y = pt.y(); @@ -882,20 +882,20 @@ break; - x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); qy = (1 - x)*x*x*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) - (1 - x)*x*x*y*std::sin(std::sqrt(2.0)*M_PI*t); - static_vector q{qx,qy}; + disk::static_vector q{qx,qy}; return q; }; } break; case reproduction_acoustic: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> static_vector { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { double x,y,qx,qy; x = pt.x(); y = pt.y(); qx = M_PI*t*t*std::cos(M_PI*x)*std::sin(M_PI*y); qy = M_PI*t*t*std::sin(M_PI*x)*std::cos(M_PI*y); - static_vector q{qx,qy}; + disk::static_vector q{qx,qy}; return q; }; } @@ -903,7 +903,7 @@ break; case EFunctionNonPolynomial_paper: { return [&t](const typename disk::generic_mesh::point_type& pt) - -> static_vector { + -> disk::static_vector { double x,y,qx,qy,w,theta; x = pt.x(); y = pt.y(); @@ -913,7 +913,7 @@ break; // theta = std::sqrt(2)*M_PI; qx = M_PI*theta*w*x*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos(M_PI*w*x)/theta + 2*theta*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)/theta; qy = M_PI*theta*w*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::cos(M_PI*w*y)/theta; - static_vector q{qx,qy}; + disk::static_vector q{qx,qy}; return q; }; } @@ -922,8 +922,8 @@ break; default: { std::cout << " Function not implemented " << std::endl; return [](const typename disk::generic_mesh::point_type& pt) - -> static_vector{ - static_vector f{0,0}; + -> disk::static_vector{ + disk::static_vector f{0,0}; return f; }; } diff --git a/apps/wave_propagation/src/prototypes/acoustic/AcousticIHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/acoustic/AcousticIHHOFirstOrder.hpp new file mode 100644 index 00000000..ee7faac6 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustic/AcousticIHHOFirstOrder.hpp @@ -0,0 +1,306 @@ + + +// Created by Romain Mottier + +void AcousticIHHOFirstOrder(int argc, char **argv); + +void AcousticIHHOFirstOrder(int argc, char **argv){ + + // ###################################################################### Simulation paramaters + // ###################################################################### + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit; + + // ###################################################################### Mesh generation + // ###################################################################### + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + Mesh_generation(sim_data, msh); + + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.5; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ###################################################################### Assigning Material Data + // ###################################################################### + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + + // Detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ###################################################################### Solving a primal HHO mixed problem + // ###################################################################### + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + + // Stabilization type + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + // ###################################################################### Projecting initial data + // ###################################################################### + + Matrix x_dof; + // Acoustic pulse intialized in pressure + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, vel_fun, null_fun); + assembler.project_over_faces(msh, x_dof, null_fun, vel_fun); + + ////////// Post process of the initial data + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "elasto_acoustic_inhomogeneous_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + std::ofstream simulation_log("elasto_acoustic_inhomogeneous_four_fields.txt"); + std::ofstream energy_file("energy_file.txt"); + std::ofstream dissipation_file("dissipation_file.txt"); + + std::ofstream Acoustic_sensor_1_log("Acoustic_s1_four_fields_h.csv"); + std::ofstream Acoustic_sensor_2_log("Acoustic_s2_four_fields_h.csv"); + std::ofstream Acoustic_sensor_3_log("Acoustic_s3_four_fields_h.csv"); + std::ofstream Acoustic_sensor_4_log("Acoustic_s4_four_fields_h.csv"); + bool e_side_Q = true; + bool a_side_Q = false; + typename mesh_type::point_type Acoustic_s1_pt(-0.10, 0.25); + typename mesh_type::point_type Acoustic_s2_pt(-0.10, 0.00); + typename mesh_type::point_type Acoustic_s3_pt(-0.10,-0.25); + std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); + std::pair Acoustic_s2_pt_cell = std::make_pair(Acoustic_s2_pt, -1); + std::pair Acoustic_s3_pt_cell = std::make_pair(Acoustic_s3_pt, -1); + std::cout << bold << cyan << " " << "Acoustic sensor at (-0.1,0.25)" << reset << std::endl; + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + std::cout << bold << cyan << " " << "Acoustic sensor at (-0.1,0.0)" << reset << std::endl; + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); + std::cout << bold << cyan << " " << "Acoustic sensor at (-0.1,0.25)" << reset << std::endl; + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s3_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + postprocessor::compute_elasto_acoustic_dissipation_four_field(assembler, t, x_dof, dissipation_file); + } + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + } + else { + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + std::cout << std::endl << std::endl; + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + dirk_an.set_static_condensation_data(vec_cell_basis_data, assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + std::cout << bold << cyan << " Matrix decomposed: "; + tc.tic(); + dirk_an.ComposeMatrix(); + // dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + } + + // ################################################## + // ################################################## Time marching + // ################################################## + + std::cout << std::endl << std::endl; + + Matrix x_dof_n; + + for(size_t it = 1; it <= nt; it++) { + + + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t + << reset; + + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + t = tn + c(i,0) * dt; + assembler.RHS.setZero(); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + // std::cout << std::endl << bold << cyan << " DIRK step completed: " << tc << " seconds" + // << reset << std::endl; + + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "elasto_acoustic_inhomogeneous_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Acoustic_sensor_1_log); + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Acoustic_sensor_2_log); + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Acoustic_sensor_3_log); + + t += dt; + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, + t, x_dof, energy_file); + postprocessor::compute_elasto_acoustic_dissipation_four_field(assembler, t, x_dof, dissipation_file); + } + + std::cout << std::endl; + tcit.toc(); + std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + + + } + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of equations: " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Number of DIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_CFL.hpp b/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_CFL.hpp new file mode 100644 index 00000000..942f8885 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_CFL.hpp @@ -0,0 +1,398 @@ + + +// Created by Romain Mottier +// ../wave_propagation -k 2 -s 0 -r 0 -c 1 -p 0 -l 2 -n 300 -f 0 -e 0 + +void EAcoustic_CFL(int argc, char **argv); + +void EAcoustic_CFL(int argc, char **argv){ + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " ACOUSTIC CFL" << std::endl << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc; + + // ################################################## + // ################################################## Time controls + // ################################################## + + RealType ti = 0.0; + RealType tf = 1.0; + RealType t = ti; + int nt_base = sim_data.m_nt_divs; + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial_paper); + + // Zero source terms, to keep the system energy constant + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + // Acoustic analytical functions + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ################################################## + // ################################################## HHO setting + // ################################################## + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if (sim_data.m_hdg_stabilization_Q) { + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l0_conv_test_1.0.txt"); // l = 0 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l1_conv_test_0.35.txt"); // + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l2_conv_test_0.15.txt"); // l = 2 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l3_conv_test_0.07.txt"); // + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l4_conv_test_0.035.txt"); // l = 4 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l5_conv_test_0.026.txt"); // + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l6_conv_test_0.017.txt"); // l = 6 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l7_conv_test_0.0125.txt"); // + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l8_conv_test_0.0085.txt"); // l = 8 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l9_conv_test_0.005.txt"); // + + mesh_files.push_back("../../meshes/conv_test/poly/poly_32.txt"); + mesh_files.push_back("../../meshes/conv_test/poly/poly_64.txt"); // -l 1 + mesh_files.push_back("../../meshes/conv_test/poly/poly_128.txt"); + mesh_files.push_back("../../meshes/conv_test/poly/poly_256.txt"); // -l 3 + mesh_files.push_back("../../meshes/conv_test/poly/poly_512.txt"); + mesh_files.push_back("../../meshes/conv_test/poly/poly_1024.txt"); // -l 5 + mesh_files.push_back("../../meshes/conv_test/poly/poly_2048.txt"); + mesh_files.push_back("../../meshes/conv_test/poly/poly_4096.txt"); // -l 7 + mesh_files.push_back("../../meshes/conv_test/poly/poly_8192.txt"); + mesh_files.push_back("../../meshes/conv_test/poly/poly_16384.txt"); // -l 9 + mesh_files.push_back("../../meshes/conv_test/poly/poly_32768.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl << std::endl; + + // ################################################## + // ################################################## Material data + // ################################################## + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ################################################## + // ################################################## Interface detection and faces repartitions + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + RealType eps = 1.0e-10; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) + interface_cell_pair_indexes[fc_id].second = cell_ind; + } + } + + + // Internal faces structure for explicit schemes + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + } + else { + acoustic_internal_faces.insert(fc_id); + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + + // boundary condition + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ######################s########################### + + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if (sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + assembler.assemble_mass(msh); + assembler.assemble_coupling_terms(msh); + + // ################################################## + // ################################################## Setting of the time marching scheme + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, null_fun); + assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + bool explicit_scheme = true; + assembler.assemble(msh, null_fun, null_s_fun, explicit_scheme); + size_t elastic_cell_dofs = 0.0; + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = 0.0; + size_t a_face_dofs = assembler.get_a_face_dof(); + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes); + erk_an.refresh_faces_unknowns(x_dof); + + // ################################################## + // ################################################## Loop over the ERK schemes + // ################################################## + + for (int s = 2; s < 5; s++) { + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + // nt *= 2; + nt = sim_data.m_nt_divs; + } + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "A_explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + auto block_dimension = assembler.Scc_block_dimension(); + // erk_an.compute_eigenvalues_bis(assembler.LHS_STAB, block_dimension, simulation_log); + // erk_an.compute_eigenvalues(simulation_log); + simulation_log.flush(); + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + auto energy_0 = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + std::cout << bold << red << " ERK(" << s << "):" << reset << std::endl << std::endl; + simulation_log << std::endl << " ERK(" << s << "):" << std::endl; + simulation_log << std::endl; + + // ################################################## + // ################################################## Loop over level of time refinement + // ################################################## + + for (unsigned int i = 0; i < 100; i++) { + + t = ti; + RealType dt = (tf-ti)/nt; + simulation_log << "Step size = " << dt << std::endl; + + // Projecting initial data + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, null_fun, s_v_fun); + + auto energy_0 = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + erk_butcher_tableau::erk_tables(s, a, b, c); + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + bool approx_fail_check_Q = false; + RealType energy = energy_0; + + for(size_t it = 1; it <= nt; it++) { + + RealType tn = dt*(it-1)+ti; + + // ERK steps + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + Matrix yn, ki; + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + RealType t = tn + c(i,0) * dt; + assembler.assemble_rhs(msh, null_fun, null_s_fun, true); + erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + x_dof = x_dof_n; + t = tn + dt; + RealType energy_n = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + RealType relative_energy = (energy_n - energy) / energy; + RealType relative_energy_0 = (energy_n - energy_0) / energy_0; + bool unstable_check_Q = (relative_energy > 500e-2) || (relative_energy_0 >= 50e-2); + // bool unstable_check_Q = (relative_energy_0 >= 7.5e-2); + if (unstable_check_Q) { // energy is increasing + approx_fail_check_Q = true; + break; + } + energy = energy_n; + } + + if (approx_fail_check_Q) { + std::cout << bold << red << " Simulation is unstable" << reset << std::endl << std::endl << std::endl; + simulation_log << std::endl; + simulation_log << " Simulation is unstable for:"<< std::endl; + simulation_log << " Number of equations: " << assembler.RHS.rows() << std::endl; + simulation_log << " Number of ERK steps = " << s << std::endl; + simulation_log << " Number of time steps = " << nt << std::endl; + simulation_log << " dt size = " << dt << std::endl; + simulation_log << " h size = " << h << std::endl; + simulation_log << " CFL c(dt/h) = " << dt/h << std::endl; + simulation_log << std::endl; + simulation_log.flush(); + break; + } + else { + simulation_log << " Simulation is stable for:"<< std::endl; + simulation_log << " Number of equations: " << assembler.RHS.rows() << std::endl; + simulation_log << " Number of ERK steps = " << s << std::endl; + simulation_log << " Number of time steps = " << nt << std::endl; + simulation_log << " dt size = " << dt << std::endl; + simulation_log << " h size = " << h << std::endl; + simulation_log << " CFL c(dt/h) = " << dt/h << std::endl; + simulation_log << std::endl; + simulation_log.flush(); + std::cout << " Simulation is stable for: n = " << nt << std::endl; + nt = int(nt - (nt*1/100+1)); + continue; + // break; + } + } + simulation_log << std::endl << " ******************************* " << std::endl; + simulation_log << std::endl << std::endl; + } +} + + diff --git a/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_stability.hpp b/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_stability.hpp new file mode 100644 index 00000000..752b4d1a --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_stability.hpp @@ -0,0 +1,379 @@ + +// Created by Romain Mottier + +void EAcoustic_stability(int argc, char **argv); + +void EAcoustic_stability(int argc, char **argv){ + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " ACOUSTIC STABILITY" << reset << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, cpu; + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + cpu.tic(); + tc.tic(); + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l0_conv_test_1.0.txt"); // l = 0 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l1_conv_test_0.35.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l2_conv_test_0.15.txt"); // l = 2 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l3_conv_test_0.07.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l4_conv_test_0.035.txt"); // l = 4 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l5_conv_test_0.026.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l6_conv_test_0.017.txt"); // l = 6 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l7_conv_test_0.0125.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l8_conv_test_0.0085.txt"); // l = 8 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l9_conv_test_0.005.txt"); // + + // mesh_files.push_back("../../meshes/conv_test/poly/poly_32.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_64.txt"); // -l 1 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_128.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_256.txt"); // -l 3 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_512.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_1024.txt"); // -l 5 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_2048.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_4096.txt"); // -l 7 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_8192.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_16384.txt"); // -l 9 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_32768.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl << std::endl; + + // ################################################## + // ################################################## Time controls + // ################################################## + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + // nt *= 2; + nt = sim_data.m_nt_divs; + } + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial_paper); + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + // Acoustic analytical functions + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ################################################## + // ################################################## HHO setting + // ################################################## + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if (sim_data.m_hdg_stabilization_Q) { + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ################################################## + // ################################################## Structure setting + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + + // Internal faces structure (for explicit schemes) + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + } + + // boundary conditions + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ################################################## + // ################################################## Projecting initial data + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, null_fun, s_v_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // ERK(s) schemes + int s = 4; + erk_butcher_tableau::erk_tables(s, a, b, c); + + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, true); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + + size_t elastic_cell_dofs = 0.0; //assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = 0.0; //assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes);//assembler.get_interfaces()); + + tc.toc(); + std::cout << bold << cyan << " ERK analysis created: " << tc << " seconds" << reset << std::endl; + tc.tic(); + erk_an.refresh_faces_unknowns(x_dof); + tc.toc(); + std::cout << bold << cyan << " Inverse of Sff + Coupling in: " << tc << " seconds" << reset << std::endl; + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "A_explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + // auto block_dimension = assembler.Scc_block_dimension(); + // erk_an.compute_eigenvalues_bis(assembler.LHS_STAB, block_dimension, simulation_log); + erk_an.compute_eigenvalues(simulation_log); + simulation_log.flush(); + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + auto energy_0 = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + bool approx_fail_check_Q = false; + RealType energy = energy_0; + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << red << " Time step number " << it << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + x_dof_n = x_dof; + + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + t = tn + c(i,0) * dt; + { + assembler.assemble_rhs(msh, null_fun, null_s_fun, true); + erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + } + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + + tc.toc(); + std::cout << bold << cyan << " ERK step completed: " << tc << " seconds" << reset; + x_dof = x_dof_n; + + t = tn + dt; + + // Energy evaluation + RealType energy_n = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + RealType relative_energy = (energy_n - energy) / energy; + RealType relative_energy_0 = (energy_n - energy_0) / energy_0; + bool unstable_check_Q = (relative_energy > 1.0e-2) || (relative_energy_0 >= 1.0e-2); + if (unstable_check_Q) { + std::cout << std::endl << std::endl << bold << red << " Simulation is unstable" << reset << std::endl; + break; + } + energy = energy_n; + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << std::endl << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + diff --git a/apps/wave_propagation/src/prototypes/acoustic/IAcoustic_conv_test.hpp b/apps/wave_propagation/src/prototypes/acoustic/IAcoustic_conv_test.hpp new file mode 100644 index 00000000..c469a10a --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustic/IAcoustic_conv_test.hpp @@ -0,0 +1,391 @@ + + +// Created by Romain Mottier + +void IAcoustic_conv_test(int argc, char **argv); + +void IAcoustic_conv_test(int argc, char **argv){ + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " IMPLICIT ACOUSTIC CONV TEST" << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, cpu; + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + cpu.tic(); + tc.tic(); + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l0_conv_test_1.0.txt"); // l = 0 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l1_conv_test_0.35.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l2_conv_test_0.15.txt"); // l = 2 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l3_conv_test_0.07.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l4_conv_test_0.035.txt"); // l = 4 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l5_conv_test_0.026.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l6_conv_test_0.017.txt"); // l = 6 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l7_conv_test_0.0125.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l8_conv_test_0.0085.txt"); // l = 8 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l9_conv_test_0.005.txt"); // + + // mesh_files.push_back("../../meshes/conv_test/poly/poly_32.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_64.txt"); // -l 1 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_128.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_256.txt"); // -l 3 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_512.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_1024.txt"); // -l 5 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_2048.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_4096.txt"); // -l 7 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_8192.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_16384.txt"); // -l 9 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_32768.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ################################################## + // ################################################## Time controls + // ################################################## + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + // nt = sim_data.m_nt_divs; + } + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + //functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + //functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + //functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::reproduction_acoustic); + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + // Acoustic analytical functions + auto s_u_fun = functions.Evaluate_s_u(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_a_fun = functions.Evaluate_s_a(t); + auto s_f_fun = functions.Evaluate_s_f(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ################################################## + // ################################################## HHO setting + // ################################################## + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ################################################## + // ################################################## Structure setting + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + + // boundary conditions + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, s_u_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ################################################## + // ################################################## Projecting initial data + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, null_fun, s_v_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 2; + bool is_sdirk_Q = true; + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + } + else { + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, s_f_fun, false); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + dirk_an.set_static_condensation_data(vec_cell_basis_data, assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + std::cout << bold << cyan << " Matrix decomposed: "; + tc.tic(); + dirk_an.ComposeMatrix(); + bool iteratif_solver = false; // if false load library: /opt/intel/oneapi/setvars.sh intel64 + if (iteratif_solver) { + dirk_an.setIterativeSolver(); + } + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + } + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "A_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of SDIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + + std::ostringstream filename_e; + filename_e << "A_energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + } + std::cout << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << red << " Time step number " << it << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + t = tn + c(i,0) * dt; + // Manufactured solution + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_f_fun = functions.Evaluate_s_f(t); + + assembler.get_a_bc_conditions().updateDirichletFunction(s_v_fun, 0); + assembler.assemble_rhs(msh, null_fun, s_f_fun, false); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + + tc.toc(); + std::cout << bold << cyan << " DIRK step completed: " << tc << " seconds" << reset << std::endl << std::endl; + x_dof = x_dof_n; + t = tn + dt; + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + if(it == nt){ + // Computing errors + postprocessor::compute_errors_four_fields_elastoacoustic(msh, hho_di, assembler, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun, simulation_log); + std::cout << std::endl; + } + + } + + bool mesh_quality = false; + if (mesh_quality) { + std::ostringstream mesh_file_name; + mesh_file_name << "mesh_quality_l" << sim_data.m_n_divs << ".txt"; + std::string mesh_file_str = mesh_file_name.str(); + std::ofstream mesh_file(mesh_file_str); + postprocessor::mesh_quality(msh, assembler, mesh_file); + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/CMakeLists.txt b/apps/wave_propagation/src/prototypes/acoustics_old/CMakeLists.txt new file mode 100644 index 00000000..5e99fa2c --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(input_files ${input_files} + ${CMAKE_CURRENT_SOURCE_DIR}/input_files/elliptic_convergence_test.lua + ${CMAKE_CURRENT_SOURCE_DIR}/input_files/acoustics_test.lua + ${CMAKE_CURRENT_SOURCE_DIR}/input_files/acoustics_simulation.lua + ${CMAKE_CURRENT_SOURCE_DIR}/input_files/acoustics_simulation_2d_pulse.lua +) + +file(COPY ${input_files} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug/input_files/) +file(COPY ${input_files} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Release/input_files/) + +file(COPY ${input_poly_meshes} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/meshes/) +file(COPY ${input_poly_meshes} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug/meshes/) +file(COPY ${input_poly_meshes} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Release/meshes/) + +add_executable(acoustics acoustics.cpp ${fitted_waves_headers} ${fitted_waves_sources}) +target_link_libraries(acoustics ${LINK_LIBS}) diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/EHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/EHHOFirstOrder.hpp new file mode 100644 index 00000000..dbd0210b --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/EHHOFirstOrder.hpp @@ -0,0 +1,233 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef EHHOFirstOrder_hpp +#define EHHOFirstOrder_hpp + +void EHHOFirstOrder(char **argv){ + + simulation_data sim_data = preprocessor::process_acoustics_lua_file(argv); + sim_data.print_simulation_data(); + + ///////////////////////////////////////////////////////////////////////// + ////////////////////////// Meshes /////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + if (sim_data.m_polygonal_mesh_Q) { + if (sim_data.m_n_divs > 8) { + sim_data.m_n_divs = 8; + } + } + + mesh_type msh; + if (sim_data.m_polygonal_mesh_Q) { + size_t l = sim_data.m_n_divs; + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + mesh_files.push_back("meshes/unit_square_polymesh_nel_20.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_40.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_80.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_160.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_320.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_640.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_1280.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_2560.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_5120.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + }else{ + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + + scal_analytic_functions functions; + switch (sim_data.m_exact_functions) { + case 1: + functions.set_function_type(scal_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + break; + case 2: + functions.set_function_type(scal_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + break; + default: + functions.set_function_type(scal_analytic_functions::EFunctionType::EFunctionNonPolynomial); + break; + } + + RealType t = ti; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_q(t); + auto rhs_fun = functions.Evaluate_f(t); + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_vel_fun); + tc.tic(); + auto assembler = acoustic_two_fields_assembler(msh, hho_di, bnd); + assembler.load_material_data(msh); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, exact_vel_fun, exact_flux_fun); + assembler.project_over_faces(msh, x_dof, exact_vel_fun); + + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "e_scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + std::ofstream simulation_log("acoustic_two_fields_explicit.txt"); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + int s = 4; + Matrix a; + Matrix b; + Matrix c; + erk_butcher_tableau::erk_tables(s, a, b, c); + + tc.tic(); + assembler.assemble(msh, rhs_fun); + tc.toc(); + std::cout << bold << cyan << "Stiffness and rhs assembly completed: " << tc << " seconds" << reset << std::endl; + size_t n_face_dof = assembler.get_n_face_dof(); + tc.tic(); + erk_hho_scheme erk_an(assembler.LHS,assembler.RHS,assembler.MASS,n_face_dof); + erk_an.Kcc_inverse(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + if(sim_data.m_hdg_stabilization_Q){ + erk_an.Sff_inverse(std::make_pair(assembler.get_n_faces(), assembler.get_face_basis_data())); + }else{ + if (sim_data.m_iterative_solver_Q) { + erk_an.setIterativeSolver(); + } + erk_an.DecomposeFaceTerm(); + } + tc.toc(); + std::cout << bold << cyan << "ERK analysis created: " << tc << " seconds" << reset << std::endl; + + erk_an.refresh_faces_unknowns(x_dof); + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + RealType tn = dt*(it-1)+ti; + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + { + RealType t = tn + c(i,0) * dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto rhs_fun = functions.Evaluate_f(t); + assembler.get_bc_conditions().updateDirichletFunction(exact_vel_fun, 0); + assembler.assemble_rhs(msh, rhs_fun); + assembler.apply_bc(msh); + erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + } + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "ERK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + t = tn + dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_q(t); + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "e_scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + if(it == nt){ + // Computing errors + postprocessor::compute_errors_two_fields(msh, hho_di, assembler, x_dof, exact_vel_fun, exact_flux_fun,simulation_log); + } + } + + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/IHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/IHHOFirstOrder.hpp new file mode 100644 index 00000000..3c877770 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/IHHOFirstOrder.hpp @@ -0,0 +1,249 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef IHHOFirstOrder_hpp +#define IHHOFirstOrder_hpp + +void IHHOFirstOrder(char **argv){ + + simulation_data sim_data = preprocessor::process_acoustics_lua_file(argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + if (sim_data.m_polygonal_mesh_Q) { + if (sim_data.m_n_divs > 8) { + sim_data.m_n_divs = 8; + } + } + + mesh_type msh; + if (sim_data.m_polygonal_mesh_Q) { + size_t l = sim_data.m_n_divs; + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + mesh_files.push_back("meshes/unit_square_polymesh_nel_20.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_40.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_80.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_160.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_320.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_640.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_1280.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_2560.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_5120.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + }else{ + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + + scal_analytic_functions functions; + switch (sim_data.m_exact_functions) { + case 1: + functions.set_function_type(scal_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + break; + case 2: + functions.set_function_type(scal_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + break; + default: + functions.set_function_type(scal_analytic_functions::EFunctionType::EFunctionNonPolynomial); + break; + } + + RealType t = ti; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_q(t); + auto rhs_fun = functions.Evaluate_f(t); + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_vel_fun); + tc.tic(); + auto assembler = acoustic_two_fields_assembler(msh, hho_di, bnd); + + // simple material + RealType rho = 1.0; + RealType vp = 1.0; + acoustic_material_data material(rho,vp); + assembler.load_material_data(msh,material); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, exact_vel_fun, exact_flux_fun); + assembler.project_over_faces(msh, x_dof, exact_vel_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + std::ofstream simulation_log("acoustic_two_fields.txt"); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + }else{ + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + tc.tic(); + assembler.assemble(msh, rhs_fun); + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + dirk_an.set_static_condensation_data(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data()), assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + // SDIRK case + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + tc.tic(); + dirk_an.ComposeMatrix(); + + if (sim_data.m_iterative_solver_Q) { + dirk_an.setIterativeSolver(); + } + + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << "Matrix decomposed: " << tc << " seconds" << reset << std::endl; + }else{ + // DIRK case + if (sim_data.m_iterative_solver_Q) { + dirk_an.setIterativeSolver(); + } + } + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + { + RealType t = tn + c(i,0) * dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto rhs_fun = functions.Evaluate_f(t); + assembler.get_bc_conditions().updateDirichletFunction(exact_vel_fun, 0); + assembler.assemble_rhs(msh, rhs_fun); + assembler.apply_bc(msh); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + } + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "DIRK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + t = tn + dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_q(t); + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + if(it == nt){ + // Computing errors + postprocessor::compute_errors_two_fields(msh, hho_di, assembler, x_dof, exact_vel_fun, exact_flux_fun,simulation_log); + } + + } + + simulation_log << "Number of equations : " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Number of DIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/IHHOSecondOrder.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/IHHOSecondOrder.hpp new file mode 100644 index 00000000..af7d49ef --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/IHHOSecondOrder.hpp @@ -0,0 +1,222 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef IHHOSecondOrder_hpp +#define IHHOSecondOrder_hpp + +void IHHOSecondOrder(char **argv){ + + simulation_data sim_data = preprocessor::process_acoustics_lua_file(argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + if (sim_data.m_polygonal_mesh_Q) { + if (sim_data.m_n_divs > 8) { + sim_data.m_n_divs = 8; + } + } + + mesh_type msh; + if (sim_data.m_polygonal_mesh_Q) { + size_t l = sim_data.m_n_divs; + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + mesh_files.push_back("meshes/unit_square_polymesh_nel_20.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_40.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_80.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_160.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_320.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_640.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_1280.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_2560.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_5120.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + }else{ + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + + scal_analytic_functions functions; + switch (sim_data.m_exact_functions) { + case 1: + functions.set_function_type(scal_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + break; + case 2: + functions.set_function_type(scal_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + break; + default: + functions.set_function_type(scal_analytic_functions::EFunctionType::EFunctionNonPolynomial); + break; + } + + + RealType t = ti; + auto exact_scal_fun = functions.Evaluate_u(t); + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_accel_fun = functions.Evaluate_a(t); + auto exact_flux_fun = functions.Evaluate_q(t); + auto rhs_fun = functions.Evaluate_f(t); + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_scal_fun); + tc.tic(); + auto assembler = acoustic_one_field_assembler(msh, hho_di, bnd); + + // simple material + RealType rho = 1.0; + RealType vp = 1.0; + acoustic_material_data material(rho,vp); + assembler.load_material_data(msh,material); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial scalar, velocity and acceleration + Matrix p_dof_n, v_dof_n, a_dof_n; + assembler.project_over_cells(msh, p_dof_n, exact_scal_fun); + assembler.project_over_cells(msh, v_dof_n, exact_vel_fun); + assembler.project_over_cells(msh, a_dof_n, exact_accel_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "scalar_"; + postprocessor::write_silo_one_field(silo_file_name, it, msh, hho_di, p_dof_n, exact_scal_fun, false); + } + + std::ofstream simulation_log("acoustic_one_field.txt"); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_one_field(msh, hho_di, assembler, t, p_dof_n, v_dof_n, simulation_log); + } + + bool standar_Q = true; + // Newmark process + { + Matrix a_dof_np = a_dof_n; + + RealType beta = 0.25; + RealType gamma = 0.5; + if (!standar_Q) { + RealType kappa = 0.25; + gamma = 1.5; + beta = kappa*(gamma+0.5)*(gamma+0.5); + } + + tc.tic(); + assembler.assemble(msh, rhs_fun); + SparseMatrix Kg = assembler.LHS; + assembler.LHS *= beta*(dt*dt); + assembler.LHS += assembler.MASS; + linear_solver analysis; + if (sim_data.m_sc_Q) { + analysis.set_Kg(assembler.LHS, assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + }else{ + analysis.set_Kg(assembler.LHS); + } + + if (sim_data.m_iterative_solver_Q) { + analysis.set_iterative_solver(true); + }else{ + analysis.set_direct_solver(true); // symmetric matrix case + } + + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + // Manufactured solution + RealType t = dt*it+ti; + auto exact_scal_fun = functions.Evaluate_u(t); + auto exact_flux_fun = functions.Evaluate_q(t); + auto rhs_fun = functions.Evaluate_f(t); + + tc.tic(); + assembler.get_bc_conditions().updateDirichletFunction(exact_scal_fun, 0); + assembler.assemble_rhs(msh, rhs_fun); + + // Compute intermediate state for scalar and rate + p_dof_n = p_dof_n + dt*v_dof_n + 0.5*dt*dt*(1-2.0*beta)*a_dof_n; + v_dof_n = v_dof_n + dt*(1-gamma)*a_dof_n; + Matrix res = Kg*p_dof_n; + + assembler.RHS -= res; + tc.toc(); + std::cout << bold << cyan << "Rhs assembly completed: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + a_dof_np = analysis.solve(assembler.RHS); // new acceleration + tc.toc(); + std::cout << bold << cyan << "Solution completed: " << tc << " seconds" << reset << std::endl; + + // update scalar and rate + p_dof_n += beta*dt*dt*a_dof_np; + v_dof_n += gamma*dt*a_dof_np; + a_dof_n = a_dof_np; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "scalar_"; + postprocessor::write_silo_one_field(silo_file_name, it, msh, hho_di, p_dof_n, exact_scal_fun, false); + } + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_one_field(msh, hho_di, assembler, t, p_dof_n, v_dof_n, simulation_log); + } + + if(it == nt){ + postprocessor::compute_errors_one_field(msh, hho_di, assembler, p_dof_n, exact_scal_fun, exact_flux_fun, simulation_log); + } + + } + simulation_log << "Number of equations : " << analysis.n_equations() << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + } +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Elliptic_Conv_Test/EllipticOneFieldConvergenceTest.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Elliptic_Conv_Test/EllipticOneFieldConvergenceTest.hpp new file mode 100644 index 00000000..a2989d86 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Elliptic_Conv_Test/EllipticOneFieldConvergenceTest.hpp @@ -0,0 +1,183 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef EllipticOneFieldConvergenceTest_hpp +#define EllipticOneFieldConvergenceTest_hpp + +void EllipticOneFieldConvergenceTest(char **argv){ + + simulation_data sim_data = preprocessor::process_convergence_test_lua_file(argv); + sim_data.print_simulation_data(); + + // Manufactured exact solution + bool quadratic_function_Q = sim_data.m_exact_functions == 1; + auto exact_scal_fun = [quadratic_function_Q](const mesh_type::point_type& pt) -> RealType { + if(quadratic_function_Q){ + return (1.0-pt.x())*pt.x() * (1.0-pt.y())*pt.y(); + }else{ + return std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + } + + }; + + auto exact_flux_fun = [quadratic_function_Q](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector flux(2); + if(quadratic_function_Q){ + flux[0] = (1 - x)*(1 - y)*y - x*(1 - y)*y; + flux[1] = (1 - x)*x*(1 - y) - (1 - x)*x*y; + return flux; + }else{ + flux[0] = M_PI*std::cos(M_PI*pt.x())*std::sin(M_PI*pt.y()); + flux[1] = M_PI*std::sin(M_PI*pt.x())*std::cos(M_PI*pt.y()); + return flux; + } + + }; + + auto rhs_fun = [quadratic_function_Q](const typename mesh_type::point_type& pt) -> RealType { + double x,y; + x = pt.x(); + y = pt.y(); + if(quadratic_function_Q){ + return -2.0*((x - 1)*x + (y - 1)*y); + }else{ + return 2.0*M_PI*M_PI*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + } + }; + + if (sim_data.m_polygonal_mesh_Q) { + if (sim_data.m_n_divs > 8) { + sim_data.m_n_divs = 8; + } + } + + // simple material + RealType rho = 1.0; + RealType vp = 1.0; + acoustic_material_data material(rho,vp); + + std::ofstream error_file("steady_scalar_polygon_error.txt"); + + for(size_t k = 0; k <= sim_data.m_k_degree; k++){ + std::cout << bold << cyan << "Running an approximation with k : " << k << reset << std::endl; + error_file << "Approximation with k : " << k << std::endl; + for(size_t l = 0; l < sim_data.m_n_divs; l++){ + + // Reading the polygonal mesh + timecounter tc; + + tc.tic(); + mesh_type msh; + if (sim_data.m_polygonal_mesh_Q) { + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + mesh_files.push_back("meshes/unit_square_polymesh_nel_20.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_40.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_80.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_160.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_320.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_640.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_1280.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_2560.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_5120.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + }else{ + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(l); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = k; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,k); + + // Solving a scalar primal HHO problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_scal_fun); + tc.tic(); + auto assembler = acoustic_one_field_assembler(msh, hho_di, bnd); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + assembler.load_material_data(msh,material); + assembler.assemble(msh, rhs_fun); + assembler.apply_bc(msh); + tc.toc(); + std::cout << bold << cyan << "Assemble in : " << tc << " seconds" << reset << std::endl; + + // Solving LS + Matrix x_dof; + if (sim_data.m_sc_Q) { + tc.tic(); + linear_solver analysis(assembler.LHS,assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + tc.toc(); + std::cout << bold << cyan << "Create analysis in : " << tc << " seconds" << reset << std::endl; + + if(sim_data.m_iterative_solver_Q){ + analysis.set_iterative_solver(true); + } + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + x_dof = analysis.solve(assembler.RHS); + tc.toc(); + std::cout << bold << cyan << "Linear Solve in : " << tc << " seconds" << reset << std::endl; + error_file << "Number of equations (SC) : " << analysis.n_equations() << std::endl; + }else{ + tc.tic(); + linear_solver analysis(assembler.LHS); + tc.toc(); + std::cout << bold << cyan << "Create analysis in : " << tc << " seconds" << reset << std::endl; + + if(sim_data.m_iterative_solver_Q){ + analysis.set_iterative_solver(true); + } + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + x_dof = analysis.solve(assembler.RHS); + tc.toc(); + std::cout << bold << cyan << "Linear Solve in : " << tc << " seconds" << reset << std::endl; + error_file << "Number of equations : " << analysis.n_equations() << std::endl; + } + + // Computing errors + postprocessor::compute_errors_one_field(msh, hho_di, assembler, x_dof, exact_scal_fun, exact_flux_fun,error_file); + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "steady_scalar_k" + std::to_string(k) + "_"; + postprocessor::write_silo_one_field(silo_file_name, l, msh, hho_di, x_dof, exact_scal_fun, false); + } + } + error_file << std::endl << std::endl; + } + error_file.close(); +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Elliptic_Conv_Test/EllipticTwoFieldsConvergenceTest.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Elliptic_Conv_Test/EllipticTwoFieldsConvergenceTest.hpp new file mode 100644 index 00000000..f1192b8a --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Elliptic_Conv_Test/EllipticTwoFieldsConvergenceTest.hpp @@ -0,0 +1,189 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef EllipticTwoFieldsConvergenceTest_hpp +#define EllipticTwoFieldsConvergenceTest_hpp + +void EllipticTwoFieldsConvergenceTest(char **argv){ + + simulation_data sim_data = preprocessor::process_convergence_test_lua_file(argv); + sim_data.print_simulation_data(); + + // Manufactured exact solution + bool quadratic_function_Q = sim_data.m_exact_functions == 1; + auto exact_scal_fun = [quadratic_function_Q](const mesh_type::point_type& pt) -> RealType { + if(quadratic_function_Q){ + return (1.0-pt.x())*pt.x() * (1.0-pt.y())*pt.y(); + }else{ + return std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + } + + }; + + auto exact_flux_fun = [quadratic_function_Q](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector flux(2); + if(quadratic_function_Q){ + flux[0] = (1 - x)*(1 - y)*y - x*(1 - y)*y; + flux[1] = (1 - x)*x*(1 - y) - (1 - x)*x*y; + return flux; + }else{ + flux[0] = M_PI*std::cos(M_PI*pt.x())*std::sin(M_PI*pt.y()); + flux[1] = M_PI*std::sin(M_PI*pt.x())*std::cos(M_PI*pt.y()); + return flux; + } + + }; + + auto rhs_fun = [quadratic_function_Q](const typename mesh_type::point_type& pt) -> RealType { + double x,y; + x = pt.x(); + y = pt.y(); + if(quadratic_function_Q){ + return -2.0*((x - 1)*x + (y - 1)*y); + }else{ + return 2.0*M_PI*M_PI*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + } + }; + + if (sim_data.m_polygonal_mesh_Q) { + if (sim_data.m_n_divs > 8) { + sim_data.m_n_divs = 8; + } + } + + // simple material + RealType rho = 1.0; + RealType vp = 1.0; + acoustic_material_data material(rho,vp); + + std::ofstream error_file("steady_scalar_mixed_polygon_error.txt"); + + for(size_t k = 0; k <= sim_data.m_k_degree; k++){ + std::cout << bold << cyan << "Running an approximation with k : " << k << reset << std::endl; + error_file << "Approximation with k : " << k << std::endl; + for(size_t l = 0; l < sim_data.m_n_divs; l++){ + + // Reading the polygonal mesh + timecounter tc; + tc.tic(); + mesh_type msh; + if (sim_data.m_polygonal_mesh_Q) { + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + mesh_files.push_back("meshes/unit_square_polymesh_nel_20.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_40.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_80.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_160.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_320.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_640.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_1280.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_2560.txt"); + mesh_files.push_back("meshes/unit_square_polymesh_nel_5120.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + }else{ + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(l); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = k; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,k); + + // Solving a scalar primal HHO problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_scal_fun); + tc.tic(); + auto assembler = acoustic_two_fields_assembler(msh, hho_di, bnd); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + assembler.load_material_data(msh,material); + assembler.assemble(msh, rhs_fun); + assembler.assemble_mass(msh, false); + assembler.apply_bc(msh); + tc.toc(); + std::cout << bold << cyan << "Assemble in : " << tc << " seconds" << reset << std::endl; + + // Solving LS + Matrix x_dof; + if (sim_data.m_sc_Q) { + tc.tic(); + SparseMatrix Kg = assembler.LHS+assembler.MASS; + linear_solver analysis(Kg,assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + tc.toc(); + std::cout << bold << cyan << "Create analysis in : " << tc << " seconds" << reset << std::endl; + + if(sim_data.m_iterative_solver_Q){ + analysis.set_iterative_solver(); + } + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + x_dof = analysis.solve(assembler.RHS); + tc.toc(); + std::cout << bold << cyan << "Linear Solve in : " << tc << " seconds" << reset << std::endl; + error_file << "Number of equations (SC) : " << analysis.n_equations() << std::endl; + }else{ + tc.tic(); + SparseMatrix Kg = assembler.LHS+assembler.MASS; + linear_solver analysis(Kg); + tc.toc(); + std::cout << bold << cyan << "Create analysis in : " << tc << " seconds" << reset << std::endl; + + if(sim_data.m_iterative_solver_Q){ + analysis.set_iterative_solver(); + } + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + x_dof = analysis.solve(assembler.RHS); + tc.toc(); + std::cout << bold << cyan << "Linear Solve in : " << tc << " seconds" << reset << std::endl; + error_file << "Number of equations : " << analysis.n_equations() << std::endl; + } + + // Computing errors + postprocessor::compute_errors_two_fields(msh, hho_di, assembler, x_dof, exact_scal_fun, exact_flux_fun, error_file); + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "steady_scalar_mixed_k" + std::to_string(k) + "_"; + postprocessor::write_silo_two_fields(silo_file_name, l, msh, hho_di, x_dof, exact_scal_fun, exact_flux_fun, false); + } + } + error_file << std::endl << std::endl; + } + error_file.close(); +} + + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Gar6more_2D/HeterogeneousGar6more2DIHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Gar6more_2D/HeterogeneousGar6more2DIHHOFirstOrder.hpp new file mode 100644 index 00000000..cf500567 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Gar6more_2D/HeterogeneousGar6more2DIHHOFirstOrder.hpp @@ -0,0 +1,254 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef HeterogeneousGar6more2DIHHOFirstOrder_hpp +#define HeterogeneousGar6more2DIHHOFirstOrder_hpp + +void HeterogeneousGar6more2DIHHOFirstOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 3.0; + RealType ly = 3.0; + size_t nx = 3; + size_t ny = 3; + + + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.5, -1.5); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + + auto null_fun = [](const mesh_type::point_type& pt) -> RealType { + RealType x,y; + x = pt.x(); + y = pt.y(); + return 0.0; + }; + + auto flux_fun = [](const mesh_type::point_type& pt) -> std::vector { + RealType x,y,xc,yc,r,wave,vx,vy,c,lp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 2.0/3.0; + c = 10.0; + lp = std::sqrt(9.0)/10.0; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = -wave*(x-xc); + vy = -wave*(y-yc); + std::vector v = {vx,vy}; + return v; + }; + + RealType t = ti; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); + tc.tic(); + auto assembler = acoustic_two_fields_assembler(msh, hho_di, bnd); + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(2); + RealType rho, vp; + rho = 1.0; + if (y < 0.0) { + vp = 1.0*std::sqrt(3.0); + }else{ + vp = 1.0*std::sqrt(9.0); + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,acoustic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + std::string silo_file_props_name = "properties_map"; + postprocessor::write_silo_acoustic_property_map(silo_file_props_name, msh, assembler.get_material_data()); + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, null_fun, flux_fun); + assembler.project_over_faces(msh, x_dof, null_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "inhomogeneous_scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, null_fun, flux_fun, false); + } + + std::ofstream simulation_log("inhomogeneous_acoustic_two_fields.txt"); + + std::ofstream sensor_1_log("s1_acoustic_two_fields_h.csv"); + std::ofstream sensor_2_log("s2_acoustic_two_fields_h.csv"); + std::ofstream sensor_3_log("s3_acoustic_two_fields_h.csv"); + typename mesh_type::point_type s1_pt(-1.0/3.0, +1.0/3.0); + typename mesh_type::point_type s2_pt( 0.0, +1.0/3.0); + typename mesh_type::point_type s3_pt(+1.0/3.0, +1.0/3.0); + std::pair s1_pt_cell = std::make_pair(s1_pt, -1); + std::pair s2_pt_cell = std::make_pair(s2_pt, -1); + std::pair s3_pt_cell = std::make_pair(s3_pt, -1); + + // postprocessor::record_velocity_data_acoustic_two_fields(0, s1_pt_cell, msh, hho_di, x_dof, sensor_1_log); + // postprocessor::record_velocity_data_acoustic_two_fields(0, s2_pt_cell, msh, hho_di, x_dof, sensor_2_log); + // postprocessor::record_velocity_data_acoustic_two_fields(0, s3_pt_cell, msh, hho_di, x_dof, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + }else{ + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + tc.tic(); + assembler.assemble(msh, null_fun); + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + dirk_an.set_static_condensation_data(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data()), assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + // SDIRK case + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + tc.tic(); + dirk_an.ComposeMatrix(); + + if (sim_data.m_iterative_solver_Q) { + dirk_an.setIterativeSolver(); + } + + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << "Matrix decomposed: " << tc << " seconds" << reset << std::endl; + }else{ + // DIRK case + if (sim_data.m_iterative_solver_Q) { + dirk_an.setIterativeSolver(); + } + } + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + { + assembler.RHS.setZero(); // Optimization: this is a problem with (f = 0) + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + } + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "DIRK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, null_fun, flux_fun, false); + } + + // postprocessor::record_velocity_data_acoustic_two_fields(it, s1_pt_cell, msh, hho_di, x_dof, sensor_1_log); + // postprocessor::record_velocity_data_acoustic_two_fields(it, s2_pt_cell, msh, hho_di, x_dof, sensor_2_log); + // postprocessor::record_velocity_data_acoustic_two_fields(it, s3_pt_cell, msh, hho_di, x_dof, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + } + + simulation_log << "Number of equations : " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Number of DIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Gar6more_2D/HeterogeneousGar6more2DIHHOSecondOrder.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Gar6more_2D/HeterogeneousGar6more2DIHHOSecondOrder.hpp new file mode 100644 index 00000000..90c10b72 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Gar6more_2D/HeterogeneousGar6more2DIHHOSecondOrder.hpp @@ -0,0 +1,242 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef HeterogeneousGar6more2DIHHOSecondOrder_hpp +#define HeterogeneousGar6more2DIHHOSecondOrder_hpp + +void HeterogeneousGar6more2DIHHOSecondOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 3.0; + RealType ly = 3.0; + size_t nx = 3; + size_t ny = 3; + + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.5, -1.5); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = tf/nt; + + auto null_fun = [](const mesh_type::point_type& pt) -> RealType { + RealType x,y; + x = pt.x(); + y = pt.y(); + return 0.0; + }; + + auto p_fun = [](const mesh_type::point_type& pt) -> RealType { + RealType x,y,xc,yc,r,wave,vx,vy,v,c,lp,factor; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 2.0/3.0; + c = 10.0; + lp = 1.0*std::sqrt(9.0)/10.0; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + factor = (lp*lp/(2.0*M_PI*M_PI)); + return factor*wave; + }; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); // easy because boundary assumes zero every where any time. + tc.tic(); + auto assembler = acoustic_one_field_assembler(msh, hho_di, bnd); + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(2); + RealType rho, vp; + rho = 1.0; + if (y < 0.0) { + vp = 1.0*std::sqrt(3.0); + }else{ + vp = 1.0*std::sqrt(9.0); + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,acoustic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial scalar, velocity and acceleration + Matrix p_dof_n, v_dof_n, a_dof_n; + assembler.project_over_cells(msh, p_dof_n, p_fun); + assembler.project_over_faces(msh, p_dof_n, p_fun); + assembler.project_over_cells(msh, v_dof_n, null_fun); + assembler.project_over_faces(msh, v_dof_n, null_fun); + assembler.project_over_cells(msh, a_dof_n, null_fun); + assembler.project_over_faces(msh, a_dof_n, null_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "inhomogeneous_scalar_"; + postprocessor::write_silo_one_field(silo_file_name, it, msh, hho_di, p_dof_n, p_fun, false); + } + + std::ofstream simulation_log("inhomogeneous_acoustic_one_field.txt"); + + std::ofstream sensor_1_log("s1_acoustic_one_field_h.csv"); + std::ofstream sensor_2_log("s2_acoustic_one_field_h.csv"); + std::ofstream sensor_3_log("s3_acoustic_one_field_h.csv"); + typename mesh_type::point_type s1_pt(-1.0/3.0, -1.0/3.0); + typename mesh_type::point_type s2_pt( 0.0, -1.0/3.0); + typename mesh_type::point_type s3_pt(+1.0/3.0, -1.0/3.0); + std::pair s1_pt_cell = std::make_pair(s1_pt, -1); + std::pair s2_pt_cell = std::make_pair(s2_pt, -1); + std::pair s3_pt_cell = std::make_pair(s3_pt, -1); + + postprocessor::record_velocity_data_acoustic_one_field(0, s1_pt_cell, msh, hho_di, assembler, p_dof_n, sensor_1_log); + postprocessor::record_velocity_data_acoustic_one_field(0, s2_pt_cell, msh, hho_di, assembler, p_dof_n, sensor_2_log); + postprocessor::record_velocity_data_acoustic_one_field(0, s3_pt_cell, msh, hho_di, assembler, p_dof_n, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_one_field(msh, hho_di, assembler, ti, p_dof_n, v_dof_n, simulation_log); + } + + timecounter simulation_tc; + bool standar_Q = true; + // Newmark process + { + Matrix a_dof_np = a_dof_n; + + RealType beta = 0.25; + RealType gamma = 0.5; + if (!standar_Q) { + RealType kappa = 0.25; + gamma = 1.0; + beta = kappa*(gamma+0.5)*(gamma+0.5); + } + + tc.tic(); + assembler.assemble(msh, null_fun); + SparseMatrix Kg = assembler.LHS; + assembler.LHS *= beta*(dt*dt); + assembler.LHS += assembler.MASS; + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + + linear_solver analysis; + if (sim_data.m_sc_Q) { + tc.tic(); + analysis.set_Kg(assembler.LHS,assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + tc.toc(); + std::cout << bold << cyan << "Create analysis in : " << tc << " seconds" << reset << std::endl; + +// analysis.set_iterative_solver(true, 1.0e-10); + analysis.set_direct_solver(true); + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + }else{ + tc.tic(); + analysis.set_Kg(assembler.LHS); + tc.toc(); + std::cout << bold << cyan << "Create analysis in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + } + + simulation_tc.tic(); + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + // Manufactured solution + RealType t = dt*it+ti; + + tc.tic(); + // Compute intermediate state for scalar and rate + p_dof_n = p_dof_n + dt*v_dof_n + 0.5*dt*dt*(1-2.0*beta)*a_dof_n; + v_dof_n = v_dof_n + dt*(1-gamma)*a_dof_n; + Matrix res = Kg*p_dof_n; + + assembler.RHS.setZero(); + assembler.RHS -= res; + tc.toc(); + std::cout << bold << cyan << "Rhs assembly completed: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + a_dof_np = analysis.solve(assembler.RHS); // new acceleration + tc.toc(); + + std::cout << bold << cyan << "Solution completed: " << tc << " seconds" << reset << std::endl; + + // update scalar and rate + p_dof_n += beta*dt*dt*a_dof_np; + v_dof_n += gamma*dt*a_dof_np; + a_dof_n = a_dof_np; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_scalar_"; + postprocessor::write_silo_one_field(silo_file_name, it, msh, hho_di, p_dof_n, p_fun, false); + } + + postprocessor::record_velocity_data_acoustic_one_field(it, s1_pt_cell, msh, hho_di, assembler, p_dof_n, sensor_1_log); + postprocessor::record_velocity_data_acoustic_one_field(it, s2_pt_cell, msh, hho_di, assembler, p_dof_n, sensor_2_log); + postprocessor::record_velocity_data_acoustic_one_field(it, s3_pt_cell, msh, hho_di, assembler, p_dof_n, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_one_field(msh, hho_di, assembler, t, p_dof_n, v_dof_n, simulation_log); + } + + } + simulation_tc.toc(); + simulation_log << "Simulation time : " << simulation_tc << " seconds" << std::endl; + simulation_log << "Number of equations : " << analysis.n_equations() << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + } + +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous/HeterogeneousEHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous/HeterogeneousEHHOFirstOrder.hpp new file mode 100644 index 00000000..0fd14297 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous/HeterogeneousEHHOFirstOrder.hpp @@ -0,0 +1,210 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef HeterogeneousEHHOFirstOrder_hpp +#define HeterogeneousEHHOFirstOrder_hpp + +void HeterogeneousEHHOFirstOrder(char **argv){ + + simulation_data sim_data = preprocessor::process_acoustics_lua_file(argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 1.0; + RealType ly = 0.2; + size_t nx = 10; + size_t ny = 1; + + + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh_x_direction(sim_data.m_n_divs); + mesh_builder.set_translation_data(0.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 0.5 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.5; + RealType dt = (tf-ti)/nt; + + scal_analytic_functions functions; + functions.set_function_type(scal_analytic_functions::EFunctionType::EFunctionInhomogeneousInSpace); + RealType t = ti; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_q(t); + auto rhs_fun = functions.Evaluate_f(t); + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_vel_fun); + tc.tic(); + auto assembler = acoustic_two_fields_assembler(msh, hho_di, bnd); + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(2); + RealType rho, vp; + if (x < 0.5) { + vp = 3.0; + }else{ + vp = 1.0; + } + rho = 1.0/(vp*vp); // this is required to make both formulations compatible by keeping kappa = 1 + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,acoustic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, exact_vel_fun, exact_flux_fun); + assembler.project_over_faces(msh, x_dof, exact_vel_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "e_scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + std::ofstream simulation_log("acoustic_two_fields_explicit.txt"); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, ti, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + int s = 4; + Matrix a; + Matrix b; + Matrix c; + erk_butcher_tableau::erk_tables(s, a, b, c); + + tc.tic(); + assembler.assemble(msh, rhs_fun); + tc.toc(); + std::cout << bold << cyan << "Stiffness and rhs assembly completed: " << tc << " seconds" << reset << std::endl; + size_t n_face_dof = assembler.get_n_face_dof(); + tc.tic(); + erk_hho_scheme erk_an(assembler.LHS,assembler.RHS,assembler.MASS,n_face_dof); + erk_an.Kcc_inverse(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + if(sim_data.m_hdg_stabilization_Q){ + erk_an.Sff_inverse(std::make_pair(assembler.get_n_faces(), assembler.get_face_basis_data())); + }else{ + if (sim_data.m_iterative_solver_Q) { + erk_an.setIterativeSolver(); + } + erk_an.DecomposeFaceTerm(); + } + tc.toc(); + std::cout << bold << cyan << "ERK analysis created: " << tc << " seconds" << reset << std::endl; + + erk_an.refresh_faces_unknowns(x_dof); + Matrix x_dof_n; + timecounter simulation_tc; + simulation_tc.tic(); + + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + RealType tn = dt*(it-1)+ti; + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + { + RealType t = tn + c(i,0) * dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto rhs_fun = functions.Evaluate_f(t); + assembler.get_bc_conditions().updateDirichletFunction(exact_vel_fun, 0); + assembler.RHS.setZero(); + assembler.apply_bc(msh); + erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + } + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "ERK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + RealType t = tn + dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_q(t); + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "e_inhomogeneous_scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + } + + + + + + simulation_tc.toc(); + simulation_log << "Simulation time : " << simulation_tc << " seconds" << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous/HeterogeneousIHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous/HeterogeneousIHHOFirstOrder.hpp new file mode 100644 index 00000000..f3b8f851 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous/HeterogeneousIHHOFirstOrder.hpp @@ -0,0 +1,232 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef HeterogeneousIHHOFirstOrder_hpp +#define HeterogeneousIHHOFirstOrder_hpp + + +void HeterogeneousIHHOFirstOrder(char **argv){ + + simulation_data sim_data = preprocessor::process_acoustics_lua_file(argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 1.0; + RealType ly = 0.2; + size_t nx = 10; + size_t ny = 1; + + + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh_x_direction(sim_data.m_n_divs); + mesh_builder.set_translation_data(0.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 0.5 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.5; + RealType dt = (tf-ti)/nt; + + scal_analytic_functions functions; + functions.set_function_type(scal_analytic_functions::EFunctionType::EFunctionInhomogeneousInSpace); + RealType t = ti; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_q(t); + auto rhs_fun = functions.Evaluate_f(t); + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_vel_fun); + tc.tic(); + auto assembler = acoustic_two_fields_assembler(msh, hho_di, bnd); + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(2); + RealType rho, vp; + if (x < 0.5) { + vp = 3.0; + }else{ + vp = 1.0; + } + rho = 1.0/(vp*vp); // this is required to make both formulations compatible by keeping kappa = 1 + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,acoustic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + std::string silo_file_props_name = "properties_map"; + postprocessor::write_silo_acoustic_property_map(silo_file_props_name, msh, assembler.get_material_data()); + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, exact_vel_fun, exact_flux_fun); + assembler.project_over_faces(msh, x_dof, exact_vel_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + std::ofstream simulation_log("acoustic_two_fields.txt"); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + }else{ + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + tc.tic(); + assembler.assemble(msh, rhs_fun); + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + dirk_an.set_static_condensation_data(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data()), assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + // SDIRK case + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + tc.tic(); + dirk_an.ComposeMatrix(); + + if (sim_data.m_iterative_solver_Q) { + dirk_an.setIterativeSolver(); + } + + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << "Matrix decomposed: " << tc << " seconds" << reset << std::endl; + }else{ + // DIRK case + if (sim_data.m_iterative_solver_Q) { + dirk_an.setIterativeSolver(); + } + } + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + { + RealType t = tn + c(i,0) * dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto rhs_fun = functions.Evaluate_f(t); + assembler.get_bc_conditions().updateDirichletFunction(exact_vel_fun, 0); + assembler.RHS.setZero(); // Optimization: this is a problem with (f = 0) + assembler.apply_bc(msh); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + } + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "DIRK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + t = tn + dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_q(t); + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + if(it == nt){ + // Computing errors + postprocessor::compute_errors_two_fields(msh, hho_di, assembler, x_dof, exact_vel_fun, exact_flux_fun,simulation_log); + } + + } + + simulation_log << "Number of equations : " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Number of DIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous/HeterogeneousIHHOSecondOrder.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous/HeterogeneousIHHOSecondOrder.hpp new file mode 100644 index 00000000..b8b85030 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous/HeterogeneousIHHOSecondOrder.hpp @@ -0,0 +1,228 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef HeterogeneousIHHOSecondOrder_hpp +#define HeterogeneousIHHOSecondOrder_hpp + +void HeterogeneousIHHOSecondOrder(char **argv){ + + simulation_data sim_data = preprocessor::process_acoustics_lua_file(argv); + sim_data.print_simulation_data(); + + /////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////// Building a cartesian mesh ////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + + timecounter tc; + tc.tic(); + + RealType lx = 1.0; + RealType ly = 0.2; + size_t nx = 10; + size_t ny = 1; + + mesh_type msh; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh_x_direction(sim_data.m_n_divs); + mesh_builder.set_translation_data(0.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + /////////////////////////////////////////////////////////////////////////////////////// + /////////////////// Time controls : Final time value 0.5 ////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + + size_t nt = 10; // Number of temp iterations + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.5; + RealType dt = (tf-ti)/nt; + + + scal_analytic_functions functions; + functions.set_function_type(scal_analytic_functions::EFunctionType::EFunctionInhomogeneousInSpace); + RealType t = ti; + auto exact_scal_fun = functions.Evaluate_u(t); + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_accel_fun = functions.Evaluate_a(t); + auto exact_flux_fun = functions.Evaluate_q(t); + auto rhs_fun = functions.Evaluate_f(t); + + /////////////////////////////////////////////////////////////////////////////////////// + /////// Creating HHO approximation spaces and corresponding linear operator ////// + /////////////////////////////////////////////////////////////////////////////////////// + + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + /////////////////////////////////////////////////////////////////////////////////////// + /////////////////////// Solving a primal HHO mixed problem //////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_scal_fun); // easy because boundary assumes zero every where any time. + tc.tic(); + auto assembler = acoustic_one_field_assembler(msh, hho_di, bnd); + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(2); + RealType rho, vp; + if (x < 0.5) { + vp = 10.0; + }else{ + vp = 1.0; + } + rho = 1.0/(vp*vp); // this is required to make both formulations compatible by keeping kappa = 1 + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,acoustic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + /////////////////////////////////////////////////////////////////////////////////////// + ///////////// Projecting initial scalar, velocity and acceleration //////////////// + /////////////////////////////////////////////////////////////////////////////////////// + + Matrix p_dof_n, v_dof_n, a_dof_n; + assembler.project_over_cells(msh, p_dof_n, exact_scal_fun); + assembler.project_over_faces(msh, p_dof_n, exact_scal_fun); + assembler.project_over_cells(msh, v_dof_n, exact_vel_fun); + assembler.project_over_faces(msh, v_dof_n, exact_vel_fun); + assembler.project_over_cells(msh, a_dof_n, exact_accel_fun); + assembler.project_over_faces(msh, a_dof_n, exact_accel_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "scalar_"; + postprocessor::write_silo_one_field(silo_file_name, it, msh, hho_di, v_dof_n, exact_vel_fun, false); + } + + std::ofstream simulation_log("acoustic_one_field.txt"); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_one_field(msh, hho_di, assembler, t, p_dof_n, v_dof_n, simulation_log); + } + + linear_solver analysis; + bool standar_Q = true; + + /////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////// Newmark process ///////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + { + Matrix a_dof_np = a_dof_n; + + RealType beta = 0.25; + RealType gamma = 0.5; + if (!standar_Q) { + RealType kappa = 0.25; + gamma = 0.6; + beta = kappa*(gamma+0.5)*(gamma+0.5); + } + + tc.tic(); + assembler.assemble(msh, rhs_fun); + SparseMatrix Kg = assembler.LHS; + assembler.LHS *= beta*(dt*dt); + assembler.LHS += assembler.MASS; + linear_solver analysis; + if (sim_data.m_sc_Q) { + analysis.set_Kg(assembler.LHS, assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + }else{ + analysis.set_Kg(assembler.LHS); + } + + if (sim_data.m_iterative_solver_Q) { + analysis.set_iterative_solver(true); + }else{ + analysis.set_direct_solver(true); // symmetric matrix case + } + + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + + /////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////// Temporal Loop /////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////// + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + // Manufactured solution + RealType t = dt*it+ti; + auto exact_scal_fun = functions.Evaluate_u(t); + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_q(t); + + assembler.get_bc_conditions().updateDirichletFunction(exact_scal_fun, 0); + assembler.RHS.setZero(); // Optimization: this is a problem with (f = 0) + assembler.apply_bc(msh); + + // Compute intermediate state for scalar and rate + p_dof_n = p_dof_n + dt*v_dof_n + 0.5*dt*dt*(1-2.0*beta)*a_dof_n; + v_dof_n = v_dof_n + dt*(1-gamma)*a_dof_n; + Matrix res = Kg*p_dof_n; + + assembler.RHS -= res; + tc.toc(); + std::cout << bold << cyan << "Rhs assembly completed: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + a_dof_np = analysis.solve(assembler.RHS); // new acceleration + tc.toc(); + + std::cout << bold << cyan << "Solution completed: " << tc << " seconds" << reset << std::endl; + + // update scalar and rate + p_dof_n += beta*dt*dt*a_dof_np; + v_dof_n += gamma*dt*a_dof_np; + a_dof_n = a_dof_np; + + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "scalar_"; + postprocessor::write_silo_one_field(silo_file_name, it, msh, hho_di, v_dof_n, exact_vel_fun, false); + } + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_one_field(msh, hho_di, assembler, t, p_dof_n, v_dof_n, simulation_log); + } + + if(it == nt){ + postprocessor::compute_errors_one_field(msh, hho_di, assembler, p_dof_n, exact_scal_fun, exact_flux_fun, simulation_log); + } + + } + + simulation_log << "Number of equations : " << analysis.n_equations() << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + } +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseEHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseEHHOFirstOrder.hpp new file mode 100644 index 00000000..08c7e30e --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseEHHOFirstOrder.hpp @@ -0,0 +1,270 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef HeterogeneousPulseEHHOFirstOrder_hpp +#define HeterogeneousPulseEHHOFirstOrder_hpp + +void HeterogeneousPulseEHHOFirstOrder(char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_acoustics_lua_file(argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + + + mesh_type msh; + if (sim_data.m_polygonal_mesh_Q) { + + auto validate_l = [](size_t l) -> size_t { + if ((0 < l) && (l < 5) ) { + return l; + }else{ + std::cout << "Warning:: Only five meshes available. Running level 4." << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_4096.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_5120.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_10240.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_16384.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_65536.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + } + + else { + + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 0.25 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.25; + RealType dt = tf/nt; + + auto null_fun = [](const mesh_type::point_type& pt) -> RealType { + RealType x,y; + x = pt.x(); + y = pt.y(); + return 0.0; + }; + + auto null_flux_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + return {0,0}; + }; + + auto vel_fun = [](const mesh_type::point_type& pt) -> RealType { + RealType x,y,xc,yc,r,wave; + x = pt.x(); + y = pt.y(); + xc = 0.5; + yc = 0.25; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = 0.1*(-4*std::sqrt(10.0/3.0)*(-1 + 1600.0*r*r))/(std::exp(800*r*r)*std::pow(M_PI,0.25)); + return wave; + }; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); + tc.tic(); + auto assembler = acoustic_two_fields_assembler(msh, hho_di, bnd); + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(2); + RealType rho, vp; + rho = 1.0; + if (y < 0.5) { + vp = 5.0; + }else{ + vp = 1.0; + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + return mat_data; + }; + assembler.load_material_data(msh,acoustic_mat_fun); + + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, vel_fun, null_flux_fun); + assembler.project_over_faces(msh, x_dof, vel_fun); + + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "e_inhomogeneous_scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, vel_fun, null_flux_fun, false); + } + + std::ofstream simulation_log("inhomogeneous_acoustic_two_fields_explicit.txt"); + + std::ofstream sensor_top_log("top_sensor_e_acoustic_two_fields.csv"); + std::ofstream sensor_bot_log("bot_sensor_e_acoustic_two_fields.csv"); + typename mesh_type::point_type top_pt(0.5, 2.0/3.0); + typename mesh_type::point_type bot_pt(0.5, 1.0/3.0); + std::pair top_pt_cell = std::make_pair(top_pt, -1); + std::pair bot_pt_cell = std::make_pair(bot_pt, -1); + + postprocessor::record_data_acoustic_two_fields(0, top_pt_cell, msh, hho_di, x_dof, sensor_top_log); + postprocessor::record_data_acoustic_two_fields(0, bot_pt_cell, msh, hho_di, x_dof, sensor_bot_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, ti, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + int s = 4; + Matrix a; + Matrix b; + Matrix c; + erk_butcher_tableau::erk_tables(s, a, b, c); + + tc.tic(); + assembler.assemble(msh, null_fun); + tc.toc(); + std::cout << bold << cyan << "Stiffness and rhs assembly completed: " << tc << " seconds" << reset << std::endl; + size_t n_face_dof = assembler.get_n_face_dof(); + tc.tic(); + erk_hho_scheme erk_an(assembler.LHS,assembler.RHS,assembler.MASS,n_face_dof); + erk_an.Kcc_inverse(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + if(sim_data.m_hdg_stabilization_Q){ + erk_an.Sff_inverse(std::make_pair(assembler.get_n_faces(), assembler.get_face_basis_data())); + } + else { + if (sim_data.m_iterative_solver_Q) { + erk_an.setIterativeSolver(); + } + erk_an.DecomposeFaceTerm(); + } + tc.toc(); + std::cout << bold << cyan << "ERK analysis created: " << tc << " seconds" << reset << std::endl; + + erk_an.refresh_faces_unknowns(x_dof); + Matrix x_dof_n; + timecounter simulation_tc; + simulation_tc.tic(); + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + RealType tn = dt*(it-1)+ti; + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + { +// RealType t = tn + c(i,0) * dt; +// auto exact_vel_fun = functions.Evaluate_v(t); +// auto rhs_fun = functions.Evaluate_f(t); +// assembler.get_bc_conditions().updateDirichletFunction(exact_vel_fun, 0); +// assembler.assemble_rhs(msh, rhs_fun); +// assembler.apply_bc(msh); +// erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + } + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "ERK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + RealType t = tn + dt; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "e_inhomogeneous_scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, vel_fun, null_flux_fun, false); + } + + postprocessor::record_data_acoustic_two_fields(it, top_pt_cell, msh, hho_di, x_dof, sensor_top_log); + postprocessor::record_data_acoustic_two_fields(it, bot_pt_cell, msh, hho_di, x_dof, sensor_bot_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + } + simulation_tc.toc(); + simulation_log << "Simulation time : " << simulation_tc << " seconds" << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOFirstOrder.hpp new file mode 100644 index 00000000..8b2ef31a --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOFirstOrder.hpp @@ -0,0 +1,337 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef HeterogeneousPulseIHHOFirstOrder_hpp +#define HeterogeneousPulseIHHOFirstOrder_hpp + +void HeterogeneousPulseIHHOFirstOrder(char **argv){ + + /////////////////////////////////////////////////////////////////////////////// + ////////////////////////////// Préprocessing ////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + using RealType = double; + simulation_data sim_data = preprocessor::process_acoustics_lua_file(argv); + sim_data.print_simulation_data(); + + /////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////// Meshes ////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + mesh_type msh; + if (sim_data.m_polygonal_mesh_Q) { + + auto validate_l = [](size_t l) -> size_t { + if ((0 < l) && (l < 5) ) { + return l; + }else{ + std::cout << "Warning:: Only five meshes available. Running level 4." << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_4096.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_5120.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_10240.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_16384.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_65536.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + // A commenter pour la lecture des différents maillages polyhédriques réguliers + /* polygon_2d_mesh_reader mesh_builder; + std::string mesh_file = "meshes/mexican_hat_polymesh_adapted_nel_8512.txt"; + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_file); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh);*/ + + } + + else { + + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + /////////////////////////////////////////////////////////////////////////////// + ///////////////////////////// Time controls /////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + // Time controls : Final time value 0.50 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.5; + RealType dt = tf/nt; + + /////////////////////////////////////////////////////////////////////////////// + ////////////////////////// Source term ? ////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + auto null_fun = [](const mesh_type::point_type& pt) -> RealType { + RealType x,y; + x = pt.x(); + y = pt.y(); + return 0.0; + }; + + auto null_flux_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + return {0,0}; + }; + + auto vel_fun = [](const mesh_type::point_type& pt) -> RealType { + RealType x,y,xc,yc,r,wave; + x = pt.x(); + y = pt.y(); + xc = 0.5; + yc = 0.5; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = 0.1*(-4*std::sqrt(10.0/3.0)*(-1 + 1600.0*r*r))/(std::exp(800*r*r)*std::pow(M_PI,0.25)); + return wave; + }; + + /////////////////////////////////////////////////////////////////////////////// + /// Creating HHO approximation spaces and corresponding linear operator /// + /////////////////////////////////////////////////////////////////////////////// + + + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + /////////////////////////////////////////////////////////////////////////////// + //////////////////// Solving a primal HHO mixed problem /////////////////// + /////////////////////////////////////////////////////////////////////////////// + + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); + tc.tic(); + auto assembler = acoustic_two_fields_assembler(msh, hho_di, bnd); + + /////////////////////////////////////////////////////////////////////////////// + ///////////////////////// Acoustic properties ///////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(2); + RealType rho, vp; + rho = 1.0; + if (y < 0.5) { + vp = 1.0; + }else{ + vp = 1.0; + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + return mat_data; + }; + assembler.load_material_data(msh,acoustic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + /////////////////////////////////////////////////////////////////////////////// + ///////////////////////// Projecting initial data ///////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, vel_fun, null_flux_fun); + assembler.project_over_faces(msh, x_dof, vel_fun); + + ///////////////////////////////////////////////////////////////////////////////// + //////////////////////////// Postprocessing ///////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "inhomogeneous_scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, vel_fun, null_flux_fun, false); + } + + std::ofstream simulation_log("inhomogeneous_acoustic_two_fields.txt"); + + std::ofstream sensor_log1("sensor1.csv"); + std::ofstream sensor_log2("sensor2.csv"); + std::ofstream sensor_log3("sensor3.csv"); + typename mesh_type::point_type pt1(1.0/3, 2.0/3); + typename mesh_type::point_type pt2(1.0/2, 2.0/3); + typename mesh_type::point_type pt3(2.0/3, 2.0/3); + std::pair pt1_cell = std::make_pair(pt1, -1); + std::pair pt2_cell = std::make_pair(pt2, -1); + std::pair pt3_cell = std::make_pair(pt3, -1); + postprocessor::record_data_acoustic_two_fields(0, pt1_cell, msh, hho_di, x_dof, sensor_log1); + postprocessor::record_data_acoustic_two_fields(0, pt2_cell, msh, hho_di, x_dof, sensor_log2); + postprocessor::record_data_acoustic_two_fields(0, pt3_cell, msh, hho_di, x_dof, sensor_log3); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, ti, x_dof, simulation_log); + } + + /////////////////////////////////////////////////////////////////////////////// + /////// Solving a first order equation HDG/HHO propagation problem //////// + /////////////////////////////////////////////////////////////////////////////// + + Matrix a; + Matrix b; + Matrix c; + + /////////////////////////////////////////////////////////////////////////////// + //////////////////////////// DIRK(s) schemes ////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + }else{ + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + tc.tic(); + assembler.assemble(msh, null_fun); + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + dirk_an.set_static_condensation_data(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data()), assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + // SDIRK case + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + tc.tic(); + dirk_an.ComposeMatrix(); + + if (sim_data.m_iterative_solver_Q) { + dirk_an.setIterativeSolver(); + } + + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << "Matrix decomposed: " << tc << " seconds" << reset << std::endl; + }else{ + // DIRK case + if (sim_data.m_iterative_solver_Q) { + dirk_an.setIterativeSolver(); + } + } + + Matrix x_dof_n; + timecounter simulation_tc; + simulation_tc.tic(); + + /////////////////////////////////////////////////////////////////////////////// + //////////////////////////// Temporal loop //////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + { + assembler.RHS.setZero(); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + } + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "DIRK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + RealType t = tn + dt; + + ///////////////////////////////////////////////////////////////////////////////// + //////////////////////////// Postprocessing ////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////// + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, vel_fun, null_flux_fun, false); + } + + postprocessor::record_data_acoustic_two_fields(it, pt1_cell, msh, hho_di, x_dof, sensor_log1); + postprocessor::record_data_acoustic_two_fields(it, pt2_cell, msh, hho_di, x_dof, sensor_log2); + postprocessor::record_data_acoustic_two_fields(it, pt3_cell, msh, hho_di, x_dof, sensor_log3); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + } + simulation_tc.toc(); + simulation_log << "Simulation time : " << simulation_tc << " seconds" << std::endl; + simulation_log << "Number of equations : " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Number of DIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOFirstOrder2.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOFirstOrder2.hpp new file mode 100644 index 00000000..e5b76df7 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOFirstOrder2.hpp @@ -0,0 +1,347 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef HeterogeneousPulseIHHOFirstOrder_hpp +#define HeterogeneousPulseIHHOFirstOrder_hpp + +void HeterogeneousPulseIHHOFirstOrder(char **argv){ + + /////////////////////////////////////////////////////////////////////////////// + ////////////////////////////// Préprocessing ////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + using RealType = double; + simulation_data sim_data = preprocessor::process_acoustics_lua_file(argv); + sim_data.print_simulation_data(); + + /////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////// Meshes ////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + mesh_type msh; + if (sim_data.m_polygonal_mesh_Q) { + + auto validate_l = [](size_t l) -> size_t { + if ((0 < l) && (l < 5) ) { + return l; + }else{ + std::cout << "Warning:: Only five meshes available. Running level 4." << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_4096.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_5120.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_10240.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_16384.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_65536.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + // A commenter pour la lecture des différents maillages polyhédriques réguliers + /* polygon_2d_mesh_reader mesh_builder; + std::string mesh_file = "meshes/mexican_hat_polymesh_adapted_nel_8512.txt"; + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_file); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh);*/ + + } + + else { + + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + /////////////////////////////////////////////////////////////////////////////// + ///////////////////////////// Time controls /////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + // Time controls : Final time value 0.50 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + size_t it = 0; + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = tf/nt; + + /////////////////////////////////////////////////////////////////////////////// + //////////////////////// Initial Condition //////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + auto null_fun = [](const mesh_type::point_type& pt) -> RealType { + RealType x,y; + x = pt.x(); + y = pt.y(); + return 0.0; + }; + + auto null_flux_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + return {0,0}; + }; + + auto vel_fun = [](const mesh_type::point_type& pt) -> RealType { + RealType x,y,xc,yc,r,wave; + x = pt.x(); + y = pt.y(); + xc = 0.5; + yc = 0.5; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = 0.1*(-4*std::sqrt(10.0/3.0)*(-1 + 1600.0*r*r))/(std::exp(800*r*r)*std::pow(M_PI,0.25)); + return wave; + }; + + /////////////////////////////////////////////////////////////////////////////// + /// Creating HHO approximation spaces and corresponding linear operator /// + /////////////////////////////////////////////////////////////////////////////// + + + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + /////////////////////////////////////////////////////////////////////////////// + //////////////////// Solving a primal HHO mixed problem /////////////////// + /////////////////////////////////////////////////////////////////////////////// + + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); + tc.tic(); + auto assembler = acoustic_two_fields_assembler(msh, hho_di, bnd); + + /////////////////////////////////////////////////////////////////////////////// + ///////////////////////// Acoustic properties ///////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(2); + RealType rho, vp; + rho = 1.0; + if (y < 0.5) { + vp = 1.0; + }else{ + vp = 1.0; + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + return mat_data; + }; + assembler.load_material_data(msh,acoustic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + /////////////////////////////////////////////////////////////////////////////// + ///////////////////////// Projecting initial data ///////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun); + assembler.project_over_faces(msh, x_dof, null_fun); + + // // Source Term + typename mesh_type::point_type pt_source(0.5,0.5); + std::pair source_cell = std::make_pair(pt_source, -1); + // source_term::ricker_fluid(it,dt,source_cell,msh,hho_di,x_dof); + + ///////////////////////////////////////////////////////////////////////////////// + //////////////////////////// Postprocessing ///////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, null_fun, null_flux_fun, false); + } + + std::ofstream simulation_log("inhomogeneous_acoustic_two_fields.txt"); + + std::ofstream sensor_log1("sensor1.csv"); + std::ofstream sensor_log2("sensor2.csv"); + std::ofstream sensor_log3("sensor3.csv"); + typename mesh_type::point_type pt1(1.0/3, 2.0/3); + typename mesh_type::point_type pt2(1.0/2, 2.0/3); + typename mesh_type::point_type pt3(2.0/3, 2.0/3); + std::pair pt1_cell = std::make_pair(pt1, -1); + std::pair pt2_cell = std::make_pair(pt2, -1); + std::pair pt3_cell = std::make_pair(pt3, -1); + postprocessor::record_data_acoustic_two_fields(0, pt1_cell, msh, hho_di, x_dof, sensor_log1); + postprocessor::record_data_acoustic_two_fields(0, pt2_cell, msh, hho_di, x_dof, sensor_log2); + postprocessor::record_data_acoustic_two_fields(0, pt3_cell, msh, hho_di, x_dof, sensor_log3); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, ti, x_dof, simulation_log); + } + + /////////////////////////////////////////////////////////////////////////////// + /////// Solving a first order equation HDG/HHO propagation problem //////// + /////////////////////////////////////////////////////////////////////////////// + + Matrix a; + Matrix b; + Matrix c; + + /////////////////////////////////////////////////////////////////////////////// + //////////////////////////// DIRK(s) schemes ////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + }else{ + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + tc.tic(); + assembler.assemble(msh, null_fun); + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + dirk_an.set_static_condensation_data(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data()), assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + // SDIRK case + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + tc.tic(); + dirk_an.ComposeMatrix(); + + if (sim_data.m_iterative_solver_Q) { + dirk_an.setIterativeSolver(); + } + + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << "Matrix decomposed: " << tc << " seconds" << reset << std::endl; + }else{ + // DIRK case + if (sim_data.m_iterative_solver_Q) { + dirk_an.setIterativeSolver(); + } + } + + Matrix x_dof_n; + timecounter simulation_tc; + simulation_tc.tic(); + + /////////////////////////////////////////////////////////////////////////////// + //////////////////////////// Temporal loop //////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + { + assembler.RHS.setZero(); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + } + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + + tc.toc(); + std::cout << bold << cyan << "DIRK step completed: " << tc << " seconds" << reset << std::endl; + source_term::punctual_source(it,dt,source_cell,msh,hho_di,x_dof_n); + x_dof = x_dof_n; + + + RealType t = tn + dt; + + ///////////////////////////////////////////////////////////////////////////////// + //////////////////////////// Postprocessing ////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////// + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_scalar_mixed_"; + postprocessor::write_silo_two_fields(silo_file_name, it, msh, hho_di, x_dof, null_fun, null_flux_fun, false); + } + + postprocessor::record_data_acoustic_two_fields(it, pt1_cell, msh, hho_di, x_dof, sensor_log1); + postprocessor::record_data_acoustic_two_fields(it, pt2_cell, msh, hho_di, x_dof, sensor_log2); + postprocessor::record_data_acoustic_two_fields(it, pt3_cell, msh, hho_di, x_dof, sensor_log3); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + } + simulation_tc.toc(); + simulation_log << "Simulation time : " << simulation_tc << " seconds" << std::endl; + simulation_log << "Number of equations : " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Number of DIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOSecondOrder.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOSecondOrder.hpp new file mode 100644 index 00000000..2d64ab5a --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOSecondOrder.hpp @@ -0,0 +1,302 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef HeterogeneousPulseIHHOSecondOrder_hpp +#define HeterogeneousPulseIHHOSecondOrder_hpp + +void HeterogeneousPulseIHHOSecondOrder(char **argv){ + + /////////////////////////////////////////////////////////////////////////////// + ////////////////////////////// Préprocessing ////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + + simulation_data sim_data = preprocessor::process_acoustics_lua_file(argv); + sim_data.print_simulation_data(); + + /////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////// Meshes ////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + mesh_type msh; + if (sim_data.m_polygonal_mesh_Q) { + + auto validate_l = [](size_t l) -> size_t { + if ((0 < l) && (l < 5) ) { + return l; + }else{ + std::cout << "Warning:: Only five meshes available. Running level 4." << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_4096.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_5120.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_10240.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_16384.txt"); + mesh_files.push_back("meshes/mexican_hat_polymesh_nel_65536.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + }else{ + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + /////////////////////////////////////////////////////////////////////////////// + ///////////////////////////// Time controls /////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = tf/nt; + + /////////////////////////////////////////////////////////////////////////////// + ////////////////////////// Source term ? ////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + auto null_fun = [](const mesh_type::point_type& pt) -> RealType { + RealType x,y; + x = pt.x(); + y = pt.y(); + return 0.0; + }; + + auto vel_fun = [](const mesh_type::point_type& pt) -> RealType { + RealType x,y,xc,yc,r,wave; + x = pt.x(); + y = pt.y(); + xc = 0.5; + yc = 0.5; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = 0.1*(-4*std::sqrt(10.0/3.0)*(-1 + 1600.0*r*r))/(std::exp(800*r*r)*std::pow(M_PI,0.25)); + return wave; + }; + + /////////////////////////////////////////////////////////////////////////////// + /// Creating HHO approximation spaces and corresponding linear operator /// + /////////////////////////////////////////////////////////////////////////////// + + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + /////////////////////////////////////////////////////////////////////////////// + //////////////////// Solving a primal HHO mixed problem /////////////////// + /////////////////////////////////////////////////////////////////////////////// + + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); // easy because boundary assumes zero every where any time. + tc.tic(); + auto assembler = acoustic_one_field_assembler(msh, hho_di, bnd); + + /////////////////////////////////////////////////////////////////////////////// + ///////////////////////// Acoustic properties ///////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(2); + RealType rho, vp; + rho = 1.0; + if (y < 0.5) { + vp = 1.0; + }else{ + vp = 1.0; + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,acoustic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + /////////////////////////////////////////////////////////////////////////////// + /////////// Projecting initial scalar, velocity and acceleration ////////// + /////////////////////////////////////////////////////////////////////////////// + + Matrix p_dof_n, v_dof_n, a_dof_n; + assembler.project_over_cells(msh, p_dof_n, null_fun); + assembler.project_over_faces(msh, p_dof_n, null_fun); + assembler.project_over_cells(msh, v_dof_n, vel_fun); + assembler.project_over_faces(msh, v_dof_n, vel_fun); + assembler.project_over_cells(msh, a_dof_n, null_fun); + assembler.project_over_faces(msh, a_dof_n, null_fun); + + ///////////////////////////////////////////////////////////////////////////////// + //////////////////////////// Postprocessing ///////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "inhomogeneous_scalar_"; + postprocessor::write_silo_one_field(silo_file_name, it, msh, hho_di, v_dof_n, vel_fun, false); + } + + std::ofstream simulation_log("inhomogeneous_acoustic_one_field.txt"); + + std::ofstream sensor_log1("sensor1.csv"); + std::ofstream sensor_log2("sensor2.csv"); + std::ofstream sensor_log3("sensor3.csv"); + typename mesh_type::point_type pt1(1.0/3, 2.0/3); + typename mesh_type::point_type pt2(1.0/2, 2.0/3); + typename mesh_type::point_type pt3(2.0/2, 2.0/3); + std::pair pt1_cell = std::make_pair(pt1, -1); + std::pair pt2_cell = std::make_pair(pt2, -1); + std::pair pt3_cell = std::make_pair(pt3, -1); + postprocessor::record_data_acoustic_one_field(0, pt1_cell, msh, hho_di, v_dof_n, sensor_log1); + postprocessor::record_data_acoustic_one_field(0, pt2_cell, msh, hho_di, v_dof_n, sensor_log2); + postprocessor::record_data_acoustic_one_field(0, pt3_cell, msh, hho_di, v_dof_n, sensor_log3); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_one_field(msh, hho_di, assembler, ti, p_dof_n, v_dof_n, simulation_log); + } + + timecounter simulation_tc; + bool standar_Q = true; + + /////////////////////////////////////////////////////////////////////////////// + //////////////////////////// Newmark process ////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + { + Matrix a_dof_np = a_dof_n; + + RealType beta = 0.25; + RealType gamma = 0.5; + if (!standar_Q) { + RealType kappa = 0.25; + gamma = 1.0; + beta = kappa*(gamma+0.5)*(gamma+0.5); + } + + tc.tic(); + assembler.assemble(msh, null_fun); + SparseMatrix Kg = assembler.LHS; + assembler.LHS *= beta*(dt*dt); + assembler.LHS += assembler.MASS; + linear_solver analysis; + if (sim_data.m_sc_Q) { + analysis.set_Kg(assembler.LHS, assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + }else{ + analysis.set_Kg(assembler.LHS); + } + + if (sim_data.m_iterative_solver_Q) { + analysis.set_iterative_solver(true); + }else{ + analysis.set_direct_solver(true); // symmetric matrix case + } + + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + + simulation_tc.tic(); + + + /////////////////////////////////////////////////////////////////////////////// + //////////////////////////// Temporal loop //////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + // Manufactured solution + RealType t = dt*it+ti; + + tc.tic(); + // Compute intermediate state for scalar and rate + p_dof_n = p_dof_n + dt*v_dof_n + 0.5*dt*dt*(1-2.0*beta)*a_dof_n; + v_dof_n = v_dof_n + dt*(1-gamma)*a_dof_n; + Matrix res = Kg*p_dof_n; + + assembler.RHS.setZero(); // Optimization: this is a problem with (f = 0) and (p_D = 0) + assembler.RHS -= res; + tc.toc(); + std::cout << bold << cyan << "Rhs assembly completed: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + a_dof_np = analysis.solve(assembler.RHS); // new acceleration + tc.toc(); + + std::cout << bold << cyan << "Solution completed: " << tc << " seconds" << reset << std::endl; + + // update scalar and rate + p_dof_n += beta*dt*dt*a_dof_np; + v_dof_n += gamma*dt*a_dof_np; + a_dof_n = a_dof_np; + + ///////////////////////////////////////////////////////////////////////////////// + //////////////////////////// Postprocessing ////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////// + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_scalar_"; + postprocessor::write_silo_one_field(silo_file_name, it, msh, hho_di, v_dof_n, vel_fun, false); + } + + postprocessor::record_data_acoustic_one_field(it, pt1_cell, msh, hho_di, v_dof_n, sensor_log1); + postprocessor::record_data_acoustic_one_field(it, pt2_cell, msh, hho_di, v_dof_n, sensor_log2); + postprocessor::record_data_acoustic_one_field(it, pt3_cell, msh, hho_di, v_dof_n, sensor_log3); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_acoustic_energy_one_field(msh, hho_di, assembler, t, p_dof_n, v_dof_n, simulation_log); + } + + //postprocessor::record_velocity_data_acoustic_one_field(it, top_pt_cell, msh, hho_di, v_dof_n, sensor_top_log); + //postprocessor::record_velocity_data_acoustic_one_field(it, bot_pt_cell, msh, hho_di, v_dof_n, sensor_bot_log); + + ///////////////////////////////////////////////////////////////////////////////// + ////////////////////////// Display Terminal ////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////// + } + simulation_tc.toc(); + simulation_log << "Simulation time : " << simulation_tc << " seconds" << std::endl; + simulation_log << "Number of equations : " << analysis.n_equations() << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + } +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/prototype_selector.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/prototype_selector.hpp new file mode 100644 index 00000000..d9cd3f66 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/prototype_selector.hpp @@ -0,0 +1,78 @@ + +// Contributions by Omar Durán and Romain Mottier + +#ifndef prototype_selector_hpp +#define prototype_selector_hpp + +void print_prototype_description(){ +} + +int prototype_selector(char **argv, EAcousticPrototype prototype){ + + switch (prototype) { + + case EAcousticPrototype::OneFieldConvTest: { + EllipticOneFieldConvergenceTest(argv); + } + break; + + case EAcousticPrototype::TwoFieldsConvTest: { + EllipticTwoFieldsConvergenceTest(argv); + } + break; + + case EAcousticPrototype::IOneFieldAcoustic: { + IHHOSecondOrder(argv); + } + break; + + case EAcousticPrototype::ITwoFieldsAcoustic: { + IHHOFirstOrder(argv); + } + break; + + case EAcousticPrototype::ETwoFieldsAcoustic: { + EHHOFirstOrder(argv); + } + break; + + case EAcousticPrototype::Hete1DIOneFieldAcoustic: { + HeterogeneousIHHOSecondOrder(argv); + } + break; + + case EAcousticPrototype::Hete1DITwoFieldsAcoustic: { + HeterogeneousIHHOFirstOrder(argv); + } + break; + + case EAcousticPrototype::Hete1DETwoFieldsAcoustic: { + HeterogeneousEHHOFirstOrder(argv); + } + break; + + case EAcousticPrototype::Hete2DIOneFieldAcoustic: { + HeterogeneousPulseIHHOSecondOrder(argv); + } + break; + + case EAcousticPrototype::Hete2DITwoFieldsAcoustic: { + HeterogeneousPulseIHHOFirstOrder(argv); + } + break; + + case EAcousticPrototype::Hete2DETwoFieldsAcoustic: { + HeterogeneousPulseEHHOFirstOrder(argv); + } + break; + + default: { + throw std::invalid_argument("Prototype not available."); + } + break; + + } + +} + +#endif diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/acoustics.cpp b/apps/wave_propagation/src/prototypes/acoustics_old/acoustics.cpp new file mode 100644 index 00000000..3f21b662 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/acoustics.cpp @@ -0,0 +1,158 @@ + +// Contributions by Omar Durán and Romain Mottier + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +using namespace Eigen; + +#include "timecounter.h" +#include "methods/hho" +#include "geometry/geometry.hpp" +#include "boundary_conditions/boundary_conditions.hpp" +#include "output/silo.hpp" + +// application common sources +#include "../common/display_settings.hpp" +#include "../common/fitted_geometry_builders.hpp" +#include "../common/linear_solver.hpp" +#include "../common/acoustic_material_data.hpp" +#include "../common/scal_analytic_functions.hpp" +#include "../common/preprocessor.hpp" +#include "../common/postprocessor.hpp" + +// implicit RK schemes +#include "../common/dirk_hho_scheme.hpp" +#include "../common/dirk_butcher_tableau.hpp" + +// explicit RK schemes +#include "../common/erk_hho_scheme.hpp" +#include "../common/erk_butcher_tableau.hpp" +#include "../common/ssprk_hho_scheme.hpp" +#include "../common/ssprk_shu_osher_tableau.hpp" + +/// Enumerate defining available function prototypes +enum EAcousticPrototype { + OneFieldConvTest = 0, + TwoFieldsConvTest = 1, + IOneFieldAcoustic = 2, + ITwoFieldsAcoustic = 3, + ETwoFieldsAcoustic = 4, + Hete1DIOneFieldAcoustic = 5, + Hete1DITwoFieldsAcoustic = 6, + Hete1DETwoFieldsAcoustic = 7, + Hete2DIOneFieldAcoustic = 8, + Hete2DITwoFieldsAcoustic = 9, + Hete2DETwoFieldsAcoustic = 10 +}; + +// ----- common data types ------------------------------ +using RealType = double; +typedef disk::mesh> mesh_type; +typedef disk::BoundaryConditions boundary_type; + +//Prototype sources +#include "Prototypes/Elliptic_Conv_Test/EllipticOneFieldConvergenceTest.hpp" +#include "Prototypes/Elliptic_Conv_Test/EllipticTwoFieldsConvergenceTest.hpp" +#include "Prototypes/Acoustic_Conv_Test/IHHOSecondOrder.hpp" +#include "Prototypes/Acoustic_Conv_Test/IHHOFirstOrder.hpp" +#include "Prototypes/Acoustic_Conv_Test/EHHOFirstOrder.hpp" +#include "Prototypes/Heterogeneous/HeterogeneousIHHOSecondOrder.hpp" +#include "Prototypes/Heterogeneous/HeterogeneousIHHOFirstOrder.hpp" +#include "Prototypes/Heterogeneous/HeterogeneousEHHOFirstOrder.hpp" +#include "Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOSecondOrder.hpp" +#include "Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOFirstOrder.hpp" +//#include "Prototypes/Heterogeneous_Pulse/HeterogeneousPulseIHHOFirstOrder2.hpp" +#include "Prototypes/Heterogeneous_Pulse/HeterogeneousPulseEHHOFirstOrder.hpp" +#include "Prototypes/Gar6more_2D/HeterogeneousGar6more2DIHHOSecondOrder.hpp" +#include "Prototypes/Gar6more_2D/HeterogeneousGar6more2DIHHOFirstOrder.hpp" + +#include "Prototypes/prototype_selector.hpp" + +// ----- function prototypes ------------------------------ + +// Convergece tests for elliptic problem +void EllipticOneFieldConvergenceTest(char **argv); +void EllipticTwoFieldsConvergenceTest(char **argv); + +// Convergece tests for the acoustic wave equation +void IHHOSecondOrder(char **argv); +void IHHOFirstOrder(char **argv); +void EHHOFirstOrder(char **argv); + +// Simulation for a heterogeneous acoustics problem +void HeterogeneousIHHOSecondOrder(char **argv); +void HeterogeneousIHHOFirstOrder(char **argv); +void HeterogeneousEHHOFirstOrder(char **argv); + +// Simulation for a heterogeneous acoustics problem on polygonal meshes +void HeterogeneousPulseIHHOSecondOrder(char **argv); +void HeterogeneousPulseIHHOFirstOrder(char **argv); +void HeterogeneousPulseEHHOFirstOrder(char **argv); + +// Comparison with Gar6more2D +void HeterogeneousGar6more2DIHHOSecondOrder(int argc, char **argv); +void HeterogeneousGar6more2DIHHOFirstOrder(int argc, char **argv); + +int prototype_selector(char **argv, EAcousticPrototype prototype); + +void print_prototype_description(); + +int main(int argc, char **argv) { + + HeterogeneousGar6more2DIHHOFirstOrder(argc,argv); + + //EAcousticPrototype prototype; + //const char* const short_opts = "p:h:"; + //const option long_opts[] = { + // {"prototype", required_argument, nullptr, 'p'}, + // {"help", no_argument, nullptr, 'h'}, + // {nullptr, no_argument, nullptr, 0} + //}; + // + //while (true) { + // const auto opt = getopt_long(argc, argv, short_opts, long_opts, nullptr); + // + // if (-1 == opt) + // break; + // + // switch (opt) { + // case 'p': + // prototype = EAcousticPrototype(std::stoi(optarg)); + // break; + // case 'h': + // print_prototype_description(); + // break; + // case '?': + // default: + // throw std::invalid_argument("Invalid option."); + // break; + // } + //} + // + //if (argc != 4) { + // throw std::invalid_argument("Please specify and option and a lua configuration file."); + // return 0; + //} + // + //HeterogeneousGar6more2DIHHOFirstOrder(argc,argv); + + //return prototype_selector(argv, prototype); + +} + diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/input_files/acoustics_simulation.lua b/apps/wave_propagation/src/prototypes/acoustics_old/input_files/acoustics_simulation.lua new file mode 100644 index 00000000..b5f9f820 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/input_files/acoustics_simulation.lua @@ -0,0 +1,13 @@ + +-- The file performs a simulation for a heterogeneous acoustics problem with analytical solution: + +config.fac_k_deg = 3 -- : Face polynomial degree: default 0 +config.num_l_ref = 3 -- : Number of uniform spatial refinements: default 0 +config.num_t_ref = 8 -- : Number of uniform time refinements: default 0 +config.stab_type = 1 -- <0-1>: Stabilization type 0 (HHO), 1 (HDG-like): default 0 +config.stab_scal = 0 -- <0-1>: Stabilization scaling 0 O(1), 1 O(1/h_{f}): default 0 +config.stat_cond = 1 -- <0-1>: Static condensation: default 0 +config.iter_solv = 0 -- <0-1>: Iterative solver : default 0 +config.writ_ener = 1 -- <0-1>: Report energy at each time value : default 0 +config.silo_output = 1 -- <0-1>: Write silo files : default 0 + diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/input_files/acoustics_simulation_2d_pulse.lua b/apps/wave_propagation/src/prototypes/acoustics_old/input_files/acoustics_simulation_2d_pulse.lua new file mode 100644 index 00000000..42464bb4 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/input_files/acoustics_simulation_2d_pulse.lua @@ -0,0 +1,14 @@ + +-- The file performs a simulation for a heterogeneous acoustics problem with analytical solution: + +config.fac_k_deg = 3 -- : Face polynomial degree: default 0 +config.num_l_ref = 1 -- : Number of uniform spatial refinements: default 0 +config.num_t_ref = 7 -- : Number of uniform time refinements: default 0 +config.stab_type = 1 -- <0-1>: Stabilization type 0 (HHO), 1 (HDG-like): default 0 +config.stab_scal = 0 -- <0-1>: Stabilization scaling 0 O(1), 1 O(1/h_{f}): default 0 +config.stat_cond = 1 -- <0-1>: Static condensation: default 0 +config.iter_solv = 0 -- <0-1>: Iterative solver : default 0 +config.writ_ener = 1 -- <0-1>: Report energy at each time value : default 0 +config.poly_mesh = 1 -- <0-1>: Use of polynoal meshes : default 0 +config.silo_output = 1 -- <0-1>: Write silo files : default 0 + diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/input_files/acoustics_test.lua b/apps/wave_propagation/src/prototypes/acoustics_old/input_files/acoustics_test.lua new file mode 100644 index 00000000..a15cf649 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/input_files/acoustics_test.lua @@ -0,0 +1,19 @@ + +-- The file performs a convergence test for the acoustics problem: +-- Exact function types: +-- 0 -> non-polynomial +-- 1 -> quadratic in space +-- 2 -> quadratic in time + +config.fac_k_deg = 3 -- : Face polynomial degree: default 0 +config.num_l_ref = 3 -- : Number of uniform spatial refinements: default 0 +config.num_t_ref = 7 -- : Number of uniform time refinements: default 0 +config.stab_type = 1 -- <0-1>: Stabilization type 0 (HHO), 1 (HDG-like): default 0 +config.stab_scal = 0 -- <0-1>: Stabilization scaling 0 O(1), 1 O(1/h_{f}): default 0 +config.stat_cond = 1 -- <0-1>: Static condensation: default 0 +config.iter_solv = 0 -- <0-1>: Iterative solver : default 0 +config.poly_mesh = 0 -- <0-1>: Use of polynoal meshes : default 0 +config.exac_func = 0 -- <0-2>: Exact function type {0,1,2} : default 0 +config.writ_ener = 1 -- <0-1>: Report energy at each time value : default 0 +config.silo_output = 1 -- <0-1>: Write silo files : default 0 + diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/input_files/elliptic_convergence_test.lua b/apps/wave_propagation/src/prototypes/acoustics_old/input_files/elliptic_convergence_test.lua new file mode 100644 index 00000000..f6d35b67 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustics_old/input_files/elliptic_convergence_test.lua @@ -0,0 +1,15 @@ + +-- The file performs a convergence test for an elliptic problem: +-- The approximation is constructed with implemented +-- assemblers for the acoustic/elastic wave equation + +config.max_k_deg = 4 -- : Maximum face polynomial degree: default 0 +config.max_l_ref = 4 -- : Maximum number of uniform spatial refinements: default 0 +config.stab_type = 0 -- <0-1>: Stabilization type 0 (HHO), 1 (HDG-like): default 0 +config.stab_scal = 1 -- <0-1>: Stabilization scaling 0 O(1), 1 O(1/h_{f}): default 0 +config.stat_cond = 1 -- <0-1>: Static condensation: default 0 +config.iter_solv = 0 -- <0-1>: Iterative solver : default 0 +config.exac_func = 0 -- <0-1>: Manufactured function type 0 (non-polynomial), 1 (quadratic): default 0 +config.poly_mesh = 0 -- <0-1>: Use of polynoal meshes : default 0 +config.silo_output = 0 -- <0-1>: Write silo files : default 0 + diff --git a/apps/wave_propagation/src/prototypes/coupling/Basin/BassinEHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Basin/BassinEHHOFirstOrder.hpp new file mode 100644 index 00000000..093bb51b --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Basin/BassinEHHOFirstOrder.hpp @@ -0,0 +1,423 @@ + +// Created by Romain Mottier + +void BassinEHHOFirstOrder(int argc, char **argv); + +void BassinEHHOFirstOrder(int argc, char **argv){ + + // ###################################################################### + // ###################################################################### Simulation paramaters + // ###################################################################### + + std::cout << std::endl << bold << red << " EXPLICIT SEDIMENTARY BASIN" << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit, cpu; + cpu.tic(); + + // ###################################################################### + // ###################################################################### Mesh generation + // ###################################################################### + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 1) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/basin.txt"); // l = 0 + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_bassin(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc.to_double() << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + // nt *= 2; + nt = sim_data.m_nt_divs; + } + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + auto air_mat_fun = []() -> acoustic_material_data { + double rho, vp; + rho = 1.225; + vp = 343.0; + acoustic_material_data material(rho,vp); + return material; + }; + + auto basin_elastic_mat_fun = []() -> elastic_material_data { + double rho, vp, vs; + rho = 2570.0; + vp = 5350.0; + vs = 3090.0; + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto basin_sediment_mat_fun = []() -> elastic_material_data { + double rho, vp, vs; + rho = 1200.0; + vp = 3400.0; + vs = 1400.0; + elastic_material_data material(rho,vp,vs); + return material; + }; + + // ###################################################################### + // ###################################################################### Structure setting -- A debug + // ###################################################################### + + std::map> basin_e_material; + std::map> basin_a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + if (mesh_builder.polygons[cell_ind].m_material == 1) { + elastic_material_data material = basin_elastic_mat_fun(); + basin_e_material.insert(std::make_pair(cell_ind,material)); + } + if (mesh_builder.polygons[cell_ind].m_material == 2) { + elastic_material_data material = basin_sediment_mat_fun(); + basin_e_material.insert(std::make_pair(cell_ind,material)); + } + if (mesh_builder.polygons[cell_ind].m_material == 3) { + acoustic_material_data material = air_mat_fun(); + basin_a_material.insert(std::make_pair(cell_ind,material)); + } + + } + + // Detect interfaces + disk::connectivity>> conn(msh); + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + auto fc_id = msh.lookup(face); + auto connected_cells = conn.connected_cells(face); + std::vector cell_inds; + std::vector materials; + for (const auto& cell : connected_cells) { + auto cell_ind = msh.lookup(cell); + cell_inds.push_back(cell_ind); + materials.push_back(mesh_builder.polygons[cell_ind].m_material); + } + if (materials[0] == 3) { + if (materials[1] == 1 || materials[1] == 2) { + interface_cell_pair_indexes[fc_id].first = cell_inds[1]; + interface_cell_pair_indexes[fc_id].second = cell_inds[0]; + continue; + } + } + if (materials[1] == 3) { + if (materials[0] == 1 || materials[0] == 2) { + interface_cell_pair_indexes[fc_id].first = cell_inds[0]; + interface_cell_pair_indexes[fc_id].second = cell_inds[1]; + continue; + } + } + } + + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> static_vector { + static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + return sigma; + }; + + // Boundary faces + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + // Detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, basin_e_material, basin_a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc.to_double() << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc.to_double() << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc.to_double() << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Projecting initial data + // ###################################################################### + + auto pulse_basin = [](const disk::mesh>::point_type& pt) -> static_vector { + double x,y,xc,yc,r,wave,vx,vy,c,lp, fc, vp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 750.0; + fc = 25.0; + c = 10; + vp = 5350.0; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + static_vector v{vx,vy}; + return v; + }; + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, pulse_basin, null_flux_fun, null_s_fun, null_fun); + assembler.project_over_faces(msh, x_dof, pulse_basin, null_s_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + + // Solving a first order equation HDG/HHO propagation problem + int s = 3; + Matrix a; + Matrix b; + Matrix c; + erk_butcher_tableau::erk_tables(s, a, b, c); + + std::cout << std::endl << std::endl; + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, true); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + + tc.tic(); + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t face_dofs = assembler.get_n_face_dof(); + + size_t e_cells = assembler.get_elastic_cells(); + size_t a_cells = assembler.get_acoustic_cells(); + size_t n_cells = e_cells + a_cells; + + ////////// Post process of the initial data + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "elasto_acoustic_inhomogeneous_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, basin_e_material, basin_a_material, false); + } + + std::ofstream simulation_log("elasto_acoustic_inhomogeneous_four_fields.txt"); + std::ofstream energy_file("energy_file.txt"); + std::ofstream dissipation_file("dissipation_file.txt"); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elasto_acoustic_energy_four_field_bassin(mesh_builder, msh, hho_di, assembler, t, x_dof, energy_file); + } + + // erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, elastic_cell_dofs, acoustic_cell_dofs, face_dofs); + // erk_an.Kcc_inverse(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + // if (sim_data.m_hdg_stabilization_Q) { + // erk_an.Sff_inverse(std::make_pair(assembler.get_n_faces(), assembler.get_face_basis_data())); + // } + // else { + // if (sim_data.m_iterative_solver_Q) { + // erk_an.setIterativeSolver(); + // } + // erk_an.DecomposeFaceTerm(); + // } + // tc.toc(); + // std::cout << bold << cyan << " ERK analysis created: " << tc << " seconds" << reset << std::endl; + + // erk_an.refresh_faces_unknowns(x_dof); + + // // ################################################## + // // ################################################## Time marching + // // ################################################## + + // std::cout << std::endl << std::endl; + + // Matrix x_dof_n; + + // for(size_t it = 1; it <= nt; it++) { + + + // tcit.tic(); + // std::cout << bold << red << " Time step number " << it << ": t = " << t + // << reset; + + // RealType tn = dt*(it-1)+ti; + + // // ERK step + // tc.tic(); + // { + // size_t n_dof = x_dof.rows(); + // Matrix k = Matrix::Zero(n_dof, s); + // Matrix Fg, Fg_c,xd; + // xd = Matrix::Zero(n_dof, 1); + + // Matrix yn, ki; + + // x_dof_n = x_dof; + // for (int i = 0; i < s; i++) { + // yn = x_dof; + // for (int j = 0; j < s - 1; j++) { + // yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + // } + // erk_an.erk_weight(yn, ki); + // // Accumulated solution + // x_dof_n += dt*b(i,0)*ki; + // k.block(0, i, n_dof, 1) = ki; + // } + // } + // tc.toc(); + // // std::cout << std::endl << bold << cyan << " DIRK step completed: " << tc << " seconds" + // // << reset << std::endl; + + // x_dof = x_dof_n; + + // // ################################################## + // // ################################################## Last postprocess + // // ################################################## + + // if (sim_data.m_render_silo_files_Q) { + // std::string silo_file_name = "elasto_acoustic_inhomogeneous_four_fields_"; + // postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, bassin_e_material, bassin_a_material, false); + // } + + // t += dt; + + // if (sim_data.m_report_energy_Q) { + // postprocessor::compute_elasto_acoustic_energy_four_field_bassin(mesh_builder, msh, hho_di, assembler, t, x_dof, energy_file); + // postprocessor::compute_elasto_acoustic_dissipation_four_field(assembler, t, x_dof, dissipation_file); + // } + + // std::cout << std::endl; + // tcit.toc(); + // std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + + + // } + // sim_data.write_simulation_data(simulation_log); + // simulation_log << "Number of ERK steps = " << s << std::endl; + // simulation_log << "Number of time steps = " << nt << std::endl; + // simulation_log << "Step size = " << dt << std::endl; + // simulation_log.flush(); + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/wave_propagation/src/prototypes/coupling/Basin/BassinIHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Basin/BassinIHHOFirstOrder.hpp new file mode 100644 index 00000000..e4c25dab --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Basin/BassinIHHOFirstOrder.hpp @@ -0,0 +1,519 @@ + + +// Created by Romain Mottier + + +void BassinIHHOFirstOrder(int argc, char **argv); + +void BassinIHHOFirstOrder(int argc, char **argv){ + + // ###################################################################### + // ###################################################################### Simulation paramaters + // ###################################################################### + + std::cout << std::endl << bold << red << " IMPLICIT SEDIMENTARY BASIN" << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit, cpu; + cpu.tic(); + + // ###################################################################### + // ###################################################################### Mesh generation + // ###################################################################### + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 5) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../meshes/basin.txt"); // l = 0 + mesh_files.push_back("../meshes/essai_tris_non_conformes.txt"); // l = 1 + mesh_files.push_back("../meshes/quad_small.txt"); // l = 2 + mesh_files.push_back("../meshes/tri_small.txt"); // l = 3 + mesh_files.push_back("../meshes/strat.txt"); // l = 4 + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_bassin(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) + h = h_l; + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + // nt = sim_data.m_nt_divs; + } + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + auto air_mat_fun = []() -> acoustic_material_data { + double rho, vp; + rho = 1.225; + vp = 343.0; + acoustic_material_data material(rho,vp); + return material; + }; + + auto basin_elastic_mat_fun = []() -> elastic_material_data { + double rho, vp, vs; + rho = 2570.0; + vp = 5350.0; + vs = 3090.0; + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto basin_sediment_mat_fun = []() -> elastic_material_data { + double rho, vp, vs; + rho = 1200.0; + vp = 3400.0; + vs = 1400.0; + elastic_material_data material(rho,vp,vs); + return material; + }; + + // ###################################################################### + // ###################################################################### Structure setting + // ###################################################################### + + std::map> basin_e_material; + std::map> basin_a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + if (mesh_builder.polygons[cell_ind].m_material == 1) { + elastic_material_data material = basin_elastic_mat_fun(); + basin_e_material.insert(std::make_pair(cell_ind,material)); + } + if (mesh_builder.polygons[cell_ind].m_material == 2) { + elastic_material_data material = basin_sediment_mat_fun(); + basin_e_material.insert(std::make_pair(cell_ind,material)); + } + if (mesh_builder.polygons[cell_ind].m_material == 3) { + acoustic_material_data material = air_mat_fun(); + basin_a_material.insert(std::make_pair(cell_ind,material)); + } + + } + + // Detect interfaces + auto conn = disk::connectivity_via_faces(msh); + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + auto fc_id = msh.lookup(face); + auto connected_cells = conn.connected_cells(msh, face); + std::vector cell_inds; + std::vector materials; + for (const auto& cell : connected_cells) { + auto cell_ind = msh.lookup(cell); + cell_inds.push_back(cell_ind); + materials.push_back(mesh_builder.polygons[cell_ind].m_material); + } + + if (materials.size() == 2) { + + if (materials[0] == 3) { + if (materials[1] == 1 || materials[1] == 2) { + interface_cell_pair_indexes[fc_id].first = cell_inds[1]; + interface_cell_pair_indexes[fc_id].second = cell_inds[0]; + // Ajouter la face parcourue a la structure interfaces + continue; + } + } + if (materials[1] == 3) { + if (materials[0] == 1 || materials[0] == 2) { + interface_cell_pair_indexes[fc_id].first = cell_inds[0]; + interface_cell_pair_indexes[fc_id].second = cell_inds[1]; + // Ajouter la face parcourue a la structure interfaces + continue; + } + } + } + + } + + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + // Boundary faces + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + + // Detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, basin_e_material, basin_a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if(sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Projecting initial data + // ###################################################################### + + auto pulse_basin = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x,y,xc,yc,r,wave,vx,vy,c,lp, fc, vp; + x = pt.x(); + y = pt.y(); + xc = -50.0;//-450.0; + yc = 450.0;//600.0; + fc = 4.0; + c = 5;//10; + vp = 5350.0; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + auto v_fun_elastic = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x,y,xc,yc,r,wave,vx,vy,c,lp, fc, vp; + x = pt.x(); + y = pt.y(); + xc = 0.5; + yc = 0.5; + fc = 10.0; + c = 10; + vp = std::sqrt(3.0); + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, pulse_basin, null_flux_fun, null_s_fun, null_fun); + assembler.project_over_faces(msh, x_dof, pulse_basin, null_s_fun); + // assembler.project_over_cells(msh, x_dof, v_fun_elastic, null_flux_fun, null_s_fun, null_fun); + // assembler.project_over_faces(msh, x_dof, v_fun_elastic, null_s_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + } + else { + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, false); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + dirk_an.set_static_condensation_data(vec_cell_basis_data, assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + std::cout << bold << cyan << " Matrix decomposed: "; + tc.tic(); + dirk_an.ComposeMatrix(); + bool iteratif_solver = false; // if false load library: source /opt/intel/oneapi/setvars.sh intel64 + if (iteratif_solver) + dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + } + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "IBasin_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of SDIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::ostringstream filename; + filename << "IBasin_silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, basin_e_material, basin_a_material, false); + } + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + // ################################################## + // ################################################## Sensors + // ################################################## + + bool e_side_Q = true; + bool a_side_Q = false; + + // std::ostringstream filename_acou; + // filename_acou << "A_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + // std::string filename_acou_str = filename_acou.str(); + // std::ofstream Acoustic_sensor_1_log(filename_acou_str); + // typename mesh_type::point_type Acoustic_s1_pt(-450, 1200); + // std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); + + // std::ostringstream filename_int; + // filename_int << "I_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + // std::string filename_int_str = filename_int.str(); + // std::ofstream Interface_sensor_1_log(filename_int_str); + // typename mesh_type::point_type Interface_s1_pt(-500, 0.0); + // std::pair Interface_s1_pt_cell = std::make_pair(Interface_s1_pt, -1); + + // std::ostringstream filename_ela; + // filename_ela << "E_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + // std::string filename_ela_str = filename_ela.str(); + // std::ofstream Elastic_sensor_1_log(filename_ela_str); + // typename mesh_type::point_type Elastic_s1_pt(-500, -250); + // std::pair Elastic_s1_pt_cell = std::make_pair(Elastic_s1_pt, -1); + + // bool sensors = true; + // if (sensors) { + // postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + // } + + std::cout << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + t = tn + c(i,0) * dt; + assembler.RHS.setZero(); // No souce term + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i), is_sdirk_Q); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << " DIRK step completed: " << tc << " seconds" << reset << std::endl; + + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + int silo_mod = static_cast(std::round(nt / 15.0)); // Number of silo files + if ((!sim_data.m_render_silo_files_Q && (it == 1 || it == std::round(nt/2) || it == nt)) || (sim_data.m_render_silo_files_Q && (it%silo_mod == 0))) { + std::ostringstream filename; + filename << "IBasin_silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, basin_e_material, basin_a_material, false); + std::cout << bold << cyan << " Silo file generated" << reset << std::endl; + } + + // if (sensors) { + // postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + // } + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + } + + t += dt; + + tcit.toc(); + std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + + if (it == nt) { + std::ostringstream filename; + filename << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, basin_e_material, basin_a_material, false); + } + + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/wave_propagation/src/prototypes/coupling/Basin/Test.hpp b/apps/wave_propagation/src/prototypes/coupling/Basin/Test.hpp new file mode 100644 index 00000000..dfb00d62 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Basin/Test.hpp @@ -0,0 +1,484 @@ + +// Created by Romain Mottier + +void Test_Laurent(int argc, char **argv); + +void Test_Laurent(int argc, char **argv){ + + // ###################################################################### + // ###################################################################### Simulation paramaters + // ###################################################################### + + std::cout << std::endl << bold << red << " IMPLICIT SEDIMENTARY BASIN" << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit, cpu; + cpu.tic(); + + // ###################################################################### + // ###################################################################### Mesh generation + // ###################################################################### + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 2) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/test_Laurent.txt"); // l = 0 + mesh_files.push_back("../../meshes/square2.txt"); // l = 1 + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_bassin(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc.to_double() << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + // nt = sim_data.m_nt_divs; + } + + RealType ti = 0.0; + RealType tf = 1.5; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + auto air_mat_fun = []() -> acoustic_material_data { + double rho, vp; + rho = 1.225; + vp = 330.0; + acoustic_material_data material(rho,vp); + return material; + }; + + auto basin_elastic_mat_fun = []() -> elastic_material_data { + double rho, vp, vs; + rho = 2570.0; + vp = 5350.0; + vs = 3009.0; + elastic_material_data material(rho,vp,vs); + return material; + }; + + // ###################################################################### + // ###################################################################### Structure setting + // ###################################################################### + + std::map> basin_e_material; + std::map> basin_a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + if (mesh_builder.polygons[cell_ind].m_material == 1) { + elastic_material_data material = basin_elastic_mat_fun(); + basin_e_material.insert(std::make_pair(cell_ind,material)); + } + if (mesh_builder.polygons[cell_ind].m_material == 2) { + acoustic_material_data material = air_mat_fun(); + // elastic_material_data material = basin_elastic_mat_fun(); + basin_a_material.insert(std::make_pair(cell_ind,material)); + // basin_e_material.insert(std::make_pair(cell_ind,material)); + } + + } + + // Detect interfaces + disk::connectivity>> conn(msh); + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + auto fc_id = msh.lookup(face); + auto connected_cells = conn.connected_cells(face); + std::vector cell_inds; + std::vector materials; + for (const auto& cell : connected_cells) { + auto cell_ind = msh.lookup(cell); + cell_inds.push_back(cell_ind); + materials.push_back(mesh_builder.polygons[cell_ind].m_material); + } + if (materials[0] == 2) { + if (materials[1] == 1 || materials[1] == 2) { + interface_cell_pair_indexes[fc_id].first = cell_inds[1]; + interface_cell_pair_indexes[fc_id].second = cell_inds[0]; + continue; + } + } + if (materials[1] == 2) { + if (materials[0] == 1 || materials[0] == 2) { + interface_cell_pair_indexes[fc_id].first = cell_inds[0]; + interface_cell_pair_indexes[fc_id].second = cell_inds[1]; + continue; + } + } + } + + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> static_vector { + static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + return sigma; + }; + + // Boundary faces + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + // Detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, basin_e_material, basin_a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc.to_double() << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc.to_double() << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc.to_double() << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Projecting initial data + // ###################################################################### + + auto pulse_basin = [](const disk::mesh>::point_type& pt) -> static_vector { + double x,y,xc,yc,r,wave,vx,vy,c,lp, fc, vp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = -4000.0; + c = 1; + vp = 5350.0; + lp = 3566; + fc = vp/lp; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + static_vector v{vx,vy}; + return v; + }; + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, pulse_basin, null_flux_fun, null_s_fun, null_fun); + assembler.project_over_faces(msh, x_dof, pulse_basin, null_s_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + if (is_sdirk_Q) + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + else + dirk_butcher_tableau::dirk_tables(s, a, b, c); + + + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, false); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + dirk_an.set_static_condensation_data(vec_cell_basis_data, assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + std::cout << bold << cyan << " Matrix decomposed: "; + tc.tic(); + dirk_an.ComposeMatrix(); + bool iteratif_solver = false; // if false load library: source /opt/intel/oneapi/setvars.sh intel64 + if (iteratif_solver) { + dirk_an.setIterativeSolver(); + } + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + } + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "IBasin_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of SDIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::ostringstream filename; + filename << "IBasin_silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, basin_e_material, basin_a_material, false); + } + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + } + + // ################################################## + // ################################################## Sensors + // ################################################## + + bool e_side_Q = true; + bool a_side_Q = false; + + std::ostringstream filename_acou; + filename_acou << "A_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str = filename_acou.str(); + std::ofstream Acoustic_sensor_1_log(filename_acou_str); + typename mesh_type::point_type Acoustic_s1_pt(0, 50); + std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); + + std::ostringstream filename_int; + filename_int << "I_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_int_str = filename_int.str(); + std::ofstream Interface_sensor_1_log(filename_int_str); + typename mesh_type::point_type Interface_s1_pt(0.0, 0.0); + std::pair Interface_s1_pt_cell = std::make_pair(Interface_s1_pt, -1); + + std::ostringstream filename_ela; + filename_ela << "S1_E_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str = filename_ela.str(); + std::ofstream Elastic_sensor_1_log(filename_ela_str); + typename mesh_type::point_type Elastic_s1_pt(0.0, -300.0); + std::pair Elastic_s1_pt_cell = std::make_pair(Elastic_s1_pt, -1); + + std::ostringstream filename_ela2; + filename_ela2 << "S2_E_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str2 = filename_ela2.str(); + std::ofstream Elastic_sensor_2_log(filename_ela_str2); + typename mesh_type::point_type Elastic_s2_pt(3000, -4000); + std::pair Elastic_s2_pt_cell = std::make_pair(Elastic_s2_pt, -1); + + bool sensors = true; + if (sensors) { + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + } + + std::cout << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + t = tn + c(i,0) * dt; + assembler.RHS.setZero(); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << " DIRK step completed: " << tc << " seconds" << reset << std::endl; + + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + if (sim_data.m_render_silo_files_Q) { + std::ostringstream filename; + filename << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, basin_e_material, basin_a_material, false); + } + + if (sensors) { + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log ); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log ); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log ); + } + + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + t += dt; + + tcit.toc(); + std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + + if (it == nt) { + std::ostringstream filename; + filename << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, basin_e_material, basin_a_material, false); + } + + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/wave_propagation/src/prototypes/coupling/CFL/EHHOFirstOrderCFL.hpp b/apps/wave_propagation/src/prototypes/coupling/CFL/EHHOFirstOrderCFL.hpp new file mode 100644 index 00000000..e5bcfc75 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/CFL/EHHOFirstOrderCFL.hpp @@ -0,0 +1,439 @@ + +// Created by Romain Mottier +// ../wave_propagation -k 1 -s 0 -r 0 -c 1 -p 0 -l 2 -n 350 -f 0 -e 0 +// BE CAREFUL ON THE CHOICE OF THE WEIGHTING IN FRONT OF THE STAB: elastoacoustic_four_field.hpp + +void EHHOFirstOrderCFL(int argc, char **argv); + +void EHHOFirstOrderCFL(int argc, char **argv) { + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " COUPLING CFL" << std::endl << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc; + + // ################################################## + // ################################################## Time controls + // ################################################## + + RealType ti = 0.0; + RealType tf = 1.0; + RealType t = ti; + int nt_base = sim_data.m_nt_divs; + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial_paper); + + // Zero source terms, to keep the system energy constant + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + // Elastic analytical functions + // auto v_fun = null_fun; + // auto flux_fun = null_flux_fun; + auto v_fun = functions.Evaluate_v(t); + auto flux_fun = functions.Evaluate_sigma(t); + // Acoustic analytical functions + // auto s_v_fun = null_s_fun; + // auto s_flux_fun = null_fun; + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ################################################## + // ################################################## HHO setting + // ################################################## + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) + return l; + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l0_conv_test_1.0.txt"); // l = 0 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l1_conv_test_0.35.txt"); // + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l2_conv_test_0.15.txt"); // l = 2 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l3_conv_test_0.07.txt"); // + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l4_conv_test_0.035.txt"); // l = 4 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l5_conv_test_0.026.txt"); // + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l6_conv_test_0.017.txt"); // l = 6 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l7_conv_test_0.0125.txt"); // + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l8_conv_test_0.0085.txt"); // l = 8 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l9_conv_test_0.005.txt"); // + + mesh_files.push_back("../../meshes/conv_test/poly/poly_32.txt"); + mesh_files.push_back("../../meshes/conv_test/poly/poly_64.txt"); // -l 1 + mesh_files.push_back("../../meshes/conv_test/poly/poly_128.txt"); + mesh_files.push_back("../../meshes/conv_test/poly/poly_256.txt"); // -l 3 + mesh_files.push_back("../../meshes/conv_test/poly/poly_512.txt"); + mesh_files.push_back("../../meshes/conv_test/poly/poly_1024.txt"); // -l 5 + mesh_files.push_back("../../meshes/conv_test/poly/poly_2048.txt"); + mesh_files.push_back("../../meshes/conv_test/poly/poly_4096.txt"); // -l 7 + mesh_files.push_back("../../meshes/conv_test/poly/poly_8192.txt"); + mesh_files.push_back("../../meshes/conv_test/poly/poly_16384.txt"); // -l 9 + mesh_files.push_back("../../meshes/conv_test/poly/poly_32768.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter_bis(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) + h = h_l; + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl << std::endl; + + // ################################################## + // ################################################## Material data + // ################################################## + + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ################################################## + // ################################################## Interface detection and faces repartitions + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + RealType eps = 1.0e-10; + + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++){ + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.x()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + if (bar.x() > 0) { + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.x() > 0) { + interface_cell_pair_indexes[fc_id].second = cell_ind; + } + else { + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + } + + // Internal faces structure for explicit schemes + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + } + else { + if (bar.y() > 0) { + acoustic_internal_faces.insert(fc_id); + } + else { + elastic_internal_faces.insert(fc_id); + } + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.x() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + + // detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ######################s########################### + + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if (sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + assembler.assemble_mass(msh); + assembler.assemble_coupling_terms(msh); + + // ################################################## + // ################################################## Setting of the time marching scheme + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, null_fun); + assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + bool explicit_scheme = true; + assembler.assemble(msh, null_fun, null_s_fun, explicit_scheme); + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes); + erk_an.refresh_faces_unknowns(x_dof); + + // ################################################## + // ################################################## Loop over the ERK schemes + // ################################################## + + for (int s = 2; s < 5; s++) { + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt = sim_data.m_nt_divs; + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "E_explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + auto energy_0 = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + std::cout << bold << red << " ERK(" << s << "):" << reset << std::endl << std::endl; + simulation_log << std::endl << " ERK(" << s << "):" << std::endl; + simulation_log << std::endl; + + // ################################################## + // ################################################## Loop over level of time refinement + // ################################################## + + for (unsigned int i = 0; i < 1000; i++) { + + t = ti; + RealType dt = (tf-ti)/nt; + simulation_log << "Step size = " << dt << std::endl; + + energy_0 = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + // Projecting initial data + assembler.project_over_cells(msh, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, v_fun, s_v_fun); + + auto energy_0 = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + erk_butcher_tableau::erk_tables(s, a, b, c); + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + bool approx_fail_check_Q = false; + RealType energy = energy_0; + + for(size_t it = 1; it <= nt; it++) { + + RealType tn = dt*(it-1)+ti; + + // ERK steps + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + Matrix yn, ki; + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + RealType t = tn + c(i,0) * dt; + assembler.assemble_rhs(msh, null_fun, null_s_fun, true); + erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + x_dof = x_dof_n; + t = tn + dt; + RealType energy_n = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + RealType relative_energy = (energy_n - energy) / energy; + RealType relative_energy_0 = (energy_n - energy_0) / energy_0; + // bool unstable_check_Q = (relative_energy > 5.0e-2) || (relative_energy_0 >= 5.0e-2); + bool unstable_check_Q = (relative_energy > 15e-2) || (relative_energy_0 >= 15e-2); + if (unstable_check_Q) { // energy is increasing + approx_fail_check_Q = true; + break; + } + energy = energy_n; + } + if (approx_fail_check_Q) { + std::cout << bold << red << " Simulation is unstable" << reset << std::endl << std::endl << std::endl; + simulation_log << std::endl; + simulation_log << " Simulation is unstable for:"<< std::endl; + simulation_log << " Number of equations: " << assembler.RHS.rows() << std::endl; + simulation_log << " Number of ERK steps = " << s << std::endl; + simulation_log << " Number of time steps = " << nt << std::endl; + simulation_log << " dt size = " << dt << std::endl; + simulation_log << " h size = " << h << std::endl; + simulation_log << " CFL c(dt/h) = " << std::sqrt(3.0)*dt/h << std::endl; + simulation_log << std::endl; + simulation_log.flush(); + break; + } + else { + simulation_log << " Simulation is stable for:"<< std::endl; + simulation_log << " Number of equations: " << assembler.RHS.rows() << std::endl; + simulation_log << " Number of ERK steps = " << s << std::endl; + simulation_log << " Number of time steps = " << nt << std::endl; + simulation_log << " dt size = " << dt << std::endl; + simulation_log << " h size = " << h << std::endl; + simulation_log << " CFL c(dt/h) = " << std::sqrt(3.0)*dt/h << std::endl; + simulation_log << std::endl; + simulation_log.flush(); + std::cout << " Simulation is stable for: n = " << nt << std::endl; + nt = int(nt - (nt*1/100+1)); + continue; + // break; + + } + } + simulation_log << std::endl << " ******************************* " << std::endl; + simulation_log << std::endl << std::endl; + } + } diff --git a/apps/wave_propagation/src/prototypes/coupling/CFL/HeterogeneousEHHOFirstOrderCFL.hpp b/apps/wave_propagation/src/prototypes/coupling/CFL/HeterogeneousEHHOFirstOrderCFL.hpp new file mode 100644 index 00000000..9a0bac5b --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/CFL/HeterogeneousEHHOFirstOrderCFL.hpp @@ -0,0 +1,470 @@ + + +// Created by Romain Mottier + +void HeterogeneousEHHOFirstOrderCFL(int argc, char **argv); + +void HeterogeneousEHHOFirstOrderCFL(int argc, char **argv){ + + // ###################################################################### Simulation paramaters + // ###################################################################### + + std::cout << std::endl << bold << red << " EXPLICIT PULSE - CFL" << std::endl << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit, cpu; + cpu.tic(); + + // ###################################################################### Mesh generation + // ###################################################################### + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l2_0.4.txt"); // l = 0 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l3_0.21.txt"); // l = 1 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l4_0.096.txt"); // l = 2 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l5_0.0485.txt"); // l = 3 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l6_0.024.txt"); // l = 4 + + // mesh_files.push_back("../../meshes/pulse/poly/poly_l2.txt"); // -l 0 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l3.txt"); // -l 1 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l4.txt"); // -l 2 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l5.txt"); // -l 3 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l6.txt"); // -l 4 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l7.txt"); // -l 5 + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 1; + RealType ly = 1; + size_t nx = 2; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-0.5, -0.5); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + // nt *= 2; + nt = sim_data.m_nt_divs; + } + RealType ti = 0.0; + RealType tf = 0.25; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // Loop over level of time step option -n + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + + RealType dt = (tf-ti)/nt; + + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ###################################################################### Assigning Material Data + // ###################################################################### + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.y()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + + // Assigning the material properties + if (bar.y() > 0) { + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.y() > 0) { + interface_cell_pair_indexes[fc_id].second = cell_ind; + // interface_face_pair_indexes[fc_id].second = cp_fc; + } + else { + interface_cell_pair_indexes[fc_id].first = cell_ind; + // interface_face_pair_indexes[fc_id].first = cp_fc; + } + } + // cp_fc = cp_fc + 1; + } + + } + + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + } + else { + if (bar.y() > 0) { + acoustic_internal_faces.insert(fc_id); + // std::cout << fc_id << std::endl; + } + else { + elastic_internal_faces.insert(fc_id); + // std::cout << fc_id << std::endl; + } + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.y() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + + // Detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ###################################################################### Solving a primal HHO mixed problem + // ###################################################################### + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + + // Stabilization type + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + // ###################################################################### Projecting initial data + // ###################################################################### + + Matrix x_dof; + + // Acoustic pulse intialized in velocity + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, v_fun_adi_acoustic); + assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + + // Elastic pulse intialized in velocity + // assembler.project_over_cells(msh, x_dof, v_fun_adi, null_flux_fun, null_s_fun, null_fun); + // assembler.project_over_faces(msh, x_dof, v_fun_adi, null_s_fun); + + ////////// Post process of the initial data + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "elasto_acoustic_inhomogeneous_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // ERK(s) schemes + int s = 2; + erk_butcher_tableau::erk_tables(s, a, b, c); + + std::cout << std::endl << std::endl; + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, true); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + + + if(sim_data.m_hdg_stabilization_Q) { + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes); + } + else { + erk_an.DecomposeFaceTerm(); + } + tc.toc(); + std::cout << bold << cyan << " ERK analysis created: " << tc << " seconds" << reset << std::endl; + tc.tic(); + erk_an.refresh_faces_unknowns(x_dof); + tc.toc(); + std::cout << bold << cyan << " Inverse of Sff + Coupling in: " << tc << " seconds" << reset << std::endl << std::endl; + + std::cout << bold << red << " CFL (dt/h) = " << dt/(lx/mesh_builder.get_nx()) << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + std::cout << std::endl << std::endl; + + Matrix x_dof_n; + + dt = (tf-ti)/nt; + t = ti; + + bool approx_fail_check_Q = false; + bool fail_check_Q = false; + + std::ofstream energy_file("energy_file.txt"); + auto energy_0 = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + RealType energy = energy_0; + + for(size_t it = 1; it <= nt; it++) { + + RealType tn = dt*(it-1)+ti; + + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + erk_an.erk_weight(yn, ki); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + + // for (int i = 0; i < elastic_cell_dofs; ++i) { + // for (int j = 0; j < x_dof_n.cols(); ++j) { + // std::cout << std::setw(4) << x_dof_n(i, j) << " "; + // } + // std::cout << std::endl; + // } + // std::cout << std::endl << std::endl << std::endl << std::endl; + + } + } + tc.toc(); + // std::cout << bold << cyan << " ERK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + + RealType energy_n = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + RealType relative_energy = (energy_n - energy) / energy; + RealType relative_energy_0 = (energy_n - energy_0) / energy_0; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "elasto_acoustic_inhomogeneous_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + t += dt; + + bool unstable_check_Q = (relative_energy > 1e-2) || (relative_energy_0 >= 0.5e-2); + // bool dissipation_check_Q = (relative_energy < -15e-2) || (relative_energy_0 <= -15e-2); + + // if (dissipation_check_Q) { // energy is increasing + // fail_check_Q = true; + // break; + // } + + if (unstable_check_Q) { // energy is increasing + approx_fail_check_Q = true; + break; + } + + energy = energy_n; + + } + + // if (fail_check_Q) { + // std::cout << bold << red << " Simulation dissipates too much energy" << reset << std::endl; + // break; + // } + + if (approx_fail_check_Q) { + std::cout << bold << red << " Simulation is unstable" << reset << std::endl << std::endl; + simulation_log << std::endl; + simulation_log << " Simulation is unstable for :"<< std::endl; + simulation_log << " Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << " Number of ERK steps = " << s << std::endl; + simulation_log << " Number of time steps = " << nt << std::endl; + simulation_log << " dt size = " << dt << std::endl; + simulation_log << " h size = " << lx/mesh_builder.get_nx() << std::endl; + simulation_log << " CFL (dt/h) = " << dt/(lx/mesh_builder.get_nx()) << std::endl; + simulation_log << std::endl; + simulation_log.flush(); + break; + } + else { + simulation_log << " Simulation is stable for :"<< std::endl; + simulation_log << " Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << " Number of ERK steps = " << s << std::endl; + simulation_log << " Number of time steps = " << nt << std::endl; + simulation_log << " dt size = " << dt << std::endl; + simulation_log << " h size = " << lx/mesh_builder.get_nx() << std::endl; + simulation_log << " CFL (dt/h) = " << dt/(lx/mesh_builder.get_nx()) << std::endl; + simulation_log << std::endl; + simulation_log.flush(); + std::cout << bold << red << "Simulation is stable for: " << nt << reset << std::endl << std::endl; + nt -= 10; + std::cout << bold << red << "Number of time steps: " << nt << reset << std::endl << std::endl; + continue; + } + + } + + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/EHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/EHHOFirstOrder.hpp new file mode 100644 index 00000000..f4d9a17f --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/EHHOFirstOrder.hpp @@ -0,0 +1,426 @@ + + +// Created by Romain Mottier + +// ../../elastoacoustic -k 1 -s 0 -r 0 -c 1 -p 1 -l 8 -n 1000 -f 0 -e 0 +void EHHOFirstOrder(int argc, char **argv); + +void EHHOFirstOrder(int argc, char **argv){ + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " EXPLICIT COUPLING CONV TEST" << reset << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, cpu; + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + cpu.tic(); + tc.tic(); + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + size_t l = sim_data.m_n_divs; + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + { // Simplicial meshes + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l0_conv_test_1.0.txt"); // l = 0 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l1_conv_test_0.35.txt"); // l = 1 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l2_conv_test_0.15.txt"); // l = 2 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l3_conv_test_0.07.txt"); // l = 3 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l4_conv_test_0.035.txt"); // l = 4 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l5_conv_test_0.026.txt"); // l = 5 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l6_conv_test_0.017.txt"); // l = 6 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l7_conv_test_0.0125.txt"); // l = 7 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l8_conv_test_0.0085.txt"); // l = 8 + // mesh_files.push_back("../../../../../meshes/conv_test/simplices/unstructured/l9_conv_test_0.005.txt"); // l = 9 + } + { // Polyhedral meshes + mesh_files.push_back("../../../../../meshes/conv_test/poly/poly_32.txt"); // -l 0 + mesh_files.push_back("../../../../../meshes/conv_test/poly/poly_64.txt"); // -l 1 + mesh_files.push_back("../../../../../meshes/conv_test/poly/poly_128.txt"); // -l 2 + mesh_files.push_back("../../../../../meshes/conv_test/poly/poly_256.txt"); // -l 3 + mesh_files.push_back("../../../../../meshes/conv_test/poly/poly_512.txt"); // -l 4 + mesh_files.push_back("../../../../../meshes/conv_test/poly/poly_1024.txt"); // -l 5 + mesh_files.push_back("../../../../../meshes/conv_test/poly/poly_2048.txt"); // -l 6 + mesh_files.push_back("../../../../../meshes/conv_test/poly/poly_4096.txt"); // -l 7 + mesh_files.push_back("../../../../../meshes/conv_test/poly/poly_8192.txt"); // -l 8 + mesh_files.push_back("../../../../../meshes/conv_test/poly/poly_16384.txt"); // -l 9 + } + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) + h = h_l; + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl << std::endl; + + // ################################################## + // ################################################## Time controls + // ################################################## + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt = sim_data.m_nt_divs; + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial_paper); + + // Elastic analytical functions + auto u_fun = functions.Evaluate_u(t); + auto v_fun = functions.Evaluate_v(t); + auto a_fun = functions.Evaluate_a(t); + auto f_fun = functions.Evaluate_f(t); + auto flux_fun = functions.Evaluate_sigma(t); + + // Acoustic analytical functions + auto s_u_fun = functions.Evaluate_s_u(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_a_fun = functions.Evaluate_s_a(t); + auto s_f_fun = functions.Evaluate_s_f(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ################################################## + // ################################################## HHO setting + // ################################################## + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ################################################## + // ################################################## Structure setting + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++){ + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.x()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + if (bar.x() > 0) { + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.x() > 0) + interface_cell_pair_indexes[fc_id].second = cell_ind; + else + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.y() > 0) + acoustic_internal_faces.insert(fc_id); + else + elastic_internal_faces.insert(fc_id); + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.x() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + // Detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, u_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, s_u_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_coupling_stabilization(); + if(sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + + // DISCRTIZATION INFOS + std::cout << bold << red << " DISCRETIZATION: "; + std::cout << cyan << "Cell degree = " << hho_di.cell_degree() << std::endl; + std::cout << bold << cyan << " Face degree = " << hho_di.face_degree() << reset << std::endl << std::endl << std::endl; + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl << std::endl; + + // ################################################## + // ################################################## Projecting initial data + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, v_fun, s_v_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // ERK schemes + int s = 2; + erk_butcher_tableau::erk_tables(s, a, b, c); + + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, f_fun, s_f_fun, true); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes);//assembler.get_interfaces()); + + tc.toc(); + std::cout << bold << cyan << " ERK analysis created: " << tc << " seconds" << reset << std::endl; + tc.tic(); + erk_an.refresh_faces_unknowns(x_dof); + tc.toc(); + std::cout << bold << cyan << " Inverse of Sff + Coupling in: " << tc << " seconds" << reset << std::endl; + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + // auto block_dimension = assembler.Scc_block_dimension(); + // erk_an.compute_eigenvalues_bis(assembler.LHS_STAB, block_dimension, simulation_log); + // erk_an.compute_eigenvalues(simulation_log); + simulation_log.flush(); + std::cout << std::endl << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + std::cout << bold << red << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + x_dof_n = x_dof; + + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + t = tn + c(i,0) * dt; + + { + // Manufactured solution + auto v_fun = functions.Evaluate_v(t); + auto f_fun = functions.Evaluate_f(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_f_fun = functions.Evaluate_s_f(t); + + assembler.get_e_bc_conditions().updateDirichletFunction(v_fun, 0); + assembler.get_a_bc_conditions().updateDirichletFunction(s_v_fun, 0); + assembler.assemble_rhs(msh, f_fun, s_f_fun, true); + erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + } + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + + tc.toc(); + std::cout << bold << cyan << " ERK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + t = tn + dt; + auto v_fun = functions.Evaluate_v(t); + auto flux_fun = functions.Evaluate_sigma(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + if(it == nt){ + std::cout << std::endl; + postprocessor::compute_errors_four_fields_elastoacoustic(msh, hho_di, assembler, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun, simulation_log); + postprocessor::compute_errors_four_fields_elastoacoustic_energy_norm(msh, hho_di, assembler, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun, simulation_log); + } + + std::cout << std::endl; + + } + + bool mesh_quality = false; + if (mesh_quality) { + std::ofstream mesh_file("mesh_file.txt"); + postprocessor::mesh_quality(msh, assembler, mesh_file); + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + diff --git a/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/EHHOFirstOrder_conv_tests.hpp b/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/EHHOFirstOrder_conv_tests.hpp new file mode 100644 index 00000000..f9d4a4c2 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/EHHOFirstOrder_conv_tests.hpp @@ -0,0 +1,373 @@ + + +// Created by Romain Mottier + +// ../../elastoacoustic -k 4 -s 0 -r 0 -c 1 -p 1 -l 9 -n 2000 -f 0 -e 0 + +void EHHOFirstOrder_conv_tests(int argc, char **argv); + +void EHHOFirstOrder_conv_tests(int argc, char **argv){ + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " EXPLICIT COUPLING CONV TEST" << reset << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // ################################################## + // ################################################## HHO setting + // ################################################## + + for (size_t k = 1; k <= sim_data.m_k_degree; k++) { + + std::cout << std::endl << bold << red << " Polynomial degree k : " << k << reset << std::endl; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = k; + if (sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + disk::hho_degree_info hho_di(cell_k_degree, k); + + // ################################################## + // ################################################## Loop over level of space refinement + // ################################################## + + for (size_t l = 0; l <= sim_data.m_n_divs; l++) { + + std::cout << bold << cyan << " Space refinment level -l : " << l << reset << std::endl; + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + // Mesh availability + auto validate_l = [](size_t l) -> size_t { + if (!((0 <= l) && (l < 15))) { + std::cout << std::endl << std::endl; + std::cout << bold << red << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + // size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + // Simplicial meshes + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l0_conv_test_1.0.txt"); // l = 0 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l1_conv_test_0.35.txt"); // + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l2_conv_test_0.15.txt"); // l = 2 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l3_conv_test_0.07.txt"); // + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l4_conv_test_0.035.txt"); // l = 4 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l5_conv_test_0.026.txt"); // + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l6_conv_test_0.017.txt"); // l = 6 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l7_conv_test_0.0125.txt"); // + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l8_conv_test_0.0085.txt"); // l = 8 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l9_conv_test_0.005.txt"); // + // Polyhedral meshes + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_32.txt"); // -l 0 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_64.txt"); // -l 1 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_128.txt"); // -l 2 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_256.txt"); // -l 3 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_512.txt"); // -l 4 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_1024.txt"); // -l 5 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_2048.txt"); // -l 6 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_4096.txt"); // -l 7 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_8192.txt"); // -l 8 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_16384.txt"); // -l 9 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_32768.txt"); // -l 10 + // Reading the mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) + h = h_l; + } + + // ################################################## + // ################################################## Time discretization infos + // ################################################## + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt = sim_data.m_nt_divs; + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ERK schemes + Matrix a; + Matrix b; + Matrix c; + int s = 4; + erk_butcher_tableau::erk_tables(s, a, b, c); + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial_paper); + + // Elastic analytical functions + auto u_fun = functions.Evaluate_u(t); + auto v_fun = functions.Evaluate_v(t); + auto a_fun = functions.Evaluate_a(t); + auto f_fun = functions.Evaluate_f(t); + auto flux_fun = functions.Evaluate_sigma(t); + + // Acoustic analytical functions + auto s_u_fun = functions.Evaluate_s_u(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_a_fun = functions.Evaluate_s_a(t); + auto s_f_fun = functions.Evaluate_s_f(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ################################################## + // ################################################## Material data + // ################################################## + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ################################################## + // ################################################## Structure setting + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++){ + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.x()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + if (bar.x() > 0) { + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.x() > 0) + interface_cell_pair_indexes[fc_id].second = cell_ind; + else + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (!is_member_Q) { + if (bar.y() > 0) + acoustic_internal_faces.insert(fc_id); + else + elastic_internal_faces.insert(fc_id); + } + } + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.x() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, u_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, s_u_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_coupling_stabilization(); + if (sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + assembler.assemble_mass(msh); + assembler.assemble_coupling_terms(msh); + + // ################################################## + // ################################################## Projecting initial data + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, v_fun, s_v_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + assembler.assemble(msh, f_fun, s_f_fun, true); + assembler.LHS += assembler.COUPLING; + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes); + erk_an.refresh_faces_unknowns(x_dof); + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "explicit_l_" << l << "_n_" << sim_data.m_nt_divs << "_k_" << k << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + RealType tn = dt*(it-1)+ti; + // ERK step + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + Matrix yn, ki; + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + t = tn + c(i,0) * dt; + {// Manufactured solution + auto v_fun = functions.Evaluate_v(t); + auto f_fun = functions.Evaluate_f(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_f_fun = functions.Evaluate_s_f(t); + assembler.get_e_bc_conditions().updateDirichletFunction(v_fun, 0); + assembler.get_a_bc_conditions().updateDirichletFunction(s_v_fun, 0); + assembler.assemble_rhs(msh, f_fun, s_f_fun, true); + erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + } + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + x_dof = x_dof_n; + t = tn + dt; + auto v_fun = functions.Evaluate_v(t); + auto flux_fun = functions.Evaluate_sigma(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + if (it == nt) { + postprocessor::compute_errors_four_fields_elastoacoustic(msh, hho_di, assembler, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun, simulation_log); + postprocessor::compute_errors_four_fields_elastoacoustic_energy_norm(msh, hho_di, assembler, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun, simulation_log); + } + } + bool mesh_quality = true; + if (mesh_quality) { + std::ostringstream filename_mesh_quality; + filename_mesh_quality << "mesh_quality_l_" << l << ".txt"; + std::string filename_str = filename_mesh_quality.str(); + std::ofstream mesh_file(filename_str); + postprocessor::mesh_quality(msh, assembler, mesh_file); + } + } + } + std::cout << std::endl << std::endl; +} + diff --git a/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder.hpp new file mode 100644 index 00000000..161f442f --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder.hpp @@ -0,0 +1,443 @@ + + +// Created by Romain Mottier + +void IHHOFirstOrder(int argc, char **argv); + +void IHHOFirstOrder(int argc, char **argv){ + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " IMPLICIT COUPLING CONV TEST" << reset << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, cpu; + cpu.tic(); + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + mesh_files.push_back("../../meshes/conv_test/poly_bad_bad_quality/poly_32.txt"); // -l 0 + mesh_files.push_back("../../meshes/conv_test/poly_bad_bad_quality/poly_64.txt"); // -l 1 + mesh_files.push_back("../../meshes/conv_test/poly_bad_bad_quality/poly_128.txt"); // -l 2 + mesh_files.push_back("../../meshes/conv_test/poly_bad_bad_quality/poly_256.txt"); // -l 3 + mesh_files.push_back("../../meshes/conv_test/poly_bad_bad_quality/poly_512.txt"); // -l 4 + mesh_files.push_back("../../meshes/conv_test/poly_bad_bad_quality/poly_1024.txt"); // -l 5 + mesh_files.push_back("../../meshes/conv_test/poly_bad_bad_quality/poly_2048.txt"); // -l 6 + mesh_files.push_back("../../meshes/conv_test/poly_bad_bad_quality/poly_4096.txt"); // -l 7 + mesh_files.push_back("../../meshes/conv_test/poly_bad_bad_quality/poly_8192.txt"); // -l 8 + mesh_files.push_back("../../meshes/conv_test/poly_bad_bad_quality/poly_16384.txt"); // -l 9 + mesh_files.push_back("../../meshes/essai_CV2.txt"); // -l 10 + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << std::endl << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl << std::endl; + + // ################################################## + // ################################################## Time controls + // ################################################## + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + // nt *= 2; + nt = sim_data.m_nt_divs; + } + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial_paper); + + // Elastic analytical functions + auto u_fun = functions.Evaluate_u(t); + auto v_fun = functions.Evaluate_v(t); + auto a_fun = functions.Evaluate_a(t); + auto f_fun = functions.Evaluate_f(t); + auto flux_fun = functions.Evaluate_sigma(t); + + // Acoustic analytical functions + auto s_u_fun = functions.Evaluate_s_u(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_a_fun = functions.Evaluate_s_a(t); + auto s_f_fun = functions.Evaluate_s_f(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ################################################## + // ################################################## HHO setting + // ################################################## + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree, sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ################################################## + // ################################################## Structure setting + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++){ + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.x()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + if (bar.x() > 0) { + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.x() > 0) + interface_cell_pair_indexes[fc_id].second = cell_ind; + else + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.x() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + // detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, u_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, s_u_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if(sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ################################################## + // ################################################## Projecting initial data + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, v_fun, s_v_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 1; + bool is_sdirk_Q = true; + if (is_sdirk_Q) + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + else + dirk_butcher_tableau::dirk_tables(s, a, b, c); + + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, f_fun, s_f_fun, false); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + + dirk_hho_scheme dirk_an(assembler.LHS, assembler.RHS, assembler.MASS); + if (sim_data.m_sc_Q) { + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + dirk_an.set_static_condensation_data(vec_cell_basis_data, assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + std::cout << bold << cyan << " Matrix decomposed: "; + tc.tic(); + dirk_an.ComposeMatrix(); + bool iteratif_solver = true; // if false load library: source /opt/intel/oneapi/setvars.sh intel64 + if (iteratif_solver) + dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + } + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of SDIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::ostringstream filename; + filename << "IHHO_silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + std::cout << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << red << " Time step number " << it << reset << std::endl; + + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + t = tn + c(i,0) * dt; + // Manufactured solution + auto v_fun = functions.Evaluate_v(t); + auto f_fun = functions.Evaluate_f(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_f_fun = functions.Evaluate_s_f(t); + + assembler.get_e_bc_conditions().updateDirichletFunction(v_fun, 0); + assembler.get_a_bc_conditions().updateDirichletFunction(s_v_fun, 0); + assembler.assemble_rhs(msh, f_fun, s_f_fun, false); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + + int silo_mod = static_cast(std::round(nt / 50.0)); // Number of silo files + if (((it == 1 || it == std::round(nt/2) || it == nt)) || (sim_data.m_render_silo_files_Q && (it%silo_mod == 0))) { + std::ostringstream filename; + filename << "IHHO_silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + tc.toc(); + std::cout << bold << cyan << " DIRK step completed: " << tc << " seconds" << reset << std::endl << std::endl; + x_dof = x_dof_n; + t = tn + dt; + auto v_fun = functions.Evaluate_v(t); + auto flux_fun = functions.Evaluate_sigma(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + } + + if(it == nt){ + // Computing errors + postprocessor::compute_errors_four_fields_elastoacoustic(msh, hho_di, assembler, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun, simulation_log); + postprocessor::compute_errors_four_fields_elastoacoustic_energy_norm(msh, hho_di, assembler, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun, simulation_log); + std::cout << std::endl; + } + + } + + bool mesh_quality = true; + if (mesh_quality) { + std::ostringstream mesh_file_name; + mesh_file_name << "mesh_quality_l" << sim_data.m_n_divs << ".txt"; + std::string mesh_file_str = mesh_file_name.str(); + std::ofstream mesh_file(mesh_file_str); + postprocessor::mesh_quality(msh, assembler, mesh_file); + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + diff --git a/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder_conv_tests.hpp b/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder_conv_tests.hpp new file mode 100644 index 00000000..d9fd3cd5 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder_conv_tests.hpp @@ -0,0 +1,358 @@ + + +// Created by Romain Mottier + +void IHHOFirstOrder_conv_tests(int argc, char **argv); + +void IHHOFirstOrder_conv_tests(int argc, char **argv){ + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " IMPLICIT COUPLING CONV TEST" << reset << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + for (size_t k = 1; k <= sim_data.m_k_degree; k++) { + + std::cout << std::endl << bold << red << " Polynomial degree k : " << k << reset << std::endl; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = k; + if (sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + disk::hho_degree_info hho_di(cell_k_degree, k); + + // ################################################## + // ################################################## Loop over level of space refinement + // ################################################## + + for (size_t l = 0; l <= sim_data.m_n_divs; l++) { + + std::cout << bold << cyan << " Space refinment level -l : " << l << reset << std::endl; + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + // Mesh availability + auto validate_l = [](size_t l) -> size_t { + if (!((0 <= l) && (l < 15))) { + std::cout << std::endl << std::endl; + std::cout << bold << red << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + // size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_32.txt"); + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_64.txt"); + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_128.txt"); // -l 2 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_256.txt"); // -l 3 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_512.txt"); + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_1024.txt"); // -l 5 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_2048.txt"); + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_4096.txt"); // -l 7 + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_8192.txt"); + mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_16384.txt"); + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) + h = h_l; + } + + // ################################################## + // ################################################## Time controls + // ################################################## + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt *= 2; + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // DIRK(s) schemes + Matrix a; + Matrix b; + Matrix c; + int s = 3; + bool is_sdirk_Q = true; + if (is_sdirk_Q) + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + else + dirk_butcher_tableau::dirk_tables(s, a, b, c); + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial_paper); + + // Elastic analytical functions + auto u_fun = functions.Evaluate_u(t); + auto v_fun = functions.Evaluate_v(t); + auto a_fun = functions.Evaluate_a(t); + auto f_fun = functions.Evaluate_f(t); + auto flux_fun = functions.Evaluate_sigma(t); + + // Acoustic analytical functions + auto s_u_fun = functions.Evaluate_s_u(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_a_fun = functions.Evaluate_s_a(t); + auto s_f_fun = functions.Evaluate_s_f(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ################################################## + // ################################################## Material data + // ################################################## + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ################################################## + // ################################################## Structure setting + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++){ + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.x()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + if (bar.x() > 0) { + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.x() > 0) + interface_cell_pair_indexes[fc_id].second = cell_ind; + else + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.x() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + + // detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, u_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, s_u_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if(sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + assembler.assemble_mass(msh); + assembler.assemble_coupling_terms(msh); + + // ################################################## + // ################################################## Projecting initial data + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, v_fun, s_v_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + assembler.assemble(msh, f_fun, s_f_fun, false); + assembler.LHS += assembler.COUPLING; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + dirk_an.set_static_condensation_data(vec_cell_basis_data, assembler.get_n_face_dof()); + } + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + dirk_an.ComposeMatrix(); + bool iteratif_solver = false; // if false load library: source /opt/intel/oneapi/setvars.sh intel64 + if (iteratif_solver) + dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + } + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "implicit_l_" << l << "_n_" << sim_data.m_nt_divs << "_k_" << k << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of SDIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + RealType tn = dt*(it-1)+ti; + // DIRK step + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + RealType t; + Matrix yn, ki; + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + t = tn + c(i,0) * dt; + {// Manufactured solution + auto v_fun = functions.Evaluate_v(t); + auto f_fun = functions.Evaluate_f(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_f_fun = functions.Evaluate_s_f(t); + assembler.get_e_bc_conditions().updateDirichletFunction(v_fun, 0); + assembler.get_a_bc_conditions().updateDirichletFunction(s_v_fun, 0); + assembler.assemble_rhs(msh, f_fun, s_f_fun, false); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + } + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + x_dof = x_dof_n; + t = tn + dt; + auto v_fun = functions.Evaluate_v(t); + auto flux_fun = functions.Evaluate_sigma(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + if (it == nt) { + postprocessor::compute_errors_four_fields_elastoacoustic(msh, hho_di, assembler, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun, simulation_log); + postprocessor::compute_errors_four_fields_elastoacoustic_energy_norm(msh, hho_di, assembler, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun, simulation_log); + } + } + bool mesh_quality = true; + if (mesh_quality) { + std::ostringstream mesh_file_name; + mesh_file_name << "mesh_quality_l" << l << ".txt"; + std::string mesh_file_str = mesh_file_name.str(); + std::ofstream mesh_file(mesh_file_str); + postprocessor::mesh_quality(msh, assembler, mesh_file); + } + } + } + std::cout << std::endl << std::endl; +} diff --git a/apps/wave_propagation/src/prototypes/coupling/EHHOFirstOrder_stability.hpp b/apps/wave_propagation/src/prototypes/coupling/EHHOFirstOrder_stability.hpp new file mode 100644 index 00000000..cf165690 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/EHHOFirstOrder_stability.hpp @@ -0,0 +1,434 @@ + +// Created by Romain Mottier + +// ../../../../elastoacoustic -k 1 -s 1 -r 0 -c 1 -p 0 -l 0 -n 0 -f 0 -e 0 + +void EHHOFirstOrder_stability(int argc, char **argv); + +void EHHOFirstOrder_stability(int argc, char **argv){ + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " COUPLING STABILITY" << reset << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit, cpu; + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) + return l; + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + mesh_files.push_back("../../meshes/conv_test/poly/poly_32.txt"); // -l 0 + mesh_files.push_back("../../meshes/conv_test/poly/poly_64.txt"); // -l 1 + mesh_files.push_back("../../meshes/conv_test/poly/poly_128.txt"); // -l 2 + mesh_files.push_back("../../meshes/conv_test/poly/poly_256.txt"); // -l 3 + mesh_files.push_back("../../meshes/conv_test/poly/poly_512.txt"); // -l 4 + mesh_files.push_back("../../meshes/conv_test/poly/poly_1024.txt"); // -l 5 + mesh_files.push_back("../../meshes/conv_test/poly/poly_2048.txt"); // -l 6 + mesh_files.push_back("../../meshes/conv_test/poly/poly_4096.txt"); // -l 7 + mesh_files.push_back("../../meshes/conv_test/poly/poly_8192.txt"); // -l 8 + mesh_files.push_back("../../meshes/conv_test/poly/poly_16384.txt"); // -l 9 + mesh_files.push_back("../../meshes/conv_test/poly/poly_32768.txt"); // -l 10 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l0_conv_test_1.0.txt"); // l = 0 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l1_conv_test_0.35.txt"); // + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l2_conv_test_0.15.txt"); // l = 2 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l3_conv_test_0.07.txt"); // + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l4_conv_test_0.035.txt"); // l = 4 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l5_conv_test_0.026.txt"); // + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l6_conv_test_0.017.txt"); // l = 6 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l7_conv_test_0.0125.txt"); // + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l8_conv_test_0.0085.txt"); // l = 8 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l9_conv_test_0.005.txt"); // + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) + h = h_l; + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ################################################## + // ################################################## Time controls + // ################################################## + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt = sim_data.m_nt_divs; + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial_paper); + + // Zero source terms, to keep the system energy constant + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + // Elastic analytical functions + auto v_fun = functions.Evaluate_v(t); + auto flux_fun = functions.Evaluate_sigma(t); + + // Acoustic analytical functions + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ################################################## + // ################################################## HHO setting + // ################################################## + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ################################################## + // ################################################## Structure setting + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++){ + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.x()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + if (bar.x() > 0) { + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.x() > 0) + interface_cell_pair_indexes[fc_id].second = cell_ind; + else + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (!is_member_Q) { + if (bar.y() > 0) + acoustic_internal_faces.insert(fc_id); + else + elastic_internal_faces.insert(fc_id); + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.x() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + + // detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_coupling_stabilization(); + if (sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ################################################## + // ################################################## Projecting initial data + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, v_fun, s_v_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // ERK schemes + int s = 4; + erk_butcher_tableau::erk_tables(s, a, b, c); + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + bool explicit_scheme = true; + assembler.assemble(msh, null_fun, null_s_fun, explicit_scheme); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes);//assembler.get_interfaces()); + + tc.toc(); + std::cout << bold << cyan << " ERK analysis created: " << tc << " seconds" << reset << std::endl; + tc.tic(); + erk_an.refresh_faces_unknowns(x_dof); + tc.toc(); + std::cout << bold << cyan << " Inverse of Sff + Coupling in: " << tc << " seconds" << reset << std::endl; + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + // erk_an.compute_eigenvalues(simulation_log); + simulation_log.flush(); + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + auto energy_0 = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + if (sim_data.m_render_silo_files_Q) { + std::ostringstream silo; + silo << "Silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_str = silo.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_str, 0, msh, hho_di, x_dof, e_material, a_material, false); + } + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + bool approx_fail_check_Q = false; + RealType energy = energy_0; + for(size_t it = 1; it <= nt; it++) { + + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t << reset; + RealType tn = dt*(it-1)+ti; + + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + Matrix yn, ki; + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + t = tn + c(i,0) * dt; + assembler.assemble_rhs(msh, null_fun, null_s_fun, true); + erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + + tc.toc(); + std::cout << bold << cyan << " ERK step completed: " << tc << " seconds" << reset; + x_dof = x_dof_n; + t = tn + dt; + + // Energy evalutation + RealType energy_n = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + RealType relative_energy = (energy_n - energy) / energy; + RealType relative_energy_0 = (energy_n - energy_0) / energy_0; + bool unstable_check_Q = (relative_energy > 5.0e-2) || (relative_energy_0 >= 5.0e-2); + if (unstable_check_Q) { // energy is increasing + std::cout << std::endl << std::endl << bold << red << " Simulation is unstable" << std::endl; + break; + } + energy = energy_n; + std::cout << std::endl << std::endl; + + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << std::endl << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + diff --git a/apps/wave_propagation/src/prototypes/coupling/HeterogeneousGar6more2DIHHOSecondOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/HeterogeneousGar6more2DIHHOSecondOrder.hpp new file mode 100644 index 00000000..d6648bcf --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/HeterogeneousGar6more2DIHHOSecondOrder.hpp @@ -0,0 +1,314 @@ + + +// Created by Romain Mottier + +void HeterogeneousGar6more2DIHHOSecondOrder(int argc, char **argv); + +void HeterogeneousGar6more2DIHHOSecondOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 3.0; + RealType ly = 3.0; + size_t nx = 3; + size_t ny = 3; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.5, -1.5); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + tc.toc(); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // fluid mass density + vp = std::sqrt(3.0); // seismic compressional velocity vp + vs = 1.0; // seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // fluid mass density + vp = std::sqrt(9.0); // seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + auto null_fun = [](const mesh_type::point_type& pt) -> static_vector { + static_vector f{0,0}; + return f; + }; + auto null_s_fun = [](const mesh_type::point_type& pt) -> RealType { + return 0; + }; + + auto u_s_fun = [](const mesh_type::point_type& pt) -> RealType { + RealType x,y,xc,yc,r,wave,vx,vy,v,c,lp,factor; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 2.0/3.0; + c = 10.0; + lp = std::sqrt(9.0)/10.0; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + factor = (lp*lp/(2.0*M_PI*M_PI)); + return factor*wave; + }; + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) + { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.y()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + if (bar.y() > 0) { + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + }else{ + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.y() > 0) { + interface_cell_pair_indexes[fc_id].second = cell_ind; + }else{ + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) + { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.y() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + }else{ + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + + } + + // detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // Solving a primal HHO mixed problem + + + tc.tic(); + auto assembler = elastoacoustic_two_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << "Coupling Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial scalar, velocity and acceleration + Matrix u_dof_n, v_dof_n, a_dof_n; + assembler.project_over_cells(msh, u_dof_n, null_fun, u_s_fun); + assembler.project_over_faces(msh, u_dof_n, null_fun, u_s_fun); + assembler.project_over_cells(msh, v_dof_n, null_fun, null_s_fun); + assembler.project_over_faces(msh, v_dof_n, null_fun, null_s_fun); + assembler.project_over_cells(msh, a_dof_n, null_fun, null_s_fun); + assembler.project_over_faces(msh, a_dof_n, null_fun, null_s_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "elasto_acoustic_inhomogeneous_two_fields_"; + postprocessor::write_silo_two_fields_elastoacoustic(silo_file_name, it, msh, hho_di, v_dof_n, e_material, a_material, false); + } + + std::ofstream simulation_log("elasto_acoustic_inhomogeneous_two_fields.txt"); + + std::ofstream sensor_1_log("s1_elasto_acoustic_two_fields_h.csv"); + std::ofstream sensor_2_log("s2_elasto_acoustic_two_fields_h.csv"); + std::ofstream sensor_3_log("s3_elasto_acoustic_two_fields_h.csv"); + bool e_side_Q = false; + typename mesh_type::point_type s1_pt(-1.0/3.0, +1.0/3.0); + typename mesh_type::point_type s2_pt( 0.0, +1.0/3.0); + typename mesh_type::point_type s3_pt(+1.0/3.0, +1.0/3.0); + std::pair s1_pt_cell = std::make_pair(s1_pt, -1); + std::pair s2_pt_cell = std::make_pair(s2_pt, -1); + std::pair s3_pt_cell = std::make_pair(s3_pt, -1); + + postprocessor::record_velocity_data_elasto_acoustic_two_fields(0, s1_pt_cell, msh, hho_di, assembler, u_dof_n, v_dof_n, e_side_Q, sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_two_fields(0, s2_pt_cell, msh, hho_di, assembler, u_dof_n, v_dof_n, e_side_Q, sensor_2_log); + postprocessor::record_velocity_data_elasto_acoustic_two_fields(0, s3_pt_cell, msh, hho_di, assembler, u_dof_n, v_dof_n, e_side_Q, sensor_3_log); + +// if (sim_data.m_report_energy_Q) { +// postprocessor::compute_acoustic_energy_one_field(msh, hho_di, assembler, t, p_dof_n, v_dof_n, simulation_log); +// } + + bool standar_Q = true; + // Newmark process + { + Matrix a_dof_np = a_dof_n; + + RealType beta = 0.25; + RealType gamma = 0.5; + if (!standar_Q) { + RealType kappa = 0.25; + gamma = 1.5; + beta = kappa*(gamma+0.5)*(gamma+0.5); + } + + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun); + SparseMatrix Kg = assembler.LHS; + SparseMatrix C = assembler.COUPLING; + + assembler.LHS *= beta*(dt*dt); + assembler.LHS += gamma*dt*C; + assembler.LHS += assembler.MASS; + linear_solver analysis; + if (sim_data.m_sc_Q) { + analysis.set_Kg(assembler.LHS, assembler.get_n_face_dof()); + + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + analysis.condense_equations(vec_cell_basis_data); + }else{ + analysis.set_Kg(assembler.LHS); + } +// analysis.set_iterative_solver(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + // Manufactured solution + RealType t = dt*it+ti; + + tc.tic(); + assembler.RHS.setZero(); + assembler.apply_bc(msh); + + // Compute intermediate state for scalar and rate + u_dof_n = u_dof_n + dt*v_dof_n + 0.5*dt*dt*(1-2.0*beta)*a_dof_n; + v_dof_n = v_dof_n + dt*(1-gamma)*a_dof_n; + Matrix res = Kg*u_dof_n; + Matrix res_v = C*v_dof_n; + assembler.RHS -= res; + assembler.RHS -= res_v; + tc.toc(); + std::cout << bold << cyan << "Rhs assembly completed: " << tc << " seconds" << reset << std::endl; + tc.tic(); + a_dof_np = analysis.solve(assembler.RHS); // new acceleration + tc.toc(); + std::cout << bold << cyan << "Solution completed: " << tc << " seconds" << reset << std::endl; + + // update scalar and rate + u_dof_n += beta*dt*dt*a_dof_np; + v_dof_n += gamma*dt*a_dof_np; + a_dof_n = a_dof_np; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "elasto_acoustic_inhomogeneous_two_fields_"; + postprocessor::write_silo_two_fields_elastoacoustic(silo_file_name, it, msh, hho_di, v_dof_n, e_material, a_material, false); + } + + postprocessor::record_velocity_data_elasto_acoustic_two_fields(it, s1_pt_cell, msh, hho_di, assembler, u_dof_n, v_dof_n, e_side_Q, sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_two_fields(it, s2_pt_cell, msh, hho_di, assembler, u_dof_n, v_dof_n, e_side_Q, sensor_2_log); + postprocessor::record_velocity_data_elasto_acoustic_two_fields(it, s3_pt_cell, msh, hho_di, assembler, u_dof_n, v_dof_n, e_side_Q, sensor_3_log); + +// if (sim_data.m_report_energy_Q) { +// postprocessor::compute_acoustic_energy_one_field(msh, hho_di, assembler, t, p_dof_n, v_dof_n, simulation_log); +// } + + } + + simulation_log << "Number of equations : " << analysis.n_equations() << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + } + + return 0; + +} diff --git a/apps/wave_propagation/src/prototypes/coupling/IHHOSecondOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/IHHOSecondOrder.hpp new file mode 100644 index 00000000..9bff807b --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/IHHOSecondOrder.hpp @@ -0,0 +1,301 @@ + +// Created by Romain Mottier + +void IHHOSecondOrder(int argc, char **argv); + +void IHHOSecondOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + tc.toc(); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + + scal_vec_analytic_functions functions; + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + RealType t = ti; + + auto u_fun = functions.Evaluate_u(t); + auto v_fun = functions.Evaluate_v(t); + auto a_fun = functions.Evaluate_a(t); + auto f_fun = functions.Evaluate_f(t); + auto flux_fun = functions.Evaluate_sigma(t); + + auto s_u_fun = functions.Evaluate_s_u(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_a_fun = functions.Evaluate_s_a(t); + auto s_f_fun = functions.Evaluate_s_f(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // fluid mass density + vp = std::sqrt(3.0); // seismic compressional velocity vp + vs = 1.0; // seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // fluid mass density + vp = 1.0; // seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) + { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.x()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + if (bar.x() > 0) { + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + }else{ + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.x() > 0) { + interface_cell_pair_indexes[fc_id].second = cell_ind; + }else{ + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) + { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.x() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + }else{ + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + + } + + // detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, u_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, s_u_fun); + + // Solving a primal HHO mixed problem + + + tc.tic(); + auto assembler = elastoacoustic_two_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << "Coupling Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial scalar, velocity and acceleration + Matrix u_dof_n, v_dof_n, a_dof_n; + assembler.project_over_cells(msh, u_dof_n, u_fun, s_u_fun); + assembler.project_over_faces(msh, u_dof_n, u_fun, s_u_fun); + assembler.project_over_cells(msh, v_dof_n, v_fun, s_v_fun); + assembler.project_over_faces(msh, v_dof_n, v_fun, s_v_fun); + assembler.project_over_cells(msh, a_dof_n, a_fun, s_a_fun); + assembler.project_over_faces(msh, a_dof_n, a_fun, s_a_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "elasto_acoustic_two_fields_"; + postprocessor::write_silo_two_fields_elastoacoustic(silo_file_name, it, msh, hho_di, v_dof_n, e_material, a_material, false); + } + + std::ofstream simulation_log("elasto_acoustic_two_fields.txt"); + +// if (sim_data.m_report_energy_Q) { +// postprocessor::compute_acoustic_energy_one_field(msh, hho_di, assembler, t, p_dof_n, v_dof_n, simulation_log); +// } + + bool standar_Q = true; + // Newmark process + { + Matrix a_dof_np = a_dof_n; + + RealType beta = 0.25; + RealType gamma = 0.5; + if (!standar_Q) { + RealType kappa = 0.25; + gamma = 1.5; + beta = kappa*(gamma+0.5)*(gamma+0.5); + } + + tc.tic(); + assembler.assemble(msh, f_fun, s_f_fun); + SparseMatrix Kg = assembler.LHS; + SparseMatrix C = assembler.COUPLING; + + assembler.LHS *= beta*(dt*dt); + assembler.LHS += gamma*dt*C; + assembler.LHS += assembler.MASS; + linear_solver analysis; + if (sim_data.m_sc_Q) { + analysis.set_Kg(assembler.LHS, assembler.get_n_face_dof()); + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + analysis.condense_equations(vec_cell_basis_data); + }else{ + analysis.set_Kg(assembler.LHS); + } +// analysis.set_iterative_solver(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + // Manufactured solution + RealType t = dt*it+ti; + auto u_fun = functions.Evaluate_u(t); + auto v_fun = functions.Evaluate_v(t); + auto f_fun = functions.Evaluate_f(t); + auto flux_fun = functions.Evaluate_sigma(t); + auto s_u_fun = functions.Evaluate_s_u(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_f_fun = functions.Evaluate_s_f(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + + tc.tic(); + assembler.get_e_bc_conditions().updateDirichletFunction(u_fun, 0); + assembler.get_a_bc_conditions().updateDirichletFunction(s_u_fun, 0); + assembler.assemble_rhs(msh, f_fun, s_f_fun); + + // Compute intermediate state for scalar and rate + u_dof_n = u_dof_n + dt*v_dof_n + 0.5*dt*dt*(1-2.0*beta)*a_dof_n; + v_dof_n = v_dof_n + dt*(1-gamma)*a_dof_n; + Matrix res = Kg*u_dof_n; + Matrix res_v = C*v_dof_n; + assembler.RHS -= res; + assembler.RHS -= res_v; + tc.toc(); + std::cout << bold << cyan << "Rhs assembly completed: " << tc << " seconds" << reset << std::endl; + tc.tic(); + a_dof_np = analysis.solve(assembler.RHS); // new acceleration + tc.toc(); + std::cout << bold << cyan << "Solution completed: " << tc << " seconds" << reset << std::endl; + + // update scalar and rate + u_dof_n += beta*dt*dt*a_dof_np; + v_dof_n += gamma*dt*a_dof_np; + a_dof_n = a_dof_np; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "elasto_acoustic_two_fields_"; + postprocessor::write_silo_two_fields_elastoacoustic(silo_file_name, it, msh, hho_di, v_dof_n, e_material, a_material, false); + } + +// if (sim_data.m_report_energy_Q) { +// postprocessor::compute_acoustic_energy_one_field(msh, hho_di, assembler, t, p_dof_n, v_dof_n, simulation_log); +// } + + if(it == nt){ + postprocessor::compute_errors_two_fields_elastoacoustic(msh, hho_di, assembler, u_dof_n, u_fun, flux_fun, s_u_fun, s_flux_fun, simulation_log); + } + + } + simulation_log << "Number of equations : " << analysis.n_equations() << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + } + + return 0; + +} + diff --git a/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesEHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesEHHOFirstOrder.hpp new file mode 100644 index 00000000..1033085f --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesEHHOFirstOrder.hpp @@ -0,0 +1,490 @@ + + +// Created by Romain Mottier + +// source /opt/intel/oneapi/setvars.sh intel64 +// ../../../elastoacoustic -k 3 -s 0 -r 0 -c 0 -p 0 -l 0 -n 1400 -f 0 -e 0 + +void ConicWavesEHHOFirstOrder(int argc, char **argv); + +void ConicWavesEHHOFirstOrder(int argc, char **argv){ + + // ###################################################################### + // ###################################################################### Simulation paramaters + // ###################################################################### + + std::cout << std::endl << bold << red << " EXPLICIT PULSE - COUPLING - GEOPHYSIC" << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit, cpu; + cpu.tic(); + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l2_0.4.txt"); // l = 0 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l3_0.21.txt"); // l = 1 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l4_0.096.txt"); // l = 2 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l5_0.0485.txt"); // l = 3 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l6_0.024.txt"); // l = 4 + + // mesh_files.push_back("../../meshes/pulse/poly/poly_l2.txt"); // -l 0 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l3.txt"); // -l 1 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l4.txt"); // -l 2 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l5.txt"); // -l 3 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l6.txt"); // -l 4 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l7.txt"); // -l 5 + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + // RealType lx = 5000.0; + // RealType ly = 3500.0; + RealType lx = 7500.0; + RealType ly = 5250.0; + // size_t nx = 140; + // size_t ny = 140; + size_t nx = 322; // k= 4 -> 224 + size_t ny = 322; + cartesian_2d_mesh_builder mesh_builder(lx, ly, nx, ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + // mesh_builder.set_translation_data(-2500.0, -2500.0); + mesh_builder.set_translation_data(-3750.0, -3750.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt = sim_data.m_nt_divs; + + RealType ti = 0.0; + RealType tf = 0.625; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + disk::hho_degree_info hho_di(cell_k_degree, sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + auto water_mat_fun = [](const typename disk::mesh>::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp; + rho = 1025.0; + vp = 1500.0; + acoustic_material_data material(rho,vp); + return material; + }; + + auto granit_mat_fun = [](const typename disk::mesh>::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp, vs; + rho = 2690.0; + vp = 6000.0; + vs = 3000.0; + elastic_material_data material(rho,vp,vs); + return material; + }; + + // ###################################################################### + // ###################################################################### Structure setting + // ###################################################################### + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.y()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + + // Assigning the material properties + if (bar.y() > 0) { + acoustic_material_data material = water_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = granit_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.y() > 0) { + interface_cell_pair_indexes[fc_id].second = cell_ind; + } + else { + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + } + + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + } + else { + if (bar.y() > 0) { + acoustic_internal_faces.insert(fc_id); + } + else { + elastic_internal_faces.insert(fc_id); + } + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.y() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + // Boundary Condition + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if (sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + // ###################################################################### + // ###################################################################### Projecting initial data + // ###################################################################### + + // Acoustic pulse - Heterogeneous domain - Fluide = Eau + auto pulse_geophysic_v = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x, y, xc, yc, r, wave, vp, lp, fc, c, vx, vy; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 100.0; + fc = 10.0; + c = 10.0; + vp = 1500.0; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + Matrix x_dof; + // Acoustic pulse intialized in pressure + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, pulse_geophysic_v); + assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // ERK(s) schemes + int s = 4; + erk_butcher_tableau::erk_tables(s, a, b, c); + std::cout << std::endl << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, true); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes);//assembler.get_interfaces()); + + tc.toc(); + std::cout << bold << cyan << " ERK analysis created: " << tc << " seconds" << reset << std::endl; + tc.tic(); + erk_an.refresh_faces_unknowns(x_dof); + tc.toc(); + std::cout << bold << cyan << " Inverse of Sff + Coupling in: " << tc << " seconds" << reset << std::endl; + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "Explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + + size_t it = 0; + std::ostringstream filename_silo; + filename_silo << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename_silo.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + // ################################################## + // ################################################## Sensors + // ################################################## + + bool e_side_Q = true; + bool a_side_Q = false; + + std::ostringstream filename_acou; + filename_acou << "A_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str = filename_acou.str(); + std::ofstream Acoustic_sensor_1_log(filename_acou_str); + typename mesh_type::point_type Acoustic_s1_pt(-2300, 100); + std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); + + std::ostringstream filename_int; + filename_int << "I_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_int_str = filename_int.str(); + std::ofstream Interface_sensor_1_log(filename_int_str); + typename mesh_type::point_type Interface_s1_pt(-1300, 0.0); + std::pair Interface_s1_pt_cell = std::make_pair(Interface_s1_pt, -1); + + std::ostringstream filename_ela; + filename_ela << "E_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str = filename_ela.str(); + std::ofstream Elastic_sensor_1_log(filename_ela_str); + typename mesh_type::point_type Elastic_s1_pt(-2300, -200); + std::pair Elastic_s1_pt_cell = std::make_pair(Elastic_s1_pt, -1); + + bool sensors = true; + if (sensors) { + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + } + + std::cout << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + erk_an.erk_weight(yn, ki); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << " ERK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + int silo_mod = static_cast(std::round(nt / 50.0)); // Number of silo files + if ((!sim_data.m_render_silo_files_Q && (it == 1 || it == std::round(nt/2) || it == nt)) || ((sim_data.m_render_silo_files_Q && (it%silo_mod == 0)) || it == nt)) { + std::ostringstream filename; + filename << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + if (sensors) { + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + } + + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + t += dt; + + tcit.toc(); + std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + + + + diff --git a/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp new file mode 100644 index 00000000..2fa6233c --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp @@ -0,0 +1,531 @@ + + +// Created by Romain Mottier + +// source /opt/intel/oneapi/setvars.sh intel64 +// ../../../elastoacoustic -k 3 -s 1 -r 1 -c 1 -p 0 -l 0 -n 8 -f 1 -e 0 + +void ConicWavesIHHOFirstOrder(int argc, char **argv); + +void ConicWavesIHHOFirstOrder(int argc, char **argv){ + + // ###################################################################### + // ###################################################################### Simulation paramaters + // ###################################################################### + + std::cout << std::endl << bold << red << " IMPLICIT PULSE - COUPLING - GEOPHYSIC" << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit, cpu; + cpu.tic(); + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l2_0.4.txt"); // l = 0 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l3_0.21.txt"); // l = 1 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l4_0.096.txt"); // l = 2 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l5_0.0485.txt"); // l = 3 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l6_0.024.txt"); // l = 4 + + // mesh_files.push_back("../../meshes/pulse/poly/poly_l2.txt"); // -l 0 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l3.txt"); // -l 1 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l4.txt"); // -l 2 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l5.txt"); // -l 3 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l6.txt"); // -l 4 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l7.txt"); // -l 5 + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + // RealType lx = 5000.0; + // RealType ly = 3500.0; + RealType lx = 7500.0; + RealType ly = 5250.0; + // size_t nx = 140; + // size_t ny = 140; + size_t nx = 322; // k= 4 -> 224 + size_t ny = 322; + cartesian_2d_mesh_builder mesh_builder(lx, ly, nx, ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + // mesh_builder.set_translation_data(-2500.0, -2500.0); + mesh_builder.set_translation_data(-3750.0, -3750.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) + h = h_l; + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt *= 2; + + RealType ti = 0.0; + RealType tf = 0.625; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + auto water_mat_fun = [](const typename disk::mesh>::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp; + rho = 1025.0; + vp = 1500.0; + acoustic_material_data material(rho,vp); + return material; + }; + + auto granit_mat_fun = [](const typename disk::mesh>::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp, vs; + rho = 2690.0; + vp = 6000.0; + vs = 3000.0; + elastic_material_data material(rho,vp,vs); + return material; + }; + + // ###################################################################### + // ###################################################################### Structure setting + // ###################################################################### + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.y()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + + // Assigning the material properties + if (bar.y() > 0) { + acoustic_material_data material = water_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = granit_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.y() > 0) + interface_cell_pair_indexes[fc_id].second = cell_ind; + else + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.y() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + // Boundary Condition + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if(sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + // ###################################################################### + // ###################################################################### Projecting initial data + // ###################################################################### + + // Acoustic pulse - Heterogeneous domain - Fluide = Eau + auto pulse_geophysic_v = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x, y, xc, yc, r, wave, vp, lp, fc, c, vx, vy; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 100.0; + fc = 10.0; + c = 10.0; + vp = 1500.0; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + Matrix x_dof; + // Acoustic pulse intialized in pressure + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, pulse_geophysic_v); + assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + if (is_sdirk_Q) + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + else + dirk_butcher_tableau::dirk_tables(s, a, b, c); + + std::cout << std::endl; + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, false); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + dirk_an.set_static_condensation_data(vec_cell_basis_data, assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + std::cout << bold << cyan << " Matrix decomposed: "; + tc.tic(); + dirk_an.ComposeMatrix(); + bool iteratif_solver = true; // if false load library: source /opt/intel/oneapi/setvars.sh intel64 + if (iteratif_solver) + dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + } + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of SDIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations = " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + + size_t it = 0; + std::ostringstream filename_silo; + filename_silo << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename_silo.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + + // ################################################## + // ################################################## Sensors + // ################################################## + + bool e_side_Q = true; + bool a_side_Q = false; + + std::ostringstream filename_acou; + filename_acou << "AP_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str = filename_acou.str(); + std::ofstream Acoustic_sensor_1_log(filename_acou_str); + typename mesh_type::point_type Acoustic_s1_pt(-2300, 100); + std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); + std::ostringstream filename_acou2; + filename_acou2 << "AV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str2 = filename_acou2.str(); + std::ofstream Acoustic_sensor_2_log(filename_acou_str2); + typename mesh_type::point_type Acoustic_s2_pt(-2300, 100); + std::pair Acoustic_s2_pt_cell = std::make_pair(Acoustic_s2_pt, -1); + + std::ostringstream filename_int; + filename_int << "IP_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_acoustic_pressure.csv"; + std::string filename_int_str = filename_int.str(); + std::ofstream Interface_sensor_acoustic_pressure(filename_int_str); + typename mesh_type::point_type Interface_s1_pt(-1300.0, 0.0); + std::pair Interface_s1_pt_cell = std::make_pair(Interface_s1_pt, -1); + std::ostringstream filename_int2; + filename_int2 << "IAV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_acoustic_velocity.csv"; + std::string filename_int_str2 = filename_int2.str(); + std::ofstream Interface_sensor_acoustic_velocity(filename_int_str2); + typename mesh_type::point_type Interface_s2_pt(-1300.0, 0.0); + std::pair Interface_s2_pt_cell = std::make_pair(Interface_s2_pt, -1); + std::ostringstream filename_int3; + filename_int3 << "IEV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_elastic_velocity.csv"; + std::string filename_int_str3 = filename_int3.str(); + std::ofstream Interface_sensor_elastic_velocity(filename_int_str3); + typename mesh_type::point_type Interface_s3_pt(-1300.0, 0.0); + std::pair Interface_s3_pt_cell = std::make_pair(Interface_s3_pt, -1); + std::ostringstream filename_int4; + filename_int4 << "IS_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_elastic_stress.csv"; + std::string filename_int_str4 = filename_int4.str(); + std::ofstream Interface_sensor_elastic_stress(filename_int_str4); + typename mesh_type::point_type Interface_s4_pt(-1300.0, 0.0); + std::pair Interface_s4_pt_cell = std::make_pair(Interface_s4_pt, -1); + + std::ostringstream filename_ela; + filename_ela << "EV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str = filename_ela.str(); + std::ofstream Elastic_sensor_1_log(filename_ela_str); + typename mesh_type::point_type Elastic_s1_pt(-2300, -200); + std::pair Elastic_s1_pt_cell = std::make_pair(Elastic_s1_pt, -1); + std::ostringstream filename_ela2; + filename_ela2 << "ES_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str2 = filename_ela2.str(); + std::ofstream Elastic_sensor_2_log(filename_ela_str2); + typename mesh_type::point_type Elastic_s2_pt(-2300, -200); + std::pair Elastic_s2_pt_cell = std::make_pair(Elastic_s2_pt, -1); + + bool sensors = true; + if (sensors) { + // Acoustic sensor + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); + // Interface sensor + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_pressure); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_velocity); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_velocity); + postprocessor::record_elastic_data_elasto_acoustic_four_fields(0, Interface_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_stress); + // Elastic sensor + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + postprocessor::record_elastic_data_elasto_acoustic_four_fields(0, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + } + + std::cout << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + t = tn + c(i,0) * dt; + assembler.RHS.setZero(); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << " SDIRK step completed: " << tc << " seconds" << reset << std::endl; + + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + int silo_mod = static_cast(std::round(nt / 50.0)); // Number of silo files + if ((it == 1 || it == std::round(nt/2) || it == nt) || (sim_data.m_render_silo_files_Q && (it%silo_mod == 0))) { + std::ostringstream filename; + filename << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + if (sensors) { + // Acoustic sensor + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); + // Interface sensor + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_pressure); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_velocity); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_velocity); + postprocessor::record_elastic_data_elasto_acoustic_four_fields(it, Interface_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_stress); + // Elastic sensor + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + postprocessor::record_elastic_data_elasto_acoustic_four_fields(it, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + } + + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + t += dt; + + tcit.toc(); + std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + + + + diff --git a/apps/wave_propagation/src/prototypes/coupling/Pulse/HeterogeneousEHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Pulse/HeterogeneousEHHOFirstOrder.hpp new file mode 100644 index 00000000..5e6969a4 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Pulse/HeterogeneousEHHOFirstOrder.hpp @@ -0,0 +1,530 @@ + + +// Created by Romain Mottier +// ../wave_propagation -k 2 -s 0 -r 0 -c 0 -p 0 -l 6 -n 2500 -f 1 -e 0 + +void HeterogeneousEHHOFirstOrder(int argc, char **argv); + +void HeterogeneousEHHOFirstOrder(int argc, char **argv){ + + // ###################################################################### + // ###################################################################### Simulation paramaters + // ###################################################################### + + std::cout << std::endl << bold << red << " EXPLICIT PULSE - COUPLING" << std::endl << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit, cpu; + cpu.tic(); + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l2_0.4.txt"); // l = 0 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l3_0.21.txt"); // l = 1 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l4_0.096.txt"); // l = 2 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l5_0.0485.txt"); // l = 3 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l6_0.024.txt"); // l = 4 + + // mesh_files.push_back("../../meshes/pulse/poly/poly_l2.txt"); // -l 0 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l3.txt"); // -l 1 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l4.txt"); // -l 2 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l5.txt"); // -l 3 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l6.txt"); // -l 4 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l7.txt"); // -l 5 + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 1; + RealType ly = 1; + size_t nx = 2; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-0.5, -0.5); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt = sim_data.m_nt_divs; + + RealType ti = 0.0; + RealType tf = 0.25; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if (sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + disk::hho_degree_info hho_di(cell_k_degree, sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + auto water_mat_fun_adi = [](const typename disk::mesh>::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp; + rho = 1.0; + vp = 1.0; + acoustic_material_data material(rho,vp); + return material; + }; + + auto granit_mat_fun_adi = [](const typename disk::mesh>::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp, vs; + rho = 2.624390244; + vp = 4.0; + vs = 2.0; + elastic_material_data material(rho,vp,vs); + return material; + }; + + // ###################################################################### + // ###################################################################### Structure setting + // ###################################################################### + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.y()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + + // Assigning the material properties + if (bar.y() > 0) { + // acoustic_material_data material = water_mat_fun_adi(bar); + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + // elastic_material_data material = granit_mat_fun_adi(bar); + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.y() > 0) { + interface_cell_pair_indexes[fc_id].second = cell_ind; + } + else { + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + } + + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + } + else { + if (bar.y() > 0) { + acoustic_internal_faces.insert(fc_id); + } + else { + elastic_internal_faces.insert(fc_id); + } + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.y() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + // Boundary condition + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if (sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Projecting initial data + // ###################################################################### + + auto v_fun_adi_acoustic = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x,y,xc,yc,r,wave,vx,vy,c,lp, fc, vp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 0.125; // 0.1; + fc = 10.0; + c = 10; + vp = std::sqrt(1.0); + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + Matrix x_dof; + // Acoustic pulse intialized in pressure + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, v_fun_adi_acoustic); + assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + // Elastic pulse intialized in pressure + // assembler.project_over_cells(msh, x_dof, v_fun, null_flux_fun, null_s_fun, null_fun); + // assembler.project_over_faces(msh, x_dof, v_fun, null_s_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // ERK(s) schemes + int s = 2; + erk_butcher_tableau::erk_tables(s, a, b, c); + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, true); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes);//assembler.get_interfaces()); + + tc.toc(); + std::cout << bold << cyan << " ERK analysis created: " << tc << " seconds" << reset << std::endl; + tc.tic(); + erk_an.refresh_faces_unknowns(x_dof); + tc.toc(); + std::cout << bold << cyan << " Inverse of Sff + Coupling in: " << tc << " seconds" << reset << std::endl; + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "Explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log.flush(); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::ostringstream filename; + filename << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + // ################################################## + // ################################################## Sensors + // ################################################## + + bool e_side_Q = true; + bool a_side_Q = false; + + std::ostringstream filename_acou; + filename_acou << "A_explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str = filename_acou.str(); + std::ofstream Acoustic_sensor_1_log(filename_acou_str); + typename mesh_type::point_type Acoustic_s1_pt(-0.15, 0.1); + std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); + + std::ostringstream filename_int; + filename_int << "I_explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_int_str = filename_int.str(); + std::ofstream Interface_sensor_1_log(filename_int_str); + typename mesh_type::point_type Interface_s1_pt(-0.15, 0.0); + std::pair Interface_s1_pt_cell = std::make_pair(Interface_s1_pt, -1); + + std::ostringstream filename_ela; + filename_ela << "E_explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str = filename_ela.str(); + std::ofstream Elastic_sensor_1_log(filename_ela_str); + typename mesh_type::point_type Elastic_s1_pt(-0.15, -0.1); + std::pair Elastic_s1_pt_cell = std::make_pair(Elastic_s1_pt, -1); + + bool sensors = false; + if (sensors) { + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + } + + std::cout << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + erk_an.erk_weight(yn, ki); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << " ERK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "elasto_acoustic_inhomogeneous_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + + t += dt; + + tcit.toc(); + std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + + if (it == nt) { + std::ostringstream silo; + silo << "Silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_str = silo.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_str, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/wave_propagation/src/prototypes/coupling/Pulse/HeterogeneousIHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Pulse/HeterogeneousIHHOFirstOrder.hpp new file mode 100644 index 00000000..b7a7662f --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Pulse/HeterogeneousIHHOFirstOrder.hpp @@ -0,0 +1,680 @@ + + +// Created by Romain Mottier + +// source /opt/intel/oneapi/setvars.sh intel64 +// ../wave_propagation -k 2 -s 1 -r 1 -c 1 -p 0 -l 6 -n 7 -f 1 -e 0 + +void HeterogeneousIHHOFirstOrder(int argc, char **argv); + +void HeterogeneousIHHOFirstOrder(int argc, char **argv){ + + // ###################################################################### + // ###################################################################### Simulation paramaters + // ###################################################################### + + std::cout << std::endl << bold << red << " IMPLICIT PULSE - COUPLING" << std::endl << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit, cpu; + cpu.tic(); + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l2_0.4.txt"); // l = 0 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l3_0.21.txt"); // l = 1 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l4_0.096.txt"); // l = 2 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l5_0.0485.txt"); // l = 3 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l6_0.024.txt"); // l = 4 + + // mesh_files.push_back("../../meshes/pulse/poly/poly_l2.txt"); // -l 0 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l3.txt"); // -l 1 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l4.txt"); // -l 2 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l5.txt"); // -l 3 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l6.txt"); // -l 4 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l7.txt"); // -l 5 + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 1; + RealType ly = 1; + size_t nx = 2; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-0.5, -0.5); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) + h = h_l; + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt *= 2; + + RealType ti = 0.0; + RealType tf = 1.0; //0.5; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun_adi_water = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0/2.00; // Fluid mass density + vp = 1.0/2.00; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + auto granit_mat_fun_adi_water = [](const typename disk::mesh>::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp, vs; + rho = 2.6/2.00; + vp = 4.0/2.00; + vs = 2.0/2.00; + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun_adi_air = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0/15; // 2.75; // Fluid mass density + vp = 1.0/15; // 2.75; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + auto granit_mat_fun_adi_air = [](const typename disk::mesh>::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp, vs; + rho = 2200.0/15; // 2.75; + vp = 17.5/15; // 2.75; + vs = 9.0/15; // 2.75; + elastic_material_data material(rho,vp,vs); + return material; + }; + + // ###################################################################### + // ###################################################################### Structure setting + // ###################################################################### + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.y()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + if (bar.y() > 0) { + acoustic_material_data material = acoustic_mat_fun(bar); + // acoustic_material_data material = acoustic_mat_fun_adi_water(bar); + // acoustic_material_data material = acoustic_mat_fun_adi_air(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = elastic_mat_fun(bar); + // elastic_material_data material = granit_mat_fun_adi_water(bar); + // elastic_material_data material = granit_mat_fun_adi_air(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.y() > 0) + interface_cell_pair_indexes[fc_id].second = cell_ind; + else + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.y() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + // Boundary condition + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if (sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Projecting initial data + // ###################################################################### + + // No contrast case + auto v_fun_acoustic = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x,y,xc,yc,r,wave,vx,vy,c,lp, fc, vp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 0.125; // 0.1; + fc = 10.0; + c = 10; + vp = 1.0; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + // Contrasted case + auto v_fun_acoustic_water = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x,y,xc,yc,r,wave,vx,vy,c,lp, fc, vp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 0.125; // 0.1; + fc = 10.0; + c = 10; + vp = 1.0/2.0; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + // Contrasted case + auto v_fun_acoustic_air = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x,y,xc,yc,r,wave,vx,vy,c,lp, fc, vp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 0.125; // 0.1; + fc = 10.0; + c = 10; + vp = 1.0/15; // 2.75; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + // No contrast case + auto v_fun_elastic = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x,y,xc,yc,r,wave,vx,vy,c,lp, fc, vp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = -0.125; + fc = 10.0; + c = 10; + vp = std::sqrt(3.0); + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + auto v_fun_elastic_granit_water = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x,y,xc,yc,r,wave,vx,vy,c,lp, fc, vp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = -0.125; + fc = 10.0; + c = 10; + vp = 4.0/2.0; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + auto v_fun_elastic_granit_air = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x,y,xc,yc,r,wave,vx,vy,c,lp, fc, vp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = -0.125; + fc = 10.0; + c = 10; + vp = 17.5/15; // 2.75; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + Matrix x_dof; + // // Acoustic pulse intialized in velocity + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, v_fun_acoustic); + assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + // Elastic pulse intialized in velocity + // assembler.project_over_cells(msh, x_dof, v_fun_elastic_granit_air, null_flux_fun, null_s_fun, null_fun); + // assembler.project_over_faces(msh, x_dof, v_fun_elastic_granit_air, null_s_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + if (is_sdirk_Q) + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + else + dirk_butcher_tableau::dirk_tables(s, a, b, c); + + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, false); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + dirk_an.set_static_condensation_data(vec_cell_basis_data, assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + std::cout << bold << cyan << " Matrix decomposed: "; + tc.tic(); + dirk_an.ComposeMatrix(); + bool iteratif_solver = false; // if false load library: source /opt/intel/oneapi/setvars.sh intel64 + if (iteratif_solver) + dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + } + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of SDIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + + size_t it = 0; + std::ostringstream filename_silo; + filename_silo << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename_silo.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + + // ################################################## + // ################################################## Sensors + // ################################################## + + bool e_side_Q = true; + bool a_side_Q = false; + + std::ostringstream filename_acou; + filename_acou << "AP_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str = filename_acou.str(); + std::ofstream Acoustic_sensor_1_log(filename_acou_str); + typename mesh_type::point_type Acoustic_s1_pt(-0.1, 0.05); + std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); + std::ostringstream filename_acou2; + filename_acou2 << "AV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str2 = filename_acou2.str(); + std::ofstream Acoustic_sensor_2_log(filename_acou_str2); + typename mesh_type::point_type Acoustic_s2_pt(-0.1, 0.05); + std::pair Acoustic_s2_pt_cell = std::make_pair(Acoustic_s2_pt, -1); + + std::ostringstream filename_int; + filename_int << "IP_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_acoustic_pressure.csv"; + std::string filename_int_str = filename_int.str(); + std::ofstream Interface_sensor_acoustic_pressure(filename_int_str); + typename mesh_type::point_type Interface_s1_pt(-0.1, 0.0); + std::pair Interface_s1_pt_cell = std::make_pair(Interface_s1_pt, -1); + std::ostringstream filename_int2; + filename_int2 << "IAV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_acoustic_velocity.csv"; + std::string filename_int_str2 = filename_int2.str(); + std::ofstream Interface_sensor_acoustic_velocity(filename_int_str2); + typename mesh_type::point_type Interface_s2_pt(-0.1, 0.0); + std::pair Interface_s2_pt_cell = std::make_pair(Interface_s2_pt, -1); + std::ostringstream filename_int3; + filename_int3 << "IEV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_elastic_velocity.csv"; + std::string filename_int_str3 = filename_int3.str(); + std::ofstream Interface_sensor_elastic_velocity(filename_int_str3); + typename mesh_type::point_type Interface_s3_pt(-0.1, 0.0); + std::pair Interface_s3_pt_cell = std::make_pair(Interface_s3_pt, -1); + std::ostringstream filename_int4; + filename_int4 << "IS_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_elastic_stress.csv"; + std::string filename_int_str4 = filename_int4.str(); + std::ofstream Interface_sensor_elastic_stress(filename_int_str4); + typename mesh_type::point_type Interface_s4_pt(-0.1, 0.0); + std::pair Interface_s4_pt_cell = std::make_pair(Interface_s4_pt, -1); + + std::ostringstream filename_ela; + filename_ela << "EV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str = filename_ela.str(); + std::ofstream Elastic_sensor_1_log(filename_ela_str); + typename mesh_type::point_type Elastic_s1_pt(-0.1, -0.05); + std::pair Elastic_s1_pt_cell = std::make_pair(Elastic_s1_pt, -1); + std::ostringstream filename_ela2; + filename_ela2 << "ES_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str2 = filename_ela2.str(); + std::ofstream Elastic_sensor_2_log(filename_ela_str2); + typename mesh_type::point_type Elastic_s2_pt(-0.1, -0.05); + std::pair Elastic_s2_pt_cell = std::make_pair(Elastic_s2_pt, -1); + + bool sensors = true; + if (sensors) { + // Acoustic sensor + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); + // Interface sensor + postprocessor::record_acoustic_pressure_coupling_data_elasto_acoustic_four_fields(0, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, interface_face_indexes, Interface_sensor_acoustic_pressure); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_velocity); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_velocity); + postprocessor::record_elastic_data_elasto_acoustic_four_fields(0, Interface_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_stress); + // Elastic sensor + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + postprocessor::record_elastic_data_elasto_acoustic_four_fields(0, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + } + std::cout << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + // DIRK step + tc.tic(); + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + Matrix yn, ki; + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + t = tn + c(i,0) * dt; + assembler.RHS.setZero(); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i), is_sdirk_Q); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + tc.toc(); + std::cout << bold << cyan << " DIRK step completed: " << tc << " seconds" << reset << std::endl; + + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + int silo_mod = static_cast(std::round(nt / 50.0)); // Number of silo files + if (((it == 1 || it == std::round(nt/2) || it == nt)) || (sim_data.m_render_silo_files_Q && (it%silo_mod == 0))) { + std::ostringstream filename; + filename << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + if (sensors) { + // Acoustic sensor + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); + // Interface sensor + postprocessor::record_acoustic_pressure_coupling_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, interface_face_indexes, Interface_sensor_acoustic_pressure); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_velocity); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_velocity); + postprocessor::record_elastic_data_elasto_acoustic_four_fields(it, Interface_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_stress); + // Elastic sensor + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + postprocessor::record_elastic_data_elasto_acoustic_four_fields(it, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + } + + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + t += dt; + + tcit.toc(); + std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/wave_propagation/src/prototypes/coupling/Pulse/IPulseEfficiency.hpp b/apps/wave_propagation/src/prototypes/coupling/Pulse/IPulseEfficiency.hpp new file mode 100644 index 00000000..2903168e --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Pulse/IPulseEfficiency.hpp @@ -0,0 +1,328 @@ + + +// Created by Romain Mottier + + +void IPulseEfficiency(int argc, char **argv); + +void IPulseEfficiency(int argc, char **argv){ + + // ###################################################################### Simulation paramaters + // ###################################################################### + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit; + + // ###################################################################### Mesh generation + // ###################################################################### + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + RealType lx = 5000.0; + RealType ly = 3500.0; + size_t nx = 140; + size_t ny = 140; + cartesian_2d_mesh_builder mesh_builder(lx, ly, nx, ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-2500.0, -2500.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.425; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ###################################################################### Assigning Material Data + // ###################################################################### + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.y()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + + // Assigning the material properties + if (bar.y() > 0) { + acoustic_material_data material = water_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = granit_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.y() > 0) { + interface_cell_pair_indexes[fc_id].second = cell_ind; + } + else { + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.y() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + + // Detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ###################################################################### Solving a primal HHO mixed problem + // ###################################################################### + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + + // Stabilization type + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl << std::endl; + + // ###################################################################### Projecting initial data + // ###################################################################### + + Matrix x_dof; + + // Acoustic pulse intialized in pressure + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, pulse_geophysic_v); + assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + + ////////// Post process of the initial data + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "elasto_acoustic_inhomogeneous_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + std::ofstream simulation_log("elasto_acoustic_inhomogeneous_four_fields.txt"); + std::ofstream energy_file("energy_file.txt"); + + bool e_side_Q = true; + bool a_side_Q = false; + std::ofstream Acoustic_sensor_1_log("Acoustic.csv"); + std::ofstream Interface_sensor_1_log("Interface.csv"); + std::ofstream Elastic_sensor_1_log("Elastic.csv"); + typename mesh_type::point_type Acoustic_s1_pt(-500, 250); + typename mesh_type::point_type Interface_s1_pt(-500, 0.0); + typename mesh_type::point_type Elastic_s1_pt(-500, -250); + std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); + std::pair Interface_s1_pt_cell = std::make_pair(Interface_s1_pt, -1); + std::pair Elastic_s1_pt_cell = std::make_pair(Elastic_s1_pt, -1); + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + } + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + } + else { + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + std::cout << std::endl << std::endl; + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, false); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + dirk_an.set_static_condensation_data(vec_cell_basis_data, assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + std::cout << bold << cyan << " Matrix decomposed: "; + tc.tic(); + dirk_an.ComposeMatrix(); + // dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + } + + // ################################################## + // ################################################## Time marching + // ################################################## + + std::cout << std::endl << std::endl; + + Matrix x_dof_n; + + for(size_t it = 1; it <= nt; it++) { + + + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t + << reset; + + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + t = tn + c(i,0) * dt; + assembler.RHS.setZero(); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + // std::cout << std::endl << bold << cyan << " DIRK step completed: " << tc << " seconds" + // << reset << std::endl; + + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "elasto_acoustic_inhomogeneous_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Acoustic_sensor_1_log); + + t += dt; + + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + } + + std::cout << std::endl; + tcit.toc(); + std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + } + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of equations: " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Number of DIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + diff --git a/apps/wave_propagation/src/prototypes/elastic/EElastic_stability.hpp b/apps/wave_propagation/src/prototypes/elastic/EElastic_stability.hpp new file mode 100644 index 00000000..06aa2cfb --- /dev/null +++ b/apps/wave_propagation/src/prototypes/elastic/EElastic_stability.hpp @@ -0,0 +1,405 @@ + +// Created by Romain Mottier + +void EElastic_stability(int argc, char **argv); + +void EElastic_stability(int argc, char **argv){ + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " ELASTICITY STABILITY" << reset << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, cpu; + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + cpu.tic(); + tc.tic(); + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l0_conv_test_1.0.txt"); // l = 0 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l1_conv_test_0.35.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l2_conv_test_0.15.txt"); // l = 2 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l3_conv_test_0.07.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l4_conv_test_0.035.txt"); // l = 4 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l5_conv_test_0.026.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l6_conv_test_0.017.txt"); // l = 6 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l7_conv_test_0.0125.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l8_conv_test_0.0085.txt"); // l = 8 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l9_conv_test_0.005.txt"); // + + // mesh_files.push_back("../../meshes/conv_test/poly/poly_32.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_64.txt"); // -l 1 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_128.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_256.txt"); // -l 3 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_512.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_1024.txt"); // -l 5 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_2048.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_4096.txt"); // -l 7 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_8192.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_16384.txt"); // -l 9 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_32768.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl << std::endl; + + // ################################################## + // ################################################## Time controls + // ################################################## + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + nt = sim_data.m_nt_divs; + } + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial_paper); + + // Zero source terms, to keep the system energy constant + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + // Elastic analytical functions + auto v_fun = functions.Evaluate_v(t); + auto flux_fun = functions.Evaluate_sigma(t); + + // ################################################## + // ################################################## HHO setting + // ################################################## + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q) { + cell_k_degree++; + } + + // Stabilization type + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ################################################## + // ################################################## Structure setting + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + } + + // detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ################################################## + // ################################################## Projecting initial data + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, v_fun, flux_fun, null_s_fun, null_fun); + assembler.project_over_faces(msh, x_dof, v_fun, null_s_fun); + + // ################################################## + // ################################################## Setting of the time marching scheme + // ################################################## + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // ERK(s) schemes + int s = 4; + erk_butcher_tableau::erk_tables(s, a, b, c); + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, true); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = 0.0; + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = 0.0; + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes);//assembler.get_interfaces()); + + tc.toc(); + std::cout << bold << cyan << " ERK analysis created: " << tc << " seconds" << reset << std::endl; + tc.tic(); + erk_an.refresh_faces_unknowns(x_dof); + tc.toc(); + std::cout << bold << cyan << " Inverse of Sff + Coupling in: " << tc << " seconds" << reset << std::endl; + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "elasto_acoustic_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material,false); + std::cout << std::endl; + } + + std::ostringstream filename; + filename << "E_explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "h size = " << h << std::endl; + simulation_log << "CFL c(dt/h) = " << std::sqrt(3.0)*dt/h << std::endl; + auto block_dimension = assembler.Scc_block_dimension(); + // erk_an.compute_eigenvalues_bis(assembler.LHS_STAB, block_dimension, simulation_log); + erk_an.compute_eigenvalues(simulation_log); + simulation_log.flush(); + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + auto energy_0 = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + bool approx_fail_check_Q = false; + RealType energy = energy_0; + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << red << " Time step number " << it << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + x_dof_n = x_dof; + + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + t = tn + c(i,0) * dt; + { + assembler.assemble_rhs(msh, null_fun, null_s_fun, true); + erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + } + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + + tc.toc(); + std::cout << bold << cyan << " ERK step completed: " << tc << " seconds" << reset; + x_dof = x_dof_n; + t = tn + dt; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "elasto_acoustic_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + // Energy evaluation + RealType energy_n = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + RealType relative_energy = (energy_n - energy) / energy; + RealType relative_energy_0 = (energy_n - energy_0) / energy_0; + bool unstable_check_Q = (relative_energy > 1.0e-2) || (relative_energy_0 >= 1.0e-2); + if (unstable_check_Q) { + std::cout << std::endl << std::endl << bold << red << " Simulation is unstable" << reset << std::endl; + break; + } + energy = energy_n; + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << std::endl << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; +} + diff --git a/apps/wave_propagation/src/prototypes/elastic/EElasticity_CFL.hpp b/apps/wave_propagation/src/prototypes/elastic/EElasticity_CFL.hpp new file mode 100644 index 00000000..6cf52f02 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/elastic/EElasticity_CFL.hpp @@ -0,0 +1,397 @@ + + +// Created by Romain Mottier +// ../wave_propagation -k 1 -s 0 -r 0 -c 1 -p 0 -l 2 -n 350 -f 0 -e 0 + +void EElasticity_CFL(int argc, char **argv); + +void EElasticity_CFL(int argc, char **argv){ + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " ELASTIC CFL" << std::endl << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc; + + // ################################################## + // ################################################## Time controls + // ################################################## + + RealType ti = 0.0; + RealType tf = 1.0; + RealType t = ti; + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial_paper); + + // Zero source terms, to keep the system energy constant + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + // Elastic analytical functions + auto v_fun = functions.Evaluate_v(t); + auto flux_fun = functions.Evaluate_sigma(t); + + // ################################################## + // ################################################## HHO setting + // ################################################## + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if (sim_data.m_hdg_stabilization_Q) { + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l0_conv_test_1.0.txt"); // l = 0 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l1_conv_test_0.35.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l2_conv_test_0.15.txt"); // l = 2 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l3_conv_test_0.07.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l4_conv_test_0.035.txt"); // l = 4 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l5_conv_test_0.026.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l6_conv_test_0.017.txt"); // l = 6 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l7_conv_test_0.0125.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l8_conv_test_0.0085.txt"); // l = 8 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l9_conv_test_0.005.txt"); // + + // mesh_files.push_back("../../meshes/conv_test/poly/poly_32.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_64.txt"); // -l 1 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_128.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_256.txt"); // -l 3 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_512.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_1024.txt"); // -l 5 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_2048.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_4096.txt"); // -l 7 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_8192.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_16384.txt"); // -l 9 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_32768.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl << std::endl; + + // ################################################## + // ################################################## Material data + // ################################################## + + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + // ################################################## + // ################################################## Interface detection and faces repartitions + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + RealType eps = 1.0e-10; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + interface_cell_pair_indexes[fc_id].second = cell_ind; + } + } + } + + // Internal faces structure for explicit schemes + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + } + else { + elastic_internal_faces.insert(fc_id); + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + + // boundary condition + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ######################s########################### + + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if (sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + assembler.assemble_mass(msh); + assembler.assemble_coupling_terms(msh); + + // ################################################## + // ################################################## Setting of the time marching scheme + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, null_fun); + assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + bool explicit_scheme = true; + assembler.assemble(msh, null_fun, null_s_fun, explicit_scheme); + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = 0.0; + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = 0.0; + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes); + erk_an.refresh_faces_unknowns(x_dof); + + // ################################################## + // ################################################## Loop over the ERK schemes + // ################################################## + + for (int s = 2; s < 5; s++) { + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + // nt *= 2; + nt = sim_data.m_nt_divs; + } + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "E_explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + auto block_dimension = assembler.Scc_block_dimension(); + // erk_an.compute_eigenvalues_bis(assembler.LHS_STAB, block_dimension, simulation_log); + // erk_an.compute_eigenvalues(simulation_log); + simulation_log.flush(); + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + auto energy_0 = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + std::cout << bold << red << " ERK(" << s << "):" << reset << std::endl << std::endl; + simulation_log << std::endl << " ERK(" << s << "):" << std::endl; + simulation_log << std::endl; + + // ################################################## + // ################################################## Loop over level of time refinement + // ################################################## + + for (unsigned int i = 0; i < 100; i++) { + + t = ti; + RealType dt = (tf-ti)/nt; + simulation_log << "Step size = " << dt << std::endl; + + // Projecting initial data + assembler.project_over_cells(msh, x_dof, v_fun, flux_fun, null_s_fun, null_fun); + assembler.project_over_faces(msh, x_dof, v_fun, null_s_fun); + + auto energy_0 = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + erk_butcher_tableau::erk_tables(s, a, b, c); + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + bool approx_fail_check_Q = false; + RealType energy = energy_0; + + for(size_t it = 1; it <= nt; it++) { + + RealType tn = dt*(it-1)+ti; + + // ERK steps + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + Matrix yn, ki; + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + RealType t = tn + c(i,0) * dt; + assembler.assemble_rhs(msh, null_fun, null_s_fun, true); + erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + x_dof = x_dof_n; + t = tn + dt; + RealType energy_n = postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + RealType relative_energy = (energy_n - energy) / energy; + RealType relative_energy_0 = (energy_n - energy_0) / energy_0; + bool unstable_check_Q = (relative_energy > 5.0e-2) || (relative_energy_0 >= 5.0e-2); + if (unstable_check_Q) { // energy is increasing + approx_fail_check_Q = true; + break; + } + energy = energy_n; + } + if (approx_fail_check_Q) { + std::cout << bold << red << " Simulation is unstable" << reset << std::endl << std::endl << std::endl; + simulation_log << std::endl; + simulation_log << " Simulation is unstable for:"<< std::endl; + simulation_log << " Number of equations: " << assembler.RHS.rows() << std::endl; + simulation_log << " Number of ERK steps = " << s << std::endl; + simulation_log << " Number of time steps = " << nt << std::endl; + simulation_log << " dt size = " << dt << std::endl; + simulation_log << " h size = " << h << std::endl; + simulation_log << " CFL c(dt/h) = " << std::sqrt(3.0)*dt/h << std::endl; + simulation_log << std::endl; + simulation_log.flush(); + break; + } + else { + simulation_log << " Simulation is stable for:"<< std::endl; + simulation_log << " Number of equations: " << assembler.RHS.rows() << std::endl; + simulation_log << " Number of ERK steps = " << s << std::endl; + simulation_log << " Number of time steps = " << nt << std::endl; + simulation_log << " dt size = " << dt << std::endl; + simulation_log << " h size = " << h << std::endl; + simulation_log << " CFL c(dt/h) = " << std::sqrt(3.0)*dt/h << std::endl; + simulation_log << std::endl; + simulation_log.flush(); + std::cout << " Simulation is stable for: n = " << nt << std::endl; + nt = int(nt - (nt*1/100+1)); + continue; + // break; + } + } + simulation_log << std::endl << " ******************************* " << std::endl; + simulation_log << std::endl << std::endl; + } + +} + + diff --git a/apps/wave_propagation/src/prototypes/elastic/ElasticIHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/elastic/ElasticIHHOFirstOrder.hpp new file mode 100644 index 00000000..ec1fdbf0 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/elastic/ElasticIHHOFirstOrder.hpp @@ -0,0 +1,308 @@ + + +// Created by Romain Mottier + +void ElasticIHHOFirstOrder(int argc, char **argv); + +void ElasticIHHOFirstOrder(int argc, char **argv){ + + // ###################################################################### Simulation paramaters + // ###################################################################### + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit; + + // ###################################################################### Mesh generation + // ###################################################################### + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + Mesh_generation(sim_data, msh); + + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.5; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ###################################################################### Assigning Material Data + // ###################################################################### + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + + // Detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ###################################################################### Solving a primal HHO mixed problem + // ###################################################################### + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + + // Stabilization type + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + // ###################################################################### Projecting initial data + // ###################################################################### + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, sin_elastic, null_flux_fun, null_s_fun, null_fun); + assembler.project_over_faces(msh, x_dof, sin_elastic, null_s_fun); + + ////////// Post process of the initial data + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "elasto_acoustic_inhomogeneous_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + std::ofstream simulation_log("elasto_acoustic_inhomogeneous_four_fields.txt"); + std::ofstream energy_file("energy_file.txt"); + std::ofstream dissipation_file("dissipation_file.txt"); + + std::ofstream Elastic_sensor_1_log("Elastic_s1_four_fields_h.csv"); + std::ofstream Elastic_sensor_2_log("Elastic_s2_four_fields_h.csv"); + std::ofstream Elastic_sensor_3_log("Elastic_s3_four_fields_h.csv"); + std::ofstream Elastic_sensor_4_log("Elastic_s4_four_fields_h.csv"); + bool e_side_Q = true; + bool a_side_Q = false; + typename mesh_type::point_type Elastic_s1_pt(-7.5, -2.5); + typename mesh_type::point_type Elastic_s2_pt(-5.0, -2.5); + typename mesh_type::point_type Elastic_s3_pt(-2.5, -2.5); + typename mesh_type::point_type Elastic_s4_pt( 0.0, -2.5); + std::pair Elastic_s1_pt_cell = std::make_pair(Elastic_s1_pt, -1); + std::pair Elastic_s2_pt_cell = std::make_pair(Elastic_s2_pt, -1); + std::pair Elastic_s3_pt_cell = std::make_pair(Elastic_s3_pt, -1); + std::pair Elastic_s4_pt_cell = std::make_pair(Elastic_s4_pt, -1); + std::cout << bold << cyan << " " << "Elastic sensor at (-7.5,-2.5)" << reset << std::endl; + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + std::cout << bold << cyan << " " << "Elastic sensor at (-5.0,-2.5)" << reset << std::endl; + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + std::cout << bold << cyan << " " << "Elastic sensor at (-2.5,-2.5)" << reset << std::endl; + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_3_log); + std::cout << bold << cyan << " " << "Elastic sensor at (0.0,-2.5)" << reset << std::endl; + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_4_log); + + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + postprocessor::compute_elasto_acoustic_dissipation_four_field(assembler, t, x_dof, dissipation_file); + } + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + } + else { + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + std::cout << std::endl << std::endl; + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + dirk_an.set_static_condensation_data(vec_cell_basis_data, assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + std::cout << bold << cyan << " Matrix decomposed: "; + tc.tic(); + dirk_an.ComposeMatrix(); + // dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + } + + // ################################################## + // ################################################## Time marching + // ################################################## + + std::cout << std::endl << std::endl; + + Matrix x_dof_n; + + for(size_t it = 1; it <= nt; it++) { + + + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t + << reset; + + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + t = tn + c(i,0) * dt; + assembler.RHS.setZero(); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + // std::cout << std::endl << bold << cyan << " DIRK step completed: " << tc << " seconds" + // << reset << std::endl; + + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "elasto_acoustic_inhomogeneous_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_3_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_4_log); + + t += dt; + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, + t, x_dof, energy_file); + postprocessor::compute_elasto_acoustic_dissipation_four_field(assembler, t, x_dof, dissipation_file); + } + + std::cout << std::endl; + tcit.toc(); + std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + + + } + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of equations: " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Number of DIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/wave_propagation/src/prototypes/elastic/IElastic_conv_test.hpp b/apps/wave_propagation/src/prototypes/elastic/IElastic_conv_test.hpp new file mode 100644 index 00000000..3f7b995d --- /dev/null +++ b/apps/wave_propagation/src/prototypes/elastic/IElastic_conv_test.hpp @@ -0,0 +1,397 @@ + + +// Created by Romain Mottier + +void IElastic_conv_test(int argc, char **argv); + +void IElastic_conv_test(int argc, char **argv){ + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " IMPLICIT ELASTIC CONV TEST" << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, cpu; + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + cpu.tic(); + tc.tic(); + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l0_conv_test_1.0.txt"); // l = 0 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l1_conv_test_0.35.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l2_conv_test_0.15.txt"); // l = 2 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l3_conv_test_0.07.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l4_conv_test_0.035.txt"); // l = 4 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l5_conv_test_0.026.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l6_conv_test_0.017.txt"); // l = 6 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l7_conv_test_0.0125.txt"); // + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l8_conv_test_0.0085.txt"); // l = 8 + mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l9_conv_test_0.005.txt"); // + + // mesh_files.push_back("../../meshes/conv_test/poly/poly_32.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_64.txt"); // -l 1 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_128.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_256.txt"); // -l 3 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_512.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_1024.txt"); // -l 5 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_2048.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_4096.txt"); // -l 7 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_8192.txt"); + // mesh_files.push_back("../../meshes/conv_test/poly/poly_16384.txt"); // -l 9 + // mesh_files.push_back("../../meshes/conv_test/poly/poly_32768.txt"); + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ################################################## + // ################################################## Time controls + // ################################################## + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + // nt = sim_data.m_nt_divs; + } + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + //functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + //functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + //functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::reproduction_elastic); + + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + // Elastic analytical functions + auto u_fun = functions.Evaluate_u(t); + auto v_fun = functions.Evaluate_v(t); + auto a_fun = functions.Evaluate_a(t); + auto f_fun = functions.Evaluate_f(t); + auto flux_fun = functions.Evaluate_sigma(t); + + // ################################################## + // ################################################## HHO setting + // ################################################## + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q) { + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt)-> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + // ################################################## + // ################################################## Structure setting + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + + // detect interface elastic - acoustic + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, u_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ################################################## + // ################################################## Projecting initial data + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, v_fun, flux_fun, null_s_fun, null_fun); + assembler.project_over_faces(msh, x_dof, v_fun, null_s_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 2; + bool is_sdirk_Q = true; + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + } + else { + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, v_fun, null_s_fun, false); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + dirk_an.set_static_condensation_data(vec_cell_basis_data, assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + std::cout << bold << cyan << " Matrix decomposed: "; + tc.tic(); + dirk_an.ComposeMatrix(); + bool iteratif_solver = false; // if false load library: /opt/intel/oneapi/setvars.sh intel64 + if (iteratif_solver) { + dirk_an.setIterativeSolver(); + } + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + } + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "E_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of SDIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + + std::ostringstream filename_e; + filename_e << "E_energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + } + std::cout << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << red << " Time step number " << it << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + t = tn + c(i,0) * dt; + // Manufactured solution + auto v_fun = functions.Evaluate_v(t); + auto flux_fun = functions.Evaluate_sigma(t); + + assembler.get_e_bc_conditions().updateDirichletFunction(v_fun, 0); + assembler.assemble_rhs(msh, f_fun, null_s_fun, false); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + + tc.toc(); + std::cout << bold << cyan << " DIRK step completed: " << tc << " seconds" << reset << std::endl << std::endl; + x_dof = x_dof_n; + t = tn + dt; + auto v_fun = functions.Evaluate_v(t); + auto flux_fun = functions.Evaluate_sigma(t); + + if(it == nt){ + // Computing errors + postprocessor::compute_errors_four_fields_elastoacoustic(msh, hho_di, assembler, x_dof, v_fun, flux_fun, null_s_fun, null_fun, simulation_log); + std::cout << std::endl; + } + + } + + bool mesh_quality = false; + if (mesh_quality) { + std::ostringstream mesh_file_name; + mesh_file_name << "mesh_quality_l" << sim_data.m_n_divs << ".txt"; + std::string mesh_file_str = mesh_file_name.str(); + std::ofstream mesh_file(mesh_file_str); + postprocessor::mesh_quality(msh, assembler, mesh_file); + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + diff --git a/apps/wave_propagation/src/prototypes/elastodynamics_old/CMakeLists.txt b/apps/wave_propagation/src/prototypes/elastodynamics_old/CMakeLists.txt new file mode 100644 index 00000000..ff30940b --- /dev/null +++ b/apps/wave_propagation/src/prototypes/elastodynamics_old/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(elastodynamics elastodynamics.cpp ${fitted_waves_headers} ${fitted_waves_sources}) +target_link_libraries(elastodynamics ${LINK_LIBS}) diff --git a/apps/wave_propagation/src/prototypes/elastodynamics_old/elastodynamics.cpp b/apps/wave_propagation/src/prototypes/elastodynamics_old/elastodynamics.cpp new file mode 100644 index 00000000..eaca52cc --- /dev/null +++ b/apps/wave_propagation/src/prototypes/elastodynamics_old/elastodynamics.cpp @@ -0,0 +1,3122 @@ + +// Contributions by Omar Durán and Romain Mottier + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +using namespace Eigen; + +#include "timecounter.h" +#include "methods/hho" +#include "geometry/geometry.hpp" +#include "boundary_conditions/boundary_conditions.hpp" +#include "output/silo.hpp" + +// application common sources +#include "../common/display_settings.hpp" +#include "../common/fitted_geometry_builders.hpp" +#include "../common/linear_solver.hpp" +#include "../common/vec_analytic_functions.hpp" +#include "../common/preprocessor.hpp" +#include "../common/postprocessor.hpp" + +// implicit RK schemes +#include "../common/dirk_hho_scheme.hpp" +#include "../common/dirk_butcher_tableau.hpp" + +// explicit RK schemes +#include "../common/ssprk_hho_scheme.hpp" +#include "../common/ssprk_shu_osher_tableau.hpp" + +void HeterogeneousGar6more2DIHHOSecondOrder(int argc, char **argv); + +void HeterogeneousGar6more2DIHHOFirstOrder(int argc, char **argv); + +void HeterogeneousGar6more2DIHHOFirstOrderTwoFields(int argc, char **argv); + +void Gar6more2DIHHOSecondOrder(int argc, char **argv); + +void Gar6more2DIHHOFirstOrder(int argc, char **argv); + +void HeterogeneousIHHOFirstOrder(int argc, char **argv); + +void HeterogeneousIHHOSecondOrder(int argc, char **argv); + +void EHHOFirstOrder(int argc, char **argv); + +void IHHOFirstOrderTwoFields(int argc, char **argv); + +void IHHOFirstOrder(int argc, char **argv); + +void IHHOSecondOrder(int argc, char **argv); + +void HHOOneFieldConvergenceExample(int argc, char **argv); + +void HHOTwoFieldsConvergenceExample(int argc, char **argv); + +void HHOThreeFieldsConvergenceExample(int argc, char **argv); + +int main(int argc, char **argv) +{ + + HeterogeneousGar6more2DIHHOFirstOrderTwoFields(argc, argv); + +// HeterogeneousGar6more2DIHHOFirstOrder(argc, argv); +// HeterogeneousGar6more2DIHHOSecondOrder(argc, argv); + +// Gar6more2DIHHOFirstOrder(argc, argv); +// Gar6more2DIHHOSecondOrder(argc, argv); + +// HeterogeneousIHHOFirstOrder(argc, argv); +// HeterogeneousIHHOSecondOrder(argc, argv); + +// EHHOFirstOrder(argc, argv); +// IHHOFirstOrderTwoFields(argc, argv); +// IHHOFirstOrder(argc, argv); +// IHHOSecondOrder(argc, argv); + +// // Examples using main app objects for solving a linear elastic problem with optimal convergence rates + // Primal HHO +// HHOOneFieldConvergenceExample(argc, argv); + // Dual HHO +// HHOTwoFieldsConvergenceExample(argc, argv); +// HHOThreeFieldsConvergenceExample(argc, argv); + + return 0; +} + +void HHOOneFieldConvergenceExample(int argc, char **argv){ + + using RealType = double; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + + simulation_data sim_data = preprocessor::process_convergence_test_args(argc, argv); + sim_data.print_simulation_data(); + + // Manufactured exact solution + bool quadratic_function_Q = false; + bool Nonzero_Dirichlet_Q = false; + RealType lambda = 1000.0; + auto exact_vec_fun = [quadratic_function_Q,Nonzero_Dirichlet_Q](const mesh_type::point_type& pt) -> static_vector { + RealType x,y; + x = pt.x(); + y = pt.y(); + if(quadratic_function_Q){ + RealType ux = (1 - x)*x*(1 - y)*y; + RealType uy = (1 - x)*x*(1 - y)*y; + return static_vector{ux, uy}; + }else{ + if (Nonzero_Dirichlet_Q) { + RealType ux = - std::sin(M_PI * pt.x()) * std::cos(M_PI * pt.y()); + RealType uy = + std::cos(M_PI * pt.x()) * std::sin(M_PI * pt.y()); + return static_vector{ux, uy}; + }else{ + RealType ux = std::sin(2.0 * M_PI * pt.x()) * std::sin(2.0 * M_PI * pt.y()); + RealType uy = std::sin(3.0 * M_PI * pt.x()) * std::sin(3.0 * M_PI * pt.y()); + return static_vector{ux, uy}; + } + + } + + }; + + auto exact_flux_fun = [quadratic_function_Q,Nonzero_Dirichlet_Q,lambda](const typename mesh_type::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + if(quadratic_function_Q){ + static_matrix sigma = static_matrix::Zero(2,2); + RealType sxx = 2*(1 - x)*(1 - y)*y - 2*x*(1 - y)*y + (2*(1 - x)*x*(1 - y) - 2*(1 - x)*x*y)/2. + (2*(1 - x)*(1 - y)*y - 2*x*(1 - y)*y)/2.; + RealType sxy = (1 - x)*x*(1 - y) - (1 - x)*x*y + (1 - x)*(1 - y)*y - x*(1 - y)*y; + RealType syy = 2*(1 - x)*x*(1 - y) - 2*(1 - x)*x*y + (2*(1 - x)*x*(1 - y) - 2*(1 - x)*x*y)/2. + (2*(1 - x)*(1 - y)*y - 2*x*(1 - y)*y)/2.; + sigma(0,0) = sxx; + sigma(0,1) = sxy; + sigma(1,0) = sxy; + sigma(1,1) = syy; + return sigma; + }else{ + static_matrix sigma = static_matrix::Zero(2,2); + if (Nonzero_Dirichlet_Q) { + RealType sxx = - 2.0 * M_PI * std::cos(M_PI * x) * std::cos(M_PI * y); + RealType syy = + 2.0 * M_PI * std::cos(M_PI * x) * std::cos(M_PI * y); + sigma(0,0) = sxx; + sigma(1,1) = syy; + return sigma; + }else{ + RealType sxx = 4*M_PI*std::cos(2*M_PI*x)*std::sin(2*M_PI*y) + + lambda*(3*M_PI*std::cos(3*M_PI*y)*std::sin(3*M_PI*x) + 2*M_PI*std::cos(2*M_PI*x)*std::sin(2*M_PI*y)); + RealType sxy = 2*M_PI*std::cos(2*M_PI*y)*std::sin(2*M_PI*x) + + 3*M_PI*std::cos(3*M_PI*x)*std::sin(3*M_PI*y); + RealType syy = 6*M_PI*std::cos(3*M_PI*y)*std::sin(3*M_PI*x) + + lambda*(3*M_PI*std::cos(3*M_PI*y)*std::sin(3*M_PI*x) + 2*M_PI*std::cos(2*M_PI*x)*std::sin(2*M_PI*y)); + sigma(0,0) = sxx; + sigma(0,1) = sxy; + sigma(1,0) = sxy; + sigma(1,1) = syy; + return sigma; + } + } + + }; + + auto rhs_fun = [quadratic_function_Q,Nonzero_Dirichlet_Q,lambda](const typename mesh_type::point_type& pt) -> static_vector { + double x,y; + x = pt.x(); + y = pt.y(); + if(quadratic_function_Q){ + RealType fx = 2*(1 + x*x + y*(-5 + 3*y) + x*(-3 + 4*y)); + RealType fy = 2*(1 + 3*x*x + (-3 + y)*y + x*(-5 + 4*y)); + return static_vector{-fx, -fy}; + }else{ + if (Nonzero_Dirichlet_Q) { + RealType fx = + 2.0 * M_PI * M_PI * ( std::sin(M_PI * x) * std::cos( M_PI * y)); + RealType fy = - 2.0 * M_PI * M_PI * ( std::cos(M_PI * x) * std::sin( M_PI * y)); + return static_vector{-fx, -fy}; + }else{ + RealType fx = M_PI*M_PI*(9*(1 + lambda)*std::cos(3*M_PI*x)*std::cos(3*M_PI*y) - 4*(3 + lambda)*std::sin(2*M_PI*x)*std::sin(2*M_PI*y)); + RealType fy = M_PI*M_PI*(4*(1 + lambda)*std::cos(2*M_PI*x)*std::cos(2*M_PI*y) - 9*(3 + lambda)*std::sin(3*M_PI*x)*std::sin(3*M_PI*y)); + return static_vector{-fx, -fy}; + } + } + }; + + // simple material + RealType rho = 1.0; + RealType vp; + if (Nonzero_Dirichlet_Q || quadratic_function_Q) { + vp = std::sqrt(3.0); + }else{ + vp = std::sqrt(2.0 + lambda); + } + RealType vs = 1.0; + elastic_material_data material(rho,vp,vs); + + std::ofstream error_file("steady_vector_error.txt"); + + for(size_t k = 1; k <= sim_data.m_k_degree; k++){ + std::cout << bold << cyan << "Running an approximation with k : " << k << reset << std::endl; + error_file << "Approximation with k : " << k << std::endl; + for(size_t l = 0; l <= sim_data.m_n_divs; l++){ + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(l); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = k; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,k); + + // Solving a scalar primal HHO problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_vec_fun); + tc.tic(); + auto assembler = elastodynamic_one_field_assembler(msh, hho_di, bnd); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + assembler.load_material_data(msh,material); + assembler.assemble(msh, rhs_fun); + assembler.apply_bc(msh); + tc.toc(); + std::cout << bold << cyan << "Assemble in : " << tc << " seconds" << reset << std::endl; + + // Solving LS + + Matrix x_dof; + if (sim_data.m_sc_Q) { + tc.tic(); + linear_solver analysis(assembler.LHS,assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + tc.toc(); + std::cout << bold << cyan << "Create analysis in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + x_dof = analysis.solve(assembler.RHS); + tc.toc(); + std::cout << bold << cyan << "Linear Solve in : " << tc << " seconds" << reset << std::endl; + std::cout << bold << cyan << "Number of equations (SC) : " << analysis.n_equations() << reset << std::endl; + }else{ + tc.tic(); + linear_solver analysis(assembler.LHS); + tc.toc(); + std::cout << bold << cyan << "Create analysis in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + x_dof = analysis.solve(assembler.RHS); + tc.toc(); + std::cout << bold << cyan << "Linear Solve in : " << tc << " seconds" << reset << std::endl; + std::cout << bold << cyan << "Number of equations : " << analysis.n_equations() << reset << std::endl; + } + + // Computing errors + postprocessor::compute_errors_one_field_vectorial(msh, hho_di, assembler, x_dof, exact_vec_fun, exact_flux_fun,error_file); + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "steady_vector_k" + std::to_string(k) + "_"; + postprocessor::write_silo_one_field_vectorial(silo_file_name, l, msh, hho_di, x_dof, exact_vec_fun, false); + } + } + error_file << std::endl << std::endl; + } + error_file.close(); +} + +void HHOTwoFieldsConvergenceExample(int argc, char **argv){ + + using RealType = double; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + + simulation_data sim_data = preprocessor::process_convergence_test_args(argc, argv); + sim_data.print_simulation_data(); + + // Manufactured exact solution + bool quadratic_function_Q = false; + bool Nonzero_Dirichlet_Q = false; + RealType lambda = 1000.0; + auto exact_vec_fun = [quadratic_function_Q,Nonzero_Dirichlet_Q](const mesh_type::point_type& pt) -> static_vector { + RealType x,y; + x = pt.x(); + y = pt.y(); + if(quadratic_function_Q){ + RealType ux = (1 - x)*x*(1 - y)*y; + RealType uy = (1 - x)*x*(1 - y)*y; + return static_vector{ux, uy}; + }else{ + if (Nonzero_Dirichlet_Q) { + RealType ux = - std::sin(M_PI * pt.x()) * std::cos(M_PI * pt.y()); + RealType uy = + std::cos(M_PI * pt.x()) * std::sin(M_PI * pt.y()); + return static_vector{ux, uy}; + }else{ + RealType ux = std::sin(2.0 * M_PI * pt.x()) * std::sin(2.0 * M_PI * pt.y()); + RealType uy = std::sin(3.0 * M_PI * pt.x()) * std::sin(3.0 * M_PI * pt.y()); + return static_vector{ux, uy}; + } + + } + + }; + + auto exact_flux_fun = [quadratic_function_Q,Nonzero_Dirichlet_Q,lambda](const typename mesh_type::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + if(quadratic_function_Q){ + static_matrix sigma = static_matrix::Zero(2,2); + RealType sxx = 2*(1 - x)*(1 - y)*y - 2*x*(1 - y)*y + (2*(1 - x)*x*(1 - y) - 2*(1 - x)*x*y)/2. + (2*(1 - x)*(1 - y)*y - 2*x*(1 - y)*y)/2.; + RealType sxy = (1 - x)*x*(1 - y) - (1 - x)*x*y + (1 - x)*(1 - y)*y - x*(1 - y)*y; + RealType syy = 2*(1 - x)*x*(1 - y) - 2*(1 - x)*x*y + (2*(1 - x)*x*(1 - y) - 2*(1 - x)*x*y)/2. + (2*(1 - x)*(1 - y)*y - 2*x*(1 - y)*y)/2.; + sigma(0,0) = sxx; + sigma(0,1) = sxy; + sigma(1,0) = sxy; + sigma(1,1) = syy; + return sigma; + }else{ + static_matrix sigma = static_matrix::Zero(2,2); + if (Nonzero_Dirichlet_Q) { + RealType sxx = - 2.0 * M_PI * std::cos(M_PI * x) * std::cos(M_PI * y); + RealType syy = + 2.0 * M_PI * std::cos(M_PI * x) * std::cos(M_PI * y); + sigma(0,0) = sxx; + sigma(1,1) = syy; + return sigma; + }else{ + RealType sxx = 4*M_PI*std::cos(2*M_PI*x)*std::sin(2*M_PI*y) + + lambda*(3*M_PI*std::cos(3*M_PI*y)*std::sin(3*M_PI*x) + 2*M_PI*std::cos(2*M_PI*x)*std::sin(2*M_PI*y)); + RealType sxy = 2*M_PI*std::cos(2*M_PI*y)*std::sin(2*M_PI*x) + + 3*M_PI*std::cos(3*M_PI*x)*std::sin(3*M_PI*y); + RealType syy = 6*M_PI*std::cos(3*M_PI*y)*std::sin(3*M_PI*x) + + lambda*(3*M_PI*std::cos(3*M_PI*y)*std::sin(3*M_PI*x) + 2*M_PI*std::cos(2*M_PI*x)*std::sin(2*M_PI*y)); + sigma(0,0) = sxx; + sigma(0,1) = sxy; + sigma(1,0) = sxy; + sigma(1,1) = syy; + return sigma; + } + } + + }; + + auto rhs_fun = [quadratic_function_Q,Nonzero_Dirichlet_Q,lambda](const typename mesh_type::point_type& pt) -> static_vector { + double x,y; + x = pt.x(); + y = pt.y(); + if(quadratic_function_Q){ + RealType fx = 2*(1 + x*x + y*(-5 + 3*y) + x*(-3 + 4*y)); + RealType fy = 2*(1 + 3*x*x + (-3 + y)*y + x*(-5 + 4*y)); + return static_vector{-fx, -fy}; + }else{ + if (Nonzero_Dirichlet_Q) { + RealType fx = + 2.0 * M_PI * M_PI * ( std::sin(M_PI * x) * std::cos( M_PI * y)); + RealType fy = - 2.0 * M_PI * M_PI * ( std::cos(M_PI * x) * std::sin( M_PI * y)); + return static_vector{-fx, -fy}; + }else{ + RealType fx = M_PI*M_PI*(9*(1 + lambda)*std::cos(3*M_PI*x)*std::cos(3*M_PI*y) - 4*(3 + lambda)*std::sin(2*M_PI*x)*std::sin(2*M_PI*y)); + RealType fy = M_PI*M_PI*(4*(1 + lambda)*std::cos(2*M_PI*x)*std::cos(2*M_PI*y) - 9*(3 + lambda)*std::sin(3*M_PI*x)*std::sin(3*M_PI*y)); + return static_vector{-fx, -fy}; + } + } + }; + + // simple material + RealType rho = 1.0; + RealType vp; + if (Nonzero_Dirichlet_Q || quadratic_function_Q) { + vp = std::sqrt(3.0); + }else{ + vp = std::sqrt(2.0 + lambda); + } + RealType vs = 1.0; + elastic_material_data material(rho,vp,vs); + + std::ofstream error_file("steady_vector_mixed_two_fields_error.txt"); + + for(size_t k = 1; k <= sim_data.m_k_degree; k++){ + std::cout << bold << cyan << "Running an approximation with k : " << k << reset << std::endl; + error_file << "Approximation with k : " << k << std::endl; + for(size_t l = 0; l <= sim_data.m_n_divs; l++){ + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(l); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = k; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,k); + + // Solving a scalar primal HHO problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_vec_fun); + tc.tic(); + auto assembler = elastodynamic_two_fields_assembler(msh, hho_di, bnd); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + assembler.load_material_data(msh,material); + assembler.assemble(msh, rhs_fun); + assembler.assemble_mass(msh, false); + assembler.apply_bc(msh); + tc.toc(); + std::cout << bold << cyan << "Assemble in : " << tc << " seconds" << reset << std::endl; + + // Solving LS + Matrix x_dof; + if (sim_data.m_sc_Q) { + tc.tic(); + SparseMatrix Kg = assembler.LHS+assembler.MASS; + linear_solver analysis(Kg,assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + tc.toc(); + + std::cout << bold << cyan << "Create analysis in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + x_dof = analysis.solve(assembler.RHS); + tc.toc(); + std::cout << bold << cyan << "Linear Solve in : " << tc << " seconds" << reset << std::endl; + std::cout << bold << cyan << "Number of equations (SC) : " << analysis.n_equations() << reset << std::endl; + }else{ + tc.tic(); + SparseMatrix Kg = assembler.LHS+assembler.MASS; + linear_solver analysis(Kg); + tc.toc(); + std::cout << bold << cyan << "Create analysis in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + x_dof = analysis.solve(assembler.RHS); + tc.toc(); + std::cout << bold << cyan << "Linear Solve in : " << tc << " seconds" << reset << std::endl; + std::cout << bold << cyan << "Number of equations : " << analysis.n_equations() << reset << std::endl; + } + + // Computing errors + postprocessor::compute_errors_two_fields_vectorial(msh, hho_di, x_dof, exact_vec_fun, exact_flux_fun, error_file); + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "steady_vector_mixed_two_fields_k" + std::to_string(k) + "_"; + postprocessor::write_silo_two_fields_vectorial(silo_file_name, l, msh, hho_di, x_dof, exact_vec_fun, exact_flux_fun, false); + } + } + error_file << std::endl << std::endl; + } + error_file.close(); + + +} + +void HHOThreeFieldsConvergenceExample(int argc, char **argv){ + + using RealType = double; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + + simulation_data sim_data = preprocessor::process_convergence_test_args(argc, argv); + sim_data.print_simulation_data(); + + // Manufactured exact solution + bool quadratic_function_Q = false; + bool Nonzero_Dirichlet_Q = false; + RealType lambda = 1000.0; + auto exact_vec_fun = [quadratic_function_Q,Nonzero_Dirichlet_Q](const mesh_type::point_type& pt) -> static_vector { + RealType x,y; + x = pt.x(); + y = pt.y(); + if(quadratic_function_Q){ + RealType ux = (1 - x)*x*(1 - y)*y; + RealType uy = (1 - x)*x*(1 - y)*y; + return static_vector{ux, uy}; + }else{ + if (Nonzero_Dirichlet_Q) { + RealType ux = - std::sin(M_PI * pt.x()) * std::cos(M_PI * pt.y()); + RealType uy = + std::cos(M_PI * pt.x()) * std::sin(M_PI * pt.y()); + return static_vector{ux, uy}; + }else{ + RealType ux = std::sin(2.0 * M_PI * pt.x()) * std::sin(2.0 * M_PI * pt.y()); + RealType uy = std::sin(3.0 * M_PI * pt.x()) * std::sin(3.0 * M_PI * pt.y()); + return static_vector{ux, uy}; + } + + } + + }; + + auto exact_flux_fun = [quadratic_function_Q,Nonzero_Dirichlet_Q,lambda](const typename mesh_type::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + if(quadratic_function_Q){ + static_matrix sigma = static_matrix::Zero(2,2); + RealType sxx = 2*(1 - x)*(1 - y)*y - 2*x*(1 - y)*y + (2*(1 - x)*x*(1 - y) - 2*(1 - x)*x*y)/2. + (2*(1 - x)*(1 - y)*y - 2*x*(1 - y)*y)/2.; + RealType sxy = (1 - x)*x*(1 - y) - (1 - x)*x*y + (1 - x)*(1 - y)*y - x*(1 - y)*y; + RealType syy = 2*(1 - x)*x*(1 - y) - 2*(1 - x)*x*y + (2*(1 - x)*x*(1 - y) - 2*(1 - x)*x*y)/2. + (2*(1 - x)*(1 - y)*y - 2*x*(1 - y)*y)/2.; + sigma(0,0) = sxx; + sigma(0,1) = sxy; + sigma(1,0) = sxy; + sigma(1,1) = syy; + return sigma; + }else{ + static_matrix sigma = static_matrix::Zero(2,2); + if (Nonzero_Dirichlet_Q) { + RealType sxx = - 2.0 * M_PI * std::cos(M_PI * x) * std::cos(M_PI * y); + RealType syy = + 2.0 * M_PI * std::cos(M_PI * x) * std::cos(M_PI * y); + sigma(0,0) = sxx; + sigma(1,1) = syy; + return sigma; + }else{ + RealType sxx = 4*M_PI*std::cos(2*M_PI*x)*std::sin(2*M_PI*y) + + lambda*(3*M_PI*std::cos(3*M_PI*y)*std::sin(3*M_PI*x) + 2*M_PI*std::cos(2*M_PI*x)*std::sin(2*M_PI*y)); + RealType sxy = 2*M_PI*std::cos(2*M_PI*y)*std::sin(2*M_PI*x) + + 3*M_PI*std::cos(3*M_PI*x)*std::sin(3*M_PI*y); + RealType syy = 6*M_PI*std::cos(3*M_PI*y)*std::sin(3*M_PI*x) + + lambda*(3*M_PI*std::cos(3*M_PI*y)*std::sin(3*M_PI*x) + 2*M_PI*std::cos(2*M_PI*x)*std::sin(2*M_PI*y)); + sigma(0,0) = sxx; + sigma(0,1) = sxy; + sigma(1,0) = sxy; + sigma(1,1) = syy; + return sigma; + } + } + + }; + + auto rhs_fun = [quadratic_function_Q,Nonzero_Dirichlet_Q,lambda](const typename mesh_type::point_type& pt) -> static_vector { + double x,y; + x = pt.x(); + y = pt.y(); + if(quadratic_function_Q){ + RealType fx = 2*(1 + x*x + y*(-5 + 3*y) + x*(-3 + 4*y)); + RealType fy = 2*(1 + 3*x*x + (-3 + y)*y + x*(-5 + 4*y)); + return static_vector{-fx, -fy}; + }else{ + if (Nonzero_Dirichlet_Q) { + RealType fx = + 2.0 * M_PI * M_PI * ( std::sin(M_PI * x) * std::cos( M_PI * y)); + RealType fy = - 2.0 * M_PI * M_PI * ( std::cos(M_PI * x) * std::sin( M_PI * y)); + return static_vector{-fx, -fy}; + }else{ + RealType fx = M_PI*M_PI*(9*(1 + lambda)*std::cos(3*M_PI*x)*std::cos(3*M_PI*y) - 4*(3 + lambda)*std::sin(2*M_PI*x)*std::sin(2*M_PI*y)); + RealType fy = M_PI*M_PI*(4*(1 + lambda)*std::cos(2*M_PI*x)*std::cos(2*M_PI*y) - 9*(3 + lambda)*std::sin(3*M_PI*x)*std::sin(3*M_PI*y)); + return static_vector{-fx, -fy}; + } + } + }; + + // simple material + RealType rho = 1.0; + RealType vp; + if (Nonzero_Dirichlet_Q || quadratic_function_Q) { + vp = std::sqrt(3.0); + }else{ + vp = std::sqrt(2.0 + lambda); + } + RealType vs = 1.0; + elastic_material_data material(rho,vp,vs); + + std::ofstream error_file("steady_vector_mixed_error.txt"); + + for(size_t k = 1; k <= sim_data.m_k_degree; k++){ + std::cout << bold << cyan << "Running an approximation with k : " << k << reset << std::endl; + error_file << "Approximation with k : " << k << std::endl; + for(size_t l = 0; l <= sim_data.m_n_divs; l++){ + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(l); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = k; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,k); + + // Solving a scalar primal HHO problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_vec_fun); + tc.tic(); + auto assembler = elastodynamic_three_fields_assembler(msh, hho_di, bnd); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + assembler.load_material_data(msh,material); + assembler.assemble(msh, rhs_fun); + assembler.assemble_mass(msh, false); + assembler.apply_bc(msh); + tc.toc(); + std::cout << bold << cyan << "Assemble in : " << tc << " seconds" << reset << std::endl; + + // Solving LS + Matrix x_dof; + if (sim_data.m_sc_Q) { + tc.tic(); + SparseMatrix Kg = assembler.LHS+assembler.MASS; + linear_solver analysis(Kg,assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + tc.toc(); + std::cout << bold << cyan << "Create analysis in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + x_dof = analysis.solve(assembler.RHS); + tc.toc(); + std::cout << bold << cyan << "Linear Solve in : " << tc << " seconds" << reset << std::endl; + std::cout << bold << cyan << "Number of equations (SC) : " << analysis.n_equations() << reset << std::endl; + }else{ + tc.tic(); + SparseMatrix Kg = assembler.LHS+assembler.MASS; + linear_solver analysis(Kg); + tc.toc(); + std::cout << bold << cyan << "Create analysis in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + tc.tic(); + x_dof = analysis.solve(assembler.RHS); + tc.toc(); + std::cout << bold << cyan << "Linear Solve in : " << tc << " seconds" << reset << std::endl; + std::cout << bold << cyan << "Number of equations : " << analysis.n_equations() << reset << std::endl; + } + + // Computing errors + postprocessor::compute_errors_three_fields_vectorial(msh, hho_di, x_dof, exact_vec_fun, exact_flux_fun, error_file); + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "steady_vector_mixed_k" + std::to_string(k) + "_"; + postprocessor::write_silo_three_fields_vectorial(silo_file_name, l, msh, hho_di, x_dof, exact_vec_fun, exact_flux_fun, false); + } + } + error_file << std::endl << std::endl; + } + error_file.close(); + + +} + +void EHHOFirstOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = tf/nt; + + vec_analytic_functions functions; + functions.set_function_type(vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + RealType t = ti; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_sigma(t); + auto rhs_fun = functions.Evaluate_f(t); + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_vel_fun); + tc.tic(); + auto assembler = elastodynamic_three_fields_assembler(msh, hho_di, bnd); + assembler.load_material_data(msh); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, exact_vel_fun, exact_flux_fun); + assembler.project_over_faces(msh, x_dof, exact_vel_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "vector_mixed_"; + postprocessor::write_silo_three_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + std::ofstream simulation_log("elastodynamic_three_fields_explicit.txt"); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_three_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + int s = 3; + Matrix alpha; + Matrix beta; + ssprk_shu_osher_tableau::ossprk_tables(s, alpha, beta); + + tc.tic(); + assembler.assemble(msh, rhs_fun); + tc.toc(); + std::cout << bold << cyan << "Stiffness and rhs assembly completed: " << tc << " seconds" << reset << std::endl; + size_t n_face_dof = assembler.get_n_face_dof(); + ssprk_hho_scheme ssprk_an(assembler.LHS,assembler.RHS,assembler.MASS,n_face_dof); + tc.toc(); + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + { // Updating rhs + RealType t = dt*(it)+ti; + auto rhs_fun = functions.Evaluate_f(t); + assembler.assemble_rhs(msh, rhs_fun); + ssprk_an.SetFg(assembler.RHS); + } + RealType tn = dt*(it-1)+ti; + tc.tic(); + { + + size_t n_dof = x_dof.rows(); + Matrix ys = Matrix::Zero(n_dof, s+1); + + Matrix yn, ysi, yj; + ys.block(0, 0, n_dof, 1) = x_dof; + for (int i = 0; i < s; i++) { + + ysi = Matrix::Zero(n_dof, 1); + for (int j = 0; j <= i; j++) { + yn = ys.block(0, j, n_dof, 1); + ssprk_an.ssprk_weight(yn, yj, dt, alpha(i,j), beta(i,j)); + ysi += yj; + } + ys.block(0, i+1, n_dof, 1) = ysi; + } + + x_dof_n = ys.block(0, s, n_dof, 1); + } + tc.toc(); + std::cout << bold << cyan << "SSPRK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + t = tn + dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_sigma(t); + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "vector_mixed_"; + postprocessor::write_silo_three_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_three_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + if(it == nt){ + // Computing errors + postprocessor::compute_errors_three_fields_vectorial(msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun); + } + } + + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Number of SSPRKSS steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); +} + +void IHHOFirstOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + tc.toc(); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + + vec_analytic_functions functions; + functions.set_function_type(vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + RealType t = ti; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_sigma(t); + auto rhs_fun = functions.Evaluate_f(t); + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_vel_fun); + tc.tic(); + auto assembler = elastodynamic_three_fields_assembler(msh, hho_di, bnd); + assembler.load_material_data(msh); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, exact_vel_fun, exact_flux_fun); + assembler.project_over_faces(msh, x_dof, exact_vel_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "vector_mixed_"; + postprocessor::write_silo_three_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + std::ofstream simulation_log("elastodynamic_three_fields.txt"); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_three_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 1; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + }else{ + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + tc.tic(); + assembler.assemble(msh, rhs_fun); + tc.toc(); + std::cout << bold << cyan << "First stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + dirk_an.set_static_condensation_data(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data()), assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + tc.tic(); + dirk_an.ComposeMatrix(); +// dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << "Matrix decomposed: " << tc << " seconds" << reset << std::endl; + } + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + t = tn + c(i,0) * dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto rhs_fun = functions.Evaluate_f(t); + assembler.get_bc_conditions().updateDirichletFunction(exact_vel_fun, 0); + assembler.assemble_rhs(msh, rhs_fun); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "DIRK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + t = tn + dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_sigma(t); + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "vector_mixed_"; + postprocessor::write_silo_three_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_three_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + if(it == nt){ + // Computing errors + postprocessor::compute_errors_three_fields_vectorial(msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, simulation_log); + } + + } + + simulation_log << "Number of equations : " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Number of DIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + +void IHHOFirstOrderTwoFields(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + tc.toc(); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + + vec_analytic_functions functions; + functions.set_function_type(vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + RealType t = ti; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_sigma(t); + auto rhs_fun = functions.Evaluate_f(t); + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_vel_fun); + tc.tic(); + auto assembler = elastodynamic_two_fields_assembler(msh, hho_di, bnd); + assembler.load_material_data(msh); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, exact_vel_fun, exact_flux_fun); + assembler.project_over_faces(msh, x_dof, exact_vel_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "vector_mixed_two_fields"; + postprocessor::write_silo_two_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + std::ofstream simulation_log("elastodynamic_two_fields.txt"); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + }else{ + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + tc.tic(); + assembler.assemble(msh, rhs_fun); + tc.toc(); + std::cout << bold << cyan << "First stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + dirk_an.set_static_condensation_data(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data()), assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + tc.tic(); + dirk_an.ComposeMatrix(); +// dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << "Matrix decomposed: " << tc << " seconds" << reset << std::endl; + } + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + t = tn + c(i,0) * dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto rhs_fun = functions.Evaluate_f(t); + assembler.get_bc_conditions().updateDirichletFunction(exact_vel_fun, 0); + assembler.assemble_rhs(msh, rhs_fun); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "DIRK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + t = tn + dt; + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_sigma(t); + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "vector_mixed__two_fields"; + postprocessor::write_silo_two_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, false); + } + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + if(it == nt){ + // Computing errors + postprocessor::compute_errors_three_fields_vectorial(msh, hho_di, x_dof, exact_vel_fun, exact_flux_fun, simulation_log); + } + + } + + simulation_log << "Number of equations : " << dirk_an.DirkAnalysis().n_equations() << std::endl; + simulation_log << "Number of DIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + +void IHHOSecondOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.125; + RealType dt = (tf-ti)/nt; + + vec_analytic_functions functions; + functions.set_function_type(vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + RealType t = ti; + auto exact_vec_fun = functions.Evaluate_u(t); + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_accel_fun = functions.Evaluate_a(t); + auto rhs_fun = functions.Evaluate_f(t); + auto exact_flux_fun = functions.Evaluate_sigma(t); + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(exact_vec_fun); + + tc.tic(); + auto assembler = elastodynamic_one_field_assembler(msh, hho_di, bnd); + assembler.load_material_data(msh); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler created: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial displacement, velocity and acceleration + tc.tic(); + Matrix u_dof_n, v_dof_n, a_dof_n; + assembler.project_over_cells(msh, u_dof_n, exact_vec_fun); + assembler.project_over_cells(msh, v_dof_n, exact_vel_fun); + assembler.project_over_cells(msh, a_dof_n, exact_accel_fun); + + assembler.project_over_faces(msh, u_dof_n, exact_vec_fun); + assembler.project_over_faces(msh, v_dof_n, exact_vel_fun); + assembler.project_over_faces(msh, a_dof_n, exact_accel_fun); + tc.toc(); + std::cout << bold << cyan << "Initialization completed: " << tc << " seconds" << reset << std::endl; + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "vec_"; + postprocessor::write_silo_one_field_vectorial(silo_file_name, it, msh, hho_di, u_dof_n, exact_vec_fun, false); + } + + std::ofstream simulation_log("elastodynamic_one_field.txt"); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_one_field(msh, hho_di, assembler, t, u_dof_n, v_dof_n, simulation_log); + } + + bool standar_Q = true; + // Newmark process + { + Matrix a_dof_np = a_dof_n; + + RealType beta = 0.275; + RealType gamma = 0.55; + if (!standar_Q) { + RealType kappa = 0.25; + gamma = 1.5; + beta = kappa*(gamma+0.5)*(gamma+0.5); + } + + tc.tic(); + assembler.assemble(msh, rhs_fun); + SparseMatrix Kg = assembler.LHS; + assembler.LHS *= beta*(dt*dt); + assembler.LHS += assembler.MASS; + linear_solver analysis; + if (sim_data.m_sc_Q) { + analysis.set_Kg(assembler.LHS, assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + }else{ + analysis.set_Kg(assembler.LHS); + } + analysis.set_direct_solver(true); +// analysis.set_iterative_solver(true); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + // Manufactured solution + RealType t = dt*(it)+ti; + auto exact_vec_fun = functions.Evaluate_u(t); + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_accel_fun = functions.Evaluate_a(t); + auto exact_flux_fun = functions.Evaluate_sigma(t); + auto rhs_fun = functions.Evaluate_f(t); + assembler.get_bc_conditions().updateDirichletFunction(exact_vec_fun, 0); + assembler.assemble_rhs(msh, rhs_fun); + + // Compute intermediate state for scalar and rate + u_dof_n = u_dof_n + dt*v_dof_n + 0.5*dt*dt*(1.0-2.0*beta)*a_dof_n; + v_dof_n = v_dof_n + dt*(1.0-gamma)*a_dof_n; + Matrix res = Kg*u_dof_n; + + assembler.RHS -= res; + tc.toc(); + std::cout << bold << cyan << "Rhs assembly completed: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + a_dof_np = analysis.solve(assembler.RHS); // new acceleration + tc.toc(); + std::cout << bold << cyan << "Solution completed: " << tc << " seconds" << reset << std::endl; + + // update displacement, velocity and acceleration + u_dof_n += beta*dt*dt*a_dof_np; + v_dof_n += gamma*dt*a_dof_np; + a_dof_n = a_dof_np; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "vec_"; + postprocessor::write_silo_one_field_vectorial(silo_file_name, it, msh, hho_di, u_dof_n, exact_vec_fun, false); + } + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_one_field(msh, hho_di, assembler, t, u_dof_n, v_dof_n, simulation_log); + } + + if(it == nt){ + postprocessor::compute_errors_one_field_vectorial(msh, hho_di, assembler, u_dof_n, exact_vec_fun, exact_flux_fun, simulation_log); + } + + } + simulation_log << "Number of equations : " << analysis.n_equations() << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + } + +} + +void HeterogeneousIHHOSecondOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 3.0; + RealType ly = 2.5; + size_t nx = 3; + size_t ny = 3; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + tc.toc(); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.75; + RealType dt = (tf-ti)/nt; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + auto null_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y; + x = pt.x(); + y = pt.y(); + static_vector f{0,0}; + return f; + }; + + auto vec_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y,xc,yc,r,wave,vx,vy,c,lp; + x = pt.x(); + y = pt.y(); + xc = 0.5; + yc = (2.0/3.0)+1.25; + c = 10.0; + lp = std::sqrt(3.0)/10.0; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + static_vector v{vx,vy}; + return v; + }; + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); + + tc.tic(); + auto assembler = elastodynamic_one_field_assembler(msh, hho_di, bnd); + + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(3); + RealType rho, vp, vs; + rho = 1.0; + if (y < 1.25) { + vp = 1.0*std::sqrt(3.0); + vs = 1.0; + }else{ + vp = std::sqrt(3.0); + vs = 1; + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + mat_data[2] = vs; // seismic shear velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,elastic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler created: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial displacement, velocity and acceleration + tc.tic(); + Matrix u_dof_n, v_dof_n, a_dof_n; + assembler.project_over_cells(msh, u_dof_n, null_fun); + assembler.project_over_faces(msh, u_dof_n, null_fun); + + assembler.project_over_cells(msh, v_dof_n, vec_fun); + assembler.project_over_faces(msh, v_dof_n, vec_fun); + + assembler.project_over_cells(msh, a_dof_n, null_fun); + assembler.project_over_faces(msh, a_dof_n, null_fun); + tc.toc(); + std::cout << bold << cyan << "Initialization completed: " << tc << " seconds" << reset << std::endl; + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "inhomogeneous_vec_"; + postprocessor::write_silo_one_field_vectorial(silo_file_name, it, msh, hho_di, v_dof_n, vec_fun, false); + } + + std::ofstream simulation_log("elastodynamic_inhomogeneous_one_field.txt"); + + std::ofstream sensor_1_log("s1_elastodynamic_one_field.csv"); + std::ofstream sensor_2_log("s2_elastodynamic_one_field.csv"); + std::ofstream sensor_3_log("s3_elastodynamic_one_field.csv"); + typename mesh_type::point_type s1_pt(0.5-2.0/3.0, 1.0/3.0); + typename mesh_type::point_type s2_pt(0.5, 1.0/3.0); + typename mesh_type::point_type s3_pt(0.5+2.0/3.0, 1.0/3.0); + std::pair s1_pt_cell = std::make_pair(s1_pt, -1); + std::pair s2_pt_cell = std::make_pair(s2_pt, -1); + std::pair s3_pt_cell = std::make_pair(s3_pt, -1); + + postprocessor::record_data_elastic_one_field(0, s1_pt_cell, msh, hho_di, v_dof_n, sensor_1_log); + postprocessor::record_data_elastic_one_field(0, s2_pt_cell, msh, hho_di, v_dof_n, sensor_2_log); + postprocessor::record_data_elastic_one_field(0, s3_pt_cell, msh, hho_di, v_dof_n, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_one_field(msh, hho_di, assembler, ti, u_dof_n, v_dof_n, simulation_log); + } + + linear_solver analysis; + bool standar_Q = true; + // Newmark process + { + Matrix a_dof_np = a_dof_n; + + RealType beta = 0.25; + RealType gamma = 0.5; + if (!standar_Q) { + RealType kappa = 0.25; + gamma = 1.5; + beta = kappa*(gamma+0.5)*(gamma+0.5); + } + + tc.tic(); + assembler.assemble(msh, null_fun); + SparseMatrix Kg = assembler.LHS; + assembler.LHS *= beta*(dt*dt); + assembler.LHS += assembler.MASS; + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + + if (sim_data.m_sc_Q) { + tc.tic(); + analysis.set_Kg(assembler.LHS,assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + tc.toc(); + std::cout << bold << cyan << "Equations condensed in : " << tc << " seconds" << reset << std::endl; + + analysis.set_direct_solver(true); + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + }else{ + analysis.set_Kg(assembler.LHS); + analysis.set_direct_solver(true); + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + } + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + RealType t = dt*it+ti; + tc.tic(); + // Compute intermediate state for scalar and rate + u_dof_n = u_dof_n + dt*v_dof_n + 0.5*dt*dt*(1-2.0*beta)*a_dof_n; + v_dof_n = v_dof_n + dt*(1-gamma)*a_dof_n; + Matrix res = Kg*u_dof_n; + + assembler.RHS.setZero(); + assembler.RHS -= res; + tc.toc(); + std::cout << bold << cyan << "Rhs assembly completed: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + a_dof_np = analysis.solve(assembler.RHS); // new acceleration + tc.toc(); + std::cout << bold << cyan << "Solution completed: " << tc << " seconds" << reset << std::endl; + + // update displacement, velocity and acceleration + u_dof_n += beta*dt*dt*a_dof_np; + v_dof_n += gamma*dt*a_dof_np; + a_dof_n = a_dof_np; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_vec_"; + postprocessor::write_silo_one_field_vectorial(silo_file_name, it, msh, hho_di, v_dof_n, vec_fun, false); + } + + postprocessor::record_data_elastic_one_field(it, s1_pt_cell, msh, hho_di, v_dof_n, sensor_1_log); + postprocessor::record_data_elastic_one_field(it, s2_pt_cell, msh, hho_di, v_dof_n, sensor_2_log); + postprocessor::record_data_elastic_one_field(it, s3_pt_cell, msh, hho_di, v_dof_n, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_one_field(msh, hho_di, assembler, t, u_dof_n, v_dof_n, simulation_log); + } + + } + simulation_log << "Number of equations : " << analysis.n_equations() << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + } + +} + +void HeterogeneousIHHOFirstOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 1.0; + RealType ly = 1.0; + size_t nx = 2; + size_t ny = 2; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + tc.toc(); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + + auto null_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y; + x = pt.x(); + y = pt.y(); + static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename mesh_type::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + return sigma; + }; + + auto vec_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y,xc,yc,r,wave,vx,vy; + x = pt.x(); + y = pt.y(); + xc = 0.5; + yc = 0.75; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (-4*std::sqrt(10.0/3.0)*(-1 + 1600.0*r*r))/(std::exp(800*r*r)*std::pow(M_PI,0.25)); + vx = wave*(x-xc); + vy = wave*(y-yc); + static_vector v{vx,vy}; + return v; + }; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); + tc.tic(); + auto assembler = elastodynamic_three_fields_assembler(msh, hho_di, bnd); + + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(3); + RealType rho, vp, vs; + rho = 1.0; + if (y < 0.5) { + vp = 1.0*std::sqrt(3.0); + vs = 1.0; + }else{ + vp = std::sqrt(3.0); + vs = 1; + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + mat_data[2] = vs; // seismic shear velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,elastic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, vec_fun, null_flux_fun); + assembler.project_over_faces(msh, x_dof, vec_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "inhomogeneous_vector_mixed_"; + postprocessor::write_silo_three_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, vec_fun, null_flux_fun, false); + } + + std::ofstream simulation_log("elastodynamic_inhomogeneous_three_fields.txt"); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_three_fields(msh, hho_di, assembler, ti, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + }else{ + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + tc.tic(); + assembler.assemble(msh, null_fun); + tc.toc(); + std::cout << bold << cyan << "First stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + dirk_an.set_static_condensation_data(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data()), assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + tc.tic(); + dirk_an.ComposeMatrix(); +// dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << "Matrix decomposed: " << tc << " seconds" << reset << std::endl; + } + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + t = tn + c(i,0) * dt; + assembler.assemble_rhs(msh, null_fun); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "DIRK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + RealType t = tn + dt; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_vector_mixed_"; + postprocessor::write_silo_three_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, vec_fun, null_flux_fun, false); + } + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_three_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + } + + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Number of DIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + +void Gar6more2DIHHOSecondOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 2.0; + RealType ly = 1.5; + size_t nx = 3; + size_t ny = 3; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-0.5, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + tc.toc(); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.75; + RealType dt = (tf-ti)/nt; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + auto null_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y; + x = pt.x(); + y = pt.y(); + static_vector f{0,0}; + return f; + }; + + auto vec_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y,xc,yc,r,wave,vx,vy,c,lp; + x = pt.x(); + y = pt.y(); + xc = 0.5; + yc = 2.0/3.0; + c = 10.0; + lp = 1.0*std::sqrt(3.0)/10.0; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + static_vector v{vx,vy}; + return v; + }; + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); + + tc.tic(); + auto assembler = elastodynamic_one_field_assembler(msh, hho_di, bnd); + + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(3); + RealType rho, vp, vs; + rho = 1.0; + if (y < 0.5) { + vp = 1.0*std::sqrt(3.0); + vs = 1.0; + }else{ + vp = 1.0*std::sqrt(3.0); + vs = 1.0; + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + mat_data[2] = vs; // seismic shear velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,elastic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler created: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial displacement, velocity and acceleration + tc.tic(); + Matrix u_dof_n, v_dof_n, a_dof_n; + assembler.project_over_cells(msh, u_dof_n, null_fun); + assembler.project_over_faces(msh, u_dof_n, null_fun); + + assembler.project_over_cells(msh, v_dof_n, vec_fun); + assembler.project_over_faces(msh, v_dof_n, vec_fun); + + assembler.project_over_cells(msh, a_dof_n, null_fun); + assembler.project_over_faces(msh, a_dof_n, null_fun); + tc.toc(); + std::cout << bold << cyan << "Initialization completed: " << tc << " seconds" << reset << std::endl; + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "inhomogeneous_vec_"; + postprocessor::write_silo_one_field_vectorial(silo_file_name, it, msh, hho_di, v_dof_n, vec_fun, false); + } + + std::ofstream simulation_log("elastodynamic_inhomogeneous_one_field.txt"); + + std::ofstream sensor_1_log("s1_elastodynamic_one_field.csv"); + std::ofstream sensor_2_log("s2_elastodynamic_one_field.csv"); + std::ofstream sensor_3_log("s3_elastodynamic_one_field.csv"); + typename mesh_type::point_type s1_pt(0.5-2.0/3.0, 1.0/3.0); + typename mesh_type::point_type s2_pt(0.5, 1.0/3.0); + typename mesh_type::point_type s3_pt(0.5+2.0/3.0, 1.0/3.0); + std::pair s1_pt_cell = std::make_pair(s1_pt, -1); + std::pair s2_pt_cell = std::make_pair(s2_pt, -1); + std::pair s3_pt_cell = std::make_pair(s3_pt, -1); + + postprocessor::record_data_elastic_one_field(0, s1_pt_cell, msh, hho_di, v_dof_n, sensor_1_log); + postprocessor::record_data_elastic_one_field(0, s2_pt_cell, msh, hho_di, v_dof_n, sensor_2_log); + postprocessor::record_data_elastic_one_field(0, s3_pt_cell, msh, hho_di, v_dof_n, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_one_field(msh, hho_di, assembler, ti, u_dof_n, v_dof_n, simulation_log); + } + + linear_solver analysis; + bool standar_Q = true; + // Newmark process + { + Matrix a_dof_np = a_dof_n; + + RealType beta = 0.25; + RealType gamma = 0.5; + if (!standar_Q) { + RealType kappa = 0.25; + gamma = 1.5; + beta = kappa*(gamma+0.5)*(gamma+0.5); + } + + tc.tic(); + assembler.assemble(msh, null_fun); + SparseMatrix Kg = assembler.LHS; + assembler.LHS *= beta*(dt*dt); + assembler.LHS += assembler.MASS; + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + + if (sim_data.m_sc_Q) { + tc.tic(); + analysis.set_Kg(assembler.LHS,assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + tc.toc(); + std::cout << bold << cyan << "Equations condensed in : " << tc << " seconds" << reset << std::endl; + + analysis.set_direct_solver(true); + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + }else{ + analysis.set_Kg(assembler.LHS); + analysis.set_direct_solver(true); + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + } + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + RealType t = dt*it+ti; + tc.tic(); + // Compute intermediate state for scalar and rate + u_dof_n = u_dof_n + dt*v_dof_n + 0.5*dt*dt*(1-2.0*beta)*a_dof_n; + v_dof_n = v_dof_n + dt*(1-gamma)*a_dof_n; + Matrix res = Kg*u_dof_n; + + assembler.RHS.setZero(); + assembler.RHS -= res; + tc.toc(); + std::cout << bold << cyan << "Rhs assembly completed: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + a_dof_np = analysis.solve(assembler.RHS); // new acceleration + tc.toc(); + std::cout << bold << cyan << "Solution completed: " << tc << " seconds" << reset << std::endl; + + // update displacement, velocity and acceleration + u_dof_n += beta*dt*dt*a_dof_np; + v_dof_n += gamma*dt*a_dof_np; + a_dof_n = a_dof_np; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_vec_"; + postprocessor::write_silo_one_field_vectorial(silo_file_name, it, msh, hho_di, v_dof_n, vec_fun, false); + } + + postprocessor::record_data_elastic_one_field(it, s1_pt_cell, msh, hho_di, v_dof_n, sensor_1_log); + postprocessor::record_data_elastic_one_field(it, s2_pt_cell, msh, hho_di, v_dof_n, sensor_2_log); + postprocessor::record_data_elastic_one_field(it, s3_pt_cell, msh, hho_di, v_dof_n, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_one_field(msh, hho_di, assembler, t, u_dof_n, v_dof_n, simulation_log); + } + + } + simulation_log << "Number of equations : " << analysis.n_equations() << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + } + +} + +void Gar6more2DIHHOFirstOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 2.0; + RealType ly = 1.5; + size_t nx = 3; + size_t ny = 3; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-0.5, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + tc.toc(); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.75; + RealType dt = (tf-ti)/nt; + + auto null_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y; + x = pt.x(); + y = pt.y(); + static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename mesh_type::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + return sigma; + }; + + auto vec_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y,xc,yc,r,wave,vx,vy,c,lp; + x = pt.x(); + y = pt.y(); + xc = 0.5; + yc = 2.0/3.0; + c = 10.0; + lp = 1.0*std::sqrt(3.0)/10.0; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + static_vector v{vx,vy}; + return v; + }; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); + tc.tic(); + auto assembler = elastodynamic_three_fields_assembler(msh, hho_di, bnd); + + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(3); + RealType rho, vp, vs; + rho = 1.0; + if (y < 0.5) { + vp = 1.0*std::sqrt(3.0); + vs = 1.0; + }else{ + vp = 1.0*std::sqrt(3.0); + vs = 1.0; + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + mat_data[2] = vs; // seismic shear velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,elastic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, vec_fun, null_flux_fun); + assembler.project_over_faces(msh, x_dof, vec_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "inhomogeneous_vector_mixed_"; + postprocessor::write_silo_three_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, vec_fun, null_flux_fun, false); + } + + std::ofstream simulation_log("elastodynamic_inhomogeneous_three_fields.txt"); + + std::ofstream sensor_1_log("s1_elastodynamic_three_fields.csv"); + std::ofstream sensor_2_log("s2_elastodynamic_three_fields.csv"); + std::ofstream sensor_3_log("s3_elastodynamic_three_fields.csv"); + typename mesh_type::point_type s1_pt(0.5-2.0/3.0, 1.0/3.0); + typename mesh_type::point_type s2_pt(0.5, 1.0/3.0); + typename mesh_type::point_type s3_pt(0.5+2.0/3.0, 1.0/3.0); + std::pair s1_pt_cell = std::make_pair(s1_pt, -1); + std::pair s2_pt_cell = std::make_pair(s2_pt, -1); + std::pair s3_pt_cell = std::make_pair(s3_pt, -1); + + postprocessor::record_data_elastic_three_fields(0, s1_pt_cell, msh, hho_di, x_dof, sensor_1_log); + postprocessor::record_data_elastic_three_fields(0, s2_pt_cell, msh, hho_di, x_dof, sensor_2_log); + postprocessor::record_data_elastic_three_fields(0, s3_pt_cell, msh, hho_di, x_dof, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_three_fields(msh, hho_di, assembler, ti, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + }else{ + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + tc.tic(); + assembler.assemble(msh, null_fun); + tc.toc(); + std::cout << bold << cyan << "First stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + dirk_an.set_static_condensation_data(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data()), assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + tc.tic(); + dirk_an.ComposeMatrix(); +// dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << "Matrix decomposed: " << tc << " seconds" << reset << std::endl; + } + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + t = tn + c(i,0) * dt; +// assembler.assemble_rhs(msh, null_fun); + assembler.RHS.setZero(); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "SDIRK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + RealType t = tn + dt; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_vector_mixed_"; + postprocessor::write_silo_three_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, vec_fun, null_flux_fun, false); + } + + postprocessor::record_data_elastic_three_fields(it, s1_pt_cell, msh, hho_di, x_dof, sensor_1_log); + postprocessor::record_data_elastic_three_fields(it, s2_pt_cell, msh, hho_di, x_dof, sensor_2_log); + postprocessor::record_data_elastic_three_fields(it, s3_pt_cell, msh, hho_di, x_dof, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_three_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + } + + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Number of SDIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + +void HeterogeneousGar6more2DIHHOSecondOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 3.0; + RealType ly = 3.0; + size_t nx = 3; + size_t ny = 3; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.5, -1.5); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + tc.toc(); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + auto null_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y; + x = pt.x(); + y = pt.y(); + static_vector f{0,0}; + return f; + }; + + auto vec_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y,xc,yc,r,wave,vx,vy,c,lp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 2.0/3.0; + c = 10.0; + lp = 2.0*std::sqrt(3.0)/10.0; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + static_vector v{vx,vy}; + return v; + }; + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); + + tc.tic(); + auto assembler = elastodynamic_one_field_assembler(msh, hho_di, bnd); + + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(3); + RealType rho, vp, vs; + if (y > 0.0) { + vp = 2.0*std::sqrt(3.0); + vs = 2.0; + rho = 1.0; + }else{ + vp = std::sqrt(3.0); + vs = 1.0; + rho = 1.0; + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + mat_data[2] = vs; // seismic shear velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,elastic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler created: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial displacement, velocity and acceleration + tc.tic(); + Matrix u_dof_n, v_dof_n, a_dof_n; + assembler.project_over_cells(msh, u_dof_n, null_fun); + assembler.project_over_faces(msh, u_dof_n, null_fun); + + assembler.project_over_cells(msh, v_dof_n, vec_fun); + assembler.project_over_faces(msh, v_dof_n, vec_fun); + + assembler.project_over_cells(msh, a_dof_n, null_fun); + assembler.project_over_faces(msh, a_dof_n, null_fun); + tc.toc(); + std::cout << bold << cyan << "Initialization completed: " << tc << " seconds" << reset << std::endl; + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "inhomogeneous_vec_"; + postprocessor::write_silo_one_field_vectorial(silo_file_name, it, msh, hho_di, v_dof_n, vec_fun, false); + } + + std::ofstream simulation_log("elastodynamic_inhomogeneous_one_field.txt"); + + std::ofstream sensor_1_log("s1_elastodynamic_one_field_h.csv"); + std::ofstream sensor_2_log("s2_elastodynamic_one_field_h.csv"); + std::ofstream sensor_3_log("s3_elastodynamic_one_field_h.csv"); + typename mesh_type::point_type s1_pt(-1.0/3.0, -1.0/3.0); + typename mesh_type::point_type s2_pt( 0.0, -1.0/3.0); + typename mesh_type::point_type s3_pt(+1.0/3.0, -1.0/3.0); + std::pair s1_pt_cell = std::make_pair(s1_pt, -1); + std::pair s2_pt_cell = std::make_pair(s2_pt, -1); + std::pair s3_pt_cell = std::make_pair(s3_pt, -1); + + postprocessor::record_data_elastic_one_field(0, s1_pt_cell, msh, hho_di, v_dof_n, sensor_1_log); + postprocessor::record_data_elastic_one_field(0, s2_pt_cell, msh, hho_di, v_dof_n, sensor_2_log); + postprocessor::record_data_elastic_one_field(0, s3_pt_cell, msh, hho_di, v_dof_n, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_one_field(msh, hho_di, assembler, ti, u_dof_n, v_dof_n, simulation_log); + } + + linear_solver analysis; + bool standar_Q = true; + // Newmark process + { + Matrix a_dof_np = a_dof_n; + + RealType beta = 0.25; + RealType gamma = 0.5; + if (!standar_Q) { + RealType kappa = 0.25; + gamma = 1.5; + beta = kappa*(gamma+0.5)*(gamma+0.5); + } + + tc.tic(); + assembler.assemble(msh, null_fun); + SparseMatrix Kg = assembler.LHS; + assembler.LHS *= beta*(dt*dt); + assembler.LHS += assembler.MASS; + tc.toc(); + std::cout << bold << cyan << "Stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + + if (sim_data.m_sc_Q) { + tc.tic(); + analysis.set_Kg(assembler.LHS,assembler.get_n_face_dof()); + analysis.condense_equations(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data())); + tc.toc(); + std::cout << bold << cyan << "Equations condensed in : " << tc << " seconds" << reset << std::endl; + + analysis.set_direct_solver(true); + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + }else{ + analysis.set_Kg(assembler.LHS); + analysis.set_direct_solver(true); + + tc.tic(); + analysis.factorize(); + tc.toc(); + std::cout << bold << cyan << "Factorized in : " << tc << " seconds" << reset << std::endl; + + } + + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + + RealType t = dt*it+ti; + tc.tic(); + // Compute intermediate state for scalar and rate + u_dof_n = u_dof_n + dt*v_dof_n + 0.5*dt*dt*(1-2.0*beta)*a_dof_n; + v_dof_n = v_dof_n + dt*(1-gamma)*a_dof_n; + Matrix res = Kg*u_dof_n; + + assembler.RHS.setZero(); + assembler.RHS -= res; + tc.toc(); + std::cout << bold << cyan << "Rhs assembly completed: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + a_dof_np = analysis.solve(assembler.RHS); // new acceleration + tc.toc(); + std::cout << bold << cyan << "Solution completed: " << tc << " seconds" << reset << std::endl; + + // update displacement, velocity and acceleration + u_dof_n += beta*dt*dt*a_dof_np; + v_dof_n += gamma*dt*a_dof_np; + a_dof_n = a_dof_np; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_vec_"; + postprocessor::write_silo_one_field_vectorial(silo_file_name, it, msh, hho_di, v_dof_n, vec_fun, false); + } + + postprocessor::record_data_elastic_one_field(it, s1_pt_cell, msh, hho_di, v_dof_n, sensor_1_log); + postprocessor::record_data_elastic_one_field(it, s2_pt_cell, msh, hho_di, v_dof_n, sensor_2_log); + postprocessor::record_data_elastic_one_field(it, s3_pt_cell, msh, hho_di, v_dof_n, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_one_field(msh, hho_di, assembler, t, u_dof_n, v_dof_n, simulation_log); + } + + } + simulation_log << "Number of equations : " << analysis.n_equations() << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + } + +} + +void HeterogeneousGar6more2DIHHOFirstOrder(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 3.0; + RealType ly = 3.0; + size_t nx = 3; + size_t ny = 3; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.5, -1.5); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + tc.toc(); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + + auto null_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y; + x = pt.x(); + y = pt.y(); + static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename mesh_type::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + return sigma; + }; + + auto vec_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y,xc,yc,r,wave,vx,vy,c,lp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 2.0/3.0; + c = 10.0; + lp = 2.0*std::sqrt(3.0)/10.0; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + static_vector v{vx,vy}; + return v; + }; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); + tc.tic(); + auto assembler = elastodynamic_three_fields_assembler(msh, hho_di, bnd); + + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(3); + RealType rho, vp, vs; + if (y > 0.0) { + vp = 2.0*std::sqrt(3.0); + vs = 2.0; + rho = 1.0; + }else{ + vp = std::sqrt(3.0); + vs = 1.0; + rho = 1.0; + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + mat_data[2] = vs; // seismic shear velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,elastic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, vec_fun, null_flux_fun); + assembler.project_over_faces(msh, x_dof, vec_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "inhomogeneous_vector_mixed_"; + postprocessor::write_silo_three_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, vec_fun, null_flux_fun, false); + } + + std::ofstream simulation_log("elastodynamic_inhomogeneous_three_fields.txt"); + + std::ofstream sensor_1_log("s1_elastodynamic_three_fields_h.csv"); + std::ofstream sensor_2_log("s2_elastodynamic_three_fields_h.csv"); + std::ofstream sensor_3_log("s3_elastodynamic_three_fields_h.csv"); + typename mesh_type::point_type s1_pt(-1.0/3.0, 1.0/3.0); + typename mesh_type::point_type s2_pt( 0.0, 1.0/3.0); + typename mesh_type::point_type s3_pt(+1.0/3.0, 1.0/3.0); + std::pair s1_pt_cell = std::make_pair(s1_pt, -1); + std::pair s2_pt_cell = std::make_pair(s2_pt, -1); + std::pair s3_pt_cell = std::make_pair(s3_pt, -1); + + postprocessor::record_data_elastic_three_fields(0, s1_pt_cell, msh, hho_di, x_dof, sensor_1_log); + postprocessor::record_data_elastic_three_fields(0, s2_pt_cell, msh, hho_di, x_dof, sensor_2_log); + postprocessor::record_data_elastic_three_fields(0, s3_pt_cell, msh, hho_di, x_dof, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_three_fields(msh, hho_di, assembler, ti, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + }else{ + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + tc.tic(); + assembler.assemble(msh, null_fun); + tc.toc(); + std::cout << bold << cyan << "First stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + dirk_an.set_static_condensation_data(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data()), assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + tc.tic(); + dirk_an.ComposeMatrix(); +// dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << "Matrix decomposed: " << tc << " seconds" << reset << std::endl; + } + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + t = tn + c(i,0) * dt; + assembler.RHS.setZero(); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "SDIRK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + RealType t = tn + dt; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_vector_mixed_"; + postprocessor::write_silo_three_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, vec_fun, null_flux_fun, false); + } + + postprocessor::record_data_elastic_three_fields(it, s1_pt_cell, msh, hho_di, x_dof, sensor_1_log); + postprocessor::record_data_elastic_three_fields(it, s2_pt_cell, msh, hho_di, x_dof, sensor_2_log); + postprocessor::record_data_elastic_three_fields(it, s3_pt_cell, msh, hho_di, x_dof, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_three_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + } + + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Number of SDIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + +void HeterogeneousGar6more2DIHHOFirstOrderTwoFields(int argc, char **argv){ + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + + // Building a cartesian mesh + timecounter tc; + tc.tic(); + + RealType lx = 2.0; + RealType ly = 2.0; + size_t nx = 2; + size_t ny = 2; + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions boundary_type; + mesh_type msh; + + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, -1.25); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + tc.toc(); + std::cout << bold << cyan << "Mesh generation: " << tc << " seconds" << reset << std::endl; + + // Time controls : Final time value 1.0 + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + RealType ti = 0.0; + RealType tf = 0.5; + RealType dt = (tf-ti)/nt; + + auto null_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y; + x = pt.x(); + y = pt.y(); + static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename mesh_type::point_type& pt) -> static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + static_matrix sigma = static_matrix::Zero(2,2); + return sigma; + }; + + auto vec_fun = [](const mesh_type::point_type& pt) -> static_vector { + RealType x,y,xc,yc,r,wave,vx,vy,c,lp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 0.25; + c = 10.0; + lp = 2.0*std::sqrt(3.0)/10.0; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + static_vector v{vx,vy}; + return v; + }; + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q){ + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // Solving a primal HHO mixed problem + boundary_type bnd(msh); + bnd.addDirichletEverywhere(null_fun); + tc.tic(); + auto assembler = elastodynamic_two_fields_assembler(msh, hho_di, bnd); + + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> std::vector { + double x,y; + x = pt.x(); + y = pt.y(); + std::vector mat_data(3); + RealType rho, vp, vs; + if (y > 0.0) { + vp = std::sqrt(3.0); + vs = 1.0; + rho = 1.0; + }else{ + vp = std::sqrt(3.0); + vs = 1.0; + rho = 1.0; + } + mat_data[0] = rho; // rho + mat_data[1] = vp; // seismic compressional velocity vp + mat_data[2] = vs; // seismic shear velocity vp + return mat_data; + }; + + assembler.load_material_data(msh,elastic_mat_fun); + if(sim_data.m_hdg_stabilization_Q){ + assembler.set_hdg_stabilization(); + } + if(sim_data.m_scaled_stabilization_Q){ + assembler.set_scaled_stabilization(); + } + tc.toc(); + std::cout << bold << cyan << "Assembler generation: " << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << "Mass Assembly completed: " << tc << " seconds" << reset << std::endl; + + // Projecting initial data + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, vec_fun, null_flux_fun); + assembler.project_over_faces(msh, x_dof, vec_fun); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::string silo_file_name = "inhomogeneous_vector_mixed_two_fields_"; + postprocessor::write_silo_two_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, vec_fun, null_flux_fun, false); + } + + std::ofstream simulation_log("elastodynamic_inhomogeneous_two_fields.txt"); + + std::ofstream sensor_1_log("s1_elastodynamic_two_fields_h.csv"); + std::ofstream sensor_2_log("s2_elastodynamic_two_fields_h.csv"); + std::ofstream sensor_3_log("s3_elastodynamic_two_fields_h.csv"); + typename mesh_type::point_type s1_pt(-1.0/3.0, 1.0/3.0); + typename mesh_type::point_type s2_pt( 0.0, 1.0/3.0); + typename mesh_type::point_type s3_pt(+1.0/3.0, 1.0/3.0); + std::pair s1_pt_cell = std::make_pair(s1_pt, -1); + std::pair s2_pt_cell = std::make_pair(s2_pt, -1); + std::pair s3_pt_cell = std::make_pair(s3_pt, -1); + + postprocessor::record_data_elastic_two_fields(0, s1_pt_cell, msh, hho_di, x_dof, sensor_1_log); + postprocessor::record_data_elastic_two_fields(0, s2_pt_cell, msh, hho_di, x_dof, sensor_2_log); + postprocessor::record_data_elastic_two_fields(0, s3_pt_cell, msh, hho_di, x_dof, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_two_fields(msh, hho_di, assembler, ti, x_dof, simulation_log); + } + + // Solving a first order equation HDG/HHO propagation problem + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + }else{ + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + tc.tic(); + assembler.assemble(msh, null_fun); + tc.toc(); + std::cout << bold << cyan << "First stiffness assembly completed: " << tc << " seconds" << reset << std::endl; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + dirk_an.set_static_condensation_data(std::make_pair(msh.cells_size(), assembler.get_cell_basis_data()), assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + tc.tic(); + dirk_an.ComposeMatrix(); +// dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << bold << cyan << "Matrix decomposed: " << tc << " seconds" << reset << std::endl; + } + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++){ + + std::cout << bold << yellow << "Time step number : " << it << " being executed." << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + t = tn + c(i,0) * dt; + assembler.RHS.setZero(); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << "SDIRK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + RealType t = tn + dt; + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "inhomogeneous_vector_mixed_two_fields_"; + postprocessor::write_silo_two_fields_vectorial(silo_file_name, it, msh, hho_di, x_dof, vec_fun, null_flux_fun, false); + } + + postprocessor::record_data_elastic_two_fields(it, s1_pt_cell, msh, hho_di, x_dof, sensor_1_log); + postprocessor::record_data_elastic_two_fields(it, s2_pt_cell, msh, hho_di, x_dof, sensor_2_log); + postprocessor::record_data_elastic_two_fields(it, s3_pt_cell, msh, hho_di, x_dof, sensor_3_log); + + if (sim_data.m_report_energy_Q) { + postprocessor::compute_elastic_energy_two_fields(msh, hho_di, assembler, t, x_dof, simulation_log); + } + + } + + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Number of SDIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log.flush(); + +} + diff --git a/apps/wave_propagation/src/prototypes/postpro/parser_bassin.py b/apps/wave_propagation/src/prototypes/postpro/parser_bassin.py new file mode 100644 index 00000000..6186a833 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/postpro/parser_bassin.py @@ -0,0 +1,134 @@ +import os +import vtkmodules.all as vtk +import subprocess + +# Obtenez le chemin absolu du fichier en cours +current_file_path = os.path.abspath(__file__) +# Obtenez le répertoire du fichier en cours +current_directory = os.path.dirname(current_file_path) +# Changez le répertoire de travail actuel pour le répertoire du fichier en cours +os.chdir(current_directory) + +# Lire le fichier VTK +reader = vtk.vtkUnstructuredGridReader() +reader.SetFileName('square2.vtk') +reader.Update() + +# Récupérer les données du maillage +unstructured_grid = reader.GetOutput() + +# Lire le fichier VTK +with open('square2.vtk', "r") as vtk_file: + lines = vtk_file.readlines() + +# Trouver la ligne qui commence par "POINTS" +points_line = None +for line in lines: + if line.startswith("POINTS"): + points_line = line + break + +# Si la ligne "POINTS" est trouvée, extraire les coordonnées des points +if points_line: + num_points = int(points_line.split()[1]) + points_data = [line.split() for line in lines[lines.index(points_line) + 1:lines.index(points_line) + num_points + 1]] + +# Trouver la ligne qui commence par "CELLS" +cells_line = None +for line in lines: + if line.startswith("CELLS"): + cells_line = line + break + +# Si la ligne "CELLS" est trouvée, extraire les informations des cellules +if cells_line: + num_cells, _ = map(int, cells_line.split()[1:]) # Ne pas exclure le premier chiffre (nombre de sommets) + cells_data = [line.split() for line in lines[lines.index(cells_line) + 1:lines.index(cells_line) + num_cells + 1]] + +# Propriétés matérielles +# Trouver la ligne qui commence par "CELL_DATA" +cell_data_line = None +for line in lines: + if line.startswith("CELL_DATA"): + cell_data_line = line + break + +# Si la ligne "CELL_DATA" est trouvée, extraire le nombre de cellules associées aux données +if cell_data_line: + num_cells_data = int(cell_data_line.split()[1]) + + # Chercher la ligne qui commence par "SCALARS CellEntityIds int 1" + cell_entity_ids_line = None + for line in lines: + if line.startswith("LOOKUP_TABLE default"): + cell_entity_ids_line = line + break + + # Si la ligne est trouvée, extraire les valeurs associées à chaque cellule + if cell_entity_ids_line: + cell_entity_ids_data = [int(line) for line in lines[lines.index(cell_entity_ids_line) + 1:lines.index(cell_entity_ids_line) + num_cells_data + 1]] + + +# Ouvrir un fichier de sortie pour les coordonnées des points en écriture +with open("square2.txt", "w") as output_file: + + # Écrire le nombre de points, le nombre de cellules, et "4" sur la première ligne + output_file.write(f"{len(points_data)} {num_cells} 4\n") + + for point_data in points_data: + # Les coordonnées sont dans les trois premières colonnes + x, y, z = map(float, point_data[:3]) + output_file.write(f"{x} {y}\n") + + for cell_data in cells_data: + adjusted_cell_data = [cell_data[0]] + [str(int(idx) + 1) for idx in cell_data[1:]] + # Écrire toutes les données des cellules, y compris le nombre de sommets + output_file.write(" ".join(adjusted_cell_data) + "\n") + + # Extract the points + points = unstructured_grid.GetPoints() + + # Calculate the dimensions of the domain + x_coords = [points.GetPoint(i)[0] for i in range(points.GetNumberOfPoints())] + y_coords = [points.GetPoint(i)[1] for i in range(points.GetNumberOfPoints())] + + min_x, max_x = min(x_coords), max(x_coords) + min_y, max_y = min(y_coords), max(y_coords) + + print(f"Min X: {min_x}, Max X: {max_x}") + print(f"Min Y: {min_y}, Max Y: {max_y}") + + # Define lists to store point indices on each side + indices_left = [] + indices_right = [] + indices_bottom = [] + indices_top = [] + + # Define a threshold to determine which points are on the sides + threshold = 1e-6 + + for i in range(points.GetNumberOfPoints()): + x, y, _ = points.GetPoint(i) + if abs(x - min_x) < threshold: + indices_left.append(i+1) + if abs(x - max_x) < threshold: + indices_right.append(i+1) + if abs(y - min_y) < threshold: + indices_bottom.append(i+1) + if abs(y - max_y) < threshold: + indices_top.append(i+1) + + # # Écrire les numéros des points de la frontière dans un fichier + #with open("square2.txt", "a") as frontiere_file: + output_file.write(" ".join(map(str, indices_left)) + "\n") + output_file.write(" ".join(map(str, indices_right)) + "\n") + output_file.write(" ".join(map(str, indices_bottom)) + "\n") + output_file.write(" ".join(map(str, indices_top)) + "\n") + + for entity_id in cell_entity_ids_data: + output_file.write(f"{entity_id}\n") + +################################################################################## + +print("Les coordonnées des points et les informations des cellules ont été écrites dans le fichier 'output.txt'.") +print("Les numéros des points de la frontière ont été enregistrés dans 'frontiere_points.txt'.") diff --git a/apps/wave_propagation/src/prototypes/postpro/parser_gmsh_diskpp.py b/apps/wave_propagation/src/prototypes/postpro/parser_gmsh_diskpp.py new file mode 100644 index 00000000..9997cb11 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/postpro/parser_gmsh_diskpp.py @@ -0,0 +1,109 @@ +import os +import vtkmodules.all as vtk +import subprocess + +# Obtenez le chemin absolu du fichier en cours +current_file_path = os.path.abspath(__file__) +# Obtenez le répertoire du fichier en cours +current_directory = os.path.dirname(current_file_path) +# Changez le répertoire de travail actuel pour le répertoire du fichier en cours +os.chdir(current_directory) + +# Lire le fichier VTK +reader = vtk.vtkUnstructuredGridReader() +reader.SetFileName('simplex_l7.vtk') +reader.Update() + +# Récupérer les données du maillage +unstructured_grid = reader.GetOutput() + +# Lire le fichier VTK +with open('simplex_l7.vtk', "r") as vtk_file: + lines = vtk_file.readlines() + +# Trouver la ligne qui commence par "POINTS" +points_line = None +for line in lines: + if line.startswith("POINTS"): + points_line = line + break + +# Si la ligne "POINTS" est trouvée, extraire les coordonnées des points +if points_line: + num_points = int(points_line.split()[1]) + points_data = [line.split() for line in lines[lines.index(points_line) + 1:lines.index(points_line) + num_points + 1]] + +# Trouver la ligne qui commence par "CELLS" +cells_line = None +for line in lines: + if line.startswith("CELLS"): + cells_line = line + break + +# Si la ligne "CELLS" est trouvée, extraire les informations des cellules +if cells_line: + num_cells, _ = map(int, cells_line.split()[1:]) # Ne pas exclure le premier chiffre (nombre de sommets) + cells_data = [line.split() for line in lines[lines.index(cells_line) + 1:lines.index(cells_line) + num_cells + 1]] + + + +# Ouvrir un fichier de sortie pour les coordonnées des points en écriture +with open("simplex_l7.txt", "w") as output_file: + + # Écrire le nombre de points, le nombre de cellules, et "4" sur la première ligne + output_file.write(f"{len(points_data)} {num_cells} 4\n") + + for point_data in points_data: + # Les coordonnées sont dans les trois premières colonnes + x, y, z = map(float, point_data[:3]) + output_file.write(f"{x} {y}\n") + + for cell_data in cells_data: + adjusted_cell_data = [cell_data[0]] + [str(int(idx) + 1) for idx in cell_data[1:]] + # Écrire toutes les données des cellules, y compris le nombre de sommets + output_file.write(" ".join(adjusted_cell_data) + "\n") + + # Extract the points + points = unstructured_grid.GetPoints() + + # Calculate the dimensions of the domain + x_coords = [points.GetPoint(i)[0] for i in range(points.GetNumberOfPoints())] + y_coords = [points.GetPoint(i)[1] for i in range(points.GetNumberOfPoints())] + + min_x, max_x = min(x_coords), max(x_coords) + min_y, max_y = min(y_coords), max(y_coords) + + print(f"Min X: {min_x}, Max X: {max_x}") + print(f"Min Y: {min_y}, Max Y: {max_y}") + + # Define lists to store point indices on each side + indices_left = [] + indices_right = [] + indices_bottom = [] + indices_top = [] + + # Define a threshold to determine which points are on the sides + threshold = 1e-6 + + for i in range(points.GetNumberOfPoints()): + x, y, _ = points.GetPoint(i) + if abs(x - min_x) < threshold: + indices_left.append(i+1) + if abs(x - max_x) < threshold: + indices_right.append(i+1) + if abs(y - min_y) < threshold: + indices_bottom.append(i+1) + if abs(y - max_y) < threshold: + indices_top.append(i+1) + + # # Écrire les numéros des points de la frontière dans un fichier + # with open("bassin.txt", "a") as frontiere_file: + output_file.write(" ".join(map(str, indices_left)) + "\n") + output_file.write(" ".join(map(str, indices_right)) + "\n") + output_file.write(" ".join(map(str, indices_bottom)) + "\n") + output_file.write(" ".join(map(str, indices_top)) + "\n") + +################################################################################## + +print("Les coordonnées des points et les informations des cellules ont été écrites dans le fichier 'output.txt'.") +print("Les numéros des points de la frontière ont été enregistrés dans 'frontiere_points.txt'.") diff --git a/apps/wave_propagation/src/prototypes/postpro/parser_gmsh_unstructured_simplices.py b/apps/wave_propagation/src/prototypes/postpro/parser_gmsh_unstructured_simplices.py new file mode 100644 index 00000000..2c95476b --- /dev/null +++ b/apps/wave_propagation/src/prototypes/postpro/parser_gmsh_unstructured_simplices.py @@ -0,0 +1,109 @@ +import os +import vtkmodules.all as vtk +import subprocess + +# Obtenez le chemin absolu du fichier en cours +current_file_path = os.path.abspath(__file__) +# Obtenez le répertoire du fichier en cours +current_directory = os.path.dirname(current_file_path) +# Changez le répertoire de travail actuel pour le répertoire du fichier en cours +os.chdir(current_directory) + +# Lire le fichier VTK +reader = vtk.vtkUnstructuredGridReader() +reader.SetFileName('l9_conv_test_0.005.vtk') +reader.Update() + +# Récupérer les données du maillage +unstructured_grid = reader.GetOutput() + +# Lire le fichier VTK +with open('l9_conv_test_0.005.vtk', "r") as vtk_file: + lines = vtk_file.readlines() + +# Trouver la ligne qui commence par "POINTS" +points_line = None +for line in lines: + if line.startswith("POINTS"): + points_line = line + break + +# Si la ligne "POINTS" est trouvée, extraire les coordonnées des points +if points_line: + num_points = int(points_line.split()[1]) + points_data = [line.split() for line in lines[lines.index(points_line) + 1:lines.index(points_line) + num_points + 1]] + +# Trouver la ligne qui commence par "CELLS" +cells_line = None +for line in lines: + if line.startswith("CELLS"): + cells_line = line + break + +# Si la ligne "CELLS" est trouvée, extraire les informations des cellules +if cells_line: + num_cells, _ = map(int, cells_line.split()[1:]) # Ne pas exclure le premier chiffre (nombre de sommets) + cells_data = [line.split() for line in lines[lines.index(cells_line) + 1:lines.index(cells_line) + num_cells + 1]] + + + +# Ouvrir un fichier de sortie pour les coordonnées des points en écriture +with open("l9_conv_test_0.005.txt", "w") as output_file: + + # Écrire le nombre de points, le nombre de cellules, et "4" sur la première ligne + output_file.write(f"{len(points_data)} {num_cells} 4\n") + + for point_data in points_data: + # Les coordonnées sont dans les trois premières colonnes + x, y, z = map(float, point_data[:3]) + output_file.write(f"{x} {y}\n") + + for cell_data in cells_data: + adjusted_cell_data = [cell_data[0]] + [str(int(idx) + 1) for idx in cell_data[1:]] + # Écrire toutes les données des cellules, y compris le nombre de sommets + output_file.write(" ".join(adjusted_cell_data) + "\n") + + # Extract the points + points = unstructured_grid.GetPoints() + + # Calculate the dimensions of the domain + x_coords = [points.GetPoint(i)[0] for i in range(points.GetNumberOfPoints())] + y_coords = [points.GetPoint(i)[1] for i in range(points.GetNumberOfPoints())] + + min_x, max_x = min(x_coords), max(x_coords) + min_y, max_y = min(y_coords), max(y_coords) + + print(f"Min X: {min_x}, Max X: {max_x}") + print(f"Min Y: {min_y}, Max Y: {max_y}") + + # Define lists to store point indices on each side + indices_left = [] + indices_right = [] + indices_bottom = [] + indices_top = [] + + # Define a threshold to determine which points are on the sides + threshold = 1e-6 + + for i in range(points.GetNumberOfPoints()): + x, y, _ = points.GetPoint(i) + if abs(x - min_x) < threshold: + indices_left.append(i+1) + if abs(x - max_x) < threshold: + indices_right.append(i+1) + if abs(y - min_y) < threshold: + indices_bottom.append(i+1) + if abs(y - max_y) < threshold: + indices_top.append(i+1) + + # # Écrire les numéros des points de la frontière dans un fichier + # with open("bassin.txt", "a") as frontiere_file: + output_file.write(" ".join(map(str, indices_left)) + "\n") + output_file.write(" ".join(map(str, indices_right)) + "\n") + output_file.write(" ".join(map(str, indices_bottom)) + "\n") + output_file.write(" ".join(map(str, indices_top)) + "\n") + +################################################################################## + +print("Les coordonnées des points et les informations des cellules ont été écrites dans le fichier 'output.txt'.") +print("Les numéros des points de la frontière ont été enregistrés dans 'frontiere_points.txt'.") diff --git a/apps/wave_propagation/src/wave_propagation.cpp b/apps/wave_propagation/src/wave_propagation.cpp index f2679ea6..3d3c685c 100644 --- a/apps/wave_propagation/src/wave_propagation.cpp +++ b/apps/wave_propagation/src/wave_propagation.cpp @@ -30,47 +30,46 @@ using namespace Eigen; #include "diskpp/output/silo.hpp" // application common sources -// #include "common/display_settings.hpp" -// #include "common/fitted_geometry_builders.hpp" -// #include "common/linear_solver.hpp" -// #include "common/acoustic_material_data.hpp" -// #include "common/elastic_material_data.hpp" -// #include "common/scal_vec_analytic_functions.hpp" -// #include "common/preprocessor.hpp" -// #include "common/postprocessor.hpp" +#include "common/display_settings.hpp" +#include "common/fitted_geometry_builders.hpp" +#include "common/linear_solver.hpp" +#include "common/acoustic_material_data.hpp" +#include "common/elastic_material_data.hpp" +#include "common/scal_vec_analytic_functions.hpp" +#include "common/preprocessor.hpp" +#include "common/postprocessor.hpp" // RK schemes -// #include "../common/dirk_hho_scheme.hpp" -// #include "../common/dirk_butcher_tableau.hpp" -// #include "../common/erk_butcher_tableau.hpp" -// #include "../common/erk_hho_scheme.hpp" -// #include "../common/erk_coupling_hho_scheme.hpp" +#include "common/dirk_hho_scheme.hpp" +#include "common/dirk_butcher_tableau.hpp" +#include "common/erk_butcher_tableau.hpp" +#include "common/erk_hho_scheme.hpp" +#include "common/erk_coupling_hho_scheme.hpp" // Prototypes: // Computation of an empirical CFL criteria -// #include "Prototypes/CFL/EAcoustic_CFL.hpp" // CFl - Acoustic -// #include "Prototypes/CFL/EElasticity_CFL.hpp" // CFl - Linear Elasticity -// #include "Prototypes/CFL/EHHOFirstOrderCFL.hpp" // CFl - Elasto-Acoustic Coupling +#include "prototypes/acoustic/EAcoustic_CFL.hpp" // CFl - Acoustic +#include "prototypes/elastic/EElasticity_CFL.hpp" // CFl - Linear Elasticity +#include "prototypes/coupling/CFL/EHHOFirstOrderCFL.hpp" // CFl - Elasto-Acoustic Coupling // Stability study & Spectral radius computation: -// #include "Prototypes/Stability_Study/EAcoustic_stability.hpp" // Acoustic -// #include "Prototypes/Stability_Study/EElastic_stability.hpp" // Linear Elasticity -// #include "Prototypes/Stability_Study/EHHOFirstOrder_stability.hpp" // Elasto-Acoustic Coupling -// Convergence test on sinusoidal analytical solution - Debug Implicit Direct Solver!!!! -// #include "Prototypes/Conv_Test/IAcoustic_conv_test.hpp" // Implicit Acoustic -// #include "Prototypes/Conv_Test/IElastic_conv_test.hpp" // Implicit Elastic -// #include "Prototypes/Conv_Test/IHHOFirstOrder.hpp" // Implicit Coupling -// #include "Prototypes/Conv_Test/IHHOFirstOrder_conv_tests.hpp" // Explicit Coupling -// #include "Prototypes/Conv_Test/EHHOFirstOrder.hpp" // Explicit Coupling -// #include "Prototypes/Conv_Test/EHHOFirstOrder_conv_tests.hpp" // Explicit Coupling -// Pulses for comparison with Gar6more -// #include "Prototypes/Pulses/HeterogeneousIHHOFirstOrder.hpp" // Implicit Pulse (adimensional) -// #include "Prototypes/Pulses/HeterogeneousEHHOFirstOrder.hpp" // Explicit Pulse (adimensional) -// #include "Prototypes/Pulses/ConicWavesIHHOFirstOrder.hpp" // Implicit Pulse (geophysic) -// #include "Prototypes/Pulses/ConicWavesEHHOFirstOrder.hpp" // Implicit Pulse (geophysic) +#include "prototypes/acoustic/EAcoustic_stability.hpp" // Acoustic +#include "prototypes/elastic/EElastic_stability.hpp" // Linear Elasticity +#include "prototypes/coupling/EHHOFirstOrder_stability.hpp" // Elasto-Acoustic Coupling +// Convergence test on sinusoidal analytical solution +#include "prototypes/acoustic/IAcoustic_conv_test.hpp" // Implicit Acoustic +#include "prototypes/elastic/IElastic_conv_test.hpp" // Implicit Elastic +#include "prototypes/coupling/Conv_Tests/IHHOFirstOrder.hpp" // Implicit Coupling +#include "prototypes/coupling/Conv_Tests/IHHOFirstOrder_conv_tests.hpp" // Explicit Coupling +#include "prototypes/coupling/Conv_Tests/EHHOFirstOrder.hpp" // Explicit Coupling +#include "prototypes/coupling/Conv_Tests/EHHOFirstOrder_conv_tests.hpp" // Explicit Coupling +// Pulses for comparison with Gar6more +#include "prototypes/coupling/Pulse/HeterogeneousIHHOFirstOrder.hpp" // Implicit Pulse (adimensional) +#include "prototypes/coupling/Pulse/HeterogeneousEHHOFirstOrder.hpp" // Explicit Pulse (adimensional) +#include "prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp" // Implicit Pulse (geophysic) +#include "prototypes/coupling/Pulse/ConicWavesEHHOFirstOrder.hpp" // Implicit Pulse (geophysic) // Sedimentary Basin -// #include "Prototypes/Basin/BassinIHHOFirstOrder.hpp" // Implicit Sedimentary Basin -// #include "Prototypes/Basin/Test_Laurent.hpp" // Implicit Sedimentary Basin -// #include "Prototypes/Basin/BassinEHHOFirstOrder.hpp" // Explicit Sedimentary Basin +#include "prototypes/coupling/Basin/BassinIHHOFirstOrder.hpp" // Implicit Sedimentary Basin +// #include "prototypes/coupling/Basin/BassinEHHOFirstOrder.hpp" // Explicit Sedimentary Basin - not working int main(int argc, char **argv){ @@ -94,13 +93,13 @@ int main(int argc, char **argv){ // Pulse: // HeterogeneousIHHOFirstOrder(argc, argv); - // HeterogeneousEHHOFirstOrder(argc, argv); + HeterogeneousEHHOFirstOrder(argc, argv); // ConicWavesIHHOFirstOrder(argc, argv); // ConicWavesEHHOFirstOrder(argc, argv); -// Bassin sédimentaire: +// Sedimentary basin: // BassinIHHOFirstOrder(argc, argv); - // Test_Laurent(argc, argv); + // Test(argc, argv); // BassinEHHOFirstOrder(argc, argv); Not working } diff --git a/libdiskpp/include/diskpp/boundary_conditions/boundary_conditions.hpp b/libdiskpp/include/diskpp/boundary_conditions/boundary_conditions.hpp index c2fc2ffd..37c1fb85 100644 --- a/libdiskpp/include/diskpp/boundary_conditions/boundary_conditions.hpp +++ b/libdiskpp/include/diskpp/boundary_conditions/boundary_conditions.hpp @@ -341,6 +341,14 @@ class BoundaryConditions } } + template + void + updateDirichletFunction(const Function& bcf, size_t bcf_index) + { + assert(0 <= bcf_index && bcf_index < m_dirichlet_func.size()); + m_dirichlet_func[bcf_index] = bcf; + } + void multiplyAllFunctionsByAFactor(const scalar_type& factor) { diff --git a/libdiskpp/include/diskpp/geometry/geometry_generic.hpp b/libdiskpp/include/diskpp/geometry/geometry_generic.hpp index 226f7347..38c966c8 100644 --- a/libdiskpp/include/diskpp/geometry/geometry_generic.hpp +++ b/libdiskpp/include/diskpp/geometry/geometry_generic.hpp @@ -248,6 +248,14 @@ barycenter(const generic_mesh& msh, return point(Cx, Cy); } +template +point +barycenter_bis(const Mesh& msh, const Element& elm) +{ + auto pts = points(msh, elm); + auto bar = std::accumulate(std::next(pts.begin()), pts.end(), pts.front()); + return bar / typename Mesh::coordinate_type( pts.size() ); +} /** * \brief Return the length of the specified 2D face diff --git a/libdiskpp/include/diskpp/mesh/mesh.hpp b/libdiskpp/include/diskpp/mesh/mesh.hpp index 12c880bb..bc72f424 100644 --- a/libdiskpp/include/diskpp/mesh/mesh.hpp +++ b/libdiskpp/include/diskpp/mesh/mesh.hpp @@ -761,6 +761,21 @@ class neighbour_connectivity return std::make_pair( *std::next(msh.cells_begin(), fo[1].value()), true); } + + std::set + connected_cells(const Mesh& msh, const face_type& fc) + { + std::set ret; + auto face_id = msh.lookup(fc); + auto fo = face_owners.at( face_id ); + if (fo[0]) + ret.insert( msh[fo[0].value()] ); + if (fo[1]) + ret.insert( msh[fo[1].value()] ); + + return ret; + } + }; template diff --git a/libdiskpp/include/diskpp/methods/implementation_hho/scalar_stabilization.hpp b/libdiskpp/include/diskpp/methods/implementation_hho/scalar_stabilization.hpp index d647491b..063fa996 100644 --- a/libdiskpp/include/diskpp/methods/implementation_hho/scalar_stabilization.hpp +++ b/libdiskpp/include/diskpp/methods/implementation_hho/scalar_stabilization.hpp @@ -147,7 +147,8 @@ dynamic_matrix make_scalar_hdg_stabilization(const Mesh& msh, const typename Mesh::cell_type& cl, const CellDegreeInfo& cell_infos, - bool hF = true) + bool hF = true, + bool scaling = true) { using T = typename Mesh::coordinate_type; typedef Matrix matrix_type; @@ -179,7 +180,7 @@ make_scalar_hdg_stabilization(const Mesh& msh, const auto fc = fcs[i]; const auto facdeg = fdi.degree(); - if(hF){ + if (hF) { h = diameter(msh, fc); } @@ -211,7 +212,10 @@ make_scalar_hdg_stabilization(const Mesh& msh, tr.block(0, 0, fbs, cbs) = trace; oper.block(0, 0, fbs, cbs) = mass.ldlt().solve(trace); - data += oper.transpose() * tr * (1. / h); + if (scaling) + data += oper.transpose() * tr * (1. / h); + else + data += oper.transpose() * tr; offset += fbs; } @@ -496,11 +500,12 @@ dynamic_matrix make_scalar_hdg_stabilization(const Mesh& msh, const typename Mesh::cell_type& cl, const hho_degree_info& di, - bool hF = true) + bool hF = true, + bool scaling = true) { const CellDegreeInfo cell_infos(msh, cl, di.cell_degree(), di.face_degree(), di.grad_degree()); - return make_scalar_hdg_stabilization(msh, cl, cell_infos, hF); + return make_scalar_hdg_stabilization(msh, cl, cell_infos, hF, scaling); } /** @@ -519,9 +524,10 @@ dynamic_matrix make_scalar_hdg_stabilization(const Mesh& msh, const typename Mesh::cell_type& cl, const MeshDegreeInfo& msh_infos, - bool hF = true) + bool hF = true, + bool scaling = true) { - return make_scalar_hdg_stabilization(msh, cl, msh_infos.cellDegreeInfo(msh, cl), hF); + return make_scalar_hdg_stabilization(msh, cl, msh_infos.cellDegreeInfo(msh, cl), hF, scaling); } /** diff --git a/libdiskpp/include/diskpp/methods/implementation_hho/vector_stabilization.hpp b/libdiskpp/include/diskpp/methods/implementation_hho/vector_stabilization.hpp index dcfe4d1c..b345ed0d 100644 --- a/libdiskpp/include/diskpp/methods/implementation_hho/vector_stabilization.hpp +++ b/libdiskpp/include/diskpp/methods/implementation_hho/vector_stabilization.hpp @@ -217,9 +217,10 @@ dynamic_matrix make_vector_hdg_stabilization(const Mesh& msh, const typename Mesh::cell_type& cl, const hho_degree_info& di, - const bool hF = true) + bool hF = true, + bool scaling = true) { - const auto hdg_scalar_stab = make_scalar_hdg_stabilization(msh, cl, di, hF); + const auto hdg_scalar_stab = make_scalar_hdg_stabilization(msh, cl, di, hF, scaling); return priv::compute_lhs_vector(msh, cl, di, hdg_scalar_stab); } @@ -240,9 +241,10 @@ dynamic_matrix make_vector_hdg_stabilization(const Mesh& msh, const typename Mesh::cell_type& cl, const MeshDegreeInfo& msh_infos, - const bool hF = true) + const bool hF = true, + bool scaling = true) { - const auto hdg_scalar_stab = make_scalar_hdg_stabilization(msh, cl, msh_infos, hF); + const auto hdg_scalar_stab = make_scalar_hdg_stabilization(msh, cl, msh_infos, hF, scaling); return priv::compute_lhs_vector(msh, cl, msh_infos.cellDegreeInfo(msh, cl), hdg_scalar_stab); } From f8babe1537ca680d8247648e87f9b960216d1578 Mon Sep 17 00:00:00 2001 From: Romain Mottier Date: Fri, 13 Jun 2025 15:20:13 +0200 Subject: [PATCH 08/12] PR correction --- apps/unfitted_HHO/src/unfitted_HHO.cpp~ | 5 ----- libdiskpp/include/diskpp/mesh/mesh.hpp | 10 ++++++---- .../implementation_hho/scalar_stabilization.hpp | 6 ++++-- 3 files changed, 10 insertions(+), 11 deletions(-) delete mode 100644 apps/unfitted_HHO/src/unfitted_HHO.cpp~ diff --git a/apps/unfitted_HHO/src/unfitted_HHO.cpp~ b/apps/unfitted_HHO/src/unfitted_HHO.cpp~ deleted file mode 100644 index d55dbe25..00000000 --- a/apps/unfitted_HHO/src/unfitted_HHO.cpp~ +++ /dev/null @@ -1,5 +0,0 @@ -#include -#include -#include "diskpp/loaders/loader.hpp" -int main(int argc, char **argv) { -} diff --git a/libdiskpp/include/diskpp/mesh/mesh.hpp b/libdiskpp/include/diskpp/mesh/mesh.hpp index bc72f424..2e78c0d9 100644 --- a/libdiskpp/include/diskpp/mesh/mesh.hpp +++ b/libdiskpp/include/diskpp/mesh/mesh.hpp @@ -768,10 +768,12 @@ class neighbour_connectivity std::set ret; auto face_id = msh.lookup(fc); auto fo = face_owners.at( face_id ); - if (fo[0]) - ret.insert( msh[fo[0].value()] ); - if (fo[1]) - ret.insert( msh[fo[1].value()] ); + if (fo[0]) { + ret.insert(msh[fo[0].value()]); + } + if (fo[1]) { + ret.insert(msh[fo[1].value()]); + } return ret; } diff --git a/libdiskpp/include/diskpp/methods/implementation_hho/scalar_stabilization.hpp b/libdiskpp/include/diskpp/methods/implementation_hho/scalar_stabilization.hpp index 063fa996..b8b76424 100644 --- a/libdiskpp/include/diskpp/methods/implementation_hho/scalar_stabilization.hpp +++ b/libdiskpp/include/diskpp/methods/implementation_hho/scalar_stabilization.hpp @@ -212,10 +212,12 @@ make_scalar_hdg_stabilization(const Mesh& msh, tr.block(0, 0, fbs, cbs) = trace; oper.block(0, 0, fbs, cbs) = mass.ldlt().solve(trace); - if (scaling) + if (scaling) { data += oper.transpose() * tr * (1. / h); - else + } + else { data += oper.transpose() * tr; + } offset += fbs; } From c0f1133377d005f34929f5b73b65204794e628c2 Mon Sep 17 00:00:00 2001 From: Romain Mottier Date: Fri, 13 Jun 2025 15:37:05 +0200 Subject: [PATCH 09/12] update contributions --- .../src/common/elastoacoustic_four_fields_assembler.hpp | 2 +- .../wave_propagation/src/common/fitted_geometry_builders.hpp | 5 +++-- apps/wave_propagation/src/common/postprocessor.hpp | 2 +- .../src/common/scal_vec_analytic_functions.hpp | 3 +++ .../src/prototypes/acoustic/EAcoustic_CFL.hpp | 1 - .../src/prototypes/elastodynamics_old/elastodynamics.cpp | 2 +- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp b/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp index b9656d3a..79efd3e2 100644 --- a/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp +++ b/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp @@ -3,7 +3,7 @@ // acoustics // // Created by Omar Durán on 9/7/20. -// +// Contributor: Romain Mottier #pragma once diff --git a/apps/wave_propagation/src/common/fitted_geometry_builders.hpp b/apps/wave_propagation/src/common/fitted_geometry_builders.hpp index 699e0a4f..1c27edc5 100644 --- a/apps/wave_propagation/src/common/fitted_geometry_builders.hpp +++ b/apps/wave_propagation/src/common/fitted_geometry_builders.hpp @@ -1,8 +1,9 @@ // // fitted_geometry_builder.hpp -// acoustics -// // +// Created by Omar Durán +// Contributor: Romain Mottier + #pragma once #ifndef fitted_geometry_builder_hpp diff --git a/apps/wave_propagation/src/common/postprocessor.hpp b/apps/wave_propagation/src/common/postprocessor.hpp index 3ce396a1..c2b2a7d4 100644 --- a/apps/wave_propagation/src/common/postprocessor.hpp +++ b/apps/wave_propagation/src/common/postprocessor.hpp @@ -3,7 +3,7 @@ // acoustics // // Created by Omar Durán on 4/10/20. -// +// Contributor: Romain Mottier #pragma once #ifndef postprocessor_hpp diff --git a/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp b/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp index 2ab45f97..e408c0fe 100644 --- a/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp +++ b/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp @@ -1,4 +1,7 @@ +// Created by Omar Durán +// Contributor: Romain Mottier + #pragma once #ifndef scal_vec_analytic_functions_hpp #define scal_vec_analytic_functions_hpp diff --git a/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_CFL.hpp b/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_CFL.hpp index 942f8885..be306ce0 100644 --- a/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_CFL.hpp +++ b/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_CFL.hpp @@ -1,7 +1,6 @@ // Created by Romain Mottier -// ../wave_propagation -k 2 -s 0 -r 0 -c 1 -p 0 -l 2 -n 300 -f 0 -e 0 void EAcoustic_CFL(int argc, char **argv); diff --git a/apps/wave_propagation/src/prototypes/elastodynamics_old/elastodynamics.cpp b/apps/wave_propagation/src/prototypes/elastodynamics_old/elastodynamics.cpp index eaca52cc..f18a6054 100644 --- a/apps/wave_propagation/src/prototypes/elastodynamics_old/elastodynamics.cpp +++ b/apps/wave_propagation/src/prototypes/elastodynamics_old/elastodynamics.cpp @@ -1,5 +1,5 @@ -// Contributions by Omar Durán and Romain Mottier +// Created by Omar Durán #include #include From 51feb590ae2cd3572077ba8627a0a28424335d15 Mon Sep 17 00:00:00 2001 From: Romain Mottier Date: Mon, 16 Jun 2025 18:29:01 +0200 Subject: [PATCH 10/12] Add multientry command for regression tests --- .../Pulse/ConicWavesIHHOFirstOrder.hpp | 4 ++-- apps/wave_propagation/src/wave_propagation.cpp | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp index 2fa6233c..bb08113f 100644 --- a/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp +++ b/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp @@ -105,7 +105,7 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ nt *= 2; RealType ti = 0.0; - RealType tf = 0.625; + RealType tf = 0.425; RealType dt = (tf-ti)/nt; RealType t = ti; @@ -330,7 +330,7 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ std::cout << bold << cyan << " Matrix decomposed: "; tc.tic(); dirk_an.ComposeMatrix(); - bool iteratif_solver = true; // if false load library: source /opt/intel/oneapi/setvars.sh intel64 + bool iteratif_solver = false; // if false load library: source /opt/intel/oneapi/setvars.sh intel64 if (iteratif_solver) dirk_an.setIterativeSolver(); dirk_an.DecomposeMatrix(); diff --git a/apps/wave_propagation/src/wave_propagation.cpp b/apps/wave_propagation/src/wave_propagation.cpp index 3d3c685c..d18dc27a 100644 --- a/apps/wave_propagation/src/wave_propagation.cpp +++ b/apps/wave_propagation/src/wave_propagation.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -73,6 +74,19 @@ using namespace Eigen; int main(int argc, char **argv){ + DBSetDeprecateWarnings(0); + + // REGRESSION TESTS + if (basename(argv[0]) == std::string("name1") ) { + std::cout << "called with name1" << std::endl; + return 0; + } + + if (basename(argv[0]) == std::string("name2") ) { + std::cout << "called with name2" << std::endl; + return 0; + } + // CFL tables: // EAcoustic_CFL(argc, argv); // EElasticity_CFL(argc, argv); @@ -93,8 +107,8 @@ int main(int argc, char **argv){ // Pulse: // HeterogeneousIHHOFirstOrder(argc, argv); - HeterogeneousEHHOFirstOrder(argc, argv); - // ConicWavesIHHOFirstOrder(argc, argv); + // HeterogeneousEHHOFirstOrder(argc, argv); + ConicWavesIHHOFirstOrder(argc, argv); // ConicWavesEHHOFirstOrder(argc, argv); // Sedimentary basin: From 179b7c467924c00d6e821651f202208d208bdc02 Mon Sep 17 00:00:00 2001 From: Romain Mottier Date: Mon, 28 Jul 2025 11:00:36 +0200 Subject: [PATCH 11/12] ADD REVIEW TEST CASES --- .vscode/settings.json | 69 + .../src/common/dirk_hho_scheme.hpp | 2 +- .../elastoacoustic_four_fields_assembler.hpp | 4 +- .../common/scal_vec_analytic_functions.hpp | 2015 +++++++++-------- .../acoustic/EAcoustic_conv_test.hpp | 398 ++++ .../Acoustic_Conv_Test/EHHOFirstOrder.hpp | 17 +- .../coupling/Conv_Tests/IHHOFirstOrder.hpp | 30 +- .../Pulse/ConicWavesEHHOFirstOrder.hpp | 17 +- .../Pulse/ConicWavesIHHOFirstOrder.hpp | 84 +- .../coupling/Pulse/review_CMAME.hpp | 1007 ++++++++ .../wave_propagation/src/wave_propagation.cpp | 12 +- 11 files changed, 2664 insertions(+), 991 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 apps/wave_propagation/src/prototypes/acoustic/EAcoustic_conv_test.hpp create mode 100644 apps/wave_propagation/src/prototypes/coupling/Pulse/review_CMAME.hpp diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..74239204 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,69 @@ +{ + "files.associations": { + ".inc": ".f90", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "semaphore": "cpp", + "span": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp", + "variant": "cpp", + "format": "cpp", + "text_encoding": "cpp" + } +} \ No newline at end of file diff --git a/apps/wave_propagation/src/common/dirk_hho_scheme.hpp b/apps/wave_propagation/src/common/dirk_hho_scheme.hpp index cceb8a16..584ba62e 100644 --- a/apps/wave_propagation/src/common/dirk_hho_scheme.hpp +++ b/apps/wave_propagation/src/common/dirk_hho_scheme.hpp @@ -80,7 +80,7 @@ class dirk_hho_scheme { void setIterativeSolver() { m_iteraive_solver_Q = true; - m_analysis.set_iterative_solver(false, 1.0e-2); + m_analysis.set_iterative_solver(false, 1.0e-1); } void DecomposeMatrix() { diff --git a/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp b/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp index 79efd3e2..dfe30417 100644 --- a/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp +++ b/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp @@ -604,7 +604,7 @@ class elastoacoustic_four_fields_assembler for (auto e_chunk : m_e_material) { size_t e_cell_ind = m_e_cell_index[e_chunk.first]; auto& cell = storage->surfaces[e_chunk.first]; - Matrix mixed_operator_loc = e_mixed_operator(e_chunk.second,msh,cell,explicit_scheme); + Matrix mixed_operator_loc = e_mixed_operator(e_chunk.second, msh, cell, explicit_scheme); Matrix f_loc = e_mixed_rhs(msh, cell, e_rhs_fun); scatter_e_data(e_cell_ind, msh, cell, mixed_operator_loc, f_loc); } @@ -613,7 +613,7 @@ class elastoacoustic_four_fields_assembler for (auto a_chunk : m_a_material) { size_t a_cell_ind = m_a_cell_index[a_chunk.first]; auto& cell = storage->surfaces[a_chunk.first]; - Matrix mixed_operator_loc = a_mixed_operator(a_chunk.second, msh, cell,explicit_scheme); + Matrix mixed_operator_loc = a_mixed_operator(a_chunk.second, msh, cell, explicit_scheme); Matrix f_loc = a_mixed_rhs(msh, cell, a_rhs_fun); scatter_a_data(a_cell_ind, msh, cell, mixed_operator_loc, f_loc); } diff --git a/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp b/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp index e408c0fe..3da218eb 100644 --- a/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp +++ b/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp @@ -7,938 +7,1097 @@ #define scal_vec_analytic_functions_hpp class scal_vec_analytic_functions { - -public: - - /// Enumerate defining the function type - enum EFunctionType { EFunctionNonPolynomial = 0, - EFunctionQuadraticInTime = 1, - EFunctionQuadraticInSpace = 2, - reproduction_acoustic = 3, - reproduction_elastic = 4, - EFunctionNonPolynomial_paper = 5 }; - - scal_vec_analytic_functions() { - m_function_type = EFunctionNonPolynomial; - } - ~scal_vec_analytic_functions() { - } + public: - void set_function_type(EFunctionType function_type) { - m_function_type = function_type; - } - - std::function - (const typename disk::generic_mesh::point_type& )> Evaluate_u(double & t) { - - switch (m_function_type) { - - case EFunctionNonPolynomial: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,ux,uy; - x = pt.x(); - y = pt.y(); - ux = x*x*std::sin(M_PI*y)*std::cos((M_PI*x)/2.)*std::cos(std::sqrt(2.0)*M_PI*t); - uy = x*x*std::sin(M_PI*y)*std::cos((M_PI*x)/2.)*std::cos(std::sqrt(2.0)*M_PI*t); - disk::static_vector u{ux,uy}; - return u; - }; + /// Enumerate defining the function type + enum EFunctionType { + EFunctionNonPolynomial = 0, + EFunctionQuadraticInTime = 1, + EFunctionQuadraticInSpace = 2, + reproduction_acoustic = 3, + reproduction_elastic = 4, + EFunctionNonPolynomial_paper = 5, + EFunctionCubicInTimeAcoustic = 6, + EFunctionQuarticInTimeAcoustic = 7, + EFunctionQuadraticInSpaceAcoustic = 8}; + + scal_vec_analytic_functions() { + m_function_type = EFunctionNonPolynomial; } - break; - - case EFunctionQuadraticInTime: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,ux,uy; - x = pt.x(); - y = pt.y(); - ux = x*t*t*std::sin(M_PI*x)*std::sin(M_PI*y); - uy = x*t*t*std::sin(M_PI*x)*std::sin(M_PI*y); - disk::static_vector u{ux,uy}; - return u; - }; - } - break; - - case EFunctionQuadraticInSpace: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,ux,uy; - x = pt.x(); - y = pt.y(); - ux = (1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); - uy = (1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); - disk::static_vector u{ux,uy}; - return u; - }; - } - break; - - case reproduction_elastic: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { - double x,y,ux,uy; - x = pt.x(); - y = pt.y(); - ux = -t*t*std::cos(M_PI*y)*std::sin(M_PI*x); - uy = t*t*std::cos(M_PI*x)*std::sin(M_PI*y); - disk::static_vector u{ux,uy}; - return u; - }; - } - break; - - case EFunctionNonPolynomial_paper: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { - double x,y,ux,uy, w, theta; - x = pt.x(); - y = pt.y(); - w = 1.0; - theta = 10*M_PI; - // w = 5.0; - // theta = std::sqrt(2)*M_PI; - ux = x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); - uy = x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); - disk::static_vector u{ux,uy}; - return u; - }; - } - - break; - - default: { - std::cout << " Function not implemented " << std::endl; - return [](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - disk::static_vector u; - return u; - }; - } - break; - } - - } - - std::function - (const typename disk::generic_mesh::point_type& )> Evaluate_v(double & t){ - - switch (m_function_type) { - - case EFunctionNonPolynomial: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,vx,vy; - x = pt.x(); - y = pt.y(); - vx = -(std::sqrt(2.0)*M_PI*x*x*std::cos((M_PI*x)/2.)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*y)); - vy = -(std::sqrt(2.0)*M_PI*x*x*std::cos((M_PI*x)/2.)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*y)); - disk::static_vector v{vx,vy}; - return v; - }; - } - break; - - case EFunctionQuadraticInTime: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,vx,vy; - x = pt.x(); - y = pt.y(); - vx = 2.0*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); - vy = 2.0*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); - disk::static_vector v{vx,vy}; - return v; - }; - } - break; - - case EFunctionQuadraticInSpace: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,vx,vy; - x = pt.x(); - y = pt.y(); - vx = std::sqrt(2.0)*M_PI*(1 + x)*x*x*(1 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); - vy = std::sqrt(2.0)*M_PI*(1 + x)*x*x*(1 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); - disk::static_vector v{vx,vy}; - return v; - }; - } - break; - - case reproduction_elastic:{ - return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { - double x,y,vx,vy; - x = pt.x(); - y = pt.y(); - vx = -2*t*std::cos(M_PI*y)*std::sin(M_PI*x); - vy = 2*t*std::cos(M_PI*x)*std::sin(M_PI*y); - disk::static_vector v{vx,vy}; - return v; - }; - } -break; - - case EFunctionNonPolynomial_paper:{ - return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { - double x,y,vx,vy,w,theta; - x = pt.x(); - y = pt.y(); - w = 1.0; - theta = 10*M_PI; - // w = 5.0; - // theta = std::sqrt(2)*M_PI; - vx = -(theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos((M_PI*w*x)/2.)); - vy = -(theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos((M_PI*w*x)/2.)); - disk::static_vector v{vx,vy}; - return v; - }; - } - - break; - - default: { - std::cout << " Function not implemented " << std::endl; - return [](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y; - x = pt.x(); - y = pt.y(); - disk::static_vector v; - return v; - }; - } - break; - - } - - } - - std::function - (const typename disk::generic_mesh::point_type& )> Evaluate_a(double & t){ - - switch (m_function_type) { - - case EFunctionNonPolynomial: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,ax,ay; - x = pt.x(); - y = pt.y(); - ax = -2*M_PI*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y); - ay = -2*M_PI*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y); - disk::static_vector a{ax,ay}; - return a; - }; - } - break; - - case EFunctionQuadraticInTime: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,ax,ay; - x = pt.x(); - y = pt.y(); - ax = 2.0*x*std::sin(M_PI*x)*std::sin(M_PI*y); - ay = 2.0*x*std::sin(M_PI*x)*std::sin(M_PI*y); - disk::static_vector a{ax,ay}; - return a; - }; - } - break; - - case EFunctionQuadraticInSpace: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,ax,ay; - x = pt.x(); - y = pt.y(); - ax = -2*M_PI*M_PI*(1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); - ay = -2*M_PI*M_PI*(1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); - disk::static_vector a{ax,ay}; - return a; - }; - } - break; - - case reproduction_elastic:{ - return [](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { - double x,y,ax,ay; - x = pt.x(); - y = pt.y(); - ax = -2*std::cos(M_PI*y)*std::sin(M_PI*x); - ay = 2*std::cos(M_PI*x)*std::sin(M_PI*y); - disk::static_vector a{ax,ay}; - return a; - }; - } - break; - - case EFunctionNonPolynomial_paper: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,ax,ay,w,theta; - x = pt.x(); - y = pt.y(); - w = 1.0; - theta = 10*M_PI; - // w = 5.0; - // theta = std::sqrt(2)*M_PI; - ax = -theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); - ay = -theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); - disk::static_vector a{ax,ay}; - return a; - }; - } - break; - - default: { - std::cout << " Function not implemented " << std::endl; - return [](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - disk::static_vector f; - return f; - }; - } - break; - - } - - } - - std::function - (const typename disk::generic_mesh::point_type& )> Evaluate_f(double & t){ - - switch (m_function_type) { - - case EFunctionNonPolynomial: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,fx,fy; - x = pt.x(); - y = pt.y(); - fx = -(std::cos(std::sqrt(2.0)*M_PI*t)*(-4*M_PI*x*std::sin((M_PI*x)/2.)*(M_PI*x*std::cos(M_PI*y) + 6*std::sin(M_PI*y)) + std::cos((M_PI*x)/2.)*(16*M_PI*x*std::cos(M_PI*y) + (24 + M_PI*M_PI*x*x)*std::sin(M_PI*y))))/4.0; - fy = (std::cos(std::sqrt(2.0)*M_PI*t)*(4*M_PI*x*std::sin((M_PI*x)/2.)*(M_PI*x*std::cos(M_PI*y) + 2*std::sin(M_PI*y)) + std::cos((M_PI*x)/2.)*(-16*M_PI*x*std::cos(M_PI*y) + (-8 + 5*M_PI*M_PI*x*x)*std::sin(M_PI*y))))/4.; - disk::static_vector f{fx,fy}; - return f; - }; - } - break; - - case EFunctionQuadraticInTime: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,fx,fy; - x = pt.x(); - y = pt.y(); - fx = -2 * ( M_PI*t*t*std::cos(M_PI*x)*( M_PI*x*std::cos(M_PI*y) + 3*std::sin(M_PI*y) ) + - std::sin(M_PI*x)*(M_PI*t*t*std::cos(M_PI*y) - (1+2*M_PI*M_PI*t*t)*x*std::sin(M_PI*y))); - fy = (1 + M_PI*M_PI*t*t)*x*std::cos(M_PI*(x - y)) - (1+3*M_PI*M_PI*t*t)*x*std::cos(M_PI*(x+y)) - - 2*M_PI*t*t*std::sin(M_PI*(x+y)); - disk::static_vector f{fx,fy}; - return f; - }; - } - break; - - case EFunctionQuadraticInSpace: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,fx,fy; - x = pt.x(); - y = pt.y(); - fx = 2 * ( x * (-2+(-2+x)*x) -3*y -x*(5+x*(-6+M_PI*M_PI*(1+x)))*y - + (3+x*(9+M_PI*M_PI*x*(1+x)))*y*y)*std::sin(std::sqrt(2.0)*M_PI*t); - fy = 2 * ( x*x*(6 + M_PI*M_PI*(-1 + y))*y + (-1 + y)*y + x*x*x*(3 + M_PI*M_PI*(-1 + y)*y) - + x*(-2 + y + 3*y*y))*std::sin(std::sqrt(2.0)*M_PI*t); - disk::static_vector f{fx,fy}; - return f; - }; - } - break; - - case reproduction_elastic: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { - double x,y,fx,fy; - x = pt.x(); - y = pt.y(); - fx = -2*(1 + M_PI*M_PI*t*t)*std::cos(M_PI*y)*std::sin(M_PI*x); - fy = 2*(1 + M_PI*M_PI*t*t)*std::cos(M_PI*x)*std::sin(M_PI*y); - disk::static_vector f{fx,fy}; - return f; - }; - } - break; - - case EFunctionNonPolynomial_paper: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,fx,fy,w,theta; - x = pt.x(); - y = pt.y(); - w = 1.0; - theta = 10*M_PI; - // w = 5.0; - // theta = std::sqrt(2)*M_PI; - - fx = - theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0) - + M_PI*M_PI*w*w*x*x*std::sin(M_PI*w*x/2)*std::cos(theta*t)*std::cos(M_PI*w*y) - + 7*M_PI*M_PI*w*w*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*cos(M_PI*w*x/2)/4.0 - + 6*M_PI*w*x*std::sin(M_PI*w*x/2)*std::sin(M_PI*w*y)*std::cos(theta*t) - - 4*M_PI*w*x*std::cos(theta*t)*std::cos(M_PI*w*x/2)*std::cos(M_PI*w*y) - - 6*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2); - - fy = - theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0) - + M_PI*M_PI*w*w*x*x*std::sin(M_PI*w*x/2)*std::cos(theta*t)*std::cos(M_PI*w*y) - + 13*M_PI*M_PI*w*w*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*cos(M_PI*w*x/2)/4.0 - + 2*M_PI*w*x*std::sin(M_PI*w*x/2)*std::sin(M_PI*w*y)*std::cos(theta*t) - - 4*M_PI*w*x*std::cos(theta*t)*std::cos(M_PI*w*x/2)*std::cos(M_PI*w*y) - - 2*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2); - disk::static_vector f{fx,fy}; - return f; - }; - } - break; - - default: - { - std::cout << " Function not implemented " << std::endl; - return [](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - disk::static_vector f; - return f; - }; + + ~scal_vec_analytic_functions() { } - break; - } - - } - - - std::function - (const typename disk::generic_mesh::point_type& )> Evaluate_sigma(double & t){ - - switch (m_function_type) { - - case EFunctionNonPolynomial: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_matrix { - double x,y; - x = pt.x(); - y = pt.y(); - disk::static_matrix sigma = disk::static_matrix::Zero(2,2); - sigma(0,0) = M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::cos(M_PI*y) + 4*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - - M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y) + - (4*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y))/2.0; - - sigma(0,1) = M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::cos(M_PI*y) + 2*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - - (M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y))/2.; - sigma(1,0) = sigma(0,1); - - sigma(1,1) = 3*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::cos(M_PI*y) + - (4*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y))/2.; - return sigma; - }; - } - break; - - case EFunctionQuadraticInTime: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_matrix { - double x,y; - x = pt.x(); - y = pt.y(); - disk::static_matrix sigma = disk::static_matrix::Zero(2,2); - sigma(0,0) = t*t*(M_PI*x*std::cos(M_PI*y)*std::sin(M_PI*x) - + 3*(M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y)); - - sigma(0,1) = t*t*(M_PI*x*std::cos(M_PI*y)*std::sin(M_PI*x) - + (M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y)); - sigma(1,0) = sigma(0,1); - - sigma(1,1) = t*t*(3*M_PI*x*std::cos(M_PI*y)*std::sin(M_PI*x) - + (M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y)); - return sigma; - }; - } - break; - - case EFunctionQuadraticInSpace: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_matrix { - double x,y; - x = pt.x(); - y = pt.y(); - disk::static_matrix sigma = disk::static_matrix::Zero(2,2); - sigma(0,0) = 2*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) - + 4*x*(1+x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) - + (2*x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) - - 2*x*x*(1 + x)*y*std::sin(std::sqrt(2.0)*M_PI*t))/2.0 - + (2*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) - + 4*x*(1 + x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t))/2.0; - - sigma(0,1) = x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) - - x*x*(1 + x)*y*std::sin(std::sqrt(2.0)*M_PI*t) - + x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) - + 2*x*(1 + x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); - - sigma(1,0) = sigma(0,1); - - sigma(1,1) = 2*x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) - - 2*x*x*(1 + x)*y*std::sin(std::sqrt(2.0)*M_PI*t) - + (2*x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) - - 2*x*x*(1 + x)*y*std::sin(std::sqrt(2.0)*M_PI*t))/2.0 - + (2*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) - + 4*x*(1 + x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t))/2.0; - return sigma; - }; - } - break; - - case reproduction_elastic: - { - return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_matrix { - double x,y; - x = pt.x(); - y = pt.y(); - disk::static_matrix sigma = disk::static_matrix::Zero(2,2); - sigma(0,0) = -2*M_PI*t*t*std::cos(M_PI*x)*std::cos(M_PI*y); - sigma(1,1) = 2*M_PI*t*t*std::cos(M_PI*x)*std::cos(M_PI*y); - return sigma; - }; - } - break; - - case EFunctionNonPolynomial_paper: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_matrix { - double x,y,w,theta; - x = pt.x(); - y = pt.y(); - - w = 1.0; - theta = 10*M_PI; - // w = 5.0; - // theta = std::sqrt(2)*M_PI; - - disk::static_matrix sigma = disk::static_matrix::Zero(2,2); - sigma(0,0) = - 3.0*M_PI*w*x*x*std::sin(M_PI*w*x/2.0)*std::sin(M_PI*w*y)*std::cos(theta*t)/2.0 - + M_PI*w*x*x*std::cos(theta*t)*std::cos(M_PI*w*x/2.0)*std::cos(M_PI*w*y) - + 6.0*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0); - - sigma(0,1) = - M_PI*w*x*x*std::sin(M_PI*w*x/2.0)*std::sin(M_PI*w*y)*std::cos(theta*t)/2.0 - + M_PI*w*x*x*std::cos(theta*t)*std::cos(M_PI*w*x/2.0)*std::cos(M_PI*w*y) - + 2.0*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0); - - sigma(1,0) = sigma(0,1); - - sigma(1,1) = - M_PI*w*x*x*std::sin(M_PI*w*x/2.0)*std::sin(M_PI*w*y)*std::cos(theta*t)/2.0 - + 3*M_PI*w*x*x*std::cos(theta*t)*std::cos(M_PI*w*x/2.0)*std::cos(M_PI*w*y) - + 2.0*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0); - return sigma; - }; - } - break; - - default: { - std::cout << " Function not implemented " << std::endl; - return [](const typename disk::generic_mesh::point_type& pt) - -> disk::static_matrix { - disk::static_matrix sigma(2,2); - return sigma; - }; - } - break; - } - - } - - std::function::point_type& )> Evaluate_s_u(double & t) { - - switch (m_function_type) { + void set_function_type(EFunctionType function_type) { + m_function_type = function_type; + } - case EFunctionNonPolynomial: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y; - x = pt.x(); - y = pt.y(); - return x*x*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); - }; - } - break; - - case EFunctionQuadraticInTime: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y; - x = pt.x(); - y = pt.y(); - return t*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); - }; - } - break; - - case EFunctionQuadraticInSpace: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y; - x = pt.x(); - y = pt.y(); - return (1 - x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); - }; - } - break; - - case reproduction_acoustic: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y; - x = pt.x(); - y = pt.y(); - return t*t*std::sin(M_PI*x)*std::sin(M_PI*y); - }; - } - break; - - case EFunctionNonPolynomial_paper: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y,w,theta; - x = pt.x(); - y = pt.y(); - - w = 1.0; - theta = 10*M_PI; - // w = 5.0; - // theta = std::sqrt(2)*M_PI; - - return x*x*std::sin(theta*t)*std::sin(w*M_PI*x)*std::sin(w*M_PI*y); - }; - } - break; - - default: { - std::cout << " Function not implemented " << std::endl; - return [](const typename disk::generic_mesh::point_type& pt) -> double { - return 0; - }; - } - break; - } - - } - - std::function::point_type& )> Evaluate_s_v(double & t){ - - switch (m_function_type) { - - case EFunctionNonPolynomial: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y; - x = pt.x(); - y = pt.y(); - return std::sqrt(2.0)*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); - }; - } - break; - - case EFunctionQuadraticInTime: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y; - x = pt.x(); - y = pt.y(); - return 2*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); - }; - } - break; - - case EFunctionQuadraticInSpace: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y; - x = pt.x(); - y = pt.y(); - return std::sqrt(2.0)*M_PI*(1 - x)*x*x*(1 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); - }; - } - break; - - case reproduction_acoustic: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - return 2.0*t*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); - }; - } - break; - - case EFunctionNonPolynomial_paper: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y,w,theta; - x = pt.x(); - y = pt.y(); - w = 1.0; - theta = 10*M_PI; - // w = 5.0; - // theta = std::sqrt(2)*M_PI; - return theta*x*x*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)*std::cos(theta*t); - }; - } - break; - - default: { - std::cout << " Function not implemented " << std::endl; - return [](const typename disk::generic_mesh::point_type& pt) -> double { - return 0; - }; - } - break; - } - - } - - std::function::point_type& )> Evaluate_s_a(double & t){ - - switch (m_function_type) { - case EFunctionNonPolynomial: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y; - x = pt.x(); - y = pt.y(); - return -2*M_PI*M_PI*x*x*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); - }; - } - break; - - case EFunctionQuadraticInTime: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y; - x = pt.x(); - y = pt.y(); - return 2*x*std::sin(M_PI*x)*std::sin(M_PI*y); - }; - } - break; - - case EFunctionQuadraticInSpace: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y; - x = pt.x(); - y = pt.y(); - return -2*M_PI*M_PI*(1 - x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); - }; - } - break; - - case reproduction_acoustic: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y; - x = pt.x(); - y = pt.y(); - return 2.0*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); - }; - } - break; - - case EFunctionNonPolynomial_paper: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y,w,theta; - x = pt.x(); - y = pt.y(); - w = 1.0; - theta = 10*M_PI; - // w = 5.0; - // theta = std::sqrt(2)*M_PI; - return -theta*theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y); - }; - } - break; - - default: { - std::cout << " Function not implemented " << std::endl; - return [](const typename disk::generic_mesh::point_type& pt) -> double { - return 0; - }; - } - break; - } - - } - - std::function::point_type& )> Evaluate_s_f(double & t){ - - switch (m_function_type) { - case EFunctionNonPolynomial: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y,f; - x = pt.x(); - y = pt.y(); - f = -2*std::sin(std::sqrt(2.0)*M_PI*t)*(2*M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y); - return f; - }; - } - break; - - case EFunctionQuadraticInTime: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y,f; - x = pt.x(); - y = pt.y(); - f = 2*(-(M_PI*t*t*std::cos(M_PI*x)) + (1 + M_PI*M_PI*t*t)*x*std::sin(M_PI*x))*std::sin(M_PI*y); - return f; - }; - } - break; - - case EFunctionQuadraticInSpace: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y,f; - x = pt.x(); - y = pt.y(); - f = 2*((-1 + y)*y - 3*x*(-1 + y)*y + x*x*x*(-1 - M_PI*M_PI*(-1 + y)*y) - + x*x*(1 + M_PI*M_PI*(-1 + y)*y))*std::sin(std::sqrt(2.0)*M_PI*t); - return f; - }; - } - break; - - case reproduction_acoustic: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y,f; - x = pt.x(); - y = pt.y(); - return 2.0*(1.0 + M_PI*M_PI*t*t)*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); - }; - } - break; - - case EFunctionNonPolynomial_paper: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> double { - double x,y,f,w,theta; - x = pt.x(); - y = pt.y(); - w = 1.0; - theta = 10*M_PI; - // w = 5.0; - // theta = std::sqrt(2)*M_PI; - f = - theta*theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y) - + 2*M_PI*M_PI*theta*w*w*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)/theta - - 4*M_PI*theta*w*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos(M_PI*w*x)/theta - - 2*theta*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)/theta; - return f; - }; - } - break; - - default: { - std::cout << " Function not implemented " << std::endl; - return [](const typename disk::generic_mesh::point_type& pt) -> double { - return 0; - }; - } - break; - } - - } - - - std::function - (const typename disk::generic_mesh::point_type& )> Evaluate_s_q(double & t){ - - switch (m_function_type) { - case EFunctionNonPolynomial: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,qx,qy; - x = pt.x(); - y = pt.y(); - qx = M_PI*x*x*std::cos(M_PI*x)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*y) + 2*x*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); - qy = M_PI*x*x*std::cos(M_PI*y)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x); - disk::static_vector q{qx,qy}; - return q; - }; - } - break; - - case EFunctionQuadraticInTime: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,qx,qy; - x = pt.x(); - y = pt.y(); - std::vector flux(2); - qx = M_PI*t*t*x*std::cos(M_PI*x)*std::sin(M_PI*y) + t*t*std::sin(M_PI*x)*std::sin(M_PI*y); - qy = M_PI*t*t*x*std::cos(M_PI*y)*std::sin(M_PI*x); - disk::static_vector q{qx,qy}; - return q; - }; - } - break; - - case EFunctionQuadraticInSpace: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,qx,qy; - x = pt.x(); - y = pt.y(); - std::vector flux(2); - qx = 2*(1 - x)*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) - - x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); - qy = (1 - x)*x*x*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) - - (1 - x)*x*x*y*std::sin(std::sqrt(2.0)*M_PI*t); - disk::static_vector q{qx,qy}; - return q; - }; - } - break; - - case reproduction_acoustic: { - return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { - double x,y,qx,qy; - x = pt.x(); - y = pt.y(); - qx = M_PI*t*t*std::cos(M_PI*x)*std::sin(M_PI*y); - qy = M_PI*t*t*std::sin(M_PI*x)*std::cos(M_PI*y); - disk::static_vector q{qx,qy}; - return q; - }; - } - break; - - case EFunctionNonPolynomial_paper: { - return [&t](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector { - double x,y,qx,qy,w,theta; - x = pt.x(); - y = pt.y(); - w = 1.0; - theta = 10*M_PI; - // w = 5.0; - // theta = std::sqrt(2)*M_PI; - qx = M_PI*theta*w*x*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos(M_PI*w*x)/theta + 2*theta*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)/theta; - qy = M_PI*theta*w*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::cos(M_PI*w*y)/theta; - disk::static_vector q{qx,qy}; - return q; - }; - } - break; - - default: { - std::cout << " Function not implemented " << std::endl; - return [](const typename disk::generic_mesh::point_type& pt) - -> disk::static_vector{ - disk::static_vector f{0,0}; - return f; - }; - } - break; - } - - } - -private: - - EFunctionType m_function_type; + std::function + (const typename disk::generic_mesh::point_type& )> Evaluate_u(double & t) { + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,ux,uy; + x = pt.x(); + y = pt.y(); + ux = x*x*std::sin(M_PI*y)*std::cos((M_PI*x)/2.)*std::cos(std::sqrt(2.0)*M_PI*t); + uy = x*x*std::sin(M_PI*y)*std::cos((M_PI*x)/2.)*std::cos(std::sqrt(2.0)*M_PI*t); + disk::static_vector u{ux,uy}; + return u; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,ux,uy; + x = pt.x(); + y = pt.y(); + ux = x*t*t*std::sin(M_PI*x)*std::sin(M_PI*y); + uy = x*t*t*std::sin(M_PI*x)*std::sin(M_PI*y); + disk::static_vector u{ux,uy}; + return u; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,ux,uy; + x = pt.x(); + y = pt.y(); + ux = (1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + uy = (1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + disk::static_vector u{ux,uy}; + return u; + }; + } + break; + + case reproduction_elastic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { + double x,y,ux,uy; + x = pt.x(); + y = pt.y(); + ux = -t*t*std::cos(M_PI*y)*std::sin(M_PI*x); + uy = t*t*std::cos(M_PI*x)*std::sin(M_PI*y); + disk::static_vector u{ux,uy}; + return u; + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { + double x,y,ux,uy, w, theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + ux = x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); + uy = x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); + disk::static_vector u{ux,uy}; + return u; + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + disk::static_vector u; + return u; + }; + } + break; + } + } + + std::function + (const typename disk::generic_mesh::point_type& )> Evaluate_v(double & t){ + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,vx,vy; + x = pt.x(); + y = pt.y(); + vx = -(std::sqrt(2.0)*M_PI*x*x*std::cos((M_PI*x)/2.)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*y)); + vy = -(std::sqrt(2.0)*M_PI*x*x*std::cos((M_PI*x)/2.)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*y)); + disk::static_vector v{vx,vy}; + return v; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,vx,vy; + x = pt.x(); + y = pt.y(); + vx = 2.0*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); + vy = 2.0*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); + disk::static_vector v{vx,vy}; + return v; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,vx,vy; + x = pt.x(); + y = pt.y(); + vx = std::sqrt(2.0)*M_PI*(1 + x)*x*x*(1 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); + vy = std::sqrt(2.0)*M_PI*(1 + x)*x*x*(1 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); + disk::static_vector v{vx,vy}; + return v; + }; + } + break; + + case reproduction_elastic:{ + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { + double x,y,vx,vy; + x = pt.x(); + y = pt.y(); + vx = -2*t*std::cos(M_PI*y)*std::sin(M_PI*x); + vy = 2*t*std::cos(M_PI*x)*std::sin(M_PI*y); + disk::static_vector v{vx,vy}; + return v; + }; + } + break; + + case EFunctionNonPolynomial_paper:{ + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { + double x,y,vx,vy,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + vx = -(theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos((M_PI*w*x)/2.)); + vy = -(theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos((M_PI*w*x)/2.)); + disk::static_vector v{vx,vy}; + return v; + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_vector v; + return v; + }; + } + break; + } + } + + std::function + (const typename disk::generic_mesh::point_type& )> Evaluate_a(double & t){ + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,ax,ay; + x = pt.x(); + y = pt.y(); + ax = -2*M_PI*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y); + ay = -2*M_PI*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y); + disk::static_vector a{ax,ay}; + return a; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,ax,ay; + x = pt.x(); + y = pt.y(); + ax = 2.0*x*std::sin(M_PI*x)*std::sin(M_PI*y); + ay = 2.0*x*std::sin(M_PI*x)*std::sin(M_PI*y); + disk::static_vector a{ax,ay}; + return a; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,ax,ay; + x = pt.x(); + y = pt.y(); + ax = -2*M_PI*M_PI*(1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + ay = -2*M_PI*M_PI*(1 + x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + disk::static_vector a{ax,ay}; + return a; + }; + } + break; + + case reproduction_elastic:{ + return [](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { + double x,y,ax,ay; + x = pt.x(); + y = pt.y(); + ax = -2*std::cos(M_PI*y)*std::sin(M_PI*x); + ay = 2*std::cos(M_PI*x)*std::sin(M_PI*y); + disk::static_vector a{ax,ay}; + return a; + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,ax,ay,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + ax = -theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); + ay = -theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos((M_PI*w*x)/2.); + disk::static_vector a{ax,ay}; + return a; + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + disk::static_vector f; + return f; + }; + } + break; + } + } + + std::function + (const typename disk::generic_mesh::point_type& )> Evaluate_f(double & t){ + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,fx,fy; + x = pt.x(); + y = pt.y(); + fx = -(std::cos(std::sqrt(2.0)*M_PI*t)*(-4*M_PI*x*std::sin((M_PI*x)/2.)*(M_PI*x*std::cos(M_PI*y) + 6*std::sin(M_PI*y)) + std::cos((M_PI*x)/2.)*(16*M_PI*x*std::cos(M_PI*y) + (24 + M_PI*M_PI*x*x)*std::sin(M_PI*y))))/4.0; + fy = (std::cos(std::sqrt(2.0)*M_PI*t)*(4*M_PI*x*std::sin((M_PI*x)/2.)*(M_PI*x*std::cos(M_PI*y) + 2*std::sin(M_PI*y)) + std::cos((M_PI*x)/2.)*(-16*M_PI*x*std::cos(M_PI*y) + (-8 + 5*M_PI*M_PI*x*x)*std::sin(M_PI*y))))/4.; + disk::static_vector f{fx,fy}; + return f; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,fx,fy; + x = pt.x(); + y = pt.y(); + fx = -2 * ( M_PI*t*t*std::cos(M_PI*x)*( M_PI*x*std::cos(M_PI*y) + 3*std::sin(M_PI*y) ) + + std::sin(M_PI*x)*(M_PI*t*t*std::cos(M_PI*y) - (1+2*M_PI*M_PI*t*t)*x*std::sin(M_PI*y))); + fy = (1 + M_PI*M_PI*t*t)*x*std::cos(M_PI*(x - y)) - (1+3*M_PI*M_PI*t*t)*x*std::cos(M_PI*(x+y)) + - 2*M_PI*t*t*std::sin(M_PI*(x+y)); + disk::static_vector f{fx,fy}; + return f; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,fx,fy; + x = pt.x(); + y = pt.y(); + fx = 2 * ( x * (-2+(-2+x)*x) -3*y -x*(5+x*(-6+M_PI*M_PI*(1+x)))*y + + (3+x*(9+M_PI*M_PI*x*(1+x)))*y*y)*std::sin(std::sqrt(2.0)*M_PI*t); + fy = 2 * ( x*x*(6 + M_PI*M_PI*(-1 + y))*y + (-1 + y)*y + x*x*x*(3 + M_PI*M_PI*(-1 + y)*y) + + x*(-2 + y + 3*y*y))*std::sin(std::sqrt(2.0)*M_PI*t); + disk::static_vector f{fx,fy}; + return f; + }; + } + break; + + case reproduction_elastic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { + double x,y,fx,fy; + x = pt.x(); + y = pt.y(); + fx = -2*(1 + M_PI*M_PI*t*t)*std::cos(M_PI*y)*std::sin(M_PI*x); + fy = 2*(1 + M_PI*M_PI*t*t)*std::cos(M_PI*x)*std::sin(M_PI*y); + disk::static_vector f{fx,fy}; + return f; + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,fx,fy,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + + fx = - theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0) + + M_PI*M_PI*w*w*x*x*std::sin(M_PI*w*x/2)*std::cos(theta*t)*std::cos(M_PI*w*y) + + 7*M_PI*M_PI*w*w*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*cos(M_PI*w*x/2)/4.0 + + 6*M_PI*w*x*std::sin(M_PI*w*x/2)*std::sin(M_PI*w*y)*std::cos(theta*t) + - 4*M_PI*w*x*std::cos(theta*t)*std::cos(M_PI*w*x/2)*std::cos(M_PI*w*y) + - 6*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2); + + fy = - theta*theta*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0) + + M_PI*M_PI*w*w*x*x*std::sin(M_PI*w*x/2)*std::cos(theta*t)*std::cos(M_PI*w*y) + + 13*M_PI*M_PI*w*w*x*x*std::sin(M_PI*w*y)*std::cos(theta*t)*cos(M_PI*w*x/2)/4.0 + + 2*M_PI*w*x*std::sin(M_PI*w*x/2)*std::sin(M_PI*w*y)*std::cos(theta*t) + - 4*M_PI*w*x*std::cos(theta*t)*std::cos(M_PI*w*x/2)*std::cos(M_PI*w*y) + - 2*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2); + disk::static_vector f{fx,fy}; + return f; + }; + } + break; + + default: + { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + disk::static_vector f; + return f; + }; + } + break; + } + } + + + std::function + (const typename disk::generic_mesh::point_type& )> Evaluate_sigma(double & t){ + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + sigma(0,0) = M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::cos(M_PI*y) + 4*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - + M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y) + + (4*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y))/2.0; + + sigma(0,1) = M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::cos(M_PI*y) + 2*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - + (M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y))/2.; + sigma(1,0) = sigma(0,1); + + sigma(1,1) = 3*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::cos(M_PI*y) + + (4*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::cos((M_PI*x)/2.)*std::sin(M_PI*y) - M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin((M_PI*x)/2.)*std::sin(M_PI*y))/2.; + return sigma; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + sigma(0,0) = t*t*(M_PI*x*std::cos(M_PI*y)*std::sin(M_PI*x) + + 3*(M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y)); + + sigma(0,1) = t*t*(M_PI*x*std::cos(M_PI*y)*std::sin(M_PI*x) + + (M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y)); + + sigma(1,0) = sigma(0,1); + + sigma(1,1) = t*t*(3*M_PI*x*std::cos(M_PI*y)*std::sin(M_PI*x) + + (M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y)); + return sigma; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + sigma(0,0) = 2*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + 4*x*(1+x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + (2*x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) + - 2*x*x*(1 + x)*y*std::sin(std::sqrt(2.0)*M_PI*t))/2.0 + + (2*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + 4*x*(1 + x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t))/2.0; + + sigma(0,1) = x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) + - x*x*(1 + x)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + 2*x*(1 + x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + + sigma(1,0) = sigma(0,1); + + sigma(1,1) = 2*x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) + - 2*x*x*(1 + x)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + (2*x*x*(1 + x)*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) + - 2*x*x*(1 + x)*y*std::sin(std::sqrt(2.0)*M_PI*t))/2.0 + + (2*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + + 4*x*(1 + x)*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t))/2.0; + return sigma; + }; + } + break; + + case reproduction_elastic: + { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + sigma(0,0) = -2*M_PI*t*t*std::cos(M_PI*x)*std::cos(M_PI*y); + sigma(1,1) = 2*M_PI*t*t*std::cos(M_PI*x)*std::cos(M_PI*y); + return sigma; + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_matrix { + double x,y,w,theta; + x = pt.x(); + y = pt.y(); + + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + sigma(0,0) = - 3.0*M_PI*w*x*x*std::sin(M_PI*w*x/2.0)*std::sin(M_PI*w*y)*std::cos(theta*t)/2.0 + + M_PI*w*x*x*std::cos(theta*t)*std::cos(M_PI*w*x/2.0)*std::cos(M_PI*w*y) + + 6.0*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0); + + sigma(0,1) = - M_PI*w*x*x*std::sin(M_PI*w*x/2.0)*std::sin(M_PI*w*y)*std::cos(theta*t)/2.0 + + M_PI*w*x*x*std::cos(theta*t)*std::cos(M_PI*w*x/2.0)*std::cos(M_PI*w*y) + + 2.0*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0); + + sigma(1,0) = sigma(0,1); + + sigma(1,1) = - M_PI*w*x*x*std::sin(M_PI*w*x/2.0)*std::sin(M_PI*w*y)*std::cos(theta*t)/2.0 + + 3*M_PI*w*x*x*std::cos(theta*t)*std::cos(M_PI*w*x/2.0)*std::cos(M_PI*w*y) + + 2.0*x*std::sin(M_PI*w*y)*std::cos(theta*t)*std::cos(M_PI*w*x/2.0); + return sigma; + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) + -> disk::static_matrix { + disk::static_matrix sigma(2,2); + return sigma; + }; + } + break; + } + + } + + std::function::point_type& )> Evaluate_s_u(double & t) { + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return x*x*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return t*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return (1 - x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + }; + } + break; + + case EFunctionQuadraticInSpaceAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return y*(1-x*x)*(1-y)*std::sin(M_PI*t); + }; + } + break; + + case reproduction_acoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return t*t*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,w,theta; + x = pt.x(); + y = pt.y(); + + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + + return x*x*std::sin(theta*t)*std::sin(w*M_PI*x)*std::sin(w*M_PI*y); + }; + } + + case EFunctionQuarticInTimeAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return t*t*t*t*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionCubicInTimeAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return t*t*t*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + } + } + + std::function::point_type& )> Evaluate_s_v(double & t){ + + switch (m_function_type) { + + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return std::sqrt(2.0)*M_PI*x*x*std::cos(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return 2*t*x*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return std::sqrt(2.0)*M_PI*(1 - x)*x*x*(1 - y)*y*std::cos(std::sqrt(2.0)*M_PI*t); + }; + } + break; + + case EFunctionQuadraticInSpaceAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return M_PI*y*(1-x*x)*(1-y)*std::cos(M_PI*t); + }; + } + break; + + case reproduction_acoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + return 2.0*t*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + return theta*x*x*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)*std::cos(theta*t); + }; + } + break; + + case EFunctionQuarticInTimeAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return 4.0*t*t*t * std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionCubicInTimeAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return 3.0*t*t * std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + } + + } + + std::function::point_type& )> Evaluate_s_a(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return -2*M_PI*M_PI*x*x*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return 2*x*std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return -2*M_PI*M_PI*(1 - x)*x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + }; + } + break; + + case EFunctionQuadraticInSpaceAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return -M_PI*M_PI*y*(1-x*x)*(1-y)*std::sin(M_PI*t); + }; + } + break; + + case reproduction_acoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return 2.0*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + return -theta*theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y); + }; + } + break; + + case EFunctionQuarticInTimeAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return 12*t*t * std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + case EFunctionCubicInTimeAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y; + x = pt.x(); + y = pt.y(); + return 6*t * std::sin(M_PI*x)*std::sin(M_PI*y); + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + } + } + + std::function::point_type& )> Evaluate_s_f(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + f = -2*std::sin(std::sqrt(2.0)*M_PI*t)*(2*M_PI*x*std::cos(M_PI*x) + std::sin(M_PI*x))*std::sin(M_PI*y); + return f; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + f = 2*(-(M_PI*t*t*std::cos(M_PI*x)) + (1 + M_PI*M_PI*t*t)*x*std::sin(M_PI*x))*std::sin(M_PI*y); + return f; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + f = 2*((-1 + y)*y - 3*x*(-1 + y)*y + x*x*x*(-1 - M_PI*M_PI*(-1 + y)*y) + + x*x*(1 + M_PI*M_PI*(-1 + y)*y))*std::sin(std::sqrt(2.0)*M_PI*t); + return f; + }; + } + break; + + case EFunctionQuadraticInSpaceAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + f = - M_PI*M_PI*y*(1-x*x)*(1-y)*std::sin(M_PI*t) + + 2*y*(1-y)*std::sin(M_PI*t) + + 2*(1-x*x)*std::sin(M_PI*t); + return f; + }; + } + break; + + case reproduction_acoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + return 2.0*(1.0 + M_PI*M_PI*t*t)*std::sin(M_PI*pt.x())*std::sin(M_PI*pt.y()); + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + f = - theta*theta*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y) + + 2*M_PI*M_PI*theta*w*w*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)/theta + - 4*M_PI*theta*w*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos(M_PI*w*x)/theta + - 2*theta*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)/theta; + return f; + }; + } + break; + + case EFunctionQuarticInTimeAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + f = 2*M_PI*M_PI*t*t*t*t*std::sin(M_PI*x)*std::sin(M_PI*y) + 12*t*t*std::sin(M_PI*x)*std::sin(M_PI*y); + return f; + }; + } + break; + + case EFunctionCubicInTimeAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + f = 2*M_PI*M_PI*t*t*t*std::sin(M_PI*x)*std::sin(M_PI*y) + 6*t*std::sin(M_PI*x)*std::sin(M_PI*y); + return f; + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) -> double { + return 0; + }; + } + break; + } + } + + + std::function + (const typename disk::generic_mesh::point_type& )> Evaluate_s_q(double & t){ + + switch (m_function_type) { + case EFunctionNonPolynomial: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,qx,qy; + x = pt.x(); + y = pt.y(); + qx = M_PI*x*x*std::cos(M_PI*x)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*y) + 2*x*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x)*std::sin(M_PI*y); + qy = M_PI*x*x*std::cos(M_PI*y)*std::sin(std::sqrt(2.0)*M_PI*t)*std::sin(M_PI*x); + disk::static_vector q{qx,qy}; + return q; + }; + } + break; + + case EFunctionQuadraticInTime: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,qx,qy; + x = pt.x(); + y = pt.y(); + std::vector flux(2); + qx = M_PI*t*t*x*std::cos(M_PI*x)*std::sin(M_PI*y) + t*t*std::sin(M_PI*x)*std::sin(M_PI*y); + qy = M_PI*t*t*x*std::cos(M_PI*y)*std::sin(M_PI*x); + disk::static_vector q{qx,qy}; + return q; + }; + } + break; + + case EFunctionQuadraticInSpace: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,qx,qy; + x = pt.x(); + y = pt.y(); + std::vector flux(2); + qx = 2*(1 - x)*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t) + - x*x*(1 - y)*y*std::sin(std::sqrt(2.0)*M_PI*t); + qy = (1 - x)*x*x*(1 - y)*std::sin(std::sqrt(2.0)*M_PI*t) + - (1 - x)*x*x*y*std::sin(std::sqrt(2.0)*M_PI*t); + disk::static_vector q{qx,qy}; + return q; + }; + } + break; + + case EFunctionQuadraticInSpaceAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,qx,qy; + x = pt.x(); + y = pt.y(); + std::vector flux(2); + qx = -2*x*y*(1-y)*std::sin(M_PI*t); + qy = - y*(1-x*x)*std::sin(M_PI*t) + + (1-x*x)*(1-y)*std::sin(M_PI*t); + disk::static_vector q{qx,qy}; + return q; + }; + } + break; + + case reproduction_acoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { + double x,y,qx,qy; + x = pt.x(); + y = pt.y(); + qx = M_PI*t*t*t*std::cos(M_PI*x)*std::sin(M_PI*y); + qy = M_PI*t*t*t*std::sin(M_PI*x)*std::cos(M_PI*y); + disk::static_vector q{qx,qy}; + return q; + }; + } + break; + + case EFunctionNonPolynomial_paper: { + return [&t](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector { + double x,y,qx,qy,w,theta; + x = pt.x(); + y = pt.y(); + w = 1.0; + theta = 10*M_PI; + // w = 5.0; + // theta = std::sqrt(2)*M_PI; + qx = M_PI*theta*w*x*x*std::sin(theta*t)*std::sin(M_PI*w*y)*std::cos(M_PI*w*x)/theta + 2*theta*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::sin(M_PI*w*y)/theta; + qy = M_PI*theta*w*x*x*std::sin(theta*t)*std::sin(M_PI*w*x)*std::cos(M_PI*w*y)/theta; + disk::static_vector q{qx,qy}; + return q; + }; + } + break; + + case EFunctionQuarticInTimeAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { + double x,y,qx,qy; + x = pt.x(); + y = pt.y(); + qx = M_PI*t*t*t*t*std::cos(M_PI*x)*std::sin(M_PI*y); + qy = M_PI*t*t*t*t*std::sin(M_PI*x)*std::cos(M_PI*y); + disk::static_vector q{qx,qy}; + return q; + }; + } + break; + + case EFunctionCubicInTimeAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { + double x,y,qx,qy; + x = pt.x(); + y = pt.y(); + qx = M_PI*t*t*t*std::cos(M_PI*x)*std::sin(M_PI*y); + qy = M_PI*t*t*t*std::sin(M_PI*x)*std::cos(M_PI*y); + disk::static_vector q{qx,qy}; + return q; + }; + } + break; + + default: { + std::cout << " Function not implemented " << std::endl; + return [](const typename disk::generic_mesh::point_type& pt) + -> disk::static_vector{ + disk::static_vector f{0,0}; + return f; + }; + } + break; + } + } + + private: + + EFunctionType m_function_type; + + }; -}; - -#endif /* scal_vec_analytic_functions_hpp */ + #endif /* scal_vec_analytic_functions_hpp */ + \ No newline at end of file diff --git a/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_conv_test.hpp b/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_conv_test.hpp new file mode 100644 index 00000000..bb4afc68 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_conv_test.hpp @@ -0,0 +1,398 @@ + + +// Created by Romain Mottier + +// ../../elastoacoustic -k 1 -s 0 -r 0 -c 1 -p 1 -l 8 -n 1000 -f 0 -e 0 +void EAcousticFirstOrder(int argc, char **argv); + +void EAcousticFirstOrder(int argc, char **argv){ + + // ################################################## + // ################################################## Simulation paramaters + // ################################################## + + std::cout << std::endl << bold << red << " EXPLICIT ACOUSTIC CONV TEST" << reset << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, cpu; + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + cpu.tic(); + tc.tic(); + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + size_t l = sim_data.m_n_divs; + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + { // Simplicial meshes + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l0_conv_test_1.0.txt"); // l = 0 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l1_conv_test_0.35.txt"); // l = 1 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l2_conv_test_0.15.txt"); // l = 2 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l3_conv_test_0.07.txt"); // l = 3 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l4_conv_test_0.035.txt"); // l = 4 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l5_conv_test_0.026.txt"); // l = 5 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l6_conv_test_0.017.txt"); // l = 6 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l7_conv_test_0.0125.txt"); // l = 7 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l8_conv_test_0.0085.txt"); // l = 8 + // mesh_files.push_back("../../meshes/conv_test/simplices/unstructured/l9_conv_test_0.005.txt"); // l = 9 + } + { // Polyhedral meshes + mesh_files.push_back("../../meshes/conv_test/poly/poly_32.txt"); // -l 0 + mesh_files.push_back("../../meshes/conv_test/poly/poly_64.txt"); // -l 1 + mesh_files.push_back("../../meshes/conv_test/poly/poly_128.txt"); // -l 2 + mesh_files.push_back("../../meshes/conv_test/poly/poly_256.txt"); // -l 3 + mesh_files.push_back("../../meshes/conv_test/poly/poly_512.txt"); // -l 4 + mesh_files.push_back("../../meshes/conv_test/poly/poly_1024.txt"); // -l 5 + mesh_files.push_back("../../meshes/conv_test/poly/poly_2048.txt"); // -l 6 + mesh_files.push_back("../../meshes/conv_test/poly/poly_4096.txt"); // -l 7 + mesh_files.push_back("../../meshes/conv_test/poly/poly_8192.txt"); // -l 8 + mesh_files.push_back("../../meshes/conv_test/poly/poly_16384.txt"); // -l 9 + } + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) + h = h_l; + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl << std::endl; + + // ################################################## + // ################################################## Time controls + // ################################################## + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt = sim_data.m_nt_divs; + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ################################################## + // ################################################## Manufactured solution + // ################################################## + + scal_vec_analytic_functions functions; + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionCubicInTimeAcoustic); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuarticInTimeAcoustic); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpaceAcoustic); + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + // Acoustic analytical functions + auto s_u_fun = functions.Evaluate_s_u(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_a_fun = functions.Evaluate_s_a(t); + auto s_f_fun = functions.Evaluate_s_f(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ################################################## + // ################################################## HHO setting + // ################################################## + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ################################################## + // ################################################## Structure setting + // ################################################## + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + // for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + // const auto face = *face_it; + // mesh_type::point_type bar = barycenter(msh, face); + // auto fc_id = msh.lookup(face); + // bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + // if (is_member_Q) { + // if (bar.y() > 0) + // acoustic_internal_faces.insert(fc_id); + // else + // elastic_internal_faces.insert(fc_id); + // } + // } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, s_u_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_coupling_stabilization(); + if (sim_data.m_scaled_stabilization_Q) { + assembler.set_scaled_stabilization(); + } + + // DISCRTIZATION INFOS + std::cout << bold << red << " DISCRETIZATION: "; + std::cout << cyan << "Cell degree = " << hho_di.cell_degree() << std::endl; + std::cout << bold << cyan << " Face degree = " << hho_di.face_degree() << reset << std::endl << std::endl << std::endl; + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl << std::endl; + + // ################################################## + // ################################################## Projecting initial data + // ################################################## + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, null_fun, s_v_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // ERK schemes + int s = 3; + erk_butcher_tableau::erk_tables(s, a, b, c); + + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, s_f_fun, true); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes);//assembler.get_interfaces()); + + tc.toc(); + std::cout << bold << cyan << " ERK analysis created: " << tc << " seconds" << reset << std::endl; + tc.tic(); + erk_an.refresh_faces_unknowns(x_dof); + tc.toc(); + std::cout << bold << cyan << " Inverse of Sff + Coupling in: " << tc << " seconds" << reset << std::endl; + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + std::cout << std::endl << std::endl; + + size_t it = 0; + std::ostringstream filename_silo; + filename_silo << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename_silo.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + std::cout << bold << red << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + x_dof_n = x_dof; + + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + t = tn + c(i,0) * dt; + + { + // Manufactured solution + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_f_fun = functions.Evaluate_s_f(t); + + assembler.get_e_bc_conditions().updateDirichletFunction(null_fun, 0); + assembler.get_a_bc_conditions().updateDirichletFunction(s_v_fun, 0); + assembler.assemble_rhs(msh, null_fun, s_f_fun, true); + erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + } + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + + tc.toc(); + std::cout << bold << cyan << " ERK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + t = tn + dt; + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + if(it == nt){ + std::cout << std::endl; + postprocessor::compute_errors_four_fields_elastoacoustic(msh, hho_di, assembler, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun, simulation_log); + postprocessor::compute_errors_four_fields_elastoacoustic_energy_norm(msh, hho_di, assembler, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun, simulation_log); + } + + std::cout << std::endl; + + } + + bool mesh_quality = false; + if (mesh_quality) { + std::ofstream mesh_file("mesh_file.txt"); + postprocessor::mesh_quality(msh, assembler, mesh_file); + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + diff --git a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/EHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/EHHOFirstOrder.hpp index dbd0210b..b3b45a92 100644 --- a/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/EHHOFirstOrder.hpp +++ b/apps/wave_propagation/src/prototypes/acoustics_old/Prototypes/Acoustic_Conv_Test/EHHOFirstOrder.hpp @@ -43,7 +43,8 @@ void EHHOFirstOrder(char **argv){ mesh_builder.set_poly_mesh_file(mesh_files[l]); mesh_builder.build_mesh(); mesh_builder.move_to_mesh_storage(msh); - }else{ + } + else { RealType lx = 1.0; RealType ly = 1.0; size_t nx = 2; @@ -68,7 +69,7 @@ void EHHOFirstOrder(char **argv){ } RealType ti = 0.0; RealType tf = 1.0; - RealType dt = (tf-ti)/nt; + RealType dt = (tf-ti)/nt; scal_analytic_functions functions; switch (sim_data.m_exact_functions) { @@ -84,13 +85,13 @@ void EHHOFirstOrder(char **argv){ } RealType t = ti; - auto exact_vel_fun = functions.Evaluate_v(t); - auto exact_flux_fun = functions.Evaluate_q(t); - auto rhs_fun = functions.Evaluate_f(t); + auto exact_vel_fun = functions.Evaluate_v(t); + auto exact_flux_fun = functions.Evaluate_q(t); + auto rhs_fun = functions.Evaluate_f(t); // Creating HHO approximation spaces and corresponding linear operator size_t cell_k_degree = sim_data.m_k_degree; - if(sim_data.m_hdg_stabilization_Q){ + if(sim_data.m_hdg_stabilization_Q) { cell_k_degree++; } disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); @@ -101,10 +102,10 @@ void EHHOFirstOrder(char **argv){ tc.tic(); auto assembler = acoustic_two_fields_assembler(msh, hho_di, bnd); assembler.load_material_data(msh); - if(sim_data.m_hdg_stabilization_Q){ + if (sim_data.m_hdg_stabilization_Q) { assembler.set_hdg_stabilization(); } - if(sim_data.m_scaled_stabilization_Q){ + if (sim_data.m_scaled_stabilization_Q) { assembler.set_scaled_stabilization(); } tc.toc(); diff --git a/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder.hpp index 161f442f..a00f22fa 100644 --- a/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder.hpp +++ b/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder.hpp @@ -3,7 +3,6 @@ // Created by Romain Mottier void IHHOFirstOrder(int argc, char **argv); - void IHHOFirstOrder(int argc, char **argv){ // ################################################## @@ -92,8 +91,8 @@ void IHHOFirstOrder(int argc, char **argv){ size_t nt = 10; for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { - // nt *= 2; - nt = sim_data.m_nt_divs; + nt *= 2; + // nt = sim_data.m_nt_divs; } RealType ti = 0.0; @@ -131,7 +130,7 @@ void IHHOFirstOrder(int argc, char **argv){ // Creating HHO approximation spaces and corresponding linear operator size_t cell_k_degree = sim_data.m_k_degree; - if(sim_data.m_hdg_stabilization_Q){ + if (sim_data.m_hdg_stabilization_Q){ cell_k_degree++; } disk::hho_degree_info hho_di(cell_k_degree, sim_data.m_k_degree); @@ -174,7 +173,7 @@ void IHHOFirstOrder(int argc, char **argv){ std::map> interface_cell_pair_indexes; RealType eps = 1.0e-10; - for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++){ + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { const auto face = *face_it; mesh_type::point_type bar = barycenter(msh, face); auto fc_id = msh.lookup(face); @@ -306,7 +305,7 @@ void IHHOFirstOrder(int argc, char **argv){ std::cout << bold << cyan << " Matrix decomposed: "; tc.tic(); dirk_an.ComposeMatrix(); - bool iteratif_solver = true; // if false load library: source /opt/intel/oneapi/setvars.sh intel64 + bool iteratif_solver = false; // if false load library: source /opt/intel/oneapi/setvars.sh intel64 if (iteratif_solver) dirk_an.setIterativeSolver(); dirk_an.DecomposeMatrix(); @@ -347,6 +346,19 @@ void IHHOFirstOrder(int argc, char **argv){ std::cout << std::endl; + bool e_side_Q = true; + bool a_side_Q = false; + bool sensors = true; + std::ostringstream filename_acou; + filename_acou << "A_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str = filename_acou.str(); + std::ofstream Acoustic_sensor_1_log(filename_acou_str); + typename mesh_type::point_type Acoustic_s1_pt(0.5, 0.5); + std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); + if (sensors) { + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + } + // ################################################## // ################################################## Time marching // ################################################## @@ -417,7 +429,11 @@ void IHHOFirstOrder(int argc, char **argv){ postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); } - if(it == nt){ + if (sensors) { + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + } + + if (it == nt){ // Computing errors postprocessor::compute_errors_four_fields_elastoacoustic(msh, hho_di, assembler, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun, simulation_log); postprocessor::compute_errors_four_fields_elastoacoustic_energy_norm(msh, hho_di, assembler, x_dof, v_fun, flux_fun, s_v_fun, s_flux_fun, simulation_log); diff --git a/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesEHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesEHHOFirstOrder.hpp index 1033085f..6f09fca9 100644 --- a/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesEHHOFirstOrder.hpp +++ b/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesEHHOFirstOrder.hpp @@ -19,7 +19,8 @@ void ConicWavesEHHOFirstOrder(int argc, char **argv){ sim_data.print_simulation_data(); timecounter tc, tcit, cpu; cpu.tic(); - + DBSetDeprecateWarnings(0); + // ################################################## // ################################################## Mesh generation // ################################################## @@ -73,8 +74,8 @@ void ConicWavesEHHOFirstOrder(int argc, char **argv){ RealType ly = 5250.0; // size_t nx = 140; // size_t ny = 140; - size_t nx = 322; // k= 4 -> 224 - size_t ny = 322; + size_t nx = 322/2; // k= 4 -> 224 + size_t ny = 322/2; cartesian_2d_mesh_builder mesh_builder(lx, ly, nx, ny); mesh_builder.refine_mesh(sim_data.m_n_divs); // mesh_builder.set_translation_data(-2500.0, -2500.0); @@ -101,10 +102,7 @@ void ConicWavesEHHOFirstOrder(int argc, char **argv){ // ###################################################################### Time controls // ###################################################################### - size_t nt = 10; - for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) - nt = sim_data.m_nt_divs; - + size_t nt = sim_data.m_nt_divs; RealType ti = 0.0; RealType tf = 0.625; RealType dt = (tf-ti)/nt; @@ -465,7 +463,7 @@ void ConicWavesEHHOFirstOrder(int argc, char **argv){ if (sensors) { postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); - postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); } @@ -485,6 +483,3 @@ void ConicWavesEHHOFirstOrder(int argc, char **argv){ } - - - diff --git a/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp index bb08113f..baceec2c 100644 --- a/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp +++ b/apps/wave_propagation/src/prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp @@ -19,7 +19,8 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ sim_data.print_simulation_data(); timecounter tc, tcit, cpu; cpu.tic(); - + DBSetDeprecateWarnings(0); + // ################################################## // ################################################## Mesh generation // ################################################## @@ -73,8 +74,8 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ RealType ly = 5250.0; // size_t nx = 140; // size_t ny = 140; - size_t nx = 322; // k= 4 -> 224 - size_t ny = 322; + size_t nx = 322/4; //250;// 322; // k= 4 -> 224 + size_t ny = 322/4; //175;// 322; cartesian_2d_mesh_builder mesh_builder(lx, ly, nx, ny); mesh_builder.refine_mesh(sim_data.m_n_divs); // mesh_builder.set_translation_data(-2500.0, -2500.0); @@ -100,12 +101,14 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ // ###################################################################### Time controls // ###################################################################### - size_t nt = 10; - for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + size_t nt = sim_data.m_nt_divs; + nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { nt *= 2; + } RealType ti = 0.0; - RealType tf = 0.425; + RealType tf = 1.0; //0.625; // 0.425; RealType dt = (tf-ti)/nt; RealType t = ti; @@ -273,9 +276,9 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ x = pt.x(); y = pt.y(); xc = 0.0; - yc = 100.0; + yc = 100.0; // 100.0; fc = 10.0; - c = 10.0; + c = 1.0; vp = 1500.0; lp = vp/fc; r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); @@ -285,11 +288,29 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ disk::static_vector v{vx,vy}; return v; }; - + + // Acoustic pulse - Heterogeneous domain - Fluide = Eau + auto pulse_geophysic_p = [](const disk::mesh>::point_type& pt) -> double { + double x, y, xc, yc, r, wave, vp, lp, fc, c, vx, vy; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 200.0; // 100.0; + fc = 10.0; + c = 1.0; + vp = 1500.0; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + return wave; + }; + Matrix x_dof; // Acoustic pulse intialized in pressure - assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, pulse_geophysic_v); - assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + // assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, pulse_geophysic_v); + // assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, pulse_geophysic_p, null_fun); + assembler.project_over_faces(msh, x_dof, null_fun, pulse_geophysic_p); // ################################################## // ################################################## Solving a first order equation HDG/HHO propagation problem @@ -302,10 +323,12 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ // DIRK(s) schemes int s = 3; bool is_sdirk_Q = true; - if (is_sdirk_Q) + if (is_sdirk_Q) { dirk_butcher_tableau::sdirk_tables(s, a, b, c); - else + } + else { dirk_butcher_tableau::dirk_tables(s, a, b, c); + } std::cout << std::endl; std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; @@ -367,7 +390,6 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ if (sim_data.m_report_energy_Q) postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); - // ################################################## // ################################################## Sensors // ################################################## @@ -379,13 +401,13 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ filename_acou << "AP_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; std::string filename_acou_str = filename_acou.str(); std::ofstream Acoustic_sensor_1_log(filename_acou_str); - typename mesh_type::point_type Acoustic_s1_pt(-2300, 100); + typename mesh_type::point_type Acoustic_s1_pt(-2300.0, 100.0); std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); std::ostringstream filename_acou2; filename_acou2 << "AV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; std::string filename_acou_str2 = filename_acou2.str(); std::ofstream Acoustic_sensor_2_log(filename_acou_str2); - typename mesh_type::point_type Acoustic_s2_pt(-2300, 100); + typename mesh_type::point_type Acoustic_s2_pt(-2300.0, 100.0); std::pair Acoustic_s2_pt_cell = std::make_pair(Acoustic_s2_pt, -1); std::ostringstream filename_int; @@ -417,28 +439,28 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ filename_ela << "EV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; std::string filename_ela_str = filename_ela.str(); std::ofstream Elastic_sensor_1_log(filename_ela_str); - typename mesh_type::point_type Elastic_s1_pt(-2300, -200); + typename mesh_type::point_type Elastic_s1_pt(-2300.0, -200.0); std::pair Elastic_s1_pt_cell = std::make_pair(Elastic_s1_pt, -1); std::ostringstream filename_ela2; filename_ela2 << "ES_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; std::string filename_ela_str2 = filename_ela2.str(); std::ofstream Elastic_sensor_2_log(filename_ela_str2); - typename mesh_type::point_type Elastic_s2_pt(-2300, -200); + typename mesh_type::point_type Elastic_s2_pt(-2300.0, -200.0); std::pair Elastic_s2_pt_cell = std::make_pair(Elastic_s2_pt, -1); bool sensors = true; if (sensors) { // Acoustic sensor postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); - postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); // Interface sensor - postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_pressure); - postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_velocity); - postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_velocity); - postprocessor::record_elastic_data_elasto_acoustic_four_fields(0, Interface_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_stress); + // postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_pressure); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_velocity); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_velocity); + // postprocessor::record_elastic_data_elasto_acoustic_four_fields(0, Interface_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_stress); // Elastic sensor postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); - postprocessor::record_elastic_data_elasto_acoustic_four_fields(0, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + // postprocessor::record_elastic_data_elasto_acoustic_four_fields(0, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); } std::cout << std::endl; @@ -499,15 +521,15 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ if (sensors) { // Acoustic sensor postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); - postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); // Interface sensor - postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_pressure); - postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_velocity); - postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_velocity); - postprocessor::record_elastic_data_elasto_acoustic_four_fields(it, Interface_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_stress); + // postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_pressure); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_velocity); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_velocity); + // postprocessor::record_elastic_data_elasto_acoustic_four_fields(it, Interface_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_stress); // Elastic sensor postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); - postprocessor::record_elastic_data_elasto_acoustic_four_fields(it, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + // postprocessor::record_elastic_data_elasto_acoustic_four_fields(it, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); } if (sim_data.m_report_energy_Q) @@ -522,7 +544,7 @@ void ConicWavesIHHOFirstOrder(int argc, char **argv){ cpu.toc(); simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; - std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << reset << std::endl << std::endl; } diff --git a/apps/wave_propagation/src/prototypes/coupling/Pulse/review_CMAME.hpp b/apps/wave_propagation/src/prototypes/coupling/Pulse/review_CMAME.hpp new file mode 100644 index 00000000..fc223091 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/coupling/Pulse/review_CMAME.hpp @@ -0,0 +1,1007 @@ + + +// Created by Romain Mottier + +// source /opt/intel/oneapi/setvars.sh intel64 +// ../../../elastoacoustic -k 3 -s 1 -r 1 -c 1 -p 0 -l 0 -n 8 -f 1 -e 0 + +void ConicWavesIHHOFirstOrder_review(int argc, char **argv); +void ConicWavesIHHOFirstOrder_review(int argc, char **argv){ + + // ###################################################################### + // ###################################################################### Simulation paramaters + // ###################################################################### + + std::cout << std::endl << bold << red << " IMPLICIT PULSE - COUPLING - GEOPHYSIC" << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit, cpu; + cpu.tic(); + DBSetDeprecateWarnings(0); + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + RealType lx = 3800.0; + RealType ly = 2600.0; + size_t nx = 76; + size_t ny = 52; + cartesian_2d_mesh_builder mesh_builder(lx, ly, nx, ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1800.0, -1600.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) + h = h_l; + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = sim_data.m_nt_divs; + nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt *= 2; + } + + RealType ti = 0.0; + RealType tf = 0.5; //0.625; // 0.425; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + disk::hho_degree_info hho_di(cell_k_degree,sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + auto water_mat_fun = [](const typename disk::mesh>::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp; + rho = 1025.0; + vp = 1500.0; + acoustic_material_data material(rho,vp); + return material; + }; + + auto granit_mat_fun = [](const typename disk::mesh>::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp, vs; + rho = 2690.0; + vp = 6000.0; + vs = 3000.0; + elastic_material_data material(rho,vp,vs); + return material; + }; + + // ###################################################################### + // ###################################################################### Structure setting + // ###################################################################### + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.y()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + + // Assigning the material properties + if (bar.y() > 0) { + acoustic_material_data material = water_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = granit_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.y() > 0) + interface_cell_pair_indexes[fc_id].second = cell_ind; + else + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.y() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + // Boundary Condition + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if (sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + // ###################################################################### + // ###################################################################### Projecting initial data + // ###################################################################### + + // Acoustic pulse - Heterogeneous domain - Fluide = Eau + auto pulse_geophysic_v = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x, y, xc, yc, r, wave, vp, lp, fc, c, vx, vy; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 100.0; // 100.0; + fc = 10.0; + c = 1.0; + vp = 1500.0; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + // Acoustic pulse - Heterogeneous domain - Fluide = Eau + auto pulse_geophysic_p = [](const disk::mesh>::point_type& pt) -> double { + double x, y, xc, yc, r, wave, vp, lp, fc, c, vx, vy; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 200.0; // 100.0; + fc = 10.0; + c = 1.0; + vp = 1500.0; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + return wave; + }; + + Matrix x_dof; + // Acoustic pulse intialized in pressure + // assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, pulse_geophysic_v); + // assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, pulse_geophysic_p, null_fun); + assembler.project_over_faces(msh, x_dof, null_fun, pulse_geophysic_p); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // DIRK(s) schemes + int s = 3; + bool is_sdirk_Q = true; + if (is_sdirk_Q) { + dirk_butcher_tableau::sdirk_tables(s, a, b, c); + } + else { + dirk_butcher_tableau::dirk_tables(s, a, b, c); + } + + std::cout << std::endl; + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, true); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + dirk_hho_scheme dirk_an(assembler.LHS,assembler.RHS,assembler.MASS); + + if (sim_data.m_sc_Q) { + std::vector> vec_cell_basis_data(2); + vec_cell_basis_data[0] = std::make_pair(assembler.get_e_material_data().size(), assembler.get_e_cell_basis_data()); + vec_cell_basis_data[1] = std::make_pair(assembler.get_a_material_data().size(), assembler.get_a_cell_basis_data()); + dirk_an.set_static_condensation_data(vec_cell_basis_data, assembler.get_n_face_dof()); + } + + if (is_sdirk_Q) { + double scale = a(0,0) * dt; + dirk_an.SetScale(scale); + std::cout << bold << cyan << " Matrix decomposed: "; + tc.tic(); + dirk_an.ComposeMatrix(); + bool iteratif_solver = false; // if false load library: source /opt/intel/oneapi/setvars.sh intel64 + if (iteratif_solver) + dirk_an.setIterativeSolver(); + dirk_an.DecomposeMatrix(); + tc.toc(); + std::cout << tc << " seconds" << reset << std::endl; + } + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of SDIRK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations = " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + + size_t it = 0; + std::ostringstream filename_silo; + filename_silo << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename_silo.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + // ################################################## + // ################################################## Sensors + // ################################################## + + bool e_side_Q = true; + bool a_side_Q = false; + + std::ostringstream filename_acou; + filename_acou << "AP_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str = filename_acou.str(); + std::ofstream Acoustic_sensor_1_log(filename_acou_str); + typename mesh_type::point_type Acoustic_s1_pt(500.0, 200.0); + std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); + std::ostringstream filename_acou2; + filename_acou2 << "AV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str2 = filename_acou2.str(); + std::ofstream Acoustic_sensor_2_log(filename_acou_str2); + typename mesh_type::point_type Acoustic_s2_pt(500.0, 200.0); + std::pair Acoustic_s2_pt_cell = std::make_pair(Acoustic_s2_pt, -1); + + std::ostringstream filename_int; + filename_int << "IP_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_acoustic_pressure.csv"; + std::string filename_int_str = filename_int.str(); + std::ofstream Interface_sensor_acoustic_pressure(filename_int_str); + typename mesh_type::point_type Interface_s1_pt(-400.0, 0.0); + std::pair Interface_s1_pt_cell = std::make_pair(Interface_s1_pt, -1); + std::ostringstream filename_int2; + filename_int2 << "IAV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_acoustic_velocity.csv"; + std::string filename_int_str2 = filename_int2.str(); + std::ofstream Interface_sensor_acoustic_velocity(filename_int_str2); + typename mesh_type::point_type Interface_s2_pt(-400.0, 0.0); + std::pair Interface_s2_pt_cell = std::make_pair(Interface_s2_pt, -1); + std::ostringstream filename_int3; + filename_int3 << "IEV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_elastic_velocity.csv"; + std::string filename_int_str3 = filename_int3.str(); + std::ofstream Interface_sensor_elastic_velocity(filename_int_str3); + typename mesh_type::point_type Interface_s3_pt(-400.0, 0.0); + std::pair Interface_s3_pt_cell = std::make_pair(Interface_s3_pt, -1); + std::ostringstream filename_int4; + filename_int4 << "IS_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_elastic_stress.csv"; + std::string filename_int_str4 = filename_int4.str(); + std::ofstream Interface_sensor_elastic_stress(filename_int_str4); + typename mesh_type::point_type Interface_s4_pt(-400.0, 0.0); + std::pair Interface_s4_pt_cell = std::make_pair(Interface_s4_pt, -1); + + std::ostringstream filename_ela; + filename_ela << "EV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str = filename_ela.str(); + std::ofstream Elastic_sensor_1_log(filename_ela_str); + typename mesh_type::point_type Elastic_s1_pt(1000.0, -500.0); + std::pair Elastic_s1_pt_cell = std::make_pair(Elastic_s1_pt, -1); + std::ostringstream filename_ela2; + filename_ela2 << "ES_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str2 = filename_ela2.str(); + std::ofstream Elastic_sensor_2_log(filename_ela_str2); + typename mesh_type::point_type Elastic_s2_pt(-1000.0, -500.0); + std::pair Elastic_s2_pt_cell = std::make_pair(Elastic_s2_pt, -1); + + bool sensors = true; + if (sensors) { + // Acoustic sensor + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); + // Interface sensor + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_pressure); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_velocity); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_velocity); + // postprocessor::record_elastic_data_elasto_acoustic_four_fields(0, Interface_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_stress); + // Elastic sensor + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + // postprocessor::record_elastic_data_elasto_acoustic_four_fields(0, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + } + + std::cout << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // DIRK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c,xd; + xd = Matrix::Zero(n_dof, 1); + + RealType t; + Matrix yn, ki; + + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + t = tn + c(i,0) * dt; + assembler.RHS.setZero(); + dirk_an.SetFg(assembler.RHS); + dirk_an.irk_weight(yn, ki, dt, a(i,i),is_sdirk_Q); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << " SDIRK step completed: " << tc << " seconds" << reset << std::endl; + + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + int silo_mod = static_cast(std::round(nt / 50.0)); // Number of silo files + if ((it == 1 || it == std::round(nt/2) || it == nt) || (sim_data.m_render_silo_files_Q && (it%silo_mod == 0))) { + std::ostringstream filename; + filename << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + if (sensors) { + // Acoustic sensor + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); + // Interface sensor + // postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_pressure); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_velocity); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_velocity); + // postprocessor::record_elastic_data_elasto_acoustic_four_fields(it, Interface_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_stress); + // Elastic sensor + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + // postprocessor::record_elastic_data_elasto_acoustic_four_fields(it, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + } + + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + t += dt; + + tcit.toc(); + std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << reset << std::endl << std::endl; + +} + + + + +void ConicWavesEHHOFirstOrder_review(int argc, char **argv); +void ConicWavesEHHOFirstOrder_review(int argc, char **argv){ + + // ###################################################################### + // ###################################################################### Simulation paramaters + // ###################################################################### + + std::cout << std::endl << bold << red << " EXPLICIT PULSE - COUPLING - GEOPHYSIC" << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit, cpu; + cpu.tic(); + DBSetDeprecateWarnings(0); + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + RealType lx = 3800.0; + RealType ly = 2600.0; + size_t nx = 76; + size_t ny = 52; + cartesian_2d_mesh_builder mesh_builder(lx, ly, nx, ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1800.0, -1600.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) + h = h_l; + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = sim_data.m_nt_divs; + RealType ti = 0.0; + RealType tf = 0.5; //0.625; // 0.425; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if(sim_data.m_hdg_stabilization_Q) + cell_k_degree++; + disk::hho_degree_info hho_di(cell_k_degree, sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + auto water_mat_fun = [](const typename disk::mesh>::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp; + rho = 1025.0; + vp = 1500.0; + acoustic_material_data material(rho,vp); + return material; + }; + + auto granit_mat_fun = [](const typename disk::mesh>::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp, vs; + rho = 2690.0; + vp = 6000.0; + vs = 3000.0; + elastic_material_data material(rho,vp,vs); + return material; + }; + + // ###################################################################### + // ###################################################################### Structure setting + // ###################################################################### + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.y()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + + // Assigning the material properties + if (bar.y() > 0) { + acoustic_material_data material = water_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + elastic_material_data material = granit_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.y() > 0) { + interface_cell_pair_indexes[fc_id].second = cell_ind; + } + else { + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + } + + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + } + else { + if (bar.y() > 0) { + acoustic_internal_faces.insert(fc_id); + } + else { + elastic_internal_faces.insert(fc_id); + } + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.y() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + // Boundary Condition + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if (sim_data.m_scaled_stabilization_Q) + assembler.set_scaled_stabilization(); + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + // ###################################################################### + // ###################################################################### Projecting initial data + // ###################################################################### + + // Acoustic pulse - Heterogeneous domain - Fluide = Eau + auto pulse_geophysic_v = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x, y, xc, yc, r, wave, vp, lp, fc, c, vx, vy; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 100.0; // 100.0; + fc = 10.0; + c = 1.0; + vp = 1500.0; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + // Acoustic pulse - Heterogeneous domain - Fluide = Eau + auto pulse_geophysic_p = [](const disk::mesh>::point_type& pt) -> double { + double x, y, xc, yc, r, wave, vp, lp, fc, c, vx, vy; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 200.0; // 100.0; + fc = 10.0; + c = 1.0; + vp = 1500.0; + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + return wave; + }; + + Matrix x_dof; + // Acoustic pulse intialized in pressure + // assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, pulse_geophysic_v); + // assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, pulse_geophysic_p, null_fun); + assembler.project_over_faces(msh, x_dof, null_fun, pulse_geophysic_p); + + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // ERK(s) schemes + int s = 4; + erk_butcher_tableau::erk_tables(s, a, b, c); + std::cout << std::endl << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, true); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes);//assembler.get_interfaces()); + + tc.toc(); + std::cout << bold << cyan << " ERK analysis created: " << tc << " seconds" << reset << std::endl; + tc.tic(); + erk_an.refresh_faces_unknowns(x_dof); + tc.toc(); + std::cout << bold << cyan << " Inverse of Sff + Coupling in: " << tc << " seconds" << reset << std::endl; + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "Explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + + size_t it = 0; + std::ostringstream filename_silo; + filename_silo << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename_silo.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + + std::ostringstream filename_e; + filename_e << "energy_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_e_str = filename_e.str(); + std::ofstream energy_file(filename_e_str); + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + // ################################################## + // ################################################## Sensors + // ################################################## + + bool e_side_Q = true; + bool a_side_Q = false; + + std::ostringstream filename_acou; + filename_acou << "AP_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str = filename_acou.str(); + std::ofstream Acoustic_sensor_1_log(filename_acou_str); + typename mesh_type::point_type Acoustic_s1_pt(500.0, 200.0); + std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); + std::ostringstream filename_acou2; + filename_acou2 << "AV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str2 = filename_acou2.str(); + std::ofstream Acoustic_sensor_2_log(filename_acou_str2); + typename mesh_type::point_type Acoustic_s2_pt(500.0, 200.0); + std::pair Acoustic_s2_pt_cell = std::make_pair(Acoustic_s2_pt, -1); + + std::ostringstream filename_int; + filename_int << "IP_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_acoustic_pressure.csv"; + std::string filename_int_str = filename_int.str(); + std::ofstream Interface_sensor_acoustic_pressure(filename_int_str); + typename mesh_type::point_type Interface_s1_pt(-400.0, 0.0); + std::pair Interface_s1_pt_cell = std::make_pair(Interface_s1_pt, -1); + std::ostringstream filename_int2; + filename_int2 << "IAV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_acoustic_velocity.csv"; + std::string filename_int_str2 = filename_int2.str(); + std::ofstream Interface_sensor_acoustic_velocity(filename_int_str2); + typename mesh_type::point_type Interface_s2_pt(-400.0, 0.0); + std::pair Interface_s2_pt_cell = std::make_pair(Interface_s2_pt, -1); + std::ostringstream filename_int3; + filename_int3 << "IEV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_elastic_velocity.csv"; + std::string filename_int_str3 = filename_int3.str(); + std::ofstream Interface_sensor_elastic_velocity(filename_int_str3); + typename mesh_type::point_type Interface_s3_pt(-400.0, 0.0); + std::pair Interface_s3_pt_cell = std::make_pair(Interface_s3_pt, -1); + std::ostringstream filename_int4; + filename_int4 << "IS_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_elastic_stress.csv"; + std::string filename_int_str4 = filename_int4.str(); + std::ofstream Interface_sensor_elastic_stress(filename_int_str4); + typename mesh_type::point_type Interface_s4_pt(-400.0, 0.0); + std::pair Interface_s4_pt_cell = std::make_pair(Interface_s4_pt, -1); + + std::ostringstream filename_ela; + filename_ela << "EV_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str = filename_ela.str(); + std::ofstream Elastic_sensor_1_log(filename_ela_str); + typename mesh_type::point_type Elastic_s1_pt(1000.0, -500.0); + std::pair Elastic_s1_pt_cell = std::make_pair(Elastic_s1_pt, -1); + std::ostringstream filename_ela2; + filename_ela2 << "ES_implicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str2 = filename_ela2.str(); + std::ofstream Elastic_sensor_2_log(filename_ela_str2); + typename mesh_type::point_type Elastic_s2_pt(-1000.0, -500.0); + std::pair Elastic_s2_pt_cell = std::make_pair(Elastic_s2_pt, -1); + + bool sensors = true; + if (sensors) { + // Acoustic sensor + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); + // Interface sensor + // postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_pressure); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_velocity); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_velocity); + // postprocessor::record_elastic_data_elasto_acoustic_four_fields(0, Interface_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_stress); + // Elastic sensor + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + // postprocessor::record_elastic_data_elasto_acoustic_four_fields(0, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + } + + std::cout << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + x_dof_n = x_dof; + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + erk_an.erk_weight(yn, ki); + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + tc.toc(); + std::cout << bold << cyan << " ERK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + int silo_mod = static_cast(std::round(nt / 50.0)); // Number of silo files + if ((!sim_data.m_render_silo_files_Q && (it == 1 || it == std::round(nt/2) || it == nt)) || ((sim_data.m_render_silo_files_Q && (it%silo_mod == 0)) || it == nt)) { + std::ostringstream filename; + filename << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + if (sensors) { + // Acoustic sensor + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Acoustic_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_2_log); + // Interface sensor + // postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_pressure); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s3_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_velocity); + // postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s2_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Interface_sensor_acoustic_velocity); + // postprocessor::record_elastic_data_elasto_acoustic_four_fields(it, Interface_s4_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_elastic_stress); + // Elastic sensor + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + // postprocessor::record_elastic_data_elasto_acoustic_four_fields(it, Elastic_s2_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_2_log); + } + + if (sim_data.m_report_energy_Q) + postprocessor::compute_elasto_acoustic_energy_four_field(msh, hho_di, assembler, t, x_dof, energy_file); + + t += dt; + + tcit.toc(); + std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + diff --git a/apps/wave_propagation/src/wave_propagation.cpp b/apps/wave_propagation/src/wave_propagation.cpp index d18dc27a..3f9036f3 100644 --- a/apps/wave_propagation/src/wave_propagation.cpp +++ b/apps/wave_propagation/src/wave_propagation.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -57,6 +58,7 @@ using namespace Eigen; #include "prototypes/elastic/EElastic_stability.hpp" // Linear Elasticity #include "prototypes/coupling/EHHOFirstOrder_stability.hpp" // Elasto-Acoustic Coupling // Convergence test on sinusoidal analytical solution +#include "prototypes/acoustic/EAcoustic_conv_test.hpp" // Explicit Acoustic #include "prototypes/acoustic/IAcoustic_conv_test.hpp" // Implicit Acoustic #include "prototypes/elastic/IElastic_conv_test.hpp" // Implicit Elastic #include "prototypes/coupling/Conv_Tests/IHHOFirstOrder.hpp" // Implicit Coupling @@ -67,6 +69,7 @@ using namespace Eigen; #include "prototypes/coupling/Pulse/HeterogeneousIHHOFirstOrder.hpp" // Implicit Pulse (adimensional) #include "prototypes/coupling/Pulse/HeterogeneousEHHOFirstOrder.hpp" // Explicit Pulse (adimensional) #include "prototypes/coupling/Pulse/ConicWavesIHHOFirstOrder.hpp" // Implicit Pulse (geophysic) +#include "prototypes/coupling/Pulse/review_CMAME.hpp" // Implicit Pulse (geophysic) #include "prototypes/coupling/Pulse/ConicWavesEHHOFirstOrder.hpp" // Implicit Pulse (geophysic) // Sedimentary Basin #include "prototypes/coupling/Basin/BassinIHHOFirstOrder.hpp" // Implicit Sedimentary Basin @@ -75,7 +78,7 @@ using namespace Eigen; int main(int argc, char **argv){ DBSetDeprecateWarnings(0); - + // REGRESSION TESTS if (basename(argv[0]) == std::string("name1") ) { std::cout << "called with name1" << std::endl; @@ -98,6 +101,7 @@ int main(int argc, char **argv){ // EHHOFirstOrder_stability(argc, argv); // Convergence test: + // EAcousticFirstOrder(argc, argv); // IAcoustic_conv_test(argc, argv); // IElastic_conv_test(argc, argv); // IHHOFirstOrder(argc, argv); @@ -105,11 +109,13 @@ int main(int argc, char **argv){ // EHHOFirstOrder(argc, argv); // EHHOFirstOrder_conv_tests(argc, argv); -// Pulse: +// Pulse: // HeterogeneousIHHOFirstOrder(argc, argv); // HeterogeneousEHHOFirstOrder(argc, argv); - ConicWavesIHHOFirstOrder(argc, argv); + // ConicWavesIHHOFirstOrder(argc, argv); + // ConicWavesIHHOFirstOrder_review(argc, argv); // ConicWavesEHHOFirstOrder(argc, argv); + ConicWavesEHHOFirstOrder_review(argc, argv); // Sedimentary basin: // BassinIHHOFirstOrder(argc, argv); From 901d78a6c9f006cb18903254a0968531f6f66d66 Mon Sep 17 00:00:00 2001 From: Romain Mottier Date: Sat, 25 Oct 2025 11:46:13 +0200 Subject: [PATCH 12/12] WORK IN PROGRESS LTS --- .vscode/settings.json | 19 +- .../elastoacoustic_four_fields_assembler.hpp | 1070 ++++++++--------- .../src/common/erk_coupling_hho_scheme.hpp | 216 +++- .../src/common/erk_hho_scheme.hpp | 2 + .../src/common/preprocessor.hpp | 599 ++++----- .../common/scal_vec_analytic_functions.hpp | 80 +- .../prototypes/LTS/ELTSAcoustic_conv_test.hpp | 350 ++++++ .../src/prototypes/LTS/ERK4_LTS_conv_test.hpp | 386 ++++++ .../HeterogeneousERK4_LTS_HHO_FirstOrder.hpp | 565 +++++++++ .../src/prototypes/LTS/save.hpp | 343 ++++++ .../src/prototypes/acoustic/EAcoustic_CFL.hpp | 2 +- .../acoustic/EAcoustic_conv_test.hpp | 12 +- .../acoustic/IAcoustic_conv_test.hpp | 12 +- .../Conv_Tests/IHHOFirstOrder_conv_tests.hpp | 66 +- .../Pulse/HeterogeneousEHHOFirstOrder.hpp | 15 +- .../prototypes/elastic/EElastic_stability.hpp | 2 +- .../prototypes/elastic/EElasticity_CFL.hpp | 2 +- .../src/prototypes/postpro/conv_space_RK4.py | 79 ++ .../wave_propagation/src/wave_propagation.cpp | 23 +- conv_detected.png | Bin 0 -> 123499 bytes .../include/diskpp/bases/bases_scalar.hpp | 13 + .../boundary_conditions.hpp | 3 +- 22 files changed, 2780 insertions(+), 1079 deletions(-) create mode 100644 apps/wave_propagation/src/prototypes/LTS/ELTSAcoustic_conv_test.hpp create mode 100644 apps/wave_propagation/src/prototypes/LTS/ERK4_LTS_conv_test.hpp create mode 100644 apps/wave_propagation/src/prototypes/LTS/HeterogeneousERK4_LTS_HHO_FirstOrder.hpp create mode 100644 apps/wave_propagation/src/prototypes/LTS/save.hpp create mode 100755 apps/wave_propagation/src/prototypes/postpro/conv_space_RK4.py create mode 100644 conv_detected.png diff --git a/.vscode/settings.json b/.vscode/settings.json index 74239204..171628ac 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -64,6 +64,23 @@ "typeinfo": "cpp", "variant": "cpp", "format": "cpp", - "text_encoding": "cpp" + "text_encoding": "cpp", + "csignal": "cpp", + "strstream": "cpp", + "bitset": "cpp", + "cfenv": "cpp", + "chrono": "cpp", + "codecvt": "cpp", + "condition_variable": "cpp", + "forward_list": "cpp", + "regex": "cpp", + "source_location": "cpp", + "hash_map": "cpp", + "future": "cpp", + "mutex": "cpp", + "shared_mutex": "cpp", + "stdfloat": "cpp", + "typeindex": "cpp", + "valarray": "cpp" } } \ No newline at end of file diff --git a/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp b/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp index dfe30417..e397c8fd 100644 --- a/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp +++ b/apps/wave_propagation/src/common/elastoacoustic_four_fields_assembler.hpp @@ -22,8 +22,7 @@ #endif template -class elastoacoustic_four_fields_assembler -{ +class elastoacoustic_four_fields_assembler { typedef disk::BoundaryConditions e_boundary_type; typedef disk::BoundaryConditions a_boundary_type; @@ -71,21 +70,22 @@ class elastoacoustic_four_fields_assembler SparseMatrix LHS_STAB; Matrix RHS; SparseMatrix MASS; + SparseMatrix P; + SparseMatrix IminusP; SparseMatrix COUPLING; - elastoacoustic_four_fields_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const e_boundary_type& e_bnd, const a_boundary_type& a_bnd, std::map> & e_material, std::map> & a_material) - : m_hho_di(hho_di), m_e_bnd(e_bnd), m_a_bnd(a_bnd), m_e_material(e_material), m_a_material(a_material), m_hho_stabilization_Q(true), m_scaled_stabilization_Q(false) - { + + // Identification of Dirichlet faces; Construction of compressed face index maps; Computation of dofs counts; + // Initialization of global matrices and RHS; Setup of cell classification and local-to-global mapping structures. + elastoacoustic_four_fields_assembler(const Mesh& msh, const disk::hho_degree_info& hho_di, const e_boundary_type& e_bnd, const a_boundary_type& a_bnd, std::map> & e_material, std::map> & a_material) : m_hho_di(hho_di), m_e_bnd(e_bnd), m_a_bnd(a_bnd), m_e_material(e_material), m_a_material(a_material), m_hho_stabilization_Q(true), m_scaled_stabilization_Q(false) { auto storage = msh.backend_storage(); auto is_e_dirichlet = [&](const typename Mesh::face& fc) -> bool { - auto fc_id = msh.lookup(fc); return e_bnd.is_dirichlet_face(fc_id); }; auto is_a_dirichlet = [&](const typename Mesh::face& fc) -> bool { - auto fc_id = msh.lookup(fc); return a_bnd.is_dirichlet_face(fc_id); }; @@ -131,15 +131,15 @@ class elastoacoustic_four_fields_assembler size_t e_compressed_offset = 0; for (auto face_id : e_egdes) { - m_e_compress_indexes.at(face_id) = e_compressed_offset; - m_e_expand_indexes.at(e_compressed_offset) = face_id; - e_compressed_offset++; + m_e_compress_indexes.at(face_id) = e_compressed_offset; + m_e_expand_indexes.at(e_compressed_offset) = face_id; + e_compressed_offset++; } size_t a_compressed_offset = 0; for (auto face_id : a_egdes) { - m_a_compress_indexes.at(face_id) = a_compressed_offset; - m_a_expand_indexes.at(a_compressed_offset) = face_id; - a_compressed_offset++; + m_a_compress_indexes.at(face_id) = a_compressed_offset; + m_a_expand_indexes.at(a_compressed_offset) = face_id; + a_compressed_offset++; } size_t n_cbs = get_e_cell_basis_data(); @@ -160,57 +160,17 @@ class elastoacoustic_four_fields_assembler RHS = Matrix::Zero( system_size ); MASS = SparseMatrix( system_size, system_size ); COUPLING = SparseMatrix( system_size, system_size ); + P = SparseMatrix( system_size, system_size ); + IminusP = SparseMatrix( m_n_elastic_cell_dof + m_n_acoustic_cell_dof, m_n_elastic_cell_dof + m_n_acoustic_cell_dof ); + classify_cells(msh); build_cells_maps(); } - void scatter_e_data_stab(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, - const Matrix& lhs, - const Matrix& rhs) - { - auto fcs = faces(msh, cl); - size_t n_cbs = get_e_cell_basis_data(); - size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); - std::vector asm_map; - asm_map.reserve(n_cbs + n_fbs*fcs.size()); - - auto cell_LHS_offset = e_cell_ind * n_cbs; - - for (size_t i = 0; i < n_cbs; i++) - asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); - - for (size_t face_i = 0; face_i < fcs.size(); face_i++) - { - auto fc = fcs[face_i]; - auto fc_id = msh.lookup(fc); - auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; - bool dirichlet = m_e_bnd.is_dirichlet_face(fc_id); - - for (size_t i = 0; i < n_fbs; i++) - asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); - } - - assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); - - for (size_t i = 0; i < lhs.rows(); i++) - { - if (!asm_map[i].assemble()) - continue; - - for (size_t j = 0; j < lhs.cols(); j++) - { - if ( asm_map[j].assemble() ) - m_triplets_stab.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); - } - } - - } - + // Elastic cell– and face–dofs mapping; construction of assembly indices with Dirichlet filtering; Computation of global offsets for elastic unknowns; + // Insertion of local matrix entries into global triplets; Insertion of local RHS contributions into the global vector. + void scatter_e_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& lhs, const Matrix& rhs) { - void scatter_e_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, - const Matrix& lhs, - const Matrix& rhs) - { auto fcs = faces(msh, cl); size_t n_cbs = get_e_cell_basis_data(); size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); @@ -218,48 +178,44 @@ class elastoacoustic_four_fields_assembler asm_map.reserve(n_cbs + n_fbs*fcs.size()); auto cell_LHS_offset = e_cell_ind * n_cbs; - - for (size_t i = 0; i < n_cbs; i++) + for (size_t i = 0; i < n_cbs; i++) { asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + } - for (size_t face_i = 0; face_i < fcs.size(); face_i++) - { + for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; auto fc_id = msh.lookup(fc); auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; bool dirichlet = m_e_bnd.is_dirichlet_face(fc_id); - - for (size_t i = 0; i < n_fbs; i++) + for (size_t i = 0; i < n_fbs; i++) { asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); + } } assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); - - for (size_t i = 0; i < lhs.rows(); i++) - { - if (!asm_map[i].assemble()) + for (size_t i = 0; i < lhs.rows(); i++) { + if (!asm_map[i].assemble()) { continue; - - for (size_t j = 0; j < lhs.cols(); j++) - { - if ( asm_map[j].assemble() ) + } + for (size_t j = 0; j < lhs.cols(); j++) { + if ( asm_map[j].assemble() ) { m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + } } } - for (size_t i = 0; i < rhs.rows(); i++) - { - if (!asm_map[i].assemble()) + for (size_t i = 0; i < rhs.rows(); i++) { + if (!asm_map[i].assemble()) { continue; + } RHS(asm_map[i].vidx()) += rhs(i); } - } - void scatter_a_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, - const Matrix& lhs, - const Matrix& rhs) - { + // Acoustic cell– and face–dofs mapping; Construction of assembly indices with Dirichlet filtering; Computation of global offsets for acoustic unknowns; + // Insertion of local matrix entries into global triplets; Insertion of local RHS contributions into the global vector. + void scatter_a_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& lhs, const Matrix& rhs) { + auto fcs = faces(msh, cl); size_t n_cbs = get_a_cell_basis_data(); size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); @@ -267,179 +223,121 @@ class elastoacoustic_four_fields_assembler asm_map.reserve(n_cbs + n_fbs*fcs.size()); auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; - - for (size_t i = 0; i < n_cbs; i++) + for (size_t i = 0; i < n_cbs; i++) { asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + } - for (size_t face_i = 0; face_i < fcs.size(); face_i++) - { + for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; auto fc_id = msh.lookup(fc); auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; - bool dirichlet = m_a_bnd.is_dirichlet_face(fc_id); - - for (size_t i = 0; i < n_fbs; i++) + for (size_t i = 0; i < n_fbs; i++) { asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); - + } } assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); - - for (size_t i = 0; i < lhs.rows(); i++) - { - if (!asm_map[i].assemble()) + for (size_t i = 0; i < lhs.rows(); i++) { + if (!asm_map[i].assemble()) { continue; - - for (size_t j = 0; j < lhs.cols(); j++) - { - if ( asm_map[j].assemble() ) + } + for (size_t j = 0; j < lhs.cols(); j++) { + if (asm_map[j].assemble()) { m_triplets.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); + } } } - for (size_t i = 0; i < rhs.rows(); i++) - { - if (!asm_map[i].assemble()) + for (size_t i = 0; i < rhs.rows(); i++) { + if (!asm_map[i].assemble()) { continue; + } RHS(asm_map[i].vidx()) += rhs(i); } - - } - - void scatter_a_data_stab(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, - const Matrix& lhs, - const Matrix& rhs) - { - auto fcs = faces(msh, cl); - size_t n_cbs = get_a_cell_basis_data(); - size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); - std::vector asm_map; - asm_map.reserve(n_cbs + n_fbs*fcs.size()); - - auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; - - for (size_t i = 0; i < n_cbs; i++) - asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); - for (size_t face_i = 0; face_i < fcs.size(); face_i++) - { - auto fc = fcs[face_i]; - auto fc_id = msh.lookup(fc); - auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; - - bool dirichlet = m_a_bnd.is_dirichlet_face(fc_id); - - for (size_t i = 0; i < n_fbs; i++) - asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); - - } - - assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); - - for (size_t i = 0; i < lhs.rows(); i++) - { - if (!asm_map[i].assemble()) - continue; - - for (size_t j = 0; j < lhs.cols(); j++) - { - if ( asm_map[j].assemble() ) - m_triplets_stab.push_back( Triplet(asm_map[i], asm_map[j], lhs(i,j)) ); - } - } } - void scatter_e_mass_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, - const Matrix& mass_matrix) - { + // Elastic cell–DoF mapping; Construction of assembly indices; Computation of global offsets for elastic cell unknowns; + // Insertion of local mass-matrix entries into global mass triplets. + void scatter_e_mass_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& mass_matrix) { size_t n_cbs = get_e_cell_basis_data(); std::vector asm_map; - asm_map.reserve(n_cbs); - - auto cell_LHS_offset = e_cell_ind * n_cbs; - - for (size_t i = 0; i < n_cbs; i++) - asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + asm_map.reserve(n_cbs); + auto cell_LHS_offset = e_cell_ind * n_cbs; + for (size_t i = 0; i < n_cbs; i++) { + asm_map.push_back(assembly_index(cell_LHS_offset+i, true)); + } assert( asm_map.size() == mass_matrix.rows() && asm_map.size() == mass_matrix.cols() ); - - for (size_t i = 0; i < mass_matrix.rows(); i++) - { - if (!asm_map[i].assemble()) + for (size_t i = 0; i < mass_matrix.rows(); i++) { + if (!asm_map[i].assemble()) { continue; - - for (size_t j = 0; j < mass_matrix.cols(); j++) - { - if ( asm_map[j].assemble() ) + } + for (size_t j = 0; j < mass_matrix.cols(); j++) { + if (asm_map[j].assemble()) { m_mass_triplets.push_back( Triplet(asm_map[i], asm_map[j], mass_matrix(i,j)) ); + } } } - } - void scatter_a_mass_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, - const Matrix& mass_matrix) - { + // Acoustic cell–DoF mapping; Construction of assembly indices; Computation of global offsets for acoustic cell unknowns; + // Insertion of local mass-matrix entries into global mass triplets. + void scatter_a_mass_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& mass_matrix) { + size_t n_cbs = get_a_cell_basis_data(); std::vector asm_map; asm_map.reserve(n_cbs); - - auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; - - for (size_t i = 0; i < n_cbs; i++) - asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; + for (size_t i = 0; i < n_cbs; i++) { + asm_map.push_back(assembly_index(cell_LHS_offset+i, true)); + } assert( asm_map.size() == mass_matrix.rows() && asm_map.size() == mass_matrix.cols() ); - - for (size_t i = 0; i < mass_matrix.rows(); i++) - { - if (!asm_map[i].assemble()) + for (size_t i = 0; i < mass_matrix.rows(); i++) { + if (!asm_map[i].assemble()) { continue; - - for (size_t j = 0; j < mass_matrix.cols(); j++) - { - if ( asm_map[j].assemble() ) + } + for (size_t j = 0; j < mass_matrix.cols(); j++) { + if (asm_map[j].assemble()) { m_mass_triplets.push_back( Triplet(asm_map[i], asm_map[j], mass_matrix(i,j)) ); + } } } - } - - void scatter_ea_interface_data(const Mesh& msh, const typename Mesh::face_type& face, const Matrix& interface_matrix) { - - auto vfbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); - auto sfbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); - std::vector asm_map_e, asm_map_a; - asm_map_e.reserve(vfbs); - asm_map_a.reserve(sfbs); - auto fc_id = msh.lookup(face); + // Assembly of global mass matrix; local elastic and acoustic cell mass matrix computation; + // Scattering of elastic and acoustic mass contributions into global triplets; Finalization of mass assembly. + void assemble_mass(const Mesh& msh, bool add_vector_mass_Q = true) { - auto e_face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*vfbs; - bool e_dirichlet = m_e_bnd.is_dirichlet_face(fc_id); - for (size_t i = 0; i < vfbs; i++){ - asm_map_e.push_back( assembly_index(e_face_LHS_offset+i, !e_dirichlet) ); - } - - auto a_face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*sfbs; - bool a_dirichlet = m_a_bnd.is_dirichlet_face(fc_id); - for (size_t i = 0; i < sfbs; i++){ - asm_map_a.push_back( assembly_index(a_face_LHS_offset+i, !a_dirichlet) ); + auto storage = msh.backend_storage(); + MASS.setZero(); + + // elastic block + for (auto e_chunk : m_e_material) { + size_t e_cell_ind = m_e_cell_index[e_chunk.first]; + auto& cell = storage->surfaces[e_chunk.first]; + elastic_material_data material = e_chunk.second; + Matrix mass_matrix = e_mass_operator(material, msh, cell, add_vector_mass_Q); + scatter_e_mass_data(e_cell_ind,msh, cell, mass_matrix); } - assert( asm_map_e.size() == interface_matrix.rows() && asm_map_a.size() == interface_matrix.cols() ); - - for (size_t i = 0; i < interface_matrix.rows(); i++) { - for (size_t j = 0; j < interface_matrix.cols(); j++) { - m_c_triplets.push_back( Triplet(asm_map_e[i].vidx(), asm_map_a[j].vidx(), interface_matrix(i,j)) ); - m_c_triplets.push_back( Triplet(asm_map_a[j].vidx(), asm_map_e[i].vidx(), - interface_matrix(i,j)) ); - } + // acoustic block + for (auto a_chunk : m_a_material) { + size_t a_cell_ind = m_a_cell_index[a_chunk.first]; + auto& cell = storage->surfaces[a_chunk.first]; + acoustic_material_data material = a_chunk.second; + Matrix mass_matrix = a_mass_operator(material, msh, cell); + scatter_a_mass_data(a_cell_ind, msh, cell, mass_matrix); } - + + finalize_mass(); } - + + // Elastic cell–DoF mapping; Construction of assembly indices; Computation of global offsets for elastic cell unknowns; + // Insertion of local RHS contributions into the global vector. void scatter_e_rhs_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& rhs) { size_t n_cbs = get_e_cell_basis_data(); @@ -447,46 +345,44 @@ class elastoacoustic_four_fields_assembler asm_map.reserve(n_cbs); auto cell_LHS_offset = e_cell_ind * n_cbs; - - for (size_t i = 0; i < n_cbs; i++) + for (size_t i = 0; i < n_cbs; i++) { asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + } assert( asm_map.size() == rhs.rows() ); - for (size_t i = 0; i < rhs.rows(); i++) { - if (!asm_map[i].assemble()) + if (!asm_map[i].assemble()) { continue; + } RHS(asm_map[i].vidx()) += rhs(i); } - } - void scatter_a_rhs_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, - const Matrix& rhs) - { + // Acoustic cell–DoF mapping; Construction of assembly indices; Computation of global offsets for acoustic cell unknowns; + // Insertion of local RHS contributions into the global vector. + void scatter_a_rhs_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& rhs) { + size_t n_cbs = get_a_cell_basis_data(); std::vector asm_map; asm_map.reserve(n_cbs); auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; - - for (size_t i = 0; i < n_cbs; i++) + for (size_t i = 0; i < n_cbs; i++) { asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + } assert( asm_map.size() == rhs.rows()); - - for (size_t i = 0; i < rhs.rows(); i++) - { - if (!asm_map[i].assemble()) + for (size_t i = 0; i < rhs.rows(); i++) { + if (!asm_map[i].assemble()) { continue; + } RHS(asm_map[i].vidx()) += rhs(i); } - } - void scatter_e_bc_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, - const Matrix& lhs) - { + // Elastic Dirichlet face identification; Construction of assembly indices for cell and face DoFs; + // Computation of Dirichlet face contributions via local mass matrices; Insertion of bc into the global RHS using local-to-global mapping. + void scatter_e_bc_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& lhs) { auto fcs = faces(msh, cl); size_t n_cbs = get_e_cell_basis_data(); @@ -494,54 +390,46 @@ class elastoacoustic_four_fields_assembler std::vector asm_map; asm_map.reserve(n_cbs + n_fbs*fcs.size()); - auto cell_LHS_offset = e_cell_ind * n_cbs; - - for (size_t i = 0; i < n_cbs; i++) + auto cell_LHS_offset = e_cell_ind * n_cbs; + for (size_t i = 0; i < n_cbs; i++) { asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + } Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); - for (size_t face_i = 0; face_i < fcs.size(); face_i++) - { + for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; auto fc_id = msh.lookup(fc); auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; - bool dirichlet = m_e_bnd.is_dirichlet_face(fc_id); - - for (size_t i = 0; i < n_fbs; i++) - asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); - - if (dirichlet) - { + for (size_t i = 0; i < n_fbs; i++) { + asm_map.push_back(assembly_index(face_LHS_offset+i, !dirichlet) ); + } + if (dirichlet) { auto fb = make_vector_monomial_basis(msh, fc, m_hho_di.face_degree()); auto dirichlet_fun = m_e_bnd.dirichlet_boundary_func(fc_id); - Matrix mass = make_mass_matrix(msh, fc, fb); Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); } - } - assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); - - for (size_t i = 0; i < lhs.rows(); i++) - { - if (!asm_map[i].assemble()) + assert(asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); + for (size_t i = 0; i < lhs.rows(); i++) { + if (!asm_map[i].assemble()) { continue; - - for (size_t j = 0; j < lhs.cols(); j++) - { - if ( !asm_map[j].assemble() ) + } + for (size_t j = 0; j < lhs.cols(); j++) { + if (!asm_map[j].assemble() ) { RHS(asm_map[i].vidx()) -= lhs(i,j) * dirichlet_data(j); + } } } - } - void scatter_a_bc_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, - const Matrix& lhs) - { + // Acoustic Dirichlet face identification; construction of assembly indices for cell and face DoFs; + // Computation of Dirichlet face contributions via local mass matrices; Insertion of bc into the global RHS using local-to-global mapping. + void scatter_a_bc_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& lhs) { + auto fcs = faces(msh, cl); size_t n_cbs = get_a_cell_basis_data(); size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); @@ -549,58 +437,107 @@ class elastoacoustic_four_fields_assembler asm_map.reserve(n_cbs + n_fbs*fcs.size()); auto cell_LHS_offset = a_cell_ind * n_cbs + m_n_elastic_cell_dof; - - for (size_t i = 0; i < n_cbs; i++) + for (size_t i = 0; i < n_cbs; i++) { asm_map.push_back( assembly_index(cell_LHS_offset+i, true) ); + } Matrix dirichlet_data = Matrix::Zero(n_cbs + fcs.size()*n_fbs); - for (size_t face_i = 0; face_i < fcs.size(); face_i++) - { + for (size_t face_i = 0; face_i < fcs.size(); face_i++) { auto fc = fcs[face_i]; auto fc_id = msh.lookup(fc); - auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; - + auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; bool dirichlet = m_a_bnd.is_dirichlet_face(fc_id); - - for (size_t i = 0; i < n_fbs; i++) + for (size_t i = 0; i < n_fbs; i++) { asm_map.push_back( assembly_index(face_LHS_offset+i, !dirichlet) ); - - if (dirichlet) - { + } + if (dirichlet) { auto fb = make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); auto dirichlet_fun = m_a_bnd.dirichlet_boundary_func(fc_id); - Matrix mass = make_mass_matrix(msh, fc, fb); Matrix rhs = make_rhs(msh, fc, fb, dirichlet_fun); dirichlet_data.block(n_cbs + face_i*n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); } - } assert( asm_map.size() == lhs.rows() && asm_map.size() == lhs.cols() ); - - for (size_t i = 0; i < lhs.rows(); i++) - { - if (!asm_map[i].assemble()) + for (size_t i = 0; i < lhs.rows(); i++) { + if (!asm_map[i].assemble()) { continue; - - for (size_t j = 0; j < lhs.cols(); j++) - { - if ( !asm_map[j].assemble() ) + } + for (size_t j = 0; j < lhs.cols(); j++) { + if (!asm_map[j].assemble()) { RHS(asm_map[i].vidx()) -= lhs(i,j) * dirichlet_data(j); - + } } } + } + + // Application of boundary conditions; local elastic and acoustic cell operator computation for cells with boundary faces; + // Scattering of Dirichlet contributions into the global RHS; + void apply_bc(const Mesh& msh, bool explicit_scheme){ + + #ifdef HAVE_INTEL_TBB2 + size_t n_cells = m_elements_with_bc_eges.size(); + tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), + [this,&msh] (size_t & i){ + size_t cell_ind = m_elements_with_bc_eges[i]; + auto& cell = msh.backend_storage()->surfaces[cell_ind]; + Matrix laplacian_operator_loc = laplacian_operator(cell_ind, msh, cell); + scatter_bc_data(msh, cell, laplacian_operator_loc); + } + ); + #else + auto storage = msh.backend_storage(); + for (auto& cell_ind : m_e_elements_with_bc_eges) { + auto& cell = storage->surfaces[cell_ind]; + size_t e_cell_ind = m_e_cell_index[cell_ind]; + elastic_material_data e_mat = m_e_material.find(cell_ind)->second; + Matrix mixed_operator_loc = e_mixed_operator(e_mat,msh,cell,explicit_scheme); + scatter_e_bc_data(e_cell_ind, msh, cell, mixed_operator_loc); + } + + for (auto& cell_ind : m_a_elements_with_bc_eges) { + auto& cell = storage->surfaces[cell_ind]; + size_t a_cell_ind = m_a_cell_index[cell_ind]; + acoustic_material_data a_mat = m_a_material.find(cell_ind)->second; + Matrix mixed_operator_loc = a_mixed_operator(a_mat, msh, cell, explicit_scheme); + scatter_a_bc_data(a_cell_ind, msh, cell, mixed_operator_loc); + } + + #endif + + } + // Assembly of global RHS vector; Local elastic and acoustic cell RHS computation; + // Scattering of local RHS contributions into the global vector; Application of boundary condition corrections. + void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun, bool explicit_scheme) { + + RHS.setZero(); + auto storage = msh.backend_storage(); + for (auto e_chunk : m_e_material) { + size_t e_cell_ind = m_e_cell_index[e_chunk.first]; + auto& cell = storage->surfaces[e_chunk.first]; + Matrix f_loc = e_mixed_rhs(msh, cell, e_rhs_fun); + scatter_e_rhs_data(e_cell_ind, msh, cell, f_loc); + } + + for (auto a_chunk : m_a_material) { + size_t a_cell_ind = m_a_cell_index[a_chunk.first]; + auto& cell = storage->surfaces[a_chunk.first]; + Matrix f_loc = a_mixed_rhs(msh, cell, a_rhs_fun); + scatter_a_rhs_data(a_cell_ind, msh, cell, f_loc); + } + apply_bc(msh, explicit_scheme); } - void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun, bool explicit_scheme){ + // Assembly of acoustic and elastic part separately; + void assemble(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun, bool explicit_scheme) { auto storage = msh.backend_storage(); LHS.setZero(); RHS.setZero(); - // elastic block + // Elastic block for (auto e_chunk : m_e_material) { size_t e_cell_ind = m_e_cell_index[e_chunk.first]; auto& cell = storage->surfaces[e_chunk.first]; @@ -609,7 +546,7 @@ class elastoacoustic_four_fields_assembler scatter_e_data(e_cell_ind, msh, cell, mixed_operator_loc, f_loc); } - // acoustic block + // Acoustic block for (auto a_chunk : m_a_material) { size_t a_cell_ind = m_a_cell_index[a_chunk.first]; auto& cell = storage->surfaces[a_chunk.first]; @@ -617,14 +554,51 @@ class elastoacoustic_four_fields_assembler Matrix f_loc = a_mixed_rhs(msh, cell, a_rhs_fun); scatter_a_data(a_cell_ind, msh, cell, mixed_operator_loc, f_loc); } + finalize(); + } + // Elasto–acoustic interface face identification; Construction of Interface matrix. + void scatter_ea_interface_data(const Mesh& msh, const typename Mesh::face_type& face, const Matrix& interface_matrix) { + + auto vfbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); + auto sfbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); + + std::vector asm_map_e, asm_map_a; + asm_map_e.reserve(vfbs); + asm_map_a.reserve(sfbs); + auto fc_id = msh.lookup(face); + + auto e_face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*vfbs; + bool e_dirichlet = m_e_bnd.is_dirichlet_face(fc_id); + for (size_t i = 0; i < vfbs; i++){ + asm_map_e.push_back( assembly_index(e_face_LHS_offset+i, !e_dirichlet) ); + } + + auto a_face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*sfbs; + bool a_dirichlet = m_a_bnd.is_dirichlet_face(fc_id); + for (size_t i = 0; i < sfbs; i++){ + asm_map_a.push_back( assembly_index(a_face_LHS_offset+i, !a_dirichlet) ); + } + + assert( asm_map_e.size() == interface_matrix.rows() && asm_map_a.size() == interface_matrix.cols() ); + for (size_t i = 0; i < interface_matrix.rows(); i++) { + for (size_t j = 0; j < interface_matrix.cols(); j++) { + m_c_triplets.push_back( Triplet(asm_map_e[i].vidx(), asm_map_a[j].vidx(), interface_matrix(i,j)) ); + m_c_triplets.push_back( Triplet(asm_map_a[j].vidx(), asm_map_e[i].vidx(), - interface_matrix(i,j)) ); + } + } + } + + // Assembly of global coupling matrix; Local elasto–acoustic interface operator computation for each interface face; + // Scattering of interface contributions into global coupling triplets; finalization of coupling assembly. void assemble_coupling_terms(const Mesh& msh){ auto storage = msh.backend_storage(); COUPLING.setZero(); + // coupling blocks for (auto chunk : m_interface_cell_indexes) { auto& face = storage->edges[chunk.first]; @@ -633,105 +607,12 @@ class elastoacoustic_four_fields_assembler Matrix interface_operator_loc = e_interface_operator(msh, face, e_cell, a_cell); scatter_ea_interface_data(msh, face, interface_operator_loc); } - finalize_coupling(); - } - void assemble_mass(const Mesh& msh, bool add_vector_mass_Q = true){ - - auto storage = msh.backend_storage(); - MASS.setZero(); - - // elastic block - for (auto e_chunk : m_e_material) { - size_t e_cell_ind = m_e_cell_index[e_chunk.first]; - auto& cell = storage->surfaces[e_chunk.first]; - elastic_material_data material = e_chunk.second; - Matrix mass_matrix = e_mass_operator(material, msh, cell, add_vector_mass_Q); - scatter_e_mass_data(e_cell_ind,msh, cell, mass_matrix); - } - - // acoustic block - for (auto a_chunk : m_a_material) { - size_t a_cell_ind = m_a_cell_index[a_chunk.first]; - auto& cell = storage->surfaces[a_chunk.first]; - acoustic_material_data material = a_chunk.second; - Matrix mass_matrix = a_mass_operator(material, msh, cell); - scatter_a_mass_data(a_cell_ind, msh, cell, mass_matrix); - } - - finalize_mass(); - } - - void assemble_rhs(const Mesh& msh, std::function(const typename Mesh::point_type& )> e_rhs_fun, std::function a_rhs_fun, bool explicit_scheme){ - - RHS.setZero(); - #ifdef HAVE_INTEL_TBB2 - size_t n_cells = msh.cells_size(); - tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), - [this,&msh,&rhs_fun] (size_t & cell_ind){ - auto& cell = msh.backend_storage()->surfaces[cell_ind]; - auto cell_basis = make_vector_monomial_basis(msh, cell, m_hho_di.cell_degree()); - Matrix f_loc = make_rhs(msh, cell, cell_basis, rhs_fun); - this->scatter_rhs_data(msh, cell, f_loc); - } - ); - #else - auto storage = msh.backend_storage(); - for (auto e_chunk : m_e_material) { - size_t e_cell_ind = m_e_cell_index[e_chunk.first]; - auto& cell = storage->surfaces[e_chunk.first]; - Matrix f_loc = e_mixed_rhs(msh, cell, e_rhs_fun); - scatter_e_rhs_data(e_cell_ind, msh, cell, f_loc); - } - - for (auto a_chunk : m_a_material) { - size_t a_cell_ind = m_a_cell_index[a_chunk.first]; - auto& cell = storage->surfaces[a_chunk.first]; - Matrix f_loc = a_mixed_rhs(msh, cell, a_rhs_fun); - scatter_a_rhs_data(a_cell_ind, msh, cell, f_loc); - } - - #endif - apply_bc(msh, explicit_scheme); - } - - void apply_bc(const Mesh& msh, bool explicit_scheme){ - - #ifdef HAVE_INTEL_TBB2 - size_t n_cells = m_elements_with_bc_eges.size(); - tbb::parallel_for(size_t(0), size_t(n_cells), size_t(1), - [this,&msh] (size_t & i){ - size_t cell_ind = m_elements_with_bc_eges[i]; - auto& cell = msh.backend_storage()->surfaces[cell_ind]; - Matrix laplacian_operator_loc = laplacian_operator(cell_ind, msh, cell); - scatter_bc_data(msh, cell, laplacian_operator_loc); - } - ); - #else - auto storage = msh.backend_storage(); - for (auto& cell_ind : m_e_elements_with_bc_eges) - { - auto& cell = storage->surfaces[cell_ind]; - size_t e_cell_ind = m_e_cell_index[cell_ind]; - elastic_material_data e_mat = m_e_material.find(cell_ind)->second; - Matrix mixed_operator_loc = e_mixed_operator(e_mat,msh,cell,explicit_scheme); - scatter_e_bc_data(e_cell_ind, msh, cell, mixed_operator_loc); - } - - for (auto& cell_ind : m_a_elements_with_bc_eges) - { - auto& cell = storage->surfaces[cell_ind]; - size_t a_cell_ind = m_a_cell_index[cell_ind]; - acoustic_material_data a_mat = m_a_material.find(cell_ind)->second; - Matrix mixed_operator_loc = a_mixed_operator(a_mat, msh, cell, explicit_scheme); - scatter_a_bc_data(a_cell_ind, msh, cell, mixed_operator_loc); - } - - #endif - + finalize_coupling(); } - Matrix e_mixed_operator(elastic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell, bool explicit_scheme){ + // Computation of local elastic mixed operator; Strain reconstruction & Stabilization operator; + Matrix e_mixed_operator(elastic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell, bool explicit_scheme) { T rho = material.rho(); T vp = material.vp(); @@ -767,7 +648,7 @@ class elastoacoustic_four_fields_assembler } } - // // COEF SPECTRAL RADIUS + // COEF SPECTRAL RADIUS T equal_order_eta = 1.50; T mixed_order_eta = 0.95; @@ -777,6 +658,7 @@ class elastoacoustic_four_fields_assembler return R_operator + eta*(rho*vs)*S_operator; } + // Computation of local symmetric tensor mass matrix; Matrix symmetric_tensor_mass_matrix(const Mesh& msh, const typename Mesh::cell_type& cell) { @@ -787,32 +669,30 @@ class elastoacoustic_four_fields_assembler Matrix mass_matrix = Matrix::Zero(ten_bs, ten_bs); auto qps = integrate(msh, cell, 2 * gradeg); - // number of tensor components size_t dec = 0; - if (dim == 3) + if (dim == 3) { dec = 6; - else if (dim == 2) + } + else if (dim == 2) { dec = 3; - else + } + else { std::logic_error("Expected 3 >= dim > 1"); + } - for (auto& qp : qps) - { + for (auto& qp : qps) { auto phi = ten_b.eval_functions(qp.point()); - - for (size_t j = 0; j < ten_bs; j++) - { - + for (size_t j = 0; j < ten_bs; j++) { auto qp_phi_j = disk::priv::inner_product(qp.weight(), phi[j]); - for (size_t i = j; i < ten_bs; i += dec){ - mass_matrix(i, j) += disk::priv::inner_product(phi[i], qp_phi_j); + for (size_t i = j; i < ten_bs; i += dec) { + mass_matrix(i, j) += disk::priv::inner_product(phi[i], qp_phi_j); } } } - for (size_t j = 0; j < ten_bs; j++){ - for (size_t i = 0; i < j; i++){ + for (size_t j = 0; j < ten_bs; j++) { + for (size_t i = 0; i < j; i++) { mass_matrix(i, j) = mass_matrix(j, i); } } @@ -820,9 +700,10 @@ class elastoacoustic_four_fields_assembler return mass_matrix; } + // Computation of local symmetric tensor trace mass matrix; Matrix symmetric_tensor_trace_mass_matrix(const Mesh& msh, const typename Mesh::cell_type& cell) { - + size_t dim = Mesh::dimension; auto gradeg = m_hho_di.grad_degree(); auto ten_b = make_sym_matrix_monomial_basis(msh, cell, gradeg); @@ -830,41 +711,42 @@ class elastoacoustic_four_fields_assembler Matrix mass_matrix = Matrix::Zero(ten_bs, ten_bs); auto qps = integrate(msh, cell, 2 * gradeg); - // number of tensor components size_t dec = 0; - if (dim == 3) - dec = 6; - else if (dim == 2) - dec = 3; - else - std::logic_error("Expected 3 >= dim > 1"); - - for (auto& qp : qps) { - - auto phi = ten_b.eval_functions(qp.point()); - - for (size_t j = 0; j < ten_bs; j++) { + if (dim == 3) { + dec = 6; + } + else if (dim == 2) { + dec = 3; + } + else { + std::logic_error("Expected 3 >= dim > 1"); + } + + for (auto& qp : qps) { + auto phi = ten_b.eval_functions(qp.point()); + for (size_t j = 0; j < ten_bs; j++) { auto identity = phi[j]; identity.setZero(); - for(size_t d = 0; d < dim; d++) + for(size_t d = 0; d < dim; d++) { identity(d,d) = 1.0; - + } auto trace = phi[j].trace(); auto trace_phi_j = disk::priv::inner_product(phi[j].trace(), identity); auto qp_phi_j = disk::priv::inner_product(qp.weight(), trace_phi_j); - for (size_t i = 0; i < ten_bs; i ++) + for (size_t i = 0; i < ten_bs; i ++) { mass_matrix(i, j) += disk::priv::inner_product(phi[i], qp_phi_j); - - } - } + } + } + } return mass_matrix; } + // Computation of local elastic RHS vector; Matrix - e_mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> & rhs_fun, size_t di = 0) - { + e_mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> & rhs_fun, size_t di = 0) { + auto recdeg = m_hho_di.grad_degree(); auto celdeg = m_hho_di.cell_degree(); auto facdeg = m_hho_di.face_degree(); @@ -872,25 +754,25 @@ class elastoacoustic_four_fields_assembler auto ten_bs = disk::sym_matrix_basis_size(recdeg, Mesh::dimension, Mesh::dimension); auto vec_bs = disk::vector_basis_size(celdeg, Mesh::dimension, Mesh::dimension); size_t n_cbs = ten_bs + vec_bs; - auto cell_basis = make_vector_monomial_basis(msh, cell, celdeg); + auto cell_basis = make_vector_monomial_basis(msh, cell, celdeg); using T = typename Mesh::coordinate_type; Matrix ret_loc = Matrix::Zero(cell_basis.size()); Matrix ret = Matrix::Zero(n_cbs); const auto qps = integrate(msh, cell, 2 * (celdeg + di)); - - for (auto& qp : qps) - { + for (auto& qp : qps) { const auto phi = cell_basis.eval_functions(qp.point()); const auto qp_f = disk::priv::inner_product(qp.weight(), rhs_fun(qp.point())); ret_loc += disk::priv::outer_product(phi, qp_f); } ret.block(ten_bs,0,vec_bs,1) = ret_loc; return ret; + } - Matrix e_mass_operator(elastic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell, bool add_vector_mass_Q = true){ + // Computation of local elastic mass operator; + Matrix e_mass_operator(elastic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell, bool add_vector_mass_Q = true) { size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); @@ -905,10 +787,8 @@ class elastoacoustic_four_fields_assembler Matrix mass_matrix = Matrix::Zero(n_cbs, n_cbs); // Symmetric stress tensor mass block - // Stress tensor Matrix mass_matrix_sigma = symmetric_tensor_mass_matrix(msh, cell); - // Tensor trace Matrix mass_matrix_trace_sigma = symmetric_tensor_trace_mass_matrix(msh, cell); @@ -929,12 +809,12 @@ class elastoacoustic_four_fields_assembler return mass_matrix; } + // Computation of local acoustic mass operator; Matrix a_mass_operator(acoustic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell, bool add_scalar_mass_Q = true){ size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); size_t n_vec_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; size_t n_cbs = n_scal_cbs + n_vec_cbs; - Matrix mass_matrix = Matrix::Zero(n_cbs, n_cbs); auto recdeg = m_hho_di.reconstruction_degree(); @@ -957,11 +837,11 @@ class elastoacoustic_four_fields_assembler return mass_matrix; } - std::pair< Matrix, - Matrix > + // Computation of local strain tensor reconstruction; + std::pair, Matrix> strain_tensor_reconstruction(const Mesh& msh, const typename Mesh::cell_type& cell) { - using T = typename Mesh::coordinate_type; + using T = typename Mesh::coordinate_type; typedef Matrix matrix_type; const size_t N = Mesh::dimension; @@ -983,14 +863,16 @@ class elastoacoustic_four_fields_assembler matrix_type gr_rhs = matrix_type::Zero(ten_bs, vec_bs + num_faces * fbs); const auto qps = integrate(msh, cell, 2 * graddeg); - size_t dec = 0; - if (N == 3) + if (N == 3) { dec = 6; - else if (N == 2) + } + else if (N == 2) { dec = 3; - else + } + else { std::logic_error("Expected 3 >= dim > 1"); + } for (auto& qp : qps) { const auto gphi = ten_b.eval_functions(qp.point()); @@ -1002,10 +884,12 @@ class elastoacoustic_four_fields_assembler } } - for (size_t j = 0; j < ten_bs; j++) - for (size_t i = 0; i < j; i++) + for (size_t j = 0; j < ten_bs; j++) { + for (size_t i = 0; i < j; i++) { gr_lhs(i, j) = gr_lhs(j, i); - + } + } + if (celdeg > 0) { const auto qpc = integrate(msh, cell, graddeg + celdeg - 1); for (auto& qp : qpc) { @@ -1044,6 +928,7 @@ class elastoacoustic_four_fields_assembler return std::make_pair(oper, data_mixed); } + // Computation of local acoustic mixed operator; Gradient reconstruction & Stabilization operator; Matrix a_mixed_operator(acoustic_material_data & material, const Mesh& msh, const typename Mesh::cell_type& cell, bool explicit_scheme){ auto reconstruction_operator = mixed_scalar_reconstruction(msh, cell); @@ -1052,7 +937,7 @@ class elastoacoustic_four_fields_assembler auto n_cols = R_operator.cols(); Matrix S_operator = Matrix::Zero(n_rows, n_cols); - if(explicit_scheme) { + if (explicit_scheme) { auto stabilization_operator = make_scalar_hdg_stabilization(msh, cell, m_hho_di, false, m_scaled_stabilization_Q); auto n_s_rows = stabilization_operator.rows(); auto n_s_cols = stabilization_operator.cols(); @@ -1087,10 +972,10 @@ class elastoacoustic_four_fields_assembler return R_operator + (eta/(vp*rho))*S_operator; } - std::pair< Matrix, - Matrix > - mixed_scalar_reconstruction(const Mesh& msh, const typename Mesh::cell_type& cell) - { + // Computation of local scalar (acoustic) mixed reconstruction; + std::pair, Matrix> + mixed_scalar_reconstruction(const Mesh& msh, const typename Mesh::cell_type& cell) { + using T = typename Mesh::coordinate_type; typedef Matrix matrix_type; typedef Matrix vector_type; @@ -1117,15 +1002,14 @@ class elastoacoustic_four_fields_assembler gr_rhs.block(0, 0, rbs-1, cbs) = stiff.block(1, 0, rbs-1, cbs); const auto fcs = faces(msh, cell); - for (size_t i = 0; i < fcs.size(); i++) - { + for (size_t i = 0; i < fcs.size(); i++) { + const auto fc = fcs[i]; const auto n = normal(msh, cell, fc); auto fb = make_scalar_monomial_basis(msh, fc, facdeg); auto qps_f = integrate(msh, fc, recdeg - 1 + std::max(facdeg,celdeg)); - for (auto& qp : qps_f) - { + for (auto& qp : qps_f) { vector_type c_phi_tmp = cb.eval_functions(qp.point()); vector_type c_phi = c_phi_tmp.head(cbs); Matrix c_dphi_tmp = cb.eval_gradients(qp.point()); @@ -1149,9 +1033,10 @@ class elastoacoustic_four_fields_assembler return std::make_pair(oper, data_mixed); } + // Computation of local acoustic RHS vector; Matrix - a_mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function & rhs_fun, size_t di = 0) - { + a_mixed_rhs(const Mesh& msh, const typename Mesh::cell_type& cell, std::function & rhs_fun, size_t di = 0) { + const auto recdeg = m_hho_di.reconstruction_degree(); const auto celdeg = m_hho_di.cell_degree(); const auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension) - 1; @@ -1163,9 +1048,7 @@ class elastoacoustic_four_fields_assembler Matrix ret = Matrix::Zero(cbs); const auto qps = integrate(msh, cell, 2 * (celdeg + di)); - - for (auto& qp : qps) - { + for (auto& qp : qps) { const auto phi = cell_basis.eval_functions(qp.point()); const auto qp_f = disk::priv::inner_product(qp.weight(), rhs_fun(qp.point())); ret_loc += disk::priv::outer_product(phi, qp_f); @@ -1174,7 +1057,8 @@ class elastoacoustic_four_fields_assembler return ret; } - Matrix e_interface_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell){ + // Computation of local elasto–acoustic interface operator; Quadrature over the face to integrate normal component of elastic basis with acoustic basis; + Matrix e_interface_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell) { Matrix interface_operator; auto facdeg = m_hho_di.face_degree(); @@ -1188,19 +1072,20 @@ class elastoacoustic_four_fields_assembler const auto qps = integrate(msh, face, facdeg); const auto n = disk::normal(msh, e_cell, face); for (auto& qp : qps) { - const auto v_f_phi = vfb.eval_functions(qp.point()); - const auto s_f_phi = sfb.eval_functions(qp.point()); - assert(v_f_phi.rows() == vfbs); - assert(s_f_phi.rows() == sfbs); - auto q_n = disk::priv::inner_product(qp.weight(), n); - const auto n_dot_v_f_phi = disk::priv::inner_product(v_f_phi,q_n); - const auto result = (-1.0*disk::priv::outer_product(n_dot_v_f_phi, s_f_phi)).eval(); - interface_operator += result; + const auto v_f_phi = vfb.eval_functions(qp.point()); + const auto s_f_phi = sfb.eval_functions(qp.point()); + assert(v_f_phi.rows() == vfbs); + assert(s_f_phi.rows() == sfbs); + auto q_n = disk::priv::inner_product(qp.weight(), n); + const auto n_dot_v_f_phi = disk::priv::inner_product(v_f_phi,q_n); + const auto result = (-1.0*disk::priv::outer_product(n_dot_v_f_phi, s_f_phi)).eval(); + interface_operator += result; } return interface_operator; } - Matrix e_neumman_bc_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell, std::function a_vel_fun){ + // Computation of local Neumann boundary operator for elastic cell; + Matrix e_neumman_bc_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell, std::function a_vel_fun) { Matrix neumann_operator; auto facdeg = m_hho_di.face_degree(); @@ -1212,21 +1097,21 @@ class elastoacoustic_four_fields_assembler auto sfb = make_scalar_monomial_basis(msh, face, facdeg); const auto qps = integrate(msh, face, facdeg); const auto n = disk::normal(msh, e_cell, face); - for (auto& qp : qps) - { + for (auto& qp : qps) { const auto v_f_phi = vfb.eval_functions(qp.point()); const auto s_f_phi = sfb.eval_functions(qp.point()); - assert(v_f_phi.rows() == vfbs); const auto n_dot_v_f_phi = disk::priv::inner_product(v_f_phi,disk::priv::inner_product(qp.weight(), n)); const auto result = disk::priv::outer_product(n_dot_v_f_phi, a_vel_fun(qp.point())); neumann_operator += result; - } + return neumann_operator; - } + + } - Matrix a_neumman_bc_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell, std::function(const typename Mesh::point_type& )> e_vel_fun){ + // Computation of local Neumann boundary operator for acoustic cell; + Matrix a_neumman_bc_operator(const Mesh& msh, const typename Mesh::face_type& face, const typename Mesh::cell_type& e_cell, const typename Mesh::cell_type& a_cell, std::function(const typename Mesh::point_type& )> e_vel_fun) { Matrix neumann_operator; auto facdeg = m_hho_di.face_degree(); @@ -1238,33 +1123,32 @@ class elastoacoustic_four_fields_assembler auto sfb = make_scalar_monomial_basis(msh, face, facdeg); const auto qps = integrate(msh, face, facdeg); const auto n = disk::normal(msh, a_cell, face); - for (auto& qp : qps) - { + for (auto& qp : qps) { const auto v_f_phi = vfb.eval_functions(qp.point()); const auto s_f_phi = sfb.eval_functions(qp.point()); - assert(s_f_phi.rows() == sfbs); const auto n_dot_v_f = disk::priv::inner_product(e_vel_fun(qp.point()),disk::priv::inner_product(qp.weight(), n)); const auto result = disk::priv::inner_product(n_dot_v_f, s_f_phi); neumann_operator += result; } + return neumann_operator; + } - void classify_cells(const Mesh& msh){ + // Classification of mesh cells by boundary conditions; Identification of cells with at least one Dirichlet face; + // Only for conv tests + void classify_cells(const Mesh& msh) { m_e_elements_with_bc_eges.clear(); - for (auto& cell : msh) - { + for (auto& cell : msh) { auto cell_ind = msh.lookup(cell); auto face_list = faces(msh, cell); - for (size_t face_i = 0; face_i < face_list.size(); face_i++) - { + for (size_t face_i = 0; face_i < face_list.size(); face_i++) { auto fc = face_list[face_i]; auto fc_id = msh.lookup(fc); bool is_dirichlet_Q = m_e_bnd.is_dirichlet_face(fc_id); - if (is_dirichlet_Q) - { + if (is_dirichlet_Q) { m_e_elements_with_bc_eges.push_back(cell_ind); break; } @@ -1272,22 +1156,18 @@ class elastoacoustic_four_fields_assembler } m_a_elements_with_bc_eges.clear(); - for (auto& cell : msh) - { + for (auto& cell : msh) { typename Mesh::point_type bar = barycenter(msh, cell); if (bar.x() < 0) { continue; } - auto cell_ind = msh.lookup(cell); auto face_list = faces(msh, cell); - for (size_t face_i = 0; face_i < face_list.size(); face_i++) - { + for (size_t face_i = 0; face_i < face_list.size(); face_i++) { auto fc = face_list[face_i]; auto fc_id = msh.lookup(fc); bool is_dirichlet_Q = m_a_bnd.is_dirichlet_face(fc_id); - if (is_dirichlet_Q) - { + if (is_dirichlet_Q) { m_a_elements_with_bc_eges.push_back(cell_ind); break; } @@ -1295,7 +1175,8 @@ class elastoacoustic_four_fields_assembler } } - void build_cells_maps(){ + // Construction of cell-to-index maps; + void build_cells_maps() { // elastic data size_t e_cell_ind = 0; @@ -1315,14 +1196,14 @@ class elastoacoustic_four_fields_assembler } - void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> v_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::function v_s_fun, std::function(const typename Mesh::point_type& )> flux_s_fun){ + // Function projection onto cell dofs + void project_over_cells(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> v_fun, std::function(const typename Mesh::point_type& )> flux_fun, std::function v_s_fun, std::function(const typename Mesh::point_type& )> flux_s_fun) { auto storage = msh.backend_storage(); size_t n_dof = MASS.rows(); x_glob = Matrix::Zero(n_dof); // elastic block - size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); size_t n_e_cbs = n_ten_cbs + n_vec_cbs; @@ -1330,10 +1211,8 @@ class elastoacoustic_four_fields_assembler for (auto e_chunk : m_e_material) { size_t e_cell_ind = m_e_cell_index[e_chunk.first]; auto& cell = storage->surfaces[e_chunk.first]; - Matrix x_proj_ten_dof = project_ten_function(msh, cell, flux_fun); Matrix x_proj_vec_dof = project_function(msh, cell, m_hho_di.cell_degree(), v_fun); - Matrix x_proj_dof = Matrix::Zero(n_e_cbs); x_proj_dof.block(0, 0, n_ten_cbs, 1) = x_proj_ten_dof; x_proj_dof.block(n_ten_cbs, 0, n_vec_cbs, 1) = x_proj_vec_dof; @@ -1347,21 +1226,18 @@ class elastoacoustic_four_fields_assembler for (auto a_chunk : m_a_material) { size_t a_cell_ind = m_a_cell_index[a_chunk.first]; auto& cell = storage->surfaces[a_chunk.first]; - Matrix x_proj_vec_dof = project_vec_function(msh, cell, flux_s_fun); Matrix x_proj_sca_dof = project_function(msh, cell, m_hho_di.cell_degree(), v_s_fun); - Matrix x_proj_dof = Matrix::Zero(n_a_cbs); x_proj_dof.block(0, 0, n_v_s_cbs, 1) = x_proj_vec_dof; x_proj_dof.block(n_v_s_cbs, 0, n_scal_cbs, 1) = x_proj_sca_dof; - scatter_a_cell_dof_data(a_cell_ind, msh, cell, x_glob, x_proj_dof); } } - Matrix project_vec_function(const Mesh& msh, const typename Mesh::cell_type& cell, - std::function(const typename Mesh::point_type& )> vec_fun){ + // Vector function projection onto cell dofs. + Matrix project_vec_function(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> vec_fun) { auto recdeg = m_hho_di.reconstruction_degree(); auto rec_basis = make_scalar_monomial_basis(msh, cell, recdeg); @@ -1386,10 +1262,10 @@ class elastoacoustic_four_fields_assembler return x_dof; } - Matrix project_ten_function(const Mesh& msh, const typename Mesh::cell_type& cell, - std::function(const typename Mesh::point_type& )> ten_fun){ + // Symmetric tensor function projection onto cell dofs. + Matrix project_ten_function(const Mesh& msh, const typename Mesh::cell_type& cell, std::function(const typename Mesh::point_type& )> ten_fun) { - Matrix mass_matrix = symmetric_tensor_mass_matrix(msh, cell); + Matrix mass_matrix = symmetric_tensor_mass_matrix(msh, cell); size_t dim = Mesh::dimension; auto gradeg = m_hho_di.grad_degree(); auto ten_bs = disk::sym_matrix_basis_size(gradeg, dim, dim); @@ -1397,8 +1273,7 @@ class elastoacoustic_four_fields_assembler Matrix rhs = Matrix::Zero(ten_bs); const auto qps = integrate(msh, cell, 2 * gradeg); - for (auto& qp : qps) - { + for (auto& qp : qps) { auto phi = ten_b.eval_functions(qp.point()); disk::static_matrix sigma = ten_fun(qp.point()); for (size_t i = 0; i < ten_bs; i++){ @@ -1410,26 +1285,24 @@ class elastoacoustic_four_fields_assembler return x_dof; } + // Elastic cell dofs update with projected values. void - scatter_e_cell_dof_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell, - Matrix& x_glob, Matrix x_proj_dof) const - { + scatter_e_cell_dof_data(size_t e_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell, Matrix& x_glob, Matrix x_proj_dof) const { size_t n_cbs = get_e_cell_basis_data(); auto cell_ofs = e_cell_ind * n_cbs; x_glob.block(cell_ofs, 0, n_cbs, 1) = x_proj_dof; } + // Acoustic cell dofs update with projected values. void - scatter_a_cell_dof_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell, - Matrix& x_glob, Matrix x_proj_dof) const - { + scatter_a_cell_dof_data(size_t a_cell_ind, const Mesh& msh, const typename Mesh::cell_type& cell, Matrix& x_glob, Matrix x_proj_dof) const { size_t n_cbs = get_a_cell_basis_data(); auto cell_ofs = a_cell_ind * n_cbs + m_n_elastic_cell_dof; x_glob.block(cell_ofs, 0, n_cbs, 1) = x_proj_dof; } - - void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function scal_fun){ + // Function projection onto face dofs + void project_over_faces(const Mesh& msh, Matrix & x_glob, std::function(const typename Mesh::point_type& )> vec_fun, std::function scal_fun) { auto storage = msh.backend_storage(); @@ -1437,13 +1310,11 @@ class elastoacoustic_four_fields_assembler for (auto e_chunk : m_e_material) { auto& cell = storage->surfaces[e_chunk.first]; auto fcs = faces(msh, cell); - for (size_t i = 0; i < fcs.size(); i++) - { + for (size_t i = 0; i < fcs.size(); i++) { auto face = fcs[i]; auto fc_id = msh.lookup(face); bool is_dirichlet_Q = m_e_bnd.is_dirichlet_face(fc_id); - if (is_dirichlet_Q) - { + if (is_dirichlet_Q) { continue; } Matrix x_proj_dof = project_function(msh, face, m_hho_di.face_degree(), vec_fun); @@ -1455,13 +1326,11 @@ class elastoacoustic_four_fields_assembler for (auto a_chunk : m_a_material) { auto& cell = storage->surfaces[a_chunk.first]; auto fcs = faces(msh, cell); - for (size_t i = 0; i < fcs.size(); i++) - { + for (size_t i = 0; i < fcs.size(); i++) { auto face = fcs[i]; auto fc_id = msh.lookup(face); bool is_dirichlet_Q = m_a_bnd.is_dirichlet_face(fc_id); - if (is_dirichlet_Q) - { + if (is_dirichlet_Q) { continue; } Matrix x_proj_dof = project_function(msh, face, m_hho_di.face_degree(), scal_fun); @@ -1470,29 +1339,24 @@ class elastoacoustic_four_fields_assembler } } - void - scatter_e_face_dof_data( const Mesh& msh, const typename Mesh::face_type& face, - Matrix& x_glob, Matrix x_proj_dof) const - { + // Updating elastic face dofs projection + void scatter_e_face_dof_data(const Mesh& msh, const typename Mesh::face_type& face, Matrix& x_glob, Matrix x_proj_dof) const { size_t n_fbs = disk::vector_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1, Mesh::dimension); auto fc_id = msh.lookup(face); auto glob_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_e_compress_indexes.at(fc_id)*n_fbs; x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; } - void - scatter_a_face_dof_data( const Mesh& msh, const typename Mesh::face_type& face, - Matrix& x_glob, Matrix x_proj_dof) const - { + // Updating acoustic face dofs projection + void scatter_a_face_dof_data( const Mesh& msh, const typename Mesh::face_type& face, Matrix& x_glob, Matrix x_proj_dof) const { size_t n_fbs = disk::scalar_basis_size(m_hho_di.face_degree(), Mesh::dimension - 1); auto fc_id = msh.lookup(face); auto glob_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; x_glob.block(glob_offset, 0, n_fbs, 1) = x_proj_dof; - } - Matrix - gather_e_dof_data(size_t cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& x_glob) const { + // Gathering of elastic cell and face DoFs. + Matrix gather_e_dof_data(size_t cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& x_glob) const { auto e_cell_ind = m_e_cell_index.find(cell_ind)->second; auto num_faces = howmany_faces(msh, cl); @@ -1505,7 +1369,9 @@ class elastoacoustic_four_fields_assembler for (size_t i = 0; i < fcs.size(); i++) { auto fc = fcs[i]; auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); - if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); + if (!eid.first) { + throw std::invalid_argument("This is a bug: face not found"); + } const auto face_id = eid.second; if (m_e_bnd.is_dirichlet_face( face_id)) { @@ -1524,10 +1390,10 @@ class elastoacoustic_four_fields_assembler return x_el; } + // Gathering of acoustic cell and face DoFs. Matrix - gather_a_dof_data(size_t cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, - const Matrix& x_glob) const - { + gather_a_dof_data(size_t cell_ind, const Mesh& msh, const typename Mesh::cell_type& cl, const Matrix& x_glob) const { + auto a_cell_ind = m_a_cell_index.find(cell_ind)->second; auto num_faces = howmany_faces(msh, cl); size_t n_cbs = get_a_cell_basis_data(); @@ -1536,23 +1402,21 @@ class elastoacoustic_four_fields_assembler Matrix x_local(n_cbs + num_faces * n_fbs ); x_local.block(0, 0, n_cbs, 1) = x_glob.block(a_cell_ind * n_cbs + m_n_elastic_cell_dof, 0, n_cbs, 1); auto fcs = faces(msh, cl); - for (size_t i = 0; i < fcs.size(); i++) - { + for (size_t i = 0; i < fcs.size(); i++) { auto fc = fcs[i]; auto eid = find_element_id(msh.faces_begin(), msh.faces_end(), fc); - if (!eid.first) throw std::invalid_argument("This is a bug: face not found"); - const auto face_id = eid.second; - - if (m_a_bnd.is_dirichlet_face( face_id)) - { + if (!eid.first) { + throw std::invalid_argument("This is a bug: face not found"); + } + const auto face_id = eid.second; + if (m_a_bnd.is_dirichlet_face( face_id)) { auto fb = disk::make_scalar_monomial_basis(msh, fc, m_hho_di.face_degree()); Matrix mass = make_mass_matrix(msh, fc, fb, m_hho_di.face_degree()); auto velocity = m_a_bnd.dirichlet_boundary_func(face_id); Matrix rhs = make_rhs(msh, fc, fb, velocity, m_hho_di.face_degree()); x_local.block(n_cbs + i * n_fbs, 0, n_fbs, 1) = mass.llt().solve(rhs); } - else - { + else { auto fc_id = msh.lookup(fc); auto face_LHS_offset = m_n_elastic_cell_dof + m_n_acoustic_cell_dof + m_n_elastic_face_dof + m_a_compress_indexes.at(fc_id)*n_fbs; x_local.block(n_cbs + i*n_fbs, 0, n_fbs, 1) = x_glob.block(face_LHS_offset, 0, n_fbs, 1); @@ -1560,67 +1424,152 @@ class elastoacoustic_four_fields_assembler } return x_local; } + + // Projection matrix assembly for LTS + void assemble_P(const Mesh& msh, T h_c) { + + auto storage = msh.backend_storage(); + P.setZero(); + IminusP.setZero(); + + const T hc = std::round(h_c * T(1000)) / T(1000); + + const size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); + const size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(), Mesh::dimension, Mesh::dimension); + const size_t n_v_s_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension) - 1; + const size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + + size_t elastic_tensor_offset = 0; + size_t elastic_vector_offset = n_ten_cbs * m_e_material.size(); + size_t acoustic_vector_offset = elastic_vector_offset + n_vec_cbs * m_e_material.size(); + size_t acoustic_scalar_offset = acoustic_vector_offset + n_v_s_cbs * m_a_material.size(); + + std::vector< Triplet > P_triplets; + std::vector< Triplet > IP_triplets; + P_triplets.reserve(m_n_elastic_cell_dof + m_n_acoustic_cell_dof); + IP_triplets.reserve(m_n_elastic_cell_dof + m_n_acoustic_cell_dof); + + // Elastic cells + for (auto &chunk : m_e_material) { + size_t cell_id = chunk.first; + size_t e_idx = m_e_cell_index[cell_id]; + auto &cell = storage->surfaces[cell_id]; + + T h = std::round(diameter(msh, cell) * T(1000)) / T(1000); + T val = (h < hc) ? T(1) : T(0); - void finalize() - { + if (val != T(0)) { + size_t ten_offset = elastic_tensor_offset + e_idx * n_ten_cbs; + size_t vec_offset = elastic_vector_offset + e_idx * n_vec_cbs; + for (size_t i = 0; i < n_ten_cbs; ++i) { + P_triplets.emplace_back(ten_offset+i, ten_offset+i, val); + IP_triplets.emplace_back(ten_offset+i, ten_offset+i, T(1)-val); + } + for (size_t i = 0; i < n_vec_cbs; ++i) { + P_triplets.emplace_back(vec_offset+i, vec_offset+i, val); + IP_triplets.emplace_back(vec_offset+i, vec_offset+i, T(1)-val); + } + } + } + + // Acoustic cells + for (auto &chunk : m_a_material) { + size_t cell_id = chunk.first; + size_t a_idx = m_a_cell_index[cell_id]; + auto &cell = storage->surfaces[cell_id]; + + T h = std::round(diameter(msh, cell) * T(1000)) / T(1000); + T val = (h < hc) ? T(1) : T(0); + + if (val != T(0)) { + size_t vec_offset = acoustic_vector_offset + a_idx * n_v_s_cbs; + size_t scal_offset = acoustic_scalar_offset + a_idx * n_scal_cbs; + for (size_t i = 0; i < n_v_s_cbs; ++i) { + P_triplets.emplace_back(vec_offset+i, vec_offset+i, val); + IP_triplets.emplace_back(vec_offset+i, vec_offset+i, T(1)-val); + } + for (size_t i = 0; i < n_scal_cbs; ++i) { + P_triplets.emplace_back(scal_offset+i, scal_offset+i, val); + IP_triplets.emplace_back(scal_offset+i, scal_offset+i, T(1)-val); + } + } + } + + P.setFromTriplets(P_triplets.begin(), P_triplets.end()); + IminusP.setFromTriplets(IP_triplets.begin(), IP_triplets.end()); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////// Sparse matrices triplet assembly finalization ////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void finalize() { LHS.setFromTriplets( m_triplets.begin(), m_triplets.end() ); m_triplets.clear(); LHS_STAB.setFromTriplets( m_triplets_stab.begin(), m_triplets_stab.end() ); m_triplets_stab.clear(); } - void finalize_mass() - { + void finalize_mass() { MASS.setFromTriplets( m_mass_triplets.begin(), m_mass_triplets.end() ); m_mass_triplets.clear(); } - void finalize_coupling() - { + void finalize_coupling() { COUPLING.setFromTriplets( m_c_triplets.begin(), m_c_triplets.end() ); m_c_triplets.clear(); } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////// Stabilization setting //////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void set_coupling_stabilization() { m_hho_stabilization_Q = false; } void set_hdg_stabilization() { - if(m_hho_di.cell_degree() > m_hho_di.face_degree()) - m_hho_stabilization_Q = false; - else + if(m_hho_di.cell_degree() > m_hho_di.face_degree()) { + m_hho_stabilization_Q = false; + } + else { m_hho_stabilization_Q = true; + } } - void set_interface_cell_indexes(std::map> & interface_cell_indexes){ + void set_interface_cell_indexes(std::map> & interface_cell_indexes) { m_interface_cell_indexes = interface_cell_indexes; } - void set_hho_stabilization(){ + void set_hho_stabilization() { m_hho_stabilization_Q = true; } - void set_scaled_stabilization(){ + void set_scaled_stabilization() { m_scaled_stabilization_Q = true; } - e_boundary_type & get_e_bc_conditions(){ - return m_e_bnd; + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////// Getter functions for DOFs, basis sizes, materials, boundaries, and interface data ////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + e_boundary_type & get_e_bc_conditions() { + return m_e_bnd; } - a_boundary_type & get_a_bc_conditions(){ - return m_a_bnd; + a_boundary_type & get_a_bc_conditions() { + return m_a_bnd; } - std::map> & get_e_material_data(){ - return m_e_material; + std::map> & get_e_material_data() { + return m_e_material; } - std::map> & get_a_material_data(){ - return m_a_material; + std::map> & get_a_material_data() { + return m_a_material; } - size_t get_a_n_cells_dof() const{ + size_t get_a_n_cells_dof() const { return m_n_acoustic_cell_dof; } @@ -1660,12 +1609,12 @@ class elastoacoustic_four_fields_assembler // Elastic cell basis size_t n_ten_cbs = disk::sym_matrix_basis_size(m_hho_di.grad_degree(), Mesh::dimension, Mesh::dimension); size_t n_vec_cbs = disk::vector_basis_size(m_hho_di.cell_degree(),Mesh::dimension, Mesh::dimension); - size_t n_cbs1 = n_ten_cbs + n_vec_cbs; + size_t n_cbs1 = n_ten_cbs + n_vec_cbs; // Acoustic cell basis size_t n_vel_scal_cbs = disk::scalar_basis_size(m_hho_di.reconstruction_degree(), Mesh::dimension)-1; - size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); - size_t n_cbs2 = n_vel_scal_cbs + n_scal_cbs; + size_t n_scal_cbs = disk::scalar_basis_size(m_hho_di.cell_degree(), Mesh::dimension); + size_t n_cbs2 = n_vel_scal_cbs + n_scal_cbs; size_t n_cbs = n_cbs1 + n_cbs2; @@ -1729,21 +1678,6 @@ class elastoacoustic_four_fields_assembler return m_a_expand_indexes; } - std::pair Scc_block_dimension(){ - - // Elastic block - auto graddeg = m_hho_di.grad_degree(); - auto ten_bs = disk::sym_matrix_basis_size(graddeg, Mesh::dimension, Mesh::dimension)*m_n_elastic_cells; - - // Acoustic block - auto recdeg = m_hho_di.reconstruction_degree(); - auto rbs = disk::scalar_basis_size(recdeg, Mesh::dimension); - auto vec_cell_size = (rbs-1)*m_n_acoustic_cells; - - return std::make_pair(ten_bs, vec_cell_size); - - } - }; #endif /* elastoacoustic_four_fields_assembler_hpp */ diff --git a/apps/wave_propagation/src/common/erk_coupling_hho_scheme.hpp b/apps/wave_propagation/src/common/erk_coupling_hho_scheme.hpp index 718a843b..906e7c63 100644 --- a/apps/wave_propagation/src/common/erk_coupling_hho_scheme.hpp +++ b/apps/wave_propagation/src/common/erk_coupling_hho_scheme.hpp @@ -28,7 +28,7 @@ class erk_coupling_hho_scheme Matrix m_Fc; #ifdef HAVE_INTEL_MKL - PardisoLDLT> m_analysis_f; + PardisoLDLT> m_analysis_f; #else SimplicialLDLT> m_analysis_f; #endif @@ -291,14 +291,14 @@ class erk_coupling_hho_scheme void inverse_Sff() { // Bi CG - Eigen::BiCGSTAB> solverBiCG; + BiCGSTAB> solverBiCG; solverBiCG.compute(m_Sff); - if (solverBiCG.info() != Eigen::Success) + if (solverBiCG.info() != Success) std::cout << "Error: Matrix decomposition failed, the matrix may not be invertible"; - Eigen::SparseMatrix identity(m_Sff.rows(), m_Sff.cols()); + SparseMatrix identity(m_Sff.rows(), m_Sff.cols()); identity.setIdentity(); m_inv_Sff = solverBiCG.solve(identity); - if (solverBiCG.info() != Eigen::Success) + if (solverBiCG.info() != Success) std::cout << "Error: Solving the system failed, the matrix may not be invertible"; return; @@ -339,30 +339,190 @@ class erk_coupling_hho_scheme } } - void erk_weight(Matrix & y, Matrix & k){ + void erk_weight(Matrix & y, Matrix & k) { - k=y; - Matrix y_c_dof = y.block(0, 0, m_n_c_dof, 1); - Matrix y_f_dof = y.block(m_n_c_dof, 0, m_n_f_dof, 1); + k=y; + Matrix y_c_dof = y.block(0, 0, m_n_c_dof, 1); + Matrix y_f_dof = y.block(m_n_c_dof, 0, m_n_f_dof, 1); - // Cells update - Matrix RHSc = Fc() - Kcc()*y_c_dof - Kcf()*y_f_dof; - Matrix k_c_dof = m_Mc_inv * RHSc; - k.block(0, 0, m_n_c_dof, 1) = k_c_dof; + ////////// CELLS UPDATE + Matrix RHSc = Fc() - Kcc()*y_c_dof - Kcf()*y_f_dof; + Matrix k_c_dof = m_Mc_inv * RHSc; + k.block(0, 0, m_n_c_dof, 1) = k_c_dof; - // Faces update - Matrix RHSf = Kfc()*k_c_dof ; - // To comment to test eta = 0 - if (m_sff_is_block_diagonal_Q) { - k.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_Sff_inv * RHSf; - } - else { - k.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_inv_Sff * RHSf; - } + // FACES UPDATE + Matrix RHSf = Kfc()*k_c_dof ; + if (m_sff_is_block_diagonal_Q) { + k.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_Sff_inv * RHSf; + } + else { + k.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_inv_Sff * RHSf; + } + + } + + void erk_lts_weight(const Matrix & y, Matrix & k, const Matrix & w_stage) { + + k=y; + Matrix y_c = y.block(0,0,m_n_c_dof,1); + Matrix y_f = y.block(m_n_c_dof,0,m_n_f_dof,1); + + // CELLS UPDATE + Matrix RHSc = w_stage + Kcc()*y_c + Kcf()*y_f; // w_stage contient déjà les termes (I-P) + Matrix k_c = m_Mc_inv * RHSc; + k.block(0,0,m_n_c_dof,1) = k_c; + + // FACES UPDATE (condensation) + Matrix RHSf = Kfc()*k_c; + if (m_sff_is_block_diagonal_Q) { + k.block(m_n_c_dof,0,m_n_f_dof,1) = - m_Sff_inv * RHSf; + } + else { + k.block(m_n_c_dof,0,m_n_f_dof,1) = - m_inv_Sff * RHSf; + } + + } + + void compute_wi(const Matrix &y, const int n_w, const Eigen::SparseMatrix &IminusP, std::vector &w, std::vector &k) { + + w.resize(n_w); + k.resize(n_w); + int total_dof = m_n_c_dof + m_n_f_dof; + for(int i=0;i Biy = y; // B^i y0 + Matrix tmp(total_dof); + Matrix By_c(m_n_c_dof), By_f(m_n_f_dof); + + for(int i=0; i 0) { + Matrix y_c = Biy.block(0, 0, m_n_c_dof, 1); + Matrix y_f = Biy.block(m_n_c_dof, 0, m_n_f_dof, 1); + + Matrix kc = - m_Mc_inv * (Kcc()*y_c + Kcf()*y_f ); + Matrix kf = - m_Sff_inv * (Kfc()*kc); + + Biy.block(0,0,m_n_c_dof,1) = kc; + Biy.block(m_n_c_dof,0,m_n_f_dof,1) = kf; + } + auto tmp_c = IminusP * Biy.block(0,0,m_n_c_dof,1); + auto tmp_f = - m_Sff_inv * (Kfc()*tmp_c); + + By_c = - m_Mc_inv * ( Kcc() * tmp_c + Kcf() * tmp_f ); + w[i] = By_c; + } } + void erk_LTS_weight(Matrix & y, Matrix & k) { + + k=y; + Matrix y_c_dof = y.block(0, 0, m_n_c_dof, 1); + Matrix y_f_dof = y.block(m_n_c_dof, 0, m_n_f_dof, 1); + + ////////// CELLS UPDATE + Matrix RHSc = Fc() - Kcc()*y_c_dof - Kcf()*y_f_dof; + Matrix k_c_dof = m_Mc_inv * RHSc; + k.block(0, 0, m_n_c_dof, 1) = k_c_dof; + + // FACES UPDATE + Matrix RHSf = Kfc()*k_c_dof ; + if (m_sff_is_block_diagonal_Q) { + k.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_Sff_inv * RHSf; + } + else { + k.block(m_n_c_dof, 0, m_n_f_dof, 1) = - m_inv_Sff * RHSf; + } + + } + + Matrix + apply_B(const Matrix& vT) { + Matrix Kcc_v = Kcc() * vT; + Matrix Kfc_v = Kfc() * vT; + Matrix tmpF; + if (m_sff_is_block_diagonal_Q) { + tmpF = m_Sff_inv * Kfc_v; + } + else { + tmpF = m_inv_Sff * Kfc_v; + } + Matrix corr = Kcf() * tmpF; + Matrix result = - m_Mc_inv * (Kcc_v - corr); + return result; + } + + Matrix + apply_B_power(const Matrix& vT, int n) { + Matrix result = vT; + for (int i = 0; i < n; ++i) { + result = apply_B(result); + } + return result; + } + + Matrix + coarse_predictor(int s, Matrix &b, Matrix &c, Matrix & y, SparseMatrix IminusP) { + + Matrix W = Matrix::Zero(m_n_c_dof, s); + Matrix y_c_dof = y.block(0, 0, m_n_c_dof, 1); + + for (int i = 0; i < s; ++i) { + Matrix S = Matrix::Zero(m_n_c_dof); + for (int j = 0; j < s; ++j) { + T coeff = b(j,0) * std::pow(c(j,0), i); + Matrix term = apply_B_power(y_c_dof, i); + for (int ell = 1; ell <= i; ++ell) { + // term += apply_B_power(H(ell-1), i-ell); + } + S += coeff * term; + } + T factor = T(i+1) / tgamma(i+1); + S *= factor; + W.col(i) = apply_B(IminusP * S); + } + + return W; + } + + void compute_k(int r, int m, int s, T Delta_tau, Matrix W, Matrix c, Matrix & y,Matrix k, Matrix a, SparseMatrix P, SparseMatrix IminusP) { + + Matrix k_T = Matrix::Zero(m_n_c_dof,1); + Matrix k_F = Matrix::Zero(m_n_f_dof,1); + + // CELL UPDATE + T alpha = (m + c(r-1,0)) * Delta_tau; + for(int j = 0; j < s; ++j) { + k_T += std::pow(alpha, j) * W.col(j); + } + Matrix tmp = Matrix::Zero(m_n_c_dof,1); + for(int i = 1; i <= r-1; ++i) { + tmp += a(r,i) * k_T; + } + tmp *= Delta_tau; + Matrix y_c = y.block(0, 0, m_n_c_dof, 1); + tmp += y_c; + k_T = apply_B(P * tmp); + + // FACE UPDATE + Matrix RHSf = Kfc()*k_T; + if (m_sff_is_block_diagonal_Q) { + k_F = - m_Sff_inv * RHSf; + } + else { + k_F = - m_inv_Sff * RHSf; + } + + k.block(0, r, m_n_c_dof, 1) = k_T; + k.block(m_n_c_dof, r, m_n_f_dof, 1) = k_F; + + } + #ifdef HAVE_INTEL_MKL - PardisoLDLT> & FacesAnalysis(){ + PardisoLDLT> & FacesAnalysis(){ return m_analysis_f; } #else @@ -375,6 +535,10 @@ class erk_coupling_hho_scheme return m_Mc; } + SparseMatrix & invMc(){ + return m_Mc_inv; + } + SparseMatrix & Kcc(){ return m_Kcc; } @@ -462,12 +626,6 @@ class erk_coupling_hho_scheme } -// Delta = A_{TF} A_{FF}^{-1} A_{FT} -// A' = A_{TT}-Delta -// S'=S_{TT}-Delta - -// Pb spectral pour A'MA' - S'MS' - }; diff --git a/apps/wave_propagation/src/common/erk_hho_scheme.hpp b/apps/wave_propagation/src/common/erk_hho_scheme.hpp index ee6d4720..88c78209 100644 --- a/apps/wave_propagation/src/common/erk_hho_scheme.hpp +++ b/apps/wave_propagation/src/common/erk_hho_scheme.hpp @@ -284,6 +284,8 @@ class erk_hho_scheme } } + + }; diff --git a/apps/wave_propagation/src/common/preprocessor.hpp b/apps/wave_propagation/src/common/preprocessor.hpp index 7a2cec59..f9c99078 100644 --- a/apps/wave_propagation/src/common/preprocessor.hpp +++ b/apps/wave_propagation/src/common/preprocessor.hpp @@ -1,3 +1,4 @@ + // // preprocessor.hpp // acoustics @@ -17,133 +18,136 @@ class simulation_data { public: - size_t m_k_degree; - - size_t m_n_divs; - - bool m_hdg_stabilization_Q; - - bool m_scaled_stabilization_Q; - - bool m_sc_Q; - - size_t m_nt_divs; - - bool m_render_silo_files_Q; + size_t m_k_degree; + size_t m_n_divs; + bool m_hdg_stabilization_Q; + bool m_scaled_stabilization_Q; + bool m_sc_Q; + size_t m_nt_divs; + bool m_render_silo_files_Q; + bool m_report_energy_Q; + bool m_iterative_solver_Q; + bool m_polygonal_mesh_Q; - bool m_report_energy_Q; + simulation_data() : m_k_degree(2), m_n_divs(2), m_hdg_stabilization_Q(false), m_scaled_stabilization_Q(false), m_sc_Q(false), m_nt_divs(0), m_render_silo_files_Q(true), m_report_energy_Q(false), m_iterative_solver_Q(false), m_polygonal_mesh_Q(false) {} - bool m_iterative_solver_Q; - - bool m_polygonal_mesh_Q; - - size_t m_exact_functions; - - simulation_data() : m_k_degree(2), m_n_divs(2), m_hdg_stabilization_Q(false), - m_scaled_stabilization_Q(false), m_sc_Q(false), m_nt_divs(0), - m_render_silo_files_Q(true), m_report_energy_Q(false), - m_iterative_solver_Q(true), m_polygonal_mesh_Q(false), m_exact_functions(1) { - - } + simulation_data(const simulation_data & other) { + m_k_degree = other.m_k_degree; + m_n_divs = other.m_n_divs; + m_hdg_stabilization_Q = other.m_hdg_stabilization_Q; + m_scaled_stabilization_Q = other.m_scaled_stabilization_Q; + m_sc_Q = other.m_sc_Q; + m_nt_divs = other.m_nt_divs; + m_render_silo_files_Q = other.m_render_silo_files_Q; + m_report_energy_Q = other.m_report_energy_Q; + m_iterative_solver_Q = other.m_iterative_solver_Q; + m_polygonal_mesh_Q = other.m_polygonal_mesh_Q; + } - simulation_data(const simulation_data & other){ + const simulation_data & operator=(const simulation_data & other) { - m_k_degree = other.m_k_degree; - m_n_divs = other.m_n_divs; - m_hdg_stabilization_Q = other.m_hdg_stabilization_Q; - m_scaled_stabilization_Q = other.m_scaled_stabilization_Q; - m_sc_Q = other.m_sc_Q; - m_nt_divs = other.m_nt_divs; - m_render_silo_files_Q = other.m_render_silo_files_Q; - m_report_energy_Q = other.m_report_energy_Q; - m_iterative_solver_Q = other.m_iterative_solver_Q; - m_polygonal_mesh_Q = other.m_polygonal_mesh_Q; - m_exact_functions = other.m_exact_functions; - } - - const simulation_data & operator=(const simulation_data & other){ + if (&other == this) { + return *this; + } + + m_k_degree = other.m_k_degree; + m_n_divs = other.m_n_divs; + m_hdg_stabilization_Q = other.m_hdg_stabilization_Q; + m_scaled_stabilization_Q = other.m_scaled_stabilization_Q; + m_sc_Q = other.m_sc_Q; + m_nt_divs = other.m_nt_divs; + m_render_silo_files_Q = other.m_render_silo_files_Q; + m_report_energy_Q = other.m_report_energy_Q; + m_iterative_solver_Q = other.m_iterative_solver_Q; + m_polygonal_mesh_Q = other.m_polygonal_mesh_Q; + + return *this; - // check for self-assignment - if(&other == this){ - return *this; } - - m_k_degree = other.m_k_degree; - m_n_divs = other.m_n_divs; - m_hdg_stabilization_Q = other.m_hdg_stabilization_Q; - m_scaled_stabilization_Q = other.m_scaled_stabilization_Q; - m_sc_Q = other.m_sc_Q; - m_nt_divs = other.m_nt_divs; - m_render_silo_files_Q = other.m_render_silo_files_Q; - m_report_energy_Q = other.m_report_energy_Q; - m_iterative_solver_Q = other.m_iterative_solver_Q; - m_polygonal_mesh_Q = other.m_polygonal_mesh_Q; - m_exact_functions = other.m_exact_functions; - return *this; - } - - ~simulation_data(){ - } - - void write_simulation_data(std::ostream & simulation_log = std::cout){ - simulation_log << " Input parameters:" << std::endl; - simulation_log << " Iterative solver: " << m_iterative_solver_Q << std::endl; - simulation_log << " HHO setting: " << std::endl; - simulation_log << " - Polynomial degree -k: " << m_k_degree << " (Face unknowns)" << std::endl; - simulation_log << " - Stabilization type -s: " << m_hdg_stabilization_Q << " (Equal-order=0, Mixed-order=1)" << std::endl; - simulation_log << " - Scaled stabilization -r: " << m_scaled_stabilization_Q << " (O(1)=0, O(1/h)=1)" << std::endl; - simulation_log << " - Static condensation -c: " << m_sc_Q << std::endl; - simulation_log << " Mesh:" << "- Refinement level -l : " << m_n_divs << std::endl; - simulation_log << " Time refinement level -n : " << m_nt_divs << std::endl; - }; - void print_simulation_data(){ - - std::cout << std::endl << " "; - std::cout << bold << red << "SIMULATION PARAMETERS : " << reset; + ~simulation_data(){} - std::cout << bold << cyan << std::endl; - std::cout << " "; - std::cout << bold << "Iterative solver : " << m_iterative_solver_Q << reset; - - std::cout << bold << cyan << std::endl; - std::cout << " "; - std::cout << bold << "HHO setting : " << reset; - std::cout << yellow; - std::cout << bold << " - Polynomial degree -k : " << m_k_degree << " (Face unknowns)" - << std::endl; - std::cout << " "; - std::cout << " - Stabilization type -s : " << m_hdg_stabilization_Q - << " (Equal-order=0, Mixed-order=1)" << std::endl; - std::cout << " "; - std::cout << " - Scaled stabilization -r : " << m_scaled_stabilization_Q - << " (O(1)=0, O(1/h)=1)" << std::endl; - std::cout << " "; - std::cout << " - Static condensation -c : " << m_sc_Q; - - std::cout << bold << cyan << std::endl; - std::cout << " "; - std::cout << bold << "Mesh :" << reset; - std::cout << yellow; - std::cout << bold << " - Polygonal mesh -p : " << m_polygonal_mesh_Q << std::endl; - std::cout << " "; - std::cout << " - Refinement level -l : " << m_n_divs << std::endl; - - std::cout << bold << cyan; - std::cout << " "; - std::cout << bold << "Time refinement level -n : " << m_nt_divs << reset; - - std::cout << bold << cyan << std::endl; - std::cout << " "; - std::cout << bold << "Post process :" << reset; - std::cout << yellow; - std::cout << bold << " - Silo files -f : " << m_render_silo_files_Q << std::endl; - std::cout << " "; - std::cout << bold << " - Energy file -e : " << m_report_energy_Q << reset; - - std::cout << std::endl << std::endl; - - } + void write_simulation_data(std::ostream & simulation_log = std::cout) { + simulation_log << " Input parameters:" << std::endl; + simulation_log << " Iterative solver: " << m_iterative_solver_Q << std::endl; + simulation_log << " HHO setting: " << std::endl; + simulation_log << " - Polynomial degree -k: " << m_k_degree << " (Face unknowns)" << std::endl; + simulation_log << " - Stabilization type -s: " << m_hdg_stabilization_Q << " (Equal-order=0, Mixed-order=1)" << std::endl; + simulation_log << " - Scaled stabilization -r: " << m_scaled_stabilization_Q << " (O(1)=0, O(1/h)=1)" << std::endl; + simulation_log << " - Static condensation -c: " << m_sc_Q << std::endl; + simulation_log << " Mesh:" << "- Refinement level -l : " << m_n_divs << std::endl; + simulation_log << " Time refinement level -n : " << m_nt_divs << std::endl; + }; + + void print_simulation_data() { + std::cout << "\n " << bold << red << "HHO SETTING: " << reset; + std::cout << bold << cyan + << "\n " << bold << "Discretization: "; + if (m_hdg_stabilization_Q) { + std::cout << bold << yellow << "Mixed-order" << " -s" + << "\n Cell degree = " << m_k_degree+1 << " -k" + << "\n Face degree = " << m_k_degree << std::endl; + } + else { + std::cout << bold << yellow << "Equal-order" << " -s" + << "\n Cell degree = " << m_k_degree << " -k" + << "\n Face degree = " << m_k_degree << std::endl; + } + std::cout << bold << cyan << " Stabilization scaling: "; + if (m_scaled_stabilization_Q) { + std::cout << "O(1/h) -r" << std::endl; + } + else { + std::cout << "O(1) -r " << std::endl; + } + std::cout << cyan << " Static condensation = "; + if (m_sc_Q) { + std::cout << "YES" << " -c" << reset << std::endl; + } + else { + std::cout << "NO" << " -c" << reset << std::endl; + } + + std::cout << "\n " << bold << red << "SIMULATION PARAMETERS: " + << "\n " << bold << cyan << "Mesh:" << yellow << bold << " Cartesian mesh: "; + if (m_polygonal_mesh_Q) { + std::cout << "NO" << " -p"; + } + else { + std::cout << "YES" << " -p"; + } + std::cout << "\n " << "Mesh refinement level: " << m_n_divs << " -l"; + if (m_nt_divs > 12) { + std::cout << "\n " << bold << cyan << "Number of time steps: " << m_nt_divs << " -n"; + } + else { + std::cout << "\n " << bold << cyan << "Time refinement level: " << m_nt_divs << " -n"; + } + std::cout << "\n " << bold << cyan << "Solver:"; + if (m_iterative_solver_Q) { + std::cout << " Iterative" << " -i" << std::endl; + } + else { + std::cout << " Direct" << " -i" << std::endl; + } + + std::cout << "\n " << bold << red << "POSTPROCESS:" << reset + << cyan + << "\n " << bold << "Silo files: "; + if (m_render_silo_files_Q) { + std::cout << " YES" << " -f"; + } + else { + std::cout << " NO" << " -f"; + } + std::cout << "\n " << bold << "Energy file: "; + if (m_report_energy_Q) { + std::cout << "YES" << " -e"; + } + else { + std::cout << "NO" << " -e"; + } + } }; @@ -151,12 +155,10 @@ class preprocessor { public: - + static void PrintHelp() { - static void PrintHelp() - { std::cout << - "-k : Face polynomial degree: default 0\n" + "-k : blabla Face polynomial degree: default 0\n" "-l : Number of uniform space refinements: default 0\n" "-s <0-1>: Stabilization type 0 -> HHO, 1 -> HDG-like: default 0 \n" "-r <0-1>: Scaled stabilization 0 -> without, 1 -> with: default 0 \n" @@ -168,289 +170,104 @@ class preprocessor { exit(1); } - static simulation_data process_args(int argc, char** argv) - { - const char* const short_opts = "k:p:l:s:r:n:c:f:e:"; - const option long_opts[] = { - {"degree", required_argument, nullptr, 'k'}, - {"poly_mesh", required_argument, nullptr, 'p'}, - {"xref", required_argument, nullptr, 'l'}, - {"stab", required_argument, nullptr, 's'}, - {"scal", required_argument, nullptr, 'r'}, - {"tref", required_argument, nullptr, 'n'}, - {"c", optional_argument, nullptr, 'c'}, - {"file", optional_argument, nullptr, 'f'}, - {"energy", optional_argument, nullptr, 'e'}, - {"help", no_argument, nullptr, 'h'}, - {nullptr, no_argument, nullptr, 0} - }; + static simulation_data process_args(int argc, char** argv) { - size_t k_degree = 0; - size_t n_divs = 0; - size_t nt_divs = 0; - size_t poly_mesh = 0; - bool hdg_Q = false; - bool scaled_Q = false; - bool sc_Q = false; - bool silo_files_Q = true; - bool report_energy_Q = true; + const char* const short_opts = "k:s:r:c:p:l:n:i:f:e:?"; - while (true) - { - const auto opt = getopt_long(argc, argv, short_opts, long_opts, nullptr); - - if (-1 == opt) - break; - - switch (opt) - { - case 'k': - k_degree = std::stoi(optarg); - break; - - case 'p': - poly_mesh = std::stoi(optarg); - break; - - case 'l': - n_divs = std::stoi(optarg); - break; - - case 's': - hdg_Q = std::stoi(optarg); - break; - - case 'r': - scaled_Q = std::stoi(optarg); - break; - - case 'n': - nt_divs = std::stoi(optarg); - break; - - case 'c': - sc_Q = std::stoi(optarg); - break; - - case 'f': - silo_files_Q = std::stoi(optarg); - break; - - case 'e': - report_energy_Q = std::stoi(optarg); - break; - - - case 'h': // -h or --help - case '?': // Unrecognized option - default: - preprocessor::PrintHelp(); - break; - } - } - - // populating simulation data - simulation_data sim_data; - sim_data.m_k_degree = k_degree; - sim_data.m_polygonal_mesh_Q = poly_mesh; - sim_data.m_n_divs = n_divs; - sim_data.m_hdg_stabilization_Q = hdg_Q; - sim_data.m_scaled_stabilization_Q = scaled_Q; - sim_data.m_sc_Q = sc_Q; - sim_data.m_nt_divs = nt_divs; - sim_data.m_render_silo_files_Q = silo_files_Q; - sim_data.m_report_energy_Q = report_energy_Q; - return sim_data; - } - - static void PrintTestHelp() - { - std::cout << - "-k : Maximum Face polynomial degree: default 0\n" - "-l : Maximum Number of uniform space refinements: default 0\n" - "-s <0-1>: Stabilization type 0 -> HHO, 1 -> HDG-like: default 0 \n" - "-r <0-1>: Scaled stabilization 0 -> without, 1 -> with: default 0 \n" - "-q <0-1>: Quadratic function type 0 -> non-polynomial, 1 -> quadratic: default 0 \n" - "-f <0-1>: Write silo files : default 0\n" - "-c <0-1>: Static Condensation: default 0 \n" - "-help: Show help\n"; - exit(1); - } - - static simulation_data process_convergence_test_args(int argc, char** argv) - { - const char* const short_opts = "k:l:s:r:c:q:f:"; const option long_opts[] = { - {"degree", required_argument, nullptr, 'k'}, - {"xref", required_argument, nullptr, 'l'}, - {"stab", required_argument, nullptr, 's'}, - {"scal", required_argument, nullptr, 'r'}, - {"file", optional_argument, nullptr, 'f'}, - {"qfunc", optional_argument, nullptr, 'q'}, - {"cond", optional_argument, nullptr, 'c'}, - {"help", no_argument, nullptr, 'h'}, - {nullptr, no_argument, nullptr, 0} + // HHO SETTING + {"degree", required_argument, nullptr, 'k'}, + {"stab", required_argument, nullptr, 's'}, + {"scal", required_argument, nullptr, 'r'}, + {"c", optional_argument, nullptr, 'c'}, + // SIMULATION PARAMETERS + {"poly_mesh", required_argument, nullptr, 'p'}, + {"xref", required_argument, nullptr, 'l'}, + {"tref", required_argument, nullptr, 'n'}, + {"solv", required_argument, nullptr, 'i'}, + // POST PROCESSOR + {"file", optional_argument, nullptr, 'f'}, + {"energy", optional_argument, nullptr, 'e'}, + // HELP + {"help", no_argument, nullptr, '?'}, + {nullptr, no_argument, nullptr, 0} }; - size_t k_degree = 0; - size_t n_divs = 0; - bool hdg_Q = false; - bool scaled_Q = false; - bool sc_Q = false; - bool quadratic_func_Q = false; - bool silo_files_Q = false; + size_t k_degree = 0; + size_t n_divs = 0; + size_t nt_divs = 0; + size_t poly_mesh = 0; + bool hdg_Q = false; + bool scaled_Q = false; + bool sc_Q = false; + bool silo_files_Q = true; + bool report_energy_Q = true; + bool it_sol = false; - while (true) - { + while (true) { const auto opt = getopt_long(argc, argv, short_opts, long_opts, nullptr); - if (-1 == opt) break; - - switch (opt) - { - case 'k': - k_degree = std::stoi(optarg); - break; - - case 'l': - n_divs = std::stoi(optarg); - break; - - case 's': - hdg_Q = std::stoi(optarg); - break; - - case 'r': - scaled_Q = std::stoi(optarg); - break; - - case 'c': - sc_Q = std::stoi(optarg); - break; - - case 'q': - quadratic_func_Q = std::stoi(optarg); - break; - - case 'f': - silo_files_Q = std::stoi(optarg); - break; - - case 'h': // -h or --help - case '?': // Unrecognized option - default: - preprocessor::PrintTestHelp(); - break; + switch (opt) { + // HHO SETTING + case 'k': + k_degree = std::stoi(optarg); + break; + case 's': + hdg_Q = std::stoi(optarg); + break; + case 'r': + scaled_Q = std::stoi(optarg); + break; + case 'c': + sc_Q = std::stoi(optarg); + break; + // SIMULATION PARAMETERS + case 'p': + poly_mesh = std::stoi(optarg); + break; + case 'l': + n_divs = std::stoi(optarg); + break; + case 'n': + nt_divs = std::stoi(optarg); + break; + case 'i': + it_sol = std::stoi(optarg); + break; + // POSTPROCESSOR + case 'f': + silo_files_Q = std::stoi(optarg); + break; + case 'e': + report_energy_Q = std::stoi(optarg); + break; + // HELP + case '?': + preprocessor::PrintHelp(); + break; } } - // populating simulation data + // POPULATING SIM DATA simulation_data sim_data; - sim_data.m_k_degree = k_degree; - sim_data.m_n_divs = n_divs; - sim_data.m_hdg_stabilization_Q = hdg_Q; - sim_data.m_scaled_stabilization_Q = scaled_Q; - sim_data.m_sc_Q = sc_Q; - sim_data.m_render_silo_files_Q = silo_files_Q; - return sim_data; + // HHO SETTING + sim_data.m_k_degree = k_degree; + sim_data.m_hdg_stabilization_Q = hdg_Q; + sim_data.m_scaled_stabilization_Q = scaled_Q; + sim_data.m_sc_Q = sc_Q; + // SIMULATION PARAMETERS + sim_data.m_polygonal_mesh_Q = poly_mesh; + sim_data.m_n_divs = n_divs; + sim_data.m_nt_divs = nt_divs; + sim_data.m_iterative_solver_Q = it_sol; + // POSTPROCESSOR + sim_data.m_render_silo_files_Q = silo_files_Q; + sim_data.m_report_energy_Q = report_energy_Q; + + return sim_data; } - static simulation_data process_convergence_test_lua_file(char** argv) - { - - sol::state lua; - lua.open_libraries(sol::lib::math, sol::lib::base); - - // expected input tables - lua["config"] = lua.create_table(); - - std::string lua_file = argv[3]; - auto r = lua.do_file(lua_file); - if ( !r.valid() ){ - PrintConvergeceTestExample(); - } - - // populating simulation data - simulation_data sim_data; - sim_data.m_k_degree = lua["config"]["max_k_deg"].get_or(0); - sim_data.m_n_divs = lua["config"]["max_l_ref"].get_or(0); - sim_data.m_hdg_stabilization_Q = lua["config"]["stab_type"].get_or(0); - sim_data.m_scaled_stabilization_Q = lua["config"]["stab_scal"].get_or(0); - sim_data.m_sc_Q = lua["config"]["stat_cond"].get_or(0); - sim_data.m_render_silo_files_Q = lua["config"]["silo_output"].get_or(0); - sim_data.m_iterative_solver_Q = lua["config"]["iter_solv"].get_or(0); - sim_data.m_exact_functions = lua["config"]["exac_func"].get_or(0); - sim_data.m_polygonal_mesh_Q = lua["config"]["poly_mesh"].get_or(0); - return sim_data; - } - - static void PrintConvergeceTestExample() - { - std::cout << "Please specify a lua configuration file like this: " << std::endl; - std::cout << - "config.max_k_deg = 4 -- : Maximum face polynomial degree: default 0\n" - "config.max_l_ref = 4 -- : Maximum number of uniform spatial refinements: default 0\n" - "config.stab_type = 0 -- <0-1>: Stabilization type 0 (HHO), 1 (HDG-like): default 0\n" - "config.stab_scal = 1 -- <0-1>: Stabilization scaling 0 O(1), 1 O(1/h_{f}): default 0\n" - "config.stat_cond = 1 -- <0-1>: Static condensation: default 0\n" - "config.iter_solv = 0 -- <0-1>: Iterative solver : default 0\n" - "config.exac_func = 0 -- <0-1>: Manufactured function type 0 (non-polynomial), 1 (quadratic): default 0\n" - "config.poly_mesh = 0 -- <0-1>: Use of polynoal meshes : default 0\n" - "config.silo_output = 0 -- <0-1>: Write silo files : default 0\n"; - exit(1); - throw std::invalid_argument("Program will stop."); - } - - static simulation_data process_acoustics_lua_file(char** argv) - { - - sol::state lua; - lua.open_libraries(sol::lib::math, sol::lib::base); - - // expected input tables - lua["config"] = lua.create_table(); - - std::string lua_file = argv[3]; - auto r = lua.do_file(lua_file); - if ( !r.valid() ){ - PrintSimulationExample(); - } - - // populating simulation data - simulation_data sim_data; - sim_data.m_k_degree = lua["config"]["fac_k_deg"].get_or(0); - sim_data.m_n_divs = lua["config"]["num_l_ref"].get_or(0); - sim_data.m_nt_divs = lua["config"]["num_t_ref"].get_or(0); - sim_data.m_hdg_stabilization_Q = lua["config"]["stab_type"].get_or(0); - sim_data.m_scaled_stabilization_Q = lua["config"]["stab_scal"].get_or(0); - sim_data.m_sc_Q = lua["config"]["stat_cond"].get_or(0); - sim_data.m_render_silo_files_Q = lua["config"]["silo_output"].get_or(0); - sim_data.m_iterative_solver_Q = lua["config"]["iter_solv"].get_or(0); - sim_data.m_polygonal_mesh_Q = lua["config"]["poly_mesh"].get_or(0); - sim_data.m_exact_functions = lua["config"]["exac_func"].get_or(0); - sim_data.m_report_energy_Q = lua["config"]["writ_ener"].get_or(0); - return sim_data; - } - - static void PrintSimulationExample() - { - std::cout << "Please specify a lua configuration file like this: " << std::endl; - std::cout << - "config.fac_k_deg = 3 -- : Face polynomial degree: default 0\n" - "config.num_l_ref = 3 -- : Number of uniform spatial refinements: default 0\n" - "config.num_t_ref = 7 -- : Number of uniform time refinements: default 0\n" - "config.stab_type = 1 -- <0-1>: Stabilization type 0 (HHO), 1 (HDG-like): default 0\n" - "config.stab_scal = 0 -- <0-1>: Stabilization scaling 0 O(1), 1 O(1/h_{f}): default 0\n" - "config.stat_cond = 1 -- <0-1>: Static condensation: default 0\n" - "config.iter_solv = 0 -- <0-1>: Iterative solver : default 0\n" - "config.poly_mesh = 0 -- <0-1>: Use of polynoal meshes : default 0\n" - "config.exac_func = 0 -- <0-2>: Exact function type {0,1,2} : default 0\n" - "config.writ_ener = 1 -- <0-1>: Report energy at each time value : default 0\n" - "config.silo_output = 0 -- <0-1>: Write silo files : default 0\n"; - exit(1); - throw std::invalid_argument("Program will stop."); - } }; diff --git a/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp b/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp index 3da218eb..0c41caf6 100644 --- a/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp +++ b/apps/wave_propagation/src/common/scal_vec_analytic_functions.hpp @@ -12,15 +12,16 @@ class scal_vec_analytic_functions { /// Enumerate defining the function type enum EFunctionType { - EFunctionNonPolynomial = 0, - EFunctionQuadraticInTime = 1, - EFunctionQuadraticInSpace = 2, - reproduction_acoustic = 3, - reproduction_elastic = 4, - EFunctionNonPolynomial_paper = 5, - EFunctionCubicInTimeAcoustic = 6, - EFunctionQuarticInTimeAcoustic = 7, - EFunctionQuadraticInSpaceAcoustic = 8}; + EFunctionNonPolynomial = 0, + EFunctionQuadraticInTime = 1, + EFunctionQuadraticInSpace = 2, + reproduction_acoustic = 3, + reproduction_elastic = 4, + EFunctionNonPolynomial_paper = 5, + EFunctionCubicInTimeAcoustic = 6, + EFunctionQuarticInTimeAcoustic = 7, + EFunctionQuadraticInSpaceAcoustic = 8, + EFunctionPlaneWaveAcoustic = 9}; scal_vec_analytic_functions() { m_function_type = EFunctionNonPolynomial; @@ -411,7 +412,6 @@ class scal_vec_analytic_functions { } } - std::function (const typename disk::generic_mesh::point_type& )> Evaluate_sigma(double & t){ @@ -551,6 +551,7 @@ class scal_vec_analytic_functions { } + // ACOUSTIC std::function::point_type& )> Evaluate_s_u(double & t) { @@ -640,6 +641,17 @@ class scal_vec_analytic_functions { }; } break; + + case EFunctionPlaneWaveAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y, theta; + x = pt.x(); + y = pt.y(); + theta = x + y - std::sqrt(2)*t; + return -(1.0/std::sqrt(2)) * std::sin(theta); + }; + } + break; default: { std::cout << " Function not implemented " << std::endl; @@ -736,6 +748,17 @@ class scal_vec_analytic_functions { }; } break; + + case EFunctionPlaneWaveAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y, theta; + x = pt.x(); + y = pt.y(); + theta = x + y - std::sqrt(2)*t; + return std::cos(theta); + }; + } + break; default: { std::cout << " Function not implemented " << std::endl; @@ -835,6 +858,17 @@ class scal_vec_analytic_functions { }; } break; + + case EFunctionPlaneWaveAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y, theta; + x = pt.x(); + y = pt.y(); + theta = x + y - std::sqrt(2)*t; + return std::sqrt(2) * std::sin(theta); + }; + } + break; default: { std::cout << " Function not implemented " << std::endl; @@ -947,6 +981,17 @@ class scal_vec_analytic_functions { } break; + case EFunctionPlaneWaveAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> double { + double x,y,f; + x = pt.x(); + y = pt.y(); + f = 0.0; + return f; + }; + } + break; + default: { std::cout << " Function not implemented " << std::endl; return [](const typename disk::generic_mesh::point_type& pt) -> double { @@ -957,7 +1002,6 @@ class scal_vec_analytic_functions { } } - std::function (const typename disk::generic_mesh::point_type& )> Evaluate_s_q(double & t){ @@ -1081,6 +1125,20 @@ class scal_vec_analytic_functions { } break; + case EFunctionPlaneWaveAcoustic: { + return [&t](const typename disk::generic_mesh::point_type& pt) -> disk::static_vector { + double x, y, qx, qy, theta; + x = pt.x(); + y = pt.y(); + theta = x + y - std::sqrt(2)*t; + qx = (1.0/std::sqrt(2.0)) * std::sin(theta); + qy = (1.0/std::sqrt(2.0)) * std::sin(theta); + disk::static_vector q{qx,qy}; + return q; + }; + } + break; + default: { std::cout << " Function not implemented " << std::endl; return [](const typename disk::generic_mesh::point_type& pt) diff --git a/apps/wave_propagation/src/prototypes/LTS/ELTSAcoustic_conv_test.hpp b/apps/wave_propagation/src/prototypes/LTS/ELTSAcoustic_conv_test.hpp new file mode 100644 index 00000000..513520b2 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/LTS/ELTSAcoustic_conv_test.hpp @@ -0,0 +1,350 @@ + + +// Created by Romain Mottier + +// ../wave_propagation -s0 -k3 -r0 -c0 -p0 -l4 -n300 -i0 -f0 -e0 + +void ELTSAcousticFirstOrder(int argc, char **argv); + +void ELTSAcousticFirstOrder(int argc, char **argv){ + + // ############################################################################################# + // ############################## Simulation paramaters ######################################## + // ############################################################################################# + + std::cout << std::endl << bold << red << " EXPLICIT ACOUSTIC CONV TEST" << reset << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, cpu; + + // ############################################################################################# + // ############################## Mesh generation ############################################## + // ############################################################################################# + + cpu.tic(); + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + size_t l = sim_data.m_n_divs; + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + bool use_poly_mesh = false; + bool use_simp_mesh = false; + if (use_poly_mesh) { + for (int i = 0; i <= 9; ++i) { + mesh_files.push_back("../../meshes/conv_test/poly/poly_" + std::to_string(32 * (1 << i)) + ".txt"); + } + } + else if (use_simp_mesh) { + std::vector conv_vals = {1.0, 0.35, 0.15, 0.07, 0.035, 0.026, 0.017, 0.0125, 0.0085, 0.005}; + for (int i = 0; i < conv_vals.size(); ++i) { + mesh_files.push_back( + "../../meshes/conv_test/simplices/unstructured/l" + std::to_string(i) + "_conv_test_" + std::to_string(conv_vals[i]) + ".txt"); + } + } + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + + // ############################################################################################# + // ################################ Time controls ############################################## + // ############################################################################################# + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt = sim_data.m_nt_divs; + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ############################################################################################# + // ############################## Manufactured solution ######################################## + // ############################################################################################# + + scal_vec_analytic_functions functions; + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionCubicInTimeAcoustic); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuarticInTimeAcoustic); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpaceAcoustic); + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + // Acoustic analytical functions + auto s_u_fun = functions.Evaluate_s_u(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_a_fun = functions.Evaluate_s_a(t); + auto s_f_fun = functions.Evaluate_s_f(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ############################################################################################# + // ################################## HHO setting ############################################## + // ############################################################################################# + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if (sim_data.m_hdg_stabilization_Q) { + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree, sim_data.m_k_degree); + + // ############################################################################################# + // ################################ Material data ############################################## + // ############################################################################################# + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ############################################################################################# + // ############################## Boundary conditions ########################################## + // ############################################################################################# + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, s_u_fun); + + // ############################################################################################# + // ###################################### Assembly ############################################# + // ############################################################################################# + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_coupling_stabilization(); + if (sim_data.m_scaled_stabilization_Q) { + assembler.set_scaled_stabilization(); + } + assembler.assemble_mass(msh); + assembler.assemble_coupling_terms(msh); + + // ############################################################################################# + // ###################### Projecting initial data ############################################## + // ############################################################################################# + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, null_fun, s_v_fun); + + // ############################################################################################# + // ###################################### Solving ############################################## + // ############################################################################################# + + Matrix a; + Matrix b; + Matrix c; + + // ERK schemes + int s = 4; + erk_butcher_tableau::erk_tables(s, a, b, c); + assembler.assemble(msh, null_fun, s_f_fun, true); + assembler.LHS += assembler.COUPLING; + assembler.assemble_P(msh, 1); + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes);//assembler.get_interfaces()); + erk_an.refresh_faces_unknowns(x_dof); + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + std::cout << std::endl << std::endl; + + size_t it = 0; + std::ostringstream filename_silo; + filename_silo << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename_silo.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + + // ################################################## + // ################################################## Time marching + // ################################################## + + size_t p = 1; + size_t dtau = dt / p; + + // DISCRTIZATION INFOS + std::cout << bold << red << " TIME LOOP: " << std::endl; + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + std::cout << bold << cyan << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // ERK step + tc.tic(); + + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix k_T = Matrix::Zero(n_dof, s); + Matrix k_F = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + x_dof_n = x_dof; + + // PREDICTOR STEP + auto W = erk_an.coarse_predictor(s, b, c, x_dof_n, assembler.IminusP); + + // LOOP ON LOCAL REFINEMENT RATIOS + for (int m = 0; m < p; ++m) { + yn = x_dof; + + // LOOP ON ERK STAGES + for (int r = 0; r < s; ++r) { + + t = tn + (m+c(r,0)) * dtau; + + // MANUFACTURED SOLUTION + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_f_fun = functions.Evaluate_s_f(t); + assembler.get_e_bc_conditions().updateDirichletFunction(null_fun, 0); + assembler.get_a_bc_conditions().updateDirichletFunction(s_v_fun, 0); + assembler.assemble_rhs(msh, null_fun, s_f_fun, true); + erk_an.SetFg(assembler.RHS); + + // UPDATE + erk_an.compute_k(r, m, s, dtau, W, c, yn, k, a, assembler.P, assembler.IminusP); + + } + // ACCUMULATED SOLUTION + for (int i = 0; i < s; i++) { + x_dof_n += dtau*b(i,0)*k.block(0, i, n_dof, 1); + } + } + + tc.toc(); + std::cout << bold << yellow << " LTS-ERK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + t = tn + dt; + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + if(it == nt) { + std::cout << std::endl; + postprocessor::compute_errors_four_fields_elastoacoustic(msh, hho_di, assembler, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun, simulation_log); + postprocessor::compute_errors_four_fields_elastoacoustic_energy_norm(msh, hho_di, assembler, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun, simulation_log); + } + } + + bool mesh_quality = false; + if (mesh_quality) { + std::ofstream mesh_file("mesh_file.txt"); + postprocessor::mesh_quality(msh, assembler, mesh_file); + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + diff --git a/apps/wave_propagation/src/prototypes/LTS/ERK4_LTS_conv_test.hpp b/apps/wave_propagation/src/prototypes/LTS/ERK4_LTS_conv_test.hpp new file mode 100644 index 00000000..54347c5c --- /dev/null +++ b/apps/wave_propagation/src/prototypes/LTS/ERK4_LTS_conv_test.hpp @@ -0,0 +1,386 @@ + + +// Created by Romain Mottier + +// ../wave_propagation -s0 -k3 -r0 -c0 -p0 -l4 -n300 -i0 -f0 -e0 + +void ERK4_LTS_conv_test(int argc, char **argv); + +void ERK4_LTS_conv_test(int argc, char **argv){ + + // ############################################################################################# + // ############################## Simulation paramaters ######################################## + // ############################################################################################# + + std::cout << std::endl << bold << red << " EXPLICIT ACOUSTIC CONV TEST" << reset << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, cpu; + + // ############################################################################################# + // ############################## Mesh generation ############################################## + // ############################################################################################# + + cpu.tic(); + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + size_t l = sim_data.m_n_divs; + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + bool use_poly_mesh = false; + bool use_simp_mesh = false; + if (use_poly_mesh) { + for (int i = 0; i <= 9; ++i) { + mesh_files.push_back("../../meshes/conv_test/poly/poly_" + std::to_string(32 * (1 << i)) + ".txt"); + } + } + else if (use_simp_mesh) { + std::vector conv_vals = {1.0, 0.35, 0.15, 0.07, 0.035, 0.026, 0.017, 0.0125, 0.0085, 0.005}; + for (int i = 0; i < conv_vals.size(); ++i) { + mesh_files.push_back( + "../../meshes/conv_test/simplices/unstructured/l" + std::to_string(i) + "_conv_test_" + std::to_string(conv_vals[i]) + ".txt"); + } + } + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + + // ############################################################################################# + // ################################ Time controls ############################################## + // ############################################################################################# + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt = sim_data.m_nt_divs; + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ############################################################################################# + // ############################## Manufactured solution ######################################## + // ############################################################################################# + + scal_vec_analytic_functions functions; + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionCubicInTimeAcoustic); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuarticInTimeAcoustic); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpaceAcoustic); + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + // Acoustic analytical functions + auto s_u_fun = functions.Evaluate_s_u(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_a_fun = functions.Evaluate_s_a(t); + auto s_f_fun = functions.Evaluate_s_f(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ############################################################################################# + // ################################## HHO setting ############################################## + // ############################################################################################# + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if (sim_data.m_hdg_stabilization_Q) { + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree, sim_data.m_k_degree); + + // ############################################################################################# + // ################################ Material data ############################################## + // ############################################################################################# + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ############################################################################################# + // ############################## Boundary conditions ########################################## + // ############################################################################################# + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, s_u_fun); + + // ############################################################################################# + // ###################################### Assembly ############################################# + // ############################################################################################# + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_coupling_stabilization(); + if (sim_data.m_scaled_stabilization_Q) { + assembler.set_scaled_stabilization(); + } + assembler.assemble_mass(msh); + assembler.assemble_coupling_terms(msh); + + // ############################################################################################# + // ###################### Projecting initial data ############################################## + // ############################################################################################# + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, null_fun, s_v_fun); + + // ############################################################################################# + // ###################################### Solving ############################################## + // ############################################################################################# + + Matrix a; + Matrix b; + Matrix c; + + // ERK schemes + int s = 4; + erk_butcher_tableau::erk_tables(s, a, b, c); + assembler.assemble(msh, null_fun, s_f_fun, true); + assembler.LHS += assembler.COUPLING; + assembler.assemble_P(msh, 1); + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes);//assembler.get_interfaces()); + erk_an.refresh_faces_unknowns(x_dof); + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + std::cout << std::endl << std::endl; + + size_t it = 0; + std::ostringstream filename_silo; + filename_silo << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename_silo.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + + // ################################################## + // ################################################## Time marching + // ################################################## + + size_t p = 1; + size_t dtau = dt / p; + auto l0 = x_dof; + + // DISCRTIZATION INFOS + std::cout << bold << red << " TIME LOOP: " << std::endl; + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + std::cout << bold << cyan << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + tc.tic(); + + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix k_T = Matrix::Zero(n_dof, s); + Matrix k_F = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + x_dof_n = x_dof; + + //////////////////////////////////////////////////////////// SOURCE TERMS + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_f_fun_tn = functions.Evaluate_s_f(t); + assembler.get_a_bc_conditions().updateDirichletFunction(s_v_fun, 0); + assembler.assemble_rhs(msh, null_fun, s_f_fun, true); + erk_an.SetFg(assembler.RHS); + auto F0 = erk_an.invMc() * erk_an.Fc(); + + auto t_dt = t+dt; + s_v_fun = functions.Evaluate_s_v(t_dt); + s_f_fun = functions.Evaluate_s_f(t_dt); + assembler.get_a_bc_conditions().updateDirichletFunction(s_v_fun, 0); + assembler.assemble_rhs(msh, null_fun, s_f_fun, true); + erk_an.SetFg(assembler.RHS); + auto F1 = erk_an.invMc() * erk_an.Fc(); + + auto t_dt_2 = t+dt/2.0; + s_v_fun = functions.Evaluate_s_v(t_dt_2); + s_f_fun = functions.Evaluate_s_f(t_dt_2); + assembler.get_a_bc_conditions().updateDirichletFunction(s_v_fun, 0); + assembler.assemble_rhs(msh, null_fun, s_f_fun, true); + erk_an.SetFg(assembler.RHS); + auto F2 = erk_an.invMc() * erk_an.Fc(); + + ////////////////////////////////////////////////////////////// COARSE PREDICTOR + Matrix w0, w1, w2, w3; + Eigen::VectorXd tmp; + tmp = assembler.IminusP * x_dof_n; + // w0 + w0 = erk_an.apply_B(tmp) + assembler.IminusP * F0; + // w1 + tmp = assembler.IminusP * (erk_an.apply_B(x_dof_n) + F0); + w1 = erk_an.apply_B(tmp) + assembler.IminusP * ((-3.0*F0 + 4.0*F2 - F1)/dt); + // w2 + tmp = assembler.IminusP * (erk_an.apply_B_power(x_dof_n,2) + erk_an.apply_B(F0) + (-3.0*F0 + 4.0*F2 - F1)/dt); + w2 = erk_an.apply_B(tmp) + assembler.IminusP * ((4.0*F0 - 8.0*F2 + 4.0*F1)/(dt*dt)); + + // w3 + auto tmp1 = (-3*F0+4*F2-F1)/dt; + tmp = assembler.IminusP * (erk_an.apply_B_power(x_dof_n,3) + erk_an.apply_B_power(F0,2) + erk_an.apply_B(tmp1) + ((4.0*F0 - 8.0*F2 + 4.0*F1)/(dt*dt)) ); + w3 = erk_an.apply_B(tmp); + + // LOOP ON LOCAL REFINEMENT RATIOS + for (int m = 0; m < p; ++m) { + + auto tm = tn + m * dtau; + auto tm1 = tn + (m+1)*dtau; + auto tm2 = tn + (m+0.5)*dtau; + + auto tmp1 = assembler.P*l0; + auto k1 = w0 + m*dtau*w1 + (m*m/2)*dtau*dtau*w2 + (m*m*m/6)*dtau*dtau*dtau*w3 + erk_an.apply_B(tmp1); + + auto tmp2 = assembler.P*(l0 + (dtau/2)*k1); + auto k2 = w0 + (m+0.5)*dtau*w1 + 0.5*(m+0.5)*(m+0.5)*dtau*dtau*w2 + (1/6)*(m+0.5)*(m+0.5)*(m+0.5)*dtau*dtau*dtau*w3 + erk_an.apply_B(tmp2); + + auto tmp3 = assembler.P*(l0 + (dtau/2)*k2); + auto k3 = w0 + (m+0.5)*dtau*w1 + 0.5*(m+0.5)*(m+0.5)*dtau*dtau*w2 + (1/6)*(m+0.5)*(m+0.5)*(m+0.5)*dtau*dtau*dtau*w3 + erk_an.apply_B(tmp3); + + auto tmp4 = assembler.P*(l0 + dtau*k3); + auto k4 = w0 + (m+1)*dtau*w1 + 0.5*(m+1)*(m+1)*dtau*dtau*w2 + (1/6)*(m+1)*(m+1)*(m+1)*dtau*dtau*dtau*w3 + erk_an.apply_B(tmp4); + + // ACCUMULATED SOLUTION + auto l1 = l0 + (dtau/6) * (k1 + 2*k2 + 2*k3 + k4); + l0 = l1; + + } + + tc.toc(); + std::cout << bold << yellow << " LTS-ERK step completed: " << tc << " seconds" << reset << std::endl; + x_dof_n = l0; + x_dof = x_dof_n; + t = tn + dt; + + if(it == nt) { + std::cout << std::endl; + postprocessor::compute_errors_four_fields_elastoacoustic(msh, hho_di, assembler, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun, simulation_log); + postprocessor::compute_errors_four_fields_elastoacoustic_energy_norm(msh, hho_di, assembler, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun, simulation_log); + } + + } + + bool mesh_quality = false; + if (mesh_quality) { + std::ofstream mesh_file("mesh_file.txt"); + postprocessor::mesh_quality(msh, assembler, mesh_file); + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + diff --git a/apps/wave_propagation/src/prototypes/LTS/HeterogeneousERK4_LTS_HHO_FirstOrder.hpp b/apps/wave_propagation/src/prototypes/LTS/HeterogeneousERK4_LTS_HHO_FirstOrder.hpp new file mode 100644 index 00000000..5429e7ac --- /dev/null +++ b/apps/wave_propagation/src/prototypes/LTS/HeterogeneousERK4_LTS_HHO_FirstOrder.hpp @@ -0,0 +1,565 @@ + + +// Created by Romain Mottier +// ../wave_propagation -k 2 -s 0 -r 0 -c 0 -p 0 -l 6 -n 2500 -f 1 -e 0 + +void HeterogeneousERK4_LTS_HHO_FirstOrder(int argc, char **argv); + +void HeterogeneousERK4_LTS_HHO_FirstOrder(int argc, char **argv){ + + // ###################################################################### + // ###################################################################### Simulation paramaters + // ###################################################################### + + std::cout << std::endl << bold << red << " EXPLICIT PULSE - COUPLING" << std::endl << std::endl; + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, tcit, cpu; + cpu.tic(); + + // ################################################## + // ################################################## Mesh generation + // ################################################## + + tc.tic(); + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + auto validate_l = [](size_t l) -> size_t { + if ((0 <= l) && (l < 15) ) { + return l; + } + else { + std::cout << std::endl << std::endl; + std::cout << "Warning:: Only few polygonal meshes available."; + std::cout << std::endl << std::endl; + return 4; + } + }; + + size_t l = validate_l(sim_data.m_n_divs); + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l2_0.4.txt"); // l = 0 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l3_0.21.txt"); // l = 1 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l4_0.096.txt"); // l = 2 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l5_0.0485.txt"); // l = 3 + mesh_files.push_back("../../meshes/pulse/simplices/simplex_l6_0.024.txt"); // l = 4 + + // mesh_files.push_back("../../meshes/pulse/poly/poly_l2.txt"); // -l 0 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l3.txt"); // -l 1 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l4.txt"); // -l 2 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l5.txt"); // -l 3 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l6.txt"); // -l 4 + // mesh_files.push_back("../../meshes/pulse/poly/poly_l7.txt"); // -l 5 + + // Reading the polygonal mesh + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 1; + RealType ly = 1; + size_t nx = 2; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-0.5, -0.5); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) { + h = h_l; + } + } + + tc.toc(); + std::cout << bold << red << " MESH GENERATION : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Time controls + // ###################################################################### + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { + nt = sim_data.m_nt_divs; + } + + RealType ti = 0.0; + RealType tf = 0.25; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ###################################################################### + // ###################################################################### HHO setting + // ###################################################################### + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if (sim_data.m_hdg_stabilization_Q) { + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree, sim_data.m_k_degree); + + // ################################################## + // ################################################## Material data + // ################################################## + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + auto water_mat_fun_adi = [](const typename disk::mesh>::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp; + rho = 1.0; + vp = 1.0; + acoustic_material_data material(rho,vp); + return material; + }; + + auto granit_mat_fun_adi = [](const typename disk::mesh>::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + double rho, vp, vs; + rho = 2.624390244; + vp = 4.0; + vs = 2.0; + elastic_material_data material(rho,vp,vs); + return material; + }; + + // ###################################################################### + // ###################################################################### Structure setting + // ###################################################################### + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + RealType eps = 1.0e-10; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (std::fabs(bar.y()) < eps) { + interface_face_indexes.insert(fc_id); + continue; + } + } + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + + // Assigning the material properties + if (bar.y() > 0) { + // acoustic_material_data material = water_mat_fun_adi(bar); + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + else { + // elastic_material_data material = granit_mat_fun_adi(bar); + elastic_material_data material = elastic_mat_fun(bar); + e_material.insert(std::make_pair(cell_ind,material)); + } + + // Detection of faces on the interfaces + auto cell_faces = faces(msh,cell); + for (auto face :cell_faces) { + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + if (bar.y() > 0) { + interface_cell_pair_indexes[fc_id].second = cell_ind; + } + else { + interface_cell_pair_indexes[fc_id].first = cell_ind; + } + } + } + } + + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + for (auto face_it = msh.faces_begin(); face_it != msh.faces_end(); face_it++) { + const auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + bool is_member_Q = interface_face_indexes.find(fc_id) != interface_face_indexes.end(); + if (is_member_Q) { + } + else { + if (bar.y() > 0) { + acoustic_internal_faces.insert(fc_id); + } + else { + elastic_internal_faces.insert(fc_id); + } + } + } + + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++) { + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + if (bar.y() > 0) { + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + else { + disk::boundary_descriptor bi{bc_elastic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + elastic_bc_face_indexes.insert(fc_id); + } + } + + auto null_s_fun = [](const disk::mesh>::point_type& pt) -> double { + return 0.0; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + // Boundary condition + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, null_s_fun); + + // ################################################## + // ################################################## Solving a primal HHO mixed problem + // ################################################## + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_hdg_stabilization(); + if (sim_data.m_scaled_stabilization_Q) { + assembler.set_scaled_stabilization(); + } + + tc.toc(); + std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; + std::cout << bold << cyan << " Assembler generation : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_mass(msh); + tc.toc(); + std::cout << bold << cyan << " Mass Assembly : "; + std::cout << tc << " seconds" << reset << std::endl; + + tc.tic(); + assembler.assemble_coupling_terms(msh); + tc.toc(); + std::cout << bold << cyan << " Coupling assembly : "; + std::cout << tc << " seconds" << reset << std::endl << std::endl; + + // ###################################################################### + // ###################################################################### Projecting initial data + // ###################################################################### + + auto v_fun_adi_acoustic = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + double x, y, xc, yc, r, wave, vx, vy, c, lp, fc, vp; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 0.125; // 0.1; + fc = 10.0; + c = 10; + vp = std::sqrt(1.0); + lp = vp/fc; + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + wave = (c)/(std::exp((1.0/(lp*lp))*r*r*M_PI*M_PI)); + vx = wave*(x-xc); + vy = wave*(y-yc); + disk::static_vector v{vx,vy}; + return v; + }; + + auto p_fun_ricker = [](const disk::mesh>::point_type& pt) -> double { + double x, y, xc, yc, r, fc, c, vp, lp, p0, pi2; + x = pt.x(); + y = pt.y(); + xc = 0.0; + yc = 0.15; + fc = 10.0; + c = 10.0; + vp = std::sqrt(1.0); + lp = vp / fc; // longueur caractéristique + p0 = 1.0; + pi2 = M_PI * M_PI; + + r = std::sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc)); + + double arg = pi2 * r*r / (lp*lp); + + double p = p0 * (1.0 - 2.0 * arg) * std::exp(-arg); + return p; + }; + + + Matrix x_dof; + // Acoustic pulse intialized in pressure + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, p_fun_ricker, null_fun); + assembler.project_over_faces(msh, x_dof, null_fun, p_fun_ricker); + // // Acoustic pulse intialized in velocity + // assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, null_s_fun, v_fun_adi_acoustic); + // assembler.project_over_faces(msh, x_dof, null_fun, null_s_fun); + // Elastic pulse intialized in velocity + // assembler.project_over_cells(msh, x_dof, v_fun, null_flux_fun, null_s_fun, null_fun); + // assembler.project_over_faces(msh, x_dof, v_fun, null_s_fun); + + // ################################################## + // ################################################## Solving a first order equation HDG/HHO propagation problem + // ################################################## + + Matrix a; + Matrix b; + Matrix c; + + // ERK(s) schemes + int s = 4; + erk_butcher_tableau::erk_tables(s, a, b, c); + std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; + std::cout << bold << cyan << " First stiffness assembly completed: "; + tc.tic(); + assembler.assemble(msh, null_fun, null_s_fun, true); + tc.toc(); + std::cout << bold << cyan << tc << " seconds" << reset << std::endl; + assembler.LHS += assembler.COUPLING; + assembler.assemble_P(msh, 1); + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes);//assembler.get_interfaces()); + + tc.toc(); + std::cout << bold << cyan << " ERK analysis created: " << tc << " seconds" << reset << std::endl; + tc.tic(); + erk_an.refresh_faces_unknowns(x_dof); + tc.toc(); + std::cout << bold << cyan << " Inverse of Sff + Coupling in: " << tc << " seconds" << reset << std::endl; + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "Explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log.flush(); + + if (sim_data.m_render_silo_files_Q) { + size_t it = 0; + std::ostringstream filename; + filename << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + // ################################################## + // ################################################## Sensors + // ################################################## + + bool e_side_Q = true; + bool a_side_Q = false; + + std::ostringstream filename_acou; + filename_acou << "A_explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_acou_str = filename_acou.str(); + std::ofstream Acoustic_sensor_1_log(filename_acou_str); + typename mesh_type::point_type Acoustic_s1_pt(-0.15, 0.1); + std::pair Acoustic_s1_pt_cell = std::make_pair(Acoustic_s1_pt, -1); + + std::ostringstream filename_int; + filename_int << "I_explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_int_str = filename_int.str(); + std::ofstream Interface_sensor_1_log(filename_int_str); + typename mesh_type::point_type Interface_s1_pt(-0.15, 0.0); + std::pair Interface_s1_pt_cell = std::make_pair(Interface_s1_pt, -1); + + std::ostringstream filename_ela; + filename_ela << "E_explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << ".csv"; + std::string filename_ela_str = filename_ela.str(); + std::ofstream Elastic_sensor_1_log(filename_ela_str); + typename mesh_type::point_type Elastic_s1_pt(-0.15, -0.1); + std::pair Elastic_s1_pt_cell = std::make_pair(Elastic_s1_pt, -1); + + bool sensors = false; + if (sensors) { + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(0, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(0, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + } + + std::cout << std::endl; + + // ################################################## + // ################################################## Time marching + // ################################################## + + size_t p = 1; + size_t dtau = dt / p; + auto l0 = x_dof; + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + tcit.tic(); + std::cout << bold << red << " Time step number " << it << ": t = " << t << reset << std::endl; + x_dof_n = x_dof; + size_t n_dof = x_dof.rows(); + + ////////////////////////////////////////////////////////////// COARSE PREDICTOR + std::vector> w, k; + erk_an.compute_wi(x_dof_n, s, assembler.IminusP, w, k); + + for (int m = 0; m < p; ++m) { + + auto w_stage_1 = w[0] + (m*dtau)*w[1] + (0.5*m*m*dtau*dtau)*w[2] + (m*m*m*dtau*dtau*dtau)*w[3]/6.0; + auto w_stage_2_3 = w[0] + ((m+0.5)*dtau)*w[1] + (0.5*(m+0.5)*(m+0.5)*dtau*dtau)*w[2] + ((m+0.5)*(m+0.5)*(m+0.5)*dtau*dtau*dtau)*w[3]/6.0; + auto w_stage_4 = w[0] + ((m+1.0)*dtau)*w[1] + (0.5*(m+1.0)*(m+1.0)*dtau*dtau)*w[2] + ((m+1.0)*(m+1.0)*(m+1.0)*dtau*dtau*dtau)*w[3]/6.0; + + auto y_stage_1 = assembler.P*x_dof; + erk_an.erk_lts_weight(y_stage_1, k[0], w_stage_1); + + auto y_stage_2 = assembler.P*(x_dof + dtau/2.0 * k[0]); + erk_an.erk_lts_weight(y_stage_2, k[1], w_stage_2_3); + + auto y_stage_3 = assembler.P*(x_dof + dtau/2.0 * k[1]); + erk_an.erk_lts_weight(y_stage_3, k[2], w_stage_2_3); + + auto y_stage_4 = assembler.P*(x_dof + dtau * k[2]); + erk_an.erk_lts_weight(y_stage_4, k[3], w_stage_4); + + x_dof_n = x_dof + dtau/6 * (k[0] + 2*k[1] + 2*k[2] + k[3]); + + } + x_dof = x_dof_n; + + // ################################################## + // ################################################## Last postprocess + // ################################################## + + if (sim_data.m_render_silo_files_Q) { + std::string silo_file_name = "elasto_acoustic_inhomogeneous_four_fields_"; + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + postprocessor::record_acoustic_data_elasto_acoustic_four_fields(it, Acoustic_s1_pt_cell, msh, hho_di, assembler, x_dof, a_side_Q, Acoustic_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Interface_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Interface_sensor_1_log); + postprocessor::record_velocity_data_elasto_acoustic_four_fields(it, Elastic_s1_pt_cell, msh, hho_di, assembler, x_dof, e_side_Q, Elastic_sensor_1_log); + + t += dt; + + tcit.toc(); + std::cout << bold << cyan << " Iteration completed in " << tcit << " seconds" << reset << std::endl << std::endl; + + if (it == nt) { + std::ostringstream silo; + silo << "Silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_str = silo.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_str, it, msh, hho_di, x_dof, e_material, a_material, false); + } + + + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/wave_propagation/src/prototypes/LTS/save.hpp b/apps/wave_propagation/src/prototypes/LTS/save.hpp new file mode 100644 index 00000000..e1670924 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/LTS/save.hpp @@ -0,0 +1,343 @@ + + +// Created by Romain Mottier + +// ../../elastoacoustic -k 1 -s 0 -r 0 -c 1 -p 1 -l 8 -n 1000 -f 0 -e 0 +void ELTSAcousticFirstOrder(int argc, char **argv); + +void ELTSAcousticFirstOrder(int argc, char **argv){ + + // ############################################################################################# + // ############################## Simulation paramaters ######################################## + // ############################################################################################# + + std::cout << std::endl << bold << red << " EXPLICIT ACOUSTIC CONV TEST" << reset << std::endl; + + using RealType = double; + simulation_data sim_data = preprocessor::process_args(argc, argv); + sim_data.print_simulation_data(); + timecounter tc, cpu; + + // ############################################################################################# + // ############################## Mesh generation ############################################## + // ############################################################################################# + + cpu.tic(); + + typedef disk::mesh> mesh_type; + typedef disk::BoundaryConditions e_boundary_type; + typedef disk::BoundaryConditions a_boundary_type; + mesh_type msh; + + if (sim_data.m_polygonal_mesh_Q) { + size_t l = sim_data.m_n_divs; + polygon_2d_mesh_reader mesh_builder; + std::vector mesh_files; + bool use_poly_mesh = false; + bool use_simp_mesh = false; + if (use_poly_mesh) { + for (int i = 0; i <= 9; ++i) { + mesh_files.push_back( + "../../meshes/conv_test/poly/poly_" + std::to_string(32 * (1 << i)) + ".txt" + ); + } + } + else if (use_simp_mesh) { + std::vector conv_vals = {1.0, 0.35, 0.15, 0.07, 0.035, 0.026, 0.017, 0.0125, 0.0085, 0.005}; + for (int i = 0; i < conv_vals.size(); ++i) { + mesh_files.push_back( + "../../meshes/conv_test/simplices/unstructured/l" + std::to_string(i) + + "_conv_test_" + std::to_string(conv_vals[i]) + ".txt" + ); + } + } + mesh_builder.set_poly_mesh_file(mesh_files[l]); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + mesh_builder.remove_duplicate_points(); + } + else { + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(sim_data.m_n_divs); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); + } + + RealType h = 10; + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + RealType h_l = diameter(msh, cell); + if (h_l < h) + h = h_l; + } + + + // ############################################################################################# + // ################################ Time controls ############################################## + // ############################################################################################# + + size_t nt = 10; + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + nt = sim_data.m_nt_divs; + + RealType ti = 0.0; + RealType tf = 1.0; + RealType dt = (tf-ti)/nt; + RealType t = ti; + + // ############################################################################################# + // ############################## Manufactured solution ######################################## + // ############################################################################################# + + scal_vec_analytic_functions functions; + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionCubicInTimeAcoustic); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuarticInTimeAcoustic); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpaceAcoustic); + + auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { + double x,y; + x = pt.x(); + y = pt.y(); + disk::static_matrix sigma = disk::static_matrix::Zero(2,2); + return sigma; + }; + + auto null_fun = [](const disk::mesh>::point_type& pt) -> disk::static_vector { + disk::static_vector f{0,0}; + return f; + }; + + // Acoustic analytical functions + auto s_u_fun = functions.Evaluate_s_u(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_a_fun = functions.Evaluate_s_a(t); + auto s_f_fun = functions.Evaluate_s_f(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + // ############################################################################################# + // ################################## HHO setting ############################################## + // ############################################################################################# + + // Creating HHO approximation spaces and corresponding linear operator + size_t cell_k_degree = sim_data.m_k_degree; + if (sim_data.m_hdg_stabilization_Q) { + cell_k_degree++; + } + disk::hho_degree_info hho_di(cell_k_degree, sim_data.m_k_degree); + + // ############################################################################################# + // ################################ Material data ############################################## + // ############################################################################################# + + // Classify cells per material data and bc faces + auto elastic_mat_fun = [](const typename mesh_type::point_type& pt) -> elastic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp, vs; + rho = 1.0; // Solid mass density + vp = std::sqrt(3.0); // Seismic compressional velocity vp + vs = 1.0; // Seismic shear velocity vs + elastic_material_data material(rho,vp,vs); + return material; + }; + + auto acoustic_mat_fun = [](const typename mesh_type::point_type& pt) -> acoustic_material_data { + double x,y; + x = pt.x(); + y = pt.y(); + RealType rho, vp; + rho = 1.0; // Fluid mass density + vp = 1.0; // Seismic compressional velocity vp + acoustic_material_data material(rho,vp); + return material; + }; + + // ############################################################################################# + // ############################## Boundary conditions ########################################## + // ############################################################################################# + + std::map> e_material; + std::map> a_material; + std::set elastic_bc_face_indexes, acoustic_bc_face_indexes, interface_face_indexes; + std::map> interface_cell_pair_indexes; + + for (auto & cell : msh ) { + auto cell_ind = msh.lookup(cell); + mesh_type::point_type bar = barycenter(msh, cell); + // Assigning the material properties + acoustic_material_data material = acoustic_mat_fun(bar); + a_material.insert(std::make_pair(cell_ind,material)); + } + + // Internal faces structure + std::set elastic_internal_faces; + std::set acoustic_internal_faces; + size_t bc_elastic_id = 0; + size_t bc_acoustic_id = 1; + for (auto face_it = msh.boundary_faces_begin(); face_it != msh.boundary_faces_end(); face_it++){ + auto face = *face_it; + mesh_type::point_type bar = barycenter(msh, face); + auto fc_id = msh.lookup(face); + disk::boundary_descriptor bi{bc_acoustic_id, true}; + msh.backend_storage()->boundary_info.at(fc_id) = bi; + acoustic_bc_face_indexes.insert(fc_id); + } + + e_boundary_type e_bnd(msh); + a_boundary_type a_bnd(msh); + e_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_elastic_id, null_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, s_u_fun); + + // ############################################################################################# + // ###################################### Assembly ############################################# + // ############################################################################################# + + tc.tic(); + auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); + assembler.set_interface_cell_indexes(interface_cell_pair_indexes); + assembler.set_coupling_stabilization(); + if (sim_data.m_scaled_stabilization_Q) { + assembler.set_scaled_stabilization(); + } + assembler.assemble_mass(msh); + assembler.assemble_coupling_terms(msh); + + // ############################################################################################# + // ###################### Projecting initial data ############################################## + // ############################################################################################# + + Matrix x_dof; + assembler.project_over_cells(msh, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun); + assembler.project_over_faces(msh, x_dof, null_fun, s_v_fun); + + // ############################################################################################# + // ###################################### Solving ############################################## + // ############################################################################################# + + Matrix a; + Matrix b; + Matrix c; + + // ERK schemes + int s = 4; + erk_butcher_tableau::erk_tables(s, a, b, c); + assembler.assemble(msh, null_fun, s_f_fun, true); + assembler.LHS += assembler.COUPLING; + + size_t elastic_cell_dofs = assembler.get_e_n_cells_dof(); + size_t acoustic_cell_dofs = assembler.get_a_n_cells_dof(); + size_t e_face_dofs = assembler.get_e_face_dof(); + size_t a_face_dofs = assembler.get_a_face_dof(); + + erk_coupling_hho_scheme erk_an(assembler.LHS, assembler.RHS, assembler.MASS, assembler.COUPLING, elastic_cell_dofs, acoustic_cell_dofs, e_face_dofs, a_face_dofs); + erk_an.Mcc_inverse(assembler.get_elastic_cells(), assembler.get_acoustic_cells(), assembler.get_e_cell_basis_data(), assembler.get_a_cell_basis_data()); + erk_an.Sff_inverse(assembler.get_elastic_faces(), assembler.get_acoustic_faces(), assembler.get_e_face_basis_data(), assembler.get_a_face_basis_data(), assembler.get_e_compress(), assembler.get_a_compress(), elastic_internal_faces, acoustic_internal_faces, interface_face_indexes);//assembler.get_interfaces()); + erk_an.refresh_faces_unknowns(x_dof); + + // ################################################## + // ################################################## Preprocessor + // ################################################## + + std::ostringstream filename; + filename << "explicit_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_discret_" << sim_data.m_hdg_stabilization_Q << ".txt"; + std::string filename_str = filename.str(); + std::ofstream simulation_log(filename_str); + sim_data.write_simulation_data(simulation_log); + simulation_log << "Number of ERK steps = " << s << std::endl; + simulation_log << "Number of time steps = " << nt << std::endl; + simulation_log << "Step size = " << dt << std::endl; + simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; + simulation_log << "Space step = " << h << std::endl; + simulation_log.flush(); + std::cout << std::endl << std::endl; + + size_t it = 0; + std::ostringstream filename_silo; + filename_silo << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; + std::string silo_file_name = filename_silo.str(); + postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); + + // ################################################## + // ################################################## Time marching + // ################################################## + + // DISCRTIZATION INFOS + std::cout << bold << red << " TIME LOOP: " << std::endl; + Matrix x_dof_n; + for(size_t it = 1; it <= nt; it++) { + + std::cout << bold << cyan << " Time step number " << it << ": t = " << t << reset << std::endl; + RealType tn = dt*(it-1)+ti; + + // ERK step + tc.tic(); + { + size_t n_dof = x_dof.rows(); + Matrix k = Matrix::Zero(n_dof, s); + Matrix Fg, Fg_c, xd; + xd = Matrix::Zero(n_dof, 1); + + Matrix yn, ki; + x_dof_n = x_dof; + + for (int i = 0; i < s; i++) { + yn = x_dof; + for (int j = 0; j < s - 1; j++) { + yn += a(i,j) * dt * k.block(0, j, n_dof, 1); + } + + t = tn + c(i,0) * dt; + + { + // Manufactured solution + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_f_fun = functions.Evaluate_s_f(t); + + assembler.get_e_bc_conditions().updateDirichletFunction(null_fun, 0); + assembler.get_a_bc_conditions().updateDirichletFunction(s_v_fun, 0); + assembler.assemble_rhs(msh, null_fun, s_f_fun, true); + erk_an.SetFg(assembler.RHS); + erk_an.erk_weight(yn, ki); + } + + // Accumulated solution + x_dof_n += dt*b(i,0)*ki; + k.block(0, i, n_dof, 1) = ki; + } + } + + tc.toc(); + std::cout << bold << yellow << " ERK step completed: " << tc << " seconds" << reset << std::endl; + x_dof = x_dof_n; + + t = tn + dt; + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_flux_fun = functions.Evaluate_s_q(t); + + if(it == nt){ + std::cout << std::endl; + postprocessor::compute_errors_four_fields_elastoacoustic(msh, hho_di, assembler, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun, simulation_log); + postprocessor::compute_errors_four_fields_elastoacoustic_energy_norm(msh, hho_di, assembler, x_dof, null_fun, null_flux_fun, s_v_fun, s_flux_fun, simulation_log); + } + + } + + bool mesh_quality = false; + if (mesh_quality) { + std::ofstream mesh_file("mesh_file.txt"); + postprocessor::mesh_quality(msh, assembler, mesh_file); + } + + cpu.toc(); + simulation_log << "TOTAL CPU TIME: " << cpu << std::endl; + std::cout << bold << red << " TOTAL CPU TIME: " << cpu << std::endl << std::endl; + +} + diff --git a/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_CFL.hpp b/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_CFL.hpp index be306ce0..2e607b25 100644 --- a/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_CFL.hpp +++ b/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_CFL.hpp @@ -277,7 +277,7 @@ void EAcoustic_CFL(int argc, char **argv){ simulation_log << "Number of ERK steps = " << s << std::endl; simulation_log << "Number of time steps = " << nt << std::endl; simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; - auto block_dimension = assembler.Scc_block_dimension(); + // auto block_dimension = assembler.Scc_block_dimension(); // erk_an.compute_eigenvalues_bis(assembler.LHS_STAB, block_dimension, simulation_log); // erk_an.compute_eigenvalues(simulation_log); simulation_log.flush(); diff --git a/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_conv_test.hpp b/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_conv_test.hpp index bb4afc68..925b08f7 100644 --- a/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_conv_test.hpp +++ b/apps/wave_propagation/src/prototypes/acoustic/EAcoustic_conv_test.hpp @@ -313,12 +313,6 @@ void EAcousticFirstOrder(int argc, char **argv){ simulation_log.flush(); std::cout << std::endl << std::endl; - size_t it = 0; - std::ostringstream filename_silo; - filename_silo << "silo_l_" << sim_data.m_n_divs << "_n_" << sim_data.m_nt_divs << "_k_" << sim_data.m_k_degree << "_s_" << s << "_"; - std::string silo_file_name = filename_silo.str(); - postprocessor::write_silo_four_fields_elastoacoustic(silo_file_name, it, msh, hho_di, x_dof, e_material, a_material, false); - // ################################################## // ################################################## Time marching // ################################################## @@ -342,7 +336,7 @@ void EAcousticFirstOrder(int argc, char **argv){ for (int i = 0; i < s; i++) { yn = x_dof; - for (int j = 0; j < s - 1; j++) { + for (int j = 0; j < i; j++) { yn += a(i,j) * dt * k.block(0, j, n_dof, 1); } @@ -350,8 +344,8 @@ void EAcousticFirstOrder(int argc, char **argv){ { // Manufactured solution - auto s_v_fun = functions.Evaluate_s_v(t); - auto s_f_fun = functions.Evaluate_s_f(t); + auto s_v_fun = functions.Evaluate_s_v(t); + auto s_f_fun = functions.Evaluate_s_f(t); assembler.get_e_bc_conditions().updateDirichletFunction(null_fun, 0); assembler.get_a_bc_conditions().updateDirichletFunction(s_v_fun, 0); diff --git a/apps/wave_propagation/src/prototypes/acoustic/IAcoustic_conv_test.hpp b/apps/wave_propagation/src/prototypes/acoustic/IAcoustic_conv_test.hpp index c469a10a..ecfc07e7 100644 --- a/apps/wave_propagation/src/prototypes/acoustic/IAcoustic_conv_test.hpp +++ b/apps/wave_propagation/src/prototypes/acoustic/IAcoustic_conv_test.hpp @@ -2,6 +2,8 @@ // Created by Romain Mottier +// ../wave_propagation -s1 -k3 -r1 -c1 -p0 -l4 -n7 -i0 -f1 -e0 + void IAcoustic_conv_test(int argc, char **argv); void IAcoustic_conv_test(int argc, char **argv){ @@ -121,10 +123,11 @@ void IAcoustic_conv_test(int argc, char **argv){ // ################################################## scal_vec_analytic_functions functions; - //functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); - //functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); - //functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpaceAcoustic); functions.set_function_type(scal_vec_analytic_functions::EFunctionType::reproduction_acoustic); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionPlaneWaveAcoustic); auto null_flux_fun = [](const typename disk::mesh>::point_type& pt) -> disk::static_matrix { double x,y; @@ -202,7 +205,7 @@ void IAcoustic_conv_test(int argc, char **argv){ // boundary conditions e_boundary_type e_bnd(msh); a_boundary_type a_bnd(msh); - a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, s_u_fun); + a_bnd.addDirichletBC(disk::DirichletType::DIRICHLET, bc_acoustic_id, s_v_fun); // ################################################## // ################################################## Solving a primal HHO mixed problem @@ -344,6 +347,7 @@ void IAcoustic_conv_test(int argc, char **argv){ } t = tn + c(i,0) * dt; + // Manufactured solution auto s_v_fun = functions.Evaluate_s_v(t); auto s_f_fun = functions.Evaluate_s_f(t); diff --git a/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder_conv_tests.hpp b/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder_conv_tests.hpp index d9fd3cd5..ca9aa0a9 100644 --- a/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder_conv_tests.hpp +++ b/apps/wave_propagation/src/prototypes/coupling/Conv_Tests/IHHOFirstOrder_conv_tests.hpp @@ -42,47 +42,17 @@ void IHHOFirstOrder_conv_tests(int argc, char **argv){ typedef disk::BoundaryConditions e_boundary_type; typedef disk::BoundaryConditions a_boundary_type; mesh_type msh; + + RealType lx = 2.0; + RealType ly = 1.0; + size_t nx = 4; + size_t ny = 2; + cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); + mesh_builder.refine_mesh(l); + mesh_builder.set_translation_data(-1.0, 0.0); + mesh_builder.build_mesh(); + mesh_builder.move_to_mesh_storage(msh); - if (sim_data.m_polygonal_mesh_Q) { - // Mesh availability - auto validate_l = [](size_t l) -> size_t { - if (!((0 <= l) && (l < 15))) { - std::cout << std::endl << std::endl; - std::cout << bold << red << "Warning:: Only few polygonal meshes available."; - std::cout << std::endl << std::endl; - return 4; - } - }; - // size_t l = validate_l(sim_data.m_n_divs); - polygon_2d_mesh_reader mesh_builder; - std::vector mesh_files; - mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_32.txt"); - mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_64.txt"); - mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_128.txt"); // -l 2 - mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_256.txt"); // -l 3 - mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_512.txt"); - mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_1024.txt"); // -l 5 - mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_2048.txt"); - mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_4096.txt"); // -l 7 - mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_8192.txt"); - mesh_files.push_back("../../meshes/conv_test/poly_bad_quality/poly_16384.txt"); - // Reading the polygonal mesh - mesh_builder.set_poly_mesh_file(mesh_files[l]); - mesh_builder.build_mesh(); - mesh_builder.move_to_mesh_storage(msh); - mesh_builder.remove_duplicate_points(); - } - else { - RealType lx = 2.0; - RealType ly = 1.0; - size_t nx = 4; - size_t ny = 2; - cartesian_2d_mesh_builder mesh_builder(lx,ly,nx,ny); - mesh_builder.refine_mesh(sim_data.m_n_divs); - mesh_builder.set_translation_data(-1.0, 0.0); - mesh_builder.build_mesh(); - mesh_builder.move_to_mesh_storage(msh); - } RealType h = 10; for (auto & cell : msh ) { auto cell_ind = msh.lookup(cell); @@ -97,8 +67,9 @@ void IHHOFirstOrder_conv_tests(int argc, char **argv){ // ################################################## size_t nt = 10; - for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { nt *= 2; + } RealType ti = 0.0; RealType tf = 1.0; @@ -111,18 +82,20 @@ void IHHOFirstOrder_conv_tests(int argc, char **argv){ Matrix c; int s = 3; bool is_sdirk_Q = true; - if (is_sdirk_Q) + if (is_sdirk_Q) { dirk_butcher_tableau::sdirk_tables(s, a, b, c); - else + } + else { dirk_butcher_tableau::dirk_tables(s, a, b, c); + } // ################################################## // ################################################## Manufactured solution // ################################################## scal_vec_analytic_functions functions; - // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); - functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); + functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial); + // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInTime); // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionQuadraticInSpace); // functions.set_function_type(scal_vec_analytic_functions::EFunctionType::EFunctionNonPolynomial_paper); @@ -275,8 +248,9 @@ void IHHOFirstOrder_conv_tests(int argc, char **argv){ dirk_an.SetScale(scale); dirk_an.ComposeMatrix(); bool iteratif_solver = false; // if false load library: source /opt/intel/oneapi/setvars.sh intel64 - if (iteratif_solver) + if (iteratif_solver) { dirk_an.setIterativeSolver(); + } dirk_an.DecomposeMatrix(); } diff --git a/apps/wave_propagation/src/prototypes/coupling/Pulse/HeterogeneousEHHOFirstOrder.hpp b/apps/wave_propagation/src/prototypes/coupling/Pulse/HeterogeneousEHHOFirstOrder.hpp index 5e6969a4..f1afb308 100644 --- a/apps/wave_propagation/src/prototypes/coupling/Pulse/HeterogeneousEHHOFirstOrder.hpp +++ b/apps/wave_propagation/src/prototypes/coupling/Pulse/HeterogeneousEHHOFirstOrder.hpp @@ -95,8 +95,9 @@ void HeterogeneousEHHOFirstOrder(int argc, char **argv){ // ###################################################################### size_t nt = 10; - for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) + for (unsigned int i = 0; i < sim_data.m_nt_divs; i++) { nt = sim_data.m_nt_divs; + } RealType ti = 0.0; RealType tf = 0.25; @@ -109,8 +110,9 @@ void HeterogeneousEHHOFirstOrder(int argc, char **argv){ // Creating HHO approximation spaces and corresponding linear operator size_t cell_k_degree = sim_data.m_k_degree; - if (sim_data.m_hdg_stabilization_Q) + if (sim_data.m_hdg_stabilization_Q) { cell_k_degree++; + } disk::hho_degree_info hho_di(cell_k_degree, sim_data.m_k_degree); // ################################################## @@ -285,8 +287,9 @@ void HeterogeneousEHHOFirstOrder(int argc, char **argv){ auto assembler = elastoacoustic_four_fields_assembler(msh, hho_di, e_bnd, a_bnd, e_material, a_material); assembler.set_interface_cell_indexes(interface_cell_pair_indexes); assembler.set_hdg_stabilization(); - if (sim_data.m_scaled_stabilization_Q) + if (sim_data.m_scaled_stabilization_Q) { assembler.set_scaled_stabilization(); + } tc.toc(); std::cout << bold << red << " ASSEMBLY 1 : " << std::endl; @@ -344,7 +347,7 @@ void HeterogeneousEHHOFirstOrder(int argc, char **argv){ Matrix c; // ERK(s) schemes - int s = 2; + int s = 4; erk_butcher_tableau::erk_tables(s, a, b, c); std::cout << bold << red << " ASSEMBLY 2 : " << std::endl; std::cout << bold << cyan << " First stiffness assembly completed: "; @@ -446,9 +449,7 @@ void HeterogeneousEHHOFirstOrder(int argc, char **argv){ { size_t n_dof = x_dof.rows(); Matrix k = Matrix::Zero(n_dof, s); - Matrix Fg, Fg_c, xd; - xd = Matrix::Zero(n_dof, 1); - + Matrix Fg, Fg_c; Matrix yn, ki; x_dof_n = x_dof; for (int i = 0; i < s; i++) { diff --git a/apps/wave_propagation/src/prototypes/elastic/EElastic_stability.hpp b/apps/wave_propagation/src/prototypes/elastic/EElastic_stability.hpp index 06aa2cfb..082fb497 100644 --- a/apps/wave_propagation/src/prototypes/elastic/EElastic_stability.hpp +++ b/apps/wave_propagation/src/prototypes/elastic/EElastic_stability.hpp @@ -324,7 +324,7 @@ void EElastic_stability(int argc, char **argv){ simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; simulation_log << "h size = " << h << std::endl; simulation_log << "CFL c(dt/h) = " << std::sqrt(3.0)*dt/h << std::endl; - auto block_dimension = assembler.Scc_block_dimension(); + // auto block_dimension = assembler.Scc_block_dimension(); // erk_an.compute_eigenvalues_bis(assembler.LHS_STAB, block_dimension, simulation_log); erk_an.compute_eigenvalues(simulation_log); simulation_log.flush(); diff --git a/apps/wave_propagation/src/prototypes/elastic/EElasticity_CFL.hpp b/apps/wave_propagation/src/prototypes/elastic/EElasticity_CFL.hpp index 6cf52f02..49921412 100644 --- a/apps/wave_propagation/src/prototypes/elastic/EElasticity_CFL.hpp +++ b/apps/wave_propagation/src/prototypes/elastic/EElasticity_CFL.hpp @@ -278,7 +278,7 @@ void EElasticity_CFL(int argc, char **argv){ simulation_log << "Number of ERK steps = " << s << std::endl; simulation_log << "Number of time steps = " << nt << std::endl; simulation_log << "Number of equations : " << assembler.RHS.rows() << std::endl; - auto block_dimension = assembler.Scc_block_dimension(); + // auto block_dimension = assembler.Scc_block_dimension(); // erk_an.compute_eigenvalues_bis(assembler.LHS_STAB, block_dimension, simulation_log); // erk_an.compute_eigenvalues(simulation_log); simulation_log.flush(); diff --git a/apps/wave_propagation/src/prototypes/postpro/conv_space_RK4.py b/apps/wave_propagation/src/prototypes/postpro/conv_space_RK4.py new file mode 100755 index 00000000..0d0f9488 --- /dev/null +++ b/apps/wave_propagation/src/prototypes/postpro/conv_space_RK4.py @@ -0,0 +1,79 @@ +import os +import re +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.lines import Line2D + +# --- Répertoire de travail --- +try: + script_dir = os.path.dirname(os.path.abspath(__file__)) + os.chdir(script_dir) +except: + pass + +# --- Paramètres --- +results = {k: {'h': [], 'l2': [], 'dg': []} for k in range(1, 4)} # k = 1,2,3 + +# Parcourir tous les fichiers implicit_l_*.txt +for filename in os.listdir('.'): + if not filename.startswith("implicit_l_") or not filename.endswith(".txt"): + continue + + # Extraire l et k du nom de fichier + m = re.match(r"implicit_l_(\d+)_n_\d+_k_(\d+)_s_\d+\.txt", filename) + if not m: + continue + l_number = int(m.group(1)) + k = int(m.group(2)) + if k not in results: + continue + + h = l2_error = dg_error = None + + with open(filename, 'r') as f: + lines = f.readlines() + for i, line in enumerate(lines): + # h + if "Characteristic h size" in line: + match_h = re.search(r"Characteristic h size = ([0-9.eE+-]+)", line) + if match_h: + h = float(match_h.group(1)) + + # L2 error acoustique + if line.strip() == "Acoustic region :": + if i+1 < len(lines): + match_l2 = re.search(r"L2-norm error = ([0-9.eE+-]+)", lines[i+1]) + if match_l2: + l2_error = float(match_l2.group(1)) + + # dG error acoustique + if line.strip().startswith("L2 errors of dG unknowns:"): + for j in range(i+1, min(i+5, len(lines))): + if lines[j].strip().startswith("Acoustic region :"): + try: + dg_error = float(lines[j].split(":")[1].strip()) + except: + dg_error = None + break + + if h is not None and l2_error is not None and dg_error is not None: + results[k]['h'].append(h) + results[k]['l2'].append(l2_error) + results[k]['dg'].append(dg_error) + else: + print(f"⚠️ Données manquantes dans {filename}") + +# --- Tracé --- +plt.figure(figsize=(8,8)) +styles = {1:{'color':'darkgreen','marker':'^'}, 2:{'color':'orange','marker':'s'}, 3:{'color':'darkred','marker':'o'}} +for k in results: + if results[k]['h']: + h_sorted, l2_sorted, dg_sorted = zip(*sorted(zip(results[k]['h'], results[k]['l2'], results[k]['dg']))) + plt.loglog(h_sorted, l2_sorted, marker=styles[k]['marker'], linestyle='-', color=styles[k]['color'], label=f'k={k} (L2)') + plt.loglog(h_sorted, dg_sorted, marker=styles[k]['marker'], linestyle='--', color=styles[k]['color'], alpha=0.7, label=f'k={k} (dG)') + +plt.xlabel("h") +plt.ylabel("L2 error / dG error") +plt.legend() +plt.grid(True, which='both') +plt.show() diff --git a/apps/wave_propagation/src/wave_propagation.cpp b/apps/wave_propagation/src/wave_propagation.cpp index 3f9036f3..0919a582 100644 --- a/apps/wave_propagation/src/wave_propagation.cpp +++ b/apps/wave_propagation/src/wave_propagation.cpp @@ -73,7 +73,10 @@ using namespace Eigen; #include "prototypes/coupling/Pulse/ConicWavesEHHOFirstOrder.hpp" // Implicit Pulse (geophysic) // Sedimentary Basin #include "prototypes/coupling/Basin/BassinIHHOFirstOrder.hpp" // Implicit Sedimentary Basin -// #include "prototypes/coupling/Basin/BassinEHHOFirstOrder.hpp" // Explicit Sedimentary Basin - not working +// LTS +#include "prototypes/LTS/ELTSAcoustic_conv_test.hpp" +#include "prototypes/LTS/ERK4_LTS_conv_test.hpp" +#include "prototypes/LTS/HeterogeneousERK4_LTS_HHO_FirstOrder.hpp" int main(int argc, char **argv){ @@ -90,17 +93,17 @@ int main(int argc, char **argv){ return 0; } -// CFL tables: +// CFL TABLE: // EAcoustic_CFL(argc, argv); // EElasticity_CFL(argc, argv); // EHHOFirstOrderCFL(argc, argv); - -// Stability study & Spectral radius computation: + +// STABILITY STUDY & SPECTRAL RADIUS COMPUTATION: // EAcoustic_stability(argc, argv); // EElastic_stability(argc, argv); // EHHOFirstOrder_stability(argc, argv); -// Convergence test: +// CV TESTS: // EAcousticFirstOrder(argc, argv); // IAcoustic_conv_test(argc, argv); // IElastic_conv_test(argc, argv); @@ -109,19 +112,23 @@ int main(int argc, char **argv){ // EHHOFirstOrder(argc, argv); // EHHOFirstOrder_conv_tests(argc, argv); -// Pulse: +// PULSE: // HeterogeneousIHHOFirstOrder(argc, argv); // HeterogeneousEHHOFirstOrder(argc, argv); // ConicWavesIHHOFirstOrder(argc, argv); // ConicWavesIHHOFirstOrder_review(argc, argv); // ConicWavesEHHOFirstOrder(argc, argv); - ConicWavesEHHOFirstOrder_review(argc, argv); + // ConicWavesEHHOFirstOrder_review(argc, argv); -// Sedimentary basin: +// SEDIMENTARY BASIN: // BassinIHHOFirstOrder(argc, argv); // Test(argc, argv); // BassinEHHOFirstOrder(argc, argv); Not working +// LOCAL TIME STEPPING + // ELTSAcousticFirstOrder(argc, argv); + // ERK4_LTS_conv_test(argc, argv); + HeterogeneousERK4_LTS_HHO_FirstOrder(argc, argv); } diff --git a/conv_detected.png b/conv_detected.png new file mode 100644 index 0000000000000000000000000000000000000000..ec728e176c87789ebbbe61373eabb7267f978356 GIT binary patch literal 123499 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 literal 0 HcmV?d00001 diff --git a/libdiskpp/include/diskpp/bases/bases_scalar.hpp b/libdiskpp/include/diskpp/bases/bases_scalar.hpp index be7a5936..c30db597 100644 --- a/libdiskpp/include/diskpp/bases/bases_scalar.hpp +++ b/libdiskpp/include/diskpp/bases/bases_scalar.hpp @@ -65,6 +65,8 @@ struct scaled_monomial_scalar_basis /* Basis 'factory'. */ #ifndef USE_LEGENDRE +#ifndef ORTHO_BASIS + template auto make_scalar_monomial_basis(const MeshType& msh, @@ -74,6 +76,17 @@ make_scalar_monomial_basis(const MeshType& msh, { return scaled_monomial_scalar_basis(msh, elem, degree, use_inertia_axes); } +#else +template +auto +make_scalar_monomial_basis(const MeshType& msh, + const ElementType& elem, + size_t degree, + bool use_inertia_axes = USE_INERTIA_AXES) +{ + return scaled_monomial_scalar_basis_ortho(msh, elem, degree, use_inertia_axes); +} +#endif #endif /***************************************************************************************************/ diff --git a/libdiskpp/include/diskpp/boundary_conditions/boundary_conditions.hpp b/libdiskpp/include/diskpp/boundary_conditions/boundary_conditions.hpp index 37c1fb85..ca07b678 100644 --- a/libdiskpp/include/diskpp/boundary_conditions/boundary_conditions.hpp +++ b/libdiskpp/include/diskpp/boundary_conditions/boundary_conditions.hpp @@ -311,8 +311,7 @@ class BoundaryConditions template void - addDirichletBC(const size_t& btype, const size_t& b_id, const Function& bcf) - { + addDirichletBC(const size_t& btype, const size_t& b_id, const Function& bcf) { const size_t bcf_id = m_dirichlet_func.size(); m_dirichlet_func.push_back(bcf);