libMesh
petscdmlibmeshimpl.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 #include "libmesh/petsc_macro.h"
21 
22 #ifdef LIBMESH_HAVE_PETSC
23 
24 #include "libmesh/ignore_warnings.h"
25 
26 // PETSc includes
27 #if !PETSC_VERSION_LESS_THAN(3,6,0)
28 # include <petsc/private/dmimpl.h>
29 #else
30 # include <petsc-private/dmimpl.h>
31 #endif
32 
33 #include "libmesh/restore_warnings.h"
34 
35 // Local Includes
36 #include "libmesh/libmesh_common.h"
37 #include "libmesh/nonlinear_implicit_system.h"
38 #include "libmesh/petsc_nonlinear_solver.h"
39 #include "libmesh/petsc_linear_solver.h"
40 #include "libmesh/petsc_vector.h"
41 #include "libmesh/petsc_matrix_base.h"
42 #include "libmesh/petscdmlibmesh.h"
43 #include "libmesh/dof_map.h"
44 #include "libmesh/preconditioner.h"
45 #include "libmesh/elem.h"
46 #include "libmesh/parallel.h"
47 
48 
49 using namespace libMesh;
50 
51 
52 #define DMLIBMESH_NO_DECOMPOSITION 0
53 #define DMLIBMESH_FIELD_DECOMPOSITION 1
54 #define DMLIBMESH_DOMAIN_DECOMPOSITION 2
55 
56 #define DMLIBMESH_NO_EMBEDDING 0
57 #define DMLIBMESH_FIELD_EMBEDDING 1
58 #define DMLIBMESH_DOMAIN_EMBEDDING 2
59 
60 struct DM_libMesh
61 {
63  std::map<std::string, unsigned int> * varids;
64  std::map<unsigned int, std::string> * varnames;
65  std::map<std::string, unsigned int> * blockids;
66  std::map<unsigned int, std::string> * blocknames;
67  unsigned int decomposition_type;
68  std::vector<std::set<unsigned int>> * decomposition;
69  unsigned int embedding_type;
71  unsigned int vec_count;
72 };
73 
74 struct DMVec_libMesh {
75  std::string label;
76 };
77 
78 #undef __FUNCT__
79 #define __FUNCT__ "DMlibMeshGetVec_Private"
80 PetscErrorCode DMlibMeshGetVec_Private(DM /*dm*/, const char * /*name*/, Vec *)
81 {
82  PetscFunctionBegin;
83 
84  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
85 }
86 
87 
88 
89 PetscErrorCode DMlibMeshSetUpName_Private(DM dm);
90 
91 #undef __FUNCT__
92 #define __FUNCT__ "DMlibMeshSetSystem_libMesh"
94 {
95  const Parallel::Communicator & comm = sys.comm();
96 
97  PetscFunctionBegin;
98  PetscValidHeaderSpecific(dm,DM_CLASSID,1);
99  PetscBool islibmesh;
100  LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)dm, DMLIBMESH,&islibmesh));
101  if (!islibmesh) LIBMESH_SETERRQ2(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Got DM of type %s, not of type %s", ((PetscObject)dm)->type_name, DMLIBMESH);
102 
103  if (dm->setupcalled) SETERRQ(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot reset the libMesh system after DM has been set up.");
104  DM_libMesh * dlm = (DM_libMesh *)(dm->data);
105  dlm->sys =&sys;
106  /* Initially populate the sets of active blockids and varids using all of the
107  existing blocks/variables (only variables are supported at the moment). */
108  DofMap & dofmap = dlm->sys->get_dof_map();
109  dlm->varids->clear();
110  dlm->varnames->clear();
111  for (auto v : make_range(dofmap.n_variables())) {
112  std::string vname = dofmap.variable(v).name();
113  dlm->varids->insert(std::pair<std::string,unsigned int>(vname,v));
114  dlm->varnames->insert(std::pair<unsigned int,std::string>(v,vname));
115  }
116  const MeshBase & mesh = dlm->sys->get_mesh();
117  dlm->blockids->clear();
118  dlm->blocknames->clear();
119  std::set<subdomain_id_type> blocks;
120  /* The following effectively is a verbatim copy of MeshBase::n_subdomains(). */
121  // This requires an inspection on every processor
122  libmesh_parallel_only(mesh.comm());
123  for (const auto & elem : mesh.active_element_ptr_range())
124  blocks.insert(elem->subdomain_id());
125  // Some subdomains may only live on other processors
126  comm.set_union(blocks);
127 
128  std::set<subdomain_id_type>::iterator bit = blocks.begin();
129  std::set<subdomain_id_type>::iterator bend = blocks.end();
130  if (bit == bend) SETERRQ(((PetscObject)dm)->comm, PETSC_ERR_PLIB, "No mesh blocks found.");
131 
132  for (; bit != bend; ++bit) {
133  subdomain_id_type bid = *bit;
134  std::string bname = mesh.subdomain_name(bid);
135  if (!bname.length()) {
136  /* Block names are currently implemented for Exodus II meshes
137  only, so we might have to make up our own block names and
138  maintain our own mapping of block ids to names.
139  */
140  std::ostringstream ss;
141  ss << "dm" << bid;
142  bname = ss.str();
143  }
144  dlm->blockids->insert(std::pair<std::string,unsigned int>(bname,bid));
145  dlm->blocknames->insert(std::pair<unsigned int,std::string>(bid,bname));
146  }
148  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
149 }
150 
151 #undef __FUNCT__
152 #define __FUNCT__ "DMlibMeshGetSystem_libMesh"
154 {
155  PetscFunctionBegin;
156  PetscValidHeaderSpecific(dm,DM_CLASSID,1);
157  PetscBool islibmesh;
158  LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)dm, DMLIBMESH,&islibmesh));
159  if (!islibmesh) LIBMESH_SETERRQ2(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Got DM of type %s, not of type %s", ((PetscObject)dm)->type_name, DMLIBMESH);
160  DM_libMesh * dlm = (DM_libMesh *)(dm->data);
161  sys = dlm->sys;
162  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
163 }
164 
165 
166 #undef __FUNCT__
167 #define __FUNCT__ "DMlibMeshGetBlocks"
168 PetscErrorCode DMlibMeshGetBlocks(DM dm, PetscInt * n, char *** blocknames)
169 {
170  PetscInt i;
171  PetscFunctionBegin;
172  PetscValidHeaderSpecific(dm,DM_CLASSID,1);
173  PetscBool islibmesh;
174  LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)dm, DMLIBMESH,&islibmesh));
175  if (!islibmesh) LIBMESH_SETERRQ2(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Got DM of type %s, not of type %s", ((PetscObject)dm)->type_name, DMLIBMESH);
176  DM_libMesh * dlm = (DM_libMesh *)(dm->data);
177 #if PETSC_RELEASE_GREATER_EQUALS(3,20,0)
178  PetscAssertPointer(n,2);
179 #else
180  PetscValidPointer(n,2);
181 #endif
182  *n = cast_int<unsigned int>(dlm->blockids->size());
183  if (!blocknames) PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
184  LibmeshPetscCallQ(PetscMalloc(*n*sizeof(char *), blocknames));
185  i = 0;
186  for (const auto & pr : *(dlm->blockids))
187  {
188  LibmeshPetscCallQ(PetscStrallocpy(pr.first.c_str(), *blocknames+i));
189  ++i;
190  }
191  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
192 }
193 
194 #undef __FUNCT__
195 #define __FUNCT__ "DMlibMeshGetVariables"
196 PetscErrorCode DMlibMeshGetVariables(DM dm, PetscInt * n, char *** varnames)
197 {
198  PetscFunctionBegin;
199  PetscValidHeaderSpecific(dm,DM_CLASSID,1);
200  PetscBool islibmesh;
201  PetscInt i;
202  LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)dm, DMLIBMESH,&islibmesh));
203  if (!islibmesh) LIBMESH_SETERRQ2(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Got DM of type %s, not of type %s", ((PetscObject)dm)->type_name, DMLIBMESH);
204  DM_libMesh * dlm = (DM_libMesh *)(dm->data);
205 #if PETSC_RELEASE_GREATER_EQUALS(3,20,0)
206  PetscAssertPointer(n,2);
207 #else
208  PetscValidPointer(n,2);
209 #endif
210  *n = cast_int<unsigned int>(dlm->varids->size());
211  if (!varnames) PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
212  LibmeshPetscCallQ(PetscMalloc(*n*sizeof(char *), varnames));
213  i = 0;
214  for (const auto & pr : *(dlm->varids))
215  {
216  LibmeshPetscCallQ(PetscStrallocpy(pr.first.c_str(), *varnames+i));
217  ++i;
218  }
219  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
220 }
221 
222 #undef __FUNCT__
223 #define __FUNCT__ "DMlibMeshSetUpName_Private"
224 PetscErrorCode DMlibMeshSetUpName_Private(DM dm)
225 {
226  DM_libMesh * dlm = (DM_libMesh *)dm->data;
227  PetscFunctionBegin;
228  std::string name = dlm->sys->name();
229  std::map<unsigned int, std::string> * dnames = LIBMESH_PETSC_NULLPTR,
230  * enames = LIBMESH_PETSC_NULLPTR;
231  if (dlm->decomposition_type == DMLIBMESH_FIELD_DECOMPOSITION) {
232  name += ":dec:var:";
233  dnames = dlm->varnames;
234  }
235  if (dlm->decomposition_type == DMLIBMESH_DOMAIN_DECOMPOSITION) {
236  name += ":dec:block:";
237  dnames = dlm->blocknames;
238  }
239  if (dnames) {
240  for (auto decomp : *dlm->decomposition) {
241  for (std::set<unsigned int>::iterator dit_begin = decomp.begin(),
242  dit = dit_begin,
243  dit_end = decomp.end();
244  dit != dit_end; ++dit) {
245  unsigned int id = *dit;
246  if (dit != dit_begin)
247  name += ",";
248  name += (*dnames)[id];
249  }
250  name += ";";
251  }
252  }
253  if (dlm->embedding_type == DMLIBMESH_FIELD_EMBEDDING) {
254  name += ":emb:var:";
255  enames = dlm->varnames;
256  }
257  if (dlm->embedding_type == DMLIBMESH_DOMAIN_EMBEDDING) {
258  name += ":emb:block:";
259  enames = dlm->blocknames;
260  }
261  if (enames) {
262  for (auto eit = enames->begin(),
263  eit_end = enames->end(); eit != eit_end; ++eit) {
264  std::string & ename = eit->second;
265  if (eit != enames->begin())
266  name += ",";
267  name += ename;
268  }
269  name += ";";
270  }
271  LibmeshPetscCallQ(PetscObjectSetName((PetscObject)dm, name.c_str()));
272  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
273 }
274 
275 
276 #undef __FUNCT__
277 #define __FUNCT__ "DMCreateFieldDecomposition_libMesh"
278 static PetscErrorCode DMCreateFieldDecomposition_libMesh(DM dm, PetscInt * len, char *** namelist, IS ** islist, DM ** dmlist)
279 {
280  PetscFunctionBegin;
281  DM_libMesh * dlm = (DM_libMesh *)(dm->data);
282  NonlinearImplicitSystem * sys = dlm->sys;
283  IS emb;
284  if (dlm->decomposition_type != DMLIBMESH_FIELD_DECOMPOSITION) PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
285 
286  *len = cast_int<unsigned int>(dlm->decomposition->size());
287  if (namelist) {LibmeshPetscCallQ(PetscMalloc(*len*sizeof(char *), namelist));}
288  if (islist) {LibmeshPetscCallQ(PetscMalloc(*len*sizeof(IS), islist));}
289  if (dmlist) {LibmeshPetscCallQ(PetscMalloc(*len*sizeof(DM), dmlist));}
290  DofMap & dofmap = dlm->sys->get_dof_map();
291  for (auto d : index_range(*dlm->decomposition)) {
292  std::set<numeric_index_type> dindices;
293  std::string dname;
294  std::map<std::string, unsigned int> dvarids;
295  std::map<unsigned int, std::string> dvarnames;
296  unsigned int dvcount = 0;
297  for (const auto & v : (*dlm->decomposition)[d]) {
298  std::string vname = (*dlm->varnames)[v];
299  dvarids.insert(std::pair<std::string, unsigned int>(vname,v));
300  dvarnames.insert(std::pair<unsigned int,std::string>(v,vname));
301  if (!dvcount) dname = vname;
302  else dname += "_" + vname;
303  ++dvcount;
304  if (!islist) continue;
305  // Iterate only over this DM's blocks.
306  for (const auto & pr : *(dlm->blockids)) {
307  const subdomain_id_type sbd_id = cast_int<subdomain_id_type>(pr.second);
308  for (const auto & elem :
309  as_range(sys->get_mesh().active_local_subdomain_elements_begin(sbd_id),
310  sys->get_mesh().active_local_subdomain_elements_end(sbd_id))) {
311  //unsigned int e_subdomain = elem->subdomain_id();
312  std::vector<numeric_index_type> evindices;
313  // Get the degree of freedom indices for the given variable off the current element.
314  dofmap.dof_indices(elem, evindices, v);
315  for (numeric_index_type dof : evindices) {
316  if (dof >= dofmap.first_dof() && dof < dofmap.end_dof()) // might want to use variable_first/last_local_dof instead
317  dindices.insert(dof);
318  }
319  }
320  }
321  }
322  if (namelist) {
323  LibmeshPetscCallQ(PetscStrallocpy(dname.c_str(),(*namelist)+d));
324  }
325  if (islist) {
326  IS dis;
327  PetscInt * darray;
328  LibmeshPetscCallQ(PetscMalloc(sizeof(PetscInt)*dindices.size(), &darray));
329  numeric_index_type i = 0;
330  for (const auto & id : dindices) {
331  darray[i] = id;
332  ++i;
333  }
334  LibmeshPetscCallQ(ISCreateGeneral(((PetscObject)dm)->comm,
335  cast_int<PetscInt>(dindices.size()),
336  darray, PETSC_OWN_POINTER, &dis));
337  if (dlm->embedding) {
338  /* Create a relative embedding into the parent's index space. */
339  LibmeshPetscCallQ(ISEmbed(dis,dlm->embedding, PETSC_TRUE, &emb));
340  PetscInt elen, dlen;
341  LibmeshPetscCallQ(ISGetLocalSize(emb, &elen));
342  LibmeshPetscCallQ(ISGetLocalSize(dis, &dlen));
343  if (elen != dlen) LIBMESH_SETERRQ1(((PetscObject)dm)->comm, PETSC_ERR_PLIB, "Failed to embed subdomain %zu", d);
344  LibmeshPetscCallQ(ISDestroy(&dis));
345  dis = emb;
346  }
347  else {
348  emb = dis;
349  }
350  (*islist)[d] = dis;
351  }
352  if (dmlist) {
353  DM ddm;
354  LibmeshPetscCallQ(DMCreate(((PetscObject)dm)->comm, &ddm));
355  LibmeshPetscCallQ(DMSetType(ddm, DMLIBMESH));
356  DM_libMesh * ddlm = (DM_libMesh *)(ddm->data);
357  ddlm->sys = dlm->sys;
358  /* copy over the block ids and names */
359  *ddlm->blockids = *dlm->blockids;
360  *ddlm->blocknames = *dlm->blocknames;
361  /* set the vars from the d-th part of the decomposition. */
362  *ddlm->varids = dvarids;
363  *ddlm->varnames = dvarnames;
364  LibmeshPetscCallQ(PetscObjectReference((PetscObject)emb));
365  ddlm->embedding = emb;
366  ddlm->embedding_type = DMLIBMESH_FIELD_EMBEDDING;
367 
369  LibmeshPetscCallQ(DMSetFromOptions(ddm));
370  (*dmlist)[d] = ddm;
371  }
372  }
373  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
374 }
375 
376 #undef __FUNCT__
377 #define __FUNCT__ "DMCreateDomainDecomposition_libMesh"
378 static PetscErrorCode DMCreateDomainDecomposition_libMesh(DM dm, PetscInt * len, char *** namelist, IS ** innerislist, IS ** outerislist, DM ** dmlist)
379 {
380  PetscFunctionBegin;
381  DM_libMesh * dlm = (DM_libMesh *)(dm->data);
382  NonlinearImplicitSystem * sys = dlm->sys;
383  IS emb;
384  if (dlm->decomposition_type != DMLIBMESH_DOMAIN_DECOMPOSITION) PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
385  *len = cast_int<unsigned int>(dlm->decomposition->size());
386  if (namelist) {LibmeshPetscCallQ(PetscMalloc(*len*sizeof(char *), namelist));}
387  if (innerislist) {LibmeshPetscCallQ(PetscMalloc(*len*sizeof(IS), innerislist));}
388  if (outerislist) *outerislist = LIBMESH_PETSC_NULLPTR; /* FIX: allow mesh-based overlap. */
389  if (dmlist) {LibmeshPetscCallQ(PetscMalloc(*len*sizeof(DM), dmlist));}
390  for (auto d : index_range(*dlm->decomposition)) {
391  std::set<numeric_index_type> dindices;
392  std::string dname;
393  std::map<std::string, unsigned int> dblockids;
394  std::map<unsigned int,std::string> dblocknames;
395  unsigned int dbcount = 0;
396  for (const auto & b : (*dlm->decomposition)[d]) {
397  std::string bname = (*dlm->blocknames)[b];
398  dblockids.insert(std::pair<std::string, unsigned int>(bname,b));
399  dblocknames.insert(std::pair<unsigned int,std::string>(b,bname));
400  if (!dbcount) dname = bname;
401  else dname += "_" + bname;
402  ++dbcount;
403  if (!innerislist) continue;
404  const subdomain_id_type b_sbd_id = cast_int<subdomain_id_type>(b);
405  MeshBase::const_element_iterator el = sys->get_mesh().active_local_subdomain_elements_begin(b_sbd_id);
406  const MeshBase::const_element_iterator end_el = sys->get_mesh().active_local_subdomain_elements_end(b_sbd_id);
407  for ( ; el != end_el; ++el) {
408  const Elem * elem = *el;
409  std::vector<numeric_index_type> evindices;
410  // Iterate only over this DM's variables.
411  for (const auto & pr : *(dlm->varids)) {
412  // Get the degree of freedom indices for the given variable off the current element.
413  sys->get_dof_map().dof_indices(elem, evindices, pr.second);
414  for (const auto & dof : evindices) {
415  if (dof >= sys->get_dof_map().first_dof() && dof < sys->get_dof_map().end_dof()) // might want to use variable_first/last_local_dof instead
416  dindices.insert(dof);
417  }
418  }
419  }
420  }
421  if (namelist) {
422  LibmeshPetscCallQ(PetscStrallocpy(dname.c_str(),(*namelist)+d));
423  }
424  if (innerislist) {
425  PetscInt * darray;
426  IS dis;
427  LibmeshPetscCallQ(PetscMalloc(sizeof(PetscInt)*dindices.size(), &darray));
428  numeric_index_type i = 0;
429  for (const auto & id : dindices) {
430  darray[i] = id;
431  ++i;
432  }
433  LibmeshPetscCallQ(ISCreateGeneral(((PetscObject)dm)->comm,
434  cast_int<PetscInt>(dindices.size()),
435  darray, PETSC_OWN_POINTER, &dis));
436  if (dlm->embedding) {
437  /* Create a relative embedding into the parent's index space. */
438  LibmeshPetscCallQ(ISEmbed(dis,dlm->embedding, PETSC_TRUE, &emb));
439  PetscInt elen, dlen;
440  LibmeshPetscCallQ(ISGetLocalSize(emb, &elen));
441  LibmeshPetscCallQ(ISGetLocalSize(dis, &dlen));
442  if (elen != dlen) LIBMESH_SETERRQ1(((PetscObject)dm)->comm, PETSC_ERR_PLIB, "Failed to embed field %zu" , d);
443  LibmeshPetscCallQ(ISDestroy(&dis));
444  dis = emb;
445  }
446  else {
447  emb = dis;
448  }
449  if (innerislist) {
450  LibmeshPetscCallQ(PetscObjectReference((PetscObject)dis));
451  (*innerislist)[d] = dis;
452  }
453  LibmeshPetscCallQ(ISDestroy(&dis));
454  }
455  if (dmlist) {
456  DM ddm;
457  LibmeshPetscCallQ(DMCreate(((PetscObject)dm)->comm, &ddm));
458  LibmeshPetscCallQ(DMSetType(ddm, DMLIBMESH));
459  DM_libMesh * ddlm = (DM_libMesh *)(ddm->data);
460  ddlm->sys = dlm->sys;
461  /* copy over the varids and varnames */
462  *ddlm->varids = *dlm->varids;
463  *ddlm->varnames = *dlm->varnames;
464  /* set the blocks from the d-th part of the decomposition. */
465  *ddlm->blockids = dblockids;
466  *ddlm->blocknames = dblocknames;
467  LibmeshPetscCallQ(PetscObjectReference((PetscObject)emb));
468  ddlm->embedding = emb;
469  ddlm->embedding_type = DMLIBMESH_DOMAIN_EMBEDDING;
470 
472  LibmeshPetscCallQ(DMSetFromOptions(ddm));
473  (*dmlist)[d] = ddm;
474  }
475  }
476  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
477 }
478 
479 
480 #undef __FUNCT__
481 #define __FUNCT__ "DMlibMeshCreateFieldDecompositionDM"
482 PetscErrorCode DMlibMeshCreateFieldDecompositionDM(DM dm, PetscInt dnumber, PetscInt * dsizes, char *** dvarlists, DM * ddm)
483 {
484  PetscBool islibmesh;
485  PetscFunctionBegin;
486  PetscValidHeaderSpecific(dm,DM_CLASSID,1);
487  LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)dm, DMLIBMESH,&islibmesh));
488  if (!islibmesh) LIBMESH_SETERRQ2(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Got DM of type %s, not of type %s", ((PetscObject)dm)->type_name, DMLIBMESH);
489  if (dnumber < 0) LIBMESH_SETERRQ1(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Negative number %" LIBMESH_PETSCINT_FMT " of decomposition parts", dnumber);
490 #if PETSC_RELEASE_GREATER_EQUALS(3,20,0)
491  PetscAssertPointer(ddm,5);
492 #else
493  PetscValidPointer(ddm,5);
494 #endif
495  DM_libMesh * dlm = (DM_libMesh *)(dm->data);
496  LibmeshPetscCallQ(DMCreate(((PetscObject)dm)->comm, ddm));
497  LibmeshPetscCallQ(DMSetType(*ddm, DMLIBMESH));
498  DM_libMesh * ddlm = (DM_libMesh *)((*ddm)->data);
499  ddlm->sys = dlm->sys;
500  ddlm->varids = dlm->varids;
501  ddlm->varnames = dlm->varnames;
502  ddlm->blockids = dlm->blockids;
503  ddlm->blocknames = dlm->blocknames;
504  ddlm->decomposition = new(std::vector<std::set<unsigned int>>);
505  ddlm->decomposition_type = DMLIBMESH_FIELD_DECOMPOSITION;
506  if (dnumber) {
507  for (PetscInt d = 0; d < dnumber; ++d) {
508  if (dsizes[d] < 0) LIBMESH_SETERRQ2(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Negative size %" LIBMESH_PETSCINT_FMT " of decomposition part %" LIBMESH_PETSCINT_FMT, dsizes[d],d);
509  ddlm->decomposition->push_back(std::set<unsigned int>());
510  for (PetscInt v = 0; v < dsizes[d]; ++v) {
511  std::string vname(dvarlists[d][v]);
512  std::map<std::string, unsigned int>::const_iterator vit = dlm->varids->find(vname);
513  if (vit == dlm->varids->end())
514  LIBMESH_SETERRQ3(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Variable %" LIBMESH_PETSCINT_FMT " on the %" LIBMESH_PETSCINT_FMT "-th list with name %s is not owned by this DM", v, d, dvarlists[d][v]);
515  unsigned int vid = vit->second;
516  (*ddlm->decomposition)[d].insert(vid);
517  }
518  }
519  }
520  else { // Empty splits indicate default: split all variables with one per split.
521  PetscInt d = 0;
522  for (const auto & pr : (*ddlm->varids)) {
523  ddlm->decomposition->push_back(std::set<unsigned int>());
524  unsigned int vid = pr.second;
525  (*ddlm->decomposition)[d].insert(vid);
526  ++d;
527  }
528  }
530  LibmeshPetscCallQ(DMSetFromOptions(*ddm));
531  LibmeshPetscCallQ(DMSetUp(*ddm));
532  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
533 }
534 
535 #undef __FUNCT__
536 #define __FUNCT__ "DMlibMeshCreateDomainDecompositionDM"
537 PetscErrorCode DMlibMeshCreateDomainDecompositionDM(DM dm, PetscInt dnumber, PetscInt * dsizes, char *** dblocklists, DM * ddm)
538 {
539  PetscBool islibmesh;
540  PetscFunctionBegin;
541  PetscValidHeaderSpecific(dm,DM_CLASSID,1);
542  LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)dm, DMLIBMESH,&islibmesh));
543  if (!islibmesh) LIBMESH_SETERRQ2(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Got DM of type %s, not of type %s", ((PetscObject)dm)->type_name, DMLIBMESH);
544  if (dnumber < 0) LIBMESH_SETERRQ1(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Negative number %" LIBMESH_PETSCINT_FMT " of decomposition parts", dnumber);
545 #if PETSC_RELEASE_GREATER_EQUALS(3,20,0)
546  PetscAssertPointer(ddm,5);
547 #else
548  PetscValidPointer(ddm,5);
549 #endif
550  DM_libMesh * dlm = (DM_libMesh *)(dm->data);
551  LibmeshPetscCallQ(DMCreate(((PetscObject)dm)->comm, ddm));
552  LibmeshPetscCallQ(DMSetType(*ddm, DMLIBMESH));
553  DM_libMesh * ddlm = (DM_libMesh *)((*ddm)->data);
554  ddlm->sys = dlm->sys;
555  ddlm->varids = dlm->varids;
556  ddlm->varnames = dlm->varnames;
557  ddlm->blockids = dlm->blockids;
558  ddlm->blocknames = dlm->blocknames;
559  ddlm->decomposition = new(std::vector<std::set<unsigned int>>);
560  ddlm->decomposition_type = DMLIBMESH_DOMAIN_DECOMPOSITION;
561  if (dnumber) {
562  for (PetscInt d = 0; d < dnumber; ++d) {
563  if (dsizes[d] < 0) LIBMESH_SETERRQ2(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Negative size %" LIBMESH_PETSCINT_FMT " of decomposition part %" LIBMESH_PETSCINT_FMT, dsizes[d],d);
564  ddlm->decomposition->push_back(std::set<unsigned int>());
565  for (PetscInt b = 0; b < dsizes[d]; ++b) {
566  std::string bname(dblocklists[d][b]);
567  std::map<std::string, unsigned int>::const_iterator bit = dlm->blockids->find(bname);
568  if (bit == dlm->blockids->end())
569  LIBMESH_SETERRQ3(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Block %" LIBMESH_PETSCINT_FMT " on the %" LIBMESH_PETSCINT_FMT "-th list with name %s is not owned by this DM", b, d, dblocklists[d][b]);
570  unsigned int bid = bit->second;
571  (*ddlm->decomposition)[d].insert(bid);
572  }
573  }
574  }
575  else { // Empty splits indicate default: split all blocks with one per split.
576  PetscInt d = 0;
577  for (const auto & pr : (*ddlm->blockids)) {
578  ddlm->decomposition->push_back(std::set<unsigned int>());
579  unsigned int bid = pr.second;
580  (*ddlm->decomposition)[d].insert(bid);
581  ++d;
582  }
583  }
585  LibmeshPetscCallQ(DMSetFromOptions(*ddm));
586  LibmeshPetscCallQ(DMSetUp(*ddm));
587  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
588 }
589 
590 struct token {
591  const char * s;
592  struct token * next;
593 };
594 
595 
596 
597 #undef __FUNCT__
598 #define __FUNCT__ "DMlibMeshFunction"
599 static PetscErrorCode DMlibMeshFunction(DM dm, Vec x, Vec r)
600 {
601  PetscFunctionBegin;
602  libmesh_assert(x);
603  libmesh_assert(r);
604 
607  NonlinearImplicitSystem & sys = *_sys;
608  PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
609  PetscVector<Number> & R_sys = *cast_ptr<PetscVector<Number> *>(sys.rhs);
610  PetscVector<Number> X_global(x, _sys->comm()), R(r, _sys->comm());
611 
612  // Use the systems update() to get a good local version of the parallel solution
613  X_global.swap(X_sys);
614  R.swap(R_sys);
615 
617  _sys->update();
618 
619  // Swap back
620  X_global.swap(X_sys);
621  R.swap(R_sys);
622  R.zero();
623 
624  // if the user has provided both function pointers and objects only the pointer
625  // will be used, so catch that as an error
626  libmesh_error_msg_if(_sys->nonlinear_solver->residual && _sys->nonlinear_solver->residual_object,
627  "ERROR: cannot specify both a function and object to compute the Residual!");
628 
629  libmesh_error_msg_if(_sys->nonlinear_solver->matvec && _sys->nonlinear_solver->residual_and_jacobian_object,
630  "ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!");
631 
632  if (_sys->nonlinear_solver->residual != nullptr)
633  _sys->nonlinear_solver->residual(*(_sys->current_local_solution.get()), R, *_sys);
634 
635  else if (_sys->nonlinear_solver->residual_object != nullptr)
636  _sys->nonlinear_solver->residual_object->residual(*(_sys->current_local_solution.get()), R, *_sys);
637 
638  else if (_sys->nonlinear_solver->matvec != nullptr)
639  _sys->nonlinear_solver->matvec(*(_sys->current_local_solution.get()), &R, nullptr, *_sys);
640 
641  else if (_sys->nonlinear_solver->residual_and_jacobian_object != nullptr)
642  _sys->nonlinear_solver->residual_and_jacobian_object->residual_and_jacobian(*(_sys->current_local_solution.get()), &R, nullptr, *_sys);
643 
644  else
645  libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");
646 
647  R.close();
648  X_global.close();
649  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
650 }
651 
652 #undef __FUNCT__
653 #define __FUNCT__ "SNESFunction_DMlibMesh"
654 static PetscErrorCode SNESFunction_DMlibMesh(SNES, Vec x, Vec r, void * ctx)
655 {
656  DM dm = (DM)ctx;
657  PetscFunctionBegin;
659  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
660 }
661 
662 
663 #undef __FUNCT__
664 #define __FUNCT__ "DMlibMeshJacobian"
665 static PetscErrorCode DMlibMeshJacobian(DM dm, Vec x, Mat jac, Mat pc)
666 {
667  PetscFunctionBegin;
670  NonlinearImplicitSystem & sys = *_sys;
671 
672  libmesh_assert(pc);
673  libmesh_assert(jac);
676  PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
677  PetscMatrixBase<Number> & Jac_sys = *cast_ptr<PetscMatrixBase<Number> *>(sys.matrix);
678  PetscVector<Number> X_global(x, sys.comm());
679 
680  // Set the dof maps
681  the_pc.attach_dof_map(sys.get_dof_map());
682  Jac.attach_dof_map(sys.get_dof_map());
683 
684  // Use the systems update() to get a good local version of the parallel solution
685  X_global.swap(X_sys);
686  Jac.swap(Jac_sys);
687 
689  sys.update();
690 
691  X_global.swap(X_sys);
692  Jac.swap(Jac_sys);
693 
694  the_pc.zero();
695 
696  // if the user has provided both function pointers and objects only the pointer
697  // will be used, so catch that as an error
698  libmesh_error_msg_if(sys.nonlinear_solver->jacobian && sys.nonlinear_solver->jacobian_object,
699  "ERROR: cannot specify both a function and object to compute the Jacobian!");
700 
701  libmesh_error_msg_if(sys.nonlinear_solver->matvec && sys.nonlinear_solver->residual_and_jacobian_object,
702  "ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!");
703 
704  if (sys.nonlinear_solver->jacobian != nullptr)
705  sys.nonlinear_solver->jacobian(*(sys.current_local_solution.get()), the_pc, sys);
706 
707  else if (sys.nonlinear_solver->jacobian_object != nullptr)
708  sys.nonlinear_solver->jacobian_object->jacobian(*(sys.current_local_solution.get()), the_pc, sys);
709 
710  else if (sys.nonlinear_solver->matvec != nullptr)
711  sys.nonlinear_solver->matvec(*(sys.current_local_solution.get()), nullptr, &the_pc, sys);
712 
713  else if (sys.nonlinear_solver->residual_and_jacobian_object != nullptr)
714  sys.nonlinear_solver->residual_and_jacobian_object->residual_and_jacobian(*(sys.current_local_solution.get()), nullptr, &the_pc, sys);
715 
716  else
717  libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");
718 
719  the_pc.close();
720  Jac.close();
721  X_global.close();
722  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
723 }
724 
725 #undef __FUNCT__
726 #define __FUNCT__ "SNESJacobian_DMlibMesh"
727 static PetscErrorCode SNESJacobian_DMlibMesh(SNES, Vec x, Mat jac, Mat pc, void * ctx)
728 {
729  DM dm = (DM)ctx;
730  PetscFunctionBegin;
731  LibmeshPetscCallQ(DMlibMeshJacobian(dm,x,jac,pc));
732  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
733 }
734 
735 #undef __FUNCT__
736 #define __FUNCT__ "DMVariableBounds_libMesh"
737 static PetscErrorCode DMVariableBounds_libMesh(DM dm, Vec xl, Vec xu)
738 {
741  NonlinearImplicitSystem & sys = *_sys;
742  PetscVector<Number> XL(xl, sys.comm());
743  PetscVector<Number> XU(xu, sys.comm());
744  PetscFunctionBegin;
745  // Workaround for nonstandard Q suffix warning with quad precision
746  const PetscReal petsc_inf = std::numeric_limits<PetscReal>::max() / 4;
747  LibmeshPetscCallQ(VecSet(xl, -petsc_inf));
748  LibmeshPetscCallQ(VecSet(xu, petsc_inf));
749  if (sys.nonlinear_solver->bounds != nullptr)
750  sys.nonlinear_solver->bounds(XL,XU,sys);
751  else if (sys.nonlinear_solver->bounds_object != nullptr)
752  sys.nonlinear_solver->bounds_object->bounds(XL,XU, sys);
753  else
754  SETERRQ(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "No bounds calculation in this libMesh object");
755 
756  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
757 }
758 
759 
760 #undef __FUNCT__
761 #define __FUNCT__ "DMCreateGlobalVector_libMesh"
762 static PetscErrorCode DMCreateGlobalVector_libMesh(DM dm, Vec *x)
763 {
764  PetscFunctionBegin;
765  DM_libMesh * dlm = (DM_libMesh *)(dm->data);
766  PetscBool eq;
767 
768  LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)dm, DMLIBMESH, &eq));
769 
770  if (!eq)
771  LIBMESH_SETERRQ2(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "DM of type %s, not of type %s", ((PetscObject)dm)->type_name, DMLIBMESH);
772 
773  if (!dlm->sys)
774  SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No libMesh system set for DM_libMesh");
775 
776  NumericVector<Number> * nv = (dlm->sys->solution).get();
777  PetscVector<Number> * pv = dynamic_cast<PetscVector<Number> *>(nv);
778  Vec v = pv->vec();
779  /* Unfortunately, currently this does not produce a ghosted vector, so nonlinear subproblem solves aren't going to be easily available.
780  Should work fine for getting vectors out for linear subproblem solvers. */
781  if (dlm->embedding) {
782  PetscInt n;
783  LibmeshPetscCallQ(VecCreate(((PetscObject)v)->comm, x));
784  LibmeshPetscCallQ(ISGetLocalSize(dlm->embedding, &n));
785  LibmeshPetscCallQ(VecSetSizes(*x,n,PETSC_DETERMINE));
786  LibmeshPetscCallQ(VecSetType(*x,((PetscObject)v)->type_name));
787  LibmeshPetscCallQ(VecSetFromOptions(*x));
788  LibmeshPetscCallQ(VecSetUp(*x));
789  }
790  else {
791  LibmeshPetscCallQ(VecDuplicate(v,x));
792  }
793 
794 #if PETSC_VERSION_LESS_THAN(3,13,0)
795  LibmeshPetscCallQ(PetscObjectCompose((PetscObject)*x,"DM",(PetscObject)dm));
796 #else
797  LibmeshPetscCallQ(VecSetDM(*x, dm));
798 #endif
799 
800  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
801 }
802 
803 
804 
805 
806 #undef __FUNCT__
807 #define __FUNCT__ "DMCreateMatrix_libMesh"
808 static PetscErrorCode DMCreateMatrix_libMesh(DM dm, Mat * A)
809 {
810  PetscFunctionBegin;
811  DM_libMesh * dlm = (DM_libMesh *)(dm->data);
812  PetscBool eq;
813 
814  LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)dm, DMLIBMESH, &eq));
815 
816  if (!eq)
817  LIBMESH_SETERRQ2(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "DM of type %s, not of type %s", ((PetscObject)dm)->type_name, DMLIBMESH);
818 
819  if (!dlm->sys)
820  SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No libMesh system set for DM_libMesh");
821 
822  *A = (dynamic_cast<PetscMatrixBase<Number> *>(dlm->sys->matrix))->mat();
823  LibmeshPetscCallQ(PetscObjectReference((PetscObject)(*A)));
824  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
825 }
826 
827 
828 #undef __FUNCT__
829 #define __FUNCT__ "DMView_libMesh"
830 static PetscErrorCode DMView_libMesh(DM dm, PetscViewer viewer)
831 {
832  PetscBool isascii;
833  const char * name, * prefix;
834  DM_libMesh * dlm = (DM_libMesh *)dm->data;
835  PetscFunctionBegin;
836  LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
837  if (isascii) {
838  LibmeshPetscCallQ(PetscObjectGetName((PetscObject)dm, &name));
839  LibmeshPetscCallQ(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
840  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "DM libMesh with name %s and prefix %s\n", name, prefix));
841  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "blocks:"));
842  std::map<std::string,unsigned int>::iterator bit = dlm->blockids->begin();
843  std::map<std::string,unsigned int>::const_iterator bend = dlm->blockids->end();
844  for (; bit != bend; ++bit) {
845  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "(%s,%d) ", bit->first.c_str(), bit->second));
846  }
847  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
848  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "variables:"));
849  std::map<std::string,unsigned int>::iterator vit = dlm->varids->begin();
850  std::map<std::string,unsigned int>::const_iterator vend = dlm->varids->end();
851  for (; vit != vend; ++vit) {
852  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "(%s,%d) ", vit->first.c_str(), vit->second));
853  }
854  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
855  if (dlm->decomposition_type == DMLIBMESH_NO_DECOMPOSITION) {
856  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "No decomposition\n"));
857  }
858  else {
859  if (dlm->decomposition_type == DMLIBMESH_FIELD_DECOMPOSITION) {
860  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "Field decomposition by variable: "));
861  }
862  else if (dlm->decomposition_type == DMLIBMESH_DOMAIN_DECOMPOSITION) {
863  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "Domain decomposition by block: "));
864  }
865  else LIBMESH_SETERRQ1(((PetscObject)dm)->comm, PETSC_ERR_PLIB, "Unexpected decomposition type: %d", dlm->decomposition_type);
866  /* FIX: decompositions might have different sizes and components on different ranks. */
867  for (auto d : index_range(*dlm->decomposition)) {
868  std::set<unsigned int>::iterator dbegin = (*dlm->decomposition)[d].begin();
869  std::set<unsigned int>::iterator dit = (*dlm->decomposition)[d].begin();
870  std::set<unsigned int>::iterator dend = (*dlm->decomposition)[d].end();
871  for (; dit != dend; ++dit) {
872  if (dit != dbegin) {
873  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, ","));
874  }
875  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "%u", *dit));
876  }
877  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, ";"));
878  }
879  LibmeshPetscCallQ(PetscViewerASCIIPrintf(viewer, "\n"));
880  }
881  }
882 
883  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
884 }
885 
886 #undef __FUNCT__
887 #define __FUNCT__ "DMSetUp_libMesh"
888 static PetscErrorCode DMSetUp_libMesh(DM dm)
889 {
890  PetscFunctionBegin;
891  DM_libMesh * dlm = (DM_libMesh *)(dm->data);
892  PetscBool eq;
893 
894  LibmeshPetscCallQ(PetscObjectTypeCompare((PetscObject)dm, DMLIBMESH, &eq));
895 
896  if (!eq)
897  LIBMESH_SETERRQ2(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "DM of type %s, not of type %s", ((PetscObject)dm)->type_name, DMLIBMESH);
898 
899  if (!dlm->sys)
900  SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "No libMesh system set for DM_libMesh");
901  /*
902  Do not evaluate function, Jacobian or bounds for an embedded DM -- the subproblem might not have enough information for that.
903  */
904  if (!dlm->embedding) {
905  LibmeshPetscCallQ(DMSNESSetFunction(dm, SNESFunction_DMlibMesh, (void *)dm));
906  LibmeshPetscCallQ(DMSNESSetJacobian(dm, SNESJacobian_DMlibMesh, (void *)dm));
907  if (dlm->sys->nonlinear_solver->bounds || dlm->sys->nonlinear_solver->bounds_object)
908  LibmeshPetscCallQ(DMSetVariableBounds(dm, DMVariableBounds_libMesh));
909  }
910  else {
911  /*
912  Fow now we don't implement even these, although a linear "Dirichlet" subproblem is well-defined.
913  Creating the submatrix, however, might require extracting the submatrix preallocation from an unassembled matrix.
914  */
915  dm->ops->createglobalvector = 0;
916  dm->ops->creatematrix = 0;
917  }
918  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
919 }
920 
921 
922 
923 
924 #undef __FUNCT__
925 #define __FUNCT__ "DMDestroy_libMesh"
926 static PetscErrorCode DMDestroy_libMesh(DM dm)
927 {
928  DM_libMesh * dlm = (DM_libMesh *)(dm->data);
929  PetscFunctionBegin;
930  delete dlm->varids;
931  delete dlm->varnames;
932  delete dlm->blockids;
933  delete dlm->blocknames;
934  delete dlm->decomposition;
935  LibmeshPetscCallQ(ISDestroy(&dlm->embedding));
936  LibmeshPetscCallQ(PetscFree(dm->data));
937 
938  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
939 }
940 
941 EXTERN_C_BEGIN
942 #undef __FUNCT__
943 #define __FUNCT__ "DMCreate_libMesh"
944 PetscErrorCode DMCreate_libMesh(DM dm)
945 {
946  DM_libMesh * dlm;
947 
948  PetscFunctionBegin;
949  PetscValidHeaderSpecific(dm,DM_CLASSID,1);
950  LibmeshPetscCallQ(PetscNew(&dlm));
951  dm->data = dlm;
952 
953  /* DMlibMesh impl */
954  dlm->varids = new(std::map<std::string, unsigned int>);
955  dlm->blockids = new(std::map<std::string, unsigned int>);
956  dlm->varnames = new(std::map<unsigned int, std::string>);
957  dlm->blocknames = new(std::map<unsigned int, std::string>);
958  dlm->decomposition = LIBMESH_PETSC_NULLPTR;
959  dlm->decomposition_type = DMLIBMESH_NO_DECOMPOSITION;
960 
961  /* DM API */
962  dm->ops->createglobalvector = DMCreateGlobalVector_libMesh;
963  dm->ops->createlocalvector = 0; // DMCreateLocalVector_libMesh;
964  dm->ops->getcoloring = 0; // DMGetColoring_libMesh;
965  dm->ops->creatematrix = DMCreateMatrix_libMesh;
966  dm->ops->createinterpolation= 0; // DMCreateInterpolation_libMesh;
967 
968  dm->ops->refine = 0; // DMRefine_libMesh;
969  dm->ops->coarsen = 0; // DMCoarsen_libMesh;
970 
971  // * dm->ops->getinjection was renamed to dm->ops->createinjection in PETSc 5a84ad338 (5 Jul 2019)
972  // * dm->ops-getaggregates was removed in PETSc 97779f9a (5 Jul 2019)
973  // * Both changes were merged into PETSc master in 94aad3ce (7 Jul 2019).
974 #if PETSC_VERSION_LESS_THAN(3,12,0)
975  dm->ops->getinjection = 0; // DMGetInjection_libMesh;
976  dm->ops->getaggregates = 0; // DMGetAggregates_libMesh;
977 #else
978  dm->ops->createinjection = 0;
979 #endif
980 
981 
982  dm->ops->createfielddecomposition = DMCreateFieldDecomposition_libMesh;
983  dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_libMesh;
984 
985  dm->ops->destroy = DMDestroy_libMesh;
986  dm->ops->view = DMView_libMesh;
987  dm->ops->setfromoptions = 0; // DMSetFromOptions_libMesh;
988  dm->ops->setup = DMSetUp_libMesh;
989 
990  /* DMlibMesh API */
991  LibmeshPetscCallQ(PetscObjectComposeFunction((PetscObject)dm,"DMlibMeshSetSystem_C",DMlibMeshSetSystem_libMesh));
992  LibmeshPetscCallQ(PetscObjectComposeFunction((PetscObject)dm,"DMlibMeshGetSystem_C",DMlibMeshGetSystem_libMesh));
993 
994  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
995 }
996 EXTERN_C_END
997 
998 #endif // LIBMESH_HAVE_PETSC
static PetscErrorCode SNESFunction_DMlibMesh(SNES, Vec x, Vec r, void *ctx)
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
static PetscErrorCode SNESJacobian_DMlibMesh(SNES, Vec x, Mat jac, Mat pc, void *ctx)
static PetscErrorCode DMVariableBounds_libMesh(DM dm, Vec xl, Vec xu)
static PetscErrorCode DMCreateDomainDecomposition_libMesh(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
dof_id_type end_dof(const processor_id_type proc) const
Definition: dof_map_base.h:191
NonlinearImplicitSystem * sys
This class provides a nice interface to PETSc&#39;s Vec object.
Definition: petsc_vector.h:73
static PetscErrorCode DMCreateGlobalVector_libMesh(DM dm, Vec *x)
std::unique_ptr< NonlinearSolver< Number > > nonlinear_solver
The NonlinearSolver defines the default interface used to solve the nonlinear_implicit system...
void swap(PetscMatrixBase< T > &)
Swaps the internal data pointers of two PetscMatrices, no actual values are swapped.
PetscErrorCode DMlibMeshSetUpName_Private(DM dm)
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition: dof_map.C:2164
The definition of the const_element_iterator struct.
Definition: mesh_base.h:2216
unsigned int embedding_type
const char * s
std::map< std::string, unsigned int > * blockids
PetscErrorCode DMlibMeshSetSystem_libMesh(DM dm, NonlinearImplicitSystem &sys)
std::map< std::string, unsigned int > * varids
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
static PetscErrorCode DMCreateMatrix_libMesh(DM dm, Mat *A)
static PetscErrorCode DMCreateFieldDecomposition_libMesh(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
NumericVector< Number > * rhs
The system matrix.
const Parallel::Communicator & comm() const
static PetscMatrixBase< T > * get_context(Mat mat, const TIMPI::Communicator &comm)
PETSC_EXTERN PetscErrorCode DMlibMeshGetSystem(DM, libMesh::NonlinearImplicitSystem *&)
The libMesh namespace provides an interface to certain functionality in the library.
PetscErrorCode DMlibMeshGetBlocks(DM dm, PetscInt *n, char ***blocknames)
const MeshBase & get_mesh() const
Definition: system.h:2358
This is the MeshBase class.
Definition: mesh_base.h:75
const Variable & variable(const unsigned int c) const override
Definition: dof_map.h:2190
virtual void swap(NumericVector< T > &v) override
Swaps the contents of this with v.
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
std::vector< std::set< unsigned int > > * decomposition
PetscErrorCode DMCreate_libMesh(DM dm)
static PetscErrorCode DMSetUp_libMesh(DM dm)
struct token * next
PetscErrorCode DMlibMeshCreateFieldDecompositionDM(DM dm, PetscInt dnumber, PetscInt *dsizes, char ***dvarlists, DM *ddm)
virtual void zero()=0
Set all entries to 0.
dof_id_type numeric_index_type
Definition: id_types.h:99
static PetscErrorCode DMlibMeshFunction(DM dm, Vec x, Vec r)
PetscErrorCode DMlibMeshGetSystem_libMesh(DM dm, NonlinearImplicitSystem *&sys)
unsigned int n_variables() const override
Definition: dof_map.h:628
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
Definition: simple_range.h:57
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1593
std::map< unsigned int, std::string > * varnames
libmesh_assert(ctx)
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and non-linear solv...
std::map< unsigned int, std::string > * blocknames
std::string & subdomain_name(subdomain_id_type id)
Definition: mesh_base.C:1692
unsigned int vec_count
virtual void close() override
Calls the SparseMatrix&#39;s internal assembly routines, ensuring that the values are consistent across p...
std::string label
PetscErrorCode DMlibMeshGetVec_Private(DM, const char *, Vec *)
void attach_dof_map(const DofMap &dof_map)
Set a pointer to the DofMap to use.
Definition: sparse_matrix.C:72
LibmeshPetscCallQ(DMShellGetContext(dm, &ctx))
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition: system.C:510
static PetscErrorCode DMlibMeshJacobian(DM dm, Vec x, Mat jac, Mat pc)
SparseMatrix< Number > * matrix
The system matrix.
PetscErrorCode DMlibMeshGetVariables(DM dm, PetscInt *n, char ***varnames)
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition: int_range.h:140
std::unique_ptr< NumericVector< Number > > current_local_solution
All the values I need to compute my contribution to the simulation at hand.
Definition: system.h:1605
PetscErrorCode DMlibMeshCreateDomainDecompositionDM(DM dm, PetscInt dnumber, PetscInt *dsizes, char ***dblocklists, DM *ddm)
void * ctx
const std::string & name() const
Definition: variable.h:122
const std::string & name() const
Definition: system.h:2342
dof_id_type first_dof(const processor_id_type proc) const
Definition: dof_map_base.h:185
PetscFunctionReturn(LIBMESH_PETSC_SUCCESS)
const DofMap & get_dof_map() const
Definition: system.h:2374
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:117
static PetscErrorCode DMView_libMesh(DM dm, PetscViewer viewer)
unsigned int decomposition_type
static PetscErrorCode DMDestroy_libMesh(DM dm)
void enforce_constraints_exactly(const System &system, NumericVector< Number > *v=nullptr, bool homogeneous=false) const
Constrains the numeric vector v, which represents a solution defined on the mesh. ...
Definition: dof_map.h:2350
void set_union(T &data, const unsigned int root_id) const