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
971DMMooseFunction(DM dm, Vec x, Vec r)
972{
974 libmesh_assert(x);
975 libmesh_assert(r);
976
977 NonlinearSystemBase * nl = NULL;
979 PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(nl->system().solution.get());
980 PetscVector<Number> X_global(x, nl->comm()), R(r, nl->comm());
981
982 // Use the system's update() to get a good local version of the
983 // parallel solution. system.update() does change the residual vector,
984 // so there's no reason to swap PETSc's residual into the system for
985 // this step.
986 X_global.swap(X_sys);
987 nl->system().update();
988 X_global.swap(X_sys);
989
990 // Enforce constraints (if any) exactly on the
991 // current_local_solution. This is the solution vector that is
992 // actually used in the computation of the residual below, and is
993 // not locked by debug-enabled PETSc the way that "x" is.
995 nl->system().current_local_solution.get());
996
997 // Zero the residual vector before assembling
998 R.zero();
999
1000 // if the user has provided both function pointers and objects only the pointer
1001 // will be used, so catch that as an error
1002 if (nl->nonlinearSolver()->residual && nl->nonlinearSolver()->residual_object)
1003 {
1004 std::ostringstream err;
1005 err << "ERROR: cannot specifiy both a function and object to compute the Residual!"
1006 << std::endl;
1007 mooseError(err.str());
1008 }
1009 if (nl->nonlinearSolver()->matvec && nl->nonlinearSolver()->residual_and_jacobian_object)
1010 {
1011 std::ostringstream err;
1012 err << "ERROR: cannot specifiy both a function and object to compute the combined Residual & "
1013 "Jacobian!"
1014 << std::endl;
1015 mooseError(err.str());
1016 }
1017 if (nl->nonlinearSolver()->residual != NULL)
1018 nl->nonlinearSolver()->residual(
1019 *(nl->system().current_local_solution.get()), R, nl->nonlinearSolver()->system());
1020 else if (nl->nonlinearSolver()->residual_object != NULL)
1021 nl->nonlinearSolver()->residual_object->residual(
1022 *(nl->system().current_local_solution.get()), R, nl->nonlinearSolver()->system());
1023 else if (nl->nonlinearSolver()->matvec != NULL)
1024 nl->nonlinearSolver()->matvec(
1025 *(nl->system().current_local_solution.get()), &R, NULL, nl->nonlinearSolver()->system());
1026 else if (nl->nonlinearSolver()->residual_and_jacobian_object != NULL)
1027 nl->nonlinearSolver()->residual_and_jacobian_object->residual_and_jacobian(
1028 *(nl->system().current_local_solution.get()), &R, NULL, nl->nonlinearSolver()->system());
1029 else
1030 {
1031 std::ostringstream err;
1032 err << "No suitable residual computation routine found";
1033 mooseError(err.str());
1034 }
1035 R.close();
1036 PetscFunctionReturn(PETSC_SUCCESS);
1037}
1038
1039static PetscErrorCode
1040SNESFunction_DMMoose(SNES, Vec x, Vec r, void * ctx)
1041{
1042 DM dm = (DM)ctx;
1043
1046 PetscFunctionReturn(PETSC_SUCCESS);
1047}
1048
1049static PetscErrorCode
1050DMMooseJacobian(DM dm, Vec x, Mat jac, Mat pc)
1051{
1052 NonlinearSystemBase * nl = NULL;
1053
1056
1057 PetscMatrix<Number> the_pc(pc, nl->comm());
1058 PetscMatrix<Number> Jac(jac, nl->comm());
1059 PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(nl->system().solution.get());
1060 PetscVector<Number> X_global(x, nl->comm());
1061
1062 // Set the dof maps
1063 the_pc.attach_dof_map(nl->system().get_dof_map());
1064 Jac.attach_dof_map(nl->system().get_dof_map());
1065
1066 // Use the system's update() to get a good local version of the
1067 // parallel solution. system.update() does change the Jacobian, so
1068 // there's no reason to swap PETSc's Jacobian into the system for
1069 // this step.
1070 X_global.swap(X_sys);
1071 nl->system().update();
1072 X_global.swap(X_sys);
1073
1074 // Enforce constraints (if any) exactly on the
1075 // current_local_solution. This is the solution vector that is
1076 // actually used in the computation of the Jacobian below, and is
1077 // not locked by debug-enabled PETSc the way that "x" is.
1079 nl->system().current_local_solution.get());
1080
1081 // Zero out the preconditioner before computing the Jacobian.
1082 the_pc.zero();
1083
1084 // if the user has provided both function pointers and objects only the pointer
1085 // will be used, so catch that as an error
1086 if (nl->nonlinearSolver()->jacobian && nl->nonlinearSolver()->jacobian_object)
1087 {
1088 std::ostringstream err;
1089 err << "ERROR: cannot specifiy both a function and object to compute the Jacobian!"
1090 << std::endl;
1091 mooseError(err.str());
1092 }
1093 if (nl->nonlinearSolver()->matvec && nl->nonlinearSolver()->residual_and_jacobian_object)
1094 {
1095 std::ostringstream err;
1096 err << "ERROR: cannot specifiy both a function and object to compute the combined Residual & "
1097 "Jacobian!"
1098 << std::endl;
1099 mooseError(err.str());
1100 }
1101 if (nl->nonlinearSolver()->jacobian != NULL)
1102 nl->nonlinearSolver()->jacobian(
1103 *(nl->system().current_local_solution.get()), the_pc, nl->nonlinearSolver()->system());
1104 else if (nl->nonlinearSolver()->jacobian_object != NULL)
1105 nl->nonlinearSolver()->jacobian_object->jacobian(
1106 *(nl->system().current_local_solution.get()), the_pc, nl->nonlinearSolver()->system());
1107 else if (nl->nonlinearSolver()->matvec != NULL)
1108 nl->nonlinearSolver()->matvec(*(nl->system().current_local_solution.get()),
1109 NULL,
1110 &the_pc,
1111 nl->nonlinearSolver()->system());
1112 else if (nl->nonlinearSolver()->residual_and_jacobian_object != NULL)
1113 nl->nonlinearSolver()->residual_and_jacobian_object->residual_and_jacobian(
1114 *(nl->system().current_local_solution.get()),
1115 NULL,
1116 &the_pc,
1117 nl->nonlinearSolver()->system());
1118 else
1119 {
1120 std::ostringstream err;
1121 err << "No suitable Jacobian routine or object";
1122 mooseError(err.str());
1123 }
1124 the_pc.close();
1125 Jac.close();
1126 PetscFunctionReturn(PETSC_SUCCESS);
1127}
1128
1129static PetscErrorCode
1130SNESJacobian_DMMoose(SNES, Vec x, Mat jac, Mat pc, void * ctx)
1131{
1132 DM dm = (DM)ctx;
1133
1135 LibmeshPetscCallQ(DMMooseJacobian(dm, x, jac, pc));
1136 PetscFunctionReturn(PETSC_SUCCESS);
1137}
1138
1139static PetscErrorCode
1140DMVariableBounds_Moose(DM dm, Vec xl, Vec xu)
1141{
1142 NonlinearSystemBase * nl = NULL;
1143
1146
1147 PetscVector<Number> XL(xl, nl->comm());
1148 PetscVector<Number> XU(xu, nl->comm());
1149
1150 LibmeshPetscCallQ(VecSet(xl, PETSC_NINFINITY));
1151 LibmeshPetscCallQ(VecSet(xu, PETSC_INFINITY));
1152 if (nl->nonlinearSolver()->bounds != NULL)
1153 nl->nonlinearSolver()->bounds(XL, XU, nl->nonlinearSolver()->system());
1154 else if (nl->nonlinearSolver()->bounds_object != NULL)
1155 nl->nonlinearSolver()->bounds_object->bounds(XL, XU, nl->nonlinearSolver()->system());
1156 else
1157 SETERRQ(
1158 ((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "No bounds calculation in this Moose object");
1159 PetscFunctionReturn(PETSC_SUCCESS);
1160}
1161
1162static PetscErrorCode
1164{
1165 DM_Moose * dmm = (DM_Moose *)(dm->data);
1166
1169 if (!dmm->_nl)
1170 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1171
1172 NumericVector<Number> * nv = (dmm->_system->solution).get();
1173 PetscVector<Number> * pv = dynamic_cast<PetscVector<Number> *>(nv);
1174 Vec v = pv->vec();
1175 /* Unfortunately, currently this does not produce a ghosted vector, so nonlinear subproblem solves
1176 aren't going to be easily available.
1177 Should work fine for getting vectors out for linear subproblem solvers. */
1178 if (dmm->_embedding)
1179 {
1180 PetscInt n;
1181 LibmeshPetscCallQ(VecCreate(((PetscObject)v)->comm, x));
1182 LibmeshPetscCallQ(ISGetLocalSize(dmm->_embedding, &n));
1183 LibmeshPetscCallQ(VecSetSizes(*x, n, PETSC_DETERMINE));
1184 LibmeshPetscCallQ(VecSetType(*x, ((PetscObject)v)->type_name));
1185 LibmeshPetscCallQ(VecSetFromOptions(*x));
1186 LibmeshPetscCallQ(VecSetUp(*x));
1187 }
1188 else
1189 LibmeshPetscCallQ(VecDuplicate(v, x));
1190
1191#if PETSC_RELEASE_LESS_THAN(3, 13, 0)
1192 LibmeshPetscCallQ(PetscObjectCompose((PetscObject)*x, "DM", (PetscObject)dm));
1193#else
1194 LibmeshPetscCallQ(VecSetDM(*x, dm));
1195#endif
1196 PetscFunctionReturn(PETSC_SUCCESS);
1197}
1198
1199static PetscErrorCode
1201{
1202 DM_Moose * dmm = (DM_Moose *)(dm->data);
1203 MatType type;
1204
1207 if (!dmm->_nl)
1208 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1209 LibmeshPetscCallQ(DMGetMatType(dm, &type));
1210
1211 /*
1212 The simplest thing for now: compute the sparsity_pattern using dof_map and init the matrix using
1213 that info.
1214 TODO: compute sparsity restricted to this DM's blocks, variables and sides.
1215 Even fancier: compute the sparsity of the coupling of a contact secondary to the contact primary.
1216 In any event, here we are in control of the matrix type and structure.
1217 */
1218 const auto & dof_map = *dmm->_dof_map;
1219 PetscInt M, N, m, n;
1220 MPI_Comm comm;
1221 M = dof_map.n_dofs();
1222 N = M;
1223 m = static_cast<PetscInt>(dof_map.n_local_dofs());
1224 n = m;
1225 LibmeshPetscCallQ(PetscObjectGetComm((PetscObject)dm, &comm));
1226 LibmeshPetscCallQ(MatCreate(comm, A));
1227 LibmeshPetscCallQ(MatSetSizes(*A, m, n, M, N));
1228 LibmeshPetscCallQ(MatSetType(*A, type));
1229 /* TODO: set the prefix for *A and MatSetFromOptions(*A)? Might override the type and other
1230 * settings made here. */
1231 LibmeshPetscCallQ(MatSetUp(*A));
1232 PetscFunctionReturn(PETSC_SUCCESS);
1233}
1234
1235static PetscErrorCode
1236DMView_Moose(DM dm, PetscViewer viewer)
1237{
1238 PetscBool isascii;
1239 const char *name, *prefix;
1240 DM_Moose * dmm = (DM_Moose *)dm->data;
1241
1243 LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1244 if (isascii)
1245 {
1246 LibmeshPetscCallQ(PetscObjectGetName((PetscObject)dm, &name));
1247 LibmeshPetscCallQ(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
1249 PetscViewerASCIIPrintf(viewer, "DM Moose with name %s and prefix %s\n", name, prefix));
1250 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "variables:"));
1251 for (const auto & vit : *(dmm->_var_ids))
1252 {
1253 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "(%s,%u) ", vit.first.c_str(), vit.second));
1254 }
1255 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1256 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "blocks:"));
1257 for (const auto & bit : *(dmm->_block_ids))
1258 {
1259 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "(%s,%d) ", bit.first.c_str(), bit.second));
1260 }
1261 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1262
1263 if (dmm->_side_ids->size())
1264 {
1265 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "sides:"));
1266 for (const auto & sit : *(dmm->_side_ids))
1267 {
1269 PetscViewerASCIIPrintf(viewer, "(%s,%d) ", sit.first.c_str(), sit.second));
1270 }
1271 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1272 }
1273
1274 if (dmm->_unside_ids->size())
1275 {
1276 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "unsides:"));
1277 for (const auto & sit : *(dmm->_unside_ids))
1278 {
1280 PetscViewerASCIIPrintf(viewer, "(%s,%d) ", sit.first.c_str(), sit.second));
1281 }
1282 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1283 }
1284
1285 if (dmm->_contact_names->size())
1286 {
1287 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "contacts:"));
1288 for (const auto & cit : *(dmm->_contact_names))
1289 {
1290 LibmeshPetscCallQ(PetscViewerASCIIPrintf(
1291 viewer, "(%s,%s,", cit.second.first.c_str(), cit.second.second.c_str()));
1292 if ((*dmm->_contact_displaced)[cit.second])
1293 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "displaced) "));
1294 else
1295 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "undisplaced) "));
1296 }
1297 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1298 }
1299
1300 if (dmm->_uncontact_names->size())
1301 {
1302 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "_uncontacts:"));
1303 for (const auto & cit : *(dmm->_uncontact_names))
1304 {
1305 LibmeshPetscCallQ(PetscViewerASCIIPrintf(
1306 viewer, "(%s,%s,", cit.second.first.c_str(), cit.second.second.c_str()));
1307 if ((*dmm->_uncontact_displaced)[cit.second])
1308 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "displaced) "));
1309 else
1310 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "undisplaced) "));
1311 }
1312 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1313 }
1314
1315 if (dmm->_splitlocs && dmm->_splitlocs->size())
1316 {
1317 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "Field decomposition:"));
1318 // FIX: decompositions might have different sizes and components on different ranks.
1319 for (const auto & dit : *(dmm->_splitlocs))
1320 {
1321 std::string dname = dit.first;
1322 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, " %s", dname.c_str()));
1323 }
1324 LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
1325 }
1326 }
1327 else
1328 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Non-ASCII viewers are not supported");
1329
1330 PetscFunctionReturn(PETSC_SUCCESS);
1331}
1332
1333static PetscErrorCode
1334DMMooseGetMeshBlocks_Private(DM dm, std::set<subdomain_id_type> & blocks)
1335{
1336 DM_Moose * dmm = (DM_Moose *)(dm->data);
1337
1340 if (!dmm->_nl)
1341 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1342
1343 const MeshBase & mesh = dmm->_system->get_mesh();
1344 /* The following effectively is a verbatim copy of MeshBase::n_subdomains(). */
1345 // This requires an inspection on every processor
1346 libmesh_parallel_only(mesh.comm());
1347 for (const auto & elem : mesh.active_element_ptr_range())
1348 blocks.insert(elem->subdomain_id());
1349 // Some subdomains may only live on other processors
1350 mesh.comm().set_union(blocks);
1351 PetscFunctionReturn(PETSC_SUCCESS);
1352}
1353
1354static PetscErrorCode
1356{
1357 DM_Moose * dmm = (DM_Moose *)(dm->data);
1358
1361 if (!dmm->_nl)
1362 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1363
1364 /* Set up variables, blocks and sides. */
1365 const auto & dofmap = *dmm->_dof_map;
1366 /* libMesh mesh */
1367 const MeshBase & mesh = dmm->_system->get_mesh();
1368
1369 // Do sides
1370 dmm->_nosides = PETSC_TRUE;
1371 dmm->_side_ids->clear();
1372 dmm->_side_names->clear();
1373 if (dmm->_sides)
1374 {
1375 dmm->_nosides = PETSC_FALSE;
1376 for (const auto & name : *(dmm->_sides))
1377 {
1378 boundary_id_type id = dmm->_nl->mesh().getBoundaryID(name);
1379 dmm->_side_names->insert(std::make_pair(id, name));
1380 dmm->_side_ids->insert(std::make_pair(name, id));
1381 }
1382 delete dmm->_sides;
1383 dmm->_sides = LIBMESH_PETSC_NULLPTR;
1384 }
1385
1386 // Do unsides
1387 dmm->_nounsides = PETSC_TRUE;
1388 dmm->_unside_ids->clear();
1389 dmm->_unside_names->clear();
1390 if (dmm->_unsides)
1391 {
1392 dmm->_nounsides = PETSC_FALSE;
1393 for (const auto & name : *(dmm->_unsides))
1394 {
1395 boundary_id_type id = dmm->_nl->mesh().getBoundaryID(name);
1396 dmm->_unside_names->insert(std::make_pair(id, name));
1397 dmm->_unside_ids->insert(std::make_pair(name, id));
1398 }
1399 delete dmm->_unsides;
1400 dmm->_unsides = LIBMESH_PETSC_NULLPTR;
1401 }
1402
1403 // Do unside by var
1404 dmm->_nounside_by_var = PETSC_TRUE;
1405 dmm->_unside_by_var_set->clear();
1406 if (dmm->_unside_by_var)
1407 {
1408 dmm->_nounside_by_var = PETSC_FALSE;
1409 for (const auto & name : *(dmm->_unside_by_var))
1410 {
1411 const auto colon_pos = name.find(":");
1412 auto unside_name = name.substr(0, colon_pos);
1413 auto var_name = name.substr(colon_pos + 1);
1414 boundary_id_type id = dmm->_nl->mesh().getBoundaryID(unside_name);
1415 bool var_found = false;
1416 for (unsigned int v = 0; v < dofmap.n_variables(); ++v)
1417 {
1418 const auto & vname = dofmap.variable(v).name();
1419 if (vname == var_name)
1420 {
1421 dmm->_unside_by_var_set->insert(std::make_pair(id, v));
1422 var_found = true;
1423 break;
1424 }
1425 }
1426 if (!var_found)
1427 mooseError("No variable named '", var_name, "' found");
1428 }
1429 delete dmm->_unside_by_var;
1430 dmm->_unside_by_var = LIBMESH_PETSC_NULLPTR;
1431 }
1432
1433 dmm->_nocontacts = PETSC_TRUE;
1434
1435 if (dmm->_contacts)
1436 {
1437 dmm->_nocontacts = PETSC_FALSE;
1438 for (const auto & cpair : *(dmm->_contacts))
1439 {
1440 try
1441 {
1442 if ((*dmm->_contact_displaced)[cpair])
1443 dmm->_nl->feProblem().getDisplacedProblem()->geomSearchData().getPenetrationLocator(
1444 cpair.first, cpair.second);
1445 else
1446 dmm->_nl->feProblem().geomSearchData().getPenetrationLocator(cpair.first, cpair.second);
1447 }
1448 catch (...)
1449 {
1450 std::ostringstream err;
1451 err << "Problem retrieving contact for PenetrationLocator with primary " << cpair.first
1452 << " and secondary " << cpair.second;
1453 mooseError(err.str());
1454 }
1455 BoundaryID primary_id = dmm->_nl->mesh().getBoundaryID(cpair.first);
1456 BoundaryID secondary_id = dmm->_nl->mesh().getBoundaryID(cpair.second);
1457 DM_Moose::ContactID cid(primary_id, secondary_id);
1458 dmm->_contact_names->insert(std::make_pair(cid, cpair));
1459 }
1460 }
1461
1462 dmm->_nouncontacts = PETSC_TRUE;
1463 if (dmm->_uncontacts)
1464 {
1465 dmm->_nouncontacts = PETSC_FALSE;
1466 for (const auto & cpair : *(dmm->_uncontacts))
1467 {
1468 try
1469 {
1470 if ((*dmm->_uncontact_displaced)[cpair])
1471 dmm->_nl->feProblem().getDisplacedProblem()->geomSearchData().getPenetrationLocator(
1472 cpair.first, cpair.second);
1473 else
1474 dmm->_nl->feProblem().geomSearchData().getPenetrationLocator(cpair.first, cpair.second);
1475 }
1476 catch (...)
1477 {
1478 std::ostringstream err;
1479 err << "Problem retrieving uncontact for PenetrationLocator with primary " << cpair.first
1480 << " and secondary " << cpair.second;
1481 mooseError(err.str());
1482 }
1483 BoundaryID primary_id = dmm->_nl->mesh().getBoundaryID(cpair.first);
1484 BoundaryID secondary_id = dmm->_nl->mesh().getBoundaryID(cpair.second);
1485 DM_Moose::ContactID cid(primary_id, secondary_id);
1486 dmm->_uncontact_names->insert(std::make_pair(cid, cpair));
1487 }
1488 }
1489
1490 dmm->_var_ids->clear();
1491 dmm->_var_names->clear();
1492 // FIXME: would be nice to invert this nested loop structure so we could iterate over the
1493 // potentially smaller dmm->vars,
1494 // but checking against dofmap.variable would still require a linear search, hence, no win. Would
1495 // be nice to endow dofmap.variable
1496 // with a fast search capability.
1497 for (unsigned int v = 0; v < dofmap.n_variables(); ++v)
1498 {
1499 std::string vname = dofmap.variable(v).name();
1500 if (dmm->_vars && dmm->_vars->size() && dmm->_vars->find(vname) == dmm->_vars->end())
1501 continue;
1502 dmm->_var_ids->insert(std::pair<std::string, unsigned int>(vname, v));
1503 dmm->_var_names->insert(std::pair<unsigned int, std::string>(v, vname));
1504 }
1505 if (dmm->_var_ids->size() == dofmap.n_variables())
1506 dmm->_all_vars = PETSC_TRUE;
1507 else
1508 dmm->_all_vars = PETSC_FALSE;
1509 if (dmm->_vars)
1510 {
1511 delete dmm->_vars;
1512 dmm->_vars = LIBMESH_PETSC_NULLPTR;
1513 }
1514
1515 dmm->_block_ids->clear();
1516 dmm->_block_names->clear();
1517 std::set<subdomain_id_type> blocks;
1519 if (blocks.empty())
1520 SETERRQ(((PetscObject)dm)->comm, PETSC_ERR_PLIB, "No mesh blocks found.");
1521
1522 for (const auto & bid : blocks)
1523 {
1524 std::string bname = mesh.subdomain_name(bid);
1525 if (!bname.length())
1526 {
1527 // Block names are currently implemented for Exodus meshes
1528 // only, so we might have to make up our own block names and
1529 // maintain our own mapping of block ids to names.
1530 std::ostringstream ss;
1531 ss << bid;
1532 bname = ss.str();
1533 }
1534 if (dmm->_nosides && dmm->_nocontacts)
1535 {
1536 // If no sides and no contacts have been specified, by default (null or empty dmm->blocks) all
1537 // blocks are included in the split Thus, skip this block only if it is explicitly excluded
1538 // from a nonempty dmm->blocks.
1539 if (dmm->_blocks && dmm->_blocks->size() &&
1540 (dmm->_blocks->find(bname) ==
1541 dmm->_blocks->end() && // We should allow users to use subdomain IDs
1542 dmm->_blocks->find(std::to_string(bid)) == dmm->_blocks->end()))
1543 continue;
1544 }
1545 else
1546 {
1547 // If sides or contacts have been specified, only the explicitly-specified blocks (those in
1548 // dmm->blocks, if it's non-null) are in the split. Thus, include this block only if it is
1549 // explicitly specified in a nonempty dmm->blocks. Equivalently, skip this block if
1550 // dmm->blocks is dmm->blocks is null or empty or excludes this block.
1551 if (!dmm->_blocks || !dmm->_blocks->size() ||
1552 (dmm->_blocks->find(bname) ==
1553 dmm->_blocks->end() // We should allow users to use subdomain IDs
1554 && dmm->_blocks->find(std::to_string(bid)) == dmm->_blocks->end()))
1555 continue;
1556 }
1557 dmm->_block_ids->insert(std::make_pair(bname, bid));
1558 dmm->_block_names->insert(std::make_pair(bid, bname));
1559 }
1560
1561 if (dmm->_block_ids->size() == blocks.size())
1562 dmm->_all_blocks = PETSC_TRUE;
1563 else
1564 dmm->_all_blocks = PETSC_FALSE;
1565 if (dmm->_blocks)
1566 {
1567 delete dmm->_blocks;
1568 dmm->_blocks = LIBMESH_PETSC_NULLPTR;
1569 }
1570
1571 std::string name = dmm->_system->name();
1572 name += "_vars";
1573 for (const auto & vit : *(dmm->_var_names))
1574 name += "_" + vit.second;
1575
1576 name += "_blocks";
1577
1578 for (const auto & bit : *(dmm->_block_names))
1579 name += "_" + bit.second;
1580
1581 if (dmm->_side_names && dmm->_side_names->size())
1582 {
1583 name += "_sides";
1584 for (const auto & sit : *(dmm->_side_names))
1585 name += "_" + sit.second;
1586 }
1587 if (dmm->_unside_names && dmm->_unside_names->size())
1588 {
1589 name += "_unsides";
1590 for (const auto & sit : *(dmm->_unside_names))
1591 name += "_" + sit.second;
1592 }
1593 if (dmm->_contact_names && dmm->_contact_names->size())
1594 {
1595 name += "_contacts";
1596 for (const auto & cit : *(dmm->_contact_names))
1597 name += "_primary_" + cit.second.first + "_secondary_" + cit.second.second;
1598 }
1599 if (dmm->_uncontact_names && dmm->_uncontact_names->size())
1600 {
1601 name += "_uncontacts";
1602 for (const auto & cit : *(dmm->_uncontact_names))
1603 name += "_primary_" + cit.second.first + "_secondary_" + cit.second.second;
1604 }
1605 LibmeshPetscCallQ(PetscObjectSetName((PetscObject)dm, name.c_str()));
1606 PetscFunctionReturn(PETSC_SUCCESS);
1607}
1608
1609PetscErrorCode
1611{
1612 PetscBool ismoose;
1613 DM_Moose * dmm = (DM_Moose *)(dm->data);
1614
1616 LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)dm, DMMOOSE, &ismoose));
1617 if (!ismoose)
1618 PetscFunctionReturn(PETSC_SUCCESS);
1619 if (!dmm->_nl)
1620 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1621 LibmeshPetscCallQ(ISDestroy(&dmm->_embedding));
1622 for (auto & it : *(dmm->_splits))
1623 {
1624 DM_Moose::SplitInfo & split = it.second;
1625 LibmeshPetscCallQ(ISDestroy(&split._rembedding));
1626 if (split._dm)
1627 LibmeshPetscCallQ(DMMooseReset(split._dm));
1628 }
1629 dm->setupcalled = PETSC_FALSE;
1630 PetscFunctionReturn(PETSC_SUCCESS);
1631}
1632
1633static PetscErrorCode
1635{
1636 DM_Moose * dmm = (DM_Moose *)(dm->data);
1637
1640 if (!dmm->_nl)
1641 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1642 if (dmm->_print_embedding)
1643 {
1644 const char *name, *prefix;
1645 IS embedding;
1646
1647 LibmeshPetscCallQ(PetscObjectGetName((PetscObject)dm, &name));
1648 LibmeshPetscCallQ(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
1649 LibmeshPetscCallQ(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_(((PetscObject)dm)->comm),
1650 "DM Moose with name %s and prefix %s\n",
1651 name,
1652 prefix));
1653 if (dmm->_all_vars && dmm->_all_blocks && dmm->_nosides && dmm->_nounsides &&
1654 dmm->_nocontacts && dmm->_nouncontacts)
1655 LibmeshPetscCallQ(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_(((PetscObject)dm)->comm),
1656 "\thas a trivial embedding\n"));
1657 else
1658 {
1660 LibmeshPetscCallQ(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_(((PetscObject)dm)->comm),
1661 "\thas embedding defined by IS:\n"));
1662 LibmeshPetscCallQ(ISView(embedding, PETSC_VIEWER_STDOUT_(((PetscObject)dm)->comm)));
1663 LibmeshPetscCallQ(ISDestroy(&embedding));
1664 }
1665 }
1666 /*
1667 Do not evaluate function, Jacobian or bounds for an embedded DM -- the subproblem might not have
1668 enough information for that.
1669 */
1670 if (dmm->_all_vars && dmm->_all_blocks && dmm->_nosides && dmm->_nounsides && dmm->_nocontacts &&
1671 dmm->_nouncontacts)
1672 {
1673 LibmeshPetscCallQ(DMSNESSetFunction(dm, SNESFunction_DMMoose, (void *)dm));
1674 LibmeshPetscCallQ(DMSNESSetJacobian(dm, SNESJacobian_DMMoose, (void *)dm));
1675 if (dmm->_nl->nonlinearSolver()->bounds || dmm->_nl->nonlinearSolver()->bounds_object)
1676 LibmeshPetscCallQ(DMSetVariableBounds(dm, DMVariableBounds_Moose));
1677 }
1678 PetscFunctionReturn(PETSC_SUCCESS);
1679}
1680#if !PETSC_VERSION_LESS_THAN(3, 23, 0)
1681PetscErrorCode
1682DMSetFromOptions_Moose(DM dm, PetscOptionItems /*options*/)
1683#elif !PETSC_VERSION_LESS_THAN(3, 18, 0)
1684PetscErrorCode
1685DMSetFromOptions_Moose(DM dm, PetscOptionItems * /*options*/) // >= 3.18.0
1686#elif !PETSC_VERSION_LESS_THAN(3, 7, 0)
1687PetscErrorCode
1688DMSetFromOptions_Moose(PetscOptionItems * /*options*/, DM dm) // >= 3.7.0
1689#else
1690PetscErrorCode
1691DMSetFromOptions_Moose(PetscOptions * /*options*/, DM dm) // >= 3.6.0
1692#endif
1693{
1694 DM_Moose * dmm = (DM_Moose *)dm->data;
1695
1698 if (!dmm->_nl)
1699 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No Moose system set for DM_Moose");
1700// PETSc changed macro definitions in 3.18; the former correct usage
1701// is now a compiler error and the new usage is now a compiler
1702// warning.
1703#if !PETSC_VERSION_LESS_THAN(3, 18, 0)
1704 PetscOptionsBegin(((PetscObject)dm)->comm, ((PetscObject)dm)->prefix, "DMMoose options", "DM");
1705#else
1707 ((PetscObject)dm)->comm, ((PetscObject)dm)->prefix, "DMMoose options", "DM"));
1708#endif
1709 std::string opt, help;
1710 PetscInt maxvars = dmm->_dof_map->n_variables();
1711 char ** vars;
1712 std::set<std::string> varset;
1713 PetscInt nvars = maxvars;
1714 LibmeshPetscCallQ(PetscMalloc(maxvars * sizeof(char *), &vars));
1715 opt = "-dm_moose_vars";
1716 help = "Variables in DMMoose";
1717 LibmeshPetscCallQ(PetscOptionsStringArray(
1718 opt.c_str(), help.c_str(), "DMMooseSetVars", vars, &nvars, LIBMESH_PETSC_NULLPTR));
1719 for (PetscInt i = 0; i < nvars; ++i)
1720 {
1721 varset.insert(std::string(vars[i]));
1722 LibmeshPetscCallQ(PetscFree(vars[i]));
1723 }
1725 if (varset.size())
1727 //
1728 std::set<subdomain_id_type> meshblocks;
1730 PetscInt maxblocks = meshblocks.size();
1731 char ** blocks;
1732 LibmeshPetscCallQ(PetscMalloc(maxblocks * sizeof(char *), &blocks));
1733 std::set<std::string> blockset;
1734 PetscInt nblocks = maxblocks;
1735 opt = "-dm_moose_blocks";
1736 help = "Blocks in DMMoose";
1737 LibmeshPetscCallQ(PetscOptionsStringArray(
1738 opt.c_str(), help.c_str(), "DMMooseSetBlocks", blocks, &nblocks, LIBMESH_PETSC_NULLPTR));
1739 for (PetscInt i = 0; i < nblocks; ++i)
1740 {
1741 blockset.insert(std::string(blocks[i]));
1742 LibmeshPetscCallQ(PetscFree(blocks[i]));
1743 }
1745 if (blockset.size())
1747 PetscInt maxsides = dmm->_system->get_mesh().get_boundary_info().get_global_boundary_ids().size();
1748 char ** sides;
1749 LibmeshPetscCallQ(PetscMalloc(maxsides * maxvars * sizeof(char *), &sides));
1750 PetscInt nsides = maxsides;
1751 std::set<std::string> sideset;
1752
1753 // Do sides
1754 opt = "-dm_moose_sides";
1755 help = "Sides to include in DMMoose";
1756 LibmeshPetscCallQ(PetscOptionsStringArray(
1757 opt.c_str(), help.c_str(), "DMMooseSetSides", sides, &nsides, LIBMESH_PETSC_NULLPTR));
1758 for (PetscInt i = 0; i < nsides; ++i)
1759 {
1760 sideset.insert(std::string(sides[i]));
1761 LibmeshPetscCallQ(PetscFree(sides[i]));
1762 }
1763 if (sideset.size())
1765
1766 // Do unsides
1767 opt = "-dm_moose_unsides";
1768 help = "Sides to exclude from DMMoose";
1769 nsides = maxsides;
1770 LibmeshPetscCallQ(PetscOptionsStringArray(
1771 opt.c_str(), help.c_str(), "DMMooseSetUnSides", sides, &nsides, LIBMESH_PETSC_NULLPTR));
1772 sideset.clear();
1773 for (PetscInt i = 0; i < nsides; ++i)
1774 {
1775 sideset.insert(std::string(sides[i]));
1776 LibmeshPetscCallQ(PetscFree(sides[i]));
1777 }
1778 if (sideset.size())
1780
1781 // Do unsides by var
1782 opt = "-dm_moose_unside_by_var";
1783 help = "Sides to exclude from DMMoose on a by-var basis";
1785 LibmeshPetscCallQ(PetscOptionsStringArray(
1786 opt.c_str(), help.c_str(), "DMMooseSetUnSideByVar", sides, &nsides, LIBMESH_PETSC_NULLPTR));
1787 sideset.clear();
1788 for (PetscInt i = 0; i < nsides; ++i)
1789 {
1790 sideset.insert(std::string(sides[i]));
1791 LibmeshPetscCallQ(PetscFree(sides[i]));
1792 }
1793 if (sideset.size())
1795
1798 std::shared_ptr<DisplacedProblem> displaced_problem = dmm->_nl->feProblem().getDisplacedProblem();
1800 maxcontacts = PetscMax(
1801 maxcontacts, (PetscInt)displaced_problem->geomSearchData()._penetration_locators.size());
1802
1803 std::vector<DM_Moose::ContactName> contacts;
1804 std::vector<PetscBool> contact_displaced;
1805 PetscInt ncontacts = 0;
1806 opt = "-dm_moose_ncontacts";
1807 help =
1808 "Number of contacts to include in DMMoose. For each <n> < "
1809 "dm_moose_contacts\n\t-dm_moose_contact_<n> is a comma-separated <primary>,<secondary> pair "
1810 "defining the contact surfaces"
1811 "\t-dm_moose_contact_<n>_displaced <bool> determines whether the contact is defined on "
1812 "the displaced mesh or not";
1813 LibmeshPetscCallQ(PetscOptionsInt(opt.c_str(),
1814 help.c_str(),
1815 "DMMooseSetContacts",
1816 ncontacts,
1817 &ncontacts,
1818 LIBMESH_PETSC_NULLPTR));
1819 if (ncontacts > maxcontacts)
1820 LIBMESH_SETERRQ2(((PetscObject)dm)->comm,
1821 PETSC_ERR_ARG_SIZ,
1822 "Number of requested contacts %" LIBMESH_PETSCINT_FMT
1823 " exceeds the maximum number of contacts %" LIBMESH_PETSCINT_FMT,
1824 ncontacts,
1825 maxcontacts);
1826 for (PetscInt i = 0; i < ncontacts; ++i)
1827 {
1828 {
1829 char * primary_secondary[2];
1830 PetscInt sz = 2;
1831 std::ostringstream oopt, ohelp;
1832 oopt << "-dm_moose_contact_" << i;
1833 ohelp << "Primary and secondary for contact " << i;
1834 LibmeshPetscCallQ(PetscOptionsStringArray(oopt.str().c_str(),
1835 ohelp.str().c_str(),
1836 "DMMooseSetContacts",
1837 primary_secondary,
1838 &sz,
1839 LIBMESH_PETSC_NULLPTR));
1840 if (sz != 2)
1841 LIBMESH_SETERRQ2(
1842 ((PetscObject)dm)->comm,
1843 PETSC_ERR_ARG_SIZ,
1844 "Expected 2 sideset IDs (primary & secondary) for contact %" LIBMESH_PETSCINT_FMT
1845 ", got %" LIBMESH_PETSCINT_FMT " instead",
1846 i,
1847 sz);
1848 contacts.push_back(DM_Moose::ContactName(std::string(primary_secondary[0]),
1849 std::string(primary_secondary[1])));
1850 LibmeshPetscCallQ(PetscFree(primary_secondary[0]));
1851 LibmeshPetscCallQ(PetscFree(primary_secondary[1]));
1852 }
1853 {
1854 PetscBool displaced = PETSC_FALSE;
1855 std::ostringstream oopt, ohelp;
1856 oopt << "-dm_moose_contact_" << i << "_displaced";
1857 ohelp << "Whether contact " << i << " is determined using displaced mesh or not";
1858 LibmeshPetscCallQ(PetscOptionsBool(oopt.str().c_str(),
1859 ohelp.str().c_str(),
1860 "DMMooseSetContacts",
1861 PETSC_FALSE,
1862 &displaced,
1863 LIBMESH_PETSC_NULLPTR));
1864 contact_displaced.push_back(displaced);
1865 }
1866 }
1867 if (contacts.size())
1869 {
1870 std::ostringstream oopt, ohelp;
1872 oopt << "-dm_moose_includeAllContactNodes";
1873 ohelp << "Whether to include all nodes on the contact surfaces into the subsolver";
1874 LibmeshPetscCallQ(PetscOptionsBool(oopt.str().c_str(),
1875 ohelp.str().c_str(),
1876 "",
1877 PETSC_FALSE,
1879 LIBMESH_PETSC_NULLPTR));
1881 }
1882 std::vector<DM_Moose::ContactName> uncontacts;
1883 std::vector<PetscBool> uncontact_displaced;
1884 PetscInt nuncontacts = 0;
1885 opt = "-dm_moose_nuncontacts";
1886 help =
1887 "Number of contacts to exclude from DMMoose. For each <n> < "
1888 "dm_moose_contacts\n\t-dm_moose_contact_<n> is a comma-separated <primary>,<secondary> pair "
1889 "defining the contact surfaces"
1890 "\t-dm_moose_contact_<n>_displaced <bool> determines whether the contact is defined on "
1891 "the displaced mesh or not";
1892 LibmeshPetscCallQ(PetscOptionsInt(opt.c_str(),
1893 help.c_str(),
1894 "DMMooseSetUnContacts",
1896 &nuncontacts,
1897 LIBMESH_PETSC_NULLPTR));
1899 LIBMESH_SETERRQ2(((PetscObject)dm)->comm,
1900 PETSC_ERR_ARG_SIZ,
1901 "Number of requested uncontacts %" LIBMESH_PETSCINT_FMT
1902 " exceeds the maximum number of contacts %" LIBMESH_PETSCINT_FMT,
1904 maxcontacts);
1905 for (PetscInt i = 0; i < nuncontacts; ++i)
1906 {
1907 {
1908 char * primary_secondary[2];
1909 PetscInt sz = 2;
1910 std::ostringstream oopt, ohelp;
1911 oopt << "-dm_moose_uncontact_" << i;
1912 ohelp << "Primary and secondary for uncontact " << i;
1913 LibmeshPetscCallQ(PetscOptionsStringArray(oopt.str().c_str(),
1914 ohelp.str().c_str(),
1915 "DMMooseSetUnContacts",
1916 primary_secondary,
1917 &sz,
1918 LIBMESH_PETSC_NULLPTR));
1919 if (sz != 2)
1920 LIBMESH_SETERRQ2(
1921 ((PetscObject)dm)->comm,
1922 PETSC_ERR_ARG_SIZ,
1923 "Expected 2 sideset IDs (primary & secondary) for uncontact %" LIBMESH_PETSCINT_FMT
1924 ", got %" LIBMESH_PETSCINT_FMT " instead",
1925 i,
1926 sz);
1927 uncontacts.push_back(DM_Moose::ContactName(std::string(primary_secondary[0]),
1928 std::string(primary_secondary[1])));
1929 LibmeshPetscCallQ(PetscFree(primary_secondary[0]));
1930 LibmeshPetscCallQ(PetscFree(primary_secondary[1]));
1931 }
1932 {
1933 PetscBool displaced = PETSC_FALSE;
1934 std::ostringstream oopt, ohelp;
1935 oopt << "-dm_moose_uncontact_" << i << "_displaced";
1936 ohelp << "Whether uncontact " << i << " is determined using displaced mesh or not";
1937 LibmeshPetscCallQ(PetscOptionsBool(oopt.str().c_str(),
1938 ohelp.str().c_str(),
1939 "DMMooseSetUnContact",
1940 PETSC_FALSE,
1941 &displaced,
1942 LIBMESH_PETSC_NULLPTR));
1943 uncontact_displaced.push_back(displaced);
1944 }
1945 }
1946 if (uncontacts.size())
1948
1949 PetscInt nsplits = 0;
1950 /* Insert the usage of -dm_moose_fieldsplit_names into this help message, since the following
1951 * if-clause might never fire, if -help is requested. */
1952 const char * fdhelp = "Number of named fieldsplits defined by the DM.\n\
1953 \tNames of fieldsplits are defined by -dm_moose_fieldsplit_names <splitname1> <splitname2> ...\n\
1954 \tEach split can be configured with its own variables, blocks and sides, as any DMMoose";
1955 LibmeshPetscCallQ(PetscOptionsInt(
1956 "-dm_moose_nfieldsplits", fdhelp, "DMMooseSetSplitNames", nsplits, &nsplits, NULL));
1958 {
1959 PetscInt nnsplits = nsplits;
1960 std::vector<std::string> split_names;
1961 char ** splitnames;
1962 LibmeshPetscCallQ(PetscMalloc(nsplits * sizeof(char *), &splitnames));
1963 LibmeshPetscCallQ(PetscOptionsStringArray("-dm_moose_fieldsplit_names",
1964 "Names of fieldsplits defined by the DM",
1965 "DMMooseSetSplitNames",
1966 splitnames,
1967 &nnsplits,
1968 LIBMESH_PETSC_NULLPTR));
1969 if (!nnsplits)
1970 {
1971 for (PetscInt i = 0; i < nsplits; ++i)
1972 {
1973 std::ostringstream s;
1974 s << i;
1975 split_names.push_back(s.str());
1976 }
1977 }
1978 else if (nsplits != nnsplits)
1979 LIBMESH_SETERRQ2(((PetscObject)dm)->comm,
1980 PETSC_ERR_ARG_SIZ,
1981 "Expected %" LIBMESH_PETSCINT_FMT
1982 " fieldsplit names, got %" LIBMESH_PETSCINT_FMT " instead",
1983 nsplits,
1984 nnsplits);
1985 else
1986 {
1987 for (PetscInt i = 0; i < nsplits; ++i)
1988 {
1989 split_names.push_back(std::string(splitnames[i]));
1990 LibmeshPetscCallQ(PetscFree(splitnames[i]));
1991 }
1992 }
1993 LibmeshPetscCallQ(PetscFree(splitnames));
1995 }
1996 LibmeshPetscCallQ(PetscOptionsBool("-dm_moose_print_embedding",
1997 "Print IS embedding DM's dofs",
1998 "DMMoose",
1999 dmm->_print_embedding,
2000 &dmm->_print_embedding,
2001 LIBMESH_PETSC_NULLPTR));
2003 LibmeshPetscCallQ(DMSetUp_Moose_Pre(dm)); /* Need some preliminary set up because, strangely
2004 enough, DMView() is called in DMSetFromOptions(). */
2005 PetscFunctionReturn(PETSC_SUCCESS);
2006}
2007
2008static PetscErrorCode
2010{
2011 DM_Moose * dmm = (DM_Moose *)(dm->data);
2012
2014 delete dmm->_name;
2015 if (dmm->_vars)
2016 delete dmm->_vars;
2017 delete dmm->_var_ids;
2018 delete dmm->_var_names;
2019 if (dmm->_blocks)
2020 delete dmm->_blocks;
2021 delete dmm->_block_ids;
2022 delete dmm->_block_names;
2023 if (dmm->_sides)
2024 delete dmm->_sides;
2025 delete dmm->_side_ids;
2026 delete dmm->_side_names;
2027 if (dmm->_unsides)
2028 delete dmm->_unsides;
2029 delete dmm->_unside_ids;
2030 delete dmm->_unside_names;
2031 if (dmm->_unside_by_var)
2032 delete dmm->_unside_by_var;
2033 delete dmm->_unside_by_var_set;
2034 if (dmm->_contacts)
2035 delete dmm->_contacts;
2036 delete dmm->_contact_names;
2037 delete dmm->_contact_displaced;
2038 if (dmm->_uncontacts)
2039 delete dmm->_uncontacts;
2040 delete dmm->_uncontact_names;
2041 delete dmm->_uncontact_displaced;
2042 if (dmm->_splits)
2043 {
2044 for (auto & sit : *(dmm->_splits))
2045 {
2046 LibmeshPetscCallQ(DMDestroy(&(sit.second._dm)));
2047 LibmeshPetscCallQ(ISDestroy(&(sit.second._rembedding)));
2048 }
2049 delete dmm->_splits;
2050 }
2051 if (dmm->_splitlocs)
2052 delete dmm->_splitlocs;
2053 LibmeshPetscCallQ(ISDestroy(&dmm->_embedding));
2054 LibmeshPetscCallQ(PetscFree(dm->data));
2055 PetscFunctionReturn(PETSC_SUCCESS);
2056}
2057
2058PetscErrorCode
2059DMCreateMoose(MPI_Comm comm,
2061 const libMesh::DofMapBase & dof_map,
2062 const System & system,
2063 const std::string & dm_name,
2064 DM * dm)
2065{
2067 LibmeshPetscCallQ(DMCreate(comm, dm));
2068 LibmeshPetscCallQ(DMSetType(*dm, DMMOOSE));
2073 PetscFunctionReturn(PETSC_SUCCESS);
2074}
2075
2076EXTERN_C_BEGIN
2077PetscErrorCode
2079{
2080 DM_Moose * dmm;
2081
2083 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2084#if PETSC_RELEASE_LESS_THAN(3, 18, 0)
2085 LibmeshPetscCallQ(PetscNewLog(dm, &dmm));
2086#else // PetscNewLog was deprecated
2087 LibmeshPetscCallQ(PetscNew(&dmm));
2088#endif
2089 dm->data = dmm;
2090
2091 dmm->_name = new (std::string);
2092 dmm->_var_ids = new (std::map<std::string, unsigned int>);
2093 dmm->_block_ids = new (std::map<std::string, subdomain_id_type>);
2094 dmm->_var_names = new (std::map<unsigned int, std::string>);
2095 dmm->_block_names = new (std::map<unsigned int, std::string>);
2096 dmm->_side_ids = new (std::map<std::string, BoundaryID>);
2097 dmm->_side_names = new (std::map<BoundaryID, std::string>);
2098 dmm->_unside_ids = new (std::map<std::string, BoundaryID>);
2099 dmm->_unside_names = new (std::map<BoundaryID, std::string>);
2100 dmm->_unside_by_var_set = new (std::set<std::pair<BoundaryID, unsigned int>>);
2101 dmm->_contact_names = new (std::map<DM_Moose::ContactID, DM_Moose::ContactName>);
2102 dmm->_uncontact_names = new (std::map<DM_Moose::ContactID, DM_Moose::ContactName>);
2103 dmm->_contact_displaced = new (std::map<DM_Moose::ContactName, PetscBool>);
2104 dmm->_uncontact_displaced = new (std::map<DM_Moose::ContactName, PetscBool>);
2105
2106 dmm->_splits = new (std::map<std::string, DM_Moose::SplitInfo>);
2107
2108 dmm->_print_embedding = PETSC_FALSE;
2109
2110 dm->ops->createglobalvector = DMCreateGlobalVector_Moose;
2111 dm->ops->createlocalvector = 0; // DMCreateLocalVector_Moose;
2112 dm->ops->getcoloring = 0; // DMGetColoring_Moose;
2113 dm->ops->creatematrix = DMCreateMatrix_Moose;
2114 dm->ops->createinterpolation = 0; // DMCreateInterpolation_Moose;
2115
2116 dm->ops->refine = 0; // DMRefine_Moose;
2117 dm->ops->coarsen = 0; // DMCoarsen_Moose;
2118#if PETSC_RELEASE_LESS_THAN(3, 12, 0)
2119 dm->ops->getinjection = 0; // DMGetInjection_Moose;
2120 dm->ops->getaggregates = 0; // DMGetAggregates_Moose;
2121#else
2122 dm->ops->createinjection = 0;
2123#endif
2124
2125 dm->ops->createfielddecomposition = DMCreateFieldDecomposition_Moose;
2126 dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_Moose;
2127
2128 dm->ops->destroy = DMDestroy_Moose;
2129 dm->ops->view = DMView_Moose;
2130 dm->ops->setfromoptions = DMSetFromOptions_Moose;
2131 dm->ops->setup = DMSetUp_Moose;
2132 PetscFunctionReturn(PETSC_SUCCESS);
2133}
2135
2136#undef __FUNCT__
2137#define __FUNCT__ "SNESUpdateDMMoose"
2138PetscErrorCode
2139SNESUpdateDMMoose(SNES snes, PetscInt iteration)
2140{
2141 /* This is called any time the structure of the problem changes in a way that affects the Jacobian
2142 sparsity pattern.
2143 For example, this may happen when NodeFaceConstraints change Jacobian's sparsity pattern based
2144 on newly-detected Penetration.
2145 In that case certain preconditioners (e.g., PCASM) will not work, unless we tell them that the
2146 sparsity pattern has changed.
2147 For now we are rebuilding the whole KSP, when necessary.
2148 */
2149 DM dm;
2150 KSP ksp;
2151 const char * prefix;
2152 MPI_Comm comm;
2153 PC pc;
2154
2156 if (iteration)
2157 {
2158 /* TODO: limit this only to situations when displaced (un)contact splits are present, as is
2159 * DisplacedProblem(). */
2160 LibmeshPetscCallQ(SNESGetDM(snes, &dm));
2162 LibmeshPetscCallQ(DMSetUp(dm));
2163 LibmeshPetscCallQ(SNESGetKSP(snes, &ksp));
2164 /* Should we rebuild the whole KSP? */
2165 LibmeshPetscCallQ(PetscObjectGetOptionsPrefix((PetscObject)ksp, &prefix));
2166 LibmeshPetscCallQ(PetscObjectGetComm((PetscObject)ksp, &comm));
2167 LibmeshPetscCallQ(PCCreate(comm, &pc));
2168 LibmeshPetscCallQ(PCSetDM(pc, dm));
2169 LibmeshPetscCallQ(PCSetOptionsPrefix(pc, prefix));
2170 LibmeshPetscCallQ(PCSetFromOptions(pc));
2171 LibmeshPetscCallQ(KSPSetPC(ksp, pc));
2172 LibmeshPetscCallQ(PCDestroy(&pc));
2173 }
2174 PetscFunctionReturn(PETSC_SUCCESS);
2175}
2176
2177PetscErrorCode
2179{
2180 static PetscBool DMMooseRegisterAllCalled = PETSC_FALSE;
2181
2183 if (!DMMooseRegisterAllCalled)
2184 {
2185 LibmeshPetscCallQ(DMRegister(DMMOOSE, DMCreate_Moose));
2186 DMMooseRegisterAllCalled = PETSC_TRUE;
2187 }
2188 PetscFunctionReturn(PETSC_SUCCESS);
2189}
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 DMMooseFunction(DM dm, Vec x, Vec r)
static PetscErrorCode DMCreateDomainDecomposition_Moose(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
std::vector< PetscBool > uncontact_displaced
PetscErrorCode SNESUpdateDMMoose(SNES snes, PetscInt iteration)
static PetscErrorCode DMView_Moose(DM dm, PetscViewer viewer)
static PetscErrorCode DMVariableBounds_Moose(DM dm, Vec xl, Vec xu)
PetscInt nsides
static PetscErrorCode SNESJacobian_DMMoose(SNES, Vec x, Mat jac, Mat pc, void *ctx)
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)
PetscErrorCode DMMooseRegisterAll()
static PetscErrorCode SNESFunction_DMMoose(SNES, Vec x, Vec r, void *ctx)
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)
static PetscErrorCode DMMooseJacobian(DM dm, Vec x, Mat jac, Mat pc)
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)
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:1239
BoundaryID getBoundaryID(const BoundaryName &boundary_name) const
Get the associated BoundaryID for the boundary name.
Definition MooseMesh.C:1684
libMesh::StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode * > * getBoundaryNodeRange()
Definition MooseMesh.C:1288
libMesh::StoredRange< MooseMesh::const_bnd_elem_iterator, const BndElement * > * getBoundaryElementRange()
Definition MooseMesh.C:1301
Nonlinear system to be solved.
virtual libMesh::NonlinearSolver< Number > * nonlinearSolver()=0
virtual libMesh::System & system() override
Get the reference to the libMesh system.
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:89
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:144
virtual bool hasVariable(const std::string &var_name) const
Query a system for a variable.
Definition SystemBase.C:850
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
void enforce_constraints_exactly(const System &system, NumericVector< Number > *v=nullptr, bool homogeneous=false) const
const Parallel::Communicator & comm() const
std::unique_ptr< NumericVector< Number > > current_local_solution
std::unique_ptr< NumericVector< Number > > solution
virtual void update()
const DofMap & get_dof_map() 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