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 76 : explicit StandardType(const ADRankTwoTensor * example = nullptr)
41 76 : : DataType(StandardType<ADReal>(example ? &((*example)(0, 0)) : nullptr),
42 152 : LIBMESH_DIM * LIBMESH_DIM)
43 : {
44 76 : }
45 :
46 76 : 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 230126 : 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 1294854 : for (auto & pr : dof_map)
84 : {
85 1064728 : const auto * const dof_object = pr.first;
86 1064728 : const auto proc_id = dof_object->processor_id();
87 1064728 : if (proc_id == our_proc_id)
88 1040364 : continue;
89 :
90 48728 : push_data[proc_id].push_back(std::make_pair(dof_object->id(), std::move(pr.second)));
91 : }
92 :
93 230126 : 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 230126 : auto action_functor =
98 15902 : [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 40266 : for (auto & pr : sent_data)
105 : {
106 24364 : const auto dof_id = pr.first;
107 24364 : const auto * const dof_object =
108 24364 : 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 24364 : if (send_data_back)
113 5874 : pid_to_dof_object_for_sending_back[pid].push_back(dof_object);
114 :
115 24364 : dof_map[dof_object][0] += pr.second[0];
116 24364 : dof_map[dof_object][1] += pr.second[1];
117 : }
118 : };
119 :
120 230126 : TIMPI::push_parallel_vector_data(communicator, push_data, action_functor);
121 :
122 : // Now send data back if requested
123 230126 : if (!send_data_back)
124 : return;
125 :
126 : std::unordered_map<processor_id_type, std::vector<Datum>> push_back_data;
127 :
128 37350 : for (const auto & [pid, dof_objects] : pid_to_dof_object_for_sending_back)
129 : {
130 : auto & pid_send_data = push_back_data[pid];
131 3958 : pid_send_data.reserve(dof_objects.size());
132 9832 : for (const DofObject * const dof_object : dof_objects)
133 : {
134 5874 : const auto & [tangent_one, tangent_two] = libmesh_map_find(dof_map, dof_object);
135 5874 : pid_send_data.push_back({dof_object->id(), {tangent_one, tangent_two}});
136 : }
137 : }
138 :
139 33392 : auto sent_back_action_functor =
140 3958 : [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 9832 : for (auto & [dof_id, tangents] : sent_data)
147 : {
148 5874 : const auto * const dof_object =
149 5874 : 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 5874 : auto & [our_tangent_one, our_tangent_two] = dof_map[dof_object];
153 5874 : our_tangent_one = tangents[0];
154 5874 : our_tangent_two = tangents[1];
155 : }
156 : };
157 :
158 33392 : TIMPI::push_parallel_vector_data(communicator, push_back_data, sent_back_action_functor);
159 5874 : }
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 15360 : 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 48526 : for (auto & pr : dof_map_adr2t)
184 : {
185 33166 : const auto * const dof_object = pr.first;
186 33166 : const auto proc_id = dof_object->processor_id();
187 33166 : if (proc_id == our_proc_id)
188 32148 : continue;
189 :
190 1018 : push_data[proc_id].push_back(std::make_pair(dof_object->id(), std::move(pr.second)));
191 : }
192 :
193 15360 : 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 1018 : [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 2036 : for (auto & pr : sent_data)
209 : {
210 1018 : const auto dof_id = pr.first;
211 : const auto * const dof_object =
212 1018 : 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 1018 : if (send_data_back)
217 1018 : pid_to_dof_object_for_sending_back[pid].push_back(dof_object);
218 :
219 4072 : for (const auto i : make_range(3))
220 12216 : for (const auto j : make_range(3))
221 9162 : dof_map_adr2t[dof_object](i, j) += pr.second(i, j);
222 : }
223 1018 : };
224 :
225 15360 : TIMPI::push_parallel_vector_data(communicator, push_data, action_functor);
226 :
227 : // Now send data back if requested
228 15360 : if (!send_data_back)
229 : return;
230 :
231 : std::unordered_map<processor_id_type, std::vector<Datum>> push_back_data;
232 :
233 16378 : for (const auto & [pid, dof_objects] : pid_to_dof_object_for_sending_back)
234 : {
235 : auto & pid_send_data = push_back_data[pid];
236 1018 : pid_send_data.reserve(dof_objects.size());
237 2036 : for (const DofObject * const dof_object : dof_objects)
238 : {
239 1018 : const auto & r2t = libmesh_map_find(dof_map_adr2t, dof_object);
240 1018 : pid_send_data.push_back({dof_object->id(), r2t});
241 : }
242 : }
243 :
244 : auto sent_back_action_functor =
245 1018 : [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 2036 : for (auto & [dof_id, r2t_sent] : sent_data)
252 : {
253 : const auto * const dof_object =
254 1018 : 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 1018 : auto & r2t = dof_map_adr2t[dof_object];
258 : r2t = r2t_sent;
259 : }
260 16378 : };
261 :
262 15360 : TIMPI::push_parallel_vector_data(communicator, push_back_data, sent_back_action_functor);
263 : }
264 :
265 : template <typename T>
266 : void
267 38400 : 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 121315 : for (auto & pr : dof_to_adreal)
281 : {
282 82915 : const auto * const dof_object = pr.first;
283 82915 : const auto proc_id = dof_object->processor_id();
284 82915 : if (proc_id == our_proc_id)
285 80370 : continue;
286 :
287 4581 : push_data[proc_id].push_back(std::make_tuple(dof_object->id(), std::move(pr.second)));
288 : }
289 :
290 38400 : 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 38400 : auto action_functor =
295 2545 : [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 5090 : for (auto & [dof_id, weighted_gap] : sent_data)
306 : {
307 2545 : const auto * const dof_object =
308 2545 : 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 2545 : if (send_data_back)
312 2545 : pid_to_dof_object_for_sending_back[pid].push_back(dof_object);
313 2545 : auto & our_adreal = dof_to_adreal[dof_object];
314 2545 : our_adreal += weighted_gap;
315 : }
316 : };
317 :
318 38400 : TIMPI::push_parallel_vector_data(communicator, push_data, action_functor);
319 :
320 : // Now send data back if requested
321 38400 : if (!send_data_back)
322 : return;
323 :
324 : std::unordered_map<processor_id_type, std::vector<Datum>> push_back_data;
325 :
326 40945 : for (const auto & [pid, dof_objects] : pid_to_dof_object_for_sending_back)
327 : {
328 : auto & pid_send_data = push_back_data[pid];
329 2545 : pid_send_data.reserve(dof_objects.size());
330 5090 : for (const DofObject * const dof_object : dof_objects)
331 : {
332 2545 : const auto & our_adreal = libmesh_map_find(dof_to_adreal, dof_object);
333 2545 : pid_send_data.push_back(std::make_tuple(dof_object->id(), our_adreal));
334 : }
335 : }
336 :
337 38400 : auto sent_back_action_functor =
338 2545 : [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 5090 : for (auto & [dof_id, adreal] : sent_data)
345 : {
346 2545 : const auto * const dof_object =
347 2545 : 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 2545 : auto & our_adreal = dof_to_adreal[dof_object];
351 2036 : our_adreal = adreal;
352 : }
353 : };
354 38400 : 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 : }
|