xref: /petsc/src/dm/interface/dmi.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
1af0996ceSBarry Smith #include <petsc/private/dmimpl.h> /*I      "petscdm.h"     I*/
22764a2aaSMatthew G. Knepley #include <petscds.h>
311689aebSJed Brown 
45b8243e1SJed Brown // Greatest common divisor of two nonnegative integers
5*d71ae5a4SJacob Faibussowitsch PetscInt PetscGCD(PetscInt a, PetscInt b)
6*d71ae5a4SJacob Faibussowitsch {
75b8243e1SJed Brown   while (b != 0) {
85b8243e1SJed Brown     PetscInt tmp = b;
95b8243e1SJed Brown     b            = a % b;
105b8243e1SJed Brown     a            = tmp;
115b8243e1SJed Brown   }
125b8243e1SJed Brown   return a;
135b8243e1SJed Brown }
145b8243e1SJed Brown 
15*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateGlobalVector_Section_Private(DM dm, Vec *vec)
16*d71ae5a4SJacob Faibussowitsch {
1711689aebSJed Brown   PetscSection gSection;
18cc30b04dSMatthew G Knepley   PetscInt     localSize, bs, blockSize = -1, pStart, pEnd, p;
195d1c0279SHong Zhang   PetscInt     in[2], out[2];
2011689aebSJed Brown 
2111689aebSJed Brown   PetscFunctionBegin;
229566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &gSection));
239566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(gSection, &pStart, &pEnd));
2411689aebSJed Brown   for (p = pStart; p < pEnd; ++p) {
2511689aebSJed Brown     PetscInt dof, cdof;
2611689aebSJed Brown 
279566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(gSection, p, &dof));
289566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(gSection, p, &cdof));
290680ce0aSHong Zhang 
305b8243e1SJed Brown     if (dof - cdof > 0) {
315b8243e1SJed Brown       if (blockSize < 0) {
320680ce0aSHong Zhang         /* set blockSize */
330680ce0aSHong Zhang         blockSize = dof - cdof;
345b8243e1SJed Brown       } else {
355b8243e1SJed Brown         blockSize = PetscGCD(dof - cdof, blockSize);
3611689aebSJed Brown       }
3711689aebSJed Brown     }
380680ce0aSHong Zhang   }
395d1c0279SHong Zhang 
402c8be454SMatthew G. Knepley   in[0] = blockSize < 0 ? PETSC_MIN_INT : -blockSize;
415d1c0279SHong Zhang   in[1] = blockSize;
421c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
435d1c0279SHong Zhang   /* -out[0] = min(blockSize), out[1] = max(blockSize) */
445d1c0279SHong Zhang   if (-out[0] == out[1]) {
455d1c0279SHong Zhang     bs = out[1];
465d1c0279SHong Zhang   } else bs = 1;
475d1c0279SHong Zhang 
485d1c0279SHong Zhang   if (bs < 0) { /* Everyone was empty */
495d1c0279SHong Zhang     blockSize = 1;
505d1c0279SHong Zhang     bs        = 1;
515d1c0279SHong Zhang   }
525d1c0279SHong Zhang 
539566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gSection, &localSize));
547a8be351SBarry Smith   PetscCheck(localSize % blockSize == 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mismatch between blocksize %" PetscInt_FMT " and local storage size %" PetscInt_FMT, blockSize, localSize);
559566063dSJacob Faibussowitsch   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), vec));
569566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*vec, localSize, PETSC_DETERMINE));
579566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(*vec, bs));
589566063dSJacob Faibussowitsch   PetscCall(VecSetType(*vec, dm->vectype));
599566063dSJacob Faibussowitsch   PetscCall(VecSetDM(*vec, dm));
609566063dSJacob Faibussowitsch   /* PetscCall(VecSetLocalToGlobalMapping(*vec, dm->ltogmap)); */
6111689aebSJed Brown   PetscFunctionReturn(0);
6211689aebSJed Brown }
6311689aebSJed Brown 
64*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateLocalVector_Section_Private(DM dm, Vec *vec)
65*d71ae5a4SJacob Faibussowitsch {
66fad22124SMatthew G Knepley   PetscSection section;
6711689aebSJed Brown   PetscInt     localSize, blockSize = -1, pStart, pEnd, p;
6811689aebSJed Brown 
6911689aebSJed Brown   PetscFunctionBegin;
709566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
719566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
7211689aebSJed Brown   for (p = pStart; p < pEnd; ++p) {
7311689aebSJed Brown     PetscInt dof;
7411689aebSJed Brown 
759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
7611689aebSJed Brown     if ((blockSize < 0) && (dof > 0)) blockSize = dof;
775b8243e1SJed Brown     if (dof > 0) blockSize = PetscGCD(dof, blockSize);
7811689aebSJed Brown   }
799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &localSize));
809566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, vec));
819566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(*vec, localSize, localSize));
829566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(*vec, blockSize));
839566063dSJacob Faibussowitsch   PetscCall(VecSetType(*vec, dm->vectype));
849566063dSJacob Faibussowitsch   PetscCall(VecSetDM(*vec, dm));
8511689aebSJed Brown   PetscFunctionReturn(0);
8611689aebSJed Brown }
874d9407bcSMatthew G. Knepley 
88792b654fSMatthew G. Knepley /*@C
89792b654fSMatthew G. Knepley   DMCreateSectionSubDM - Returns an IS and subDM+subSection encapsulating a subproblem defined by the fields in a PetscSection in the DM.
90792b654fSMatthew G. Knepley 
91792b654fSMatthew G. Knepley   Not collective
92792b654fSMatthew G. Knepley 
93792b654fSMatthew G. Knepley   Input Parameters:
94792b654fSMatthew G. Knepley + dm        - The DM object
95792b654fSMatthew G. Knepley . numFields - The number of fields in this subproblem
96792b654fSMatthew G. Knepley - fields    - The field numbers of the selected fields
97792b654fSMatthew G. Knepley 
98792b654fSMatthew G. Knepley   Output Parameters:
99792b654fSMatthew G. Knepley + is - The global indices for the subproblem
100792b654fSMatthew G. Knepley - subdm - The DM for the subproblem, which must already have be cloned from dm
101792b654fSMatthew G. Knepley 
102792b654fSMatthew G. Knepley   Note: This handles all information in the DM class and the PetscSection. This is used as the basis for creating subDMs in specialized classes,
103792b654fSMatthew G. Knepley   such as Plex and Forest.
104792b654fSMatthew G. Knepley 
105792b654fSMatthew G. Knepley   Level: intermediate
106792b654fSMatthew G. Knepley 
107db781477SPatrick Sanan .seealso `DMCreateSubDM()`, `DMGetLocalSection()`, `DMPlexSetMigrationSF()`, `DMView()`
108792b654fSMatthew G. Knepley @*/
109*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSectionSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
110*d71ae5a4SJacob Faibussowitsch {
1114d9407bcSMatthew G. Knepley   PetscSection section, sectionGlobal;
1124d9407bcSMatthew G. Knepley   PetscInt    *subIndices;
113696188eaSMatthew G. Knepley   PetscInt     subSize = 0, subOff = 0, Nf, f, pStart, pEnd, p;
1144d9407bcSMatthew G. Knepley 
1154d9407bcSMatthew G. Knepley   PetscFunctionBegin;
1164d9407bcSMatthew G. Knepley   if (!numFields) PetscFunctionReturn(0);
1179566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
1189566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
1197a8be351SBarry Smith   PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting fields");
1207a8be351SBarry Smith   PetscCheck(sectionGlobal, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DM before splitting fields");
1219566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
1227a8be351SBarry Smith   PetscCheck(numFields <= Nf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Number of requested fields %" PetscInt_FMT " greater than number of DM fields %" PetscInt_FMT, numFields, Nf);
1234d9407bcSMatthew G. Knepley   if (is) {
1243a544194SStefano Zampini     PetscInt bs, bsLocal[2], bsMinMax[2];
1253a544194SStefano Zampini 
1263a544194SStefano Zampini     for (f = 0, bs = 0; f < numFields; ++f) {
1273a544194SStefano Zampini       PetscInt Nc;
1283a544194SStefano Zampini 
1299566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldComponents(section, fields[f], &Nc));
1303a544194SStefano Zampini       bs += Nc;
1313a544194SStefano Zampini     }
1329566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
1334d9407bcSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
134b9eca265Ssarens       PetscInt gdof, pSubSize = 0;
1354d9407bcSMatthew G. Knepley 
1369566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
1374d9407bcSMatthew G. Knepley       if (gdof > 0) {
1384d9407bcSMatthew G. Knepley         for (f = 0; f < numFields; ++f) {
1394d9407bcSMatthew G. Knepley           PetscInt fdof, fcdof;
1404d9407bcSMatthew G. Knepley 
1419566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, fields[f], &fdof));
1429566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof));
143b9eca265Ssarens           pSubSize += fdof - fcdof;
144b9eca265Ssarens         }
145b9eca265Ssarens         subSize += pSubSize;
1463a544194SStefano Zampini         if (pSubSize && bs != pSubSize) {
147b9eca265Ssarens           /* Layout does not admit a pointwise block size */
148b9eca265Ssarens           bs = 1;
1494d9407bcSMatthew G. Knepley         }
1504d9407bcSMatthew G. Knepley       }
1514d9407bcSMatthew G. Knepley     }
152b9eca265Ssarens     /* Must have same blocksize on all procs (some might have no points) */
1539371c9d4SSatish Balay     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
1549371c9d4SSatish Balay     bsLocal[1] = bs;
1559566063dSJacob Faibussowitsch     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
1569371c9d4SSatish Balay     if (bsMinMax[0] != bsMinMax[1]) {
1579371c9d4SSatish Balay       bs = 1;
1589371c9d4SSatish Balay     } else {
1599371c9d4SSatish Balay       bs = bsMinMax[0];
1609371c9d4SSatish Balay     }
1619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(subSize, &subIndices));
1624d9407bcSMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
1634d9407bcSMatthew G. Knepley       PetscInt gdof, goff;
1644d9407bcSMatthew G. Knepley 
1659566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
1664d9407bcSMatthew G. Knepley       if (gdof > 0) {
1679566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &goff));
1684d9407bcSMatthew G. Knepley         for (f = 0; f < numFields; ++f) {
1694d9407bcSMatthew G. Knepley           PetscInt fdof, fcdof, fc, f2, poff = 0;
1704d9407bcSMatthew G. Knepley 
1714d9407bcSMatthew G. Knepley           /* Can get rid of this loop by storing field information in the global section */
1724d9407bcSMatthew G. Knepley           for (f2 = 0; f2 < fields[f]; ++f2) {
1739566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof));
1749566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof));
1754d9407bcSMatthew G. Knepley             poff += fdof - fcdof;
1764d9407bcSMatthew G. Knepley           }
1779566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(section, p, fields[f], &fdof));
1789566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof));
179ad540459SPierre Jolivet           for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc;
1804d9407bcSMatthew G. Knepley         }
1814d9407bcSMatthew G. Knepley       }
1824d9407bcSMatthew G. Knepley     }
1839566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is));
184627349f5SMatthew G. Knepley     if (bs > 1) {
185627349f5SMatthew G. Knepley       /* We need to check that the block size does not come from non-contiguous fields */
18688206212SAlexis Marboeuf       PetscInt i, j, set = 1, rset = 1;
187627349f5SMatthew G. Knepley       for (i = 0; i < subSize; i += bs) {
188627349f5SMatthew G. Knepley         for (j = 0; j < bs; ++j) {
1899371c9d4SSatish Balay           if (subIndices[i + j] != subIndices[i] + j) {
1909371c9d4SSatish Balay             set = 0;
1919371c9d4SSatish Balay             break;
1929371c9d4SSatish Balay           }
193627349f5SMatthew G. Knepley         }
194627349f5SMatthew G. Knepley       }
19588206212SAlexis Marboeuf       PetscCallMPI(MPI_Allreduce(&set, &rset, 1, MPIU_INT, MPI_PROD, PetscObjectComm((PetscObject)dm)));
19688206212SAlexis Marboeuf       if (rset) PetscCall(ISSetBlockSize(*is, bs));
197627349f5SMatthew G. Knepley     }
1984d9407bcSMatthew G. Knepley   }
1994d9407bcSMatthew G. Knepley   if (subdm) {
2004d9407bcSMatthew G. Knepley     PetscSection subsection;
2014d9407bcSMatthew G. Knepley     PetscBool    haveNull = PETSC_FALSE;
2028cda7954SMatthew G. Knepley     PetscInt     f, nf = 0, of = 0;
2034d9407bcSMatthew G. Knepley 
2049566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreateSubsection(section, numFields, fields, &subsection));
2059566063dSJacob Faibussowitsch     PetscCall(DMSetLocalSection(*subdm, subsection));
2069566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&subsection));
2074d9407bcSMatthew G. Knepley     for (f = 0; f < numFields; ++f) {
2084d9407bcSMatthew G. Knepley       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
2094d9407bcSMatthew G. Knepley       if ((*subdm)->nullspaceConstructors[f]) {
2104d9407bcSMatthew G. Knepley         haveNull = PETSC_TRUE;
2114d9407bcSMatthew G. Knepley         nf       = f;
2128cda7954SMatthew G. Knepley         of       = fields[f];
2134d9407bcSMatthew G. Knepley       }
2144d9407bcSMatthew G. Knepley     }
215e5e52638SMatthew G. Knepley     if (dm->probs) {
2169566063dSJacob Faibussowitsch       PetscCall(DMSetNumFields(*subdm, numFields));
2174d9407bcSMatthew G. Knepley       for (f = 0; f < numFields; ++f) {
2180f21e855SMatthew G. Knepley         PetscObject disc;
2190f21e855SMatthew G. Knepley 
2209566063dSJacob Faibussowitsch         PetscCall(DMGetField(dm, fields[f], NULL, &disc));
2219566063dSJacob Faibussowitsch         PetscCall(DMSetField(*subdm, f, NULL, disc));
2224d9407bcSMatthew G. Knepley       }
2239566063dSJacob Faibussowitsch       PetscCall(DMCreateDS(*subdm));
224f646a522SMatthew G. Knepley       if (numFields == 1 && is) {
2250f21e855SMatthew G. Knepley         PetscObject disc, space, pmat;
2264d9407bcSMatthew G. Knepley 
2279566063dSJacob Faibussowitsch         PetscCall(DMGetField(*subdm, 0, NULL, &disc));
2289566063dSJacob Faibussowitsch         PetscCall(PetscObjectQuery(disc, "nullspace", &space));
2299566063dSJacob Faibussowitsch         if (space) PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", space));
2309566063dSJacob Faibussowitsch         PetscCall(PetscObjectQuery(disc, "nearnullspace", &space));
2319566063dSJacob Faibussowitsch         if (space) PetscCall(PetscObjectCompose((PetscObject)*is, "nearnullspace", space));
2329566063dSJacob Faibussowitsch         PetscCall(PetscObjectQuery(disc, "pmat", &pmat));
2339566063dSJacob Faibussowitsch         if (pmat) PetscCall(PetscObjectCompose((PetscObject)*is, "pmat", pmat));
2344d9407bcSMatthew G. Knepley       }
2359310035eSMatthew G. Knepley       /* Check if DSes record their DM fields */
236e21d936aSMatthew G. Knepley       if (dm->probs[0].fields) {
2379310035eSMatthew G. Knepley         PetscInt d, e;
2389310035eSMatthew G. Knepley 
2399310035eSMatthew G. Knepley         for (d = 0, e = 0; d < dm->Nds && e < (*subdm)->Nds; ++d) {
2409310035eSMatthew G. Knepley           const PetscInt  Nf = dm->probs[d].ds->Nf;
2419310035eSMatthew G. Knepley           const PetscInt *fld;
2429310035eSMatthew G. Knepley           PetscInt        f, g;
2439310035eSMatthew G. Knepley 
2449566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(dm->probs[d].fields, &fld));
2459310035eSMatthew G. Knepley           for (f = 0; f < Nf; ++f) {
2469371c9d4SSatish Balay             for (g = 0; g < numFields; ++g)
2479371c9d4SSatish Balay               if (fld[f] == fields[g]) break;
2489310035eSMatthew G. Knepley             if (g < numFields) break;
2499310035eSMatthew G. Knepley           }
2509566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(dm->probs[d].fields, &fld));
2519310035eSMatthew G. Knepley           if (f == Nf) continue;
2529566063dSJacob Faibussowitsch           PetscCall(PetscDSCopyConstants(dm->probs[d].ds, (*subdm)->probs[e].ds));
2539566063dSJacob Faibussowitsch           PetscCall(PetscDSCopyBoundary(dm->probs[d].ds, numFields, fields, (*subdm)->probs[e].ds));
2549310035eSMatthew G. Knepley           /* Translate DM fields to DS fields */
2559310035eSMatthew G. Knepley           {
256e21d936aSMatthew G. Knepley             IS              infields, dsfields;
25774a61aaaSMatthew G. Knepley             const PetscInt *fld, *ofld;
25874a61aaaSMatthew G. Knepley             PetscInt       *fidx;
25974a61aaaSMatthew G. Knepley             PetscInt        onf, nf, f, g;
260e21d936aSMatthew G. Knepley 
2619566063dSJacob Faibussowitsch             PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numFields, fields, PETSC_USE_POINTER, &infields));
2629566063dSJacob Faibussowitsch             PetscCall(ISIntersect(infields, dm->probs[d].fields, &dsfields));
2639566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&infields));
2649566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(dsfields, &nf));
2657a8be351SBarry Smith             PetscCheck(nf, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DS cannot be supported on 0 fields");
2669566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(dsfields, &fld));
2679566063dSJacob Faibussowitsch             PetscCall(ISGetLocalSize(dm->probs[d].fields, &onf));
2689566063dSJacob Faibussowitsch             PetscCall(ISGetIndices(dm->probs[d].fields, &ofld));
2699566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(nf, &fidx));
2703268a0aaSMatthew G. Knepley             for (f = 0, g = 0; f < onf && g < nf; ++f) {
27174a61aaaSMatthew G. Knepley               if (ofld[f] == fld[g]) fidx[g++] = f;
27274a61aaaSMatthew G. Knepley             }
2739566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(dm->probs[d].fields, &ofld));
2749566063dSJacob Faibussowitsch             PetscCall(ISRestoreIndices(dsfields, &fld));
2759566063dSJacob Faibussowitsch             PetscCall(ISDestroy(&dsfields));
2769566063dSJacob Faibussowitsch             PetscCall(PetscDSSelectDiscretizations(dm->probs[0].ds, nf, fidx, (*subdm)->probs[0].ds));
2779566063dSJacob Faibussowitsch             PetscCall(PetscDSSelectEquations(dm->probs[0].ds, nf, fidx, (*subdm)->probs[0].ds));
2789566063dSJacob Faibussowitsch             PetscCall(PetscFree(fidx));
2799310035eSMatthew G. Knepley           }
2809310035eSMatthew G. Knepley           ++e;
2819310035eSMatthew G. Knepley         }
282e21d936aSMatthew G. Knepley       } else {
2839566063dSJacob Faibussowitsch         PetscCall(PetscDSCopyConstants(dm->probs[0].ds, (*subdm)->probs[0].ds));
2849566063dSJacob Faibussowitsch         PetscCall(PetscDSCopyBoundary(dm->probs[0].ds, PETSC_DETERMINE, NULL, (*subdm)->probs[0].ds));
2859566063dSJacob Faibussowitsch         PetscCall(PetscDSSelectDiscretizations(dm->probs[0].ds, numFields, fields, (*subdm)->probs[0].ds));
2869566063dSJacob Faibussowitsch         PetscCall(PetscDSSelectEquations(dm->probs[0].ds, numFields, fields, (*subdm)->probs[0].ds));
287d5af271aSMatthew G. Knepley       }
288e21d936aSMatthew G. Knepley     }
2898cda7954SMatthew G. Knepley     if (haveNull && is) {
2908cda7954SMatthew G. Knepley       MatNullSpace nullSpace;
2918cda7954SMatthew G. Knepley 
2929566063dSJacob Faibussowitsch       PetscCall((*(*subdm)->nullspaceConstructors[nf])(*subdm, of, nf, &nullSpace));
2939566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace));
2949566063dSJacob Faibussowitsch       PetscCall(MatNullSpaceDestroy(&nullSpace));
2958cda7954SMatthew G. Knepley     }
29648a46eb9SPierre Jolivet     if (dm->coarseMesh) PetscCall(DMCreateSubDM(dm->coarseMesh, numFields, fields, NULL, &(*subdm)->coarseMesh));
2974d9407bcSMatthew G. Knepley   }
2984d9407bcSMatthew G. Knepley   PetscFunctionReturn(0);
2994d9407bcSMatthew G. Knepley }
3002adcc780SMatthew G. Knepley 
301792b654fSMatthew G. Knepley /*@C
302792b654fSMatthew G. Knepley   DMCreateSectionSuperDM - Returns an arrays of ISes and DM+Section encapsulating a superproblem defined by the DM+Sections passed in.
303792b654fSMatthew G. Knepley 
304792b654fSMatthew G. Knepley   Not collective
305792b654fSMatthew G. Knepley 
306d8d19677SJose E. Roman   Input Parameters:
307792b654fSMatthew G. Knepley + dms - The DM objects
308792b654fSMatthew G. Knepley - len - The number of DMs
309792b654fSMatthew G. Knepley 
310792b654fSMatthew G. Knepley   Output Parameters:
311792b654fSMatthew G. Knepley + is - The global indices for the subproblem, or NULL
312792b654fSMatthew G. Knepley - superdm - The DM for the superproblem, which must already have be cloned
313792b654fSMatthew G. Knepley 
314792b654fSMatthew G. Knepley   Note: This handles all information in the DM class and the PetscSection. This is used as the basis for creating subDMs in specialized classes,
315792b654fSMatthew G. Knepley   such as Plex and Forest.
316792b654fSMatthew G. Knepley 
317792b654fSMatthew G. Knepley   Level: intermediate
318792b654fSMatthew G. Knepley 
319db781477SPatrick Sanan .seealso `DMCreateSuperDM()`, `DMGetLocalSection()`, `DMPlexSetMigrationSF()`, `DMView()`
320792b654fSMatthew G. Knepley @*/
321*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateSectionSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
322*d71ae5a4SJacob Faibussowitsch {
3239796d432SMatthew G. Knepley   MPI_Comm     comm;
3249796d432SMatthew G. Knepley   PetscSection supersection, *sections, *sectionGlobals;
3258cda7954SMatthew G. Knepley   PetscInt    *Nfs, Nf = 0, f, supf, oldf = -1, nullf = -1, i;
3269796d432SMatthew G. Knepley   PetscBool    haveNull = PETSC_FALSE;
3272adcc780SMatthew G. Knepley 
3282adcc780SMatthew G. Knepley   PetscFunctionBegin;
3299566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dms[0], &comm));
3309796d432SMatthew G. Knepley   /* Pull out local and global sections */
3319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(len, &Nfs, len, &sections, len, &sectionGlobals));
3322adcc780SMatthew G. Knepley   for (i = 0; i < len; ++i) {
3339566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dms[i], &sections[i]));
3349566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(dms[i], &sectionGlobals[i]));
3357a8be351SBarry Smith     PetscCheck(sections[i], comm, PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting fields");
3367a8be351SBarry Smith     PetscCheck(sectionGlobals[i], comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DM before splitting fields");
3379566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(sections[i], &Nfs[i]));
3382adcc780SMatthew G. Knepley     Nf += Nfs[i];
3392adcc780SMatthew G. Knepley   }
3409796d432SMatthew G. Knepley   /* Create the supersection */
3419566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreateSupersection(sections, len, &supersection));
3429566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(*superdm, supersection));
3439796d432SMatthew G. Knepley   /* Create ISes */
3442adcc780SMatthew G. Knepley   if (is) {
3459796d432SMatthew G. Knepley     PetscSection supersectionGlobal;
3469796d432SMatthew G. Knepley     PetscInt     bs = -1, startf = 0;
3472adcc780SMatthew G. Knepley 
3489566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(len, is));
3499566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalSection(*superdm, &supersectionGlobal));
3509796d432SMatthew G. Knepley     for (i = 0; i < len; startf += Nfs[i], ++i) {
3519796d432SMatthew G. Knepley       PetscInt *subIndices;
352ec4c761aSMatthew G. Knepley       PetscInt  subSize, subOff, pStart, pEnd, p, start, end, dummy;
3532adcc780SMatthew G. Knepley 
3549566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetChart(sectionGlobals[i], &pStart, &pEnd));
3559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobals[i], &subSize));
3569566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(subSize, &subIndices));
3579796d432SMatthew G. Knepley       for (p = pStart, subOff = 0; p < pEnd; ++p) {
3589796d432SMatthew G. Knepley         PetscInt gdof, gcdof, gtdof, d;
3592adcc780SMatthew G. Knepley 
3609566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(sectionGlobals[i], p, &gdof));
3619566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintDof(sections[i], p, &gcdof));
3622adcc780SMatthew G. Knepley         gtdof = gdof - gcdof;
3632adcc780SMatthew G. Knepley         if (gdof > 0 && gtdof) {
3649371c9d4SSatish Balay           if (bs < 0) {
3659371c9d4SSatish Balay             bs = gtdof;
3669371c9d4SSatish Balay           } else if (bs != gtdof) {
3679371c9d4SSatish Balay             bs = 1;
3689371c9d4SSatish Balay           }
3699566063dSJacob Faibussowitsch           PetscCall(DMGetGlobalFieldOffset_Private(*superdm, p, startf, &start, &dummy));
3709566063dSJacob Faibussowitsch           PetscCall(DMGetGlobalFieldOffset_Private(*superdm, p, startf + Nfs[i] - 1, &dummy, &end));
37163a3b9bcSJacob Faibussowitsch           PetscCheck(end - start == gtdof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Invalid number of global dofs %" PetscInt_FMT " != %" PetscInt_FMT " for dm %" PetscInt_FMT " on point %" PetscInt_FMT, end - start, gtdof, i, p);
3729796d432SMatthew G. Knepley           for (d = start; d < end; ++d, ++subOff) subIndices[subOff] = d;
3732adcc780SMatthew G. Knepley         }
3742adcc780SMatthew G. Knepley       }
3759566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, subSize, subIndices, PETSC_OWN_POINTER, &(*is)[i]));
3762adcc780SMatthew G. Knepley       /* Must have same blocksize on all procs (some might have no points) */
3779796d432SMatthew G. Knepley       {
3789796d432SMatthew G. Knepley         PetscInt bs = -1, bsLocal[2], bsMinMax[2];
3799796d432SMatthew G. Knepley 
3809371c9d4SSatish Balay         bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
3819371c9d4SSatish Balay         bsLocal[1] = bs;
3829566063dSJacob Faibussowitsch         PetscCall(PetscGlobalMinMaxInt(comm, bsLocal, bsMinMax));
3839371c9d4SSatish Balay         if (bsMinMax[0] != bsMinMax[1]) {
3849371c9d4SSatish Balay           bs = 1;
3859371c9d4SSatish Balay         } else {
3869371c9d4SSatish Balay           bs = bsMinMax[0];
3879371c9d4SSatish Balay         }
3889566063dSJacob Faibussowitsch         PetscCall(ISSetBlockSize((*is)[i], bs));
3892adcc780SMatthew G. Knepley       }
3902adcc780SMatthew G. Knepley     }
3912adcc780SMatthew G. Knepley   }
3929796d432SMatthew G. Knepley   /* Preserve discretizations */
393e5e52638SMatthew G. Knepley   if (len && dms[0]->probs) {
3949566063dSJacob Faibussowitsch     PetscCall(DMSetNumFields(*superdm, Nf));
3959796d432SMatthew G. Knepley     for (i = 0, supf = 0; i < len; ++i) {
3969796d432SMatthew G. Knepley       for (f = 0; f < Nfs[i]; ++f, ++supf) {
3972adcc780SMatthew G. Knepley         PetscObject disc;
3982adcc780SMatthew G. Knepley 
3999566063dSJacob Faibussowitsch         PetscCall(DMGetField(dms[i], f, NULL, &disc));
4009566063dSJacob Faibussowitsch         PetscCall(DMSetField(*superdm, supf, NULL, disc));
4012adcc780SMatthew G. Knepley       }
4022adcc780SMatthew G. Knepley     }
4039566063dSJacob Faibussowitsch     PetscCall(DMCreateDS(*superdm));
4042adcc780SMatthew G. Knepley   }
4059796d432SMatthew G. Knepley   /* Preserve nullspaces */
4069796d432SMatthew G. Knepley   for (i = 0, supf = 0; i < len; ++i) {
4079796d432SMatthew G. Knepley     for (f = 0; f < Nfs[i]; ++f, ++supf) {
4089796d432SMatthew G. Knepley       (*superdm)->nullspaceConstructors[supf] = dms[i]->nullspaceConstructors[f];
4099796d432SMatthew G. Knepley       if ((*superdm)->nullspaceConstructors[supf]) {
4109796d432SMatthew G. Knepley         haveNull = PETSC_TRUE;
4119796d432SMatthew G. Knepley         nullf    = supf;
4128cda7954SMatthew G. Knepley         oldf     = f;
4132adcc780SMatthew G. Knepley       }
4149796d432SMatthew G. Knepley     }
4159796d432SMatthew G. Knepley   }
4169796d432SMatthew G. Knepley   /* Attach nullspace to IS */
4179796d432SMatthew G. Knepley   if (haveNull && is) {
4189796d432SMatthew G. Knepley     MatNullSpace nullSpace;
4199796d432SMatthew G. Knepley 
4209566063dSJacob Faibussowitsch     PetscCall((*(*superdm)->nullspaceConstructors[nullf])(*superdm, oldf, nullf, &nullSpace));
4219566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)(*is)[nullf], "nullspace", (PetscObject)nullSpace));
4229566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceDestroy(&nullSpace));
4239796d432SMatthew G. Knepley   }
4249566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&supersection));
4259566063dSJacob Faibussowitsch   PetscCall(PetscFree3(Nfs, sections, sectionGlobals));
4262adcc780SMatthew G. Knepley   PetscFunctionReturn(0);
4272adcc780SMatthew G. Knepley }
428