diff --git a/CMakeLists.txt b/CMakeLists.txt index 127b72af3dbdccab17393fb27568ba7b3bdc23db..73cda5739485b07c04c44c93ae6f4e9533d0f055 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -425,6 +425,7 @@ target_link_libraries( PugsLanguage PugsLanguageAST PugsLanguageModules + PugsLanguageAlgorithms PugsMesh PugsUtils PugsLanguageUtils diff --git a/src/algebra/BiCGStab.hpp b/src/algebra/BiCGStab.hpp index c931385b214c91ca2807db4f07fca027ebd79b25..bc822668a7f63c4d5d7cc4c45f4d1b1d70084fc0 100644 --- a/src/algebra/BiCGStab.hpp +++ b/src/algebra/BiCGStab.hpp @@ -5,14 +5,19 @@ #include <iomanip> #include <iostream> +#include <rang.hpp> + +template <bool verbose = true> struct BiCGStab { template <typename VectorType, typename MatrixType> BiCGStab(const VectorType& b, const MatrixType& A, VectorType& x, const size_t max_iter, const double epsilon = 1e-6) { - std::cout << "- bi-conjugate gradient stabilized\n"; - std::cout << " epsilon = " << epsilon << '\n'; - std::cout << " maximum number of iterations: " << max_iter << '\n'; + if constexpr (verbose) { + std::cout << "- bi-conjugate gradient stabilized\n"; + std::cout << " epsilon = " << epsilon << '\n'; + std::cout << " maximum number of iterations: " << max_iter << '\n'; + } VectorType r_k_1{b.size()}; @@ -33,10 +38,14 @@ struct BiCGStab VectorType r_k{x.size()}; - std::cout << " initial residu: " << resid0 << '\n'; + if constexpr (verbose) { + std::cout << " initial residu: " << resid0 << '\n'; + } for (size_t i = 1; i <= max_iter; ++i) { - std::cout << " - iteration: " << std::setw(6) << i << "\tresidu: " << residu / resid0 - << "\tabsolute: " << residu << '\n'; + if constexpr (verbose) { + std::cout << " - iteration: " << std::setw(6) << i << "\tresidu: " << residu / resid0 + << "\tabsolute: " << residu << '\n'; + } Ap_k = A * p_k; @@ -64,14 +73,14 @@ struct BiCGStab } if (residu / resid0 > epsilon) { - std::cout << " bi_conjugate gradient stabilized: *NOT CONVERGED*\n"; + std::cout << " bi-conjugate gradient stabilized: " << rang::fgB::red << "*NOT CONVERGED*" << rang::style::reset + << '\n'; + ; std::cout << " - epsilon: " << epsilon << '\n'; std::cout << " - relative residu : " << residu / resid0 << '\n'; std::cout << " - absolute residu : " << residu << '\n'; } } - - std::cout << "- bi-conjugate gradient stabilized: done\n"; } }; diff --git a/src/algebra/PCG.hpp b/src/algebra/PCG.hpp index 74c17ee40971b96c512c196d630f1edfadfa6ddc..36a4635b313d2bba13d97e1b7a4ea1882e2a66a2 100644 --- a/src/algebra/PCG.hpp +++ b/src/algebra/PCG.hpp @@ -4,6 +4,9 @@ #include <iomanip> #include <iostream> +#include <rang.hpp> + +template <bool verbose = true> struct PCG { template <typename VectorType, typename MatrixType, typename PreconditionerType> @@ -14,14 +17,16 @@ struct PCG const size_t maxiter, const double epsilon = 1e-6) { - std::cout << "- conjugate gradient\n"; - std::cout << " epsilon = " << epsilon << '\n'; - std::cout << " maximum number of iterations: " << maxiter << '\n'; + if constexpr (verbose) { + std::cout << "- conjugate gradient\n"; + std::cout << " epsilon = " << epsilon << '\n'; + std::cout << " maximum number of iterations: " << maxiter << '\n'; + } VectorType h{f.size()}; VectorType b = copy(f); - if (true) { + if constexpr (verbose) { h = A * x; h -= f; std::cout << "- initial *real* residu : " << (h, h) << '\n'; @@ -69,10 +74,14 @@ struct PCG if ((i == 1) && (gcg != 0)) { relativeEpsilon = epsilon * gcg; gcg0 = gcg; - std::cout << " initial residu: " << gcg << '\n'; + if constexpr (verbose) { + std::cout << " initial residu: " << gcg << '\n'; + } + } + if constexpr (verbose) { + std::cout << " - iteration " << std::setw(6) << i << "\tresidu: " << gcg / gcg0; + std::cout << "\tabsolute: " << gcg << '\n'; } - std::cout << " - iteration " << std::setw(6) << i << "\tresidu: " << gcg / gcg0; - std::cout << "\tabsolute: " << gcg << '\n'; if (gcg < relativeEpsilon) { break; @@ -85,7 +94,7 @@ struct PCG } if (gcg > relativeEpsilon) { - std::cout << " conjugate gradient: *NOT CONVERGED*\n"; + std::cout << " conjugate gradient: " << rang::fgB::red << "*NOT CONVERGED*" << rang::style::reset << '\n'; std::cout << " - epsilon: " << epsilon << '\n'; std::cout << " - relative residu : " << gcg / gcg0 << '\n'; std::cout << " - absolute residu : " << gcg << '\n'; diff --git a/src/algebra/SparseMatrixDescriptor.hpp b/src/algebra/SparseMatrixDescriptor.hpp index 3533a4017011b0c5c1f5d7f04ae2b893fa8a7d0b..100000366d3bd0e5a072084864e82cdb4b73ba29 100644 --- a/src/algebra/SparseMatrixDescriptor.hpp +++ b/src/algebra/SparseMatrixDescriptor.hpp @@ -28,14 +28,16 @@ class SparseMatrixDescriptor return m_id_value_map.size(); } - const DataType& operator[](const IndexType& j) const + const DataType& + operator[](const IndexType& j) const { auto i_value = m_id_value_map.find(j); Assert(i_value != m_id_value_map.end()); return i_value->second; } - DataType& operator[](const IndexType& j) + DataType& + operator[](const IndexType& j) { auto i_value = m_id_value_map.find(j); if (i_value != m_id_value_map.end()) { @@ -51,7 +53,7 @@ class SparseMatrixDescriptor operator<<(std::ostream& os, const SparseRowDescriptor& row) { for (auto [j, value] : row.m_id_value_map) { - os << ' ' << j << ':' << value; + os << ' ' << static_cast<size_t>(j) << ':' << value; } return os; } @@ -73,24 +75,30 @@ class SparseMatrixDescriptor SparseRowDescriptor& row(const IndexType i) { + Assert(i < m_row_array.size()); return m_row_array[i]; } const SparseRowDescriptor& row(const IndexType i) const { + Assert(i < m_row_array.size()); return m_row_array[i]; } DataType& operator()(const IndexType& i, const IndexType& j) { + Assert(i < m_row_array.size()); + Assert(j < m_row_array.size()); return m_row_array[i][j]; } const DataType& operator()(const IndexType& i, const IndexType& j) const { + Assert(i < m_row_array.size()); + Assert(j < m_row_array.size()); const auto& r = m_row_array[i]; // split to ensure const-ness of call return r[j]; } @@ -99,7 +107,7 @@ class SparseMatrixDescriptor operator<<(std::ostream& os, const SparseMatrixDescriptor& M) { for (IndexType i = 0; i < M.m_row_array.size(); ++i) { - os << i << " |" << M.m_row_array[i] << '\n'; + os << static_cast<size_t>(i) << " |" << M.m_row_array[i] << '\n'; } return os; } diff --git a/src/language/CMakeLists.txt b/src/language/CMakeLists.txt index b9c6094e4403cb1d2289d8cfcae58de9e2e3c4e5..3565082161700da019088f7bfca70b0d9dfe6fd8 100644 --- a/src/language/CMakeLists.txt +++ b/src/language/CMakeLists.txt @@ -1,5 +1,6 @@ # ------------------- Source files -------------------- +add_subdirectory(algorithms) add_subdirectory(ast) add_subdirectory(modules) add_subdirectory(node_processor) @@ -12,6 +13,7 @@ add_library( # Additional dependencies add_dependencies(PugsLanguage PugsLanguage + PugsLanguageAlgorithms PugsLanguageAST PugsLanguageModules PugsLanguageUtils diff --git a/src/language/algorithms/AcousticSolverAlgorithm.cpp b/src/language/algorithms/AcousticSolverAlgorithm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9811c90f0b0f2c52d5f72369efea4a4398f007e3 --- /dev/null +++ b/src/language/algorithms/AcousticSolverAlgorithm.cpp @@ -0,0 +1,245 @@ +#include <language/algorithms/AcousticSolverAlgorithm.hpp> + +#include <language/utils/InterpolateItemValue.hpp> +#include <output/VTKWriter.hpp> +#include <scheme/AcousticSolver.hpp> +#include <scheme/DirichletBoundaryConditionDescriptor.hpp> +#include <scheme/IBoundaryDescriptor.hpp> +#include <scheme/SymmetryBoundaryConditionDescriptor.hpp> + +template <size_t Dimension> +AcousticSolverAlgorithm<Dimension>::AcousticSolverAlgorithm( + const AcousticSolverType& solver_type, + std::shared_ptr<const IMesh> i_mesh, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + const FunctionSymbolId& rho_id, + const FunctionSymbolId& u_id, + const FunctionSymbolId& p_id) +{ + using ConnectivityType = Connectivity<Dimension>; + using MeshType = Mesh<ConnectivityType>; + using MeshDataType = MeshData<Dimension>; + using UnknownsType = FiniteVolumesEulerUnknowns<MeshType>; + + std::shared_ptr<const MeshType> mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); + + typename AcousticSolver<MeshType>::BoundaryConditionList bc_list; + { + constexpr ItemType FaceType = [] { + if constexpr (Dimension > 1) { + return ItemType::face; + } else { + return ItemType::node; + } + }(); + + for (const auto& bc_descriptor : bc_descriptor_list) { + bool is_valid_boundary_condition = true; + + switch (bc_descriptor->type()) { + case IBoundaryConditionDescriptor::Type::symmetry: { + using SymmetryBoundaryCondition = typename AcousticSolver<MeshType>::SymmetryBoundaryCondition; + + const SymmetryBoundaryConditionDescriptor& sym_bc_descriptor = + dynamic_cast<const SymmetryBoundaryConditionDescriptor&>(*bc_descriptor); + for (size_t i_ref_face_list = 0; + i_ref_face_list < mesh->connectivity().template numberOfRefItemList<FaceType>(); ++i_ref_face_list) { + const auto& ref_face_list = mesh->connectivity().template refItemList<FaceType>(i_ref_face_list); + const RefId& ref = ref_face_list.refId(); + if (ref == sym_bc_descriptor.boundaryDescriptor()) { + bc_list.push_back( + SymmetryBoundaryCondition{MeshFlatNodeBoundary<MeshType::Dimension>(mesh, ref_face_list)}); + } + } + is_valid_boundary_condition = true; + break; + } + + case IBoundaryConditionDescriptor::Type::dirichlet: { + const DirichletBoundaryConditionDescriptor& dirichlet_bc_descriptor = + dynamic_cast<const DirichletBoundaryConditionDescriptor&>(*bc_descriptor); + if (dirichlet_bc_descriptor.name() == "velocity") { + using VelocityBoundaryCondition = typename AcousticSolver<MeshType>::VelocityBoundaryCondition; + + for (size_t i_ref_face_list = 0; + i_ref_face_list < mesh->connectivity().template numberOfRefItemList<FaceType>(); ++i_ref_face_list) { + const auto& ref_face_list = mesh->connectivity().template refItemList<FaceType>(i_ref_face_list); + const RefId& ref = ref_face_list.refId(); + if (ref == dirichlet_bc_descriptor.boundaryDescriptor()) { + MeshNodeBoundary<Dimension> mesh_node_boundary{mesh, ref_face_list}; + + const FunctionSymbolId velocity_id = dirichlet_bc_descriptor.rhsSymbolId(); + + const auto& node_list = mesh_node_boundary.nodeList(); + + Array<const TinyVector<Dimension>> value_list = InterpolateItemValue<TinyVector<Dimension>( + TinyVector<Dimension>)>::template interpolate<ItemType::node>(velocity_id, mesh->xr(), node_list); + + bc_list.push_back(VelocityBoundaryCondition{node_list, value_list}); + } + } + } else if (dirichlet_bc_descriptor.name() == "pressure") { + using PressureBoundaryCondition = typename AcousticSolver<MeshType>::PressureBoundaryCondition; + + for (size_t i_ref_face_list = 0; + i_ref_face_list < mesh->connectivity().template numberOfRefItemList<FaceType>(); ++i_ref_face_list) { + const auto& ref_face_list = mesh->connectivity().template refItemList<FaceType>(i_ref_face_list); + const RefId& ref = ref_face_list.refId(); + if (ref == dirichlet_bc_descriptor.boundaryDescriptor()) { + const auto& face_list = ref_face_list.list(); + + const FunctionSymbolId pressure_id = dirichlet_bc_descriptor.rhsSymbolId(); + + Array<const double> face_values = [&] { + if constexpr (Dimension == 1) { + return InterpolateItemValue<double( + TinyVector<Dimension>)>::template interpolate<FaceType>(pressure_id, mesh->xr(), face_list); + } else { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*mesh); + + return InterpolateItemValue<double( + TinyVector<Dimension>)>::template interpolate<FaceType>(pressure_id, mesh_data.xl(), face_list); + } + }(); + + bc_list.push_back(PressureBoundaryCondition{face_list, face_values}); + } + } + } else { + is_valid_boundary_condition = false; + } + 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 acoustic solver"; + throw NormalError(error_msg.str()); + } + } + } + + UnknownsType unknowns(*mesh); + + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*mesh); + + unknowns.rhoj() = + InterpolateItemValue<double(TinyVector<Dimension>)>::template interpolate<ItemType::cell>(rho_id, mesh_data.xj()); + + unknowns.pj() = + InterpolateItemValue<double(TinyVector<Dimension>)>::template interpolate<ItemType::cell>(p_id, mesh_data.xj()); + + unknowns.uj() = + InterpolateItemValue<TinyVector<Dimension>(TinyVector<Dimension>)>::template interpolate<ItemType::cell>(u_id, + mesh_data + .xj()); + } + unknowns.gammaj().fill(1.4); + + AcousticSolver acoustic_solver(mesh, bc_list, solver_type); + + const double tmax = 0.2; + double t = 0; + + int itermax = std::numeric_limits<int>::max(); + int iteration = 0; + + CellValue<double>& rhoj = unknowns.rhoj(); + CellValue<double>& ej = unknowns.ej(); + CellValue<double>& pj = unknowns.pj(); + CellValue<double>& gammaj = unknowns.gammaj(); + CellValue<double>& cj = unknowns.cj(); + CellValue<TinyVector<Dimension>>& uj = unknowns.uj(); + CellValue<double>& Ej = unknowns.Ej(); + CellValue<double>& mj = unknowns.mj(); + CellValue<double>& inv_mj = unknowns.invMj(); + + BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj); + block_eos.updateEandCFromRhoP(); + + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*mesh); + + const CellValue<const double> Vj = mesh_data.Vj(); + + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { Ej[j] = ej[j] + 0.5 * (uj[j], uj[j]); }); + + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { mj[j] = rhoj[j] * Vj[j]; }); + + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { inv_mj[j] = 1. / mj[j]; }); + } + + VTKWriter vtk_writer("mesh_" + std::to_string(Dimension), 0.01); + + while ((t < tmax) and (iteration < itermax)) { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*mesh); + + vtk_writer.write(mesh, + {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, + NamedItemValue{"coords", mesh->xr()}, NamedItemValue{"xj", mesh_data.xj()}, + NamedItemValue{"cell_owner", mesh->connectivity().cellOwner()}, + NamedItemValue{"node_owner", mesh->connectivity().nodeOwner()}}, + t); + + double dt = 0.4 * acoustic_solver.acoustic_dt(mesh_data.Vj(), cj); + if (t + dt > tmax) { + dt = tmax - t; + } + + std::cout.setf(std::cout.scientific); + std::cout << "iteration " << rang::fg::cyan << std::setw(4) << iteration << rang::style::reset + << " time=" << rang::fg::green << t << rang::style::reset << " dt=" << rang::fgB::blue << dt + << rang::style::reset << '\n'; + + mesh = acoustic_solver.computeNextStep(dt, unknowns); + + block_eos.updatePandCFromRhoE(); + + t += dt; + ++iteration; + } + std::cout << rang::style::bold << "Final time=" << rang::fgB::green << t << rang::style::reset << " reached after " + << rang::fgB::cyan << iteration << rang::style::reset << rang::style::bold << " iterations" + << rang::style::reset << '\n'; + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*mesh); + + vtk_writer.write(mesh, + {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, + NamedItemValue{"coords", mesh->xr()}, NamedItemValue{"xj", mesh_data.xj()}, + NamedItemValue{"cell_owner", mesh->connectivity().cellOwner()}, + NamedItemValue{"node_owner", mesh->connectivity().nodeOwner()}}, + t, true); // forces last output + } +} + +template AcousticSolverAlgorithm<1>::AcousticSolverAlgorithm( + const AcousticSolverType&, + std::shared_ptr<const IMesh>, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&, + const FunctionSymbolId&, + const FunctionSymbolId&, + const FunctionSymbolId&); + +template AcousticSolverAlgorithm<2>::AcousticSolverAlgorithm( + const AcousticSolverType&, + std::shared_ptr<const IMesh>, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&, + const FunctionSymbolId&, + const FunctionSymbolId&, + const FunctionSymbolId&); + +template AcousticSolverAlgorithm<3>::AcousticSolverAlgorithm( + const AcousticSolverType&, + std::shared_ptr<const IMesh>, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&, + const FunctionSymbolId&, + const FunctionSymbolId&, + const FunctionSymbolId&); diff --git a/src/language/algorithms/AcousticSolverAlgorithm.hpp b/src/language/algorithms/AcousticSolverAlgorithm.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a6973480c4cd913c6463d39012f6eea906540003 --- /dev/null +++ b/src/language/algorithms/AcousticSolverAlgorithm.hpp @@ -0,0 +1,20 @@ +#ifndef ACOUSTIC_SOLVER_ALGORITHM_HPP +#define ACOUSTIC_SOLVER_ALGORITHM_HPP + +#include <language/utils/FunctionSymbolId.hpp> +#include <mesh/IMesh.hpp> +#include <scheme/AcousticSolverType.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> + +template <size_t Dimension> +struct AcousticSolverAlgorithm +{ + AcousticSolverAlgorithm(const AcousticSolverType& solver_type, + std::shared_ptr<const IMesh> i_mesh, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + const FunctionSymbolId& rho_id, + const FunctionSymbolId& u_id, + const FunctionSymbolId& p_id); +}; + +#endif // ACOUSTIC_SOLVER_ALGORITHM_HPP diff --git a/src/language/algorithms/CMakeLists.txt b/src/language/algorithms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a8599f575058185b5ceeed0814b242ae6ec70b0a --- /dev/null +++ b/src/language/algorithms/CMakeLists.txt @@ -0,0 +1,10 @@ +# ------------------- Source files -------------------- + +add_library(PugsLanguageAlgorithms + AcousticSolverAlgorithm.cpp +) + + +add_dependencies(PugsLanguageAlgorithms + PugsUtils + PugsMesh) diff --git a/src/language/modules/CMakeLists.txt b/src/language/modules/CMakeLists.txt index 703f19857cfb99c0053aecf1af0984dab371d72e..f8cf2f0b445882a672d54e60dbc75858bbb246c7 100644 --- a/src/language/modules/CMakeLists.txt +++ b/src/language/modules/CMakeLists.txt @@ -11,5 +11,6 @@ add_library(PugsLanguageModules add_dependencies(PugsLanguageModules + PugsLanguageAlgorithms PugsUtils PugsMesh) diff --git a/src/language/modules/MeshModule.cpp b/src/language/modules/MeshModule.cpp index b9a65729637128081a7206ad6fa5d98ad95e9978..89e678c3fb4095350842b19a9145502cd7f558a8 100644 --- a/src/language/modules/MeshModule.cpp +++ b/src/language/modules/MeshModule.cpp @@ -9,7 +9,7 @@ #include <language/utils/TypeDescriptor.hpp> #include <mesh/CartesianMeshBuilder.hpp> #include <mesh/Connectivity.hpp> -#include <mesh/DiamondDualMeshBuilder.hpp> +#include <mesh/DiamondDualMeshManager.hpp> #include <mesh/GmshReader.hpp> #include <mesh/Mesh.hpp> #include <utils/Exceptions.hpp> @@ -184,9 +184,30 @@ MeshModule::MeshModule() std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IMesh>( const std::shared_ptr<const IMesh>&)>>( - [](const std::shared_ptr<const IMesh>& p_mesh) -> std::shared_ptr<const IMesh> { - DiamondDualMeshBuilder builder{p_mesh}; - return builder.mesh(); + [](const std::shared_ptr<const IMesh>& i_mesh) -> std::shared_ptr<const IMesh> { + switch (i_mesh->dimension()) { + case 1: { + using MeshType = Mesh<Connectivity<1>>; + + std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); + return DiamondDualMeshManager::instance().getDiamondDualMesh(p_mesh); + } + case 2: { + using MeshType = Mesh<Connectivity<2>>; + + std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); + return DiamondDualMeshManager::instance().getDiamondDualMesh(p_mesh); + } + case 3: { + using MeshType = Mesh<Connectivity<3>>; + + std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); + return DiamondDualMeshManager::instance().getDiamondDualMesh(p_mesh); + } + default: { + throw UnexpectedError("invalid dimension"); + } + } } )); diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp index c04f29ad41df122df252cdc9e7009b49241e8ed2..542690a4ffcfb73ba174f0014b358548208d830f 100644 --- a/src/language/modules/SchemeModule.cpp +++ b/src/language/modules/SchemeModule.cpp @@ -1,215 +1,21 @@ #include <language/modules/SchemeModule.hpp> +#include <language/algorithms/AcousticSolverAlgorithm.hpp> #include <language/utils/BuiltinFunctionEmbedder.hpp> #include <language/utils/TypeDescriptor.hpp> #include <mesh/Mesh.hpp> -#include <scheme/AcousticSolver.hpp> +#include <scheme/DirichletBoundaryConditionDescriptor.hpp> +#include <scheme/FourierBoundaryConditionDescriptor.hpp> +#include <scheme/FreeBoundaryConditionDescriptor.hpp> #include <scheme/IBoundaryConditionDescriptor.hpp> #include <scheme/IBoundaryDescriptor.hpp> #include <scheme/NamedBoundaryDescriptor.hpp> +#include <scheme/NeumannBoundaryConditionDescriptor.hpp> #include <scheme/NumberedBoundaryDescriptor.hpp> #include <scheme/SymmetryBoundaryConditionDescriptor.hpp> #include <memory> -/////////// TEMPORARY - -#include <language/utils/PugsFunctionAdapter.hpp> -#include <output/VTKWriter.hpp> - -template <typename T> -class InterpolateItemValue; -template <typename OutputType, typename InputType> -class InterpolateItemValue<OutputType(InputType)> : public PugsFunctionAdapter<OutputType(InputType)> -{ - static constexpr size_t Dimension = OutputType::Dimension; - using Adapter = PugsFunctionAdapter<OutputType(InputType)>; - - public: - template <ItemType item_type> - static inline ItemValue<OutputType, item_type> - interpolate(const FunctionSymbolId& function_symbol_id, const ItemValue<const InputType, item_type>& position) - { - auto& expression = Adapter::getFunctionExpression(function_symbol_id); - auto convert_result = Adapter::getResultConverter(expression.m_data_type); - - Array<ExecutionPolicy> context_list = Adapter::getContextList(expression); - - using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; - Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; - const IConnectivity& connectivity = *position.connectivity_ptr(); - - ItemValue<OutputType, item_type> value(connectivity); - using ItemId = ItemIdT<item_type>; - - parallel_for(connectivity.template numberOf<item_type>(), [=, &expression, &tokens](ItemId i) { - const int32_t t = tokens.acquire(); - - auto& execution_policy = context_list[t]; - - Adapter::convertArgs(execution_policy.currentContext(), position[i]); - auto result = expression.execute(execution_policy); - value[i] = convert_result(std::move(result)); - - tokens.release(t); - }); - - return value; - } -}; - -template <size_t Dimension> -struct GlaceScheme -{ - using ConnectivityType = Connectivity<Dimension>; - using MeshType = Mesh<ConnectivityType>; - using MeshDataType = MeshData<Dimension>; - using UnknownsType = FiniteVolumesEulerUnknowns<MeshType>; - - std::shared_ptr<const MeshType> m_mesh; - - GlaceScheme(std::shared_ptr<const IMesh> i_mesh, - const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, - const FunctionSymbolId& rho_id, - const FunctionSymbolId& u_id, - const FunctionSymbolId& p_id) - : m_mesh{std::dynamic_pointer_cast<const MeshType>(i_mesh)} - { - std::cout << "number of bc descr = " << bc_descriptor_list.size() << '\n'; - - std::vector<BoundaryConditionHandler> bc_list; - { - constexpr ItemType FaceType = [] { - if constexpr (Dimension > 1) { - return ItemType::face; - } else { - return ItemType::node; - } - }(); - - for (const auto& bc_descriptor : bc_descriptor_list) { - switch (bc_descriptor->type()) { - case IBoundaryConditionDescriptor::Type::symmetry: { - const SymmetryBoundaryConditionDescriptor& sym_bc_descriptor = - dynamic_cast<const SymmetryBoundaryConditionDescriptor&>(*bc_descriptor); - for (size_t i_ref_face_list = 0; - i_ref_face_list < m_mesh->connectivity().template numberOfRefItemList<FaceType>(); ++i_ref_face_list) { - const auto& ref_face_list = m_mesh->connectivity().template refItemList<FaceType>(i_ref_face_list); - const RefId& ref = ref_face_list.refId(); - if (ref == sym_bc_descriptor.boundaryDescriptor()) { - SymmetryBoundaryCondition<MeshType::Dimension>* sym_bc = - new SymmetryBoundaryCondition<MeshType::Dimension>( - MeshFlatNodeBoundary<MeshType::Dimension>(m_mesh, ref_face_list)); - std::shared_ptr<SymmetryBoundaryCondition<MeshType::Dimension>> bc(sym_bc); - bc_list.push_back(BoundaryConditionHandler(bc)); - } - } - break; - } - default: { - throw UnexpectedError("Unknown BCDescription\n"); - } - } - } - } - - UnknownsType unknowns(*m_mesh); - - { - MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh); - - unknowns.rhoj() = - InterpolateItemValue<double(TinyVector<Dimension>)>::template interpolate<ItemType::cell>(rho_id, - mesh_data.xj()); - - unknowns.pj() = - InterpolateItemValue<double(TinyVector<Dimension>)>::template interpolate<ItemType::cell>(p_id, mesh_data.xj()); - - unknowns.uj() = InterpolateItemValue<TinyVector<Dimension>( - TinyVector<Dimension>)>::template interpolate<ItemType::cell>(u_id, mesh_data.xj()); - } - unknowns.gammaj().fill(1.4); - - AcousticSolver acoustic_solver(m_mesh, bc_list); - - const double tmax = 0.2; - double t = 0; - - int itermax = std::numeric_limits<int>::max(); - int iteration = 0; - - CellValue<double>& rhoj = unknowns.rhoj(); - CellValue<double>& ej = unknowns.ej(); - CellValue<double>& pj = unknowns.pj(); - CellValue<double>& gammaj = unknowns.gammaj(); - CellValue<double>& cj = unknowns.cj(); - CellValue<TinyVector<Dimension>>& uj = unknowns.uj(); - CellValue<double>& Ej = unknowns.Ej(); - CellValue<double>& mj = unknowns.mj(); - CellValue<double>& inv_mj = unknowns.invMj(); - - BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj); - block_eos.updateEandCFromRhoP(); - - { - MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh); - - const CellValue<const double> Vj = mesh_data.Vj(); - - parallel_for( - m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { Ej[j] = ej[j] + 0.5 * (uj[j], uj[j]); }); - - parallel_for( - m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { mj[j] = rhoj[j] * Vj[j]; }); - - parallel_for( - m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { inv_mj[j] = 1. / mj[j]; }); - } - - VTKWriter vtk_writer("mesh_" + std::to_string(Dimension), 0.01); - - while ((t < tmax) and (iteration < itermax)) { - MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh); - - vtk_writer.write(m_mesh, - {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, - NamedItemValue{"coords", m_mesh->xr()}, NamedItemValue{"xj", mesh_data.xj()}, - NamedItemValue{"cell_owner", m_mesh->connectivity().cellOwner()}, - NamedItemValue{"node_owner", m_mesh->connectivity().nodeOwner()}}, - t); - double dt = 0.4 * acoustic_solver.acoustic_dt(mesh_data.Vj(), cj); - if (t + dt > tmax) { - dt = tmax - t; - } - - std::cout.setf(std::cout.scientific); - std::cout << "iteration " << rang::fg::cyan << std::setw(4) << iteration << rang::style::reset - << " time=" << rang::fg::green << t << rang::style::reset << " dt=" << rang::fgB::blue << dt - << rang::style::reset << '\n'; - - m_mesh = acoustic_solver.computeNextStep(dt, unknowns); - - block_eos.updatePandCFromRhoE(); - - t += dt; - ++iteration; - } - std::cout << rang::style::bold << "Final time=" << rang::fgB::green << t << rang::style::reset << " reached after " - << rang::fgB::cyan << iteration << rang::style::reset << rang::style::bold << " iterations" - << rang::style::reset << '\n'; - { - MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh); - - vtk_writer.write(m_mesh, - {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()}, - NamedItemValue{"coords", m_mesh->xr()}, NamedItemValue{"xj", mesh_data.xj()}, - NamedItemValue{"cell_owner", m_mesh->connectivity().cellOwner()}, - NamedItemValue{"node_owner", m_mesh->connectivity().nodeOwner()}}, - t, true); // forces last output - } - } -}; - SchemeModule::SchemeModule() { this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IBoundaryDescriptor>>); @@ -247,6 +53,34 @@ SchemeModule::SchemeModule() )); + this->_addBuiltinFunction("pressure", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr< + const IBoundaryConditionDescriptor>(std::shared_ptr<const IBoundaryDescriptor>, + const FunctionSymbolId&)>>( + + [](std::shared_ptr<const IBoundaryDescriptor> boundary, + const FunctionSymbolId& pressure_id) + -> std::shared_ptr<const IBoundaryConditionDescriptor> { + return std::make_shared<DirichletBoundaryConditionDescriptor>("pressure", boundary, + pressure_id); + } + + )); + + this->_addBuiltinFunction("velocity", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr< + const IBoundaryConditionDescriptor>(std::shared_ptr<const IBoundaryDescriptor>, + const FunctionSymbolId&)>>( + + [](std::shared_ptr<const IBoundaryDescriptor> boundary, + const FunctionSymbolId& velocity_id) + -> std::shared_ptr<const IBoundaryConditionDescriptor> { + return std::make_shared<DirichletBoundaryConditionDescriptor>("velocity", boundary, + velocity_id); + } + + )); + this->_addBuiltinFunction("glace", std::make_shared<BuiltinFunctionEmbedder< void(std::shared_ptr<const IMesh>, @@ -260,15 +94,77 @@ SchemeModule::SchemeModule() const FunctionSymbolId& p_id) -> void { switch (p_mesh->dimension()) { case 1: { - GlaceScheme<1>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id}; + AcousticSolverAlgorithm<1>{AcousticSolverType::Glace, + p_mesh, + bc_descriptor_list, + rho_id, + u_id, + p_id}; + break; + } + case 2: { + AcousticSolverAlgorithm<2>{AcousticSolverType::Glace, + p_mesh, + bc_descriptor_list, + rho_id, + u_id, + p_id}; + break; + } + case 3: { + AcousticSolverAlgorithm<3>{AcousticSolverType::Glace, + p_mesh, + bc_descriptor_list, + rho_id, + u_id, + p_id}; + break; + } + default: { + throw UnexpectedError("invalid mesh dimension"); + } + } + } + + )); + + this->_addBuiltinFunction("eucclhyd", + std::make_shared<BuiltinFunctionEmbedder< + void(std::shared_ptr<const IMesh>, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&, + const FunctionSymbolId&, const FunctionSymbolId&, const FunctionSymbolId&)>>( + + [](std::shared_ptr<const IMesh> p_mesh, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list, + const FunctionSymbolId& rho_id, const FunctionSymbolId& u_id, + const FunctionSymbolId& p_id) -> void { + switch (p_mesh->dimension()) { + case 1: { + AcousticSolverAlgorithm<1>{AcousticSolverType::Eucclhyd, + p_mesh, + bc_descriptor_list, + rho_id, + u_id, + p_id}; break; } case 2: { - GlaceScheme<2>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id}; + AcousticSolverAlgorithm<2>{AcousticSolverType::Eucclhyd, + p_mesh, + bc_descriptor_list, + rho_id, + u_id, + p_id}; break; } case 3: { - GlaceScheme<3>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id}; + AcousticSolverAlgorithm<3>{AcousticSolverType::Eucclhyd, + p_mesh, + bc_descriptor_list, + rho_id, + u_id, + p_id}; break; } default: { diff --git a/src/language/modules/VTKModule.cpp b/src/language/modules/VTKModule.cpp index f815a78e763b387ee5707d9ac65ec1f038a36b14..ce84141ee866f7ac6fdbb8448db78d0d1b64de88 100644 --- a/src/language/modules/VTKModule.cpp +++ b/src/language/modules/VTKModule.cpp @@ -24,7 +24,10 @@ VTKModule::VTKModule() const std::shared_ptr<const MeshType> mesh = std::dynamic_pointer_cast<const MeshType>(p_mesh); - writer.write(mesh, OutputNamedItemValueSet{}, time, true); + writer.write(mesh, + OutputNamedItemValueSet{ + NamedItemValue{"cell_number", mesh->connectivity().cellNumber()}}, + time, true); break; } case 2: { @@ -32,7 +35,10 @@ VTKModule::VTKModule() const std::shared_ptr<const MeshType> mesh = std::dynamic_pointer_cast<const MeshType>(p_mesh); - writer.write(mesh, OutputNamedItemValueSet{}, time, true); + writer.write(mesh, + OutputNamedItemValueSet{ + NamedItemValue{"cell_number", mesh->connectivity().cellNumber()}}, + time, true); break; } case 3: { @@ -40,7 +46,10 @@ VTKModule::VTKModule() const std::shared_ptr<const MeshType> mesh = std::dynamic_pointer_cast<const MeshType>(p_mesh); - writer.write(mesh, OutputNamedItemValueSet{}, time, true); + writer.write(mesh, + OutputNamedItemValueSet{ + NamedItemValue{"cell_number", mesh->connectivity().cellNumber()}}, + time, true); break; } } diff --git a/src/language/utils/InterpolateItemValue.hpp b/src/language/utils/InterpolateItemValue.hpp new file mode 100644 index 0000000000000000000000000000000000000000..16a87b4952c7cb0c2907833705e8142d9c0a7178 --- /dev/null +++ b/src/language/utils/InterpolateItemValue.hpp @@ -0,0 +1,82 @@ +#ifndef INTERPOLATE_ITEM_VALUE_HPP +#define INTERPOLATE_ITEM_VALUE_HPP + +#include <language/utils/PugsFunctionAdapter.hpp> +#include <mesh/ItemType.hpp> +#include <mesh/ItemValue.hpp> + +template <typename T> +class InterpolateItemValue; +template <typename OutputType, typename InputType> +class InterpolateItemValue<OutputType(InputType)> : public PugsFunctionAdapter<OutputType(InputType)> +{ + static constexpr size_t Dimension = OutputType::Dimension; + using Adapter = PugsFunctionAdapter<OutputType(InputType)>; + + public: + template <ItemType item_type> + static inline ItemValue<OutputType, item_type> + interpolate(const FunctionSymbolId& function_symbol_id, const ItemValue<const InputType, item_type>& position) + { + auto& expression = Adapter::getFunctionExpression(function_symbol_id); + auto convert_result = Adapter::getResultConverter(expression.m_data_type); + + Array<ExecutionPolicy> context_list = Adapter::getContextList(expression); + + using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; + Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; + const IConnectivity& connectivity = *position.connectivity_ptr(); + + ItemValue<OutputType, item_type> value(connectivity); + using ItemId = ItemIdT<item_type>; + + parallel_for(connectivity.template numberOf<item_type>(), [=, &expression, &tokens](ItemId i) { + const int32_t t = tokens.acquire(); + + auto& execution_policy = context_list[t]; + + Adapter::convertArgs(execution_policy.currentContext(), position[i]); + auto result = expression.execute(execution_policy); + value[i] = convert_result(std::move(result)); + + tokens.release(t); + }); + + return value; + } + + template <ItemType item_type> + static inline Array<OutputType> + interpolate(const FunctionSymbolId& function_symbol_id, + const ItemValue<const InputType, item_type>& position, + const Array<const ItemIdT<item_type>>& list_of_items) + { + auto& expression = Adapter::getFunctionExpression(function_symbol_id); + auto convert_result = Adapter::getResultConverter(expression.m_data_type); + + Array<ExecutionPolicy> context_list = Adapter::getContextList(expression); + + using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; + Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; + + Array<OutputType> value{list_of_items.size()}; + using ItemId = ItemIdT<item_type>; + + parallel_for(list_of_items.size(), [=, &expression, &tokens](size_t i_item) { + ItemId item_id = list_of_items[i_item]; + const int32_t t = tokens.acquire(); + + auto& execution_policy = context_list[t]; + + Adapter::convertArgs(execution_policy.currentContext(), position[item_id]); + auto result = expression.execute(execution_policy); + value[i_item] = convert_result(std::move(result)); + + tokens.release(t); + }); + + return value; + } +}; + +#endif // INTERPOLATE_ITEM_VALUE_HPP diff --git a/src/main.cpp b/src/main.cpp index 9b853028133fd9035f67f743c62ee2a0a298202a..aad67d58a5d228cdc502e9b024cfc497fef23291 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,8 @@ #include <utils/PugsUtils.hpp> #include <language/PugsParser.hpp> +#include <mesh/DiamondDualConnectivityManager.hpp> +#include <mesh/DiamondDualMeshManager.hpp> #include <mesh/MeshDataManager.hpp> #include <mesh/SynchronizerManager.hpp> @@ -11,9 +13,13 @@ main(int argc, char* argv[]) SynchronizerManager::create(); MeshDataManager::create(); + DiamondDualConnectivityManager::create(); + DiamondDualMeshManager::create(); parser(filename); + DiamondDualMeshManager::destroy(); + DiamondDualConnectivityManager::destroy(); MeshDataManager::destroy(); SynchronizerManager::destroy(); finalize(); diff --git a/src/mesh/CMakeLists.txt b/src/mesh/CMakeLists.txt index 92c865c599767db0d5e5fed84e7d16d0cbec8579..6c0088831c86023e31914b953c9ea137e5411d21 100644 --- a/src/mesh/CMakeLists.txt +++ b/src/mesh/CMakeLists.txt @@ -8,8 +8,11 @@ add_library( ConnectivityComputer.cpp ConnectivityDispatcher.cpp DiamondDualConnectivityBuilder.cpp + DiamondDualConnectivityManager.cpp DiamondDualMeshBuilder.cpp + DiamondDualMeshManager.cpp GmshReader.cpp + IConnectivity.cpp IMesh.cpp LogicalConnectivityBuilder.cpp MeshBuilderBase.cpp diff --git a/src/mesh/Connectivity.hpp b/src/mesh/Connectivity.hpp index 5a888190841e7886d4548a5405dc3126223318ac..3bf5cd4201c574749e5b6a67a2b6c4d667bd88f1 100644 --- a/src/mesh/Connectivity.hpp +++ b/src/mesh/Connectivity.hpp @@ -12,7 +12,6 @@ #include <mesh/RefId.hpp> #include <mesh/RefItemList.hpp> #include <mesh/SubItemValuePerItem.hpp> -#include <mesh/SynchronizerManager.hpp> #include <utils/CSRGraph.hpp> #include <utils/Exceptions.hpp> #include <utils/PugsAssert.hpp> @@ -651,11 +650,7 @@ class Connectivity final : public IConnectivity void _buildFrom(const ConnectivityDescriptor& descriptor); public: - ~Connectivity() - { - auto& manager = SynchronizerManager::instance(); - manager.deleteConnectivitySynchronizer(this); - } + ~Connectivity() = default; }; template <size_t Dim> diff --git a/src/mesh/ConnectivityBuilderBase.cpp b/src/mesh/ConnectivityBuilderBase.cpp index f5d47e25003a710e1e2c18ba6b772ffd04bb532f..60c38bfb84fb975c0e2cdc3b07d1d97e39eb0021 100644 --- a/src/mesh/ConnectivityBuilderBase.cpp +++ b/src/mesh/ConnectivityBuilderBase.cpp @@ -2,12 +2,13 @@ #include <mesh/Connectivity.hpp> #include <mesh/ConnectivityDescriptor.hpp> -#include <mesh/ConnectivityDispatcher.hpp> #include <mesh/ItemId.hpp> #include <mesh/Mesh.hpp> #include <utils/PugsAssert.hpp> #include <utils/PugsMacros.hpp> +#include <map> +#include <unordered_map> #include <vector> template <size_t Dimension> diff --git a/src/mesh/ConnectivityToDiamondDualConnectivityDataMapper.hpp b/src/mesh/ConnectivityToDiamondDualConnectivityDataMapper.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8d35d2ff9541fbfab7e8e6e30976bd5f88970f56 --- /dev/null +++ b/src/mesh/ConnectivityToDiamondDualConnectivityDataMapper.hpp @@ -0,0 +1,153 @@ +#ifndef CONNECTIVITY_TO_DIAMOND_DUAL_CONNECTIVITY_DATA_MAPPER_HPP +#define CONNECTIVITY_TO_DIAMOND_DUAL_CONNECTIVITY_DATA_MAPPER_HPP + +#include <mesh/Connectivity.hpp> +#include <mesh/ItemIdToItemIdMap.hpp> +#include <mesh/ItemValue.hpp> +#include <utils/Array.hpp> +#include <utils/PugsAssert.hpp> + +class IConnectivityToDiamondDualConnectivityDataMapper +{ + public: + IConnectivityToDiamondDualConnectivityDataMapper(const IConnectivityToDiamondDualConnectivityDataMapper&) = delete; + IConnectivityToDiamondDualConnectivityDataMapper(IConnectivityToDiamondDualConnectivityDataMapper&&) = delete; + + IConnectivityToDiamondDualConnectivityDataMapper() = default; + virtual ~IConnectivityToDiamondDualConnectivityDataMapper() = default; +}; + +template <size_t Dimension> +class ConnectivityToDiamondDualConnectivityDataMapper : public IConnectivityToDiamondDualConnectivityDataMapper +{ + private: + const IConnectivity* m_primal_connectivity; + const IConnectivity* m_dual_connectivity; + + NodeIdToNodeIdMap m_primal_node_to_dual_node_map; + CellIdToNodeIdMap m_primal_cell_to_dual_node_map; + FaceIdToCellIdMap m_primal_face_to_dual_cell_map; + + public: + template <typename OriginDataType1, typename OriginDataType2, typename DestinationDataType> + void + toDualNode(const NodeValue<OriginDataType1>& primal_node_value, + const CellValue<OriginDataType2>& primal_cell_value, + const NodeValue<DestinationDataType>& dual_node_value) const + { + static_assert(not std::is_const_v<DestinationDataType>, "destination data type must not be constant"); + static_assert(std::is_same_v<std::remove_const_t<OriginDataType1>, DestinationDataType>, "incompatible types"); + static_assert(std::is_same_v<std::remove_const_t<OriginDataType2>, DestinationDataType>, "incompatible types"); + + Assert(m_primal_connectivity == primal_cell_value.connectivity_ptr().get()); + Assert(m_primal_connectivity == primal_node_value.connectivity_ptr().get()); + Assert(m_dual_connectivity == dual_node_value.connectivity_ptr().get()); + + parallel_for( + m_primal_node_to_dual_node_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_node_id, dual_node_id] = m_primal_node_to_dual_node_map[i]; + + dual_node_value[dual_node_id] = primal_node_value[primal_node_id]; + }); + + parallel_for( + m_primal_cell_to_dual_node_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_cell_id, dual_node_id] = m_primal_cell_to_dual_node_map[i]; + dual_node_value[dual_node_id] = primal_cell_value[primal_cell_id]; + }); + } + + template <typename OriginDataType, typename DestinationDataType1, typename DestinationDataType2> + void + fromDualNode(const NodeValue<OriginDataType>& dual_node_value, + const NodeValue<DestinationDataType1>& primal_node_value, + const CellValue<DestinationDataType2>& primal_cell_value) const + { + static_assert(not std::is_const_v<DestinationDataType1>, "destination data type must not be constant"); + static_assert(not std::is_const_v<DestinationDataType2>, "destination data type must not be constant"); + static_assert(std::is_same_v<std::remove_const_t<OriginDataType>, DestinationDataType1>, "incompatible types"); + static_assert(std::is_same_v<std::remove_const_t<OriginDataType>, DestinationDataType2>, "incompatible types"); + + Assert(m_primal_connectivity == primal_cell_value.connectivity_ptr().get()); + Assert(m_primal_connectivity == primal_node_value.connectivity_ptr().get()); + Assert(m_dual_connectivity == dual_node_value.connectivity_ptr().get()); + + parallel_for( + m_primal_node_to_dual_node_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_node_id, dual_node_id] = m_primal_node_to_dual_node_map[i]; + + primal_node_value[primal_node_id] = dual_node_value[dual_node_id]; + }); + + parallel_for( + m_primal_cell_to_dual_node_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_cell_id, dual_node_id] = m_primal_cell_to_dual_node_map[i]; + primal_cell_value[primal_cell_id] = dual_node_value[dual_node_id]; + }); + } + + template <typename OriginDataType, typename DestinationDataType> + void + toDualCell(const FaceValue<OriginDataType>& primal_face_value, + const CellValue<DestinationDataType>& dual_cell_value) const + { + static_assert(not std::is_const_v<DestinationDataType>, "destination data type must not be constant"); + static_assert(std::is_same_v<std::remove_const_t<OriginDataType>, DestinationDataType>, "incompatible types"); + + Assert(m_primal_connectivity == primal_face_value.connectivity_ptr().get()); + Assert(m_dual_connectivity == dual_cell_value.connectivity_ptr().get()); + + parallel_for( + m_primal_face_to_dual_cell_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_face_id, dual_cell_id] = m_primal_face_to_dual_cell_map[i]; + + dual_cell_value[dual_cell_id] = primal_face_value[primal_face_id]; + }); + + parallel_for( + m_primal_cell_to_dual_node_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_face_id, dual_cell_id] = m_primal_face_to_dual_cell_map[i]; + + dual_cell_value[dual_cell_id] = primal_face_value[primal_face_id]; + }); + } + + template <typename OriginDataType, typename DestinationDataType> + void + fromDualCell(const CellValue<DestinationDataType>& dual_cell_value, + const FaceValue<OriginDataType>& primal_face_value) const + { + static_assert(not std::is_const_v<DestinationDataType>, "destination data type must not be constant"); + static_assert(std::is_same_v<std::remove_const_t<OriginDataType>, DestinationDataType>, "incompatible types"); + + Assert(m_primal_connectivity == primal_face_value.connectivity_ptr().get()); + Assert(m_dual_connectivity == dual_cell_value.connectivity_ptr().get()); + + parallel_for( + m_primal_face_to_dual_cell_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_face_id, dual_cell_id] = m_primal_face_to_dual_cell_map[i]; + + primal_face_value[primal_face_id] = dual_cell_value[dual_cell_id]; + }); + + parallel_for( + m_primal_cell_to_dual_node_map.size(), PUGS_LAMBDA(size_t i) { + const auto [primal_face_id, dual_cell_id] = m_primal_face_to_dual_cell_map[i]; + primal_face_value[primal_face_id] = dual_cell_value[dual_cell_id]; + }); + } + + ConnectivityToDiamondDualConnectivityDataMapper(const Connectivity<Dimension>& primal_connectivity, + const Connectivity<Dimension>& dual_connectivity, + const NodeIdToNodeIdMap& primal_node_to_dual_node_map, + const CellIdToNodeIdMap& primal_cell_to_dual_node_map, + const FaceIdToCellIdMap& primal_face_to_dual_cell_map) + : m_primal_connectivity{&primal_connectivity}, + m_dual_connectivity{&dual_connectivity}, + m_primal_node_to_dual_node_map{primal_node_to_dual_node_map}, + m_primal_cell_to_dual_node_map{primal_cell_to_dual_node_map}, + m_primal_face_to_dual_cell_map{primal_face_to_dual_cell_map} + {} +}; + +#endif // CONNECTIVITY_TO_DIAMOND_DUAL_CONNECTIVITY_DATA_MAPPER_HPP diff --git a/src/mesh/DiamondDualConnectivityBuilder.cpp b/src/mesh/DiamondDualConnectivityBuilder.cpp index 8bcbe9bad8e15cbef1dfa449c0d6defc115f126f..31d54be8997e9571958399f17c44dbcede1c35e4 100644 --- a/src/mesh/DiamondDualConnectivityBuilder.cpp +++ b/src/mesh/DiamondDualConnectivityBuilder.cpp @@ -3,12 +3,16 @@ #include <mesh/Connectivity.hpp> #include <mesh/ConnectivityDescriptor.hpp> #include <mesh/ConnectivityDispatcher.hpp> +#include <mesh/ConnectivityToDiamondDualConnectivityDataMapper.hpp> #include <mesh/ItemValueUtils.hpp> #include <mesh/Mesh.hpp> #include <mesh/RefId.hpp> #include <utils/Array.hpp> +#include <utils/ArrayUtils.hpp> #include <utils/Messenger.hpp> +#include <vector> + template <size_t Dimension> void DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connectivity<Dimension>& primal_connectivity, @@ -18,32 +22,56 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connec const size_t primal_number_of_faces = primal_connectivity.numberOfFaces(); const size_t primal_number_of_cells = primal_connectivity.numberOfCells(); + const auto& primal_node_number = primal_connectivity.nodeNumber(); + const auto& primal_cell_number = primal_connectivity.cellNumber(); + const size_t diamond_number_of_nodes = primal_number_of_cells + primal_number_of_nodes; + const size_t diamond_number_of_cells = primal_number_of_faces; - diamond_descriptor.node_number_vector.resize(diamond_number_of_nodes); + { + m_primal_node_to_dual_node_map = NodeIdToNodeIdMap{primal_number_of_nodes}; - const auto& primal_node_number = primal_connectivity.nodeNumber(); + NodeId diamond_node_id = 0; + for (NodeId primal_node_id = 0; primal_node_id < primal_number_of_nodes; ++primal_node_id) { + m_primal_node_to_dual_node_map[primal_node_id] = std::make_pair(primal_node_id, diamond_node_id++); + } - for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { - diamond_descriptor.node_number_vector[primal_node_id] = primal_node_number[primal_node_id]; + m_primal_cell_to_dual_node_map = CellIdToNodeIdMap{primal_number_of_cells}; + for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { + m_primal_cell_to_dual_node_map[primal_cell_id] = std::make_pair(primal_cell_id, diamond_node_id++); + } } - const auto& primal_cell_number = primal_connectivity.cellNumber(); + diamond_descriptor.node_number_vector.resize(diamond_number_of_nodes); - const size_t max_node_number = max(primal_node_number); + parallel_for(m_primal_node_to_dual_node_map.size(), [&](size_t i) { + const auto [primal_node_id, diamond_dual_node_id] = m_primal_node_to_dual_node_map[i]; - for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { - diamond_descriptor.node_number_vector[primal_number_of_nodes + primal_cell_id] = - primal_cell_number[primal_cell_id] + max_node_number; + diamond_descriptor.node_number_vector[diamond_dual_node_id] = primal_node_number[primal_node_id]; + }); + + const size_t cell_number_shift = max(primal_node_number) + 1; + parallel_for(primal_number_of_cells, [&](size_t i) { + const auto [primal_cell_id, diamond_dual_node_id] = m_primal_cell_to_dual_node_map[i]; + + diamond_descriptor.node_number_vector[diamond_dual_node_id] = + primal_cell_number[primal_cell_id] + cell_number_shift; + }); + + { + m_primal_face_to_dual_cell_map = FaceIdToCellIdMap{primal_number_of_faces}; + CellId diamond_cell_id = 0; + for (FaceId primal_face_id = 0; primal_face_id < primal_number_of_faces; ++primal_face_id) { + m_primal_face_to_dual_cell_map[primal_face_id] = std::make_pair(primal_face_id, diamond_cell_id++); + } } - const size_t diamond_number_of_cells = primal_number_of_faces; diamond_descriptor.cell_number_vector.resize(diamond_number_of_cells); - const auto& primal_face_number = primal_connectivity.faceNumber(); - for (FaceId i_primal_face = 0; i_primal_face < primal_number_of_faces; ++i_primal_face) { - diamond_descriptor.cell_number_vector[i_primal_face] = primal_face_number[i_primal_face]; - } + parallel_for(diamond_number_of_cells, [&](size_t i) { + const auto [primal_face_id, dual_cell_id] = m_primal_face_to_dual_cell_map[i]; + diamond_descriptor.cell_number_vector[dual_cell_id] = primal_face_number[primal_face_id]; + }); if constexpr (Dimension == 3) { const size_t number_of_edges = diamond_descriptor.edge_to_node_vector.size(); @@ -60,9 +88,9 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connec const auto& primal_face_to_cell_matrix = primal_connectivity.faceToCellMatrix(); - for (FaceId i_face = 0; i_face < primal_connectivity.numberOfFaces(); ++i_face) { - const size_t i_cell = i_face; - const auto& primal_face_cell_list = primal_face_to_cell_matrix[i_face]; + parallel_for(primal_number_of_faces, [&](FaceId face_id) { + const size_t i_cell = face_id; + const auto& primal_face_cell_list = primal_face_to_cell_matrix[face_id]; if (primal_face_cell_list.size() == 1) { diamond_descriptor.cell_type_vector[i_cell] = CellType::Triangle; @@ -79,22 +107,22 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connec diamond_descriptor.cell_type_vector[i_cell] = CellType::Diamond; } } - } + }); diamond_descriptor.cell_to_node_vector.resize(diamond_number_of_cells); const auto& primal_face_to_node_matrix = primal_connectivity.faceToNodeMatrix(); const auto& primal_face_local_number_in_their_cells = primal_connectivity.faceLocalNumbersInTheirCells(); const auto& cell_face_is_reversed = primal_connectivity.cellFaceIsReversed(); - for (FaceId i_face = 0; i_face < primal_connectivity.numberOfFaces(); ++i_face) { - const size_t& i_diamond_cell = i_face; - const auto& primal_face_cell_list = primal_face_to_cell_matrix[i_face]; - const auto& primal_face_node_list = primal_face_to_node_matrix[i_face]; + parallel_for(primal_number_of_faces, [&](FaceId face_id) { + const size_t& i_diamond_cell = face_id; + const auto& primal_face_cell_list = primal_face_to_cell_matrix[face_id]; + const auto& primal_face_node_list = primal_face_to_node_matrix[face_id]; if (primal_face_cell_list.size() == 1) { diamond_descriptor.cell_to_node_vector[i_diamond_cell].resize(primal_face_node_list.size() + 1); const CellId cell_id = primal_face_cell_list[0]; - const auto i_face_in_cell = primal_face_local_number_in_their_cells(i_face, 0); + const auto i_face_in_cell = primal_face_local_number_in_their_cells(face_id, 0); for (size_t i_node = 0; i_node < primal_face_node_list.size(); ++i_node) { diamond_descriptor.cell_to_node_vector[i_diamond_cell][i_node] = primal_face_node_list[i_node]; @@ -121,7 +149,7 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connec const CellId cell0_id = primal_face_cell_list[0]; const CellId cell1_id = primal_face_cell_list[1]; - const auto i_face_in_cell0 = primal_face_local_number_in_their_cells(i_face, 0); + const auto i_face_in_cell0 = primal_face_local_number_in_their_cells(face_id, 0); if constexpr (Dimension == 2) { Assert(primal_face_node_list.size() == 2); @@ -148,7 +176,7 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connec } } } - } + }); } template <> @@ -162,23 +190,34 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor<1>(const Con const size_t diamond_number_of_nodes = 2 * primal_number_of_nodes - primal_number_of_cells; - diamond_descriptor.node_number_vector.resize(diamond_number_of_nodes); - - const auto& primal_node_number = primal_connectivity.nodeNumber(); - const size_t diamond_number_of_cells = primal_number_of_faces; const size_t number_of_kept_nodes = 2 * (diamond_number_of_nodes - diamond_number_of_cells); const auto& primal_node_to_cell_matrix = primal_connectivity.nodeToCellMatrix(); size_t next_kept_node_id = 0; - for (NodeId node_id = 0; node_id < primal_connectivity.numberOfNodes(); ++node_id) { - const auto& primal_node_cell_list = primal_node_to_cell_matrix[node_id]; + diamond_descriptor.node_number_vector.resize(diamond_number_of_nodes); + + const auto& primal_node_number = primal_connectivity.nodeNumber(); + + for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { + const auto& primal_node_cell_list = primal_node_to_cell_matrix[primal_node_id]; if (primal_node_cell_list.size() == 1) { - diamond_descriptor.node_number_vector[next_kept_node_id++] = primal_node_number[node_id]; + diamond_descriptor.node_number_vector[next_kept_node_id++] = primal_node_number[primal_node_id]; } } + const size_t primal_number_of_kept_nodes = next_kept_node_id; + + const auto& primal_cell_number = primal_connectivity.cellNumber(); + + const size_t cell_number_shift = max(primal_node_number) + 1; + + for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { + diamond_descriptor.node_number_vector[primal_number_of_kept_nodes + primal_cell_id] = + primal_cell_number[primal_cell_id] + cell_number_shift; + } + if (number_of_kept_nodes != next_kept_node_id) { throw UnexpectedError("unexpected number of kept node" + std::to_string(next_kept_node_id) + " != " + std::to_string(number_of_kept_nodes)); @@ -200,8 +239,6 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor<1>(const Con diamond_descriptor.cell_to_node_vector.resize(diamond_number_of_cells); - ; - const auto& primal_node_local_number_in_their_cells = primal_connectivity.nodeLocalNumbersInTheirCells(); { @@ -278,7 +315,6 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityFrom(const IConnectivit node_array[i] = diamond_node_list[i]; } diamond_descriptor.addRefItemList(RefNodeList{primal_ref_node_list.refId(), node_array}); - std::cout << "stored " << primal_ref_node_list.refId() << '\n'; } } } @@ -332,7 +368,6 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityFrom(const IConnectivit face_array[i] = diamond_face_list[i]; } diamond_descriptor.addRefItemList(RefFaceList{primal_ref_face_list.refId(), face_array}); - std::cout << "stored " << primal_ref_face_list.refId() << '\n'; } } } @@ -384,7 +419,6 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityFrom(const IConnectivit edge_array[i] = diamond_edge_list[i]; } diamond_descriptor.addRefItemList(RefEdgeList{primal_ref_edge_list.refId(), edge_array}); - std::cout << "stored " << primal_ref_edge_list.refId() << '\n'; } } } @@ -466,15 +500,60 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityFrom(const IConnectivit diamond_descriptor.edge_owner_vector.resize(edge_cell_owner.size()); for (size_t i_edge = 0; i_edge < edge_cell_owner.size(); ++i_edge) { - diamond_descriptor.face_owner_vector[i_edge] = diamond_descriptor.cell_owner_vector[edge_cell_owner[i_edge]]; + diamond_descriptor.edge_owner_vector[i_edge] = diamond_descriptor.cell_owner_vector[edge_cell_owner[i_edge]]; } } m_connectivity = ConnectivityType::build(diamond_descriptor); + + if constexpr (Dimension == 1) { + const auto& node_to_cell_matrix = primal_connectivity.nodeToCellMatrix(); + + NodeId dual_node_id = 0; + m_primal_node_to_dual_node_map = [&]() { + std::vector<std::pair<NodeId, NodeId>> primal_node_to_dual_node_vector; + for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { + if (node_to_cell_matrix[primal_node_id].size() == 1) { + primal_node_to_dual_node_vector.push_back(std::make_pair(primal_node_id, dual_node_id++)); + } + } + return convert_to_array(primal_node_to_dual_node_vector); + }(); + + m_primal_cell_to_dual_node_map = [&]() { + CellIdToNodeIdMap primal_cell_to_dual_node_map{primal_number_of_cells}; + for (CellId primal_cell_id = 0; primal_cell_id < primal_cell_to_dual_node_map.size(); ++primal_cell_id) { + primal_cell_to_dual_node_map[primal_cell_id] = std::make_pair(primal_cell_id, dual_node_id++); + } + return primal_cell_to_dual_node_map; + }(); + + m_primal_face_to_dual_cell_map = [&]() { + FaceIdToCellIdMap primal_face_to_dual_cell_map{primal_connectivity.numberOfFaces()}; + for (size_t id = 0; id < primal_face_to_dual_cell_map.size(); ++id) { + const CellId dual_cell_id = id; + const FaceId primal_face_id = id; + + primal_face_to_dual_cell_map[id] = std::make_pair(primal_face_id, dual_cell_id); + } + return primal_face_to_dual_cell_map; + }(); + } + + m_mapper = + std::make_shared<ConnectivityToDiamondDualConnectivityDataMapper<Dimension>>(primal_connectivity, + dynamic_cast<const ConnectivityType&>( + *m_connectivity), + m_primal_node_to_dual_node_map, + m_primal_cell_to_dual_node_map, + m_primal_face_to_dual_cell_map); } DiamondDualConnectivityBuilder::DiamondDualConnectivityBuilder(const IConnectivity& connectivity) { + if (parallel::size() > 1) { + throw NotImplementedError("Construction of diamond dual mesh is not implemented in parallel"); + } switch (connectivity.dimension()) { case 1: { this->_buildDiamondConnectivityFrom<1>(connectivity); diff --git a/src/mesh/DiamondDualConnectivityBuilder.hpp b/src/mesh/DiamondDualConnectivityBuilder.hpp index 670372df9e53d3bfa8dd3f1b03545d9264b41dc4..36b120811ad6478af90b89112740d272014b2e7a 100644 --- a/src/mesh/DiamondDualConnectivityBuilder.hpp +++ b/src/mesh/DiamondDualConnectivityBuilder.hpp @@ -2,6 +2,7 @@ #define DIAMOND_DUAL_CONNECTIVITY_BUILDER_HPP #include <mesh/ConnectivityBuilderBase.hpp> +#include <mesh/ItemIdToItemIdMap.hpp> #include <memory> @@ -9,17 +10,33 @@ template <size_t> class Connectivity; class ConnectivityDescriptor; +class IConnectivityToDiamondDualConnectivityDataMapper; + class DiamondDualConnectivityBuilder : public ConnectivityBuilderBase { private: + NodeIdToNodeIdMap m_primal_node_to_dual_node_map; + CellIdToNodeIdMap m_primal_cell_to_dual_node_map; + FaceIdToCellIdMap m_primal_face_to_dual_cell_map; + + std::shared_ptr<IConnectivityToDiamondDualConnectivityDataMapper> m_mapper; + template <size_t Dimension> void _buildDiamondConnectivityDescriptor(const Connectivity<Dimension>&, ConnectivityDescriptor&); template <size_t Dimension> void _buildDiamondConnectivityFrom(const IConnectivity&); - public: + friend class DiamondDualConnectivityManager; DiamondDualConnectivityBuilder(const IConnectivity&); + + public: + std::shared_ptr<IConnectivityToDiamondDualConnectivityDataMapper> + mapper() const + { + return m_mapper; + } + ~DiamondDualConnectivityBuilder() = default; }; diff --git a/src/mesh/DiamondDualConnectivityManager.cpp b/src/mesh/DiamondDualConnectivityManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9459010b69e89acaf3f247866d2f6e81ef00cd81 --- /dev/null +++ b/src/mesh/DiamondDualConnectivityManager.cpp @@ -0,0 +1,96 @@ +#include <utils/PugsAssert.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityToDiamondDualConnectivityDataMapper.hpp> +#include <mesh/DiamondDualConnectivityBuilder.hpp> +#include <mesh/DiamondDualConnectivityManager.hpp> +#include <utils/Exceptions.hpp> + +#include <sstream> + +DiamondDualConnectivityManager* DiamondDualConnectivityManager::m_instance{nullptr}; + +void +DiamondDualConnectivityManager::create() +{ + Assert(m_instance == nullptr, "DiamondDualConnectivityManager is already created"); + m_instance = new DiamondDualConnectivityManager; +} + +void +DiamondDualConnectivityManager::destroy() +{ + Assert(m_instance != nullptr, "DiamondDualConnectivityManager was not created!"); + + if (m_instance->m_connectivity_to_diamond_dual_connectivity_info_map.size() > 0) { + std::stringstream error; + error << ": some connectivities are still registered\n"; + for (const auto& [connectivity, diamond_dual_connectivity_info] : + m_instance->m_connectivity_to_diamond_dual_connectivity_info_map) { + error << " - connectivity " << rang::fgB::magenta << connectivity << rang::style::reset << '\n'; + } + throw UnexpectedError(error.str()); + } + delete m_instance; + m_instance = nullptr; +} + +void +DiamondDualConnectivityManager::deleteConnectivity(const IConnectivity* p_connectivity) +{ + m_connectivity_to_diamond_dual_connectivity_info_map.erase(p_connectivity); +} + +DiamondDualConnectivityManager::DiamondDualConnectivityInfo +DiamondDualConnectivityManager::_getDiamondDualConnectivityInfo(const IConnectivity& connectivity) +{ + const IConnectivity* p_connectivity = &connectivity; + + if (auto i_connectivity = m_connectivity_to_diamond_dual_connectivity_info_map.find(p_connectivity); + i_connectivity != m_connectivity_to_diamond_dual_connectivity_info_map.end()) { + return i_connectivity->second; + } else { + DiamondDualConnectivityBuilder builder{connectivity}; + + DiamondDualConnectivityInfo connectivity_info{builder.connectivity(), builder.mapper()}; + + m_connectivity_to_diamond_dual_connectivity_info_map[p_connectivity] = connectivity_info; + + return connectivity_info; + } +} + +template <size_t Dimension> +std::shared_ptr<const Connectivity<Dimension>> +DiamondDualConnectivityManager::getDiamondDualConnectivity(const Connectivity<Dimension>& connectivity) +{ + return std::dynamic_pointer_cast<const Connectivity<Dimension>>( + this->_getDiamondDualConnectivityInfo(connectivity).diamondDualConnectivity()); +} + +template <size_t Dimension> +std::shared_ptr<const ConnectivityToDiamondDualConnectivityDataMapper<Dimension>> +DiamondDualConnectivityManager::getConnectivityToDiamondDualConnectivityDataMapper( + const Connectivity<Dimension>& connectivity) +{ + return std::dynamic_pointer_cast<const ConnectivityToDiamondDualConnectivityDataMapper<Dimension>>( + this->_getDiamondDualConnectivityInfo(connectivity).connectivityToDiamondDualConnectivityDataMapper()); +} + +template std::shared_ptr<const Connectivity<1>> DiamondDualConnectivityManager::getDiamondDualConnectivity( + const Connectivity<1>& connectivity); + +template std::shared_ptr<const Connectivity<2>> DiamondDualConnectivityManager::getDiamondDualConnectivity( + const Connectivity<2>& connectivity); + +template std::shared_ptr<const Connectivity<3>> DiamondDualConnectivityManager::getDiamondDualConnectivity( + const Connectivity<3>& connectivity); + +template std::shared_ptr<const ConnectivityToDiamondDualConnectivityDataMapper<1>> +DiamondDualConnectivityManager::getConnectivityToDiamondDualConnectivityDataMapper(const Connectivity<1>&); + +template std::shared_ptr<const ConnectivityToDiamondDualConnectivityDataMapper<2>> +DiamondDualConnectivityManager::getConnectivityToDiamondDualConnectivityDataMapper(const Connectivity<2>&); + +template std::shared_ptr<const ConnectivityToDiamondDualConnectivityDataMapper<3>> +DiamondDualConnectivityManager::getConnectivityToDiamondDualConnectivityDataMapper(const Connectivity<3>&); diff --git a/src/mesh/DiamondDualConnectivityManager.hpp b/src/mesh/DiamondDualConnectivityManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..33dfbaf4cf7cc8e59eebfc095624d43c5bf038b3 --- /dev/null +++ b/src/mesh/DiamondDualConnectivityManager.hpp @@ -0,0 +1,94 @@ +#ifndef DIAMOND_DUAL_CONNECTIVITY_MANAGER_HPP +#define DIAMOND_DUAL_CONNECTIVITY_MANAGER_HPP + +#include <mesh/IConnectivity.hpp> + +#include <memory> +#include <unordered_map> + +template <size_t Dimension> +class Connectivity; + +class IConnectivityToDiamondDualConnectivityDataMapper; + +template <size_t Dimension> +class ConnectivityToDiamondDualConnectivityDataMapper; + +class DiamondDualConnectivityManager +{ + private: + class DiamondDualConnectivityInfo + { + private: + std::shared_ptr<const IConnectivity> m_diamond_dual_connectivity; + std::shared_ptr<const IConnectivityToDiamondDualConnectivityDataMapper> + m_connectivity_to_diamond_dual_connectivity_data_mapper; + + public: + PUGS_INLINE + std::shared_ptr<const IConnectivity> + diamondDualConnectivity() const + { + return m_diamond_dual_connectivity; + } + + PUGS_INLINE + std::shared_ptr<const IConnectivityToDiamondDualConnectivityDataMapper> + connectivityToDiamondDualConnectivityDataMapper() + { + return m_connectivity_to_diamond_dual_connectivity_data_mapper; + } + + DiamondDualConnectivityInfo& operator=(const DiamondDualConnectivityInfo&) = default; + DiamondDualConnectivityInfo& operator=(DiamondDualConnectivityInfo&&) = default; + + DiamondDualConnectivityInfo() = default; + DiamondDualConnectivityInfo(const DiamondDualConnectivityInfo&) = default; + DiamondDualConnectivityInfo(DiamondDualConnectivityInfo&&) = default; + + DiamondDualConnectivityInfo(const std::shared_ptr<const IConnectivity>& diamond_dual_connectivity, + const std::shared_ptr<const IConnectivityToDiamondDualConnectivityDataMapper>& + connectivity_to_diamond_dual_connectivity_data_mapper) + : m_diamond_dual_connectivity{diamond_dual_connectivity}, + m_connectivity_to_diamond_dual_connectivity_data_mapper{connectivity_to_diamond_dual_connectivity_data_mapper} + {} + + ~DiamondDualConnectivityInfo() = default; + }; + + DiamondDualConnectivityInfo _getDiamondDualConnectivityInfo(const IConnectivity& connectivity); + + std::unordered_map<const IConnectivity*, DiamondDualConnectivityInfo> + m_connectivity_to_diamond_dual_connectivity_info_map; + + static DiamondDualConnectivityManager* m_instance; + + DiamondDualConnectivityManager(const DiamondDualConnectivityManager&) = delete; + DiamondDualConnectivityManager(DiamondDualConnectivityManager&&) = delete; + + DiamondDualConnectivityManager() = default; + ~DiamondDualConnectivityManager() = default; + + public: + static void create(); + static void destroy(); + + PUGS_INLINE + static DiamondDualConnectivityManager& + instance() + { + Assert(m_instance != nullptr, "DiamondDualConnectivityManager was not created!"); + return *m_instance; + } + + void deleteConnectivity(const IConnectivity*); + + template <size_t Dimension> + std::shared_ptr<const Connectivity<Dimension>> getDiamondDualConnectivity(const Connectivity<Dimension>&); + + template <size_t Dimension> + std::shared_ptr<const ConnectivityToDiamondDualConnectivityDataMapper<Dimension>> + getConnectivityToDiamondDualConnectivityDataMapper(const Connectivity<Dimension>&); +}; + +#endif // DIAMOND_DUAL_CONNECTIVITY_MANAGER_HPP diff --git a/src/mesh/DiamondDualMeshBuilder.cpp b/src/mesh/DiamondDualMeshBuilder.cpp index 2218541b338e196a913b3c0859b882ad668d252e..df4157c9c19b377f77b754d3f33ac54141539f2f 100644 --- a/src/mesh/DiamondDualMeshBuilder.cpp +++ b/src/mesh/DiamondDualMeshBuilder.cpp @@ -1,117 +1,60 @@ #include <mesh/DiamondDualMeshBuilder.hpp> -#include <mesh/DiamondDualConnectivityBuilder.hpp> - #include <mesh/Connectivity.hpp> -#include <mesh/ConnectivityDescriptor.hpp> -#include <mesh/ConnectivityDispatcher.hpp> +#include <mesh/ConnectivityToDiamondDualConnectivityDataMapper.hpp> +#include <mesh/DiamondDualConnectivityBuilder.hpp> +#include <mesh/DiamondDualConnectivityManager.hpp> #include <mesh/ItemValueUtils.hpp> #include <mesh/Mesh.hpp> #include <mesh/MeshData.hpp> #include <mesh/MeshDataManager.hpp> -#include <mesh/RefId.hpp> -#include <utils/Array.hpp> -#include <utils/Messenger.hpp> template <size_t Dimension> void -DiamondDualMeshBuilder::_buildDualDiamondMeshFrom( - const Mesh<Connectivity<Dimension>>& primal_mesh, - const std::shared_ptr<const Connectivity<Dimension>>& p_diamond_connectivity) +DiamondDualMeshBuilder::_buildDualDiamondMeshFrom(const std::shared_ptr<const IMesh>& p_i_mesh) { using ConnectivityType = Connectivity<Dimension>; using MeshType = Mesh<Connectivity<Dimension>>; - const ConnectivityType& diamond_connectivity = *p_diamond_connectivity; - - NodeValue<TinyVector<Dimension>> diamond_xr{diamond_connectivity}; - - const NodeValue<const TinyVector<Dimension>> primal_xr = primal_mesh.xr(); - MeshData<Dimension>& primal_mesh_data = MeshDataManager::instance().getMeshData(primal_mesh); - const CellValue<const TinyVector<Dimension>> primal_xj = primal_mesh_data.xj(); - - NodeId i_node = 0; - for (; i_node < primal_mesh.numberOfNodes(); ++i_node) { - diamond_xr[i_node] = primal_xr[i_node]; - } + std::shared_ptr p_primal_mesh = std::dynamic_pointer_cast<const MeshType>(p_i_mesh); + const MeshType& primal_mesh = *p_primal_mesh; - for (CellId i_cell = 0; i_cell < primal_mesh.numberOfCells(); ++i_cell) { - diamond_xr[i_node++] = primal_xj[i_cell]; - } + DiamondDualConnectivityManager& manager = DiamondDualConnectivityManager::instance(); - m_mesh = std::make_shared<MeshType>(p_diamond_connectivity, diamond_xr); -} - -template <> -void -DiamondDualMeshBuilder::_buildDualDiamondMeshFrom(const Mesh<Connectivity<1>>& primal_mesh, - const std::shared_ptr<const Connectivity<1>>& p_diamond_connectivity) -{ - using ConnectivityType = Connectivity<1>; - using MeshType = Mesh<Connectivity<1>>; - - const ConnectivityType& primal_connectivity = primal_mesh.connectivity(); - const auto& node_to_cell_matrix = primal_connectivity.nodeToCellMatrix(); + std::shared_ptr<const ConnectivityType> p_diamond_connectivity = + manager.getDiamondDualConnectivity(primal_mesh.connectivity()); const ConnectivityType& diamond_connectivity = *p_diamond_connectivity; - NodeValue<TinyVector<1>> diamond_xr{diamond_connectivity}; + const NodeValue<const TinyVector<Dimension>> primal_xr = primal_mesh.xr(); - const NodeValue<const TinyVector<1>> primal_xr = primal_mesh.xr(); - MeshData<1>& primal_mesh_data = MeshDataManager::instance().getMeshData(primal_mesh); - const CellValue<const TinyVector<1>> primal_xj = primal_mesh_data.xj(); + MeshData<Dimension>& primal_mesh_data = MeshDataManager::instance().getMeshData(primal_mesh); + const CellValue<const TinyVector<Dimension>> primal_xj = primal_mesh_data.xj(); - NodeId next_node_id = 0; - for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { - if (node_to_cell_matrix[primal_node_id].size() == 1) { - diamond_xr[next_node_id++] = primal_xr[primal_node_id]; - } - } + std::shared_ptr connectivity_to_diamond_dual_connectivity_data_mapper = + manager.getConnectivityToDiamondDualConnectivityDataMapper(primal_mesh.connectivity()); - for (CellId i_cell = 0; i_cell < primal_mesh.numberOfCells(); ++i_cell) { - diamond_xr[next_node_id++] = primal_xj[i_cell]; - } + NodeValue<TinyVector<Dimension>> diamond_xr{diamond_connectivity}; + connectivity_to_diamond_dual_connectivity_data_mapper->toDualNode(primal_xr, primal_xj, diamond_xr); m_mesh = std::make_shared<MeshType>(p_diamond_connectivity, diamond_xr); } DiamondDualMeshBuilder::DiamondDualMeshBuilder(const std::shared_ptr<const IMesh>& p_mesh) { + std::cout << "building DiamondDualMesh\n"; + switch (p_mesh->dimension()) { case 1: { - using ConnectivityType = Connectivity<1>; - using MeshType = Mesh<ConnectivityType>; - - std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(p_mesh); - DiamondDualConnectivityBuilder builder(mesh->connectivity()); - - std::shared_ptr p_diamond_connectivity = std::dynamic_pointer_cast<const ConnectivityType>(builder.connectivity()); - - this->_buildDualDiamondMeshFrom(*mesh, p_diamond_connectivity); + this->_buildDualDiamondMeshFrom<1>(p_mesh); break; } case 2: { - using ConnectivityType = Connectivity<2>; - using MeshType = Mesh<ConnectivityType>; - - std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(p_mesh); - DiamondDualConnectivityBuilder builder(mesh->connectivity()); - - std::shared_ptr p_diamond_connectivity = std::dynamic_pointer_cast<const ConnectivityType>(builder.connectivity()); - - this->_buildDualDiamondMeshFrom(*mesh, p_diamond_connectivity); + this->_buildDualDiamondMeshFrom<2>(p_mesh); break; } case 3: { - using ConnectivityType = Connectivity<3>; - using MeshType = Mesh<ConnectivityType>; - - std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(p_mesh); - DiamondDualConnectivityBuilder builder(mesh->connectivity()); - - std::shared_ptr p_diamond_connectivity = std::dynamic_pointer_cast<const ConnectivityType>(builder.connectivity()); - - this->_buildDualDiamondMeshFrom(*mesh, p_diamond_connectivity); + this->_buildDualDiamondMeshFrom<3>(p_mesh); break; } default: { diff --git a/src/mesh/DiamondDualMeshBuilder.hpp b/src/mesh/DiamondDualMeshBuilder.hpp index ded3cfb0f40ca4d1b1bd9dc06f7981391f9401c6..2e47cfe21b4790a63e0e4aeba2fcfb9c59699286 100644 --- a/src/mesh/DiamondDualMeshBuilder.hpp +++ b/src/mesh/DiamondDualMeshBuilder.hpp @@ -5,21 +5,16 @@ #include <memory> -template <size_t> -class Connectivity; - -template <typename ConnectivityType> -class Mesh; - class DiamondDualMeshBuilder : public MeshBuilderBase { private: template <size_t Dimension> - void _buildDualDiamondMeshFrom(const Mesh<Connectivity<Dimension>>&, - const std::shared_ptr<const Connectivity<Dimension>>&); + void _buildDualDiamondMeshFrom(const std::shared_ptr<const IMesh>&); - public: + friend class DiamondDualMeshManager; DiamondDualMeshBuilder(const std::shared_ptr<const IMesh>&); + + public: ~DiamondDualMeshBuilder() = default; }; diff --git a/src/mesh/DiamondDualMeshManager.cpp b/src/mesh/DiamondDualMeshManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0619736753f2b49a4229c60492ea6fd4c0de7212 --- /dev/null +++ b/src/mesh/DiamondDualMeshManager.cpp @@ -0,0 +1,65 @@ +#include <mesh/DiamondDualMeshManager.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/DiamondDualMeshBuilder.hpp> +#include <mesh/Mesh.hpp> +#include <utils/Exceptions.hpp> +#include <utils/PugsAssert.hpp> + +#include <sstream> + +DiamondDualMeshManager* DiamondDualMeshManager::m_instance{nullptr}; + +void +DiamondDualMeshManager::create() +{ + Assert(m_instance == nullptr, "DiamondDualMeshManager is already created"); + m_instance = new DiamondDualMeshManager; +} + +void +DiamondDualMeshManager::destroy() +{ + Assert(m_instance != nullptr, "DiamondDualMeshManager was not created!"); + + if (m_instance->m_mesh_to_diamond_dual_mesh_map.size() > 0) { + std::stringstream error; + error << ": some meshes are still registered\n"; + for (const auto& i_mesh_data : m_instance->m_mesh_to_diamond_dual_mesh_map) { + error << " - mesh " << rang::fgB::magenta << i_mesh_data.first << rang::style::reset << '\n'; + } + throw UnexpectedError(error.str()); + } + delete m_instance; + m_instance = nullptr; +} + +void +DiamondDualMeshManager::deleteMesh(const IMesh* p_mesh) +{ + m_mesh_to_diamond_dual_mesh_map.erase(p_mesh); +} + +template <size_t Dimension> +std::shared_ptr<const Mesh<Connectivity<Dimension>>> +DiamondDualMeshManager::getDiamondDualMesh(std::shared_ptr<const Mesh<Connectivity<Dimension>>> mesh) +{ + const IMesh* p_mesh = mesh.get(); + + if (auto i_mesh_data = m_mesh_to_diamond_dual_mesh_map.find(p_mesh); + i_mesh_data != m_mesh_to_diamond_dual_mesh_map.end()) { + return std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh_data->second); + } else { + DiamondDualMeshBuilder builder{mesh}; + + m_mesh_to_diamond_dual_mesh_map[p_mesh] = builder.mesh(); + return std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(builder.mesh()); + } +} + +template std::shared_ptr<const Mesh<Connectivity<1>>> DiamondDualMeshManager::getDiamondDualMesh( + std::shared_ptr<const Mesh<Connectivity<1>>>); +template std::shared_ptr<const Mesh<Connectivity<2>>> DiamondDualMeshManager::getDiamondDualMesh( + std::shared_ptr<const Mesh<Connectivity<2>>>); +template std::shared_ptr<const Mesh<Connectivity<3>>> DiamondDualMeshManager::getDiamondDualMesh( + std::shared_ptr<const Mesh<Connectivity<3>>>); diff --git a/src/mesh/DiamondDualMeshManager.hpp b/src/mesh/DiamondDualMeshManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9f802eb96d13704235f50e82ad75e84ba9be8a64 --- /dev/null +++ b/src/mesh/DiamondDualMeshManager.hpp @@ -0,0 +1,49 @@ +#ifndef DIAMOND_DUAL_MESH_MANAGER_HPP +#define DIAMOND_DUAL_MESH_MANAGER_HPP + +#include <mesh/IMesh.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/PugsMacros.hpp> + +#include <memory> +#include <unordered_map> + +template <size_t Dimension> +class Connectivity; + +template <typename ConnectivityType> +class Mesh; + +class DiamondDualMeshManager +{ + private: + std::unordered_map<const IMesh*, std::shared_ptr<const IMesh>> m_mesh_to_diamond_dual_mesh_map; + + static DiamondDualMeshManager* m_instance; + + DiamondDualMeshManager(const DiamondDualMeshManager&) = delete; + DiamondDualMeshManager(DiamondDualMeshManager&&) = delete; + + DiamondDualMeshManager() = default; + ~DiamondDualMeshManager() = default; + + public: + static void create(); + static void destroy(); + + PUGS_INLINE + static DiamondDualMeshManager& + instance() + { + Assert(m_instance != nullptr, "DiamondDualMeshManager was not created!"); + return *m_instance; + } + + void deleteMesh(const IMesh*); + + template <size_t Dimension> + std::shared_ptr<const Mesh<Connectivity<Dimension>>> getDiamondDualMesh( + std::shared_ptr<const Mesh<Connectivity<Dimension>>>); +}; + +#endif // DIAMOND_DUAL_MESH_MANAGER_HPP diff --git a/src/mesh/IConnectivity.cpp b/src/mesh/IConnectivity.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48cf57d55ebceb7818f755fd9214807a247f6575 --- /dev/null +++ b/src/mesh/IConnectivity.cpp @@ -0,0 +1,10 @@ +#include <mesh/IConnectivity.hpp> + +#include <mesh/DiamondDualConnectivityManager.hpp> +#include <mesh/SynchronizerManager.hpp> + +IConnectivity::~IConnectivity() +{ + SynchronizerManager::instance().deleteConnectivitySynchronizer(this); + DiamondDualConnectivityManager::instance().deleteConnectivity(this); +} diff --git a/src/mesh/IConnectivity.hpp b/src/mesh/IConnectivity.hpp index 27be707cbcc4976b17e9db1e7bf6f37195c9d63a..9bfb8e5043088a18880440235cd72b1677c1f519 100644 --- a/src/mesh/IConnectivity.hpp +++ b/src/mesh/IConnectivity.hpp @@ -35,7 +35,7 @@ class IConnectivity : public std::enable_shared_from_this<IConnectivity> IConnectivity() = default; IConnectivity(IConnectivity&&) = delete; IConnectivity(const IConnectivity&) = delete; - ~IConnectivity() = default; + virtual ~IConnectivity(); }; template <> diff --git a/src/mesh/IMesh.cpp b/src/mesh/IMesh.cpp index cb2accc141ed09c778237587373494797fee726d..f315f4b74b01eb371c42eb4bf029f81e93ae6016 100644 --- a/src/mesh/IMesh.cpp +++ b/src/mesh/IMesh.cpp @@ -1,8 +1,10 @@ #include <mesh/IMesh.hpp> +#include <mesh/DiamondDualMeshManager.hpp> #include <mesh/MeshDataManager.hpp> IMesh::~IMesh() { - MeshDataManager::instance().deleteMeshData(*this); + MeshDataManager::instance().deleteMeshData(this); + DiamondDualMeshManager::instance().deleteMesh(this); } diff --git a/src/mesh/ItemIdToItemIdMap.hpp b/src/mesh/ItemIdToItemIdMap.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0e92eb13ce3943c4e2487081ee2e48fc3deac8ee --- /dev/null +++ b/src/mesh/ItemIdToItemIdMap.hpp @@ -0,0 +1,30 @@ +#ifndef ITEM_ID_TO_ITEM_ID_MAP_HPP +#define ITEM_ID_TO_ITEM_ID_MAP_HPP + +#include <mesh/ItemId.hpp> +#include <utils/Array.hpp> + +template <ItemType type1, ItemType type2> +using ItemIdToItemIdMap = Array<std::pair<ItemIdT<type1>, ItemIdT<type2>>>; + +using NodeIdToNodeIdMap = ItemIdToItemIdMap<ItemType::node, ItemType::node>; +using NodeIdToEdgeIdMap = ItemIdToItemIdMap<ItemType::node, ItemType::edge>; +using NodeIdToFaceIdMap = ItemIdToItemIdMap<ItemType::node, ItemType::face>; +using NodeIdToCellIdMap = ItemIdToItemIdMap<ItemType::node, ItemType::cell>; + +using EdgeIdToNodeIdMap = ItemIdToItemIdMap<ItemType::edge, ItemType::node>; +using EdgeIdToEdgeIdMap = ItemIdToItemIdMap<ItemType::edge, ItemType::edge>; +using EdgeIdToFaceIdMap = ItemIdToItemIdMap<ItemType::edge, ItemType::face>; +using EdgeIdToCellIdMap = ItemIdToItemIdMap<ItemType::edge, ItemType::cell>; + +using FaceIdToNodeIdMap = ItemIdToItemIdMap<ItemType::face, ItemType::node>; +using FaceIdToEdgeIdMap = ItemIdToItemIdMap<ItemType::face, ItemType::edge>; +using FaceIdToFaceIdMap = ItemIdToItemIdMap<ItemType::face, ItemType::face>; +using FaceIdToCellIdMap = ItemIdToItemIdMap<ItemType::face, ItemType::cell>; + +using CellIdToNodeIdMap = ItemIdToItemIdMap<ItemType::cell, ItemType::node>; +using CellIdToEdgeIdMap = ItemIdToItemIdMap<ItemType::cell, ItemType::edge>; +using CellIdToFaceIdMap = ItemIdToItemIdMap<ItemType::cell, ItemType::face>; +using CellIdToCellIdMap = ItemIdToItemIdMap<ItemType::cell, ItemType::cell>; + +#endif // ITEM_ID_TO_ITEM_ID_MAP_HPP diff --git a/src/mesh/ItemToItemMatrix.hpp b/src/mesh/ItemToItemMatrix.hpp index e8d7071af5ae2c09b60c10478560087f5b2bdc86..1cb20d3ee595cf0963b95b4cc67f201cf2cddb5c 100644 --- a/src/mesh/ItemToItemMatrix.hpp +++ b/src/mesh/ItemToItemMatrix.hpp @@ -29,8 +29,10 @@ class ItemToItemMatrix } PUGS_INLINE - TargetItemId operator[](size_t j) const + TargetItemId + operator[](size_t j) const { + Assert(j < m_row.length); return m_row(j); } @@ -73,15 +75,19 @@ class ItemToItemMatrix } PUGS_INLINE - auto operator[](const SourceItemId& source_id) const + auto + operator[](const SourceItemId& source_id) const { + Assert(source_id < m_connectivity_matrix.numRows()); using RowType = decltype(m_connectivity_matrix.rowConst(source_id)); return SubItemList<RowType>(m_connectivity_matrix.rowConst(source_id)); } template <typename IndexType> - PUGS_INLINE const auto& operator[](const IndexType& source_id) const + PUGS_INLINE const auto& + operator[](const IndexType& source_id) const { + Assert(source_id < m_connectivity_matrix.numRows()); static_assert(std::is_same_v<IndexType, SourceItemId>, "ItemToItemMatrix must be indexed using correct ItemId"); using RowType = decltype(m_connectivity_matrix.rowConst(source_id)); return SubItemList<RowType>(m_connectivity_matrix.rowConst(source_id)); diff --git a/src/mesh/MeshData.hpp b/src/mesh/MeshData.hpp index 86e78f5f7fde25656882535258f6fb3779855d01..c82e9ce06ec8b7d43ce1c6cc2fec282f89dc1fee 100644 --- a/src/mesh/MeshData.hpp +++ b/src/mesh/MeshData.hpp @@ -32,36 +32,113 @@ class MeshData : public IMeshData private: const MeshType& m_mesh; - std::shared_ptr<NodeValuePerCell<const Rd>> m_Cjr; - std::shared_ptr<NodeValuePerCell<const double>> m_ljr; - std::shared_ptr<NodeValuePerCell<const Rd>> m_njr; - std::shared_ptr<CellValue<const Rd>> m_xj; - std::shared_ptr<CellValue<const double>> m_Vj; - std::shared_ptr<NodeValuePerFace<const Rd>> m_Nlr; + NodeValuePerFace<const Rd> m_Nlr; + NodeValuePerFace<const Rd> m_nlr; + NodeValuePerCell<const Rd> m_Cjr; + NodeValuePerCell<const double> m_ljr; + NodeValuePerCell<const Rd> m_njr; + FaceValue<const Rd> m_xl; + CellValue<const Rd> m_cell_centroid; + CellValue<const Rd> m_cell_iso_barycenter; + CellValue<const double> m_Vj; + FaceValue<const double> m_ll; PUGS_INLINE void - _computeIsobarycenter() + _compute_ll() + { + if constexpr (Dimension == 1) { + static_assert(Dimension != 1, "ll does not make sense in 1d"); + } else { + const auto& Nlr = this->Nlr(); + + FaceValue<double> ll{m_mesh.connectivity()}; + + const auto& face_to_node_matrix = m_mesh.connectivity().faceToNodeMatrix(); + parallel_for( + m_mesh.numberOfFaces(), PUGS_LAMBDA(FaceId face_id) { + const auto& face_nodes = face_to_node_matrix[face_id]; + + double lenght = 0; + for (size_t i_node = 0; i_node < face_nodes.size(); ++i_node) { + lenght += l2Norm(Nlr(face_id, i_node)); + } + + ll[face_id] = lenght; + }); + + m_ll = ll; + } + } + + PUGS_INLINE + void + _compute_nlr() + { + if constexpr (Dimension == 1) { + static_assert(Dimension != 1, "nlr does not make sense in 1d"); + } else { + const auto& Nlr = this->Nlr(); + + NodeValuePerFace<Rd> nlr{m_mesh.connectivity()}; + + parallel_for( + Nlr.numberOfValues(), PUGS_LAMBDA(size_t lr) { + double length = l2Norm(Nlr[lr]); + nlr[lr] = 1. / length * Nlr[lr]; + }); + + m_nlr = nlr; + } + } + + PUGS_INLINE + void + _computeFaceIsobarycenter() + { // Computes vertices isobarycenter + if constexpr (Dimension == 1) { + static_assert(Dimension != 1, "xl does not make sense in 1d"); + } else { + const NodeValue<const Rd>& xr = m_mesh.xr(); + + const auto& face_to_node_matrix = m_mesh.connectivity().faceToNodeMatrix(); + FaceValue<Rd> xl(m_mesh.connectivity()); + parallel_for( + m_mesh.numberOfFaces(), PUGS_LAMBDA(FaceId face_id) { + Rd X = zero; + const auto& face_nodes = face_to_node_matrix[face_id]; + for (size_t R = 0; R < face_nodes.size(); ++R) { + X += xr[face_nodes[R]]; + } + xl[face_id] = 1. / face_nodes.size() * X; + }); + m_xl = xl; + } + } + + PUGS_INLINE + void + _computeCellIsoBarycenter() { // Computes vertices isobarycenter if constexpr (Dimension == 1) { const NodeValue<const Rd>& xr = m_mesh.xr(); const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); - CellValue<Rd> xj(m_mesh.connectivity()); + CellValue<Rd> cell_iso_barycenter{m_mesh.connectivity()}; parallel_for( m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { const auto& cell_nodes = cell_to_node_matrix[j]; - xj[j] = 0.5 * (xr[cell_nodes[0]] + xr[cell_nodes[1]]); + cell_iso_barycenter[j] = 0.5 * (xr[cell_nodes[0]] + xr[cell_nodes[1]]); }); - m_xj = std::make_shared<CellValue<const Rd>>(xj); + m_cell_iso_barycenter = cell_iso_barycenter; } else { const NodeValue<const Rd>& xr = m_mesh.xr(); const CellValue<const double>& inv_cell_nb_nodes = m_mesh.connectivity().invCellNbNodes(); const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); - CellValue<Rd> xj(m_mesh.connectivity()); + CellValue<Rd> cell_iso_barycenter{m_mesh.connectivity()}; parallel_for( m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { Rd X = zero; @@ -69,9 +146,98 @@ class MeshData : public IMeshData for (size_t R = 0; R < cell_nodes.size(); ++R) { X += xr[cell_nodes[R]]; } - xj[j] = inv_cell_nb_nodes[j] * X; + cell_iso_barycenter[j] = inv_cell_nb_nodes[j] * X; }); - m_xj = std::make_shared<CellValue<const Rd>>(xj); + m_cell_iso_barycenter = cell_iso_barycenter; + } + } + + PUGS_INLINE + void + _computeCellCentroid() + { + const CellValue<const Rd> cell_iso_barycenter = this->cellIsoBarycenter(); + if constexpr (Dimension == 1) { + m_cell_centroid = cell_iso_barycenter; + } else { + if constexpr (Dimension == 2) { + const CellValue<const double> Vj = this->Vj(); + const NodeValue<const Rd>& xr = m_mesh.xr(); + const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); + + CellValue<Rd> cell_centroid{m_mesh.connectivity()}; + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + Rd sum = zero; + + const auto& cell_nodes = cell_to_node_matrix[j]; + + for (size_t R = 0; R < cell_nodes.size(); ++R) { + const Rd& xr0 = xr[cell_nodes[R]]; + const Rd& xr1 = xr[cell_nodes[(R + 1) % cell_nodes.size()]]; + + Rd xjxr0 = xr[cell_nodes[R]] - cell_iso_barycenter[j]; + Rd xjxr1 = xr[cell_nodes[(R + 1) % cell_nodes.size()]] - cell_iso_barycenter[j]; + + const double Vjl = 0.5 * (xjxr0[0] * xjxr1[1] - xjxr0[1] * xjxr1[0]); + + sum += Vjl * (xr0 + xr1 + cell_iso_barycenter[j]); + } + + sum *= 1 / (3 * Vj[j]); + + cell_centroid[j] = sum; + }); + m_cell_centroid = cell_centroid; + } else { + const auto& face_center = this->xl(); + const CellValue<const double> Vj = this->Vj(); + const NodeValue<const Rd>& xr = m_mesh.xr(); + const auto& cell_to_face_matrix = m_mesh.connectivity().cellToFaceMatrix(); + const auto& face_to_node_matrix = m_mesh.connectivity().faceToNodeMatrix(); + const auto& cell_face_is_reversed = m_mesh.connectivity().cellFaceIsReversed(); + + CellValue<Rd> cell_centroid{m_mesh.connectivity()}; + parallel_for( + m_mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const Rd xj = m_cell_iso_barycenter[j]; + + const auto& cell_faces = cell_to_face_matrix[j]; + + Rd sum = zero; + for (size_t i_face = 0; i_face < cell_faces.size(); ++i_face) { + const FaceId face_id = cell_faces[i_face]; + + const Rd xl = face_center[face_id]; + + const Rd xjxl = xl - xj; + + const auto& face_nodes = face_to_node_matrix[face_id]; + + const Rd xl_plus_xj = xl + xj; + + double sign = (cell_face_is_reversed(j, i_face)) ? -1 : 1; + + for (size_t i_face_node = 0; i_face_node < face_nodes.size(); ++i_face_node) { + const Rd& xr0 = xr[face_nodes[i_face_node]]; + const Rd& xr1 = xr[face_nodes[(i_face_node + 1) % face_nodes.size()]]; + + const Rd xjxr0 = xr0 - xj; + const Rd xjxr1 = xr1 - xj; + + const double Vjlr = (crossProduct(xjxr0, xjxr1), xjxl); + + sum += (sign * Vjlr) * (xl_plus_xj + xr0 + xr1); + } + } + + sum *= 1 / (24 * Vj[j]); + + cell_centroid[j] = sum; + }); + + m_cell_centroid = cell_centroid; + } } } @@ -95,7 +261,7 @@ class MeshData : public IMeshData } Vj[j] = inv_Dimension * sum_cjr_xr; }); - m_Vj = std::make_shared<CellValue<const double>>(Vj); + m_Vj = Vj; } PUGS_INLINE @@ -123,7 +289,7 @@ class MeshData : public IMeshData Nlr(l, 0) = Nr; Nlr(l, 1) = Nr; }); - m_Nlr = std::make_shared<NodeValuePerFace<const Rd>>(Nlr); + m_Nlr = Nlr; } else { const NodeValue<const Rd>& xr = m_mesh.xr(); @@ -150,7 +316,7 @@ class MeshData : public IMeshData Nlr(l, r) = Nr; } }); - m_Nlr = std::make_shared<NodeValuePerFace<const Rd>>(Nlr); + m_Nlr = Nlr; } } @@ -165,7 +331,7 @@ class MeshData : public IMeshData Cjr(j, 0) = -1; Cjr(j, 1) = 1; }); - m_Cjr = std::make_shared<NodeValuePerCell<const Rd>>(Cjr); + m_Cjr = Cjr; } else if constexpr (Dimension == 2) { const NodeValue<const Rd>& xr = m_mesh.xr(); const auto& cell_to_node_matrix = m_mesh.connectivity().cellToNodeMatrix(); @@ -181,7 +347,7 @@ class MeshData : public IMeshData Cjr(j, R) = Rd{half_xrp_xrm[1], -half_xrp_xrm[0]}; } }); - m_Cjr = std::make_shared<NodeValuePerCell<const Rd>>(Cjr); + m_Cjr = Cjr; } else if (Dimension == 3) { auto Nlr = this->Nlr(); @@ -228,7 +394,7 @@ class MeshData : public IMeshData } }); - m_Cjr = std::make_shared<NodeValuePerCell<const Rd>>(Cjr); + m_Cjr = Cjr; } } @@ -241,13 +407,13 @@ class MeshData : public IMeshData NodeValuePerCell<double> ljr(m_mesh.connectivity()); parallel_for( ljr.numberOfValues(), PUGS_LAMBDA(size_t jr) { ljr[jr] = 1; }); - m_ljr = std::make_shared<NodeValuePerCell<const double>>(ljr); + m_ljr = ljr; } else { NodeValuePerCell<double> ljr(m_mesh.connectivity()); parallel_for( Cjr.numberOfValues(), PUGS_LAMBDA(size_t jr) { ljr[jr] = l2Norm(Cjr[jr]); }); - m_ljr = std::make_shared<NodeValuePerCell<const double>>(ljr); + m_ljr = ljr; } } @@ -265,19 +431,18 @@ class MeshData : public IMeshData NodeValuePerCell<Rd> njr(m_mesh.connectivity()); parallel_for( Cjr.numberOfValues(), PUGS_LAMBDA(size_t jr) { njr[jr] = (1. / ljr[jr]) * Cjr[jr]; }); - m_njr = std::make_shared<NodeValuePerCell<const Rd>>(njr); + m_njr = njr; } } void _checkCellVolume() { - Assert(m_Vj); - auto& Vj = *m_Vj; + Assert(m_Vj.isBuilt()); bool is_valid = [&] { for (CellId j = 0; j < m_mesh.numberOfCells(); ++j) { - if (Vj[j] <= 0) { + if (m_Vj[j] <= 0) { return false; } } @@ -297,65 +462,105 @@ class MeshData : public IMeshData return m_mesh; } + PUGS_INLINE + FaceValue<const double> + ll() + { + if (not m_ll.isBuilt()) { + this->_compute_ll(); + } + return m_ll; + } + PUGS_INLINE NodeValuePerFace<const Rd> Nlr() { - if (not m_Nlr) { + if (not m_Nlr.isBuilt()) { this->_computeNlr(); } - return *m_Nlr; + return m_Nlr; + } + + PUGS_INLINE + NodeValuePerFace<const Rd> + nlr() + { + if (not m_nlr.isBuilt()) { + this->_compute_nlr(); + } + return m_nlr; } PUGS_INLINE NodeValuePerCell<const Rd> Cjr() { - if (not m_Cjr) { + if (not m_Cjr.isBuilt()) { this->_computeCjr(); } - return *m_Cjr; + return m_Cjr; } PUGS_INLINE NodeValuePerCell<const double> ljr() { - if (not m_ljr) { + if (not m_ljr.isBuilt()) { this->_compute_ljr(); } - return *m_ljr; + return m_ljr; } PUGS_INLINE NodeValuePerCell<const Rd> njr() { - if (not m_njr) { + if (not m_njr.isBuilt()) { this->_compute_njr(); } - return *m_njr; + return m_njr; + } + + PUGS_INLINE + FaceValue<const Rd> + xl() + { + if (not m_xl.isBuilt()) { + this->_computeFaceIsobarycenter(); + } + return m_xl; + } + + PUGS_INLINE + CellValue<const Rd> + cellIsoBarycenter() + { + if (not m_cell_iso_barycenter.isBuilt()) { + this->_computeCellIsoBarycenter(); + } + return m_cell_iso_barycenter; } PUGS_INLINE CellValue<const Rd> xj() { - if (not m_xj) { - this->_computeIsobarycenter(); + if (not m_cell_centroid.isBuilt()) { + this->_computeCellCentroid(); } - return *m_xj; + return m_cell_centroid; } PUGS_INLINE CellValue<const double> Vj() { - if (not m_Vj) { + if (not m_Vj.isBuilt()) { this->_computeCellVolume(); this->_checkCellVolume(); } - return *m_Vj; + return m_Vj; } private: diff --git a/src/mesh/MeshDataManager.cpp b/src/mesh/MeshDataManager.cpp index 281e7517aa704e6c4352769e88f854b86cbc7366..8ca184a6013c083f5e8df7412d19f80b8f50f95a 100644 --- a/src/mesh/MeshDataManager.cpp +++ b/src/mesh/MeshDataManager.cpp @@ -35,9 +35,9 @@ MeshDataManager::destroy() } void -MeshDataManager::deleteMeshData(const IMesh& mesh) +MeshDataManager::deleteMeshData(const IMesh* p_mesh) { - m_mesh_mesh_data_map.erase(&mesh); + m_mesh_mesh_data_map.erase(p_mesh); } template <size_t Dimension> diff --git a/src/mesh/MeshDataManager.hpp b/src/mesh/MeshDataManager.hpp index 7b127148b889bc585082d626b79c435293fa4cd7..fd04101dea29a2d15e0feb2193f22f785ff65dc3 100644 --- a/src/mesh/MeshDataManager.hpp +++ b/src/mesh/MeshDataManager.hpp @@ -5,8 +5,8 @@ #include <utils/PugsAssert.hpp> #include <utils/PugsMacros.hpp> -#include <map> #include <memory> +#include <unordered_map> class IMesh; @@ -22,7 +22,7 @@ class MeshData; class MeshDataManager { private: - std::map<const IMesh*, std::shared_ptr<IMeshData>> m_mesh_mesh_data_map; + std::unordered_map<const IMesh*, std::shared_ptr<IMeshData>> m_mesh_mesh_data_map; static MeshDataManager* m_instance; @@ -44,7 +44,7 @@ class MeshDataManager return *m_instance; } - void deleteMeshData(const IMesh&); + void deleteMeshData(const IMesh*); template <size_t Dimension> MeshData<Dimension>& getMeshData(const Mesh<Connectivity<Dimension>>&); diff --git a/src/mesh/SubItemValuePerItem.hpp b/src/mesh/SubItemValuePerItem.hpp index 9ce6369e07b63537ac698149703547aa107e83cd..66af694c7255da41ff7570d294dd4777acb0164f 100644 --- a/src/mesh/SubItemValuePerItem.hpp +++ b/src/mesh/SubItemValuePerItem.hpp @@ -54,16 +54,18 @@ class SubItemValuePerItem const size_t m_size; public: - PUGS_INLINE - const DataType& operator[](size_t i) const noexcept(NO_ASSERT) + template <typename IndexType> + PUGS_INLINE const DataType& operator[](IndexType i) const noexcept(NO_ASSERT) { + static_assert(std::is_integral_v<IndexType>, "SubView is indexed by integral values"); Assert(i < m_size); return m_sub_values[i]; } - PUGS_FORCEINLINE - DataType& operator[](size_t i) noexcept(NO_ASSERT) + template <typename IndexType> + PUGS_FORCEINLINE DataType& operator[](IndexType i) noexcept(NO_ASSERT) { + static_assert(std::is_integral_v<IndexType>, "SubView is indexed by integral values"); Assert(i < m_size); return m_sub_values[i]; } @@ -96,23 +98,15 @@ class SubItemValuePerItem return m_connectivity_ptr.use_count() != 0; } - // Following Kokkos logic, these classes are view and const view does allow - // changes in data - PUGS_FORCEINLINE - DataType& - operator()(ItemId j, size_t r) const noexcept(NO_ASSERT) - { - Assert(this->isBuilt()); - return m_values[m_host_row_map(size_t{j}) + r]; - } - - template <typename IndexType> + template <typename IndexType, typename SubIndexType> PUGS_FORCEINLINE DataType& - operator()(IndexType j, size_t r) const noexcept(NO_ASSERT) + operator()(IndexType item_id, SubIndexType i) const noexcept(NO_ASSERT) { - static_assert(std::is_same_v<IndexType, ItemId>, "SubItemValuePerItem indexed by ItemId"); + static_assert(std::is_same_v<IndexType, ItemId>, "first index must be of the correct ItemId type"); + static_assert(std::is_integral_v<SubIndexType>, "second index must be an integral type"); Assert(this->isBuilt()); - return m_values[m_host_row_map(size_t{j}) + r]; + Assert(i + m_host_row_map(size_t{item_id}) < m_host_row_map(size_t{item_id} + 1)); + return m_values[m_host_row_map(size_t{item_id}) + i]; } PUGS_INLINE @@ -125,19 +119,12 @@ class SubItemValuePerItem // Following Kokkos logic, these classes are view and const view does allow // changes in data - PUGS_FORCEINLINE - DataType& operator[](size_t i) const noexcept(NO_ASSERT) + template <typename ArrayIndexType> + DataType& operator[](const ArrayIndexType& i) const noexcept(NO_ASSERT) { + static_assert(std::is_integral_v<ArrayIndexType>, "index must be an integral type"); Assert(this->isBuilt()); - return m_values[i]; - } - - template <typename IndexType> - DataType& operator[](const IndexType& i) const noexcept(NO_ASSERT) - { - static_assert(std::is_same_v<IndexType, size_t>, "Access to SubItemValuePerItem's array must be indexed by " - "size_t"); - Assert(this->isBuilt()); + Assert(i < m_values.size()); return m_values[i]; } @@ -150,34 +137,40 @@ class SubItemValuePerItem return m_host_row_map.extent(0); } - PUGS_INLINE - size_t - numberOfSubValues(size_t i_cell) const noexcept(NO_ASSERT) + template <typename IndexType> + PUGS_INLINE size_t + numberOfSubValues(IndexType item_id) const noexcept(NO_ASSERT) { + static_assert(std::is_same_v<IndexType, ItemId>, "index must be an ItemId"); Assert(this->isBuilt()); - return m_host_row_map(i_cell + 1) - m_host_row_map(i_cell); + Assert(item_id < m_host_row_map.extent(0)); + return m_host_row_map(size_t{item_id} + 1) - m_host_row_map(size_t{item_id}); } - PUGS_INLINE - SubView - itemValues(size_t i_cell) noexcept(NO_ASSERT) + template <typename IndexType> + PUGS_INLINE SubView + itemValues(IndexType item_id) noexcept(NO_ASSERT) { + static_assert(std::is_same_v<IndexType, ItemId>, "index must be an ItemId"); Assert(this->isBuilt()); - const auto& cell_begin = m_host_row_map(i_cell); - const auto& cell_end = m_host_row_map(i_cell + 1); - return SubView(m_values, cell_begin, cell_end); + Assert(item_id < m_host_row_map.extent(0)); + const auto& item_begin = m_host_row_map(size_t{item_id}); + const auto& item_end = m_host_row_map(size_t{item_id} + 1); + return SubView(m_values, item_begin, item_end); } // Following Kokkos logic, these classes are view and const view does allow // changes in data - PUGS_INLINE - SubView - itemValues(size_t i_cell) const noexcept(NO_ASSERT) + template <typename IndexType> + PUGS_INLINE SubView + itemValues(IndexType item_id) const noexcept(NO_ASSERT) { + static_assert(std::is_same_v<IndexType, ItemId>, "index must be an ItemId"); Assert(this->isBuilt()); - const auto& cell_begin = m_host_row_map(i_cell); - const auto& cell_end = m_host_row_map(i_cell + 1); - return SubView(m_values, cell_begin, cell_end); + Assert(item_id < m_host_row_map.extent(0)); + const auto& item_begin = m_host_row_map(size_t{item_id}); + const auto& item_end = m_host_row_map(size_t{item_id} + 1); + return SubView(m_values, item_begin, item_end); } template <typename DataType2, typename ConnectivityPtr2> diff --git a/src/mesh/SynchronizerManager.hpp b/src/mesh/SynchronizerManager.hpp index 79cb3db0a3473bdbe9f88d4d20836a835aca9260..8bcb441f05c4e841a71c103f9a252bb52c59dcb2 100644 --- a/src/mesh/SynchronizerManager.hpp +++ b/src/mesh/SynchronizerManager.hpp @@ -4,8 +4,8 @@ #include <utils/PugsAssert.hpp> #include <utils/PugsMacros.hpp> -#include <map> #include <memory> +#include <unordered_map> class IConnectivity; class Synchronizer; @@ -13,7 +13,7 @@ class Synchronizer; class SynchronizerManager { private: - std::map<const IConnectivity*, std::shared_ptr<Synchronizer>> m_connectivity_synchronizer_map; + std::unordered_map<const IConnectivity*, std::shared_ptr<Synchronizer>> m_connectivity_synchronizer_map; static SynchronizerManager* m_instance; diff --git a/src/output/VTKWriter.hpp b/src/output/VTKWriter.hpp index 5d85b3630e2afc77ef7f2a3422b2f7d207abe5b7..f3c202ffc51633d291d36150d662fe950023ef58 100644 --- a/src/output/VTKWriter.hpp +++ b/src/output/VTKWriter.hpp @@ -8,12 +8,14 @@ #include <output/OutputNamedItemValueSet.hpp> #include <utils/Exceptions.hpp> #include <utils/Messenger.hpp> +#include <utils/PugsAssert.hpp> #include <fstream> #include <iomanip> #include <iostream> #include <sstream> #include <string> +#include <unordered_map> class VTKWriter { @@ -234,6 +236,10 @@ class VTKWriter std::visit([&, name = name](auto&& item_value) { return this->_write_cell_pvtu(fout, name, item_value); }, item_value_variant); } + if constexpr (MeshType::Dimension == 3) { + fout << "<PDataArray type=\"Int64\" IdType=\"1\" Name=\"faces\"/>\n"; + fout << "<PDataArray type=\"Int64\" IdType=\"1\" Name=\"faceoffsets\"/>\n"; + } fout << "</PCells>\n"; fout << "<PPointData>\n"; @@ -315,7 +321,9 @@ class VTKWriter { Array<int8_t> types(mesh->numberOfCells()); - const auto& cell_type = mesh->connectivity().cellType(); + const auto& cell_type = mesh->connectivity().cellType(); + const auto& cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix(); + parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { switch (cell_type[j]) { @@ -336,7 +344,11 @@ class VTKWriter break; } case CellType::Pyramid: { - types[j] = 14; + if (cell_to_node_matrix[j].size() == 5) { + types[j] = 14; // quadrangle basis + } else { + types[j] = 41; // polygonal basis + } break; } case CellType::Prism: { @@ -347,6 +359,10 @@ class VTKWriter types[j] = 12; break; } + case CellType::Diamond: { + types[j] = 41; + break; + } default: { std::ostringstream os; os << __FILE__ << ':' << __LINE__ << ": unknown cell type"; @@ -355,6 +371,70 @@ class VTKWriter } }); _write_array(fout, "types", types); + if constexpr (MeshType::Dimension == 3) { + const bool has_general_polyhedron = [&] { + for (size_t i = 0; i < types.size(); ++i) { + if (types[i] == 41) + return true; + } + return false; + }(); + if (has_general_polyhedron) { + const auto& cell_to_face_matrix = mesh->connectivity().cellToFaceMatrix(); + const auto& face_to_node_matrix = mesh->connectivity().faceToNodeMatrix(); + const auto& cell_face_is_reversed = mesh->connectivity().cellFaceIsReversed(); + + Array<size_t> faces_offsets(mesh->numberOfCells()); + size_t next_offset = 0; + fout << "<DataArray type=\"Int64\" IdType=\"1\" Name=\"faces\">\n"; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + const auto& cell_nodes = cell_to_node_matrix[cell_id]; + std::unordered_map<size_t, size_t> node_id_to_local_number_in_cell; + for (size_t i_cell_node = 0; i_cell_node < cell_nodes.size(); ++i_cell_node) { + node_id_to_local_number_in_cell[cell_nodes[i_cell_node]] = i_cell_node; + } + + const auto& cell_faces = cell_to_face_matrix[cell_id]; + fout << cell_faces.size() << '\n'; + next_offset++; + for (size_t i_cell_face = 0; i_cell_face < cell_faces.size(); ++i_cell_face) { + const FaceId& face_id = cell_faces[i_cell_face]; + const auto& face_nodes = face_to_node_matrix[face_id]; + fout << face_nodes.size(); + next_offset++; + Array<size_t> face_node_in_cell(face_nodes.size()); + + for (size_t i_face_node = 0; i_face_node < face_nodes.size(); ++i_face_node) { + const NodeId& node_id = face_nodes[i_face_node]; + auto i_node_id_to_local_number_in_cell = node_id_to_local_number_in_cell.find(node_id); + Assert(i_node_id_to_local_number_in_cell != node_id_to_local_number_in_cell.end()); + face_node_in_cell[i_face_node] = i_node_id_to_local_number_in_cell->second; + } + + if (cell_face_is_reversed(cell_id, i_cell_face)) { + for (size_t i = 0; i < face_node_in_cell.size(); ++i) { + fout << ' ' << face_node_in_cell[face_node_in_cell.size() - 1 - i]; + } + } else { + for (size_t i = 0; i < face_node_in_cell.size(); ++i) { + fout << ' ' << face_node_in_cell[i]; + } + } + + next_offset += face_nodes.size(); + + fout << '\n'; + } + faces_offsets[cell_id] = next_offset; + } + fout << "</DataArray>\n"; + fout << "<DataArray type=\"Int64\" IdType=\"1\" Name=\"faceoffsets\">\n"; + for (size_t i_face_offsets = 0; i_face_offsets < faces_offsets.size(); ++i_face_offsets) { + fout << faces_offsets[i_face_offsets] << '\n'; + } + fout << "</DataArray>\n"; + } + } } fout << "</Cells>\n"; diff --git a/src/scheme/AcousticSolver.hpp b/src/scheme/AcousticSolver.hpp index d0eb4d0b699709e0cddff74035e6b2263b7fffd2..3e3151d25429593955cb281c2dd814690f67bfa5 100644 --- a/src/scheme/AcousticSolver.hpp +++ b/src/scheme/AcousticSolver.hpp @@ -1,47 +1,170 @@ #ifndef ACOUSTIC_SOLVER_HPP #define ACOUSTIC_SOLVER_HPP -#include <rang.hpp> - -#include <utils/ArrayUtils.hpp> - -#include <scheme/BlockPerfectGas.hpp> -#include <utils/PugsAssert.hpp> - -#include <scheme/BoundaryCondition.hpp> -#include <scheme/FiniteVolumesEulerUnknowns.hpp> - -#include <mesh/Mesh.hpp> -#include <mesh/MeshData.hpp> -#include <mesh/MeshDataManager.hpp> - #include <algebra/TinyMatrix.hpp> #include <algebra/TinyVector.hpp> - #include <mesh/ItemValueUtils.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/MeshData.hpp> +#include <mesh/MeshDataManager.hpp> +#include <mesh/MeshNodeBoundary.hpp> #include <mesh/SubItemValuePerItem.hpp> - +#include <scheme/AcousticSolverType.hpp> +#include <scheme/BlockPerfectGas.hpp> +#include <scheme/FiniteVolumesEulerUnknowns.hpp> +#include <utils/ArrayUtils.hpp> #include <utils/Exceptions.hpp> #include <utils/Messenger.hpp> +#include <utils/PugsAssert.hpp> + +#include <rang.hpp> #include <iostream> template <typename MeshType> class AcousticSolver { + public: + class PressureBoundaryCondition; + class SymmetryBoundaryCondition; + class VelocityBoundaryCondition; + + using BoundaryCondition = + std::variant<PressureBoundaryCondition, SymmetryBoundaryCondition, VelocityBoundaryCondition>; + + using BoundaryConditionList = std::vector<BoundaryCondition>; + constexpr static size_t Dimension = MeshType::Dimension; + private: using MeshDataType = MeshData<Dimension>; using UnknownsType = FiniteVolumesEulerUnknowns<MeshType>; std::shared_ptr<const MeshType> m_mesh; const typename MeshType::Connectivity& m_connectivity; - const std::vector<BoundaryConditionHandler>& m_boundary_condition_list; using Rd = TinyVector<Dimension>; using Rdd = TinyMatrix<Dimension>; - private: + const BoundaryConditionList m_boundary_condition_list; + + const AcousticSolverType m_solver_type; + + void + _applyPressureBC() + { + for (const auto& boundary_condition : m_boundary_condition_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(*m_mesh); + if constexpr (Dimension == 1) { + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + + const auto& node_to_cell_matrix = m_connectivity.nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = m_connectivity.nodeLocalNumbersInTheirCells(); + + const auto& node_list = bc.faceList(); + 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); + + m_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 = m_connectivity.faceToCellMatrix(); + const auto& face_to_node_matrix = m_connectivity.faceToNodeMatrix(); + const auto& face_local_numbers_in_their_cells = m_connectivity.faceLocalNumbersInTheirCells(); + const auto& face_cell_is_reversed = m_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]; + m_br[node_id] -= sign * value_list[i_face] * Nlr(face_id, i_node); + } + } + } + } + }, + boundary_condition); + } + } + + void + _applySymmetryBC() + { + for (const auto& boundary_condition : m_boundary_condition_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 Rdd I = identity; + const Rdd nxn = tensorProduct(n, n); + const Rdd 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]; + + m_Ar[r] = P * m_Ar[r] * P + nxn; + m_br[r] = P * m_br[r]; + }); + } + }, + boundary_condition); + } + } + + void + _applyVelocityBC() + { + for (const auto& boundary_condition : m_boundary_condition_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]; + + m_Ar[node_id] = identity; + m_br[node_id] = value; + }); + } + }, + boundary_condition); + } + } + PUGS_INLINE const CellValue<const double> computeRhoCj(const CellValue<const double>& rhoj, const CellValue<const double>& cj) @@ -53,11 +176,13 @@ class AcousticSolver PUGS_INLINE void - computeAjr(const CellValue<const double>& rhocj, - const NodeValuePerCell<const Rd>& Cjr, - const NodeValuePerCell<const double>& /* ljr */, - const NodeValuePerCell<const Rd>& njr) + _computeGlaceAjr(const CellValue<const double>& rhocj) { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh); + + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + const NodeValuePerCell<const Rd> njr = mesh_data.njr(); + parallel_for( m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) { const size_t& nb_nodes = m_Ajr.numberOfSubValues(j); @@ -68,6 +193,71 @@ class AcousticSolver }); } + PUGS_INLINE + void + _computeEucclhydAjr(const CellValue<const double>& rhocj) + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh); + + const NodeValuePerFace<const Rd> Nlr = mesh_data.Nlr(); + const NodeValuePerFace<const Rd> nlr = mesh_data.nlr(); + + const auto& face_to_node_matrix = m_connectivity.faceToNodeMatrix(); + const auto& cell_to_node_matrix = m_connectivity.cellToNodeMatrix(); + const auto& cell_to_face_matrix = m_connectivity.cellToFaceMatrix(); + + parallel_for( + m_Ajr.numberOfValues(), PUGS_LAMBDA(size_t jr) { m_Ajr[jr] = zero; }); + + parallel_for( + m_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_c = rhocj[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]); + m_Ajr(j, R) += tensorProduct(rho_c * Nlr(l, rl), nlr(l, rl)); + } + } + }); + } + + PUGS_INLINE + void + computeAjr(const CellValue<const double>& rhocj) + { + switch (m_solver_type) { + case AcousticSolverType::Glace: { + this->_computeGlaceAjr(rhocj); + break; + } + case AcousticSolverType::Eucclhyd: { + if constexpr (Dimension > 1) { + this->_computeEucclhydAjr(rhocj); + } else { + this->_computeGlaceAjr(rhocj); + } + break; + } + } + } + PUGS_INLINE const NodeValue<const Rdd> computeAr(const NodeValuePerCell<const Rdd>& Ajr) @@ -94,11 +284,13 @@ class AcousticSolver PUGS_INLINE const NodeValue<const Rd> - computeBr(const NodeValuePerCell<Rdd>& Ajr, - const NodeValuePerCell<const Rd>& Cjr, - const CellValue<const Rd>& uj, - const CellValue<const double>& pj) + computeBr(const CellValue<const Rd>& uj, const CellValue<const double>& pj) { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh); + + const NodeValuePerCell<const Rd>& Cjr = mesh_data.Cjr(); + const NodeValuePerCell<const Rdd>& Ajr = m_Ajr; + const auto& node_to_cell_matrix = m_connectivity.nodeToCellMatrix(); const auto& node_local_numbers_in_their_cells = m_connectivity.nodeLocalNumbersInTheirCells(); @@ -121,58 +313,33 @@ class AcousticSolver void applyBoundaryConditions() { - for (const auto& handler : m_boundary_condition_list) { - switch (handler.boundaryCondition().type()) { - case BoundaryCondition::normal_velocity: { - throw NotImplementedError("normal_velocity BC"); - } - case BoundaryCondition::velocity: { - throw NotImplementedError("velocity BC"); - } - case BoundaryCondition::pressure: { - throw NotImplementedError("pressure BC"); - } - case BoundaryCondition::symmetry: { - const SymmetryBoundaryCondition<Dimension>& symmetry_bc = - dynamic_cast<const SymmetryBoundaryCondition<Dimension>&>(handler.boundaryCondition()); - const Rd& n = symmetry_bc.outgoingNormal(); - - const Rdd I = identity; - const Rdd nxn = tensorProduct(n, n); - const Rdd P = I - nxn; - - const Array<const NodeId>& node_list = symmetry_bc.nodeList(); - parallel_for( - symmetry_bc.numberOfNodes(), PUGS_LAMBDA(int r_number) { - const NodeId r = node_list[r_number]; - - m_Ar[r] = P * m_Ar[r] * P + nxn; - m_br[r] = P * m_br[r]; - }); - break; - } - } - } + this->_applyPressureBC(); + this->_applySymmetryBC(); + this->_applyVelocityBC(); } - NodeValue<Rd> - computeUr(const NodeValue<const Rdd>& Ar, const NodeValue<const Rd>& br) + void + computeUr() { + const NodeValue<const Rdd> Ar = m_Ar; + const NodeValue<const Rd> br = m_br; + inverse(Ar, m_inv_Ar); const NodeValue<const Rdd> invAr = m_inv_Ar; parallel_for( m_mesh->numberOfNodes(), PUGS_LAMBDA(NodeId r) { m_ur[r] = invAr[r] * br[r]; }); - - return m_ur; } void - computeFjr(const NodeValuePerCell<Rdd>& Ajr, - const NodeValue<const Rd>& ur, - const NodeValuePerCell<const Rd>& Cjr, - const CellValue<const Rd>& uj, - const CellValue<const double>& pj) + computeFjr(const CellValue<const Rd>& uj, const CellValue<const double>& pj) { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh); + + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + const NodeValuePerCell<const Rdd> Ajr = m_Ajr; + + const NodeValue<const Rd> ur = m_ur; + const auto& cell_to_node_matrix = m_mesh->connectivity().cellToNodeMatrix(); parallel_for( @@ -197,26 +364,22 @@ class AcousticSolver computeExplicitFluxes(const CellValue<const double>& rhoj, const CellValue<const Rd>& uj, const CellValue<const double>& pj, - const CellValue<const double>& cj, - const NodeValuePerCell<const Rd>& Cjr, - const NodeValuePerCell<const double>& ljr, - const NodeValuePerCell<const Rd>& njr) + const CellValue<const double>& cj) { const CellValue<const double> rhocj = computeRhoCj(rhoj, cj); - computeAjr(rhocj, Cjr, ljr, njr); + computeAjr(rhocj); NodeValuePerCell<const Rdd> Ajr = m_Ajr; this->computeAr(Ajr); - this->computeBr(m_Ajr, Cjr, uj, pj); + this->computeBr(uj, pj); this->applyBoundaryConditions(); synchronize(m_Ar); synchronize(m_br); - NodeValue<Rd>& ur = m_ur; - ur = computeUr(m_Ar, m_br); - computeFjr(m_Ajr, ur, Cjr, uj, pj); + computeUr(); + computeFjr(uj, pj); } NodeValue<Rd> m_br; @@ -229,10 +392,13 @@ class AcousticSolver CellValue<double> m_Vj_over_cj; public: - AcousticSolver(std::shared_ptr<const MeshType> p_mesh, const std::vector<BoundaryConditionHandler>& bc_list) + AcousticSolver(std::shared_ptr<const MeshType> p_mesh, + const BoundaryConditionList& bc_list, + const AcousticSolverType solver_type) : m_mesh(p_mesh), m_connectivity(m_mesh->connectivity()), m_boundary_condition_list(bc_list), + m_solver_type(solver_type), m_br(m_connectivity), m_Ajr(m_connectivity), m_Ar(m_connectivity), @@ -281,12 +447,9 @@ class AcousticSolver MeshData<Dimension>& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh); - const CellValue<const double> Vj = mesh_data.Vj(); - const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); - const NodeValuePerCell<const double> ljr = mesh_data.ljr(); - const NodeValuePerCell<const Rd> njr = mesh_data.njr(); + const CellValue<const double> Vj = mesh_data.Vj(); - computeExplicitFluxes(rhoj, uj, pj, cj, Cjr, ljr, njr); + computeExplicitFluxes(rhoj, uj, pj, cj); const NodeValuePerCell<Rd>& Fjr = m_Fjr; const NodeValue<const Rd> ur = m_ur; @@ -326,4 +489,124 @@ class AcousticSolver } }; +template <typename MeshType> +class AcousticSolver<MeshType>::PressureBoundaryCondition +{ + private: + const Array<const double> m_value_list; + const Array<const FaceId> m_face_list; + + public: + const Array<const FaceId>& + faceList() const + { + return m_face_list; + } + + const Array<const double>& + valueList() const + { + return m_value_list; + } + + PressureBoundaryCondition(const Array<const FaceId>& face_list, const Array<const double>& value_list) + : m_value_list{value_list}, m_face_list{face_list} + {} + + ~PressureBoundaryCondition() = default; +}; + +template <> +class AcousticSolver<Mesh<Connectivity<1>>>::PressureBoundaryCondition +{ + private: + const Array<const double> m_value_list; + const Array<const NodeId> m_face_list; + + public: + const Array<const NodeId>& + faceList() const + { + return m_face_list; + } + + const Array<const double>& + valueList() const + { + return m_value_list; + } + + PressureBoundaryCondition(const Array<const NodeId>& face_list, const Array<const double>& value_list) + : m_value_list{value_list}, m_face_list{face_list} + {} + + ~PressureBoundaryCondition() = default; +}; + +template <typename MeshType> +class AcousticSolver<MeshType>::VelocityBoundaryCondition +{ + private: + const Array<const TinyVector<Dimension>> m_value_list; + const Array<const NodeId> m_node_list; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_node_list; + } + + const Array<const TinyVector<Dimension>>& + valueList() const + { + return m_value_list; + } + + VelocityBoundaryCondition(const Array<const NodeId>& node_list, const Array<const TinyVector<Dimension>>& value_list) + : m_value_list{value_list}, m_node_list{node_list} + {} + + ~VelocityBoundaryCondition() = default; +}; + +template <typename MeshType> +class AcousticSolver<MeshType>::SymmetryBoundaryCondition +{ + public: + static constexpr size_t Dimension = MeshType::Dimension; + + 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; +}; + #endif // ACOUSTIC_SOLVER_HPP diff --git a/src/scheme/AcousticSolverType.hpp b/src/scheme/AcousticSolverType.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3095dcc864d5598e985290302ad94106adbd6b2e --- /dev/null +++ b/src/scheme/AcousticSolverType.hpp @@ -0,0 +1,10 @@ +#ifndef ACOUSTIC_SOLVER_TYPE_HPP +#define ACOUSTIC_SOLVER_TYPE_HPP + +enum class AcousticSolverType +{ + Eucclhyd, + Glace +}; + +#endif // ACOUSTIC_SOLVER_TYPE_HPP diff --git a/src/scheme/BoundaryCondition.hpp b/src/scheme/BoundaryCondition.hpp deleted file mode 100644 index 3d3332fc92cfa88792ecf556cb97781de007a104..0000000000000000000000000000000000000000 --- a/src/scheme/BoundaryCondition.hpp +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef BOUNDARY_CONDITION_HANDLER_HPP -#define BOUNDARY_CONDITION_HANDLER_HPP - -#include <utils/Array.hpp> - -#include <mesh/MeshNodeBoundary.hpp> -#include <mesh/RefItemList.hpp> - -#include <memory> -#include <vector> - -class BoundaryCondition // clazy:exclude=copyable-polymorphic -{ - public: - enum Type - { - velocity, - normal_velocity, - pressure, - symmetry - }; - - const Type m_type; - - protected: - BoundaryCondition(Type type) : m_type(type) - { - ; - } - - public: - const Type& - type() const - { - return m_type; - } - - virtual ~BoundaryCondition() = default; -}; - -class PressureBoundaryCondition final : public BoundaryCondition // clazy:exclude=copyable-polymorphic -{ - private: - const double m_value; - - const size_t m_number_of_faces; - Array<const unsigned int> m_face_list; - - public: - double - value() const - { - return m_value; - } - - const size_t& - numberOfFaces() const - { - return m_number_of_faces; - } - - const Array<const unsigned int>& - faceList() const - { - return m_face_list; - } - - PressureBoundaryCondition(double value, const std::vector<unsigned int>& faces) - : BoundaryCondition(BoundaryCondition::pressure), m_value(value), m_number_of_faces(faces.size()) - { - Array<unsigned int> face_list(faces.size()); - parallel_for( - m_number_of_faces, PUGS_LAMBDA(int f) { face_list[f] = faces[f]; }); - m_face_list = face_list; - } - - ~PressureBoundaryCondition() = default; -}; - -template <size_t dimension> -class SymmetryBoundaryCondition : public BoundaryCondition -{ - 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) - : BoundaryCondition(BoundaryCondition::symmetry), m_mesh_flat_node_boundary(mesh_flat_node_boundary) - { - ; - } - - ~SymmetryBoundaryCondition() = default; -}; - -class BoundaryConditionHandler -{ - private: - std::shared_ptr<BoundaryCondition> m_boundary_condition; - - public: - const BoundaryCondition& - boundaryCondition() const - { - return *m_boundary_condition; - } - - PUGS_INLINE - BoundaryConditionHandler& operator=(BoundaryConditionHandler&) = default; - - PUGS_INLINE - BoundaryConditionHandler(const BoundaryConditionHandler&) = default; - - PUGS_INLINE - BoundaryConditionHandler(BoundaryConditionHandler&&) = default; - - PUGS_INLINE - BoundaryConditionHandler(std::shared_ptr<BoundaryCondition> boundary_condition) - : m_boundary_condition(boundary_condition) - {} - - ~BoundaryConditionHandler() = default; -}; - -#endif // BOUNDARY_CONDITION_HANDLER_HPP diff --git a/src/scheme/DirichletBoundaryConditionDescriptor.hpp b/src/scheme/DirichletBoundaryConditionDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5fa6c42f9d4b5333ad1ca5ef2fdb46a4f06b4242 --- /dev/null +++ b/src/scheme/DirichletBoundaryConditionDescriptor.hpp @@ -0,0 +1,64 @@ +#ifndef DIRICHLET_BOUNDARY_CONDITION_DESCRIPTOR_HPP +#define DIRICHLET_BOUNDARY_CONDITION_DESCRIPTOR_HPP + +#include <language/utils/FunctionSymbolId.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/IBoundaryDescriptor.hpp> + +#include <memory> + +class DirichletBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +{ + private: + std::ostream& + _write(std::ostream& os) const final + { + os << "dirichlet(" << m_name << ',' << *m_boundary_descriptor << ")"; + return os; + } + + const std::string_view m_name; + + std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; + const FunctionSymbolId m_rhs_symbol_id; + + public: + std::string_view + name() const + { + return m_name; + } + + FunctionSymbolId + rhsSymbolId() const + { + return m_rhs_symbol_id; + } + + const IBoundaryDescriptor& + boundaryDescriptor() const + { + return *m_boundary_descriptor; + } + + Type + type() const final + { + return Type::dirichlet; + } + + DirichletBoundaryConditionDescriptor(const std::string_view name, + std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor, + const FunctionSymbolId& rhs_symbol_id) + : m_name{name}, m_boundary_descriptor(boundary_descriptor), m_rhs_symbol_id{rhs_symbol_id} + { + ; + } + + DirichletBoundaryConditionDescriptor(const DirichletBoundaryConditionDescriptor&) = delete; + DirichletBoundaryConditionDescriptor(DirichletBoundaryConditionDescriptor&&) = delete; + + ~DirichletBoundaryConditionDescriptor() = default; +}; + +#endif // DIRICHLET_BOUNDARY_CONDITION_DESCRIPTOR_HPP diff --git a/src/scheme/FourierBoundaryConditionDescriptor.hpp b/src/scheme/FourierBoundaryConditionDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e7aeb830c3447bcf9783060210bc97e59bf2ebdf --- /dev/null +++ b/src/scheme/FourierBoundaryConditionDescriptor.hpp @@ -0,0 +1,75 @@ +#ifndef FOURIER_BOUNDARY_CONDITION_DESCRIPTOR_HPP +#define FOURIER_BOUNDARY_CONDITION_DESCRIPTOR_HPP + +#include <language/utils/FunctionSymbolId.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/IBoundaryDescriptor.hpp> + +#include <memory> + +class FourierBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +{ + private: + std::ostream& + _write(std::ostream& os) const final + { + os << "fourier(" << m_name << ',' << *m_boundary_descriptor << ")"; + return os; + } + + const std::string_view m_name; + + std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; + const FunctionSymbolId m_mass_symbol_id; + const FunctionSymbolId m_rhs_symbol_id; + + public: + std::string_view + name() const + { + return m_name; + } + + FunctionSymbolId + massSymbolId() const + { + return m_mass_symbol_id; + } + + FunctionSymbolId + rhsSymbolId() const + { + return m_rhs_symbol_id; + } + + const IBoundaryDescriptor& + boundaryDescriptor() const + { + return *m_boundary_descriptor; + } + + Type + type() const final + { + return Type::fourier; + } + + FourierBoundaryConditionDescriptor(const std::string_view name, + std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor, + const FunctionSymbolId& mass_symbol_id, + const FunctionSymbolId& rhs_symbol_id) + : m_name{name}, + m_boundary_descriptor(boundary_descriptor), + m_mass_symbol_id{mass_symbol_id}, + m_rhs_symbol_id{rhs_symbol_id} + { + ; + } + + FourierBoundaryConditionDescriptor(const FourierBoundaryConditionDescriptor&) = delete; + FourierBoundaryConditionDescriptor(FourierBoundaryConditionDescriptor&&) = delete; + + ~FourierBoundaryConditionDescriptor() = default; +}; + +#endif // FOURIER_BOUNDARY_CONDITION_DESCRIPTOR_HPP diff --git a/src/scheme/FreeBoundaryConditionDescriptor.hpp b/src/scheme/FreeBoundaryConditionDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b0eb2ceb218d77cae347a44219f13d278a25aee5 --- /dev/null +++ b/src/scheme/FreeBoundaryConditionDescriptor.hpp @@ -0,0 +1,46 @@ +#ifndef FREE_BOUNDARY_CONDITION_DESCRIPTOR_HPP +#define FREE_BOUNDARY_CONDITION_DESCRIPTOR_HPP + +#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/IBoundaryDescriptor.hpp> + +#include <memory> + +class FreeBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +{ + private: + std::ostream& + _write(std::ostream& os) const final + { + os << "free(" << *m_boundary_descriptor << ")"; + return os; + } + + std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; + + public: + const IBoundaryDescriptor& + boundaryDescriptor() const + { + return *m_boundary_descriptor; + } + + Type + type() const final + { + return Type::free; + } + + FreeBoundaryConditionDescriptor(std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor) + : m_boundary_descriptor(boundary_descriptor) + { + ; + } + + FreeBoundaryConditionDescriptor(const FreeBoundaryConditionDescriptor&) = delete; + FreeBoundaryConditionDescriptor(FreeBoundaryConditionDescriptor&&) = delete; + + ~FreeBoundaryConditionDescriptor() = default; +}; + +#endif // FREE_BOUNDARY_CONDITION_DESCRIPTOR_HPP diff --git a/src/scheme/IBoundaryConditionDescriptor.hpp b/src/scheme/IBoundaryConditionDescriptor.hpp index 0814c9e8580f6c36ad1152c3143d5877bff45dbc..30a25db66f1278e72eb2bea0ce7a017d8022da65 100644 --- a/src/scheme/IBoundaryConditionDescriptor.hpp +++ b/src/scheme/IBoundaryConditionDescriptor.hpp @@ -8,6 +8,10 @@ class IBoundaryConditionDescriptor public: enum class Type { + dirichlet, + fourier, + free, + neumann, symmetry }; diff --git a/src/scheme/NeumannBoundaryConditionDescriptor.hpp b/src/scheme/NeumannBoundaryConditionDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..edc1b1fb35b3f530c47adcd2f0073c9727707965 --- /dev/null +++ b/src/scheme/NeumannBoundaryConditionDescriptor.hpp @@ -0,0 +1,64 @@ +#ifndef NEUMANN_BOUNDARY_CONDITION_DESCRIPTOR_HPP +#define NEUMANN_BOUNDARY_CONDITION_DESCRIPTOR_HPP + +#include <language/utils/FunctionSymbolId.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/IBoundaryDescriptor.hpp> + +#include <memory> + +class NeumannBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +{ + private: + std::ostream& + _write(std::ostream& os) const final + { + os << "neumann(" << m_name << ',' << *m_boundary_descriptor << ")"; + return os; + } + + const std::string_view m_name; + + std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; + const FunctionSymbolId m_rhs_symbol_id; + + public: + std::string_view + name() const + { + return m_name; + } + + FunctionSymbolId + rhsSymbolId() const + { + return m_rhs_symbol_id; + } + + const IBoundaryDescriptor& + boundaryDescriptor() const + { + return *m_boundary_descriptor; + } + + Type + type() const final + { + return Type::neumann; + } + + NeumannBoundaryConditionDescriptor(const std::string_view name, + std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor, + const FunctionSymbolId& rhs_symbol_id) + : m_name{name}, m_boundary_descriptor(boundary_descriptor), m_rhs_symbol_id{rhs_symbol_id} + { + ; + } + + NeumannBoundaryConditionDescriptor(const NeumannBoundaryConditionDescriptor&) = delete; + NeumannBoundaryConditionDescriptor(NeumannBoundaryConditionDescriptor&&) = delete; + + ~NeumannBoundaryConditionDescriptor() = default; +}; + +#endif // NEUMANN_BOUNDARY_CONDITION_DESCRIPTOR_HPP diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2dfd3234486b352e5b9f27e13e10001846008bc1..7cd1ed89023e619af478625b58441002ecae0af2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -90,6 +90,7 @@ target_link_libraries (unit_tests PugsLanguage PugsLanguageAST PugsLanguageModules + PugsLanguageAlgorithms PugsLanguageUtils PugsMesh PugsUtils diff --git a/tests/test_BiCGStab.cpp b/tests/test_BiCGStab.cpp index b7cb2d3bd8afe280a7d8c416a662016851e0d820..99b94515ba7795903434db761d509b9052fcaf71 100644 --- a/tests/test_BiCGStab.cpp +++ b/tests/test_BiCGStab.cpp @@ -45,7 +45,7 @@ TEST_CASE("BiCGStab", "[algebra]") Vector<double> x{5}; x = 0; - BiCGStab{b, A, x, 10, 1e-12}; + BiCGStab<false>{b, A, x, 10, 1e-12}; Vector error = x - x_exact; REQUIRE(std::sqrt((error, error)) < 1E-10 * std::sqrt((x, x))); } diff --git a/tests/test_PCG.cpp b/tests/test_PCG.cpp index 4b2f2df9bed4bec0ea31502be3c5480e1eec6989..d4564761d8c564082e4668360e5a2e2a8ecce008 100644 --- a/tests/test_PCG.cpp +++ b/tests/test_PCG.cpp @@ -62,7 +62,7 @@ TEST_CASE("PCG", "[algebra]") Vector<double> x{5}; x = 0; - PCG{b, A, A, x, 10, 1e-12}; + PCG<false>{b, A, A, x, 10, 1e-12}; REQUIRE(std::sqrt((x, x)) == 0); } @@ -104,7 +104,7 @@ TEST_CASE("PCG", "[algebra]") Vector<double> x{5}; x = 0; - PCG{b, A, A, x, 1, 1e-12}; + PCG<false>{b, A, A, x, 1, 1e-12}; Vector error = x - x_exact; REQUIRE(std::sqrt((error, error)) > 1E-10 * std::sqrt((x, x))); } diff --git a/tests/test_SparseMatrixDescriptor.cpp b/tests/test_SparseMatrixDescriptor.cpp index 4e8b90134060c786cc7f97bc8fc8cd00bfba3257..cd66380b1d1beb6bcb9ba1a9c0d9c495947a3235 100644 --- a/tests/test_SparseMatrixDescriptor.cpp +++ b/tests/test_SparseMatrixDescriptor.cpp @@ -168,4 +168,30 @@ TEST_CASE("SparseMatrixDescriptor", "[algebra]") REQUIRE(value_array[6] == 1); REQUIRE(value_array[7] == -2); } + + SECTION("output") + { + SparseMatrixDescriptor<int, uint8_t> S{5}; + S(0, 2) = 3; + S(1, 2) = 11; + S(1, 1) = 1; + S(0, 2) += 2; + S(3, 3) = 5; + S(3, 1) = -3; + S(4, 1) = 1; + S(2, 2) = 4; + S(4, 4) = -2; + + std::ostringstream output; + output << '\n' << S; + + std::string expected_output = R"( +0 | 2:5 +1 | 1:1 2:11 +2 | 2:4 +3 | 1:-3 3:5 +4 | 1:1 4:-2 +)"; + REQUIRE(output.str() == expected_output); + } }