diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp index abb60970a238402f360412b380ea05092f360740..dc9502f90106ee888d7d5b5f0ae7ca687b2aab66 100644 --- a/src/language/modules/SchemeModule.cpp +++ b/src/language/modules/SchemeModule.cpp @@ -603,25 +603,39 @@ SchemeModule::SchemeModule() } )); - this - ->_addBuiltinFunction("nodalheat", - std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr< - const IDiscreteFunction>(const std::shared_ptr<const IDiscreteFunction>&, - const std::shared_ptr<const IDiscreteFunction>&, - const std::vector< - std::shared_ptr<const IBoundaryConditionDescriptor>>&, - const std::shared_ptr<const IDiscreteFunction>&, const double&)>>( - - [](const std::shared_ptr<const IDiscreteFunction>& kappa, - const std::shared_ptr<const IDiscreteFunction>& f, - const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& - bc_descriptor_list, - const std::shared_ptr<const IDiscreteFunction>& P, - const double& dt) -> const std::shared_ptr<const IDiscreteFunction> { - return ScalarNodalSchemeHandler{kappa, f, bc_descriptor_list, P, dt}.solution(); - } + this->_addBuiltinFunction("nodalheat", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr< + const IDiscreteFunction>(const std::shared_ptr<const IDiscreteFunction>&, + const std::shared_ptr<const IDiscreteFunction>&, + const std::shared_ptr<const IDiscreteFunction>&, + const std::vector< + std::shared_ptr<const IBoundaryConditionDescriptor>>&, + const std::vector< + std::shared_ptr<const IBoundaryConditionDescriptor>>&, + const std::shared_ptr<const IDiscreteFunction>&, const double&, + const double&)>>( + + [](const std::shared_ptr<const IDiscreteFunction>& kappa, + const std::shared_ptr<const IDiscreteFunction>& f, + const std::shared_ptr<const IDiscreteFunction>& f_prev, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_prev_descriptor_list, + const std::shared_ptr<const IDiscreteFunction>& P, const double& dt, + const double& cn_coeff) -> const std::shared_ptr<const IDiscreteFunction> { + return ScalarNodalSchemeHandler{kappa, + f, + f_prev, + bc_descriptor_list, + bc_prev_descriptor_list, + P, + dt, + cn_coeff} + .solution(); + } - )); + )); this->_addBuiltinFunction("unsteadyelasticity", std::make_shared<BuiltinFunctionEmbedder< diff --git a/src/scheme/ScalarNodalScheme.cpp b/src/scheme/ScalarNodalScheme.cpp index 7fd220f64f08b536255d45ec89fbb6bfa46fbbd0..06fe956c09ea9e03fddb41a9abf6e5c170e5f4e6 100644 --- a/src/scheme/ScalarNodalScheme.cpp +++ b/src/scheme/ScalarNodalScheme.cpp @@ -145,9 +145,12 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand ScalarNodalScheme(const std::shared_ptr<const MeshType>& mesh, const std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyMatrix<Dimension>>>& cell_k, const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& f, + const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& f_prev, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_prev_descriptor_list, const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& P, - const double& dt) + const double& dt, + const double& cn_coeff) { using BoundaryCondition = std::variant<DirichletBoundaryCondition, FourierBoundaryCondition, NeumannBoundaryCondition>; @@ -227,6 +230,79 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand } } + BoundaryConditionList boundary_prev_condition_list; + + for (const auto& bc_prev_descriptor : bc_prev_descriptor_list) { + bool is_valid_boundary_condition = true; + + switch (bc_prev_descriptor->type()) { + case IBoundaryConditionDescriptor::Type::dirichlet: { + const DirichletBoundaryConditionDescriptor& dirichlet_bc_prev_descriptor = + dynamic_cast<const DirichletBoundaryConditionDescriptor&>(*bc_prev_descriptor); + if constexpr (Dimension > 1) { + MeshFaceBoundary<Dimension> mesh_face_boundary = + getMeshFaceBoundary(*mesh, dirichlet_bc_prev_descriptor.boundaryDescriptor()); + MeshNodeBoundary<Dimension> mesh_node_boundary = + getMeshNodeBoundary(*mesh, dirichlet_bc_prev_descriptor.boundaryDescriptor()); + + const FunctionSymbolId g_id = dirichlet_bc_prev_descriptor.rhsSymbolId(); + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*mesh); + + Array<const double> value_list = + InterpolateItemValue<double(TinyVector<Dimension>)>::template interpolate<ItemType::face>(g_id, + mesh_data.xl(), + mesh_face_boundary + .faceList()); + boundary_prev_condition_list.push_back( + DirichletBoundaryCondition{mesh_face_boundary.faceList(), mesh_node_boundary.nodeList(), value_list}); + + } else { + throw NotImplementedError("Dirichlet BC in 1d"); + } + break; + } + case IBoundaryConditionDescriptor::Type::fourier: { + throw NotImplementedError("NIY"); + break; + } + case IBoundaryConditionDescriptor::Type::neumann: { + const NeumannBoundaryConditionDescriptor& neumann_bc_prev_descriptor = + dynamic_cast<const NeumannBoundaryConditionDescriptor&>(*bc_prev_descriptor); + + if constexpr (Dimension > 1) { + MeshFaceBoundary<Dimension> mesh_face_boundary = + getMeshFaceBoundary(*mesh, neumann_bc_prev_descriptor.boundaryDescriptor()); + MeshNodeBoundary<Dimension> mesh_node_boundary = + getMeshNodeBoundary(*mesh, neumann_bc_prev_descriptor.boundaryDescriptor()); + + const FunctionSymbolId g_id = neumann_bc_prev_descriptor.rhsSymbolId(); + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*mesh); + + Array<const double> value_list = + InterpolateItemValue<double(TinyVector<Dimension>)>::template interpolate<ItemType::face>(g_id, + mesh_data.xl(), + mesh_face_boundary + .faceList()); + + boundary_prev_condition_list.push_back( + NeumannBoundaryCondition{mesh_face_boundary.faceList(), mesh_node_boundary.nodeList(), value_list}); + + } else { + throw NotImplementedError("Neumann BC in 1d"); + } + break; + } + default: { + is_valid_boundary_condition = false; + } + } + if (not is_valid_boundary_condition) { + std::ostringstream error_msg; + error_msg << *bc_prev_descriptor << " is an invalid boundary condition for heat equation"; + throw NormalError(error_msg.str()); + } + } + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*mesh); const NodeValue<const TinyVector<Dimension>>& xr = mesh->xr(); @@ -408,11 +484,70 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand return compute_node_boundary_values; }(); + const NodeValue<const double> node_boundary_prev_values = [&] { + NodeValue<double> compute_node_boundary_values{mesh->connectivity()}; + NodeValue<double> sum_mes_l{mesh->connectivity()}; + compute_node_boundary_values.fill(0); + sum_mes_l.fill(0); + for (const auto& boundary_condition : boundary_prev_condition_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<T, NeumannBoundaryCondition>) { + 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_nodes = face_to_node_matrix[face_id]; + + for (size_t i_node = 0; i_node < face_nodes.size(); ++i_node) { + const NodeId node_id = face_nodes[i_node]; + if (not node_is_dirichlet[node_id]) { + compute_node_boundary_values[node_id] += value_list[i_face] * mes_l[face_id]; + sum_mes_l[node_id] += mes_l[face_id]; + } + } + } + + } else if constexpr (std::is_same_v<T, DirichletBoundaryCondition>) { + 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_nodes = face_to_node_matrix[face_id]; + + for (size_t i_node = 0; i_node < face_nodes.size(); ++i_node) { + const NodeId node_id = face_nodes[i_node]; + if (not node_is_neumann[node_id]) { + compute_node_boundary_values[node_id] += value_list[i_face] * mes_l[face_id]; + sum_mes_l[node_id] += mes_l[face_id]; + } else { + compute_node_boundary_values[node_id] = value_list[i_face]; + } + } + } + } + }, + boundary_condition); + } + for (NodeId node_id = 0; node_id < mesh->numberOfNodes(); ++node_id) { + if ((not node_is_dirichlet[node_id]) && (node_is_neumann[node_id])) { + compute_node_boundary_values[node_id] /= sum_mes_l[node_id]; + } else if ((not node_is_neumann[node_id]) && (node_is_dirichlet[node_id])) { + compute_node_boundary_values[node_id] /= sum_mes_l[node_id]; + } + } + return compute_node_boundary_values; + }(); + { CellValue<const TinyMatrix<Dimension>> cell_kappaj = cell_k->cellValues(); const NodeValue<const TinyMatrix<Dimension>> node_kappar = [&] { NodeValue<TinyMatrix<Dimension>> kappa{mesh->connectivity()}; + kappa.fill(zero); parallel_for( mesh->numberOfNodes(), PUGS_LAMBDA(NodeId node_id) { kappa[node_id] = zero; @@ -431,6 +566,7 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand const NodeValue<const TinyMatrix<Dimension>> node_betar = [&] { NodeValue<TinyMatrix<Dimension>> beta{mesh->connectivity()}; + beta.fill(zero); parallel_for( mesh->numberOfNodes(), PUGS_LAMBDA(NodeId node_id) { const auto& node_local_number_in_its_cell = node_local_numbers_in_their_cells.itemArray(node_id); @@ -511,6 +647,7 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand const NodeValue<const TinyVector<Dimension>> sum_Cjr = [&] { NodeValue<TinyVector<Dimension>> compute_sum_Cjr{mesh->connectivity()}; + compute_sum_Cjr.fill(zero); parallel_for( mesh->numberOfNodes(), PUGS_LAMBDA(NodeId node_id) { const auto& node_to_cell = node_to_cell_matrix[node_id]; @@ -554,6 +691,7 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand const NodeValue<const double> sum_theta = [&] { NodeValue<double> compute_sum_theta{mesh->connectivity()}; + compute_sum_theta.fill(0); parallel_for( mesh->numberOfNodes(), PUGS_LAMBDA(NodeId node_id) { if ((is_boundary_node[node_id]) && (not node_is_corner[node_id])) { @@ -573,6 +711,16 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand const Array<int> non_zeros{mesh->numberOfCells()}; non_zeros.fill(Dimension); // Modif pour optimiser CRSMatrixDescriptor<double> S(mesh->numberOfCells(), mesh->numberOfCells(), non_zeros); + for (NodeId node_id = 0; node_id < mesh->numberOfNodes(); ++node_id) { + const auto& node_to_cell = node_to_cell_matrix[node_id]; + for (size_t i_cell_j = 0; i_cell_j < node_to_cell.size(); ++i_cell_j) { + const CellId cell_id_j = node_to_cell[i_cell_j]; + for (size_t i_cell_k = 0; i_cell_k < node_to_cell.size(); ++i_cell_k) { + const CellId cell_id_k = node_to_cell[i_cell_k]; + S(cell_id_j, cell_id_k) = 0; + } + } + } for (NodeId node_id = 0; node_id < mesh->numberOfNodes(); ++node_id) { const auto& node_to_cell = node_to_cell_matrix[node_id]; @@ -726,6 +874,8 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { B[cell_id] = dt * b[cell_id] + Ph[cell_id]; }); + // std::cout << "g = " << node_boundary_values << "\n"; + LinearSolver solver; solver.solveLocalSystem(A, T, B); @@ -746,9 +896,12 @@ ScalarNodalSchemeHandler::solution() const ScalarNodalSchemeHandler::ScalarNodalSchemeHandler( const std::shared_ptr<const IDiscreteFunction>& cell_k, const std::shared_ptr<const IDiscreteFunction>& f, + const std::shared_ptr<const IDiscreteFunction>& f_prev, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_prev_descriptor_list, const std::shared_ptr<const IDiscreteFunction>& P, - const double& dt) + const double& dt, + const double& cn_coeff) { const std::shared_ptr i_mesh = getCommonMesh({cell_k, f}); if (not i_mesh) { @@ -772,8 +925,10 @@ ScalarNodalSchemeHandler::ScalarNodalSchemeHandler( m_scheme = std::make_unique<ScalarNodalScheme<2>>(mesh, std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(cell_k), std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(f), - bc_descriptor_list, - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(P), dt); + std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(f_prev), + bc_descriptor_list, bc_prev_descriptor_list, + std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(P), dt, + cn_coeff); break; } case 3: { diff --git a/src/scheme/ScalarNodalScheme.hpp b/src/scheme/ScalarNodalScheme.hpp index a43ff3b4ca7b46b45948faeae252bdff62caa450..930b15d2513a6edf8061bf9884cfc2eac1d69982 100644 --- a/src/scheme/ScalarNodalScheme.hpp +++ b/src/scheme/ScalarNodalScheme.hpp @@ -40,11 +40,15 @@ class ScalarNodalSchemeHandler std::shared_ptr<const IDiscreteFunction> solution() const; - ScalarNodalSchemeHandler(const std::shared_ptr<const IDiscreteFunction>& cell_k, - const std::shared_ptr<const IDiscreteFunction>& f, - const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, - const std::shared_ptr<const IDiscreteFunction>& P, - const double& dt); + ScalarNodalSchemeHandler( + const std::shared_ptr<const IDiscreteFunction>& cell_k, + const std::shared_ptr<const IDiscreteFunction>& f, + const std::shared_ptr<const IDiscreteFunction>& f_prec, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_prev_descriptor_list, + const std::shared_ptr<const IDiscreteFunction>& P, + const double& dt, + const double& cn_coeff); ~ScalarNodalSchemeHandler(); };