https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PetscDMMoose.C
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#include "PetscDMMoose.h"
11
12// PETSc includes
13#include <petscerror.h>
14#include <petsc/private/dmimpl.h>
15
16// MOOSE includes
17#include "FEProblem.h"
18#include "DisplacedProblem.h"
19#include "MooseMesh.h"
20#include "NonlinearSystem.h"
21#include "PenetrationLocator.h"
22#include "NearestNodeLocator.h"
23#include "GeometricSearchData.h"
24#include "MooseVariableScalar.h"
25
26#include "libmesh/nonlinear_implicit_system.h"
27#include "libmesh/nonlinear_solver.h"
28#include "libmesh/petsc_macro.h"
29#include "libmesh/petsc_vector.h"
30#include "libmesh/petsc_matrix.h"
31#include "libmesh/dof_map.h"
32#include "libmesh/preconditioner.h"
33#include "libmesh/elem_side_builder.h"
34
35template <typename I1, typename I2>
36void
37checkSize(const std::string & split_name, const I1 split_size, const I2 size_expected_by_parent)
38{
39 if (libMesh::cast_int<libMesh::numeric_index_type>(split_size) !=
40 libMesh::cast_int<libMesh::numeric_index_type>(size_expected_by_parent))
41 mooseError("Split '",
42 split_name,
43 "' has size ",
44 libMesh::cast_int<libMesh::numeric_index_type>(split_size),
45 " but the parent split expected size ",
46 libMesh::cast_int<libMesh::numeric_index_type>(size_expected_by_parent),
47 ". Make sure that you have non-overlapping complete sets for variables and "
48 "blocks as well as consistency in sides/unsides, contacts/uncontacts, etc.");
49}
50
52{
53 NonlinearSystemBase * _nl; // nonlinear system context
55 const System * _system;
56 DM_Moose * _parent = nullptr;
57 std::set<std::string> * _vars; // variables
58 std::map<std::string, unsigned int> * _var_ids;
59 std::map<unsigned int, std::string> * _var_names;
60 bool _all_vars; // whether all system variables are included
61 std::set<std::string> * _blocks; // mesh blocks
62 std::map<std::string, subdomain_id_type> * _block_ids;
63 std::map<unsigned int, std::string> * _block_names;
64 bool _all_blocks; // all blocks are included
65 std::set<std::string> * _sides; // mesh surfaces (edges in 2D)
66 std::map<BoundaryID, std::string> * _side_names;
67 std::map<std::string, BoundaryID> * _side_ids;
68 std::set<std::string> * _unsides; // excluded sides
69 std::map<std::string, BoundaryID> * _unside_ids;
70 std::map<BoundaryID, std::string> * _unside_names;
71 std::set<std::string> * _unside_by_var; // excluded sides by variable
72 std::set<std::pair<BoundaryID, unsigned int>> * _unside_by_var_set;
73 bool _nosides; // whether to include any sides
74 bool _nounsides; // whether to exclude any sides
76 typedef std::pair<std::string, std::string> ContactName;
77 typedef std::pair<BoundaryID, BoundaryID> ContactID;
78 std::set<ContactName> * _contacts;
79 std::map<ContactID, ContactName> * _contact_names;
80 std::set<ContactName> * _uncontacts;
81 std::map<ContactID, ContactName> * _uncontact_names;
82 std::map<ContactName, PetscBool> * _contact_displaced;
83 std::map<ContactName, PetscBool> * _uncontact_displaced;
87 // to locate splits without having to search, however,
88 // maintain a multimap from names to split locations (to enable
89 // the same split to appear in multiple spots (this might
90 // break the current implementation of PCFieldSplit, though).
91 std::multimap<std::string, unsigned int> * _splitlocs;
92 struct SplitInfo
93 {
94 DM _dm;
95 IS _rembedding; // relative embedding
96 };
97 std::map<std::string, SplitInfo> * _splits;
98
101
103 std::string * _name;
104
108 void checkChildSize(DM child, PetscInt child_size, const std::string & child_name);
109};
110
111void
112DM_Moose::checkChildSize(DM child, const PetscInt child_size, const std::string & child_name)
113{
114 for (const auto & split : *_splits)
115 if (split.second._dm == child)
116 {
117 mooseAssert(split.first == child_name, "These should match");
118 PetscInt parent_expected_size;
119 auto ierr = ISGetLocalSize(split.second._rembedding, &parent_expected_size);
120 if (ierr)
121 mooseError("Unable to get size");
122 checkSize(child_name, child_size, parent_expected_size);
123 return;
124 }
125
126 mooseError("No child DM match");
127}
128
129PetscErrorCode
131{
132 PetscBool ismoose;
133
135 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
136 LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)dm, DMMOOSE, &ismoose));
137 if (!ismoose)
138 LIBMESH_SETERRQ2(((PetscObject)dm)->comm,
139 PETSC_ERR_ARG_WRONG,
140 "Got DM of type %s, not of type %s",
141 ((PetscObject)dm)->type_name,
142 DMMOOSE);
143 PetscFunctionReturn(PETSC_SUCCESS);
144}
145
146PetscErrorCode
148 std::vector<std::pair<std::string, std::string>> & contact_names,
149 std::vector<PetscBool> & displaced)
150{
153 DM_Moose * dmm = (DM_Moose *)dm->data;
154 for (const auto & it : *(dmm->_contact_names))
155 {
156 contact_names.push_back(it.second);
157 displaced.push_back((*dmm->_contact_displaced)[it.second]);
158 }
159 PetscFunctionReturn(PETSC_SUCCESS);
160}
161
162PetscErrorCode
164 std::vector<std::pair<std::string, std::string>> & uncontact_names,
165 std::vector<PetscBool> & displaced)
166{
169 DM_Moose * dmm = (DM_Moose *)dm->data;
170 for (const auto & it : *(dmm->_uncontact_names))
171 {
172 uncontact_names.push_back(it.second);
173 displaced.push_back((*dmm->_uncontact_displaced)[it.second]);
174 }
175 PetscFunctionReturn(PETSC_SUCCESS);
176}
177
178PetscErrorCode
179DMMooseGetSides(DM dm, std::vector<std::string> & side_names)
180{
183 DM_Moose * dmm = (DM_Moose *)dm->data;
184 for (const auto & it : *(dmm->_side_ids))
185 side_names.push_back(it.first);
186 PetscFunctionReturn(PETSC_SUCCESS);
187}
188
189PetscErrorCode
190DMMooseGetUnSides(DM dm, std::vector<std::string> & side_names)
191{
194 DM_Moose * dmm = (DM_Moose *)dm->data;
195 for (const auto & it : *(dmm->_unside_ids))
196 side_names.push_back(it.first);
197 PetscFunctionReturn(PETSC_SUCCESS);
198}
199
200PetscErrorCode
201DMMooseGetBlocks(DM dm, std::vector<std::string> & block_names)
202{
205 DM_Moose * dmm = (DM_Moose *)dm->data;
206 for (const auto & it : *(dmm->_block_ids))
207 block_names.push_back(it.first);
208 PetscFunctionReturn(PETSC_SUCCESS);
209}
210
211PetscErrorCode
212DMMooseGetVariables(DM dm, std::vector<std::string> & var_names)
213{
216 DM_Moose * dmm = (DM_Moose *)(dm->data);
217 for (const auto & it : *(dmm->_var_ids))
218 var_names.push_back(it.first);
219 PetscFunctionReturn(PETSC_SUCCESS);
220}
221
222PetscErrorCode
224{
227 if (dm->setupcalled)
228 SETERRQ(((PetscObject)dm)->comm,
230 "Cannot reset the NonlinearSystem after DM has been set up.");
231 DM_Moose * dmm = (DM_Moose *)(dm->data);
232 dmm->_nl = &nl;
233 PetscFunctionReturn(PETSC_SUCCESS);
234}
235
236PetscErrorCode
238{
241 if (dm->setupcalled)
242 SETERRQ(((PetscObject)dm)->comm,
244 "Cannot reset the degree of freedom map after DM has been set up.");
245 DM_Moose * dmm = (DM_Moose *)(dm->data);
246 dmm->_dof_map = &dof_map;
247 PetscFunctionReturn(PETSC_SUCCESS);
248}
249
250PetscErrorCode
251DMMooseSetSystem(DM dm, const System & system)
252{
255 if (dm->setupcalled)
256 SETERRQ(((PetscObject)dm)->comm,
258 "Cannot reset the degree of freedom map after DM has been set up.");
259 DM_Moose * dmm = (DM_Moose *)(dm->data);
260 dmm->_system = &system;
261 PetscFunctionReturn(PETSC_SUCCESS);
262}
263
264PetscErrorCode
265DMMooseSetName(DM dm, const std::string & dm_name)
266{
269 if (dm->setupcalled)
270 SETERRQ(((PetscObject)dm)->comm,
272 "Cannot reset the MOOSE DM name after DM has been set up.");
273 DM_Moose * dmm = (DM_Moose *)(dm->data);
274 *dmm->_name = dm_name;
275 PetscFunctionReturn(PETSC_SUCCESS);
276}
277
278PetscErrorCode
280{
283 if (dm->setupcalled)
284 SETERRQ(((PetscObject)dm)->comm,
286 "Cannot reset the parent DM after the child DM has been set up.");
287
288 DM_Moose * dmm = (DM_Moose *)(dm->data);
289 dmm->_parent = parent;
290 PetscFunctionReturn(PETSC_SUCCESS);
291}
292
293PetscErrorCode
294DMMooseSetVariables(DM dm, const std::set<std::string> & vars)
295{
296 DM_Moose * dmm = (DM_Moose *)dm->data;
297
300 if (dm->setupcalled)
301 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for an already setup DM");
302 if (dmm->_vars)
303 delete dmm->_vars;
304 std::set<std::string> processed_vars;
305 for (const auto & var_name : vars)
306 {
307 const auto * const var =
308 dmm->_nl->hasVariable(var_name)
309 ? cast_ptr<MooseVariableBase *>(&dmm->_nl->getVariable(0, var_name))
310 : cast_ptr<MooseVariableBase *>(&dmm->_nl->getScalarVariable(0, var_name));
311 if (var->isArray())
312 for (const auto i : make_range(var->count()))
313 processed_vars.insert(var->arrayVariableComponent(i));
314 else
315 processed_vars.insert(var_name);
316 }
317
318 dmm->_vars = new std::set<std::string>(std::move(processed_vars));
319 PetscFunctionReturn(PETSC_SUCCESS);
320}
321
322PetscErrorCode
323DMMooseSetBlocks(DM dm, const std::set<std::string> & blocks)
324{
325 DM_Moose * dmm = (DM_Moose *)dm->data;
326
329 if (dm->setupcalled)
330 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for an already setup DM");
331 if (dmm->_blocks)
332 delete dmm->_blocks;
333 dmm->_blocks = new std::set<std::string>(blocks);
334 PetscFunctionReturn(PETSC_SUCCESS);
335}
336
337PetscErrorCode
338DMMooseSetSides(DM dm, const std::set<std::string> & sides)
339{
340 DM_Moose * dmm = (DM_Moose *)dm->data;
341
344 if (dm->setupcalled)
345 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for an already setup DM");
346 if (dmm->_sides)
347 delete dmm->_sides;
348 dmm->_sides = new std::set<std::string>(sides);
349 PetscFunctionReturn(PETSC_SUCCESS);
350}
351
352PetscErrorCode
353DMMooseSetUnSides(DM dm, const std::set<std::string> & unsides)
354{
355 DM_Moose * dmm = (DM_Moose *)dm->data;
356
359 if (dm->setupcalled)
360 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for an already setup DM");
361 if (dmm->_unsides)
362 delete dmm->_unsides;
363 dmm->_unsides = new std::set<std::string>(unsides);
364 PetscFunctionReturn(PETSC_SUCCESS);
365}
366
367PetscErrorCode
368DMMooseSetUnSideByVar(DM dm, const std::set<std::string> & unside_by_var)
369{
370 DM_Moose * dmm = (DM_Moose *)dm->data;
371
374 if (dm->setupcalled)
375 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for an already setup DM");
376 if (dmm->_unside_by_var)
377 delete dmm->_unside_by_var;
378 dmm->_unside_by_var = new std::set<std::string>(unside_by_var);
379 PetscFunctionReturn(PETSC_SUCCESS);
380}
381
382PetscErrorCode
384 const std::vector<std::pair<std::string, std::string>> & contacts,
385 const std::vector<PetscBool> & displaced)
386{
387 DM_Moose * dmm = (DM_Moose *)dm->data;
388
391 if (dm->setupcalled)
392 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for an already setup DM");
393 if (contacts.size() != displaced.size())
394 LIBMESH_SETERRQ2(PETSC_COMM_SELF,
395 PETSC_ERR_ARG_SIZ,
396 "Nonmatching sizes of the contact and displaced arrays: %" LIBMESH_PETSCINT_FMT
397 " != %" LIBMESH_PETSCINT_FMT,
398 static_cast<PetscInt>(contacts.size()),
399 static_cast<PetscInt>(displaced.size()));
400 if (dmm->_contacts)
401 delete dmm->_contacts;
402 dmm->_contact_displaced->clear();
403 dmm->_contacts = new std::set<DM_Moose::ContactName>();
404 for (unsigned int i = 0; i < contacts.size(); ++i)
405 {
406 dmm->_contacts->insert(contacts[i]);
407 dmm->_contact_displaced->insert(std::make_pair(contacts[i], displaced[i]));
408 }
409 PetscFunctionReturn(PETSC_SUCCESS);
410}
411
412PetscErrorCode
414 const std::vector<std::pair<std::string, std::string>> & uncontacts,
415 const std::vector<PetscBool> & displaced)
416{
417 DM_Moose * dmm = (DM_Moose *)dm->data;
418
421 if (dm->setupcalled)
422 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for an already setup DM");
423 if (uncontacts.size() != displaced.size())
424 LIBMESH_SETERRQ2(
425 PETSC_COMM_SELF,
426 PETSC_ERR_ARG_SIZ,
427 "Nonmatching sizes of the uncontact and displaced arrays: %" LIBMESH_PETSCINT_FMT
428 " != %" LIBMESH_PETSCINT_FMT,
429 static_cast<PetscInt>(uncontacts.size()),
430 static_cast<PetscInt>(displaced.size()));
431 if (dmm->_uncontacts)
432 delete dmm->_uncontacts;
433 dmm->_uncontact_displaced->clear();
434 dmm->_uncontacts = new std::set<DM_Moose::ContactName>();
435 for (unsigned int i = 0; i < uncontacts.size(); ++i)
436 {
437 dmm->_uncontacts->insert(uncontacts[i]);
438 dmm->_uncontact_displaced->insert(std::make_pair(uncontacts[i], displaced[i]));
439 }
440 PetscFunctionReturn(PETSC_SUCCESS);
441}
442
443PetscErrorCode
445{
448 DM_Moose * dmm = (DM_Moose *)(dm->data);
449 nl = dmm->_nl;
450 PetscFunctionReturn(PETSC_SUCCESS);
451}
452
453PetscErrorCode
454DMMooseSetSplitNames(DM dm, const std::vector<std::string> & split_names)
455{
458 DM_Moose * dmm = (DM_Moose *)(dm->data);
459
460 if (dmm->_splits)
461 {
462 for (auto & it : *(dmm->_splits))
463 {
464 LibmeshPetscCallQ(DMDestroy(&(it.second._dm)));
465 LibmeshPetscCallQ(ISDestroy(&(it.second._rembedding)));
466 }
467 delete dmm->_splits;
468 dmm->_splits = LIBMESH_PETSC_NULLPTR;
469 }
470 if (dmm->_splitlocs)
471 {
472 delete dmm->_splitlocs;
473 dmm->_splitlocs = LIBMESH_PETSC_NULLPTR;
474 }
475 dmm->_splits = new std::map<std::string, DM_Moose::SplitInfo>();
476 dmm->_splitlocs = new std::multimap<std::string, unsigned int>();
477 for (unsigned int i = 0; i < split_names.size(); ++i)
478 {
480 info._dm = LIBMESH_PETSC_NULLPTR;
481 info._rembedding = LIBMESH_PETSC_NULLPTR;
482 std::string name = split_names[i];
483 (*dmm->_splits)[name] = info;
484 dmm->_splitlocs->insert(std::make_pair(name, i));
485 }
486 PetscFunctionReturn(PETSC_SUCCESS);
487}
488
489PetscErrorCode
490DMMooseGetSplitNames(DM dm, std::vector<std::string> & split_names)
491{
494 DM_Moose * dmm = (DM_Moose *)(dm->data);
495 if (!dm->setupcalled)
496 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM not set up");
497 split_names.clear();
498 split_names.reserve(dmm->_splitlocs->size());
499 if (dmm->_splitlocs && dmm->_splitlocs->size())
500 for (const auto & lit : *(dmm->_splitlocs))
501 {
502 std::string sname = lit.first;
503 unsigned int sloc = lit.second;
504 split_names[sloc] = sname;
505 }
506 PetscFunctionReturn(PETSC_SUCCESS);
507}
508
509static PetscErrorCode
511{
512 DM_Moose * dmm = (DM_Moose *)dm->data;
513
515 if (!embedding)
516 PetscFunctionReturn(PETSC_SUCCESS);
517 if (!dmm->_embedding)
518 {
519 // The rules interpreting the coexistence of blocks (un)sides/(un)contacts are these
520 // [sides and contacts behave similarly, so 'sides' means 'sides/contacts']
521 // ['ANY' means 'not NONE' and covers 'ALL' as well, unless there is a specific 'ALL' clause,
522 // which overrides 'ANY'; 'NOT ALL' means not ALL and not NONE]
523 // [there are always some blocks, since by default 'ALL' is assumed, unless it is overridden by
524 // a specific list, which implies ANY]
525 // In general,
526 // (1) ALL blocks and ANY sides are interpreted as the INTERSECTION of blocks and sides,
527 // equivalent to just the sides (since ALL blocks are assumed to be a cover).
528 // (2) NOT ALL blocks and ANY or NO sides are interpreted as the UNION of blocks and sides.
529 // (3a) ANY unsides and ANY blocks are interpreted as the DIFFERENCE of blocks and unsides.
530 // (3b) ANY unsides and ANY sides are interpreted as the DIFFERENCE of sides and unsides.
531 // (4) NO unsides means NO DIFFERENCE is needed.
532 // The result is easily computed by first computing the result of (1 & 2) followed by difference
533 // with the result of (3 & 4).
534 // To simply (1 & 2) observe the following:
535 // - The intersection is computed only if ALL blocks and ANY sides, and the result is the sides,
536 // so block dofs do not need to be computed.
537 // - Otherwise the union is computed, and initially consists of the blocks' dofs, to which the
538 // sides' dofs are added, if ANY.
539 // - The result is called 'indices'
540 // To satisfy (3 & 4) simply cmpute subtrahend set 'unindices' as all of the unsides' dofs:
541 // Then take the set difference of 'indices' and 'unindices', putting the result in 'dindices'.
542 if (!dmm->_all_vars || !dmm->_all_blocks || !dmm->_nosides || !dmm->_nounsides ||
543 !dmm->_nounside_by_var || !dmm->_nocontacts || !dmm->_nouncontacts)
544 {
545 auto & dofmap = *dmm->_dof_map;
546 // Put this outside the lambda scope to avoid constant memory reallocation
547 std::vector<dof_id_type> node_indices;
548 auto process_nodal_dof_indices =
549 [&dofmap, &node_indices](const Node & node,
550 const unsigned int var_num,
551 std::set<dof_id_type> & local_indices,
552 std::set<dof_id_type> * const nonlocal_indices = nullptr)
553 {
554 dofmap.dof_indices(&node, node_indices, var_num);
555 for (const auto index : node_indices)
556 {
557 if (index >= dofmap.first_dof() && index < dofmap.end_dof())
558 local_indices.insert(index);
559 else if (nonlocal_indices)
560 nonlocal_indices->insert(index);
561 }
562 };
563
564 auto process_elem_dof_indices =
565 [&dofmap](const std::vector<dof_id_type> & elem_indices,
566 std::set<dof_id_type> & local_indices,
567 std::set<dof_id_type> * const nonlocal_indices = nullptr)
568 {
569 for (const auto index : elem_indices)
570 {
571 if (index >= dofmap.first_dof() && index < dofmap.end_dof())
572 local_indices.insert(index);
573 else if (nonlocal_indices)
574 nonlocal_indices->insert(index);
575 }
576 };
577
578 std::set<dof_id_type> indices;
579 std::set<dof_id_type> unindices;
580 std::set<dof_id_type> cached_indices;
581 std::set<dof_id_type> cached_unindices;
582 auto & lm_mesh = dmm->_system->get_mesh();
583 const auto & node_to_elem_map = dmm->_nl->feProblem().mesh().nodeToElemMap();
584 for (const auto & vit : *(dmm->_var_ids))
585 {
586 unsigned int v = vit.second;
587 // Iterate only over this DM's blocks.
588 if (!dmm->_all_blocks || (dmm->_nosides && dmm->_nocontacts))
589 for (const auto & bit : *(dmm->_block_ids))
590 {
591 subdomain_id_type b = bit.second;
592 for (const auto & elem : as_range(lm_mesh.active_local_subdomain_elements_begin(b),
593 lm_mesh.active_local_subdomain_elements_end(b)))
594 {
595 // Get the degree of freedom indices for the given variable off the current element.
596 std::vector<dof_id_type> evindices;
597 dofmap.dof_indices(elem, evindices, v);
598 process_elem_dof_indices(evindices, indices);
599 }
600
601 // Sometime, we own nodes but do not own the elements the nodes are connected to
602 {
603 bool is_on_current_block = false;
604 for (auto & node : lm_mesh.local_node_ptr_range())
605 {
606 const unsigned int n_comp = node->n_comp(dmm->_system->number(), v);
607
608 // skip it if no dof
609 if (!n_comp)
610 continue;
611
612 auto node_to_elem_pair = node_to_elem_map.find(node->id());
613 is_on_current_block = false;
614 for (const auto & elem_num : node_to_elem_pair->second)
615 {
616 // if one of incident elements belongs to a block, we consider
617 // the node lives in the block
618 const Elem & neighbor_elem = lm_mesh.elem_ref(elem_num);
619 if (neighbor_elem.subdomain_id() == b)
620 {
621 is_on_current_block = true;
622 break;
623 }
624 }
625 // we add indices for the current block only
626 if (!is_on_current_block)
627 continue;
628
629 process_nodal_dof_indices(*node, v, indices);
630 }
631 }
632 }
633
634 // Iterate over the sides from this split.
635 if (dmm->_side_ids->size())
636 {
637 // For some reason the following may return an empty node list
638 // std::vector<dof_id_type> snodes;
639 // std::vector<boundary_id_type> sides;
640 // dmm->nl->system().get_mesh().get_boundary_info().build_node_list(snodes, sides);
641 // // FIXME: make an array of (snode,side) pairs, sort on side and use std::lower_bound
642 // from <algorithm>
643 // for (dof_id_type i = 0; i < sides.size(); ++i) {
644 // boundary_id_type s = sides[i];
645 // if (!dmm->sidenames->count(s)) continue;
646 // const Node& node = dmm->nl->system().get_mesh().node_ref(snodes[i]);
647 // // determine v's dof on node and insert into indices
648 // }
649 ConstBndNodeRange & bnodes = *dmm->_nl->mesh().getBoundaryNodeRange();
650 for (const auto & bnode : bnodes)
651 {
652 BoundaryID boundary_id = bnode->_bnd_id;
653 if (dmm->_side_names->find(boundary_id) == dmm->_side_names->end())
654 continue;
655
656 const Node * node = bnode->_node;
657 process_nodal_dof_indices(*node, v, indices);
658 }
659 }
660
661 // Iterate over the sides excluded from this split.
662 if (dmm->_unside_ids->size())
663 {
664 ConstBndNodeRange & bnodes = *dmm->_nl->mesh().getBoundaryNodeRange();
665 for (const auto & bnode : bnodes)
666 {
667 BoundaryID boundary_id = bnode->_bnd_id;
668 if (dmm->_unside_names->find(boundary_id) == dmm->_unside_names->end())
669 continue;
670 const Node * node = bnode->_node;
671 process_nodal_dof_indices(*node, v, unindices);
672 }
673 }
674 if (dmm->_unside_by_var_set->size())
675 {
676 std::set<BoundaryID> eligible_bids;
677 for (const auto & [bid, var] : *(dmm->_unside_by_var_set))
678 if (var == v)
679 eligible_bids.insert(bid);
680
681 ConstBndNodeRange & bnodes = *dmm->_nl->mesh().getBoundaryNodeRange();
682 for (const auto & bnode : bnodes)
683 {
684 BoundaryID boundary_id = bnode->_bnd_id;
685 if (eligible_bids.count(boundary_id))
686 {
687 const Node * node = bnode->_node;
688 process_nodal_dof_indices(*node, v, unindices);
689 }
690 }
691 }
692
693 auto process_contact_all_nodes =
694 [dmm, process_nodal_dof_indices, v](const auto & contact_names,
695 auto & indices_to_insert_to)
696 {
697 std::set<boundary_id_type> bc_id_set;
698 // loop over contacts
699 for (const auto & [contact_bid_pair, contact_bname_pair] : contact_names)
700 {
701 libmesh_ignore(contact_bname_pair);
702 bc_id_set.insert(contact_bid_pair.first); // primary
703 bc_id_set.insert(contact_bid_pair.second); // secondary
704 }
705 // loop over boundary elements
707 for (const auto & belem : range)
708 {
709 const Elem * elem_bdry = belem->_elem;
710 const auto side = belem->_side;
711 BoundaryID boundary_id = belem->_bnd_id;
712
713 if (bc_id_set.find(boundary_id) == bc_id_set.end())
714 continue;
715
716 for (const auto node_idx : elem_bdry->node_index_range())
717 if (elem_bdry->is_node_on_side(node_idx, side))
718 process_nodal_dof_indices(elem_bdry->node_ref(node_idx), v, indices_to_insert_to);
719 }
720 };
721
722 auto process_contact_some_nodes =
723 [dmm, process_nodal_dof_indices, v, &dofmap, &lm_mesh, process_elem_dof_indices](
724 const auto & contact_names,
725 auto & indices_to_insert_to,
726 auto & nonlocal_indices_to_insert_to)
727 {
728 std::vector<dof_id_type> evindices;
729 for (const auto & it : contact_names)
730 {
731 PetscBool displaced = (*dmm->_uncontact_displaced)[it.second];
732 PenetrationLocator * locator;
733 if (displaced)
734 {
735 std::shared_ptr<DisplacedProblem> displaced_problem =
738 {
739 std::ostringstream err;
740 err << "Cannot use a displaced uncontact (" << it.second.first << ","
741 << it.second.second << ") with an undisplaced problem";
742 mooseError(err.str());
743 }
744 locator = displaced_problem->geomSearchData()._penetration_locators[it.first];
745 }
746 else
747 locator = dmm->_nl->feProblem().geomSearchData()._penetration_locators[it.first];
748
749 evindices.clear();
750 // penetration locator
751 auto lend = locator->_penetration_info.end();
752 for (auto lit = locator->_penetration_info.begin(); lit != lend; ++lit)
753 {
754 const dof_id_type secondary_node_num = lit->first;
755 PenetrationInfo * pinfo = lit->second;
756 if (pinfo && pinfo->isCaptured())
757 {
758 const Node & secondary_node = lm_mesh.node_ref(secondary_node_num);
759 process_nodal_dof_indices(
760 secondary_node, v, indices_to_insert_to, &nonlocal_indices_to_insert_to);
761
762 // indices for primary element
763 evindices.clear();
764 const Elem * primary_side = pinfo->_side;
765 dofmap.dof_indices(primary_side, evindices, v);
766 process_elem_dof_indices(
767 evindices, indices_to_insert_to, &nonlocal_indices_to_insert_to);
768 } // if pinfo
769 } // for penetration
770 } // for contact name
771 };
772
773 // Include all nodes on the contact surfaces
774 if (dmm->_contact_names->size() && dmm->_include_all_contact_nodes)
775 process_contact_all_nodes(*dmm->_contact_names, indices);
776
777 // Iterate over the contacts included in this split.
778 if (dmm->_contact_names->size() && !(dmm->_include_all_contact_nodes))
779 process_contact_some_nodes(*dmm->_contact_names, indices, cached_indices);
780
781 // Exclude all nodes on the contact surfaces
782 if (dmm->_uncontact_names->size() && dmm->_include_all_contact_nodes)
783 process_contact_all_nodes(*dmm->_uncontact_names, unindices);
784
785 // Iterate over the contacts excluded from this split.
786 if (dmm->_uncontact_names->size() && !(dmm->_include_all_contact_nodes))
787 process_contact_some_nodes(*dmm->_uncontact_names, unindices, cached_unindices);
788 } // variables
789
790 std::vector<dof_id_type> local_vec_indices(cached_indices.size());
791 std::copy(cached_indices.begin(), cached_indices.end(), local_vec_indices.begin());
792 if (dmm->_contact_names->size() && !(dmm->_include_all_contact_nodes))
793 dmm->_nl->feProblem().mesh().comm().allgather(local_vec_indices, false);
794 // insert indices
795 for (const auto & dof : local_vec_indices)
796 if (dof >= dofmap.first_dof() && dof < dofmap.end_dof())
797 indices.insert(dof);
798
799 local_vec_indices.clear();
800 local_vec_indices.resize(cached_unindices.size());
801 std::copy(cached_unindices.begin(), cached_unindices.end(), local_vec_indices.begin());
802 if (dmm->_uncontact_names->size() && !(dmm->_include_all_contact_nodes))
803 dmm->_nl->feProblem().mesh().comm().allgather(local_vec_indices, false);
804 // insert unindices
805 for (const auto & dof : local_vec_indices)
806 if (dof >= dofmap.first_dof() && dof < dofmap.end_dof())
807 unindices.insert(dof);
808
809 std::set<dof_id_type> dindices;
810 std::set_difference(indices.begin(),
811 indices.end(),
812 unindices.begin(),
813 unindices.end(),
814 std::inserter(dindices, dindices.end()));
815 PetscInt * darray;
816 LibmeshPetscCallQ(PetscMalloc(sizeof(PetscInt) * dindices.size(), &darray));
817 dof_id_type i = 0;
818 for (const auto & dof : dindices)
819 {
820 darray[i] = dof;
821 ++i;
822 }
823 LibmeshPetscCallQ(ISCreateGeneral(
824 ((PetscObject)dm)->comm, dindices.size(), darray, PETSC_OWN_POINTER, &dmm->_embedding));
825 }
826 else
827 {
828 // if (dmm->allblocks && dmm->allvars && dmm->nosides && dmm->nounsides && dmm->nocontacts &&
829 // dmm->nouncontacts)
830 // DMCreateGlobalVector is defined()
831 Vec v;
832 PetscInt low, high;
833
834 LibmeshPetscCallQ(DMCreateGlobalVector(dm, &v));
835 LibmeshPetscCallQ(VecGetOwnershipRange(v, &low, &high));
837 ISCreateStride(((PetscObject)dm)->comm, (high - low), low, 1, &dmm->_embedding));
838 }
839 }
840 LibmeshPetscCallQ(PetscObjectReference((PetscObject)(dmm->_embedding)));
841 *embedding = dmm->_embedding;
842
843 PetscFunctionReturn(PETSC_SUCCESS);
844}
845
846static PetscErrorCode
848 DM dm, PetscInt * len, char *** namelist, IS ** islist, DM ** dmlist)
849{
850 DM_Moose * dmm = (DM_Moose *)(dm->data);
851
853
854 PetscInt split_size_sum = 0;
855
856 /* Only called after DMSetUp(). */
857 if (!dmm->_splitlocs)
858 PetscFunctionReturn(PETSC_SUCCESS);
859 *len = dmm->_splitlocs->size();
860 if (namelist)
861 LibmeshPetscCallQ(PetscMalloc(*len * sizeof(char *), namelist));
862 if (islist)
863 LibmeshPetscCallQ(PetscMalloc(*len * sizeof(IS), islist));
864 if (dmlist)
865 LibmeshPetscCallQ(PetscMalloc(*len * sizeof(DM), dmlist));
866 for (const auto & dit : *(dmm->_splitlocs))
867 {
868 unsigned int d = dit.second;
869 std::string dname = dit.first;
870 DM_Moose::SplitInfo & dinfo = (*dmm->_splits)[dname];
871 if (!dinfo._dm)
872 {
874 ((PetscObject)dm)->comm, *dmm->_nl, *dmm->_dof_map, *dmm->_system, dname, &dinfo._dm));
876 PetscObjectSetOptionsPrefix((PetscObject)dinfo._dm, ((PetscObject)dm)->prefix));
877 std::string suffix = std::string("fieldsplit_") + dname + "_";
878 LibmeshPetscCallQ(PetscObjectAppendOptionsPrefix((PetscObject)dinfo._dm, suffix.c_str()));
880 }
881 LibmeshPetscCallQ(DMSetFromOptions(dinfo._dm));
882 LibmeshPetscCallQ(DMSetUp(dinfo._dm));
883 if (namelist)
884 LibmeshPetscCallQ(PetscStrallocpy(dname.c_str(), (*namelist) + d));
885 if (islist)
886 {
887 if (!dinfo._rembedding)
888 {
889 IS dembedding, lembedding;
891 if (dmm->_embedding)
892 {
893 // Create a relative embedding into the parent's index space.
894 LibmeshPetscCallQ(ISEmbed(dembedding, dmm->_embedding, PETSC_TRUE, &lembedding));
895 const PetscInt * lindices;
896 PetscInt len, dlen, llen, *rindices, off, i;
897 LibmeshPetscCallQ(ISGetLocalSize(dembedding, &dlen));
898 LibmeshPetscCallQ(ISGetLocalSize(lembedding, &llen));
899 if (llen != dlen)
900 LIBMESH_SETERRQ1(
901 ((PetscObject)dm)->comm, PETSC_ERR_PLIB, "Failed to embed split %u", d);
902 LibmeshPetscCallQ(ISDestroy(&dembedding));
903 // Convert local embedding to global (but still relative) embedding
904 LibmeshPetscCallQ(PetscMalloc(llen * sizeof(PetscInt), &rindices));
905 LibmeshPetscCallQ(ISGetIndices(lembedding, &lindices));
906 LibmeshPetscCallQ(PetscMemcpy(rindices, lindices, llen * sizeof(PetscInt)));
907 LibmeshPetscCallQ(ISDestroy(&lembedding));
908 // We could get the index offset from a corresponding global vector, but subDMs don't yet
909 // have global vectors
910 LibmeshPetscCallQ(ISGetLocalSize(dmm->_embedding, &len));
911
912 MPI_Scan(&len,
913 &off,
914 1,
915#ifdef PETSC_USE_64BIT_INDICES
916 MPI_LONG_LONG_INT,
917#else
918 MPI_INT,
919#endif
920 MPI_SUM,
921 ((PetscObject)dm)->comm);
922
923 off -= len;
924 for (i = 0; i < llen; ++i)
925 rindices[i] += off;
926 LibmeshPetscCallQ(ISCreateGeneral(
927 ((PetscObject)dm)->comm, llen, rindices, PETSC_OWN_POINTER, &(dinfo._rembedding)));
928 }
929 else
930 {
931 dinfo._rembedding = dembedding;
932 }
933 }
934 LibmeshPetscCallQ(PetscObjectReference((PetscObject)(dinfo._rembedding)));
935 (*islist)[d] = dinfo._rembedding;
936 PetscInt is_size;
937 LibmeshPetscCallQ(ISGetLocalSize(dinfo._rembedding, &is_size));
938 split_size_sum += is_size;
939 }
940 if (dmlist)
941 {
942 LibmeshPetscCallQ(PetscObjectReference((PetscObject)dinfo._dm));
943 (*dmlist)[d] = dinfo._dm;
944 }
945 }
946
947 mooseAssert(islist, "What does it even mean if this is NULL?");
948
949 if (dmm->_parent)
950 dmm->_parent->checkChildSize(dm, split_size_sum, *dmm->_name);
951 else
952 checkSize(*dmm->_name, split_size_sum, dmm->_dof_map->n_local_dofs());
953
954 PetscFunctionReturn(PETSC_SUCCESS);
955}
956
957static PetscErrorCode
959 DM dm, PetscInt * len, char *** namelist, IS ** innerislist, IS ** outerislist, DM ** dmlist)
960{
962 /* Use DMCreateFieldDecomposition_Moose() to obtain everything but outerislist, which is currently
963 * LIBMESH_PETSC_NULLPTR. */
964 if (outerislist)
965 *outerislist = LIBMESH_PETSC_NULLPTR; /* FIX: allow mesh-based overlap. */
966 LibmeshPetscCallQ(DMCreateFieldDecomposition_Moose(dm, len, namelist, innerislist, dmlist));
967 PetscFunctionReturn(PETSC_SUCCESS);
968}
969
970static PetscErrorCode
971DMVariableBounds_Moose(DM dm, Vec xl, Vec xu)
972{
973 NonlinearSystemBase * nl = NULL;
974
977
978 PetscVector<Number> XL(xl, nl->comm());
979 PetscVector<Number> XU(xu, nl->comm());
980
981 LibmeshPetscCallQ(VecSet(xl, PETSC_NINFINITY));
982 LibmeshPetscCallQ(VecSet(xu, PETSC_INFINITY));
983 if (nl->nonlinearSolver()->bounds != NULL)
984 nl->nonlinearSolver()->bounds(XL, XU, nl->nonlinearSolver()->system());
985 else if (nl->nonlinearSolver()->bounds_object != NULL)
986 nl->nonlinearSolver()->bounds_object->bounds(XL, XU, nl->nonlinearSolver()->system());
987 else
988 SETERRQ(
989 ((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "No bounds calculation in this Moose object");
990 PetscFunctionReturn(PETSC_SUCCESS);
991}
992
993static PetscErrorCode
995{
996 DM_Moose * dmm = (DM_Moose *)(dm->data);
997
1000 if (!dmm->_nl)
1001 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1002
1003 NumericVector<Number> * nv = (dmm->_system->solution).get();
1004 PetscVector<Number> * pv = dynamic_cast<PetscVector<Number> *>(nv);
1005 Vec v = pv->vec();
1006 /* Unfortunately, currently this does not produce a ghosted vector, so nonlinear subproblem solves
1007 aren't going to be easily available.
1008 Should work fine for getting vectors out for linear subproblem solvers. */
1009 if (dmm->_embedding)
1010 {
1011 PetscInt n;
1012 LibmeshPetscCallQ(VecCreate(((PetscObject)v)->comm, x));
1013 LibmeshPetscCallQ(ISGetLocalSize(dmm->_embedding, &n));
1014 LibmeshPetscCallQ(VecSetSizes(*x, n, PETSC_DETERMINE));
1015 LibmeshPetscCallQ(VecSetType(*x, ((PetscObject)v)->type_name));
1016 LibmeshPetscCallQ(VecSetFromOptions(*x));
1017 LibmeshPetscCallQ(VecSetUp(*x));
1018 }
1019 else
1020 LibmeshPetscCallQ(VecDuplicate(v, x));
1021
1022#if PETSC_RELEASE_LESS_THAN(3, 13, 0)
1023 LibmeshPetscCallQ(PetscObjectCompose((PetscObject)*x, "DM", (PetscObject)dm));
1024#else
1025 LibmeshPetscCallQ(VecSetDM(*x, dm));
1026#endif
1027 PetscFunctionReturn(PETSC_SUCCESS);
1028}
1029
1030static PetscErrorCode
1032{
1033 DM_Moose * dmm = (DM_Moose *)(dm->data);
1034 MatType type;
1035
1038 if (!dmm->_nl)
1039 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1040 LibmeshPetscCallQ(DMGetMatType(dm, &type));
1041
1042 /*
1043 The simplest thing for now: compute the sparsity_pattern using dof_map and init the matrix using
1044 that info.
1045 TODO: compute sparsity restricted to this DM's blocks, variables and sides.
1046 Even fancier: compute the sparsity of the coupling of a contact secondary to the contact primary.
1047 In any event, here we are in control of the matrix type and structure.
1048 */
1049 const auto & dof_map = *dmm->_dof_map;
1050 PetscInt M, N, m, n;
1051 MPI_Comm comm;
1052 M = dof_map.n_dofs();
1053 N = M;
1054 m = static_cast<PetscInt>(dof_map.n_local_dofs());
1055 n = m;
1056 LibmeshPetscCallQ(PetscObjectGetComm((PetscObject)dm, &comm));
1057 LibmeshPetscCallQ(MatCreate(comm, A));
1058 LibmeshPetscCallQ(MatSetSizes(*A, m, n, M, N));
1059 LibmeshPetscCallQ(MatSetType(*A, type));
1060 /* TODO: set the prefix for *A and MatSetFromOptions(*A)? Might override the type and other
1061 * settings made here. */
1062 LibmeshPetscCallQ(MatSetUp(*A));
1063 PetscFunctionReturn(PETSC_SUCCESS);
1064}
1065
1066static PetscErrorCode
1067DMView_Moose(DM dm, PetscViewer viewer)
1068{
1069 PetscBool isascii;
1070 const char *name, *prefix;
1071 DM_Moose * dmm = (DM_Moose *)dm->data;
1072
1074 LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1075 if (isascii)
1076 {
1077 LibmeshPetscCallQ(PetscObjectGetName((PetscObject)dm, &name));
1078 LibmeshPetscCallQ(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
1080 PetscViewerASCIIPrintf(viewer, "DM Moose with name %s and prefix %s\n", name, prefix));
1081 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "variables:"));
1082 for (const auto & vit : *(dmm->_var_ids))
1083 {
1084 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "(%s,%u) ", vit.first.c_str(), vit.second));
1085 }
1086 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1087 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "blocks:"));
1088 for (const auto & bit : *(dmm->_block_ids))
1089 {
1090 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "(%s,%d) ", bit.first.c_str(), bit.second));
1091 }
1092 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1093
1094 if (dmm->_side_ids->size())
1095 {
1096 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "sides:"));
1097 for (const auto & sit : *(dmm->_side_ids))
1098 {
1100 PetscViewerASCIIPrintf(viewer, "(%s,%d) ", sit.first.c_str(), sit.second));
1101 }
1102 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1103 }
1104
1105 if (dmm->_unside_ids->size())
1106 {
1107 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "unsides:"));
1108 for (const auto & sit : *(dmm->_unside_ids))
1109 {
1111 PetscViewerASCIIPrintf(viewer, "(%s,%d) ", sit.first.c_str(), sit.second));
1112 }
1113 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1114 }
1115
1116 if (dmm->_contact_names->size())
1117 {
1118 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "contacts:"));
1119 for (const auto & cit : *(dmm->_contact_names))
1120 {
1121 LibmeshPetscCallQ(PetscViewerASCIIPrintf(
1122 viewer, "(%s,%s,", cit.second.first.c_str(), cit.second.second.c_str()));
1123 if ((*dmm->_contact_displaced)[cit.second])
1124 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "displaced) "));
1125 else
1126 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "undisplaced) "));
1127 }
1128 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1129 }
1130
1131 if (dmm->_uncontact_names->size())
1132 {
1133 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "_uncontacts:"));
1134 for (const auto & cit : *(dmm->_uncontact_names))
1135 {
1136 LibmeshPetscCallQ(PetscViewerASCIIPrintf(
1137 viewer, "(%s,%s,", cit.second.first.c_str(), cit.second.second.c_str()));
1138 if ((*dmm->_uncontact_displaced)[cit.second])
1139 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "displaced) "));
1140 else
1141 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "undisplaced) "));
1142 }
1143 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1144 }
1145
1146 if (dmm->_splitlocs && dmm->_splitlocs->size())
1147 {
1148 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "Field decomposition:"));
1149 // FIX: decompositions might have different sizes and components on different ranks.
1150 for (const auto & dit : *(dmm->_splitlocs))
1151 {
1152 std::string dname = dit.first;
1153 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, " %s", dname.c_str()));
1154 }
1155 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1156 }
1157 }
1158 else
1159 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Non-ASCII viewers are not supported");
1160
1161 PetscFunctionReturn(PETSC_SUCCESS);
1162}
1163
1164static PetscErrorCode
1165DMMooseGetMeshBlocks_Private(DM dm, std::set<subdomain_id_type> & blocks)
1166{
1167 DM_Moose * dmm = (DM_Moose *)(dm->data);
1168
1171 if (!dmm->_nl)
1172 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1173
1174 const MeshBase & mesh = dmm->_system->get_mesh();
1175 /* The following effectively is a verbatim copy of MeshBase::n_subdomains(). */
1176 // This requires an inspection on every processor
1177 libmesh_parallel_only(mesh.comm());
1178 for (const auto & elem : mesh.active_element_ptr_range())
1179 blocks.insert(elem->subdomain_id());
1180 // Some subdomains may only live on other processors
1181 mesh.comm().set_union(blocks);
1182 PetscFunctionReturn(PETSC_SUCCESS);
1183}
1184
1185static PetscErrorCode
1187{
1188 DM_Moose * dmm = (DM_Moose *)(dm->data);
1189
1192 if (!dmm->_nl)
1193 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1194
1195 /* Set up variables, blocks and sides. */
1196 const auto & dofmap = *dmm->_dof_map;
1197 /* libMesh mesh */
1198 const MeshBase & mesh = dmm->_system->get_mesh();
1199
1200 // Do sides
1201 dmm->_nosides = PETSC_TRUE;
1202 dmm->_side_ids->clear();
1203 dmm->_side_names->clear();
1204 if (dmm->_sides)
1205 {
1206 dmm->_nosides = PETSC_FALSE;
1207 for (const auto & name : *(dmm->_sides))
1208 {
1209 boundary_id_type id = dmm->_nl->mesh().getBoundaryID(name);
1210 dmm->_side_names->insert(std::make_pair(id, name));
1211 dmm->_side_ids->insert(std::make_pair(name, id));
1212 }
1213 delete dmm->_sides;
1214 dmm->_sides = LIBMESH_PETSC_NULLPTR;
1215 }
1216
1217 // Do unsides
1218 dmm->_nounsides = PETSC_TRUE;
1219 dmm->_unside_ids->clear();
1220 dmm->_unside_names->clear();
1221 if (dmm->_unsides)
1222 {
1223 dmm->_nounsides = PETSC_FALSE;
1224 for (const auto & name : *(dmm->_unsides))
1225 {
1226 boundary_id_type id = dmm->_nl->mesh().getBoundaryID(name);
1227 dmm->_unside_names->insert(std::make_pair(id, name));
1228 dmm->_unside_ids->insert(std::make_pair(name, id));
1229 }
1230 delete dmm->_unsides;
1231 dmm->_unsides = LIBMESH_PETSC_NULLPTR;
1232 }
1233
1234 // Do unside by var
1235 dmm->_nounside_by_var = PETSC_TRUE;
1236 dmm->_unside_by_var_set->clear();
1237 if (dmm->_unside_by_var)
1238 {
1239 dmm->_nounside_by_var = PETSC_FALSE;
1240 for (const auto & name : *(dmm->_unside_by_var))
1241 {
1242 const auto colon_pos = name.find(":");
1243 auto unside_name = name.substr(0, colon_pos);
1244 auto var_name = name.substr(colon_pos + 1);
1245 boundary_id_type id = dmm->_nl->mesh().getBoundaryID(unside_name);
1246 bool var_found = false;
1247 for (unsigned int v = 0; v < dofmap.n_variables(); ++v)
1248 {
1249 const auto & vname = dofmap.variable(v).name();
1250 if (vname == var_name)
1251 {
1252 dmm->_unside_by_var_set->insert(std::make_pair(id, v));
1253 var_found = true;
1254 break;
1255 }
1256 }
1257 if (!var_found)
1258 mooseError("No variable named '", var_name, "' found");
1259 }
1260 delete dmm->_unside_by_var;
1261 dmm->_unside_by_var = LIBMESH_PETSC_NULLPTR;
1262 }
1263
1264 dmm->_nocontacts = PETSC_TRUE;
1265
1266 if (dmm->_contacts)
1267 {
1268 dmm->_nocontacts = PETSC_FALSE;
1269 for (const auto & cpair : *(dmm->_contacts))
1270 {
1271 try
1272 {
1273 if ((*dmm->_contact_displaced)[cpair])
1274 dmm->_nl->feProblem().getDisplacedProblem()->geomSearchData().getPenetrationLocator(
1275 cpair.first, cpair.second);
1276 else
1277 dmm->_nl->feProblem().geomSearchData().getPenetrationLocator(cpair.first, cpair.second);
1278 }
1279 catch (...)
1280 {
1281 std::ostringstream err;
1282 err << "Problem retrieving contact for PenetrationLocator with primary " << cpair.first
1283 << " and secondary " << cpair.second;
1284 mooseError(err.str());
1285 }
1286 BoundaryID primary_id = dmm->_nl->mesh().getBoundaryID(cpair.first);
1287 BoundaryID secondary_id = dmm->_nl->mesh().getBoundaryID(cpair.second);
1288 DM_Moose::ContactID cid(primary_id, secondary_id);
1289 dmm->_contact_names->insert(std::make_pair(cid, cpair));
1290 }
1291 }
1292
1293 dmm->_nouncontacts = PETSC_TRUE;
1294 if (dmm->_uncontacts)
1295 {
1296 dmm->_nouncontacts = PETSC_FALSE;
1297 for (const auto & cpair : *(dmm->_uncontacts))
1298 {
1299 try
1300 {
1301 if ((*dmm->_uncontact_displaced)[cpair])
1302 dmm->_nl->feProblem().getDisplacedProblem()->geomSearchData().getPenetrationLocator(
1303 cpair.first, cpair.second);
1304 else
1305 dmm->_nl->feProblem().geomSearchData().getPenetrationLocator(cpair.first, cpair.second);
1306 }
1307 catch (...)
1308 {
1309 std::ostringstream err;
1310 err << "Problem retrieving uncontact for PenetrationLocator with primary " << cpair.first
1311 << " and secondary " << cpair.second;
1312 mooseError(err.str());
1313 }
1314 BoundaryID primary_id = dmm->_nl->mesh().getBoundaryID(cpair.first);
1315 BoundaryID secondary_id = dmm->_nl->mesh().getBoundaryID(cpair.second);
1316 DM_Moose::ContactID cid(primary_id, secondary_id);
1317 dmm->_uncontact_names->insert(std::make_pair(cid, cpair));
1318 }
1319 }
1320
1321 dmm->_var_ids->clear();
1322 dmm->_var_names->clear();
1323 // FIXME: would be nice to invert this nested loop structure so we could iterate over the
1324 // potentially smaller dmm->vars,
1325 // but checking against dofmap.variable would still require a linear search, hence, no win. Would
1326 // be nice to endow dofmap.variable
1327 // with a fast search capability.
1328 for (unsigned int v = 0; v < dofmap.n_variables(); ++v)
1329 {
1330 std::string vname = dofmap.variable(v).name();
1331 if (dmm->_vars && dmm->_vars->size() && dmm->_vars->find(vname) == dmm->_vars->end())
1332 continue;
1333 dmm->_var_ids->insert(std::pair<std::string, unsigned int>(vname, v));
1334 dmm->_var_names->insert(std::pair<unsigned int, std::string>(v, vname));
1335 }
1336 if (dmm->_var_ids->size() == dofmap.n_variables())
1337 dmm->_all_vars = PETSC_TRUE;
1338 else
1339 dmm->_all_vars = PETSC_FALSE;
1340 if (dmm->_vars)
1341 {
1342 delete dmm->_vars;
1343 dmm->_vars = LIBMESH_PETSC_NULLPTR;
1344 }
1345
1346 dmm->_block_ids->clear();
1347 dmm->_block_names->clear();
1348 std::set<subdomain_id_type> blocks;
1350 if (blocks.empty())
1351 SETERRQ(((PetscObject)dm)->comm, PETSC_ERR_PLIB, "No mesh blocks found.");
1352
1353 for (const auto & bid : blocks)
1354 {
1355 std::string bname = mesh.subdomain_name(bid);
1356 if (!bname.length())
1357 {
1358 // Block names are currently implemented for Exodus meshes
1359 // only, so we might have to make up our own block names and
1360 // maintain our own mapping of block ids to names.
1361 std::ostringstream ss;
1362 ss << bid;
1363 bname = ss.str();
1364 }
1365 if (dmm->_nosides && dmm->_nocontacts)
1366 {
1367 // If no sides and no contacts have been specified, by default (null or empty dmm->blocks) all
1368 // blocks are included in the split Thus, skip this block only if it is explicitly excluded
1369 // from a nonempty dmm->blocks.
1370 if (dmm->_blocks && dmm->_blocks->size() &&
1371 (dmm->_blocks->find(bname) ==
1372 dmm->_blocks->end() && // We should allow users to use subdomain IDs
1373 dmm->_blocks->find(std::to_string(bid)) == dmm->_blocks->end()))
1374 continue;
1375 }
1376 else
1377 {
1378 // If sides or contacts have been specified, only the explicitly-specified blocks (those in
1379 // dmm->blocks, if it's non-null) are in the split. Thus, include this block only if it is
1380 // explicitly specified in a nonempty dmm->blocks. Equivalently, skip this block if
1381 // dmm->blocks is dmm->blocks is null or empty or excludes this block.
1382 if (!dmm->_blocks || !dmm->_blocks->size() ||
1383 (dmm->_blocks->find(bname) ==
1384 dmm->_blocks->end() // We should allow users to use subdomain IDs
1385 && dmm->_blocks->find(std::to_string(bid)) == dmm->_blocks->end()))
1386 continue;
1387 }
1388 dmm->_block_ids->insert(std::make_pair(bname, bid));
1389 dmm->_block_names->insert(std::make_pair(bid, bname));
1390 }
1391
1392 if (dmm->_block_ids->size() == blocks.size())
1393 dmm->_all_blocks = PETSC_TRUE;
1394 else
1395 dmm->_all_blocks = PETSC_FALSE;
1396 if (dmm->_blocks)
1397 {
1398 delete dmm->_blocks;
1399 dmm->_blocks = LIBMESH_PETSC_NULLPTR;
1400 }
1401
1402 std::string name = dmm->_system->name();
1403 name += "_vars";
1404 for (const auto & vit : *(dmm->_var_names))
1405 name += "_" + vit.second;
1406
1407 name += "_blocks";
1408
1409 for (const auto & bit : *(dmm->_block_names))
1410 name += "_" + bit.second;
1411
1412 if (dmm->_side_names && dmm->_side_names->size())
1413 {
1414 name += "_sides";
1415 for (const auto & sit : *(dmm->_side_names))
1416 name += "_" + sit.second;
1417 }
1418 if (dmm->_unside_names && dmm->_unside_names->size())
1419 {
1420 name += "_unsides";
1421 for (const auto & sit : *(dmm->_unside_names))
1422 name += "_" + sit.second;
1423 }
1424 if (dmm->_contact_names && dmm->_contact_names->size())
1425 {
1426 name += "_contacts";
1427 for (const auto & cit : *(dmm->_contact_names))
1428 name += "_primary_" + cit.second.first + "_secondary_" + cit.second.second;
1429 }
1430 if (dmm->_uncontact_names && dmm->_uncontact_names->size())
1431 {
1432 name += "_uncontacts";
1433 for (const auto & cit : *(dmm->_uncontact_names))
1434 name += "_primary_" + cit.second.first + "_secondary_" + cit.second.second;
1435 }
1436 LibmeshPetscCallQ(PetscObjectSetName((PetscObject)dm, name.c_str()));
1437 PetscFunctionReturn(PETSC_SUCCESS);
1438}
1439
1440PetscErrorCode
1442{
1443 PetscBool ismoose;
1444 DM_Moose * dmm = (DM_Moose *)(dm->data);
1445
1447 LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)dm, DMMOOSE, &ismoose));
1448 if (!ismoose)
1449 PetscFunctionReturn(PETSC_SUCCESS);
1450 if (!dmm->_nl)
1451 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1452 LibmeshPetscCallQ(ISDestroy(&dmm->_embedding));
1453 for (auto & it : *(dmm->_splits))
1454 {
1455 DM_Moose::SplitInfo & split = it.second;
1456 LibmeshPetscCallQ(ISDestroy(&split._rembedding));
1457 if (split._dm)
1458 LibmeshPetscCallQ(DMMooseReset(split._dm));
1459 }
1460 dm->setupcalled = PETSC_FALSE;
1461 PetscFunctionReturn(PETSC_SUCCESS);
1462}
1463
1464static PetscErrorCode
1466{
1467 DM_Moose * dmm = (DM_Moose *)(dm->data);
1468
1471 if (!dmm->_nl)
1472 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1473 if (dmm->_print_embedding)
1474 {
1475 const char *name, *prefix;
1476 IS embedding;
1477
1478 LibmeshPetscCallQ(PetscObjectGetName((PetscObject)dm, &name));
1479 LibmeshPetscCallQ(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
1480 LibmeshPetscCallQ(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_(((PetscObject)dm)->comm),
1481 "DM Moose with name %s and prefix %s\n",
1482 name,
1483 prefix));
1484 if (dmm->_all_vars && dmm->_all_blocks && dmm->_nosides && dmm->_nounsides &&
1485 dmm->_nocontacts && dmm->_nouncontacts)
1486 LibmeshPetscCallQ(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_(((PetscObject)dm)->comm),
1487 "\thas a trivial embedding\n"));
1488 else
1489 {
1491 LibmeshPetscCallQ(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_(((PetscObject)dm)->comm),
1492 "\thas embedding defined by IS:\n"));
1493 LibmeshPetscCallQ(ISView(embedding, PETSC_VIEWER_STDOUT_(((PetscObject)dm)->comm)));
1494 LibmeshPetscCallQ(ISDestroy(&embedding));
1495 }
1496 }
1497 /*
1498 Do not evaluate bounds for an embedded DM -- the subproblem might not have enough information for
1499 that.
1500 */
1501 if (dmm->_all_vars && dmm->_all_blocks && dmm->_nosides && dmm->_nounsides && dmm->_nocontacts &&
1502 dmm->_nouncontacts)
1503 if (dmm->_nl->nonlinearSolver()->bounds || dmm->_nl->nonlinearSolver()->bounds_object)
1504 LibmeshPetscCallQ(DMSetVariableBounds(dm, DMVariableBounds_Moose));
1505 PetscFunctionReturn(PETSC_SUCCESS);
1506}
1507#if !PETSC_VERSION_LESS_THAN(3, 23, 0)
1508PetscErrorCode
1509DMSetFromOptions_Moose(DM dm, PetscOptionItems /*options*/)
1510#elif !PETSC_VERSION_LESS_THAN(3, 18, 0)
1511PetscErrorCode
1512DMSetFromOptions_Moose(DM dm, PetscOptionItems * /*options*/) // >= 3.18.0
1513#elif !PETSC_VERSION_LESS_THAN(3, 7, 0)
1514PetscErrorCode
1515DMSetFromOptions_Moose(PetscOptionItems * /*options*/, DM dm) // >= 3.7.0
1516#else
1517PetscErrorCode
1518DMSetFromOptions_Moose(PetscOptions * /*options*/, DM dm) // >= 3.6.0
1519#endif
1520{
1521 DM_Moose * dmm = (DM_Moose *)dm->data;
1522
1525 if (!dmm->_nl)
1526 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1527// PETSc changed macro definitions in 3.18; the former correct usage
1528// is now a compiler error and the new usage is now a compiler
1529// warning.
1530#if !PETSC_VERSION_LESS_THAN(3, 18, 0)
1531 PetscOptionsBegin(((PetscObject)dm)->comm, ((PetscObject)dm)->prefix, "DMMoose options", "DM");
1532#else
1534 ((PetscObject)dm)->comm, ((PetscObject)dm)->prefix, "DMMoose options", "DM"));
1535#endif
1536 std::string opt, help;
1537 PetscInt maxvars = dmm->_dof_map->n_variables();
1538 char ** vars;
1539 std::set<std::string> varset;
1540 PetscInt nvars = maxvars;
1541 LibmeshPetscCallQ(PetscMalloc(maxvars * sizeof(char *), &vars));
1542 opt = "-dm_moose_vars";
1543 help = "Variables in DMMoose";
1544 LibmeshPetscCallQ(PetscOptionsStringArray(
1545 opt.c_str(), help.c_str(), "DMMooseSetVars", vars, &nvars, LIBMESH_PETSC_NULLPTR));
1546 for (PetscInt i = 0; i < nvars; ++i)
1547 {
1548 varset.insert(std::string(vars[i]));
1549 LibmeshPetscCallQ(PetscFree(vars[i]));
1550 }
1552 if (varset.size())
1554 //
1555 std::set<subdomain_id_type> meshblocks;
1557 PetscInt maxblocks = meshblocks.size();
1558 char ** blocks;
1559 LibmeshPetscCallQ(PetscMalloc(maxblocks * sizeof(char *), &blocks));
1560 std::set<std::string> blockset;
1561 PetscInt nblocks = maxblocks;
1562 opt = "-dm_moose_blocks";
1563 help = "Blocks in DMMoose";
1564 LibmeshPetscCallQ(PetscOptionsStringArray(
1565 opt.c_str(), help.c_str(), "DMMooseSetBlocks", blocks, &nblocks, LIBMESH_PETSC_NULLPTR));
1566 for (PetscInt i = 0; i < nblocks; ++i)
1567 {
1568 blockset.insert(std::string(blocks[i]));
1569 LibmeshPetscCallQ(PetscFree(blocks[i]));
1570 }
1572 if (blockset.size())
1574 PetscInt maxsides = dmm->_system->get_mesh().get_boundary_info().get_global_boundary_ids().size();
1575 char ** sides;
1576 LibmeshPetscCallQ(PetscMalloc(maxsides * maxvars * sizeof(char *), &sides));
1577 PetscInt nsides = maxsides;
1578 std::set<std::string> sideset;
1579
1580 // Do sides
1581 opt = "-dm_moose_sides";
1582 help = "Sides to include in DMMoose";
1583 LibmeshPetscCallQ(PetscOptionsStringArray(
1584 opt.c_str(), help.c_str(), "DMMooseSetSides", sides, &nsides, LIBMESH_PETSC_NULLPTR));
1585 for (PetscInt i = 0; i < nsides; ++i)
1586 {
1587 sideset.insert(std::string(sides[i]));
1588 LibmeshPetscCallQ(PetscFree(sides[i]));
1589 }
1590 if (sideset.size())
1592
1593 // Do unsides
1594 opt = "-dm_moose_unsides";
1595 help = "Sides to exclude from DMMoose";
1596 nsides = maxsides;
1597 LibmeshPetscCallQ(PetscOptionsStringArray(
1598 opt.c_str(), help.c_str(), "DMMooseSetUnSides", sides, &nsides, LIBMESH_PETSC_NULLPTR));
1599 sideset.clear();
1600 for (PetscInt i = 0; i < nsides; ++i)
1601 {
1602 sideset.insert(std::string(sides[i]));
1603 LibmeshPetscCallQ(PetscFree(sides[i]));
1604 }
1605 if (sideset.size())
1607
1608 // Do unsides by var
1609 opt = "-dm_moose_unside_by_var";
1610 help = "Sides to exclude from DMMoose on a by-var basis";
1612 LibmeshPetscCallQ(PetscOptionsStringArray(
1613 opt.c_str(), help.c_str(), "DMMooseSetUnSideByVar", sides, &nsides, LIBMESH_PETSC_NULLPTR));
1614 sideset.clear();
1615 for (PetscInt i = 0; i < nsides; ++i)
1616 {
1617 sideset.insert(std::string(sides[i]));
1618 LibmeshPetscCallQ(PetscFree(sides[i]));
1619 }
1620 if (sideset.size())
1622
1625 std::shared_ptr<DisplacedProblem> displaced_problem = dmm->_nl->feProblem().getDisplacedProblem();
1627 maxcontacts = PetscMax(
1628 maxcontacts, (PetscInt)displaced_problem->geomSearchData()._penetration_locators.size());
1629
1630 std::vector<DM_Moose::ContactName> contacts;
1631 std::vector<PetscBool> contact_displaced;
1632 PetscInt ncontacts = 0;
1633 opt = "-dm_moose_ncontacts";
1634 help =
1635 "Number of contacts to include in DMMoose. For each <n> < "
1636 "dm_moose_contacts\n\t-dm_moose_contact_<n> is a comma-separated <primary>,<secondary> pair "
1637 "defining the contact surfaces"
1638 "\t-dm_moose_contact_<n>_displaced <bool> determines whether the contact is defined on "
1639 "the displaced mesh or not";
1640 LibmeshPetscCallQ(PetscOptionsInt(opt.c_str(),
1641 help.c_str(),
1642 "DMMooseSetContacts",
1643 ncontacts,
1644 &ncontacts,
1645 LIBMESH_PETSC_NULLPTR));
1646 if (ncontacts > maxcontacts)
1647 LIBMESH_SETERRQ2(((PetscObject)dm)->comm,
1648 PETSC_ERR_ARG_SIZ,
1649 "Number of requested contacts %" LIBMESH_PETSCINT_FMT
1650 " exceeds the maximum number of contacts %" LIBMESH_PETSCINT_FMT,
1651 ncontacts,
1652 maxcontacts);
1653 for (PetscInt i = 0; i < ncontacts; ++i)
1654 {
1655 {
1656 char * primary_secondary[2];
1657 PetscInt sz = 2;
1658 std::ostringstream oopt, ohelp;
1659 oopt << "-dm_moose_contact_" << i;
1660 ohelp << "Primary and secondary for contact " << i;
1661 LibmeshPetscCallQ(PetscOptionsStringArray(oopt.str().c_str(),
1662 ohelp.str().c_str(),
1663 "DMMooseSetContacts",
1664 primary_secondary,
1665 &sz,
1666 LIBMESH_PETSC_NULLPTR));
1667 if (sz != 2)
1668 LIBMESH_SETERRQ2(
1669 ((PetscObject)dm)->comm,
1670 PETSC_ERR_ARG_SIZ,
1671 "Expected 2 sideset IDs (primary & secondary) for contact %" LIBMESH_PETSCINT_FMT
1672 ", got %" LIBMESH_PETSCINT_FMT " instead",
1673 i,
1674 sz);
1675 contacts.push_back(DM_Moose::ContactName(std::string(primary_secondary[0]),
1676 std::string(primary_secondary[1])));
1677 LibmeshPetscCallQ(PetscFree(primary_secondary[0]));
1678 LibmeshPetscCallQ(PetscFree(primary_secondary[1]));
1679 }
1680 {
1681 PetscBool displaced = PETSC_FALSE;
1682 std::ostringstream oopt, ohelp;
1683 oopt << "-dm_moose_contact_" << i << "_displaced";
1684 ohelp << "Whether contact " << i << " is determined using displaced mesh or not";
1685 LibmeshPetscCallQ(PetscOptionsBool(oopt.str().c_str(),
1686 ohelp.str().c_str(),
1687 "DMMooseSetContacts",
1688 PETSC_FALSE,
1689 &displaced,
1690 LIBMESH_PETSC_NULLPTR));
1691 contact_displaced.push_back(displaced);
1692 }
1693 }
1694 if (contacts.size())
1696 {
1697 std::ostringstream oopt, ohelp;
1699 oopt << "-dm_moose_includeAllContactNodes";
1700 ohelp << "Whether to include all nodes on the contact surfaces into the subsolver";
1701 LibmeshPetscCallQ(PetscOptionsBool(oopt.str().c_str(),
1702 ohelp.str().c_str(),
1703 "",
1704 PETSC_FALSE,
1706 LIBMESH_PETSC_NULLPTR));
1708 }
1709 std::vector<DM_Moose::ContactName> uncontacts;
1710 std::vector<PetscBool> uncontact_displaced;
1711 PetscInt nuncontacts = 0;
1712 opt = "-dm_moose_nuncontacts";
1713 help =
1714 "Number of contacts to exclude from DMMoose. For each <n> < "
1715 "dm_moose_contacts\n\t-dm_moose_contact_<n> is a comma-separated <primary>,<secondary> pair "
1716 "defining the contact surfaces"
1717 "\t-dm_moose_contact_<n>_displaced <bool> determines whether the contact is defined on "
1718 "the displaced mesh or not";
1719 LibmeshPetscCallQ(PetscOptionsInt(opt.c_str(),
1720 help.c_str(),
1721 "DMMooseSetUnContacts",
1723 &nuncontacts,
1724 LIBMESH_PETSC_NULLPTR));
1726 LIBMESH_SETERRQ2(((PetscObject)dm)->comm,
1727 PETSC_ERR_ARG_SIZ,
1728 "Number of requested uncontacts %" LIBMESH_PETSCINT_FMT
1729 " exceeds the maximum number of contacts %" LIBMESH_PETSCINT_FMT,
1731 maxcontacts);
1732 for (PetscInt i = 0; i < nuncontacts; ++i)
1733 {
1734 {
1735 char * primary_secondary[2];
1736 PetscInt sz = 2;
1737 std::ostringstream oopt, ohelp;
1738 oopt << "-dm_moose_uncontact_" << i;
1739 ohelp << "Primary and secondary for uncontact " << i;
1740 LibmeshPetscCallQ(PetscOptionsStringArray(oopt.str().c_str(),
1741 ohelp.str().c_str(),
1742 "DMMooseSetUnContacts",
1743 primary_secondary,
1744 &sz,
1745 LIBMESH_PETSC_NULLPTR));
1746 if (sz != 2)
1747 LIBMESH_SETERRQ2(
1748 ((PetscObject)dm)->comm,
1749 PETSC_ERR_ARG_SIZ,
1750 "Expected 2 sideset IDs (primary & secondary) for uncontact %" LIBMESH_PETSCINT_FMT
1751 ", got %" LIBMESH_PETSCINT_FMT " instead",
1752 i,
1753 sz);
1754 uncontacts.push_back(DM_Moose::ContactName(std::string(primary_secondary[0]),
1755 std::string(primary_secondary[1])));
1756 LibmeshPetscCallQ(PetscFree(primary_secondary[0]));
1757 LibmeshPetscCallQ(PetscFree(primary_secondary[1]));
1758 }
1759 {
1760 PetscBool displaced = PETSC_FALSE;
1761 std::ostringstream oopt, ohelp;
1762 oopt << "-dm_moose_uncontact_" << i << "_displaced";
1763 ohelp << "Whether uncontact " << i << " is determined using displaced mesh or not";
1764 LibmeshPetscCallQ(PetscOptionsBool(oopt.str().c_str(),
1765 ohelp.str().c_str(),
1766 "DMMooseSetUnContact",
1767 PETSC_FALSE,
1768 &displaced,
1769 LIBMESH_PETSC_NULLPTR));
1770 uncontact_displaced.push_back(displaced);
1771 }
1772 }
1773 if (uncontacts.size())
1775
1776 PetscInt nsplits = 0;
1777 /* Insert the usage of -dm_moose_fieldsplit_names into this help message, since the following
1778 * if-clause might never fire, if -help is requested. */
1779 const char * fdhelp = "Number of named fieldsplits defined by the DM.\n\
1780 \tNames of fieldsplits are defined by -dm_moose_fieldsplit_names <splitname1> <splitname2> ...\n\
1781 \tEach split can be configured with its own variables, blocks and sides, as any DMMoose";
1782 LibmeshPetscCallQ(PetscOptionsInt(
1783 "-dm_moose_nfieldsplits", fdhelp, "DMMooseSetSplitNames", nsplits, &nsplits, NULL));
1785 {
1786 PetscInt nnsplits = nsplits;
1787 std::vector<std::string> split_names;
1788 char ** splitnames;
1789 LibmeshPetscCallQ(PetscMalloc(nsplits * sizeof(char *), &splitnames));
1790 LibmeshPetscCallQ(PetscOptionsStringArray("-dm_moose_fieldsplit_names",
1791 "Names of fieldsplits defined by the DM",
1792 "DMMooseSetSplitNames",
1793 splitnames,
1794 &nnsplits,
1795 LIBMESH_PETSC_NULLPTR));
1796 if (!nnsplits)
1797 {
1798 for (PetscInt i = 0; i < nsplits; ++i)
1799 {
1800 std::ostringstream s;
1801 s << i;
1802 split_names.push_back(s.str());
1803 }
1804 }
1805 else if (nsplits != nnsplits)
1806 LIBMESH_SETERRQ2(((PetscObject)dm)->comm,
1807 PETSC_ERR_ARG_SIZ,
1808 "Expected %" LIBMESH_PETSCINT_FMT
1809 " fieldsplit names, got %" LIBMESH_PETSCINT_FMT " instead",
1810 nsplits,
1811 nnsplits);
1812 else
1813 {
1814 for (PetscInt i = 0; i < nsplits; ++i)
1815 {
1816 split_names.push_back(std::string(splitnames[i]));
1817 LibmeshPetscCallQ(PetscFree(splitnames[i]));
1818 }
1819 }
1820 LibmeshPetscCallQ(PetscFree(splitnames));
1822 }
1823 LibmeshPetscCallQ(PetscOptionsBool("-dm_moose_print_embedding",
1824 "Print IS embedding DM's dofs",
1825 "DMMoose",
1826 dmm->_print_embedding,
1827 &dmm->_print_embedding,
1828 LIBMESH_PETSC_NULLPTR));
1830 LibmeshPetscCallQ(DMSetUp_Moose_Pre(dm)); /* Need some preliminary set up because, strangely
1831 enough, DMView() is called in DMSetFromOptions(). */
1832 PetscFunctionReturn(PETSC_SUCCESS);
1833}
1834
1835static PetscErrorCode
1837{
1838 DM_Moose * dmm = (DM_Moose *)(dm->data);
1839
1841 delete dmm->_name;
1842 if (dmm->_vars)
1843 delete dmm->_vars;
1844 delete dmm->_var_ids;
1845 delete dmm->_var_names;
1846 if (dmm->_blocks)
1847 delete dmm->_blocks;
1848 delete dmm->_block_ids;
1849 delete dmm->_block_names;
1850 if (dmm->_sides)
1851 delete dmm->_sides;
1852 delete dmm->_side_ids;
1853 delete dmm->_side_names;
1854 if (dmm->_unsides)
1855 delete dmm->_unsides;
1856 delete dmm->_unside_ids;
1857 delete dmm->_unside_names;
1858 if (dmm->_unside_by_var)
1859 delete dmm->_unside_by_var;
1860 delete dmm->_unside_by_var_set;
1861 if (dmm->_contacts)
1862 delete dmm->_contacts;
1863 delete dmm->_contact_names;
1864 delete dmm->_contact_displaced;
1865 if (dmm->_uncontacts)
1866 delete dmm->_uncontacts;
1867 delete dmm->_uncontact_names;
1868 delete dmm->_uncontact_displaced;
1869 if (dmm->_splits)
1870 {
1871 for (auto & sit : *(dmm->_splits))
1872 {
1873 LibmeshPetscCallQ(DMDestroy(&(sit.second._dm)));
1874 LibmeshPetscCallQ(ISDestroy(&(sit.second._rembedding)));
1875 }
1876 delete dmm->_splits;
1877 }
1878 if (dmm->_splitlocs)
1879 delete dmm->_splitlocs;
1880 LibmeshPetscCallQ(ISDestroy(&dmm->_embedding));
1881 LibmeshPetscCallQ(PetscFree(dm->data));
1882 PetscFunctionReturn(PETSC_SUCCESS);
1883}
1884
1885PetscErrorCode
1886DMCreateMoose(MPI_Comm comm,
1888 const libMesh::DofMapBase & dof_map,
1889 const System & system,
1890 const std::string & dm_name,
1891 DM * dm)
1892{
1894 LibmeshPetscCallQ(DMCreate(comm, dm));
1895 LibmeshPetscCallQ(DMSetType(*dm, DMMOOSE));
1900 PetscFunctionReturn(PETSC_SUCCESS);
1901}
1902
1903EXTERN_C_BEGIN
1904PetscErrorCode
1906{
1907 DM_Moose * dmm;
1908
1910 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1911#if PETSC_RELEASE_LESS_THAN(3, 18, 0)
1912 LibmeshPetscCallQ(PetscNewLog(dm, &dmm));
1913#else // PetscNewLog was deprecated
1914 LibmeshPetscCallQ(PetscNew(&dmm));
1915#endif
1916 dm->data = dmm;
1917
1918 dmm->_name = new (std::string);
1919 dmm->_var_ids = new (std::map<std::string, unsigned int>);
1920 dmm->_block_ids = new (std::map<std::string, subdomain_id_type>);
1921 dmm->_var_names = new (std::map<unsigned int, std::string>);
1922 dmm->_block_names = new (std::map<unsigned int, std::string>);
1923 dmm->_side_ids = new (std::map<std::string, BoundaryID>);
1924 dmm->_side_names = new (std::map<BoundaryID, std::string>);
1925 dmm->_unside_ids = new (std::map<std::string, BoundaryID>);
1926 dmm->_unside_names = new (std::map<BoundaryID, std::string>);
1927 dmm->_unside_by_var_set = new (std::set<std::pair<BoundaryID, unsigned int>>);
1928 dmm->_contact_names = new (std::map<DM_Moose::ContactID, DM_Moose::ContactName>);
1929 dmm->_uncontact_names = new (std::map<DM_Moose::ContactID, DM_Moose::ContactName>);
1930 dmm->_contact_displaced = new (std::map<DM_Moose::ContactName, PetscBool>);
1931 dmm->_uncontact_displaced = new (std::map<DM_Moose::ContactName, PetscBool>);
1932
1933 dmm->_splits = new (std::map<std::string, DM_Moose::SplitInfo>);
1934
1935 dmm->_print_embedding = PETSC_FALSE;
1936
1937 dm->ops->createglobalvector = DMCreateGlobalVector_Moose;
1938 dm->ops->createlocalvector = 0; // DMCreateLocalVector_Moose;
1939 dm->ops->getcoloring = 0; // DMGetColoring_Moose;
1940 dm->ops->creatematrix = DMCreateMatrix_Moose;
1941 dm->ops->createinterpolation = 0; // DMCreateInterpolation_Moose;
1942
1943 dm->ops->refine = 0; // DMRefine_Moose;
1944 dm->ops->coarsen = 0; // DMCoarsen_Moose;
1945#if PETSC_RELEASE_LESS_THAN(3, 12, 0)
1946 dm->ops->getinjection = 0; // DMGetInjection_Moose;
1947 dm->ops->getaggregates = 0; // DMGetAggregates_Moose;
1948#else
1949 dm->ops->createinjection = 0;
1950#endif
1951
1952 dm->ops->createfielddecomposition = DMCreateFieldDecomposition_Moose;
1953 dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_Moose;
1954
1955 dm->ops->destroy = DMDestroy_Moose;
1956 dm->ops->view = DMView_Moose;
1957 dm->ops->setfromoptions = DMSetFromOptions_Moose;
1958 dm->ops->setup = DMSetUp_Moose;
1959 PetscFunctionReturn(PETSC_SUCCESS);
1960}
1962
1963PetscErrorCode
1965{
1966 static PetscBool DMMooseRegisterAllCalled = PETSC_FALSE;
1967
1969 if (!DMMooseRegisterAllCalled)
1970 {
1971 LibmeshPetscCallQ(DMRegister(DMMOOSE, DMCreate_Moose));
1972 DMMooseRegisterAllCalled = PETSC_TRUE;
1973 }
1974 PetscFunctionReturn(PETSC_SUCCESS);
1975}
boundary_id_type BoundaryID
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
PetscInt maxsides
const char * fdhelp
PetscErrorCode PetscOptionItems *PetscErrorCode DM dm
PetscErrorCode DMMooseSetSystem(DM dm, const System &system)
static PetscErrorCode DMCreateGlobalVector_Moose(DM dm, Vec *x)
std::set< std::string > blockset
PetscErrorCode DMMooseSetParentDM(DM dm, DM_Moose *parent)
PetscErrorCode DMMooseGetBlocks(DM dm, std::vector< std::string > &block_names)
void checkSize(const std::string &split_name, const I1 split_size, const I2 size_expected_by_parent)
PetscOptionsBegin(((PetscObject) dm) ->comm,((PetscObject) dm) ->prefix, "DMMoose options", "DM")
std::shared_ptr< DisplacedProblem > displaced_problem
PetscBool is_include_all_nodes
static PetscErrorCode DMCreateDomainDecomposition_Moose(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
std::vector< PetscBool > uncontact_displaced
static PetscErrorCode DMView_Moose(DM dm, PetscViewer viewer)
static PetscErrorCode DMVariableBounds_Moose(DM dm, Vec xl, Vec xu)
PetscInt nsides
LibmeshPetscCallQ(DMMooseValidityCheck(dm))
PetscInt maxvars
static PetscErrorCode DMMooseGetEmbedding_Private(DM dm, IS *embedding)
PetscErrorCode DMMooseSetUnContacts(DM dm, const std::vector< std::pair< std::string, std::string > > &uncontacts, const std::vector< PetscBool > &displaced)
std::vector< DM_Moose::ContactName > uncontacts
static PetscErrorCode DMSetUp_Moose_Pre(DM dm)
PetscInt nvars
PetscOptionsEnd()
PetscInt maxblocks
PetscFunctionReturn(PETSC_SUCCESS)
static PetscErrorCode DMDestroy_Moose(DM dm)
std::set< std::string > varset
PetscErrorCode DMMooseSetSplitNames(DM dm, const std::vector< std::string > &split_names)
PetscErrorCode DMMooseGetUnSides(DM dm, std::vector< std::string > &side_names)
PetscErrorCode DMMooseSetDofMap(DM dm, const libMesh::DofMapBase &dof_map)
PetscErrorCode DMMooseSetBlocks(DM dm, const std::set< std::string > &blocks)
contact_displaced
PetscErrorCode DMCreateMoose(MPI_Comm comm, NonlinearSystemBase &nl, const libMesh::DofMapBase &dof_map, const System &system, const std::string &dm_name, DM *dm)
PetscErrorCode DMMooseReset(DM dm)
static PetscErrorCode DMSetUp_Moose(DM dm)
std::string help
std::set< subdomain_id_type > meshblocks
std::set< std::string > sideset
PetscFunctionBegin
PetscErrorCode DMMooseSetUnSides(DM dm, const std::set< std::string > &unsides)
static PetscErrorCode DMCreateMatrix_Moose(DM dm, Mat *A)
std::string opt
PetscErrorCode DMMooseGetSplitNames(DM dm, std::vector< std::string > &split_names)
PetscErrorCode DMMooseSetSides(DM dm, const std::set< std::string > &sides)
PETSC_ERR_ARG_WRONGSTATE
PetscInt maxcontacts
PetscErrorCode DMMooseGetVariables(DM dm, std::vector< std::string > &var_names)
PetscErrorCode DMMooseSetName(DM dm, const std::string &dm_name)
PetscInt nsplits
static PetscErrorCode DMCreateFieldDecomposition_Moose(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
PetscErrorCode DMMooseSetContacts(DM dm, const std::vector< std::pair< std::string, std::string > > &contacts, const std::vector< PetscBool > &displaced)
PetscErrorCode DMMooseGetSides(DM dm, std::vector< std::string > &side_names)
static PetscErrorCode DMMooseGetMeshBlocks_Private(DM dm, std::set< subdomain_id_type > &blocks)
PetscErrorCode DMSetFromOptions_Moose(DM dm, PetscOptionItems) PetscErrorCode DMSetFromOptions_Moose(DM dm
char ** vars
PetscErrorCode DMMooseGetUnContacts(DM dm, std::vector< std::pair< std::string, std::string > > &uncontact_names, std::vector< PetscBool > &displaced)
PetscErrorCode DMMooseValidityCheck(DM dm)
EXTERN_C_END PetscErrorCode DMMooseRegisterAll()
char ** sides
PetscInt nblocks
PetscErrorCode DMMooseSetVariables(DM dm, const std::set< std::string > &vars)
PetscErrorCode DMMooseGetNonlinearSystem(DM dm, NonlinearSystemBase *&nl)
EXTERN_C_BEGIN PetscErrorCode DMCreate_Moose(DM dm)
contacts
char ** blocks
PetscErrorCode DMMooseGetContacts(DM dm, std::vector< std::pair< std::string, std::string > > &contact_names, std::vector< PetscBool > &displaced)
PetscErrorCode DMMooseSetNonlinearSystem(DM dm, NonlinearSystemBase &nl)
PetscInt nuncontacts
PetscErrorCode DMMooseSetUnSideByVar(DM dm, const std::set< std::string > &unside_by_var)
virtual std::shared_ptr< const DisplacedProblem > getDisplacedProblem() const
virtual GeometricSearchData & geomSearchData() override
virtual MooseMesh & mesh() override
std::map< std::pair< BoundaryID, BoundaryID >, PenetrationLocator * > _penetration_locators
PenetrationLocator & getPenetrationLocator(const BoundaryName &primary, const BoundaryName &secondary, libMesh::Order order=libMesh::FIRST)
const std::unordered_map< dof_id_type, std::vector< dof_id_type > > & nodeToElemMap()
If not already created, creates a map from every node to all elements to which they are connected.
Definition MooseMesh.C:1241
BoundaryID getBoundaryID(const BoundaryName &boundary_name) const
Get the associated BoundaryID for the boundary name.
Definition MooseMesh.C:1639
libMesh::StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode * > * getBoundaryNodeRange()
Definition MooseMesh.C:1290
libMesh::StoredRange< MooseMesh::const_bnd_elem_iterator, const BndElement * > * getBoundaryElementRange()
Definition MooseMesh.C:1303
Nonlinear system to be solved.
virtual libMesh::NonlinearSolver< Number > * nonlinearSolver()=0
Data structure used to hold penetration information.
const Elem * _side
bool isCaptured() const
std::map< dof_id_type, PenetrationInfo * > & _penetration_info
Data structure of nodes and their associated penetration information.
MooseVariableFieldBase & getVariable(THREAD_ID tid, const std::string &var_name) const
Gets a reference to a variable of with specified name.
Definition SystemBase.C:92
virtual MooseVariableScalar & getScalarVariable(THREAD_ID tid, const std::string &var_name) const
Gets a reference to a scalar variable with specified number.
Definition SystemBase.C:147
virtual bool hasVariable(const std::string &var_name) const
Query a system for a variable.
Definition SystemBase.C:851
FEProblemBase & feProblem()
Definition SystemBase.h:104
MooseMesh & mesh()
Definition SystemBase.h:100
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
virtual void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di, const unsigned int vn, int p_level=-12345) const=0
virtual unsigned int n_variables() const=0
dof_id_type n_local_dofs() const
const Parallel::Communicator & comm() const
MeshBase & mesh
bool _nocontacts
const libMesh::DofMapBase * _dof_map
std::string * _name
The name of this DM.
bool _nounside_by_var
std::set< ContactName > * _contacts
std::multimap< std::string, unsigned int > * _splitlocs
std::set< std::string > * _sides
std::map< BoundaryID, std::string > * _side_names
std::map< std::string, BoundaryID > * _side_ids
std::map< std::string, BoundaryID > * _unside_ids
bool _nounsides
std::map< unsigned int, std::string > * _var_names
std::set< std::string > * _unsides
bool _nouncontacts
std::map< BoundaryID, std::string > * _unside_names
bool _nosides
PetscBool _print_embedding
std::map< ContactID, ContactName > * _uncontact_names
DM_Moose * _parent
bool _include_all_contact_nodes
std::set< std::pair< BoundaryID, unsigned int > > * _unside_by_var_set
std::map< std::string, SplitInfo > * _splits
NonlinearSystemBase * _nl
void checkChildSize(DM child, PetscInt child_size, const std::string &child_name)
Check whether the size of the child matches the size we expect.
std::set< std::string > * _blocks
std::set< ContactName > * _uncontacts
std::pair< BoundaryID, BoundaryID > ContactID
std::map< std::string, subdomain_id_type > * _block_ids
bool _all_vars
std::map< unsigned int, std::string > * _block_names
std::set< std::string > * _vars
std::pair< std::string, std::string > ContactName
bool _all_blocks
std::set< std::string > * _unside_by_var
std::map< ContactName, PetscBool > * _uncontact_displaced
std::map< std::string, unsigned int > * _var_ids
std::map< ContactName, PetscBool > * _contact_displaced
std::map< ContactID, ContactName > * _contact_names
const System * _system