//! Help PETSc identify the coarser DM dmc given the fine DM dmf PetscErrorCode libmesh_petsc_DMCoarsen(DM dmf, MPI_Comm /*comm*/, DM * dmc) { libmesh_assert(dmc); libmesh_assert(dmf); PetscErrorCode ierr; // Extract our context from the incoming dmf void * ctx_f = nullptr; ierr = DMShellGetContext(dmf, &ctx_f);LIBMESH_CHKERR(ierr); libmesh_assert(ctx_f); PetscDMContext * p_ctx = static_cast<PetscDMContext*>(ctx_f); // First, ensure that there exists a coarse DM that we want to // set. There ought to be as we created it while walking the // hierarchy. libmesh_assert(p_ctx->coarser_dm); libmesh_assert(*(p_ctx->coarser_dm)); // In situations using fieldsplit we need to (potentially) // provide a coarser DM which only has the relevant subfields in // it. Since we create global DMs for each mesh level, we need // to extract the section from the DM, and check the number of // fields. When less than all the fields are used, we need to // create the proper subsections. // Get the number of fields and their names from the incomming // fine DM and the global reference DM PetscInt nfieldsf, nfieldsg; char ** fieldnamesf; char ** fieldnamesg; libmesh_assert(p_ctx->global_dm); DM * globaldm = p_ctx->global_dm; ierr = DMCreateFieldIS(dmf, &nfieldsf, &fieldnamesf, nullptr); LIBMESH_CHKERR(ierr); ierr = DMCreateFieldIS(*globaldm, &nfieldsg, &fieldnamesg, nullptr); LIBMESH_CHKERR(ierr); // If the probed number of fields is less than the number of // global fields, this amounts to PETSc 'indicating' to us we // are doing FS. So, we must create subsections for the coarser // DMs. if ( nfieldsf < nfieldsg ) { PetscSection section; PetscSection subsection; std::vector<PetscInt> subfields(nfieldsf); // extracted fields // First, get the section from the coarse DM #if PETSC_VERSION_LESS_THAN(3,10,0) ierr = DMGetDefaultSection(*(p_ctx->coarser_dm), §ion); #else ierr = DMGetSection(*(p_ctx->coarser_dm), §ion); #endif LIBMESH_CHKERR(ierr); // Now, match fine grid DM field names to their global DM // counterparts. Since PETSc can internally reassign field // numbering under a fieldsplit, we must extract // subsections via the field names. This is admittedly // gross, but c'est la vie. for (int i = 0; i < nfieldsf ; i++) { for (int j = 0; j < nfieldsg ;j++) if ( strcmp( fieldnamesg[j], fieldnamesf[i] ) == 0 ) subfields[i] = j; } // Next, for the found fields we now make a subsection and set it for the coarser DM ierr = PetscSectionCreateSubsection(section, nfieldsf, subfields.data(), &subsection); LIBMESH_CHKERR(ierr); #if PETSC_VERSION_LESS_THAN(3,10,0) ierr = DMSetDefaultSection(*(p_ctx->coarser_dm) , subsection); #else ierr = DMSetSection(*(p_ctx->coarser_dm) , subsection); #endif LIBMESH_CHKERR(ierr); ierr = PetscSectionDestroy(&subsection); LIBMESH_CHKERR(ierr); } // Finally, set the coarser DM *(dmc) = *(p_ctx->coarser_dm); return 0; }
GEN subfields0(GEN nf,GEN d) { return d? subfields(nf,d): subfieldsall(nf); }