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 "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 :
33 : namespace TIMPI
34 : {
35 :
36 : template <>
37 : class StandardType<ADRankTwoTensor> : public DataType
38 : {
39 : public:
40 45 : explicit StandardType(const ADRankTwoTensor * example = nullptr)
41 45 : : DataType(StandardType<ADReal>(example ? &((*example)(0, 0)) : nullptr),
42 90 : LIBMESH_DIM * LIBMESH_DIM)
43 : {
44 45 : }
45 :
46 45 : inline ~StandardType() { this->free(); }
47 :
48 : static const bool is_fixed_type = true;
49 : };
50 :
51 : } // namespace TIMPI
52 :
53 : namespace Moose
54 : {
55 : namespace Mortar
56 : {
57 : namespace Contact
58 : {
59 :
60 : /**
61 : * This function is used to communicate velocities across processes
62 : * @param dof_to_weighted_gap Map from degree of freedom to weighted (weak) gap
63 : * @param mesh Mesh used to locate nodes or elements
64 : * @param nodal Whether the element has Lagrange interpolation
65 : * @param communicator Process communicator
66 : * @param send_data_back Whether to send back data to a distributed constraint
67 : */
68 : template <typename T>
69 : inline void
70 148717 : communicateVelocities(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 934588 : for (auto & pr : dof_map)
84 : {
85 785871 : const auto * const dof_object = pr.first;
86 785871 : const auto proc_id = dof_object->processor_id();
87 785871 : if (proc_id == our_proc_id)
88 773105 : continue;
89 :
90 25532 : push_data[proc_id].push_back(std::make_pair(dof_object->id(), std::move(pr.second)));
91 : }
92 :
93 148717 : 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 148717 : auto action_functor =
98 7499 : [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 20265 : for (auto & pr : sent_data)
105 : {
106 12766 : const auto dof_id = pr.first;
107 12766 : const auto * const dof_object =
108 12766 : nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
109 0 : : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
110 : mooseAssert(dof_object, "This should be non-null");
111 :
112 12766 : if (send_data_back)
113 4012 : pid_to_dof_object_for_sending_back[pid].push_back(dof_object);
114 :
115 12766 : dof_map[dof_object][0] += pr.second[0];
116 12766 : dof_map[dof_object][1] += pr.second[1];
117 : }
118 : };
119 :
120 148717 : TIMPI::push_parallel_vector_data(communicator, push_data, action_functor);
121 :
122 : // Now send data back if requested
123 148717 : if (!send_data_back)
124 : return;
125 :
126 : std::unordered_map<processor_id_type, std::vector<Datum>> push_back_data;
127 :
128 32616 : for (const auto & [pid, dof_objects] : pid_to_dof_object_for_sending_back)
129 : {
130 : auto & pid_send_data = push_back_data[pid];
131 2322 : pid_send_data.reserve(dof_objects.size());
132 6334 : for (const DofObject * const dof_object : dof_objects)
133 : {
134 4012 : const auto & [tangent_one, tangent_two] = libmesh_map_find(dof_map, dof_object);
135 4012 : pid_send_data.push_back({dof_object->id(), {tangent_one, tangent_two}});
136 : }
137 : }
138 :
139 30294 : auto sent_back_action_functor =
140 2322 : [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 6334 : for (auto & [dof_id, tangents] : sent_data)
147 : {
148 4012 : const auto * const dof_object =
149 4012 : nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
150 0 : : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
151 : mooseAssert(dof_object, "This should be non-null");
152 4012 : auto & [our_tangent_one, our_tangent_two] = dof_map[dof_object];
153 4012 : our_tangent_one = tangents[0];
154 4012 : our_tangent_two = tangents[1];
155 : }
156 : };
157 :
158 30294 : TIMPI::push_parallel_vector_data(communicator, push_back_data, sent_back_action_functor);
159 4012 : }
160 :
161 : /**
162 : * This function is used to communicate velocities across processes
163 : * @param dof_map_adr2t Map from degree of freedom to weighted tank two tensor
164 : * @param mesh Mesh used to locate nodes or elements
165 : * @param nodal Whether the element has Lagrange interpolation
166 : * @param communicator Process communicator
167 : * @param send_data_back Whether to send back data to a distributed constraint
168 : */
169 : inline void
170 14174 : communicateR2T(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 44092 : for (auto & pr : dof_map_adr2t)
184 : {
185 29918 : const auto * const dof_object = pr.first;
186 29918 : const auto proc_id = dof_object->processor_id();
187 29918 : if (proc_id == our_proc_id)
188 29580 : continue;
189 :
190 338 : push_data[proc_id].push_back(std::make_pair(dof_object->id(), std::move(pr.second)));
191 : }
192 :
193 14174 : 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 338 : [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 676 : for (auto & pr : sent_data)
209 : {
210 338 : const auto dof_id = pr.first;
211 : const auto * const dof_object =
212 338 : nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
213 0 : : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
214 : mooseAssert(dof_object, "This should be non-null");
215 :
216 338 : if (send_data_back)
217 338 : pid_to_dof_object_for_sending_back[pid].push_back(dof_object);
218 :
219 1352 : for (const auto i : make_range(3))
220 4056 : for (const auto j : make_range(3))
221 3042 : dof_map_adr2t[dof_object](i, j) += pr.second(i, j);
222 : }
223 338 : };
224 :
225 14174 : TIMPI::push_parallel_vector_data(communicator, push_data, action_functor);
226 :
227 : // Now send data back if requested
228 14174 : if (!send_data_back)
229 : return;
230 :
231 : std::unordered_map<processor_id_type, std::vector<Datum>> push_back_data;
232 :
233 14512 : for (const auto & [pid, dof_objects] : pid_to_dof_object_for_sending_back)
234 : {
235 : auto & pid_send_data = push_back_data[pid];
236 338 : pid_send_data.reserve(dof_objects.size());
237 676 : for (const DofObject * const dof_object : dof_objects)
238 : {
239 338 : const auto & r2t = libmesh_map_find(dof_map_adr2t, dof_object);
240 338 : pid_send_data.push_back({dof_object->id(), r2t});
241 : }
242 : }
243 :
244 : auto sent_back_action_functor =
245 338 : [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 676 : for (auto & [dof_id, r2t_sent] : sent_data)
252 : {
253 : const auto * const dof_object =
254 338 : nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
255 0 : : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
256 : mooseAssert(dof_object, "This should be non-null");
257 338 : auto & r2t = dof_map_adr2t[dof_object];
258 : r2t = r2t_sent;
259 : }
260 14512 : };
261 :
262 14174 : TIMPI::push_parallel_vector_data(communicator, push_back_data, sent_back_action_functor);
263 : }
264 :
265 : template <typename T>
266 : void
267 35435 : communicateRealObject(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 110230 : for (auto & pr : dof_to_adreal)
281 : {
282 74795 : const auto * const dof_object = pr.first;
283 74795 : const auto proc_id = dof_object->processor_id();
284 74795 : if (proc_id == our_proc_id)
285 73950 : continue;
286 :
287 1521 : push_data[proc_id].push_back(std::make_tuple(dof_object->id(), std::move(pr.second)));
288 : }
289 :
290 35435 : 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 35435 : auto action_functor =
295 845 : [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 1690 : for (auto & [dof_id, weighted_gap] : sent_data)
306 : {
307 845 : const auto * const dof_object =
308 845 : nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
309 0 : : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
310 : mooseAssert(dof_object, "This should be non-null");
311 845 : if (send_data_back)
312 845 : pid_to_dof_object_for_sending_back[pid].push_back(dof_object);
313 845 : auto & our_adreal = dof_to_adreal[dof_object];
314 845 : our_adreal += weighted_gap;
315 : }
316 : };
317 :
318 35435 : TIMPI::push_parallel_vector_data(communicator, push_data, action_functor);
319 :
320 : // Now send data back if requested
321 35435 : if (!send_data_back)
322 : return;
323 :
324 : std::unordered_map<processor_id_type, std::vector<Datum>> push_back_data;
325 :
326 36280 : for (const auto & [pid, dof_objects] : pid_to_dof_object_for_sending_back)
327 : {
328 : auto & pid_send_data = push_back_data[pid];
329 845 : pid_send_data.reserve(dof_objects.size());
330 1690 : for (const DofObject * const dof_object : dof_objects)
331 : {
332 845 : const auto & our_adreal = libmesh_map_find(dof_to_adreal, dof_object);
333 845 : pid_send_data.push_back(std::make_tuple(dof_object->id(), our_adreal));
334 : }
335 : }
336 :
337 35435 : auto sent_back_action_functor =
338 845 : [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 1690 : for (auto & [dof_id, adreal] : sent_data)
345 : {
346 845 : const auto * const dof_object =
347 845 : nodal ? static_cast<const DofObject *>(lm_mesh.node_ptr(dof_id))
348 0 : : static_cast<const DofObject *>(lm_mesh.elem_ptr(dof_id));
349 : mooseAssert(dof_object, "This should be non-null");
350 845 : auto & our_adreal = dof_to_adreal[dof_object];
351 676 : our_adreal = adreal;
352 : }
353 : };
354 35435 : TIMPI::push_parallel_vector_data(communicator, push_back_data, sent_back_action_functor);
355 : }
356 :
357 : /**
358 : * This function is used to communicate gaps across processes
359 : * @param dof_to_weighted_gap Map from degree of freedom to weighted (weak) gap
360 : * @param mesh Mesh used to locate nodes or elements
361 : * @param nodal Whether the element has Lagrange interpolation
362 : * @param normalize_c Whether to normalize with size the c coefficient in contact constraint
363 : * @param communicator Process communicator
364 : * @param send_data_back After aggregating data on the owning process, whether to send the aggregate
365 : * back to senders. This can be necessary for things like penalty contact in which the constraint is
366 : * not enforced by the owner but in a weighted way by the displacement constraints
367 : */
368 : void 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 : }
|