LCOV - code coverage report
Current view: top level - src/solvers - petscdmlibmeshimpl.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4624 (b6265e) with base 1fb77f Lines: 242 551 43.9 %
Date: 2026-11-03 16:49:57 Functions: 14 29 48.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14