Line data Source code
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 "MooseConfig.h"
13 :
14 : #include "FEProblemBase.h"
15 : #include "ADReal.h"
16 : #include "RankTwoTensor.h"
17 : #include "MooseMesh.h"
18 :
19 : #include "libmesh/dof_object.h"
20 :
21 : #include "metaphysicl/parallel_dualnumber.h"
22 : #include "metaphysicl/parallel_semidynamicsparsenumberarray.h"
23 :
24 : #include "timpi/parallel_sync.h"
25 : #include "timpi/communicator.h"
26 : #include "libmesh/data_type.h"
27 : #include "libmesh/parallel_algebra.h"
28 : #include "timpi/parallel_sync.h"
29 :
30 : #include <utility>
31 : #include <array>
32 : #include <unordered_map>
33 : #include <vector>
34 :
35 : namespace TIMPI
36 : {
37 :
38 : template <>
39 : class StandardType<ADRankTwoTensor> : public DataType
40 : {
41 : public:
42 72 : explicit StandardType(const ADRankTwoTensor * example = nullptr)
43 72 : : DataType(StandardType<ADReal>(example ? &((*example)(0, 0)) : nullptr),
44 144 : LIBMESH_DIM * LIBMESH_DIM)
45 : {
46 72 : }
47 :
48 72 : inline ~StandardType() { this->free(); }
49 :
50 : static const bool is_fixed_type = true;
51 : };
52 :
53 : } // namespace TIMPI
54 :
55 : namespace Moose
56 : {
57 : namespace Mortar
58 : {
59 : namespace Contact
60 : {
61 :
62 : /**
63 : * This function is used to communicate velocities across processes
64 : * @param dof_to_weighted_gap Map from degree of freedom to weighted (weak) gap
65 : * @param mesh Mesh used to locate nodes or elements
66 : * @param nodal Whether the element has Lagrange interpolation
67 : * @param communicator Process communicator
68 : * @param send_data_back Whether to send back data to a distributed constraint
69 : */
70 : template <typename T>
71 : inline void
72 213736 : communicateVelocities(std::unordered_map<const DofObject *, T> & dof_map,
73 : const MooseMesh & mesh,
74 : const bool nodal,
75 : const Parallel::Communicator & communicator,
76 : const bool send_data_back)
77 : {
78 : libmesh_parallel_only(communicator);
79 : const auto our_proc_id = communicator.rank();
80 :
81 : // We may have weighted velocity information that should go to other processes that own the dofs
82 : using Datum = std::pair<dof_id_type, T>;
83 : std::unordered_map<processor_id_type, std::vector<Datum>> push_data;
84 :
85 1189638 : for (auto & pr : dof_map)
86 : {
87 975902 : const auto * const dof_object = pr.first;
88 975902 : const auto proc_id = dof_object->processor_id();
89 975902 : if (proc_id == our_proc_id)
90 950946 : continue;
91 :
92 49912 : push_data[proc_id].push_back(std::make_pair(dof_object->id(), std::move(pr.second)));
93 : }
94 :
95 213736 : const auto & lm_mesh = mesh.getMesh();
96 : std::unordered_map<processor_id_type, std::vector<const DofObject *>>
97 : pid_to_dof_object_for_sending_back;
98 :
99 213736 : auto action_functor =
100 72872 : [nodal, our_proc_id, &lm_mesh, &dof_map, &pid_to_dof_object_for_sending_back, send_data_back](
101 : const processor_id_type pid, const std::vector<Datum> & sent_data)
102 : {
103 : mooseAssert(pid != our_proc_id, "We do not send messages to ourself here");
104 : libmesh_ignore(our_proc_id);
105 :
106 41450 : for (auto & pr : sent_data)
107 : {
108 24956 : const auto dof_id = pr.first;
109 24956 : const auto * const dof_object =
110 24956 : nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
111 0 : : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
112 : mooseAssert(dof_object, "This should be non-null");
113 :
114 24956 : if (send_data_back)
115 6466 : pid_to_dof_object_for_sending_back[pid].push_back(dof_object);
116 :
117 24956 : dof_map[dof_object][0] += pr.second[0];
118 24956 : dof_map[dof_object][1] += pr.second[1];
119 : }
120 : };
121 :
122 213736 : TIMPI::push_parallel_vector_data(communicator, push_data, action_functor);
123 :
124 : // Now send data back if requested
125 213736 : if (!send_data_back)
126 : return;
127 :
128 : std::unordered_map<processor_id_type, std::vector<Datum>> push_back_data;
129 :
130 37376 : for (const auto & [pid, dof_objects] : pid_to_dof_object_for_sending_back)
131 : {
132 : auto & pid_send_data = push_back_data[pid];
133 4550 : pid_send_data.reserve(dof_objects.size());
134 11016 : for (const DofObject * const dof_object : dof_objects)
135 : {
136 6466 : const auto & [tangent_one, tangent_two] = libmesh_map_find(dof_map, dof_object);
137 6466 : pid_send_data.push_back({dof_object->id(), {tangent_one, tangent_two}});
138 : }
139 : }
140 :
141 32826 : auto sent_back_action_functor =
142 4550 : [nodal, our_proc_id, &lm_mesh, &dof_map](const processor_id_type libmesh_dbg_var(pid),
143 : const std::vector<Datum> & sent_data)
144 : {
145 : mooseAssert(pid != our_proc_id, "We do not send messages to ourself here");
146 : libmesh_ignore(our_proc_id);
147 :
148 11016 : for (auto & [dof_id, tangents] : sent_data)
149 : {
150 6466 : const auto * const dof_object =
151 6466 : nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
152 0 : : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
153 : mooseAssert(dof_object, "This should be non-null");
154 : auto & [our_tangent_one, our_tangent_two] = dof_map[dof_object];
155 6466 : our_tangent_one = tangents[0];
156 6466 : our_tangent_two = tangents[1];
157 : }
158 : };
159 :
160 32826 : TIMPI::push_parallel_vector_data(communicator, push_back_data, sent_back_action_functor);
161 6466 : }
162 :
163 : /**
164 : * This function is used to communicate velocities across processes
165 : * @param dof_map_adr2t Map from degree of freedom to weighted tank two tensor
166 : * @param mesh Mesh used to locate nodes or elements
167 : * @param nodal Whether the element has Lagrange interpolation
168 : * @param communicator Process communicator
169 : * @param send_data_back Whether to send back data to a distributed constraint
170 : */
171 : inline void
172 14182 : communicateR2T(std::unordered_map<const DofObject *, ADRankTwoTensor> & dof_map_adr2t,
173 : const MooseMesh & mesh,
174 : const bool nodal,
175 : const Parallel::Communicator & communicator,
176 : const bool send_data_back)
177 : {
178 : libmesh_parallel_only(communicator);
179 : const auto our_proc_id = communicator.rank();
180 :
181 : // We may have weighted velocity information that should go to other processes that own the dofs
182 : using Datum = std::pair<dof_id_type, ADRankTwoTensor>;
183 : std::unordered_map<processor_id_type, std::vector<Datum>> push_data;
184 :
185 43512 : for (auto & pr : dof_map_adr2t)
186 : {
187 29330 : const auto * const dof_object = pr.first;
188 29330 : const auto proc_id = dof_object->processor_id();
189 29330 : if (proc_id == our_proc_id)
190 28312 : continue;
191 :
192 1018 : push_data[proc_id].push_back(std::make_pair(dof_object->id(), std::move(pr.second)));
193 : }
194 :
195 14182 : const auto & lm_mesh = mesh.getMesh();
196 : std::unordered_map<processor_id_type, std::vector<const DofObject *>>
197 : pid_to_dof_object_for_sending_back;
198 :
199 : auto action_functor =
200 1018 : [nodal,
201 : our_proc_id,
202 : &lm_mesh,
203 : &dof_map_adr2t,
204 : &pid_to_dof_object_for_sending_back,
205 10180 : send_data_back](const processor_id_type pid, const std::vector<Datum> & sent_data)
206 : {
207 : mooseAssert(pid != our_proc_id, "We do not send messages to ourself here");
208 : libmesh_ignore(our_proc_id);
209 :
210 2036 : for (auto & pr : sent_data)
211 : {
212 1018 : const auto dof_id = pr.first;
213 : const auto * const dof_object =
214 1018 : nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
215 0 : : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
216 : mooseAssert(dof_object, "This should be non-null");
217 :
218 1018 : if (send_data_back)
219 1018 : pid_to_dof_object_for_sending_back[pid].push_back(dof_object);
220 :
221 4072 : for (const auto i : make_range(3))
222 12216 : for (const auto j : make_range(3))
223 9162 : dof_map_adr2t[dof_object](i, j) += pr.second(i, j);
224 : }
225 1018 : };
226 :
227 14182 : TIMPI::push_parallel_vector_data(communicator, push_data, action_functor);
228 :
229 : // Now send data back if requested
230 14182 : if (!send_data_back)
231 : return;
232 :
233 : std::unordered_map<processor_id_type, std::vector<Datum>> push_back_data;
234 :
235 15200 : for (const auto & [pid, dof_objects] : pid_to_dof_object_for_sending_back)
236 : {
237 : auto & pid_send_data = push_back_data[pid];
238 1018 : pid_send_data.reserve(dof_objects.size());
239 2036 : for (const DofObject * const dof_object : dof_objects)
240 : {
241 1018 : const auto & r2t = libmesh_map_find(dof_map_adr2t, dof_object);
242 1018 : pid_send_data.push_back({dof_object->id(), r2t});
243 : }
244 : }
245 :
246 : auto sent_back_action_functor =
247 1018 : [nodal, our_proc_id, &lm_mesh, &dof_map_adr2t](const processor_id_type libmesh_dbg_var(pid),
248 3054 : const std::vector<Datum> & sent_data)
249 : {
250 : mooseAssert(pid != our_proc_id, "We do not send messages to ourself here");
251 : libmesh_ignore(our_proc_id);
252 :
253 2036 : for (auto & [dof_id, r2t_sent] : sent_data)
254 : {
255 : const auto * const dof_object =
256 1018 : nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
257 1018 : : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
258 : mooseAssert(dof_object, "This should be non-null");
259 : auto & r2t = dof_map_adr2t[dof_object];
260 : r2t = r2t_sent;
261 : }
262 15200 : };
263 :
264 14182 : TIMPI::push_parallel_vector_data(communicator, push_back_data, sent_back_action_functor);
265 : }
266 :
267 : template <typename T>
268 : void
269 35455 : communicateRealObject(std::unordered_map<const DofObject *, T> & dof_to_adreal,
270 : const MooseMesh & mesh,
271 : const bool nodal,
272 : const Parallel::Communicator & communicator,
273 : const bool send_data_back)
274 : {
275 : libmesh_parallel_only(communicator);
276 : const auto our_proc_id = communicator.rank();
277 :
278 : // We may have weighted gap information that should go to other processes that own the dofs
279 : using Datum = std::tuple<dof_id_type, T>;
280 : std::unordered_map<processor_id_type, std::vector<Datum>> push_data;
281 :
282 108780 : for (auto & pr : dof_to_adreal)
283 : {
284 73325 : const auto * const dof_object = pr.first;
285 73325 : const auto proc_id = dof_object->processor_id();
286 73325 : if (proc_id == our_proc_id)
287 70780 : continue;
288 :
289 4581 : push_data[proc_id].push_back(std::make_tuple(dof_object->id(), std::move(pr.second)));
290 : }
291 :
292 35455 : const auto & lm_mesh = mesh.getMesh();
293 : std::unordered_map<processor_id_type, std::vector<const DofObject *>>
294 : pid_to_dof_object_for_sending_back;
295 :
296 35455 : auto action_functor =
297 7635 : [nodal,
298 : our_proc_id,
299 : &lm_mesh,
300 : &dof_to_adreal,
301 : &pid_to_dof_object_for_sending_back,
302 : send_data_back](const processor_id_type pid, const std::vector<Datum> & sent_data)
303 : {
304 : mooseAssert(pid != our_proc_id, "We do not send messages to ourself here");
305 : libmesh_ignore(our_proc_id);
306 :
307 5090 : for (auto & [dof_id, weighted_gap] : sent_data)
308 : {
309 2545 : const auto * const dof_object =
310 2545 : nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
311 0 : : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
312 : mooseAssert(dof_object, "This should be non-null");
313 2545 : if (send_data_back)
314 2545 : pid_to_dof_object_for_sending_back[pid].push_back(dof_object);
315 : auto & our_adreal = dof_to_adreal[dof_object];
316 2545 : our_adreal += weighted_gap;
317 : }
318 : };
319 :
320 35455 : TIMPI::push_parallel_vector_data(communicator, push_data, action_functor);
321 :
322 : // Now send data back if requested
323 35455 : if (!send_data_back)
324 : return;
325 :
326 : std::unordered_map<processor_id_type, std::vector<Datum>> push_back_data;
327 :
328 38000 : for (const auto & [pid, dof_objects] : pid_to_dof_object_for_sending_back)
329 : {
330 : auto & pid_send_data = push_back_data[pid];
331 2545 : pid_send_data.reserve(dof_objects.size());
332 5090 : for (const DofObject * const dof_object : dof_objects)
333 : {
334 2545 : const auto & our_adreal = libmesh_map_find(dof_to_adreal, dof_object);
335 2545 : pid_send_data.push_back(std::make_tuple(dof_object->id(), our_adreal));
336 : }
337 : }
338 :
339 35455 : auto sent_back_action_functor =
340 2545 : [nodal, our_proc_id, &lm_mesh, &dof_to_adreal](const processor_id_type libmesh_dbg_var(pid),
341 : const std::vector<Datum> & sent_data)
342 : {
343 : mooseAssert(pid != our_proc_id, "We do not send messages to ourself here");
344 : libmesh_ignore(our_proc_id);
345 :
346 5090 : for (auto & [dof_id, adreal] : sent_data)
347 : {
348 2545 : const auto * const dof_object =
349 2545 : nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
350 0 : : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
351 : mooseAssert(dof_object, "This should be non-null");
352 : auto & our_adreal = dof_to_adreal[dof_object];
353 2036 : our_adreal = adreal;
354 : }
355 : };
356 35455 : TIMPI::push_parallel_vector_data(communicator, push_back_data, sent_back_action_functor);
357 : }
358 :
359 : /**
360 : * This function is used to communicate gaps across processes
361 : * @param dof_to_weighted_gap Map from degree of freedom to weighted (weak) gap
362 : * @param mesh Mesh used to locate nodes or elements
363 : * @param nodal Whether the element has Lagrange interpolation
364 : * @param normalize_c Whether to normalize with size the c coefficient in contact constraint
365 : * @param communicator Process communicator
366 : * @param send_data_back After aggregating data on the owning process, whether to send the aggregate
367 : * back to senders. This can be necessary for things like penalty contact in which the constraint is
368 : * not enforced by the owner but in a weighted way by the displacement constraints
369 : */
370 : void communicateGaps(
371 : std::unordered_map<const DofObject *, std::pair<ADReal, Real>> & dof_to_weighted_gap,
372 : const MooseMesh & mesh,
373 : bool nodal,
374 : bool normalize_c,
375 : const Parallel::Communicator & communicator,
376 : bool send_data_back);
377 : }
378 : }
379 : }
|