From 7db0a94e5d4ab9aa8c0b2e1bb08845b203c21164 Mon Sep 17 00:00:00 2001 From: HBShaoUFZ <haibing.shao@ufz.de> Date: Wed, 17 Jul 2024 16:21:13 +0200 Subject: [PATCH] add the Algebraic Boundary Condition feature Rename function to algebraicBcConcreteProcess Algebraic BC in process data fix type process data set to use process data in HeatTransportBHE change weighting_factor type to double use combined structure change constructor to use the structure --- .../HeatTransportBHEProcess.cpp | 191 ++++++++++++++++-- .../HeatTransportBHEProcess.h | 31 ++- .../HeatTransportBHEProcessData.h | 17 +- 3 files changed, 220 insertions(+), 19 deletions(-) diff --git a/ProcessLib/HeatTransportBHE/HeatTransportBHEProcess.cpp b/ProcessLib/HeatTransportBHE/HeatTransportBHEProcess.cpp index 5b2a54b1110..4e7add01661 100644 --- a/ProcessLib/HeatTransportBHE/HeatTransportBHEProcess.cpp +++ b/ProcessLib/HeatTransportBHE/HeatTransportBHEProcess.cpp @@ -172,6 +172,13 @@ void HeatTransportBHEProcess::assembleConcreteProcess( _global_assembler, &VectorMatrixAssembler::assemble, _local_assemblers, getActiveElementIDs(), dof_table, t, dt, x, x_prev, process_id, &M, &K, &b); + // Algebraic BC procedure. + if (_process_data._algebraic_BC_Setting._use_algebraic_bc) + { + algebraicBcConcreteProcess(t, dt, x, x_prev, process_id, M, K, b); + } + + //_global_output(t, process_id, M, K, b); } void HeatTransportBHEProcess::assembleWithJacobianConcreteProcess( @@ -340,16 +347,120 @@ void HeatTransportBHEProcess::postTimestepConcreteProcess( } } +void HeatTransportBHEProcess::algebraicBcConcreteProcess( + [[maybe_unused]] const double t, double const /*dt*/, + [[maybe_unused]] std::vector<GlobalVector*> const& x, + std::vector<GlobalVector*> const& /*xprev*/, int const /*process_id*/, + [[maybe_unused]] GlobalMatrix& M, [[maybe_unused]] GlobalMatrix& K, + [[maybe_unused]] GlobalVector& b) +{ +#ifndef USE_PETSC + auto M_normal = M.getRawMatrix(); + auto K_normal = K.getRawMatrix(); + auto n_original_rows = K_normal.rows(); + auto const n_BHE_bottom_pairs = _vec_bottom_BHE_node_indices.size(); + auto const n_BHE_top_pairs = _vec_top_BHE_node_indices.size(); + + // apply weighting factor based on the max value from column wise inner + // product and scale it with user defined value + const double w_val = + _process_data._algebraic_BC_Setting._weighting_factor * + (Eigen::RowVectorXd::Ones(K_normal.rows()) * K_normal.cwiseAbs()) + .maxCoeff(); + + M_normal.conservativeResize( + M_normal.rows() + n_BHE_bottom_pairs + n_BHE_top_pairs, + M_normal.cols()); + K_normal.conservativeResize( + K_normal.rows() + n_BHE_bottom_pairs + n_BHE_top_pairs, + K_normal.cols()); + + for (std::size_t i = 0; i < n_BHE_bottom_pairs; i++) + { + Eigen::SparseVector<double> M_Plus(M_normal.cols()); + M_Plus.setZero(); + M_normal.row(n_original_rows + i) = M_Plus; + + Eigen::SparseVector<double> K_Plus(K_normal.cols()); + K_Plus.setZero(); + + auto const [bhe_idx, first_BHE_bottom_index, second_BHE_bottom_index] = + _vec_bottom_BHE_node_indices[i]; + + K_Plus.insert(first_BHE_bottom_index) = w_val; + K_Plus.insert(second_BHE_bottom_index) = -w_val; + + K_normal.row(n_original_rows + i) = K_Plus; + } + + auto b_normal = b.getRawVector(); + Eigen::SparseVector<double> b_Plus(b_normal.rows() + n_BHE_bottom_pairs + + n_BHE_top_pairs); + b_Plus.setZero(); + + // Copy values from the original column vector to the modified one + for (int i = 0; i < b_normal.innerSize(); ++i) + { + b_Plus.insert(i) = b_normal.coeff(i); + } + + for (std::size_t i = 0; i < n_BHE_top_pairs; i++) + { + Eigen::SparseVector<double> M_Plus(M_normal.cols()); + M_Plus.setZero(); + M_normal.row(n_original_rows + n_BHE_bottom_pairs + i) = M_Plus; + + Eigen::SparseVector<double> K_Plus(K_normal.cols()); + K_Plus.setZero(); + + auto const [bhe_idx, first_BHE_top_index, second_BHE_top_index] = + _vec_top_BHE_node_indices[i]; + + auto first_BHE_top_index_pair = first_BHE_top_index; + auto second_BHE_top_index_pair = second_BHE_top_index; + + K_Plus.insert(first_BHE_top_index_pair) = + w_val; // for power BC, the inflow node must be positive + K_Plus.insert(second_BHE_top_index_pair) = + -w_val; // for power BC, the outflow node must be negative + + K_normal.row(n_original_rows + n_BHE_bottom_pairs + i) = K_Plus; + + // get the delta_T value here + double const T_out = (*x[0])[second_BHE_top_index_pair]; + + auto calculate_delta_T = [&](auto& bhe) + { + auto const T_in = bhe.updateFlowRateAndTemperature(T_out, t); + return T_in - T_out; + }; + auto delta_T = std::visit(calculate_delta_T, + _process_data._vec_BHE_property[bhe_idx]); + + b_Plus.insert(n_original_rows + n_BHE_bottom_pairs + i) = + delta_T * w_val; + } + + M.getRawMatrix() = M_normal; + K.getRawMatrix() = K_normal; + b.getRawVector() = b_Plus; +#else + OGS_FATAL( + "The Algebraic Boundary Condition is not implemented for use with " + "PETsc Library! Simulation will be terminated."); +#endif +} + void HeatTransportBHEProcess::createBHEBoundaryConditionTopBottom( std::vector<std::vector<MeshLib::Node*>> const& all_bhe_nodes) { const int process_id = 0; auto& bcs = _boundary_conditions[process_id]; - int const n_BHEs = static_cast<int>(_process_data._vec_BHE_property.size()); + std::size_t const n_BHEs = _process_data._vec_BHE_property.size(); // for each BHE - for (int bhe_i = 0; bhe_i < n_BHEs; bhe_i++) + for (std::size_t bhe_i = 0; bhe_i < n_BHEs; bhe_i++) { auto const& bhe_nodes = all_bhe_nodes[bhe_i]; // find the variable ID @@ -434,6 +545,20 @@ void HeatTransportBHEProcess::createBHEBoundaryConditionTopBottom( nodes_and_components[1].second)); }; + auto get_global_bhe_bc_indices_with_bhe_idx = + [&](std::size_t bhe_idx, + std::array< + std::pair<std::size_t /*node_id*/, int /*component*/>, 2> + nodes_and_components) + { + return std::make_tuple( + bhe_idx, + get_global_index(nodes_and_components[0].first, + nodes_and_components[0].second), + get_global_index(nodes_and_components[1].first, + nodes_and_components[1].second)); + }; + auto createBCs = [&, bc_top_node_id = bhe_boundary_nodes[0]->getID(), bc_bottom_node_id = bhe_boundary_nodes[1]->getID()](auto& bhe) @@ -442,10 +567,11 @@ void HeatTransportBHEProcess::createBHEBoundaryConditionTopBottom( bhe.inflow_outflow_bc_component_ids) { if (bhe.use_python_bcs || - _process_data._use_server_communication) + this->_process_data._use_server_communication) // call BHEPythonBoundarycondition { - if (_process_data.py_bc_object) // the bc object exist + if (this->_process_data + .py_bc_object) // the bc object exist { // apply the customized top, inflow BC. bcs.addBoundaryCondition( @@ -466,16 +592,33 @@ void HeatTransportBHEProcess::createBHEBoundaryConditionTopBottom( } else { - // Top, inflow, normal case - bcs.addBoundaryCondition( - createBHEInflowDirichletBoundaryCondition( - get_global_bhe_bc_indices( - bhe.getBHEInflowDirichletBCNodesAndComponents( - bc_top_node_id, bc_bottom_node_id, - in_out_component_id.first)), - [&bhe](double const T, double const t) { - return bhe.updateFlowRateAndTemperature(T, t); - })); + if (this->_process_data._algebraic_BC_Setting + ._use_algebraic_bc && + bhe.isPowerBC()) + { + // for algebraic_bc method, record the pair of indices + // in a separate vector + _vec_top_BHE_node_indices.push_back( + get_global_bhe_bc_indices_with_bhe_idx( + bhe_i, + {{{bc_top_node_id, in_out_component_id.first}, + {bc_top_node_id, + in_out_component_id.second}}})); + } + else + { + // Top, inflow, normal case + bcs.addBoundaryCondition( + createBHEInflowDirichletBoundaryCondition( + get_global_bhe_bc_indices( + bhe.getBHEInflowDirichletBCNodesAndComponents( + bc_top_node_id, bc_bottom_node_id, + in_out_component_id.first)), + [&bhe](double const T, double const t) { + return bhe.updateFlowRateAndTemperature(T, + t); + })); + } } auto const bottom_nodes_and_components = @@ -484,9 +627,12 @@ void HeatTransportBHEProcess::createBHEBoundaryConditionTopBottom( in_out_component_id.first, in_out_component_id.second); - if (bottom_nodes_and_components) + if (bottom_nodes_and_components && + !this->_process_data._algebraic_BC_Setting + ._use_algebraic_bc) { - // Bottom, outflow, all cases + // Bottom, outflow, all cases | not needed for algebraic_bc + // method bcs.addBoundaryCondition( createBHEBottomDirichletBoundaryCondition( get_global_bhe_bc_indices( @@ -495,6 +641,19 @@ void HeatTransportBHEProcess::createBHEBoundaryConditionTopBottom( {bc_bottom_node_id, in_out_component_id.second}}}))); } + else if (bottom_nodes_and_components && + this->_process_data._algebraic_BC_Setting + ._use_algebraic_bc) + { + // for algebraic_bc method, record the pair of indices in a + // separate vector + _vec_bottom_BHE_node_indices.push_back( + get_global_bhe_bc_indices_with_bhe_idx( + bhe_i, + {{{bc_bottom_node_id, in_out_component_id.first}, + {bc_bottom_node_id, + in_out_component_id.second}}})); + } } }; visit(createBCs, _process_data._vec_BHE_property[bhe_i]); diff --git a/ProcessLib/HeatTransportBHE/HeatTransportBHEProcess.h b/ProcessLib/HeatTransportBHE/HeatTransportBHEProcess.h index e59d3af65fc..a50d8f66e2b 100644 --- a/ProcessLib/HeatTransportBHE/HeatTransportBHEProcess.h +++ b/ProcessLib/HeatTransportBHE/HeatTransportBHEProcess.h @@ -39,7 +39,18 @@ public: //! \name ODESystem interface //! @{ - bool isLinear() const override { return false; } + bool isLinear() const override + { + return _process_data._algebraic_BC_Setting._is_linear; + } + + bool requiresNormalization() const override + { + // In the current setup, when using algebraic bc, + // then normalization is always required + return _process_data._algebraic_BC_Setting._use_algebraic_bc; + } + //! @} void computeSecondaryVariableConcrete(double const t, double const dt, std::vector<GlobalVector*> const& x, @@ -76,6 +87,12 @@ private: const double t, const double dt, int const process_id) override; + void algebraicBcConcreteProcess(const double t, double const dt, + std::vector<GlobalVector*> const& x, + std::vector<GlobalVector*> const& xdot, + int const process_id, GlobalMatrix& M, + GlobalMatrix& K, GlobalVector& b); + NumLib::IterationResult postIterationConcreteProcess( GlobalVector const& x) override; @@ -89,6 +106,18 @@ private: std::vector<std::unique_ptr<MeshLib::MeshSubset const>> _mesh_subset_BHE_soil_nodes; + // a vector of tuple structure containing the indices of BHE top nodes, + // used only for algebraic boundary conditions + // first object is the index of BHE + // second and third object is the global indices of a pair of unknowns, + // pointing to the inflow and outflow temperature + std::vector<std::tuple<std::size_t, GlobalIndexType, GlobalIndexType>> + _vec_top_BHE_node_indices; + // a vector of tuple structure containing the indices of BHE bottom nodes, + // used only for algebraic boundary conditions + // same structure as the top node vector + std::vector<std::tuple<std::size_t, GlobalIndexType, GlobalIndexType>> + _vec_bottom_BHE_node_indices; std::unique_ptr<MeshLib::MeshSubset const> _mesh_subset_soil_nodes; diff --git a/ProcessLib/HeatTransportBHE/HeatTransportBHEProcessData.h b/ProcessLib/HeatTransportBHE/HeatTransportBHEProcessData.h index 134b42c5a54..5aa319a139c 100644 --- a/ProcessLib/HeatTransportBHE/HeatTransportBHEProcessData.h +++ b/ProcessLib/HeatTransportBHE/HeatTransportBHEProcessData.h @@ -23,6 +23,15 @@ class Element; namespace ProcessLib::HeatTransportBHE { +struct AlgebraicBCSetting +{ + const bool _use_algebraic_bc; + + const double _weighting_factor; + + const bool _is_linear; +}; + struct HeatTransportBHEProcessData final { HeatTransportBHEProcessData( @@ -31,12 +40,14 @@ struct HeatTransportBHEProcessData final BHEInflowPythonBoundaryConditionPythonSideInterface* py_bc_object_ = nullptr, const bool use_tespy = false, - const bool use_server_communication = false) + const bool use_server_communication = false, + AlgebraicBCSetting algebraicBCSetting = {false, 100.0, false}) : media_map(media_map_), _vec_BHE_property(std::move(vec_BHEs_)), py_bc_object(py_bc_object_), _use_tespy(use_tespy), - _use_server_communication(use_server_communication) + _use_server_communication(use_server_communication), + _algebraic_BC_Setting(algebraicBCSetting) { } MaterialPropertyLib::MaterialSpatialDistributionMap media_map; @@ -52,5 +63,7 @@ struct HeatTransportBHEProcessData final const bool _use_tespy; const bool _use_server_communication; + + AlgebraicBCSetting const _algebraic_BC_Setting; }; } // namespace ProcessLib::HeatTransportBHE -- GitLab