https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MortarContactUtils.h
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#pragma once
11
12#include "FEProblemBase.h"
13#include "ADReal.h"
14#include "RankTwoTensor.h"
15#include "MooseMesh.h"
16
17#include "libmesh/dof_object.h"
18
19#include "metaphysicl/parallel_dualnumber.h"
20#include "metaphysicl/parallel_semidynamicsparsenumberarray.h"
21
22#include "timpi/parallel_sync.h"
23#include "timpi/communicator.h"
24#include "libmesh/data_type.h"
25#include "libmesh/parallel_algebra.h"
26#include "timpi/parallel_sync.h"
27
28#include <utility>
29#include <array>
30#include <unordered_map>
31#include <vector>
32
33namespace TIMPI
34{
35
36template <>
38{
39public:
40 explicit StandardType(const ADRankTwoTensor * example = nullptr)
41 : DataType(StandardType<ADReal>(example ? &((*example)(0, 0)) : nullptr),
42 LIBMESH_DIM * LIBMESH_DIM)
43 {
44 }
45
46 inline ~StandardType() { this->free(); }
47
48 static const bool is_fixed_type = true;
49};
50
51} // namespace TIMPI
52
53namespace Moose
54{
55namespace Mortar
56{
57namespace Contact
58{
59
68template <typename T>
69inline void
70communicateVelocities(std::unordered_map<const DofObject *, T> & dof_map,
71 const MooseMesh & mesh,
72 const bool nodal,
73 const Parallel::Communicator & communicator,
74 const bool send_data_back)
75{
76 libmesh_parallel_only(communicator);
77 const auto our_proc_id = communicator.rank();
78
79 // We may have weighted velocity information that should go to other processes that own the dofs
80 using Datum = std::pair<dof_id_type, T>;
81 std::unordered_map<processor_id_type, std::vector<Datum>> push_data;
82
83 for (auto & pr : dof_map)
84 {
85 const auto * const dof_object = pr.first;
86 const auto proc_id = dof_object->processor_id();
87 if (proc_id == our_proc_id)
88 continue;
89
90 push_data[proc_id].push_back(std::make_pair(dof_object->id(), std::move(pr.second)));
91 }
92
93 const auto & lm_mesh = mesh.getMesh();
94 std::unordered_map<processor_id_type, std::vector<const DofObject *>>
95 pid_to_dof_object_for_sending_back;
96
97 auto action_functor =
98 [nodal, our_proc_id, &lm_mesh, &dof_map, &pid_to_dof_object_for_sending_back, send_data_back](
99 const processor_id_type pid, const std::vector<Datum> & sent_data)
100 {
101 mooseAssert(pid != our_proc_id, "We do not send messages to ourself here");
102 libmesh_ignore(our_proc_id);
103
104 for (auto & pr : sent_data)
105 {
106 const auto dof_id = pr.first;
107 const auto * const dof_object =
108 nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
109 : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
110 mooseAssert(dof_object, "This should be non-null");
111
112 if (send_data_back)
113 pid_to_dof_object_for_sending_back[pid].push_back(dof_object);
114
115 dof_map[dof_object][0] += pr.second[0];
116 dof_map[dof_object][1] += pr.second[1];
117 }
118 };
119
120 TIMPI::push_parallel_vector_data(communicator, push_data, action_functor);
121
122 // Now send data back if requested
123 if (!send_data_back)
124 return;
125
126 std::unordered_map<processor_id_type, std::vector<Datum>> push_back_data;
127
128 for (const auto & [pid, dof_objects] : pid_to_dof_object_for_sending_back)
129 {
130 auto & pid_send_data = push_back_data[pid];
131 pid_send_data.reserve(dof_objects.size());
132 for (const DofObject * const dof_object : dof_objects)
133 {
134 const auto & [tangent_one, tangent_two] = libmesh_map_find(dof_map, dof_object);
135 pid_send_data.push_back({dof_object->id(), {tangent_one, tangent_two}});
136 }
137 }
138
139 auto sent_back_action_functor =
140 [nodal, our_proc_id, &lm_mesh, &dof_map](const processor_id_type libmesh_dbg_var(pid),
141 const std::vector<Datum> & sent_data)
142 {
143 mooseAssert(pid != our_proc_id, "We do not send messages to ourself here");
144 libmesh_ignore(our_proc_id);
145
146 for (auto & [dof_id, tangents] : sent_data)
147 {
148 const auto * const dof_object =
149 nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
150 : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
151 mooseAssert(dof_object, "This should be non-null");
152 auto & [our_tangent_one, our_tangent_two] = dof_map[dof_object];
153 our_tangent_one = tangents[0];
154 our_tangent_two = tangents[1];
155 }
156 };
157
158 TIMPI::push_parallel_vector_data(communicator, push_back_data, sent_back_action_functor);
159}
160
169inline void
170communicateR2T(std::unordered_map<const DofObject *, ADRankTwoTensor> & dof_map_adr2t,
171 const MooseMesh & mesh,
172 const bool nodal,
173 const Parallel::Communicator & communicator,
174 const bool send_data_back)
175{
176 libmesh_parallel_only(communicator);
177 const auto our_proc_id = communicator.rank();
178
179 // We may have weighted velocity information that should go to other processes that own the dofs
180 using Datum = std::pair<dof_id_type, ADRankTwoTensor>;
181 std::unordered_map<processor_id_type, std::vector<Datum>> push_data;
182
183 for (auto & pr : dof_map_adr2t)
184 {
185 const auto * const dof_object = pr.first;
186 const auto proc_id = dof_object->processor_id();
187 if (proc_id == our_proc_id)
188 continue;
189
190 push_data[proc_id].push_back(std::make_pair(dof_object->id(), std::move(pr.second)));
191 }
192
193 const auto & lm_mesh = mesh.getMesh();
194 std::unordered_map<processor_id_type, std::vector<const DofObject *>>
195 pid_to_dof_object_for_sending_back;
196
197 auto action_functor =
198 [nodal,
199 our_proc_id,
200 &lm_mesh,
201 &dof_map_adr2t,
202 &pid_to_dof_object_for_sending_back,
203 send_data_back](const processor_id_type pid, const std::vector<Datum> & sent_data)
204 {
205 mooseAssert(pid != our_proc_id, "We do not send messages to ourself here");
206 libmesh_ignore(our_proc_id);
207
208 for (auto & pr : sent_data)
209 {
210 const auto dof_id = pr.first;
211 const auto * const dof_object =
212 nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
213 : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
214 mooseAssert(dof_object, "This should be non-null");
215
216 if (send_data_back)
217 pid_to_dof_object_for_sending_back[pid].push_back(dof_object);
218
219 for (const auto i : make_range(3))
220 for (const auto j : make_range(3))
221 dof_map_adr2t[dof_object](i, j) += pr.second(i, j);
222 }
223 };
224
225 TIMPI::push_parallel_vector_data(communicator, push_data, action_functor);
226
227 // Now send data back if requested
228 if (!send_data_back)
229 return;
230
231 std::unordered_map<processor_id_type, std::vector<Datum>> push_back_data;
232
233 for (const auto & [pid, dof_objects] : pid_to_dof_object_for_sending_back)
234 {
235 auto & pid_send_data = push_back_data[pid];
236 pid_send_data.reserve(dof_objects.size());
237 for (const DofObject * const dof_object : dof_objects)
238 {
239 const auto & r2t = libmesh_map_find(dof_map_adr2t, dof_object);
240 pid_send_data.push_back({dof_object->id(), r2t});
241 }
242 }
243
244 auto sent_back_action_functor =
245 [nodal, our_proc_id, &lm_mesh, &dof_map_adr2t](const processor_id_type libmesh_dbg_var(pid),
246 const std::vector<Datum> & sent_data)
247 {
248 mooseAssert(pid != our_proc_id, "We do not send messages to ourself here");
249 libmesh_ignore(our_proc_id);
250
251 for (auto & [dof_id, r2t_sent] : sent_data)
252 {
253 const auto * const dof_object =
254 nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
255 : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
256 mooseAssert(dof_object, "This should be non-null");
257 auto & r2t = dof_map_adr2t[dof_object];
258 r2t = r2t_sent;
259 }
260 };
261
262 TIMPI::push_parallel_vector_data(communicator, push_back_data, sent_back_action_functor);
263}
264
265template <typename T>
266void
267communicateRealObject(std::unordered_map<const DofObject *, T> & dof_to_adreal,
268 const MooseMesh & mesh,
269 const bool nodal,
270 const Parallel::Communicator & communicator,
271 const bool send_data_back)
272{
273 libmesh_parallel_only(communicator);
274 const auto our_proc_id = communicator.rank();
275
276 // We may have weighted gap information that should go to other processes that own the dofs
277 using Datum = std::tuple<dof_id_type, T>;
278 std::unordered_map<processor_id_type, std::vector<Datum>> push_data;
279
280 for (auto & pr : dof_to_adreal)
281 {
282 const auto * const dof_object = pr.first;
283 const auto proc_id = dof_object->processor_id();
284 if (proc_id == our_proc_id)
285 continue;
286
287 push_data[proc_id].push_back(std::make_tuple(dof_object->id(), std::move(pr.second)));
288 }
289
290 const auto & lm_mesh = mesh.getMesh();
291 std::unordered_map<processor_id_type, std::vector<const DofObject *>>
292 pid_to_dof_object_for_sending_back;
293
294 auto action_functor =
295 [nodal,
296 our_proc_id,
297 &lm_mesh,
298 &dof_to_adreal,
299 &pid_to_dof_object_for_sending_back,
300 send_data_back](const processor_id_type pid, const std::vector<Datum> & sent_data)
301 {
302 mooseAssert(pid != our_proc_id, "We do not send messages to ourself here");
303 libmesh_ignore(our_proc_id);
304
305 for (auto & [dof_id, weighted_gap] : sent_data)
306 {
307 const auto * const dof_object =
308 nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
309 : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
310 mooseAssert(dof_object, "This should be non-null");
311 if (send_data_back)
312 pid_to_dof_object_for_sending_back[pid].push_back(dof_object);
313 auto & our_adreal = dof_to_adreal[dof_object];
314 our_adreal += weighted_gap;
315 }
316 };
317
318 TIMPI::push_parallel_vector_data(communicator, push_data, action_functor);
319
320 // Now send data back if requested
321 if (!send_data_back)
322 return;
323
324 std::unordered_map<processor_id_type, std::vector<Datum>> push_back_data;
325
326 for (const auto & [pid, dof_objects] : pid_to_dof_object_for_sending_back)
327 {
328 auto & pid_send_data = push_back_data[pid];
329 pid_send_data.reserve(dof_objects.size());
330 for (const DofObject * const dof_object : dof_objects)
331 {
332 const auto & our_adreal = libmesh_map_find(dof_to_adreal, dof_object);
333 pid_send_data.push_back(std::make_tuple(dof_object->id(), our_adreal));
334 }
335 }
336
337 auto sent_back_action_functor =
338 [nodal, our_proc_id, &lm_mesh, &dof_to_adreal](const processor_id_type libmesh_dbg_var(pid),
339 const std::vector<Datum> & sent_data)
340 {
341 mooseAssert(pid != our_proc_id, "We do not send messages to ourself here");
342 libmesh_ignore(our_proc_id);
343
344 for (auto & [dof_id, adreal] : sent_data)
345 {
346 const auto * const dof_object =
347 nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
348 : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
349 mooseAssert(dof_object, "This should be non-null");
350 auto & our_adreal = dof_to_adreal[dof_object];
351 our_adreal = adreal;
352 }
353 };
354 TIMPI::push_parallel_vector_data(communicator, push_back_data, sent_back_action_functor);
355}
356
368void communicateGaps(
369 std::unordered_map<const DofObject *, std::pair<ADReal, Real>> & dof_to_weighted_gap,
370 const MooseMesh & mesh,
371 bool nodal,
372 bool normalize_c,
373 const Parallel::Communicator & communicator,
374 bool send_data_back);
375}
376}
377}
DualNumber< Real, DNDerivativeType, true > ADReal
static const bool is_fixed_type
StandardType(const ADRankTwoTensor *example=nullptr)
MeshBase & mesh
void communicateR2T(std::unordered_map< const DofObject *, ADRankTwoTensor > &dof_map_adr2t, const MooseMesh &mesh, const bool nodal, const Parallel::Communicator &communicator, const bool send_data_back)
This function is used to communicate velocities across processes.
void communicateRealObject(std::unordered_map< const DofObject *, T > &dof_to_adreal, const MooseMesh &mesh, const bool nodal, const Parallel::Communicator &communicator, const bool send_data_back)
void communicateVelocities(std::unordered_map< const DofObject *, T > &dof_map, const MooseMesh &mesh, const bool nodal, const Parallel::Communicator &communicator, const bool send_data_back)
This function is used to communicate velocities across processes.
void communicateGaps(std::unordered_map< const DofObject *, std::pair< ADReal, Real > > &dof_to_weighted_gap, const MooseMesh &mesh, bool nodal, bool normalize_c, const Parallel::Communicator &communicator, bool send_data_back)
This function is used to communicate gaps across processes.
void push_parallel_vector_data(const Communicator &comm, MapToVectors &&data, const ActionFunctor &act_on_data)