OGS
HeatTransportBHEProcess.cpp
Go to the documentation of this file.
1 
12 
13 #include <cassert>
14 
22 
23 namespace ProcessLib
24 {
25 namespace HeatTransportBHE
26 {
28  std::string name,
29  MeshLib::Mesh& mesh,
30  std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& jacobian_assembler,
31  std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters,
32  unsigned const integration_order,
33  std::vector<std::vector<std::reference_wrapper<ProcessVariable>>>&&
34  process_variables,
35  HeatTransportBHEProcessData&& process_data,
36  SecondaryVariableCollection&& secondary_variables)
37  : Process(std::move(name), mesh, std::move(jacobian_assembler), parameters,
38  integration_order, std::move(process_variables),
39  std::move(secondary_variables)),
40  _process_data(std::move(process_data)),
41  _bheMeshData(getBHEDataInMesh(mesh))
42 {
43  if (_bheMeshData.BHE_mat_IDs.size() !=
45  {
46  OGS_FATAL(
47  "The number of the given BHE properties ({:d}) are not consistent "
48  "with the number of BHE groups in the mesh ({:d}).",
50  _bheMeshData.BHE_mat_IDs.size());
51  }
52 
53  auto material_ids = MeshLib::materialIDs(mesh);
54  if (material_ids == nullptr)
55  {
56  OGS_FATAL("Not able to get material IDs! ");
57  }
58 
60 
61  // create a map from a material ID to a BHE ID
62  for (int i = 0; i < static_cast<int>(_bheMeshData.BHE_mat_IDs.size()); i++)
63  {
64  // fill in the map structure
66  i;
67  }
68 }
69 
71 {
72  // Create single component dof in every of the mesh's nodes.
74  std::make_unique<MeshLib::MeshSubset>(_mesh, _mesh.getNodes());
75 
76  //
77  // Soil temperature variable defined on the whole mesh.
78  //
80  std::make_unique<MeshLib::MeshSubset>(_mesh, _mesh.getNodes());
81  std::vector<MeshLib::MeshSubset> all_mesh_subsets{*_mesh_subset_soil_nodes};
82 
83  std::vector<std::vector<MeshLib::Element*> const*> vec_var_elements;
84  vec_var_elements.push_back(&(_mesh.getElements()));
85 
86  std::vector<int> vec_n_components{
87  1}; // one component for the soil temperature variable.
88 
89  //
90  // BHE nodes with BHE type dependent number of variables.
91  //
92  int const n_BHEs = _process_data._vec_BHE_property.size();
93  assert(n_BHEs == static_cast<int>(_bheMeshData.BHE_mat_IDs.size()));
94  assert(n_BHEs == static_cast<int>(_bheMeshData.BHE_nodes.size()));
95  assert(n_BHEs == static_cast<int>(_bheMeshData.BHE_elements.size()));
96 
97  // the BHE nodes need to be cherry-picked from the vector
98  for (int i = 0; i < n_BHEs; i++)
99  {
100  auto const number_of_unknowns =
101  visit([](auto const& bhe) { return bhe.number_of_unknowns; },
103  auto const& bhe_nodes = _bheMeshData.BHE_nodes[i];
104  auto const& bhe_elements = _bheMeshData.BHE_elements[i];
105 
106  // All the BHE nodes have additional variables.
107  _mesh_subset_BHE_nodes.push_back(
108  std::make_unique<MeshLib::MeshSubset const>(_mesh, bhe_nodes));
109 
110  std::generate_n(std::back_inserter(all_mesh_subsets),
111  // Here the number of components equals to the
112  // number of unknowns on the BHE
113  number_of_unknowns,
114  [&ms = _mesh_subset_BHE_nodes.back()]()
115  { return *ms; });
116 
117  vec_n_components.push_back(number_of_unknowns);
118  vec_var_elements.push_back(&bhe_elements);
119  }
120 
122  std::make_unique<NumLib::LocalToGlobalIndexMap>(
123  std::move(all_mesh_subsets),
124  vec_n_components,
125  vec_var_elements,
127 
128  // in case of debugging the dof table, activate the following line
129  // std::cout << *_local_to_global_index_map << "\n";
130 }
131 
133  NumLib::LocalToGlobalIndexMap const& dof_table,
134  MeshLib::Mesh const& mesh,
135  unsigned const integration_order)
136 {
137  // Quick access map to BHE's through element ids.
138  std::unordered_map<std::size_t, BHE::BHETypes*> element_to_bhe_map;
139  int const n_BHEs = _process_data._vec_BHE_property.size();
140  for (int i = 0; i < n_BHEs; i++)
141  {
142  auto const& bhe_elements = _bheMeshData.BHE_elements[i];
143  for (auto const& e : bhe_elements)
144  {
145  element_to_bhe_map[e->getID()] =
147  }
148  }
149 
150  assert(mesh.getDimension() == 3);
153  mesh.getElements(), dof_table, _local_assemblers, element_to_bhe_map,
154  mesh.isAxiallySymmetric(), integration_order, _process_data);
155 
156  // Create BHE boundary conditions for each of the BHEs
158 }
159 
161  const double t, double const dt, std::vector<GlobalVector*> const& x,
162  std::vector<GlobalVector*> const& xdot, int const process_id,
164 {
165  DBUG("Assemble HeatTransportBHE process.");
166 
167  ProcessLib::ProcessVariable const& pv = getProcessVariables(process_id)[0];
168 
169  std::vector<std::reference_wrapper<NumLib::LocalToGlobalIndexMap>>
170  dof_table = {std::ref(*_local_to_global_index_map)};
171  // Call global assembler for each local assembly item.
174  pv.getActiveElementIDs(), dof_table, t, dt, x, xdot, process_id, M, K,
175  b);
176 }
177 
179  const double t, double const dt, std::vector<GlobalVector*> const& x,
180  std::vector<GlobalVector*> const& xdot, const double dxdot_dx,
181  const double dx_dx, int const process_id, GlobalMatrix& M, GlobalMatrix& K,
182  GlobalVector& b, GlobalMatrix& Jac)
183 {
184  DBUG("AssembleWithJacobian HeatTransportBHE process.");
185 
186  std::vector<std::reference_wrapper<NumLib::LocalToGlobalIndexMap>>
187  dof_table = {std::ref(*_local_to_global_index_map)};
188  ProcessLib::ProcessVariable const& pv = getProcessVariables(process_id)[0];
189 
190  // Call global assembler for each local assembly item.
193  _local_assemblers, pv.getActiveElementIDs(), dof_table, t, dt, x, xdot,
194  dxdot_dx, dx_dx, process_id, M, K, b, Jac);
195 }
196 
198  double const t, double const dt, std::vector<GlobalVector*> const& x,
199  GlobalVector const& x_dot, int const process_id)
200 {
201  DBUG("Compute heat flux for HeatTransportBHE process.");
202 
203  std::vector<NumLib::LocalToGlobalIndexMap const*> dof_tables;
204  dof_tables.reserve(x.size());
205  std::generate_n(std::back_inserter(dof_tables), x.size(),
206  [&]() { return _local_to_global_index_map.get(); });
207 
208  ProcessLib::ProcessVariable const& pv = getProcessVariables(process_id)[0];
211  _local_assemblers, pv.getActiveElementIDs(), dof_tables, t, dt, x,
212  x_dot, process_id);
213 }
214 
215 #ifdef OGS_USE_PYTHON
217  GlobalVector const& x)
218 {
219  // if the process use python boundary condition
220  if (_process_data.py_bc_object == nullptr || !(_process_data._use_tespy))
222 
223  // Here the task is to get current time flowrate and flow temperature from
224  // TESPy and determine whether it converges.
225  auto const Tout_nodes_id =
227  const std::size_t n_bc_nodes = Tout_nodes_id.size();
228 
229  for (std::size_t i = 0; i < n_bc_nodes; i++)
230  {
231  // read the T_out and store them in dataframe
232  std::get<2>(_process_data.py_bc_object->dataframe_network)[i] =
233  x[Tout_nodes_id[i]];
234  }
235  // Transfer Tin and Tout to TESPy and return the results
236  auto const tespy_result = _process_data.py_bc_object->tespySolver(
237  std::get<0>(_process_data.py_bc_object->dataframe_network), // t
238  std::get<1>(_process_data.py_bc_object->dataframe_network), // T_in
239  std::get<2>(_process_data.py_bc_object->dataframe_network)); // T_out
241  {
242  DBUG("Method `tespySolver' not overridden in Python script.");
243  }
244 
245  // update the Tin and flow rate
246  for (std::size_t i = 0; i < n_bc_nodes; i++)
247  {
248  std::get<1>(_process_data.py_bc_object->dataframe_network)[i] =
249  std::get<2>(tespy_result)[i];
250  std::get<4>(_process_data.py_bc_object->dataframe_network)[i] =
251  std::get<3>(tespy_result)[i];
252  }
253  auto const tespy_has_converged = std::get<1>(tespy_result);
254  if (tespy_has_converged == true)
256 
258 }
259 
261  std::vector<GlobalVector*> const& x, const double t, const double dt,
262  int const process_id)
263 {
264  if (_process_data.py_bc_object == nullptr ||
266  {
267  return;
268  }
269 
270  auto& [time, Tin_value, Tout_value, Tout_nodes_ids, flowrate] =
272 
273  auto const& solution = *x[process_id];
274 
275  // Iterate through each BHE
276  const std::size_t n_bc_nodes = Tout_nodes_ids.size();
277  for (std::size_t i = 0; i < n_bc_nodes; i++)
278  {
279  // read the T_out and store them in dataframe
280  Tout_value[i] = solution[Tout_nodes_ids[i]];
281  }
282 
283  assert(time == t);
284 
285  // Transfer T_out to server_Communication and get back T_in and flowrate
286  auto const server_communication_result =
288  Tout_value, flowrate);
290  {
291  DBUG("Method `serverCommunication' not overridden in Python script.");
292  }
293 
294  auto const& [server_communication_Tin_value,
295  server_communication_flowrate] = server_communication_result;
296 
297  std::copy(begin(server_communication_Tin_value),
298  end(server_communication_Tin_value),
299  begin(Tin_value));
300  std::copy(begin(server_communication_flowrate),
301  end(server_communication_flowrate),
302  begin(flowrate));
303 }
304 #endif // OGS_USE_PYTHON
305 
307  std::vector<std::vector<MeshLib::Node*>> const& all_bhe_nodes)
308 {
309  const int process_id = 0;
310  auto& bcs = _boundary_conditions[process_id];
311 
312  int const n_BHEs = static_cast<int>(_process_data._vec_BHE_property.size());
313 
314  // for each BHE
315  for (int bhe_i = 0; bhe_i < n_BHEs; bhe_i++)
316  {
317  auto const& bhe_nodes = all_bhe_nodes[bhe_i];
318  // find the variable ID
319  // the soil temperature is 0-th variable
320  // the BHE temperature is therefore bhe_i + 1
321  const int variable_id = bhe_i + 1;
322 
323  std::vector<MeshLib::Node*> bhe_boundary_nodes;
324 
325  // cherry-pick the boundary nodes according to
326  // the number of connected line elements.
327  for (auto const& bhe_node : bhe_nodes)
328  {
329  // Count number of 1d elements connected with every BHE node.
330  auto const& connected_elements =
332  const std::size_t n_line_elements = std::count_if(
333  connected_elements.begin(), connected_elements.end(),
334  [](MeshLib::Element const* elem)
335  { return (elem->getDimension() == 1); });
336 
337  if (n_line_elements == 1)
338  {
339  bhe_boundary_nodes.push_back(bhe_node);
340  }
341  }
342 
343  if (bhe_boundary_nodes.size() != 2)
344  {
345  OGS_FATAL(
346  "Error!!! The BHE boundary nodes are not correctly found, "
347  "for every single BHE, there should be 2 boundary nodes.");
348  }
349 
350  // For 1U, 2U, CXC, CXA type BHE, the node order in the boundary nodes
351  // vector should be rearranged according to its z coordinate in
352  // descending order. In these BHE types, the z coordinate on the top and
353  // bottom node is different. The BHE top node with a higher z coordinate
354  // should be placed at the first, while the BHE bottom node with a lower
355  // z coordinate should be placed at the second. For other horizontal BHE
356  // types e.g. 1P-type BHE, the z coordinate on the top and bottom node
357  // is identical. Thus the node order in the boundary nodes vector can
358  // not be rearranged according to its z coordinate. For these BHE types,
359  // the boundary node order is according to the default node id order in
360  // the model mesh.
361  // for 1P-type BHE
362  if ((*bhe_boundary_nodes[0])[2] == (*bhe_boundary_nodes[1])[2])
363  {
364  INFO(
365  "For 1P-type BHE, the BHE inflow and outflow "
366  "nodes are identified according to their mesh node id in "
367  "ascending order");
368  }
369  // for 1U, 2U, CXC, CXA type BHE
370  else
371  {
372  // swap the boundary nodes if the z coordinate of the
373  // first node is lower than it on the second node
374  if ((*bhe_boundary_nodes[0])[2] < (*bhe_boundary_nodes[1])[2])
375  {
376  std::swap(bhe_boundary_nodes[0], bhe_boundary_nodes[1]);
377  }
378  }
379 
380  auto get_global_index =
381  [&](std::size_t const node_id, int const component)
382  {
383  return _local_to_global_index_map->getGlobalIndex(
385  variable_id, component);
386  };
387 
388  auto get_global_bhe_bc_indices =
389  [&](std::array<
390  std::pair<std::size_t /*node_id*/, int /*component*/>, 2>
391  nodes_and_components)
392  {
393  return std::make_pair(
394  get_global_index(nodes_and_components[0].first,
395  nodes_and_components[0].second),
396  get_global_index(nodes_and_components[1].first,
397  nodes_and_components[1].second));
398  };
399 
400  auto createBCs =
401  [&, bc_top_node_id = bhe_boundary_nodes[0]->getID(),
402  bc_bottom_node_id = bhe_boundary_nodes[1]->getID()](auto& bhe)
403  {
404  for (auto const& in_out_component_id :
405  bhe.inflow_outflow_bc_component_ids)
406  {
407  if (bhe.use_python_bcs ||
409  // call BHEPythonBoundarycondition
410  {
411 #ifdef OGS_USE_PYTHON
412  if (_process_data.py_bc_object) // the bc object exist
413  {
414  // apply the customized top, inflow BC.
415  bcs.addBoundaryCondition(
417  get_global_bhe_bc_indices(
418  bhe.getBHEInflowDirichletBCNodesAndComponents(
419  bc_top_node_id, bc_bottom_node_id,
420  in_out_component_id.first)),
421  bhe,
423  }
424  else
425  {
426  OGS_FATAL(
427  "The Python Boundary Condition was switched on, "
428  "but the data object does not exist! ");
429  }
430 #else
431  OGS_FATAL(
432  "The Python Boundary Condition was switched off! "
433  "Not able to create Boundary Condition for BHE! ");
434 #endif // OGS_USE_PYTHON
435  }
436  else
437  {
438  // Top, inflow, normal case
439  bcs.addBoundaryCondition(
441  get_global_bhe_bc_indices(
442  bhe.getBHEInflowDirichletBCNodesAndComponents(
443  bc_top_node_id, bc_bottom_node_id,
444  in_out_component_id.first)),
445  [&bhe](double const T, double const t) {
446  return bhe.updateFlowRateAndTemperature(T, t);
447  }));
448  }
449 
450  auto const bottom_nodes_and_components =
451  bhe.getBHEBottomDirichletBCNodesAndComponents(
452  bc_bottom_node_id,
453  in_out_component_id.first,
454  in_out_component_id.second);
455 
456  if (bottom_nodes_and_components)
457  {
458  // Bottom, outflow, all cases
459  bcs.addBoundaryCondition(
461  get_global_bhe_bc_indices(
462  {{{bc_bottom_node_id,
463  in_out_component_id.first},
464  {bc_bottom_node_id,
465  in_out_component_id.second}}})));
466  }
467  }
468  };
469  visit(createBCs, _process_data._vec_BHE_property[bhe_i]);
470  }
471 }
472 } // namespace HeatTransportBHE
473 } // namespace ProcessLib
#define OGS_FATAL(...)
Definition: Error.h:26
void INFO(char const *fmt, Args const &... args)
Definition: Logging.h:32
void DBUG(char const *fmt, Args const &... args)
Definition: Logging.h:27
Global vector based on Eigen vector.
Definition: EigenVector.h:26
bool isAxiallySymmetric() const
Definition: Mesh.h:126
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition: Mesh.h:95
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition: Mesh.h:71
std::size_t getID() const
Get id of the mesh.
Definition: Mesh.h:110
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition: Mesh.h:98
std::vector< Element const * > const & getElementsConnectedToNode(std::size_t node_id) const
Definition: Mesh.cpp:232
std::tuple< double, std::vector< double >, std::vector< double >, std::vector< int >, std::vector< double > > dataframe_network
virtual std::tuple< std::vector< double >, std::vector< double > > serverCommunication(double, double, std::vector< double > const &, std::vector< double > const &, std::vector< double > const &) const
virtual std::tuple< bool, bool, std::vector< double >, std::vector< double > > tespySolver(double, std::vector< double > const &, std::vector< double > const &) const
void computeSecondaryVariableConcrete(double const t, double const dt, std::vector< GlobalVector * > const &x, GlobalVector const &x_dot, int const process_id) override
void createBHEBoundaryConditionTopBottom(std::vector< std::vector< MeshLib::Node * >> const &all_bhe_nodes)
std::unique_ptr< MeshLib::MeshSubset const > _mesh_subset_soil_nodes
std::vector< std::unique_ptr< MeshLib::MeshSubset const > > _mesh_subset_BHE_nodes
void postTimestepConcreteProcess(std::vector< GlobalVector * > const &x, const double t, const double dt, int const process_id) override
std::vector< std::unique_ptr< HeatTransportBHELocalAssemblerInterface > > _local_assemblers
NumLib::IterationResult postIterationConcreteProcess(GlobalVector const &x) override
void assembleWithJacobianConcreteProcess(const double t, double const dt, std::vector< GlobalVector * > const &x, std::vector< GlobalVector * > const &xdot, const double dxdot_dx, const double dx_dx, int const process_id, GlobalMatrix &M, GlobalMatrix &K, GlobalVector &b, GlobalMatrix &Jac) override
void assembleConcreteProcess(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) override
void initializeConcreteProcess(NumLib::LocalToGlobalIndexMap const &dof_table, MeshLib::Mesh const &mesh, unsigned const integration_order) override
Process specific initialization called by initialize().
HeatTransportBHEProcess(std::string name, MeshLib::Mesh &mesh, std::unique_ptr< ProcessLib::AbstractJacobianAssembler > &&jacobian_assembler, std::vector< std::unique_ptr< ParameterLib::ParameterBase >> const &parameters, unsigned const integration_order, std::vector< std::vector< std::reference_wrapper< ProcessVariable >>> &&process_variables, HeatTransportBHEProcessData &&process_data, SecondaryVariableCollection &&secondary_variables)
virtual void computeSecondaryVariable(std::size_t const mesh_item_id, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_tables, double const t, double const dt, std::vector< GlobalVector * > const &x, GlobalVector const &x_dot, int const process_id)
std::vector< std::size_t > const & getActiveElementIDs() const
std::vector< BoundaryConditionCollection > _boundary_conditions
Definition: Process.h:365
std::unique_ptr< MeshLib::MeshSubset const > _mesh_subset_all_nodes
Definition: Process.h:327
MeshLib::Mesh & _mesh
Definition: Process.h:326
std::vector< std::reference_wrapper< ProcessVariable > > const & getProcessVariables(const int process_id) const
Definition: Process.h:145
VectorMatrixAssembler _global_assembler
Definition: Process.h:333
std::unique_ptr< NumLib::LocalToGlobalIndexMap > _local_to_global_index_map
Definition: Process.h:329
Handles configuration of several secondary variables from the project file.
void assembleWithJacobian(std::size_t const mesh_item_id, LocalAssemblerInterface &local_assembler, std::vector< std::reference_wrapper< NumLib::LocalToGlobalIndexMap >> const &dof_tables, const double t, double const dt, std::vector< GlobalVector * > const &x, std::vector< GlobalVector * > const &xdot, const double dxdot_dx, const double dx_dx, int const process_id, GlobalMatrix &M, GlobalMatrix &K, GlobalVector &b, GlobalMatrix &Jac)
void assemble(std::size_t const mesh_item_id, LocalAssemblerInterface &local_assembler, std::vector< std::reference_wrapper< NumLib::LocalToGlobalIndexMap >> const &dof_tables, double const t, double const dt, std::vector< GlobalVector * > const &x, std::vector< GlobalVector * > const &xdot, int const process_id, GlobalMatrix &M, GlobalMatrix &K, GlobalVector &b)
IterationResult
Status flags telling the NonlinearSolver if an iteration succeeded.
void copy(PETScVector const &x, PETScVector &y)
Definition: LinAlg.cpp:37
PropertyVector< int > const * materialIDs(Mesh const &mesh)
Definition: Mesh.cpp:258
@ BY_COMPONENT
Ordering data by component type.
std::unique_ptr< BHEBottomDirichletBoundaryCondition > createBHEBottomDirichletBoundaryCondition(std::pair< GlobalIndexType, GlobalIndexType > &&in_out_global_indices)
BHEMeshData getBHEDataInMesh(MeshLib::Mesh const &mesh)
Definition: MeshUtils.cpp:51
std::unique_ptr< BHEInflowDirichletBoundaryCondition< BHEUpdateCallback > > createBHEInflowDirichletBoundaryCondition(std::pair< GlobalIndexType, GlobalIndexType > &&in_out_global_indices, BHEUpdateCallback bhe_update_callback)
void createLocalAssemblers(std::vector< MeshLib::Element * > const &mesh_elements, NumLib::LocalToGlobalIndexMap const &dof_table, std::vector< std::unique_ptr< LocalAssemblerInterface >> &local_assemblers, ExtraCtorArgs &&... extra_ctor_args)
std::unique_ptr< BHEInflowPythonBoundaryCondition< BHEType > > createBHEInflowPythonBoundaryCondition(std::pair< GlobalIndexType, GlobalIndexType > &&in_out_global_indices, BHEType &bhe, BHEInflowPythonBoundaryConditionPythonSideInterface &py_bc_object)
static void executeSelectedMemberOnDereferenced(Method method, Container const &container, std::vector< std::size_t > const &active_container_ids, Args &&... args)
static void executeSelectedMemberDereferenced(Object &object, Method method, Container const &container, std::vector< std::size_t > const &active_container_ids, Args &&... args)
std::vector< std::vector< MeshLib::Node * > > BHE_nodes
Definition: MeshUtils.h:38
std::vector< std::vector< MeshLib::Element * > > BHE_elements
Definition: MeshUtils.h:37
BHEInflowPythonBoundaryConditionPythonSideInterface * py_bc_object
Python object computing BC values.