diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp index efa68ed6e613c5f5ea06d96cc2281e604ca6d8d6..ea6a01fbf0752ba0a26d63711c796057d072d1fb 100644 --- a/src/language/modules/SchemeModule.cpp +++ b/src/language/modules/SchemeModule.cpp @@ -40,6 +40,7 @@ #include <scheme/IDiscreteFunctionDescriptor.hpp> #include <scheme/InflowBoundaryConditionDescriptor.hpp> #include <scheme/LocalDtAcousticSolver.hpp> +#include <scheme/LocalDtHyperelasticSolver.hpp> #include <scheme/NeumannBoundaryConditionDescriptor.hpp> #include <scheme/OutflowBoundaryConditionDescriptor.hpp> #include <scheme/SymmetryBoundaryConditionDescriptor.hpp> @@ -671,6 +672,92 @@ SchemeModule::SchemeModule() )); + this->_addBuiltinFunction("local_dt_hyperelastic_eucclhyd_solver", + std::function( + + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho1, + const std::shared_ptr<const DiscreteFunctionVariant>& u1, + const std::shared_ptr<const DiscreteFunctionVariant>& E1, + const std::shared_ptr<const DiscreteFunctionVariant>& CG1, + const std::shared_ptr<const DiscreteFunctionVariant>& aL1, + const std::shared_ptr<const DiscreteFunctionVariant>& aT1, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma1, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list1, + const std::shared_ptr<const DiscreteFunctionVariant>& rho2, + const std::shared_ptr<const DiscreteFunctionVariant>& u2, + const std::shared_ptr<const DiscreteFunctionVariant>& E2, + const std::shared_ptr<const DiscreteFunctionVariant>& CG2, + const std::shared_ptr<const DiscreteFunctionVariant>& aL2, + const std::shared_ptr<const DiscreteFunctionVariant>& aT2, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma2, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list2, + const double& mu, + const double& lambda, + const double& dt1, + const size_t& q) -> std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { + return LocalDtHyperelasticSolverHandler{getCommonMesh({rho1, u1, E1, CG1, aL1, aT1, sigma1}), + getCommonMesh({rho2, u2, E2, CG2, aL2, aT2, sigma2})} + .solver() + .apply(LocalDtHyperelasticSolverHandler::SolverType::Eucclhyd, dt1, q, rho1, rho2, u1, u2, E1, E2, CG1, CG2, aL1, aL2, aT1, aT2, + sigma1, sigma2, bc_descriptor_list1, bc_descriptor_list2, mu, lambda); + } + + )); + + this->_addBuiltinFunction("local_dt_hyperelastic_glace_solver", + std::function( + + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho1, + const std::shared_ptr<const DiscreteFunctionVariant>& u1, + const std::shared_ptr<const DiscreteFunctionVariant>& E1, + const std::shared_ptr<const DiscreteFunctionVariant>& CG1, + const std::shared_ptr<const DiscreteFunctionVariant>& aL1, + const std::shared_ptr<const DiscreteFunctionVariant>& aT1, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma1, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list1, + const std::shared_ptr<const DiscreteFunctionVariant>& rho2, + const std::shared_ptr<const DiscreteFunctionVariant>& u2, + const std::shared_ptr<const DiscreteFunctionVariant>& E2, + const std::shared_ptr<const DiscreteFunctionVariant>& CG2, + const std::shared_ptr<const DiscreteFunctionVariant>& aL2, + const std::shared_ptr<const DiscreteFunctionVariant>& aT2, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma2, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list2, + const double& mu, + const double& lambda, + const double& dt1, + const size_t& q) -> std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { + return LocalDtHyperelasticSolverHandler{getCommonMesh({rho1, u1, E1, CG1, aL1, aT1, sigma1}), + getCommonMesh({rho2, u2, E2, CG2, aL2, aT2, sigma2})} + .solver() + .apply(LocalDtHyperelasticSolverHandler::SolverType::Glace, dt1, q, rho1, rho2, u1, u2, E1, E2, CG1, CG2, aL1, aL2, aT1, aT2, + sigma1, sigma2, bc_descriptor_list1, bc_descriptor_list2, mu, lambda); + } + + )); + this->_addBuiltinFunction("apply_hyperelastic_fluxes", std::function( diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt index 3baedbfb4e0f12e073a0d97812ed104ea02bf1ff..ffcc416da0b7e104f4abdc26186748319f614bf3 100644 --- a/src/scheme/CMakeLists.txt +++ b/src/scheme/CMakeLists.txt @@ -10,4 +10,5 @@ add_library( DiscreteFunctionVectorIntegrator.cpp DiscreteFunctionVectorInterpoler.cpp LocalDtAcousticSolver.cpp + LocalDtHyperelasticSolver.cpp FluxingAdvectionSolver.cpp) diff --git a/src/scheme/LocalDtAcousticSolver.cpp b/src/scheme/LocalDtAcousticSolver.cpp index f1b43366318042fad3da83a8928352c5078863b5..978593bdfef59017ada43da915cca6cc276c395d 100644 --- a/src/scheme/LocalDtAcousticSolver.cpp +++ b/src/scheme/LocalDtAcousticSolver.cpp @@ -773,7 +773,34 @@ class LocalDtAcousticSolverHandler::LocalDtAcousticSolver final const double& gamma = 1.4; double sum_dt = 0; - do{ + // do{ + + // if(sum_dt+dt2 > dt1){ + // dt2 = dt1 - sum_dt; + // } + + // const DiscreteScalarFunction& rho_d = new_rho2->get<DiscreteScalarFunction>(); + // const DiscreteVectorFunction& u_d = new_u2->get<DiscreteVectorFunction>(); + // const DiscreteScalarFunction& E_d = new_E2->get<DiscreteScalarFunction>(); + // const DiscreteScalarFunction& eps = E_d - 0.5 * dot(u_d,u_d); + // const DiscreteScalarFunction& p_d = (gamma-1) * rho_d * eps; + // const DiscreteScalarFunction& c_d = sqrt(gamma * p_d / rho_d); + + // const std::shared_ptr<const DiscreteFunctionVariant>& new_p2 = std::make_shared<const DiscreteFunctionVariant>(p_d); + // const std::shared_ptr<const DiscreteFunctionVariant>& new_c2 = std::make_shared<const DiscreteFunctionVariant>(c_d); + + // auto [ur2,Fjr2] = compute_fluxes(solver_type,new_rho2,new_c2,new_u2,new_p2,bc_descriptor_list2,CR_ur,CR_Fjr,map2); + + // std::tie(new_m2,new_rho2,new_u2,new_E2) = apply_fluxes(dt2,new_rho2,new_u2,new_E2,ur2,Fjr2); + + // sum_dt += dt2; + // }while(sum_dt < dt1); + + for(size_t i = 0; i<q; i++){ + + if(i == q-1){ + dt2 = dt1 - sum_dt; + } const DiscreteScalarFunction& rho_d = new_rho2->get<DiscreteScalarFunction>(); const DiscreteVectorFunction& u_d = new_u2->get<DiscreteVectorFunction>(); @@ -784,13 +811,13 @@ class LocalDtAcousticSolverHandler::LocalDtAcousticSolver final const std::shared_ptr<const DiscreteFunctionVariant>& new_p2 = std::make_shared<const DiscreteFunctionVariant>(p_d); const std::shared_ptr<const DiscreteFunctionVariant>& new_c2 = std::make_shared<const DiscreteFunctionVariant>(c_d); - + auto [ur2,Fjr2] = compute_fluxes(solver_type,new_rho2,new_c2,new_u2,new_p2,bc_descriptor_list2,CR_ur,CR_Fjr,map2); std::tie(new_m2,new_rho2,new_u2,new_E2) = apply_fluxes(dt2,new_rho2,new_u2,new_E2,ur2,Fjr2); sum_dt += dt2; - }while(sum_dt < dt1); + } std::tie(new_m2,new_rho2,new_u2,new_E2) = mesh_correction(new_m1,new_m2,new_rho2,new_u2,new_E2,map1,map2); diff --git a/src/scheme/LocalDtHyperelasticSolver.cpp b/src/scheme/LocalDtHyperelasticSolver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62ff4426c3d142e462067d204f3722eddc32414f --- /dev/null +++ b/src/scheme/LocalDtHyperelasticSolver.cpp @@ -0,0 +1,1381 @@ +#include <scheme/LocalDtHyperelasticSolver.hpp> + +#include <language/utils/InterpolateItemValue.hpp> +#include <mesh/ItemValueUtils.hpp> +#include <mesh/ItemValueVariant.hpp> +#include <mesh/MeshFaceBoundary.hpp> +#include <mesh/MeshFlatNodeBoundary.hpp> +#include <mesh/MeshNodeBoundary.hpp> +#include <mesh/SubItemValuePerItemVariant.hpp> +#include <scheme/DirichletBoundaryConditionDescriptor.hpp> +#include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionUtils.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> +#include <scheme/ExternalBoundaryConditionDescriptor.hpp> +#include <scheme/FixedBoundaryConditionDescriptor.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/IDiscreteFunctionDescriptor.hpp> +#include <scheme/SymmetryBoundaryConditionDescriptor.hpp> +#include <scheme/CouplingBoundaryConditionDescriptor.hpp> +#include <utils/Socket.hpp> + +#include <variant> +#include <vector> + +template <size_t Dimension> +class LocalDtHyperelasticSolverHandler::LocalDtHyperelasticSolver final : public LocalDtHyperelasticSolverHandler::ILocalDtHyperelasticSolver +{ + private: + using Rdxd = TinyMatrix<Dimension>; + using Rd = TinyVector<Dimension>; + + using MeshType = Mesh<Connectivity<Dimension>>; + using MeshDataType = MeshData<Dimension>; + + using DiscreteScalarFunction = DiscreteFunctionP0<Dimension, const double>; + using DiscreteVectorFunction = DiscreteFunctionP0<Dimension, const Rd>; + using DiscreteTensorFunction = DiscreteFunctionP0<Dimension, const Rdxd>; + + class FixedBoundaryCondition; + class PressureBoundaryCondition; + class NormalStressBoundaryCondition; + class SymmetryBoundaryCondition; + class VelocityBoundaryCondition; + class CouplingBoundaryCondition; + + using BoundaryCondition = std::variant<FixedBoundaryCondition, + PressureBoundaryCondition, + NormalStressBoundaryCondition, + SymmetryBoundaryCondition, + VelocityBoundaryCondition, + CouplingBoundaryCondition>; + + using BoundaryConditionList = std::vector<BoundaryCondition>; + + NodeValuePerCell<const Rdxd> + _computeGlaceAjr(const MeshType& mesh, const DiscreteScalarFunction& rhoaL, const DiscreteScalarFunction& rhoaT) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + const NodeValuePerCell<const Rd> njr = mesh_data.njr(); + + NodeValuePerCell<Rdxd> Ajr{mesh.connectivity()}; + const Rdxd I = identity; + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const size_t& nb_nodes = Ajr.numberOfSubValues(j); + const double& rhoaL_j = rhoaL[j]; + const double& rhoaT_j = rhoaT[j]; + for (size_t r = 0; r < nb_nodes; ++r) { + const Rdxd& M = tensorProduct(Cjr(j, r), njr(j, r)); + Ajr(j, r) = rhoaL_j * M + rhoaT_j * (l2Norm(Cjr(j, r)) * I - M); + } + }); + + return Ajr; + } + + NodeValuePerCell<const Rdxd> + _computeEucclhydAjr(const MeshType& mesh, + const DiscreteScalarFunction& rhoaL, + const DiscreteScalarFunction& rhoaT) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const NodeValuePerFace<const Rd> Nlr = mesh_data.Nlr(); + const NodeValuePerFace<const Rd> nlr = mesh_data.nlr(); + + const auto& face_to_node_matrix = mesh.connectivity().faceToNodeMatrix(); + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + const auto& cell_to_face_matrix = mesh.connectivity().cellToFaceMatrix(); + + NodeValuePerCell<Rdxd> Ajr{mesh.connectivity()}; + + parallel_for( + Ajr.numberOfValues(), PUGS_LAMBDA(size_t jr) { Ajr[jr] = zero; }); + const Rdxd I = identity; + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + const auto& cell_faces = cell_to_face_matrix[j]; + + const double& rho_aL = rhoaL[j]; + const double& rho_aT = rhoaT[j]; + + for (size_t L = 0; L < cell_faces.size(); ++L) { + const FaceId& l = cell_faces[L]; + const auto& face_nodes = face_to_node_matrix[l]; + + auto local_node_number_in_cell = [&](NodeId node_number) { + for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) { + if (node_number == cell_nodes[i_node]) { + return i_node; + } + } + return std::numeric_limits<size_t>::max(); + }; + + for (size_t rl = 0; rl < face_nodes.size(); ++rl) { + const size_t R = local_node_number_in_cell(face_nodes[rl]); + const Rdxd& M = tensorProduct(Nlr(l, rl), nlr(l, rl)); + Ajr(j, R) += rho_aL * M + rho_aT * (l2Norm(Nlr(l, rl)) * I - M); + } + } + }); + + return Ajr; + } + + NodeValuePerCell<const Rdxd> + _computeAjr(const SolverType& solver_type, + const MeshType& mesh, + const DiscreteScalarFunction& rhoaL, + const DiscreteScalarFunction& rhoaT) const + { + if constexpr (Dimension == 1) { + return _computeGlaceAjr(mesh, rhoaL, rhoaT); + } else { + switch (solver_type) { + case SolverType::Glace: { + return _computeGlaceAjr(mesh, rhoaL, rhoaT); + } + case SolverType::Eucclhyd: { + return _computeEucclhydAjr(mesh, rhoaL, rhoaT); + } + default: { + throw UnexpectedError("invalid solver type"); + } + } + } + } + + NodeValue<Rdxd> + _computeAr(const MeshType& mesh, const NodeValuePerCell<const Rdxd>& Ajr) const + { + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + + NodeValue<Rdxd> Ar{mesh.connectivity()}; + + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { + Rdxd sum = zero; + const auto& node_to_cell = node_to_cell_matrix[r]; + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(r); + + for (size_t j = 0; j < node_to_cell.size(); ++j) { + const CellId J = node_to_cell[j]; + const unsigned int R = node_local_number_in_its_cells[j]; + sum += Ajr(J, R); + } + Ar[r] = sum; + }); + + return Ar; + } + + NodeValue<Rd> + _computeBr(const Mesh<Connectivity<Dimension>>& mesh, + const NodeValuePerCell<const Rdxd>& Ajr, + const DiscreteVectorFunction& u, + const DiscreteTensorFunction& sigma) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const NodeValuePerCell<const Rd>& Cjr = mesh_data.Cjr(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + + NodeValue<Rd> b{mesh.connectivity()}; + + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { + const auto& node_to_cell = node_to_cell_matrix[r]; + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(r); + + Rd br = zero; + for (size_t j = 0; j < node_to_cell.size(); ++j) { + const CellId J = node_to_cell[j]; + const unsigned int R = node_local_number_in_its_cells[j]; + br += Ajr(J, R) * u[J] - sigma[J] * Cjr(J, R); + } + + b[r] = br; + }); + + return b; + } + + BoundaryConditionList + _getBCList(const MeshType& mesh, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const + { + BoundaryConditionList bc_list; + + for (const auto& bc_descriptor : bc_descriptor_list) { + bool is_valid_boundary_condition = true; + + switch (bc_descriptor->type()) { + case IBoundaryConditionDescriptor::Type::symmetry: { + bc_list.emplace_back( + SymmetryBoundaryCondition(getMeshFlatNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + break; + } + case IBoundaryConditionDescriptor::Type::fixed: { + bc_list.emplace_back(FixedBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + break; + } + case IBoundaryConditionDescriptor::Type::dirichlet: { + const DirichletBoundaryConditionDescriptor& dirichlet_bc_descriptor = + dynamic_cast<const DirichletBoundaryConditionDescriptor&>(*bc_descriptor); + if (dirichlet_bc_descriptor.name() == "velocity") { + MeshNodeBoundary<Dimension> mesh_node_boundary = + getMeshNodeBoundary(mesh, dirichlet_bc_descriptor.boundaryDescriptor()); + + Array<const Rd> value_list = + InterpolateItemValue<Rd(Rd)>::template interpolate<ItemType::node>(dirichlet_bc_descriptor.rhsSymbolId(), + mesh.xr(), + mesh_node_boundary.nodeList()); + + bc_list.emplace_back(VelocityBoundaryCondition{mesh_node_boundary, value_list}); + } else if (dirichlet_bc_descriptor.name() == "pressure") { + const FunctionSymbolId pressure_id = dirichlet_bc_descriptor.rhsSymbolId(); + + if constexpr (Dimension == 1) { + MeshNodeBoundary<Dimension> mesh_node_boundary = + getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()); + + Array<const double> node_values = + InterpolateItemValue<double(Rd)>::template interpolate<ItemType::node>(pressure_id, mesh.xr(), + mesh_node_boundary.nodeList()); + + bc_list.emplace_back(PressureBoundaryCondition{mesh_node_boundary, node_values}); + } else { + MeshFaceBoundary<Dimension> mesh_face_boundary = + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()); + + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + Array<const double> face_values = + InterpolateItemValue<double(Rd)>::template interpolate<ItemType::face>(pressure_id, mesh_data.xl(), + mesh_face_boundary.faceList()); + bc_list.emplace_back(PressureBoundaryCondition{mesh_face_boundary, face_values}); + } + + } else if (dirichlet_bc_descriptor.name() == "normal-stress") { + const FunctionSymbolId normal_stress_id = dirichlet_bc_descriptor.rhsSymbolId(); + + if constexpr (Dimension == 1) { + MeshNodeBoundary<Dimension> mesh_node_boundary = + getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()); + + Array<const Rdxd> node_values = + InterpolateItemValue<Rdxd(Rd)>::template interpolate<ItemType::node>(normal_stress_id, mesh.xr(), + mesh_node_boundary.nodeList()); + + bc_list.emplace_back(NormalStressBoundaryCondition{mesh_node_boundary, node_values}); + } else { + MeshFaceBoundary<Dimension> mesh_face_boundary = + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()); + + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + Array<const Rdxd> face_values = + InterpolateItemValue<Rdxd(Rd)>::template interpolate<ItemType::face>(normal_stress_id, mesh_data.xl(), + mesh_face_boundary.faceList()); + bc_list.emplace_back(NormalStressBoundaryCondition{mesh_face_boundary, face_values}); + } + + } else { + is_valid_boundary_condition = false; + } + break; + } + case IBoundaryConditionDescriptor::Type::coupling: { + const CouplingBoundaryConditionDescriptor& coupling_bc_descriptor = dynamic_cast<const CouplingBoundaryConditionDescriptor&>(*bc_descriptor); + bc_list.emplace_back( + CouplingBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()),coupling_bc_descriptor.label())); + break; + } + default: { + is_valid_boundary_condition = false; + } + } + if (not is_valid_boundary_condition) { + std::ostringstream error_msg; + error_msg << *bc_descriptor << " is an invalid boundary condition for hyperelastic solver"; + throw NormalError(error_msg.str()); + } + } + + return bc_list; + } + + void _applyPressureBC(const BoundaryConditionList& bc_list, const MeshType& mesh, NodeValue<Rd>& br) const; + void _applyNormalStressBC(const BoundaryConditionList& bc_list, const MeshType& mesh, NodeValue<Rd>& br) const; + void _applySymmetryBC(const BoundaryConditionList& bc_list, NodeValue<Rdxd>& Ar, NodeValue<Rd>& br) const; + void _applyVelocityBC(const BoundaryConditionList& bc_list, NodeValue<Rdxd>& Ar, NodeValue<Rd>& br) const; + void _applyCouplingBC(NodeValue<Rdxd>& Ar1, + NodeValue<Rdxd>& Ar2, + NodeValue<Rd>& br1, + NodeValue<Rd>& br2, + const std::vector<NodeId>& map1, + const std::vector<NodeId>& map2) const; + void _applyCouplingBC(const MeshType& mesh, + NodeValue<Rd>& ur, + NodeValue<Rd>& CR_ur, + NodeValuePerCell<Rd>& Fjr, + NodeValuePerCell<Rd>& CR_Fjr, + const std::vector<NodeId>& map2) const; + void + _applyBoundaryConditions(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValue<Rdxd>& Ar, + NodeValue<Rd>& br) const + { + this->_applyPressureBC(bc_list, mesh, br); + this->_applyNormalStressBC(bc_list, mesh, br); + this->_applySymmetryBC(bc_list, Ar, br); + this->_applyVelocityBC(bc_list, Ar, br); + } + + NodeValue<Rd> + _computeUr(const MeshType& mesh, const NodeValue<Rdxd>& Ar, const NodeValue<Rd>& br) const + { + NodeValue<Rd> u{mesh.connectivity()}; + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { u[r] = inverse(Ar[r]) * br[r]; }); + + return u; + } + + NodeValuePerCell<Rd> + _computeFjr(const MeshType& mesh, + const NodeValuePerCell<const Rdxd>& Ajr, + const NodeValue<const Rd>& ur, + const DiscreteVectorFunction& u, + const DiscreteTensorFunction& sigma) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + + NodeValuePerCell<Rd> F{mesh.connectivity()}; + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + for (size_t r = 0; r < cell_nodes.size(); ++r) { + F(j, r) = -Ajr(j, r) * (u[j] - ur[cell_nodes[r]]) + sigma[j] * Cjr(j, r); + } + }); + + return F; + } + + std::tuple<std::vector<NodeId>, + std::vector<NodeId>> + _computeMapping(std::shared_ptr<const IMesh>& i_mesh1, + std::shared_ptr<const IMesh>& i_mesh2, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list1, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list2) const + { + const MeshType& mesh1 = dynamic_cast<const MeshType&>(*i_mesh1); + const MeshType& mesh2 = dynamic_cast<const MeshType&>(*i_mesh2); + + const BoundaryConditionList bc_list1 = this->_getBCList(mesh1, bc_descriptor_list1); + const BoundaryConditionList bc_list2 = this->_getBCList(mesh2, bc_descriptor_list2); + + std::vector<NodeId> map1; + std::vector<NodeId> map2; + + NodeValue<Rd> xr1 = copy(mesh1.xr()); + NodeValue<Rd> xr2 = copy(mesh2.xr()); + for(const auto& boundary_condition1 : bc_list1){ + std::visit([&](auto&& bc1) { + using T1 = std::decay_t<decltype(bc1)>; + if constexpr (std::is_same_v<CouplingBoundaryCondition,T1>){ + const auto& node_list1 = bc1.nodeList(); + for(const auto& boundary_condition2 : bc_list2){ + std::visit([&](auto&& bc2) { + using T2 = std::decay_t<decltype(bc2)>; + if constexpr (std::is_same_v<CouplingBoundaryCondition,T2>){ + if(bc1.label() == bc2.label()){ + const auto& node_list2 = bc2.nodeList(); + for(size_t i = 0; i<node_list1.size(); i++){ + NodeId node_id1 = node_list1[i]; + NodeId node_id2; + for(size_t j = 0; j<node_list2.size(); j++){ + node_id2 = node_list2[j]; + double err = 0; + for(size_t j = 0; j<Dimension; j++){ + err += (xr1[node_id1][j] - xr2[node_id2][j])*(xr1[node_id1][j] - xr2[node_id2][j]); + } + if(sqrt(err) < 1e-14){ + map1.push_back(node_id1); + map2.push_back(node_id2); + } + } + } + } + } + },boundary_condition2); + } + } + },boundary_condition1); + } + return std::make_tuple(map1,map2); + } + + public: + std::tuple<const std::shared_ptr<const ItemValueVariant>, const std::shared_ptr<const SubItemValuePerItemVariant>> + compute_fluxes(const SolverType& solver_type, + const std::shared_ptr<const DiscreteFunctionVariant>& rho_v, + const std::shared_ptr<const DiscreteFunctionVariant>& aL_v, + const std::shared_ptr<const DiscreteFunctionVariant>& aT_v, + const std::shared_ptr<const DiscreteFunctionVariant>& u_v, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma_v, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const + { + std::shared_ptr i_mesh = getCommonMesh({rho_v, aL_v, aT_v, u_v, sigma_v}); + if (not i_mesh) { + throw NormalError("discrete functions are not defined on the same mesh"); + } + + if (not checkDiscretizationType({rho_v, aL_v, u_v, sigma_v}, DiscreteFunctionType::P0)) { + throw NormalError("hyperelastic solver expects P0 functions"); + } + + const MeshType& mesh = dynamic_cast<const MeshType&>(*i_mesh); + const DiscreteScalarFunction& rho = rho_v->get<DiscreteScalarFunction>(); + const DiscreteVectorFunction& u = u_v->get<DiscreteVectorFunction>(); + const DiscreteScalarFunction& aL = aL_v->get<DiscreteScalarFunction>(); + const DiscreteScalarFunction& aT = aT_v->get<DiscreteScalarFunction>(); + const DiscreteTensorFunction& sigma = sigma_v->get<DiscreteTensorFunction>(); + + NodeValuePerCell<const Rdxd> Ajr = this->_computeAjr(solver_type, mesh, rho * aL, rho * aT); + + NodeValue<Rdxd> Ar = this->_computeAr(mesh, Ajr); + NodeValue<Rd> br = this->_computeBr(mesh, Ajr, u, sigma); + + const BoundaryConditionList bc_list = this->_getBCList(mesh, bc_descriptor_list); + this->_applyBoundaryConditions(bc_list, mesh, Ar, br); + + synchronize(Ar); + synchronize(br); + + NodeValue<const Rd> ur = this->_computeUr(mesh, Ar, br); + NodeValuePerCell<const Rd> Fjr = this->_computeFjr(mesh, Ajr, ur, u, sigma); + + return std::make_tuple(std::make_shared<const ItemValueVariant>(ur), + std::make_shared<const SubItemValuePerItemVariant>(Fjr)); + } + + std::tuple<const std::shared_ptr<const ItemValueVariant>, + const std::shared_ptr<const SubItemValuePerItemVariant>, + const std::shared_ptr<const ItemValueVariant>, + const std::shared_ptr<const SubItemValuePerItemVariant>, + NodeValue<Rd>, + NodeValuePerCell<Rd>> + compute_fluxes(const SolverType& solver_type, + const std::shared_ptr<const DiscreteFunctionVariant>& rho1_v, + const std::shared_ptr<const DiscreteFunctionVariant>& aL1_v, + const std::shared_ptr<const DiscreteFunctionVariant>& aT1_v, + const std::shared_ptr<const DiscreteFunctionVariant>& u1_v, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma1_v, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list1, + const std::shared_ptr<const DiscreteFunctionVariant>& rho2_v, + const std::shared_ptr<const DiscreteFunctionVariant>& aL2_v, + const std::shared_ptr<const DiscreteFunctionVariant>& aT2_v, + const std::shared_ptr<const DiscreteFunctionVariant>& u2_v, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma2_v, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list2, + const std::vector<NodeId>& map1, + const std::vector<NodeId>& map2) const + { + std::shared_ptr i_mesh1 = getCommonMesh({rho1_v, aL1_v, aT1_v, u1_v, sigma1_v}); + std::shared_ptr i_mesh2 = getCommonMesh({rho2_v, aL2_v, aT2_v, u2_v, sigma2_v}); + if (not i_mesh1) { + throw NormalError("discrete functions are not defined on the same mesh"); + } + + if (not checkDiscretizationType({rho1_v, aL1_v, u1_v, sigma1_v}, DiscreteFunctionType::P0)) { + throw NormalError("hyperelastic solver expects P0 functions"); + } + if (not i_mesh2) { + throw NormalError("discrete functions are not defined on the same mesh"); + } + + if (not checkDiscretizationType({rho2_v, aL2_v, u2_v, sigma2_v}, DiscreteFunctionType::P0)) { + throw NormalError("acoustic solver expects P0 functions"); + } + + const MeshType& mesh1 = dynamic_cast<const MeshType&>(*i_mesh1); + const DiscreteScalarFunction& rho1 = rho1_v->get<DiscreteScalarFunction>(); + const DiscreteVectorFunction& u1 = u1_v->get<DiscreteVectorFunction>(); + const DiscreteScalarFunction& aL1 = aL1_v->get<DiscreteScalarFunction>(); + const DiscreteScalarFunction& aT1 = aT1_v->get<DiscreteScalarFunction>(); + const DiscreteTensorFunction& sigma1 = sigma1_v->get<DiscreteTensorFunction>(); + + const MeshType& mesh2 = dynamic_cast<const MeshType&>(*i_mesh2); + const DiscreteScalarFunction& rho2 = rho2_v->get<DiscreteScalarFunction>(); + const DiscreteVectorFunction& u2 = u2_v->get<DiscreteVectorFunction>(); + const DiscreteScalarFunction& aL2 = aL2_v->get<DiscreteScalarFunction>(); + const DiscreteScalarFunction& aT2 = aT2_v->get<DiscreteScalarFunction>(); + const DiscreteTensorFunction& sigma2 = sigma2_v->get<DiscreteTensorFunction>(); + + + NodeValuePerCell<const Rdxd> Ajr1 = this->_computeAjr(solver_type, mesh1, rho1 * aL1, rho1 * aT1); + + NodeValuePerCell<const Rdxd> Ajr2 = this->_computeAjr(solver_type, mesh2, rho2 * aL2, rho2 * aT2); + + NodeValue<Rdxd> Ar1 = this->_computeAr(mesh1, Ajr1); + NodeValue<Rd> br1 = this->_computeBr(mesh1, Ajr1, u1, sigma1); + NodeValue<Rdxd> Ar2 = this->_computeAr(mesh2, Ajr2); + NodeValue<Rd> br2 = this->_computeBr(mesh2, Ajr2, u2, sigma2); + + const BoundaryConditionList bc_list1 = this->_getBCList(mesh1, bc_descriptor_list1); + const BoundaryConditionList bc_list2 = this->_getBCList(mesh2, bc_descriptor_list2); + this->_applyBoundaryConditions(bc_list1, mesh1, Ar1, br1); + this->_applyBoundaryConditions(bc_list2, mesh2, Ar2, br2); + this->_applyCouplingBC(Ar1,Ar2,br1,br2,map1,map2); + + synchronize(Ar1); + synchronize(br1); + synchronize(Ar2); + synchronize(br2); + + NodeValue<Rd> ur1 = this->_computeUr(mesh1, Ar1, br1); + NodeValuePerCell<Rd> Fjr1 = this->_computeFjr(mesh1, Ajr1, ur1, u1, sigma1); + NodeValue<Rd> ur2 = this->_computeUr(mesh2, Ar2, br2); + NodeValuePerCell<Rd> Fjr2 = this->_computeFjr(mesh2, Ajr2, ur2, u2, sigma2); + NodeValue<Rd> CR_ur = this->_computeUr(mesh2, Ar2, br2); + NodeValuePerCell<Rd> CR_Fjr = this->_computeFjr(mesh2, Ajr2, ur2, u2, sigma2); + + return std::make_tuple(std::make_shared<const ItemValueVariant>(ur1), + std::make_shared<const SubItemValuePerItemVariant>(Fjr1), + std::make_shared<const ItemValueVariant>(ur2), + std::make_shared<const SubItemValuePerItemVariant>(Fjr2), + CR_ur, + CR_Fjr); + } + + std::tuple<const std::shared_ptr<const ItemValueVariant>,const std::shared_ptr<const SubItemValuePerItemVariant>> + compute_fluxes(const SolverType& solver_type, + const std::shared_ptr<const DiscreteFunctionVariant>& rho_v, + const std::shared_ptr<const DiscreteFunctionVariant>& aL_v, + const std::shared_ptr<const DiscreteFunctionVariant>& aT_v, + const std::shared_ptr<const DiscreteFunctionVariant>& u_v, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma_v, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + NodeValue<Rd> CR_ur, + NodeValuePerCell<Rd> CR_Fjr, + const std::vector<NodeId> map2) const + { + std::shared_ptr i_mesh = getCommonMesh({rho_v, aL_v, aT_v, u_v, sigma_v}); + if (not i_mesh) { + throw NormalError("discrete functions are not defined on the same mesh"); + } + + if (not checkDiscretizationType({rho_v, aL_v, u_v, sigma_v}, DiscreteFunctionType::P0)) { + throw NormalError("hyperelastic solver expects P0 functions"); + } + + const MeshType& mesh = dynamic_cast<const MeshType&>(*i_mesh); + const DiscreteScalarFunction& rho = rho_v->get<DiscreteScalarFunction>(); + const DiscreteVectorFunction& u = u_v->get<DiscreteVectorFunction>(); + const DiscreteScalarFunction& aL = aL_v->get<DiscreteScalarFunction>(); + const DiscreteScalarFunction& aT = aT_v->get<DiscreteScalarFunction>(); + const DiscreteTensorFunction& sigma = sigma_v->get<DiscreteTensorFunction>(); + + NodeValuePerCell<const Rdxd> Ajr = this->_computeAjr(solver_type, mesh, rho * aL, rho * aT); + + NodeValue<Rdxd> Ar = this->_computeAr(mesh, Ajr); + NodeValue<Rd> br = this->_computeBr(mesh, Ajr, u, sigma); + + const BoundaryConditionList bc_list = this->_getBCList(mesh, bc_descriptor_list); + this->_applyBoundaryConditions(bc_list, mesh, Ar, br); + + synchronize(Ar); + synchronize(br); + + NodeValue<Rd> ur = this->_computeUr(mesh, Ar, br); + NodeValuePerCell<Rd> Fjr = this->_computeFjr(mesh, Ajr, ur, u, sigma); + + this->_applyCouplingBC(mesh,ur,CR_ur,Fjr,CR_Fjr,map2); + + return std::make_tuple(std::make_shared<const ItemValueVariant>(ur), + std::make_shared<const SubItemValuePerItemVariant>(Fjr)); + } + + std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply_fluxes(const double& dt, + const MeshType& mesh, + const DiscreteScalarFunction& rho, + const DiscreteVectorFunction& u, + const DiscreteScalarFunction& E, + const DiscreteTensorFunction& CG, + const NodeValue<const Rd>& ur, + const NodeValuePerCell<const Rd>& Fjr) const + { + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + + if ((mesh.shared_connectivity() != ur.connectivity_ptr()) or + (mesh.shared_connectivity() != Fjr.connectivity_ptr())) { + throw NormalError("fluxes are not defined on the same connectivity than the mesh"); + } + + NodeValue<Rd> new_xr = copy(mesh.xr()); + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { new_xr[r] += dt * ur[r]; }); + + std::shared_ptr<const MeshType> new_mesh = std::make_shared<MeshType>(mesh.shared_connectivity(), new_xr); + + CellValue<const double> Vj = MeshDataManager::instance().getMeshData(mesh).Vj(); + const NodeValuePerCell<const Rd> Cjr = MeshDataManager::instance().getMeshData(mesh).Cjr(); + + CellValue<double> new_rho = copy(rho.cellValues()); + CellValue<Rd> new_u = copy(u.cellValues()); + CellValue<double> new_E = copy(E.cellValues()); + CellValue<Rdxd> new_CG = copy(CG.cellValues()); + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + Rd momentum_fluxes = zero; + double energy_fluxes = 0; + Rdxd gradv = zero; + for (size_t R = 0; R < cell_nodes.size(); ++R) { + const NodeId r = cell_nodes[R]; + gradv += tensorProduct(ur[r], Cjr(j, R)); + momentum_fluxes += Fjr(j, R); + energy_fluxes += dot(Fjr(j, R), ur[r]); + } + const Rdxd cauchy_green_fluxes = gradv * CG[j] + CG[j] * transpose(gradv); + const double dt_over_Mj = dt / (rho[j] * Vj[j]); + const double dt_over_Vj = dt / Vj[j]; + new_u[j] += dt_over_Mj * momentum_fluxes; + new_E[j] += dt_over_Mj * energy_fluxes; + new_CG[j] += dt_over_Vj * cauchy_green_fluxes; + new_CG[j] += transpose(new_CG[j]); + new_CG[j] *= 0.5; + }); + + CellValue<const double> new_Vj = MeshDataManager::instance().getMeshData(*new_mesh).Vj(); + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { new_rho[j] *= Vj[j] / new_Vj[j]; }); + + return {new_mesh, std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_rho)), + std::make_shared<DiscreteFunctionVariant>(DiscreteVectorFunction(new_mesh, new_u)), + std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_E)), + std::make_shared<DiscreteFunctionVariant>(DiscreteTensorFunction(new_mesh, new_CG))}; + } + + std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply_fluxes(const double& dt, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& CG, + const std::shared_ptr<const ItemValueVariant>& ur, + const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr) const + { + std::shared_ptr i_mesh = getCommonMesh({rho, u, E}); + if (not i_mesh) { + throw NormalError("discrete functions are not defined on the same mesh"); + } + + if (not checkDiscretizationType({rho, u, E}, DiscreteFunctionType::P0)) { + throw NormalError("hyperelastic solver expects P0 functions"); + } + + return this->apply_fluxes(dt, // + dynamic_cast<const MeshType&>(*i_mesh), // + rho->get<DiscreteScalarFunction>(), // + u->get<DiscreteVectorFunction>(), // + E->get<DiscreteScalarFunction>(), // + CG->get<DiscreteTensorFunction>(), // + ur->get<NodeValue<const Rd>>(), // + Fjr->get<NodeValuePerCell<const Rd>>()); + } + + std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + mesh_correction(const MeshType& mesh1, + const MeshType& mesh2, + const DiscreteScalarFunction& rho, + const DiscreteVectorFunction& u, + const DiscreteScalarFunction& E, + const DiscreteTensorFunction& CG, + std::vector<NodeId>& map1, + std::vector<NodeId>& map2) const + { + NodeValue<Rd> xr1 = copy(mesh1.xr()); + NodeValue<Rd> new_xr2 = copy(mesh2.xr()); + + size_t n = map1.size(); + + for(size_t i = 0; i<n; i++){ + for(size_t j = 0; j<Dimension; j++){ + new_xr2[map2[i]][j] = xr1[map1[i]][j]; + } + } + + std::shared_ptr<const MeshType> new_mesh2 = std::make_shared<MeshType>(mesh2.shared_connectivity(), new_xr2); + + CellValue<double> new_rho = copy(rho.cellValues()); + CellValue<Rd> new_u = copy(u.cellValues()); + CellValue<double> new_E = copy(E.cellValues()); + CellValue<Rdxd> new_CG = copy(CG.cellValues()); + + return {new_mesh2,std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh2, new_rho)), + std::make_shared<DiscreteFunctionVariant>(DiscreteVectorFunction(new_mesh2, new_u)), + std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh2, new_E)), + std::make_shared<DiscreteFunctionVariant>(DiscreteTensorFunction(new_mesh2,new_CG))}; + } + + std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + mesh_correction(const std::shared_ptr<const IMesh>& i_mesh1, + const std::shared_ptr<const IMesh>& i_mesh2, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& CG, + std::vector<NodeId>& map1, + std::vector<NodeId>& map2) const + { + + return this->mesh_correction(dynamic_cast<const MeshType&>(*i_mesh1), + dynamic_cast<const MeshType&>(*i_mesh2), + rho->get<DiscreteScalarFunction>(), + u->get<DiscreteVectorFunction>(), + E->get<DiscreteScalarFunction>(), + CG->get<DiscreteTensorFunction>(), + map1, + map2); + } + + std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply(const SolverType& solver_type, + const double& dt1, + const size_t& q, + const std::shared_ptr<const DiscreteFunctionVariant>& rho1, + const std::shared_ptr<const DiscreteFunctionVariant>& rho2, + const std::shared_ptr<const DiscreteFunctionVariant>& u1, + const std::shared_ptr<const DiscreteFunctionVariant>& u2, + const std::shared_ptr<const DiscreteFunctionVariant>& E1, + const std::shared_ptr<const DiscreteFunctionVariant>& E2, + const std::shared_ptr<const DiscreteFunctionVariant>& CG1, + const std::shared_ptr<const DiscreteFunctionVariant>& CG2, + const std::shared_ptr<const DiscreteFunctionVariant>& aL1, + const std::shared_ptr<const DiscreteFunctionVariant>& aL2, + const std::shared_ptr<const DiscreteFunctionVariant>& aT1, + const std::shared_ptr<const DiscreteFunctionVariant>& aT2, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma1, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma2, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list1, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list2, + const double& mu, + const double& lambda) const + { + std::shared_ptr<const IMesh> new_m2 = getCommonMesh({rho2, aL2, aT2, u2, sigma2}); + std::shared_ptr<const IMesh> m1 = getCommonMesh({rho1, aL1, aT1, u1, sigma1}); + + std::shared_ptr<const DiscreteFunctionVariant> new_rho2 = rho2; + std::shared_ptr<const DiscreteFunctionVariant> new_u2 = u2; + std::shared_ptr<const DiscreteFunctionVariant> new_E2 = E2; + std::shared_ptr<const DiscreteFunctionVariant> new_CG2 = CG2; + + auto [map1,map2] = _computeMapping(m1,new_m2,bc_descriptor_list1,bc_descriptor_list2); + + auto [ur1, Fjr1, ur2, Fjr2, CR_ur, CR_Fjr] = compute_fluxes(solver_type, rho1, aL1, aT1, u1, sigma1, bc_descriptor_list1, rho2, aL2, aT2, u2, sigma2, bc_descriptor_list2, map1, map2); + const auto [new_m1,new_rho1,new_u1,new_E1,new_CG1] = apply_fluxes(dt1, rho1, u1, E1, CG1, ur1, Fjr1); + + double dt2 = dt1/q; + const double gamma = 1.4; + const TinyMatrix<Dimension> I = identity; + double sum_dt = 0; + + size_t fluid = 0; + if((mu == 0) and (lambda == 0)){ + fluid = 1; + } + + for(size_t i = 0; i<q; i++){ + + if(i == q-1){ + dt2 = dt1 - sum_dt; + } + + if(i == 0){ + const DiscreteScalarFunction& rho_d = new_rho2->get<DiscreteScalarFunction>(); + const DiscreteVectorFunction& u_d = new_u2->get<DiscreteVectorFunction>(); + const DiscreteScalarFunction& E_d = new_E2->get<DiscreteScalarFunction>(); + const DiscreteScalarFunction& eps = E_d - 0.5 * dot(u_d,u_d); + // const DiscreteTensorFunction& sigma_d = -(gamma - 1) * rho_d * eps * I; + // const DiscreteScalarFunction& aL_d = sqrt(gamma*(gamma-1)*eps); + // const DiscreteScalarFunction& aT_d = 0 * aL_d; + const DiscreteTensorFunction& CG_d = new_CG2->get<DiscreteTensorFunction>(); + const DiscreteScalarFunction& p = fluid*(gamma - 1)*rho_d*eps; + const DiscreteTensorFunction& sigma_d = mu/sqrt(det(CG_d))* (CG_d - I) + lambda/sqrt(det(CG_d)) * log(sqrt(det(CG_d))) * I - p * I; + const DiscreteScalarFunction& aL_d = sqrt(lambda+2*mu/rho_d + gamma * p / rho_d); + const DiscreteScalarFunction& aT_d = sqrt(mu/rho_d); + + const std::shared_ptr<const DiscreteFunctionVariant>& new_sigma2 = std::make_shared<const DiscreteFunctionVariant>(sigma_d); + const std::shared_ptr<const DiscreteFunctionVariant>& new_aL2 = std::make_shared<const DiscreteFunctionVariant>(aL_d); + const std::shared_ptr<const DiscreteFunctionVariant>& new_aT2 = std::make_shared<const DiscreteFunctionVariant>(aT_d); + + auto [ur2,Fjr2] = compute_fluxes(solver_type,new_rho2,new_aL2,new_aT2,new_u2,new_sigma2,bc_descriptor_list2,CR_ur,CR_Fjr,map2); + } + + std::tie(new_m2,new_rho2,new_u2,new_E2,new_CG2) = apply_fluxes(dt2,new_rho2,new_u2,new_E2,new_CG2,ur2,Fjr2); + + sum_dt += dt2; + } + + std::tie(new_m2,new_rho2,new_u2,new_E2,new_CG2) = mesh_correction(new_m1,new_m2,new_rho2,new_u2,new_E2,new_CG2,map1,map2); + + return {new_m1,new_rho1,new_u1,new_E1,new_CG1,new_m2,new_rho2,new_u2,new_E2,new_CG2}; + } + + LocalDtHyperelasticSolver() = default; + LocalDtHyperelasticSolver(LocalDtHyperelasticSolver&&) = default; + ~LocalDtHyperelasticSolver() = default; +}; + +template <size_t Dimension> +void + LocalDtHyperelasticSolverHandler:: LocalDtHyperelasticSolver<Dimension>::_applyPressureBC(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValue<Rd>& br) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<PressureBoundaryCondition, T>) { + MeshData<Dimension>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + if constexpr (Dimension == 1) { + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + + const auto& node_list = bc.nodeList(); + const auto& value_list = bc.valueList(); + parallel_for( + node_list.size(), PUGS_LAMBDA(size_t i_node) { + const NodeId node_id = node_list[i_node]; + const auto& node_cell_list = node_to_cell_matrix[node_id]; + Assert(node_cell_list.size() == 1); + + CellId node_cell_id = node_cell_list[0]; + size_t node_local_number_in_cell = node_local_numbers_in_their_cells(node_id, 0); + + br[node_id] -= value_list[i_node] * Cjr(node_cell_id, node_local_number_in_cell); + }); + } else { + const NodeValuePerFace<const Rd> Nlr = mesh_data.Nlr(); + + const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix(); + const auto& face_to_node_matrix = mesh.connectivity().faceToNodeMatrix(); + const auto& face_local_numbers_in_their_cells = mesh.connectivity().faceLocalNumbersInTheirCells(); + const auto& face_cell_is_reversed = mesh.connectivity().cellFaceIsReversed(); + + const auto& face_list = bc.faceList(); + const auto& value_list = bc.valueList(); + for (size_t i_face = 0; i_face < face_list.size(); ++i_face) { + const FaceId face_id = face_list[i_face]; + const auto& face_cell_list = face_to_cell_matrix[face_id]; + Assert(face_cell_list.size() == 1); + + CellId face_cell_id = face_cell_list[0]; + size_t face_local_number_in_cell = face_local_numbers_in_their_cells(face_id, 0); + + const double sign = face_cell_is_reversed(face_cell_id, face_local_number_in_cell) ? -1 : 1; + + const auto& face_nodes = face_to_node_matrix[face_id]; + + for (size_t i_node = 0; i_node < face_nodes.size(); ++i_node) { + NodeId node_id = face_nodes[i_node]; + br[node_id] -= sign * value_list[i_face] * Nlr(face_id, i_node); + } + } + } + } + }, + boundary_condition); + } +} + +template <size_t Dimension> +void + LocalDtHyperelasticSolverHandler:: LocalDtHyperelasticSolver<Dimension>::_applyNormalStressBC(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValue<Rd>& br) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<NormalStressBoundaryCondition, T>) { + MeshData<Dimension>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + if constexpr (Dimension == 1) { + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + + const auto& node_list = bc.nodeList(); + const auto& value_list = bc.valueList(); + parallel_for( + node_list.size(), PUGS_LAMBDA(size_t i_node) { + const NodeId node_id = node_list[i_node]; + const auto& node_cell_list = node_to_cell_matrix[node_id]; + Assert(node_cell_list.size() == 1); + + CellId node_cell_id = node_cell_list[0]; + size_t node_local_number_in_cell = node_local_numbers_in_their_cells(node_id, 0); + + br[node_id] += value_list[i_node] * Cjr(node_cell_id, node_local_number_in_cell); + }); + } else { + const NodeValuePerFace<const Rd> Nlr = mesh_data.Nlr(); + + const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix(); + const auto& face_to_node_matrix = mesh.connectivity().faceToNodeMatrix(); + const auto& face_local_numbers_in_their_cells = mesh.connectivity().faceLocalNumbersInTheirCells(); + const auto& face_cell_is_reversed = mesh.connectivity().cellFaceIsReversed(); + + const auto& face_list = bc.faceList(); + const auto& value_list = bc.valueList(); + for (size_t i_face = 0; i_face < face_list.size(); ++i_face) { + const FaceId face_id = face_list[i_face]; + const auto& face_cell_list = face_to_cell_matrix[face_id]; + Assert(face_cell_list.size() == 1); + + CellId face_cell_id = face_cell_list[0]; + size_t face_local_number_in_cell = face_local_numbers_in_their_cells(face_id, 0); + + const double sign = face_cell_is_reversed(face_cell_id, face_local_number_in_cell) ? -1 : 1; + + const auto& face_nodes = face_to_node_matrix[face_id]; + + for (size_t i_node = 0; i_node < face_nodes.size(); ++i_node) { + NodeId node_id = face_nodes[i_node]; + br[node_id] += sign * value_list[i_face] * Nlr(face_id, i_node); + } + } + } + } + }, + boundary_condition); + } +} + +template <size_t Dimension> +void + LocalDtHyperelasticSolverHandler:: LocalDtHyperelasticSolver<Dimension>::_applySymmetryBC(const BoundaryConditionList& bc_list, + NodeValue<Rdxd>& Ar, + NodeValue<Rd>& br) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<SymmetryBoundaryCondition, T>) { + const Rd& n = bc.outgoingNormal(); + + const Rdxd I = identity; + const Rdxd nxn = tensorProduct(n, n); + const Rdxd P = I - nxn; + + const Array<const NodeId>& node_list = bc.nodeList(); + parallel_for( + bc.numberOfNodes(), PUGS_LAMBDA(int r_number) { + const NodeId r = node_list[r_number]; + + Ar[r] = P * Ar[r] * P + nxn; + br[r] = P * br[r]; + }); + } + }, + boundary_condition); + } +} + +template <size_t Dimension> +void + LocalDtHyperelasticSolverHandler:: LocalDtHyperelasticSolver<Dimension>::_applyVelocityBC(const BoundaryConditionList& bc_list, + NodeValue<Rdxd>& Ar, + NodeValue<Rd>& br) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<VelocityBoundaryCondition, T>) { + const auto& node_list = bc.nodeList(); + const auto& value_list = bc.valueList(); + + parallel_for( + node_list.size(), PUGS_LAMBDA(size_t i_node) { + NodeId node_id = node_list[i_node]; + const auto& value = value_list[i_node]; + + Ar[node_id] = identity; + br[node_id] = value; + }); + } else if constexpr (std::is_same_v<FixedBoundaryCondition, T>) { + const auto& node_list = bc.nodeList(); + parallel_for( + node_list.size(), PUGS_LAMBDA(size_t i_node) { + NodeId node_id = node_list[i_node]; + + Ar[node_id] = identity; + br[node_id] = zero; + }); + } + }, + boundary_condition); + } +} + +template <size_t Dimension> +void LocalDtHyperelasticSolverHandler::LocalDtHyperelasticSolver<Dimension>::_applyCouplingBC(NodeValue<Rdxd>& Ar1, + NodeValue<Rdxd>& Ar2, + NodeValue<Rd>& br1, + NodeValue<Rd>& br2, + const std::vector<NodeId>& map1, + const std::vector<NodeId>& map2) const +{ + size_t n = map1.size(); + + for(size_t i = 0; i<n; i++){ + + NodeId node_id1 = map1[i]; + NodeId node_id2 = map2[i]; + + Ar1[node_id1] += Ar2[node_id2]; + Ar2[node_id2] = Ar1[node_id1]; + + br1[node_id1] += br2[node_id2]; + br2[node_id2] = br1[node_id1]; + + } +} + +template <size_t Dimension> +void LocalDtHyperelasticSolverHandler::LocalDtHyperelasticSolver<Dimension>::_applyCouplingBC(const MeshType& mesh, + NodeValue<Rd>& ur, + NodeValue<Rd>& CR_ur, + NodeValuePerCell<Rd>& Fjr, + NodeValuePerCell<Rd>& CR_Fjr, + const std::vector<NodeId>& map2) const +{ + const size_t& n = map2.size(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + + for(size_t i = 0; i<n; i++){ + + const NodeId node_id = map2[i]; + const auto& node_to_cell = node_to_cell_matrix[node_id]; + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(node_id); + + for(size_t j = 0; j < node_to_cell.size(); j++){ + const CellId J = node_to_cell[j]; + const unsigned int R = node_local_number_in_its_cells[j]; + Fjr(J,R) = CR_Fjr(J,R); + } + ur[node_id] = CR_ur[node_id]; + } +} + +template <size_t Dimension> +class LocalDtHyperelasticSolverHandler::LocalDtHyperelasticSolver<Dimension>::FixedBoundaryCondition +{ + private: + const MeshNodeBoundary<Dimension> m_mesh_node_boundary; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + FixedBoundaryCondition(const MeshNodeBoundary<Dimension> mesh_node_boundary) + : m_mesh_node_boundary{mesh_node_boundary} + {} + + ~FixedBoundaryCondition() = default; +}; + +template <size_t Dimension> +class LocalDtHyperelasticSolverHandler::LocalDtHyperelasticSolver<Dimension>::PressureBoundaryCondition +{ + private: + const MeshFaceBoundary<Dimension> m_mesh_face_boundary; + const Array<const double> m_value_list; + + public: + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + const Array<const double>& + valueList() const + { + return m_value_list; + } + + PressureBoundaryCondition(const MeshFaceBoundary<Dimension>& mesh_face_boundary, + const Array<const double>& value_list) + : m_mesh_face_boundary{mesh_face_boundary}, m_value_list{value_list} + {} + + ~PressureBoundaryCondition() = default; +}; + +template <> +class LocalDtHyperelasticSolverHandler::LocalDtHyperelasticSolver<1>::PressureBoundaryCondition +{ + private: + const MeshNodeBoundary<1> m_mesh_node_boundary; + const Array<const double> m_value_list; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const double>& + valueList() const + { + return m_value_list; + } + + PressureBoundaryCondition(const MeshNodeBoundary<1>& mesh_node_boundary, const Array<const double>& value_list) + : m_mesh_node_boundary{mesh_node_boundary}, m_value_list{value_list} + {} + + ~PressureBoundaryCondition() = default; +}; + +template <size_t Dimension> +class LocalDtHyperelasticSolverHandler:: LocalDtHyperelasticSolver<Dimension>::NormalStressBoundaryCondition +{ + private: + const MeshFaceBoundary<Dimension> m_mesh_face_boundary; + const Array<const Rdxd> m_value_list; + + public: + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + const Array<const Rdxd>& + valueList() const + { + return m_value_list; + } + + NormalStressBoundaryCondition(const MeshFaceBoundary<Dimension>& mesh_face_boundary, + const Array<const Rdxd>& value_list) + : m_mesh_face_boundary{mesh_face_boundary}, m_value_list{value_list} + {} + + ~NormalStressBoundaryCondition() = default; +}; + +template <> +class LocalDtHyperelasticSolverHandler::LocalDtHyperelasticSolver<1>::NormalStressBoundaryCondition +{ + private: + const MeshNodeBoundary<1> m_mesh_node_boundary; + const Array<const Rdxd> m_value_list; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const Rdxd>& + valueList() const + { + return m_value_list; + } + + NormalStressBoundaryCondition(const MeshNodeBoundary<1>& mesh_node_boundary, const Array<const Rdxd>& value_list) + : m_mesh_node_boundary{mesh_node_boundary}, m_value_list{value_list} + {} + + ~NormalStressBoundaryCondition() = default; +}; + +template <size_t Dimension> +class LocalDtHyperelasticSolverHandler::LocalDtHyperelasticSolver<Dimension>::VelocityBoundaryCondition +{ + private: + const MeshNodeBoundary<Dimension> m_mesh_node_boundary; + + const Array<const TinyVector<Dimension>> m_value_list; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const TinyVector<Dimension>>& + valueList() const + { + return m_value_list; + } + + VelocityBoundaryCondition(const MeshNodeBoundary<Dimension>& mesh_node_boundary, + const Array<const TinyVector<Dimension>>& value_list) + : m_mesh_node_boundary{mesh_node_boundary}, m_value_list{value_list} + {} + + ~VelocityBoundaryCondition() = default; +}; + +template <size_t Dimension> +class LocalDtHyperelasticSolverHandler::LocalDtHyperelasticSolver<Dimension>::SymmetryBoundaryCondition +{ + public: + using Rd = TinyVector<Dimension, double>; + + private: + const MeshFlatNodeBoundary<Dimension> m_mesh_flat_node_boundary; + + public: + const Rd& + outgoingNormal() const + { + return m_mesh_flat_node_boundary.outgoingNormal(); + } + + size_t + numberOfNodes() const + { + return m_mesh_flat_node_boundary.nodeList().size(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_flat_node_boundary.nodeList(); + } + + SymmetryBoundaryCondition(const MeshFlatNodeBoundary<Dimension>& mesh_flat_node_boundary) + : m_mesh_flat_node_boundary(mesh_flat_node_boundary) + { + ; + } + + ~SymmetryBoundaryCondition() = default; +}; + +template <size_t Dimension> +class LocalDtHyperelasticSolverHandler::LocalDtHyperelasticSolver<Dimension>::CouplingBoundaryCondition +{ + private: + const MeshNodeBoundary<Dimension> m_mesh_node_boundary; + const size_t m_label; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + size_t + label() const { + return m_label; + } + + CouplingBoundaryCondition(const MeshNodeBoundary<Dimension>& mesh_node_boundary,const size_t label) + : m_mesh_node_boundary{mesh_node_boundary}, m_label{label} + { + ; + } + + ~CouplingBoundaryCondition() = default; + +}; + +LocalDtHyperelasticSolverHandler:: LocalDtHyperelasticSolverHandler(const std::shared_ptr<const IMesh>& i_mesh1, const std::shared_ptr<const IMesh>& i_mesh2) +{ + if (not i_mesh1) { + throw NormalError("mesh1 not defined"); + } + + if (not i_mesh2) { + throw NormalError("mesh2 not defined"); + } + + if (not (i_mesh1->dimension()==i_mesh2->dimension())) { + throw NormalError("mesh1 and mesh2 must have the same dimension"); + } + + switch (i_mesh1->dimension()) { + case 1: { + m_hyperelastic_solver = std::make_unique<LocalDtHyperelasticSolver<1>>(); + break; + } + case 2: { + m_hyperelastic_solver = std::make_unique<LocalDtHyperelasticSolver<2>>(); + break; + } + case 3: { + m_hyperelastic_solver = std::make_unique<LocalDtHyperelasticSolver<3>>(); + break; + } + default: { + throw UnexpectedError("invalid mesh dimension"); + } + } +} diff --git a/src/scheme/LocalDtHyperelasticSolver.hpp b/src/scheme/LocalDtHyperelasticSolver.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8cc83e5d468f913817facc76d210d4e003b44ffc --- /dev/null +++ b/src/scheme/LocalDtHyperelasticSolver.hpp @@ -0,0 +1,104 @@ +#ifndef LOCAL_DT_HYPERELASTIC_SOLVER_HPP +#define LOCAL_DT_HYPERELASTIC_SOLVER_HPP + +#include <memory> +#include <tuple> +#include <vector> + +class IBoundaryConditionDescriptor; +class IMesh; +class ItemValueVariant; +class SubItemValuePerItemVariant; +class DiscreteFunctionVariant; + +class LocalDtHyperelasticSolverHandler +{ + public: + enum class SolverType + { + Glace, + Eucclhyd + }; + + private: + struct ILocalDtHyperelasticSolver + { + virtual std::tuple<const std::shared_ptr<const ItemValueVariant>, + const std::shared_ptr<const SubItemValuePerItemVariant>> + compute_fluxes( + const SolverType& solver_type, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& aL, + const std::shared_ptr<const DiscreteFunctionVariant>& aT, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const = 0; + + virtual std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply_fluxes(const double& dt, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& CG, + const std::shared_ptr<const ItemValueVariant>& ur, + const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr) const = 0; + + virtual std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply(const SolverType& solver_type, + const double& dt1, + const size_t& q, + const std::shared_ptr<const DiscreteFunctionVariant>& rho1, + const std::shared_ptr<const DiscreteFunctionVariant>& rho2, + const std::shared_ptr<const DiscreteFunctionVariant>& u1, + const std::shared_ptr<const DiscreteFunctionVariant>& u2, + const std::shared_ptr<const DiscreteFunctionVariant>& E1, + const std::shared_ptr<const DiscreteFunctionVariant>& E2, + const std::shared_ptr<const DiscreteFunctionVariant>& CG1, + const std::shared_ptr<const DiscreteFunctionVariant>& CG2, + const std::shared_ptr<const DiscreteFunctionVariant>& aL1, + const std::shared_ptr<const DiscreteFunctionVariant>& aL2, + const std::shared_ptr<const DiscreteFunctionVariant>& aT1, + const std::shared_ptr<const DiscreteFunctionVariant>& aT2, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma1, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma2, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list1, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list2, + const double& mu, + const double& lambda) const = 0; + + ILocalDtHyperelasticSolver() = default; + ILocalDtHyperelasticSolver(ILocalDtHyperelasticSolver&&) = default; + ILocalDtHyperelasticSolver& operator=(ILocalDtHyperelasticSolver&&) = default; + + virtual ~ILocalDtHyperelasticSolver() = default; + }; + + template <size_t Dimension> + class LocalDtHyperelasticSolver; + + std::unique_ptr<ILocalDtHyperelasticSolver> m_hyperelastic_solver; + + public: + const ILocalDtHyperelasticSolver& + solver() const + { + return *m_hyperelastic_solver; + } + + LocalDtHyperelasticSolverHandler(const std::shared_ptr<const IMesh>& mesh1, const std::shared_ptr<const IMesh>& mesh2); +}; + +#endif // HYPERELASTIC_SOLVER_HPP