1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2da97024aSMatthew G. Knepley #include <petscsf.h> 3cb1e1211SMatthew G Knepley 48e3a2eefSMatthew G. Knepley #include <petscblaslapack.h> 5e8f14785SLisandro Dalcin #include <petsc/private/hashsetij.h> 6af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h> 7af0996ceSBarry Smith #include <petsc/private/petscfvimpl.h> 8a0845e3aSMatthew G. Knepley 95f0b18bfSMatthew G. Knepley PetscBool Clementcite = PETSC_FALSE; 105f0b18bfSMatthew G. Knepley const char ClementCitation[] = "@article{clement1975approximation,\n" 115f0b18bfSMatthew G. Knepley " title = {Approximation by finite element functions using local regularization},\n" 125f0b18bfSMatthew G. Knepley " author = {Philippe Cl{\\'e}ment},\n" 135f0b18bfSMatthew G. Knepley " journal = {Revue fran{\\c{c}}aise d'automatique, informatique, recherche op{\\'e}rationnelle. Analyse num{\\'e}rique},\n" 145f0b18bfSMatthew G. Knepley " volume = {9},\n" 155f0b18bfSMatthew G. Knepley " number = {R2},\n" 165f0b18bfSMatthew G. Knepley " pages = {77--84},\n" 175f0b18bfSMatthew G. Knepley " year = {1975}\n}\n"; 185f0b18bfSMatthew G. Knepley 19d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexConvertPlex(DM dm, DM *plex, PetscBool copy) 20d71ae5a4SJacob Faibussowitsch { 212f856554SMatthew G. Knepley PetscBool isPlex; 222f856554SMatthew G. Knepley 232f856554SMatthew G. Knepley PetscFunctionBegin; 249566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 252f856554SMatthew G. Knepley if (isPlex) { 262f856554SMatthew G. Knepley *plex = dm; 279566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 282f856554SMatthew G. Knepley } else { 299566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 302f856554SMatthew G. Knepley if (!*plex) { 319566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 329566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 332f856554SMatthew G. Knepley if (copy) { 342f856554SMatthew G. Knepley DMSubDomainHookLink link; 359a2a23afSMatthew G. Knepley 369566063dSJacob Faibussowitsch PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 379a2a23afSMatthew G. Knepley /* Run the subdomain hook (this will copy the DMSNES/DMTS) */ 382f856554SMatthew G. Knepley for (link = dm->subdomainhook; link; link = link->next) { 399566063dSJacob Faibussowitsch if (link->ddhook) PetscCall((*link->ddhook)(dm, *plex, link->ctx)); 402f856554SMatthew G. Knepley } 412f856554SMatthew G. Knepley } 422f856554SMatthew G. Knepley } else { 439566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)*plex)); 442f856554SMatthew G. Knepley } 452f856554SMatthew G. Knepley } 462f856554SMatthew G. Knepley PetscFunctionReturn(0); 472f856554SMatthew G. Knepley } 482f856554SMatthew G. Knepley 49d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscContainerUserDestroy_PetscFEGeom(void *ctx) 50d71ae5a4SJacob Faibussowitsch { 519b6f715bSMatthew G. Knepley PetscFEGeom *geom = (PetscFEGeom *)ctx; 529b6f715bSMatthew G. Knepley 539b6f715bSMatthew G. Knepley PetscFunctionBegin; 549566063dSJacob Faibussowitsch PetscCall(PetscFEGeomDestroy(&geom)); 559b6f715bSMatthew G. Knepley PetscFunctionReturn(0); 569b6f715bSMatthew G. Knepley } 579b6f715bSMatthew G. Knepley 58d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 59d71ae5a4SJacob Faibussowitsch { 609b6f715bSMatthew G. Knepley char composeStr[33] = {0}; 619b6f715bSMatthew G. Knepley PetscObjectId id; 629b6f715bSMatthew G. Knepley PetscContainer container; 639b6f715bSMatthew G. Knepley 649b6f715bSMatthew G. Knepley PetscFunctionBegin; 659566063dSJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)quad, &id)); 6663a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(composeStr, 32, "DMPlexGetFEGeom_%" PetscInt64_FMT "\n", id)); 679566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container)); 689b6f715bSMatthew G. Knepley if (container) { 699566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(container, (void **)geom)); 709b6f715bSMatthew G. Knepley } else { 719566063dSJacob Faibussowitsch PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 729566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 739566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(container, (void *)*geom)); 749566063dSJacob Faibussowitsch PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom)); 759566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container)); 769566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&container)); 779b6f715bSMatthew G. Knepley } 789b6f715bSMatthew G. Knepley PetscFunctionReturn(0); 799b6f715bSMatthew G. Knepley } 809b6f715bSMatthew G. Knepley 81d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 82d71ae5a4SJacob Faibussowitsch { 839b6f715bSMatthew G. Knepley PetscFunctionBegin; 849b6f715bSMatthew G. Knepley *geom = NULL; 859b6f715bSMatthew G. Knepley PetscFunctionReturn(0); 869b6f715bSMatthew G. Knepley } 879b6f715bSMatthew G. Knepley 8846fa42a0SMatthew G. Knepley /*@ 8946fa42a0SMatthew G. Knepley DMPlexGetScale - Get the scale for the specified fundamental unit 9046fa42a0SMatthew G. Knepley 9146fa42a0SMatthew G. Knepley Not collective 9246fa42a0SMatthew G. Knepley 934165533cSJose E. Roman Input Parameters: 94*a1cb98faSBarry Smith + dm - the `DM` 9546fa42a0SMatthew G. Knepley - unit - The SI unit 9646fa42a0SMatthew G. Knepley 974165533cSJose E. Roman Output Parameter: 9846fa42a0SMatthew G. Knepley . scale - The value used to scale all quantities with this unit 9946fa42a0SMatthew G. Knepley 10046fa42a0SMatthew G. Knepley Level: advanced 10146fa42a0SMatthew G. Knepley 102*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetScale()`, `PetscUnit` 10346fa42a0SMatthew G. Knepley @*/ 104d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale) 105d71ae5a4SJacob Faibussowitsch { 106cb1e1211SMatthew G Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 107cb1e1211SMatthew G Knepley 108cb1e1211SMatthew G Knepley PetscFunctionBegin; 109cb1e1211SMatthew G Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 110dadcf809SJacob Faibussowitsch PetscValidRealPointer(scale, 3); 111cb1e1211SMatthew G Knepley *scale = mesh->scale[unit]; 112cb1e1211SMatthew G Knepley PetscFunctionReturn(0); 113cb1e1211SMatthew G Knepley } 114cb1e1211SMatthew G Knepley 11546fa42a0SMatthew G. Knepley /*@ 11646fa42a0SMatthew G. Knepley DMPlexSetScale - Set the scale for the specified fundamental unit 11746fa42a0SMatthew G. Knepley 11846fa42a0SMatthew G. Knepley Not collective 11946fa42a0SMatthew G. Knepley 1204165533cSJose E. Roman Input Parameters: 121*a1cb98faSBarry Smith + dm - the `DM` 12246fa42a0SMatthew G. Knepley . unit - The SI unit 12346fa42a0SMatthew G. Knepley - scale - The value used to scale all quantities with this unit 12446fa42a0SMatthew G. Knepley 12546fa42a0SMatthew G. Knepley Level: advanced 12646fa42a0SMatthew G. Knepley 127*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetScale()`, `PetscUnit` 12846fa42a0SMatthew G. Knepley @*/ 129d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale) 130d71ae5a4SJacob Faibussowitsch { 131cb1e1211SMatthew G Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 132cb1e1211SMatthew G Knepley 133cb1e1211SMatthew G Knepley PetscFunctionBegin; 134cb1e1211SMatthew G Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 135cb1e1211SMatthew G Knepley mesh->scale[unit] = scale; 136cb1e1211SMatthew G Knepley PetscFunctionReturn(0); 137cb1e1211SMatthew G Knepley } 138cb1e1211SMatthew G Knepley 139d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nc, PetscScalar *mode, void *ctx) 140d71ae5a4SJacob Faibussowitsch { 1419371c9d4SSatish Balay const PetscInt eps[3][3][3] = { 1429371c9d4SSatish Balay {{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, 1439371c9d4SSatish Balay {{0, 0, -1}, {0, 0, 0}, {1, 0, 0} }, 1449371c9d4SSatish Balay {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0} } 1459371c9d4SSatish Balay }; 146026175e5SToby Isaac PetscInt *ctxInt = (PetscInt *)ctx; 147ad917190SMatthew G. Knepley PetscInt dim2 = ctxInt[0]; 148026175e5SToby Isaac PetscInt d = ctxInt[1]; 149026175e5SToby Isaac PetscInt i, j, k = dim > 2 ? d - dim : d; 150026175e5SToby Isaac 151ad917190SMatthew G. Knepley PetscFunctionBegin; 15263a3b9bcSJacob Faibussowitsch PetscCheck(dim == dim2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %" PetscInt_FMT " does not match context dimension %" PetscInt_FMT, dim, dim2); 153026175e5SToby Isaac for (i = 0; i < dim; i++) mode[i] = 0.; 154026175e5SToby Isaac if (d < dim) { 15512adca46SMatthew G. Knepley mode[d] = 1.; /* Translation along axis d */ 156ad917190SMatthew G. Knepley } else { 157026175e5SToby Isaac for (i = 0; i < dim; i++) { 1589371c9d4SSatish Balay for (j = 0; j < dim; j++) { mode[j] += eps[i][j][k] * X[i]; /* Rotation about axis d */ } 159026175e5SToby Isaac } 160026175e5SToby Isaac } 161ad917190SMatthew G. Knepley PetscFunctionReturn(0); 162026175e5SToby Isaac } 163026175e5SToby Isaac 164cc4e42d9SMartin Diehl /*@ 16512adca46SMatthew G. Knepley DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation 166cb1e1211SMatthew G Knepley 167d083f849SBarry Smith Collective on dm 168cb1e1211SMatthew G Knepley 1694165533cSJose E. Roman Input Parameters: 170*a1cb98faSBarry Smith + dm - the `DM` 17156cf3b9cSMatthew G. Knepley - field - The field number for the rigid body space, or 0 for the default 172cb1e1211SMatthew G Knepley 1734165533cSJose E. Roman Output Parameter: 174cb1e1211SMatthew G Knepley . sp - the null space 175cb1e1211SMatthew G Knepley 176cb1e1211SMatthew G Knepley Level: advanced 177cb1e1211SMatthew G Knepley 178*a1cb98faSBarry Smith Note: 179*a1cb98faSBarry Smith This is necessary to provide a suitable coarse space for algebraic multigrid 180*a1cb98faSBarry Smith 181*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`, `PCGAMG` 182cb1e1211SMatthew G Knepley @*/ 183d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscInt field, MatNullSpace *sp) 184d71ae5a4SJacob Faibussowitsch { 18556cf3b9cSMatthew G. Knepley PetscErrorCode (**func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *); 186cb1e1211SMatthew G Knepley MPI_Comm comm; 187026175e5SToby Isaac Vec mode[6]; 188026175e5SToby Isaac PetscSection section, globalSection; 18956cf3b9cSMatthew G. Knepley PetscInt dim, dimEmbed, Nf, n, m, mmin, d, i, j; 190cb1e1211SMatthew G Knepley 191cb1e1211SMatthew G Knepley PetscFunctionBegin; 1929566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1939566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 1949566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 1959566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 19663a3b9bcSJacob Faibussowitsch PetscCheck(!Nf || !(field < 0 || field >= Nf), comm, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", field, Nf); 19756cf3b9cSMatthew G. Knepley if (dim == 1 && Nf < 2) { 1989566063dSJacob Faibussowitsch PetscCall(MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp)); 199cb1e1211SMatthew G Knepley PetscFunctionReturn(0); 200cb1e1211SMatthew G Knepley } 2019566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 2029566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 2039566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n)); 2049566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(Nf, &func)); 205b247467aSMatthew G. Knepley m = (dim * (dim + 1)) / 2; 2069566063dSJacob Faibussowitsch PetscCall(VecCreate(comm, &mode[0])); 2079566063dSJacob Faibussowitsch PetscCall(VecSetType(mode[0], dm->vectype)); 2089566063dSJacob Faibussowitsch PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE)); 2099566063dSJacob Faibussowitsch PetscCall(VecSetUp(mode[0])); 2109566063dSJacob Faibussowitsch PetscCall(VecGetSize(mode[0], &n)); 211b247467aSMatthew G. Knepley mmin = PetscMin(m, n); 21256cf3b9cSMatthew G. Knepley func[field] = DMPlexProjectRigidBody_Private; 2139566063dSJacob Faibussowitsch for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i])); 214026175e5SToby Isaac for (d = 0; d < m; d++) { 215330485fdSToby Isaac PetscInt ctx[2]; 216026175e5SToby Isaac void *voidctx = (void *)(&ctx[0]); 217cb1e1211SMatthew G Knepley 2189d8fbdeaSMatthew G. Knepley ctx[0] = dimEmbed; 219330485fdSToby Isaac ctx[1] = d; 2209566063dSJacob Faibussowitsch PetscCall(DMProjectFunction(dm, 0.0, func, &voidctx, INSERT_VALUES, mode[d])); 221cb1e1211SMatthew G Knepley } 2223b2202bfSJacob Faibussowitsch /* Orthonormalize system */ 223b50a2c0aSJacob Faibussowitsch for (i = 0; i < mmin; ++i) { 224b77f2eeeSJacob Faibussowitsch PetscScalar dots[6]; 225b50a2c0aSJacob Faibussowitsch 2269566063dSJacob Faibussowitsch PetscCall(VecNormalize(mode[i], NULL)); 2279566063dSJacob Faibussowitsch PetscCall(VecMDot(mode[i], mmin - i - 1, mode + i + 1, dots + i + 1)); 228b50a2c0aSJacob Faibussowitsch for (j = i + 1; j < mmin; ++j) { 229b77f2eeeSJacob Faibussowitsch dots[j] *= -1.0; 2309566063dSJacob Faibussowitsch PetscCall(VecAXPY(mode[j], dots[j], mode[i])); 231b50a2c0aSJacob Faibussowitsch } 232cb1e1211SMatthew G Knepley } 2339566063dSJacob Faibussowitsch PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp)); 2349566063dSJacob Faibussowitsch for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i])); 2359566063dSJacob Faibussowitsch PetscCall(PetscFree(func)); 236cb1e1211SMatthew G Knepley PetscFunctionReturn(0); 237cb1e1211SMatthew G Knepley } 238cb1e1211SMatthew G Knepley 239cc4e42d9SMartin Diehl /*@ 24012adca46SMatthew G. Knepley DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation 24112adca46SMatthew G. Knepley 242d083f849SBarry Smith Collective on dm 24312adca46SMatthew G. Knepley 2444165533cSJose E. Roman Input Parameters: 245*a1cb98faSBarry Smith + dm - the `DM` 24612adca46SMatthew G. Knepley . nb - The number of bodies 247*a1cb98faSBarry Smith . label - The `DMLabel` marking each domain 24812adca46SMatthew G. Knepley . nids - The number of ids per body 24912adca46SMatthew G. Knepley - ids - An array of the label ids in sequence for each domain 25012adca46SMatthew G. Knepley 2514165533cSJose E. Roman Output Parameter: 25212adca46SMatthew G. Knepley . sp - the null space 25312adca46SMatthew G. Knepley 25412adca46SMatthew G. Knepley Level: advanced 25512adca46SMatthew G. Knepley 256*a1cb98faSBarry Smith Note: 257*a1cb98faSBarry Smith This is necessary to provide a suitable coarse space for algebraic multigrid 258*a1cb98faSBarry Smith 259*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()` 26012adca46SMatthew G. Knepley @*/ 261d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp) 262d71ae5a4SJacob Faibussowitsch { 26312adca46SMatthew G. Knepley MPI_Comm comm; 26412adca46SMatthew G. Knepley PetscSection section, globalSection; 26512adca46SMatthew G. Knepley Vec *mode; 26612adca46SMatthew G. Knepley PetscScalar *dots; 26712adca46SMatthew G. Knepley PetscInt dim, dimEmbed, n, m, b, d, i, j, off; 26812adca46SMatthew G. Knepley 26912adca46SMatthew G. Knepley PetscFunctionBegin; 2709566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 2719566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 2729566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 2739566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 2749566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 2759566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n)); 27612adca46SMatthew G. Knepley m = nb * (dim * (dim + 1)) / 2; 2779566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(m, &mode, m, &dots)); 2789566063dSJacob Faibussowitsch PetscCall(VecCreate(comm, &mode[0])); 2799566063dSJacob Faibussowitsch PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE)); 2809566063dSJacob Faibussowitsch PetscCall(VecSetUp(mode[0])); 2819566063dSJacob Faibussowitsch for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i])); 28212adca46SMatthew G. Knepley for (b = 0, off = 0; b < nb; ++b) { 28312adca46SMatthew G. Knepley for (d = 0; d < m / nb; ++d) { 28412adca46SMatthew G. Knepley PetscInt ctx[2]; 28512adca46SMatthew G. Knepley PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private; 28612adca46SMatthew G. Knepley void *voidctx = (void *)(&ctx[0]); 28712adca46SMatthew G. Knepley 28812adca46SMatthew G. Knepley ctx[0] = dimEmbed; 28912adca46SMatthew G. Knepley ctx[1] = d; 2909566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d])); 29112adca46SMatthew G. Knepley off += nids[b]; 29212adca46SMatthew G. Knepley } 29312adca46SMatthew G. Knepley } 2943b2202bfSJacob Faibussowitsch /* Orthonormalize system */ 295606c1a1cSJacob Faibussowitsch for (i = 0; i < m; ++i) { 296b77f2eeeSJacob Faibussowitsch PetscScalar dots[6]; 2975a0e29b9SJacob Faibussowitsch 2989566063dSJacob Faibussowitsch PetscCall(VecNormalize(mode[i], NULL)); 2999566063dSJacob Faibussowitsch PetscCall(VecMDot(mode[i], m - i - 1, mode + i + 1, dots + i + 1)); 3005a0e29b9SJacob Faibussowitsch for (j = i + 1; j < m; ++j) { 301b77f2eeeSJacob Faibussowitsch dots[j] *= -1.0; 3029566063dSJacob Faibussowitsch PetscCall(VecAXPY(mode[j], dots[j], mode[i])); 3035a0e29b9SJacob Faibussowitsch } 30412adca46SMatthew G. Knepley } 3059566063dSJacob Faibussowitsch PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp)); 3069566063dSJacob Faibussowitsch for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i])); 3079566063dSJacob Faibussowitsch PetscCall(PetscFree2(mode, dots)); 30812adca46SMatthew G. Knepley PetscFunctionReturn(0); 30912adca46SMatthew G. Knepley } 31012adca46SMatthew G. Knepley 311b29cfa1cSToby Isaac /*@ 312b29cfa1cSToby Isaac DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs 313b29cfa1cSToby Isaac are computed by associating the basis function with one of the mesh points in its transitively-closed support, and 314b29cfa1cSToby Isaac evaluating the dual space basis of that point. A basis function is associated with the point in its 315b29cfa1cSToby Isaac transitively-closed support whose mesh height is highest (w.r.t. DAG height), but not greater than the maximum 316b29cfa1cSToby Isaac projection height, which is set with this function. By default, the maximum projection height is zero, which means 317b29cfa1cSToby Isaac that only mesh cells are used to project basis functions. A height of one, for example, evaluates a cell-interior 318b29cfa1cSToby Isaac basis functions using its cells dual space basis, but all other basis functions with the dual space basis of a face. 319b29cfa1cSToby Isaac 320b29cfa1cSToby Isaac Input Parameters: 321*a1cb98faSBarry Smith + dm - the `DMPLEX` object 322b29cfa1cSToby Isaac - height - the maximum projection height >= 0 323b29cfa1cSToby Isaac 324b29cfa1cSToby Isaac Level: advanced 325b29cfa1cSToby Isaac 326*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()` 327b29cfa1cSToby Isaac @*/ 328d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height) 329d71ae5a4SJacob Faibussowitsch { 330b29cfa1cSToby Isaac DM_Plex *plex = (DM_Plex *)dm->data; 331b29cfa1cSToby Isaac 332b29cfa1cSToby Isaac PetscFunctionBegin; 333b29cfa1cSToby Isaac PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 334b29cfa1cSToby Isaac plex->maxProjectionHeight = height; 335b29cfa1cSToby Isaac PetscFunctionReturn(0); 336b29cfa1cSToby Isaac } 337b29cfa1cSToby Isaac 338b29cfa1cSToby Isaac /*@ 339b29cfa1cSToby Isaac DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in 340b29cfa1cSToby Isaac DMPlexProjectXXXLocal() functions. 341b29cfa1cSToby Isaac 342b29cfa1cSToby Isaac Input Parameters: 343*a1cb98faSBarry Smith . dm - the `DMPLEX` object 344b29cfa1cSToby Isaac 345b29cfa1cSToby Isaac Output Parameters: 346b29cfa1cSToby Isaac . height - the maximum projection height 347b29cfa1cSToby Isaac 348b29cfa1cSToby Isaac Level: intermediate 349b29cfa1cSToby Isaac 350*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()` 351b29cfa1cSToby Isaac @*/ 352d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height) 353d71ae5a4SJacob Faibussowitsch { 354b29cfa1cSToby Isaac DM_Plex *plex = (DM_Plex *)dm->data; 355b29cfa1cSToby Isaac 356b29cfa1cSToby Isaac PetscFunctionBegin; 357b29cfa1cSToby Isaac PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 358b29cfa1cSToby Isaac *height = plex->maxProjectionHeight; 359b29cfa1cSToby Isaac PetscFunctionReturn(0); 360b29cfa1cSToby Isaac } 361b29cfa1cSToby Isaac 362ca3d3a14SMatthew G. Knepley typedef struct { 363ca3d3a14SMatthew G. Knepley PetscReal alpha; /* The first Euler angle, and in 2D the only one */ 364ca3d3a14SMatthew G. Knepley PetscReal beta; /* The second Euler angle */ 365ca3d3a14SMatthew G. Knepley PetscReal gamma; /* The third Euler angle */ 366ca3d3a14SMatthew G. Knepley PetscInt dim; /* The dimension of R */ 367ca3d3a14SMatthew G. Knepley PetscScalar *R; /* The rotation matrix, transforming a vector in the local basis to the global basis */ 368ca3d3a14SMatthew G. Knepley PetscScalar *RT; /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */ 369ca3d3a14SMatthew G. Knepley } RotCtx; 370ca3d3a14SMatthew G. Knepley 371ca3d3a14SMatthew G. Knepley /* 372ca3d3a14SMatthew G. Knepley Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that 373ca3d3a14SMatthew G. Knepley we rotate with respect to a fixed initial coordinate system, the local basis (x-y-z). The global basis (X-Y-Z) is reached as follows: 374ca3d3a14SMatthew G. Knepley $ The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis. 375ca3d3a14SMatthew G. Knepley $ The XYZ system rotates again about the x axis by beta. The Z axis is now at angle beta with respect to the z axis. 376ca3d3a14SMatthew G. Knepley $ The XYZ system rotates a third time about the z axis by gamma. 377ca3d3a14SMatthew G. Knepley */ 378d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, void *ctx) 379d71ae5a4SJacob Faibussowitsch { 380ca3d3a14SMatthew G. Knepley RotCtx *rc = (RotCtx *)ctx; 381ca3d3a14SMatthew G. Knepley PetscInt dim = rc->dim; 382ca3d3a14SMatthew G. Knepley PetscReal c1, s1, c2, s2, c3, s3; 383ca3d3a14SMatthew G. Knepley 384ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 3859566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(PetscSqr(dim), &rc->R, PetscSqr(dim), &rc->RT)); 386ca3d3a14SMatthew G. Knepley switch (dim) { 387ca3d3a14SMatthew G. Knepley case 2: 3889371c9d4SSatish Balay c1 = PetscCosReal(rc->alpha); 3899371c9d4SSatish Balay s1 = PetscSinReal(rc->alpha); 3909371c9d4SSatish Balay rc->R[0] = c1; 3919371c9d4SSatish Balay rc->R[1] = s1; 3929371c9d4SSatish Balay rc->R[2] = -s1; 3939371c9d4SSatish Balay rc->R[3] = c1; 3949566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim))); 395b458e8f1SJose E. Roman DMPlex_Transpose2D_Internal(rc->RT); 396ca3d3a14SMatthew G. Knepley break; 397ca3d3a14SMatthew G. Knepley case 3: 3989371c9d4SSatish Balay c1 = PetscCosReal(rc->alpha); 3999371c9d4SSatish Balay s1 = PetscSinReal(rc->alpha); 4009371c9d4SSatish Balay c2 = PetscCosReal(rc->beta); 4019371c9d4SSatish Balay s2 = PetscSinReal(rc->beta); 4029371c9d4SSatish Balay c3 = PetscCosReal(rc->gamma); 4039371c9d4SSatish Balay s3 = PetscSinReal(rc->gamma); 4049371c9d4SSatish Balay rc->R[0] = c1 * c3 - c2 * s1 * s3; 4059371c9d4SSatish Balay rc->R[1] = c3 * s1 + c1 * c2 * s3; 4069371c9d4SSatish Balay rc->R[2] = s2 * s3; 4079371c9d4SSatish Balay rc->R[3] = -c1 * s3 - c2 * c3 * s1; 4089371c9d4SSatish Balay rc->R[4] = c1 * c2 * c3 - s1 * s3; 4099371c9d4SSatish Balay rc->R[5] = c3 * s2; 4109371c9d4SSatish Balay rc->R[6] = s1 * s2; 4119371c9d4SSatish Balay rc->R[7] = -c1 * s2; 4129371c9d4SSatish Balay rc->R[8] = c2; 4139566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim))); 414b458e8f1SJose E. Roman DMPlex_Transpose3D_Internal(rc->RT); 415ca3d3a14SMatthew G. Knepley break; 416d71ae5a4SJacob Faibussowitsch default: 417d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim); 418ca3d3a14SMatthew G. Knepley } 419ca3d3a14SMatthew G. Knepley PetscFunctionReturn(0); 420ca3d3a14SMatthew G. Knepley } 421ca3d3a14SMatthew G. Knepley 422d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, void *ctx) 423d71ae5a4SJacob Faibussowitsch { 424ca3d3a14SMatthew G. Knepley RotCtx *rc = (RotCtx *)ctx; 425ca3d3a14SMatthew G. Knepley 426ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 4279566063dSJacob Faibussowitsch PetscCall(PetscFree2(rc->R, rc->RT)); 4289566063dSJacob Faibussowitsch PetscCall(PetscFree(rc)); 429ca3d3a14SMatthew G. Knepley PetscFunctionReturn(0); 430ca3d3a14SMatthew G. Knepley } 431ca3d3a14SMatthew G. Knepley 432d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm, const PetscReal x[], PetscBool l2g, const PetscScalar **A, void *ctx) 433d71ae5a4SJacob Faibussowitsch { 434ca3d3a14SMatthew G. Knepley RotCtx *rc = (RotCtx *)ctx; 435ca3d3a14SMatthew G. Knepley 436ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 437ca3d3a14SMatthew G. Knepley PetscValidPointer(ctx, 5); 4389371c9d4SSatish Balay if (l2g) { 4399371c9d4SSatish Balay *A = rc->R; 4409371c9d4SSatish Balay } else { 4419371c9d4SSatish Balay *A = rc->RT; 4429371c9d4SSatish Balay } 443ca3d3a14SMatthew G. Knepley PetscFunctionReturn(0); 444ca3d3a14SMatthew G. Knepley } 445ca3d3a14SMatthew G. Knepley 446d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformApplyReal_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscReal *y, PetscReal *z, void *ctx) 447d71ae5a4SJacob Faibussowitsch { 448ec277c0fSMatthew G. Knepley PetscFunctionBegin; 449ab6a9622SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX) 450ab6a9622SMatthew G. Knepley switch (dim) { 4519371c9d4SSatish Balay case 2: { 45227104ee2SJacob Faibussowitsch PetscScalar yt[2] = {y[0], y[1]}, zt[2] = {0.0, 0.0}; 453ab6a9622SMatthew G. Knepley 4549566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx)); 4559371c9d4SSatish Balay z[0] = PetscRealPart(zt[0]); 4569371c9d4SSatish Balay z[1] = PetscRealPart(zt[1]); 4579371c9d4SSatish Balay } break; 4589371c9d4SSatish Balay case 3: { 45927104ee2SJacob Faibussowitsch PetscScalar yt[3] = {y[0], y[1], y[2]}, zt[3] = {0.0, 0.0, 0.0}; 460ab6a9622SMatthew G. Knepley 4619566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx)); 4629371c9d4SSatish Balay z[0] = PetscRealPart(zt[0]); 4639371c9d4SSatish Balay z[1] = PetscRealPart(zt[1]); 4649371c9d4SSatish Balay z[2] = PetscRealPart(zt[2]); 4659371c9d4SSatish Balay } break; 466ab6a9622SMatthew G. Knepley } 467ab6a9622SMatthew G. Knepley #else 4689566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx)); 469ab6a9622SMatthew G. Knepley #endif 470ec277c0fSMatthew G. Knepley PetscFunctionReturn(0); 471ab6a9622SMatthew G. Knepley } 472ab6a9622SMatthew G. Knepley 473d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, void *ctx) 474d71ae5a4SJacob Faibussowitsch { 475ca3d3a14SMatthew G. Knepley const PetscScalar *A; 476ca3d3a14SMatthew G. Knepley 477ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 4789566063dSJacob Faibussowitsch PetscCall((*dm->transformGetMatrix)(dm, x, l2g, &A, ctx)); 479ca3d3a14SMatthew G. Knepley switch (dim) { 480d71ae5a4SJacob Faibussowitsch case 2: 481d71ae5a4SJacob Faibussowitsch DMPlex_Mult2D_Internal(A, 1, y, z); 482d71ae5a4SJacob Faibussowitsch break; 483d71ae5a4SJacob Faibussowitsch case 3: 484d71ae5a4SJacob Faibussowitsch DMPlex_Mult3D_Internal(A, 1, y, z); 485d71ae5a4SJacob Faibussowitsch break; 486ca3d3a14SMatthew G. Knepley } 487ca3d3a14SMatthew G. Knepley PetscFunctionReturn(0); 488ca3d3a14SMatthew G. Knepley } 489ca3d3a14SMatthew G. Knepley 490d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a) 491d71ae5a4SJacob Faibussowitsch { 492ca3d3a14SMatthew G. Knepley PetscSection ts; 493ca3d3a14SMatthew G. Knepley const PetscScalar *ta, *tva; 494ca3d3a14SMatthew G. Knepley PetscInt dof; 495ca3d3a14SMatthew G. Knepley 496ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 4979566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(tdm, &ts)); 4989566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof)); 4999566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(tv, &ta)); 5009566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(tdm, p, f, ta, &tva)); 501ca3d3a14SMatthew G. Knepley if (l2g) { 502ca3d3a14SMatthew G. Knepley switch (dof) { 503d71ae5a4SJacob Faibussowitsch case 4: 504d71ae5a4SJacob Faibussowitsch DMPlex_Mult2D_Internal(tva, 1, a, a); 505d71ae5a4SJacob Faibussowitsch break; 506d71ae5a4SJacob Faibussowitsch case 9: 507d71ae5a4SJacob Faibussowitsch DMPlex_Mult3D_Internal(tva, 1, a, a); 508d71ae5a4SJacob Faibussowitsch break; 509ca3d3a14SMatthew G. Knepley } 510ca3d3a14SMatthew G. Knepley } else { 511ca3d3a14SMatthew G. Knepley switch (dof) { 512d71ae5a4SJacob Faibussowitsch case 4: 513d71ae5a4SJacob Faibussowitsch DMPlex_MultTranspose2D_Internal(tva, 1, a, a); 514d71ae5a4SJacob Faibussowitsch break; 515d71ae5a4SJacob Faibussowitsch case 9: 516d71ae5a4SJacob Faibussowitsch DMPlex_MultTranspose3D_Internal(tva, 1, a, a); 517d71ae5a4SJacob Faibussowitsch break; 518ca3d3a14SMatthew G. Knepley } 519ca3d3a14SMatthew G. Knepley } 5209566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(tv, &ta)); 521ca3d3a14SMatthew G. Knepley PetscFunctionReturn(0); 522ca3d3a14SMatthew G. Knepley } 523ca3d3a14SMatthew G. Knepley 524d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformFieldTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt pf, PetscInt f, PetscInt pg, PetscInt g, PetscBool l2g, PetscInt lda, PetscScalar *a) 525d71ae5a4SJacob Faibussowitsch { 526ca3d3a14SMatthew G. Knepley PetscSection s, ts; 527ca3d3a14SMatthew G. Knepley const PetscScalar *ta, *tvaf, *tvag; 528ca3d3a14SMatthew G. Knepley PetscInt fdof, gdof, fpdof, gpdof; 529ca3d3a14SMatthew G. Knepley 530ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 5319566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 5329566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(tdm, &ts)); 5339566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, pf, f, &fpdof)); 5349566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, pg, g, &gpdof)); 5359566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(ts, pf, f, &fdof)); 5369566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(ts, pg, g, &gdof)); 5379566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(tv, &ta)); 5389566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(tdm, pf, f, ta, &tvaf)); 5399566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(tdm, pg, g, ta, &tvag)); 540ca3d3a14SMatthew G. Knepley if (l2g) { 541ca3d3a14SMatthew G. Knepley switch (fdof) { 542d71ae5a4SJacob Faibussowitsch case 4: 543d71ae5a4SJacob Faibussowitsch DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a); 544d71ae5a4SJacob Faibussowitsch break; 545d71ae5a4SJacob Faibussowitsch case 9: 546d71ae5a4SJacob Faibussowitsch DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a); 547d71ae5a4SJacob Faibussowitsch break; 548ca3d3a14SMatthew G. Knepley } 549ca3d3a14SMatthew G. Knepley switch (gdof) { 550d71ae5a4SJacob Faibussowitsch case 4: 551d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a); 552d71ae5a4SJacob Faibussowitsch break; 553d71ae5a4SJacob Faibussowitsch case 9: 554d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a); 555d71ae5a4SJacob Faibussowitsch break; 556ca3d3a14SMatthew G. Knepley } 557ca3d3a14SMatthew G. Knepley } else { 558ca3d3a14SMatthew G. Knepley switch (fdof) { 559d71ae5a4SJacob Faibussowitsch case 4: 560d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a); 561d71ae5a4SJacob Faibussowitsch break; 562d71ae5a4SJacob Faibussowitsch case 9: 563d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a); 564d71ae5a4SJacob Faibussowitsch break; 565ca3d3a14SMatthew G. Knepley } 566ca3d3a14SMatthew G. Knepley switch (gdof) { 567d71ae5a4SJacob Faibussowitsch case 4: 568d71ae5a4SJacob Faibussowitsch DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a); 569d71ae5a4SJacob Faibussowitsch break; 570d71ae5a4SJacob Faibussowitsch case 9: 571d71ae5a4SJacob Faibussowitsch DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a); 572d71ae5a4SJacob Faibussowitsch break; 573ca3d3a14SMatthew G. Knepley } 574ca3d3a14SMatthew G. Knepley } 5759566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(tv, &ta)); 576ca3d3a14SMatthew G. Knepley PetscFunctionReturn(0); 577ca3d3a14SMatthew G. Knepley } 578ca3d3a14SMatthew G. Knepley 579d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a) 580d71ae5a4SJacob Faibussowitsch { 581ca3d3a14SMatthew G. Knepley PetscSection s; 582ca3d3a14SMatthew G. Knepley PetscSection clSection; 583ca3d3a14SMatthew G. Knepley IS clPoints; 584ca3d3a14SMatthew G. Knepley const PetscInt *clp; 585ca3d3a14SMatthew G. Knepley PetscInt *points = NULL; 586ca3d3a14SMatthew G. Knepley PetscInt Nf, f, Np, cp, dof, d = 0; 587ca3d3a14SMatthew G. Knepley 588ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 5899566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 5909566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &Nf)); 5919566063dSJacob Faibussowitsch PetscCall(DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 592ca3d3a14SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 593ca3d3a14SMatthew G. Knepley for (cp = 0; cp < Np * 2; cp += 2) { 5949566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, points[cp], f, &dof)); 595ca3d3a14SMatthew G. Knepley if (!dof) continue; 5969566063dSJacob Faibussowitsch if (fieldActive[f]) PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d])); 597ca3d3a14SMatthew G. Knepley d += dof; 598ca3d3a14SMatthew G. Knepley } 599ca3d3a14SMatthew G. Knepley } 6009566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 601ca3d3a14SMatthew G. Knepley PetscFunctionReturn(0); 602ca3d3a14SMatthew G. Knepley } 603ca3d3a14SMatthew G. Knepley 604d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a) 605d71ae5a4SJacob Faibussowitsch { 606ca3d3a14SMatthew G. Knepley PetscSection s; 607ca3d3a14SMatthew G. Knepley PetscSection clSection; 608ca3d3a14SMatthew G. Knepley IS clPoints; 609ca3d3a14SMatthew G. Knepley const PetscInt *clp; 610ca3d3a14SMatthew G. Knepley PetscInt *points = NULL; 6118bdb3c71SMatthew G. Knepley PetscInt Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0; 612ca3d3a14SMatthew G. Knepley 613ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 6149566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 6159566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &Nf)); 6169566063dSJacob Faibussowitsch PetscCall(DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 617ca3d3a14SMatthew G. Knepley for (f = 0, r = 0; f < Nf; ++f) { 618ca3d3a14SMatthew G. Knepley for (cpf = 0; cpf < Np * 2; cpf += 2) { 6199566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, points[cpf], f, &fdof)); 620ca3d3a14SMatthew G. Knepley for (g = 0, c = 0; g < Nf; ++g) { 621ca3d3a14SMatthew G. Knepley for (cpg = 0; cpg < Np * 2; cpg += 2) { 6229566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, points[cpg], g, &gdof)); 6239566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformFieldTensor_Internal(dm, tdm, tv, points[cpf], f, points[cpg], g, l2g, lda, &a[r * lda + c])); 624ca3d3a14SMatthew G. Knepley c += gdof; 625ca3d3a14SMatthew G. Knepley } 626ca3d3a14SMatthew G. Knepley } 62763a3b9bcSJacob Faibussowitsch PetscCheck(c == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of columns %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda); 628ca3d3a14SMatthew G. Knepley r += fdof; 629ca3d3a14SMatthew G. Knepley } 630ca3d3a14SMatthew G. Knepley } 63163a3b9bcSJacob Faibussowitsch PetscCheck(r == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of rows %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda); 6329566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 633ca3d3a14SMatthew G. Knepley PetscFunctionReturn(0); 634ca3d3a14SMatthew G. Knepley } 635ca3d3a14SMatthew G. Knepley 636d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g) 637d71ae5a4SJacob Faibussowitsch { 638ca3d3a14SMatthew G. Knepley DM tdm; 639ca3d3a14SMatthew G. Knepley Vec tv; 640ca3d3a14SMatthew G. Knepley PetscSection ts, s; 641ca3d3a14SMatthew G. Knepley const PetscScalar *ta; 642ca3d3a14SMatthew G. Knepley PetscScalar *a, *va; 643ca3d3a14SMatthew G. Knepley PetscInt pStart, pEnd, p, Nf, f; 644ca3d3a14SMatthew G. Knepley 645ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 6469566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 6479566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 6489566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(tdm, &ts)); 6499566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 6509566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 6519566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &Nf)); 6529566063dSJacob Faibussowitsch PetscCall(VecGetArray(lv, &a)); 6539566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(tv, &ta)); 654ca3d3a14SMatthew G. Knepley for (p = pStart; p < pEnd; ++p) { 655ca3d3a14SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 6569566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, p, f, a, &va)); 6579566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va)); 658ca3d3a14SMatthew G. Knepley } 659ca3d3a14SMatthew G. Knepley } 6609566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(lv, &a)); 6619566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(tv, &ta)); 662ca3d3a14SMatthew G. Knepley PetscFunctionReturn(0); 663ca3d3a14SMatthew G. Knepley } 664ca3d3a14SMatthew G. Knepley 665ca3d3a14SMatthew G. Knepley /*@ 666ca3d3a14SMatthew G. Knepley DMPlexGlobalToLocalBasis - Transform the values in the given local vector from the global basis to the local basis 667ca3d3a14SMatthew G. Knepley 668ca3d3a14SMatthew G. Knepley Input Parameters: 669*a1cb98faSBarry Smith + dm - The `DM` 670ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the global basis 671ca3d3a14SMatthew G. Knepley 672ca3d3a14SMatthew G. Knepley Output Parameters: 673ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the local basis 674ca3d3a14SMatthew G. Knepley 675ca3d3a14SMatthew G. Knepley Level: developer 676ca3d3a14SMatthew G. Knepley 677*a1cb98faSBarry Smith Note: 678*a1cb98faSBarry Smith This method is only intended to be called inside `DMGlobalToLocal()`. It is unlikely that a user will have a local vector full of coefficients for the global basis unless they are reimplementing GlobalToLocal. 679*a1cb98faSBarry Smith 680*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexLocalToGlobalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()` 681ca3d3a14SMatthew G. Knepley @*/ 682d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv) 683d71ae5a4SJacob Faibussowitsch { 684ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 685ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 686ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(lv, VEC_CLASSID, 2); 6879566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE)); 688ca3d3a14SMatthew G. Knepley PetscFunctionReturn(0); 689ca3d3a14SMatthew G. Knepley } 690ca3d3a14SMatthew G. Knepley 691ca3d3a14SMatthew G. Knepley /*@ 692ca3d3a14SMatthew G. Knepley DMPlexLocalToGlobalBasis - Transform the values in the given local vector from the local basis to the global basis 693ca3d3a14SMatthew G. Knepley 694ca3d3a14SMatthew G. Knepley Input Parameters: 695*a1cb98faSBarry Smith + dm - The `DM` 696ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the local basis 697ca3d3a14SMatthew G. Knepley 698ca3d3a14SMatthew G. Knepley Output Parameters: 699ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the global basis 700ca3d3a14SMatthew G. Knepley 701ca3d3a14SMatthew G. Knepley Level: developer 702ca3d3a14SMatthew G. Knepley 703*a1cb98faSBarry Smith Note: 704*a1cb98faSBarry Smith This method is only intended to be called inside `DMGlobalToLocal()`. It is unlikely that a user would want a local vector full of coefficients for the global basis unless they are reimplementing GlobalToLocal. 705*a1cb98faSBarry Smith 706*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()` 707ca3d3a14SMatthew G. Knepley @*/ 708d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv) 709d71ae5a4SJacob Faibussowitsch { 710ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 711ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 712ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(lv, VEC_CLASSID, 2); 7139566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE)); 714ca3d3a14SMatthew G. Knepley PetscFunctionReturn(0); 715ca3d3a14SMatthew G. Knepley } 716ca3d3a14SMatthew G. Knepley 717ca3d3a14SMatthew G. Knepley /*@ 718ca3d3a14SMatthew G. Knepley DMPlexCreateBasisRotation - Create an internal transformation from the global basis, used to specify boundary conditions 719ca3d3a14SMatthew G. Knepley and global solutions, to a local basis, appropriate for discretization integrals and assembly. 720ca3d3a14SMatthew G. Knepley 721ca3d3a14SMatthew G. Knepley Input Parameters: 722*a1cb98faSBarry Smith + dm - The `DM` 723ca3d3a14SMatthew G. Knepley . alpha - The first Euler angle, and in 2D the only one 724ca3d3a14SMatthew G. Knepley . beta - The second Euler angle 725f0fc11ceSJed Brown - gamma - The third Euler angle 726ca3d3a14SMatthew G. Knepley 727ca3d3a14SMatthew G. Knepley Level: developer 728ca3d3a14SMatthew G. Knepley 729*a1cb98faSBarry Smith Note: 730*a1cb98faSBarry Smith Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that 731*a1cb98faSBarry Smith we rotate with respect to a fixed initial coordinate system, the local basis (x-y-z). The global basis (X-Y-Z) is reached as follows 732*a1cb98faSBarry Smith .vb 733*a1cb98faSBarry Smith The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis. 734*a1cb98faSBarry Smith The XYZ system rotates again about the x axis by beta. The Z axis is now at angle beta with respect to the z axis. 735*a1cb98faSBarry Smith The XYZ system rotates a third time about the z axis by gamma. 736*a1cb98faSBarry Smith .ve 737*a1cb98faSBarry Smith 738*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()` 739ca3d3a14SMatthew G. Knepley @*/ 740d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma) 741d71ae5a4SJacob Faibussowitsch { 742ca3d3a14SMatthew G. Knepley RotCtx *rc; 743ca3d3a14SMatthew G. Knepley PetscInt cdim; 744ca3d3a14SMatthew G. Knepley 745362febeeSStefano Zampini PetscFunctionBegin; 7469566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 7479566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(1, &rc)); 748ca3d3a14SMatthew G. Knepley dm->transformCtx = rc; 749ca3d3a14SMatthew G. Knepley dm->transformSetUp = DMPlexBasisTransformSetUp_Rotation_Internal; 750ca3d3a14SMatthew G. Knepley dm->transformDestroy = DMPlexBasisTransformDestroy_Rotation_Internal; 751ca3d3a14SMatthew G. Knepley dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal; 752ca3d3a14SMatthew G. Knepley rc->dim = cdim; 753ca3d3a14SMatthew G. Knepley rc->alpha = alpha; 754ca3d3a14SMatthew G. Knepley rc->beta = beta; 755ca3d3a14SMatthew G. Knepley rc->gamma = gamma; 7569566063dSJacob Faibussowitsch PetscCall((*dm->transformSetUp)(dm, dm->transformCtx)); 7579566063dSJacob Faibussowitsch PetscCall(DMConstructBasisTransform_Internal(dm)); 758ca3d3a14SMatthew G. Knepley PetscFunctionReturn(0); 759ca3d3a14SMatthew G. Knepley } 760ca3d3a14SMatthew G. Knepley 761b278463cSMatthew G. Knepley /*@C 762ece3a9fcSMatthew G. Knepley DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector using a function of the coordinates 763b278463cSMatthew G. Knepley 764b278463cSMatthew G. Knepley Input Parameters: 765*a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 766b278463cSMatthew G. Knepley . time - The time 767b278463cSMatthew G. Knepley . field - The field to constrain 7681c531cf8SMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 7691c531cf8SMatthew G. Knepley . comps - An array of constrained component numbers, or NULL for all components 770*a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 771*a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 772b278463cSMatthew G. Knepley . ids - An array of ids for constrained points 773b278463cSMatthew G. Knepley . func - A pointwise function giving boundary values 774b278463cSMatthew G. Knepley - ctx - An optional user context for bcFunc 775b278463cSMatthew G. Knepley 776b278463cSMatthew G. Knepley Output Parameter: 777b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values 778b278463cSMatthew G. Knepley 779b278463cSMatthew G. Knepley Level: developer 780b278463cSMatthew G. Knepley 781*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLabel`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()` 782b278463cSMatthew G. Knepley @*/ 783d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValuesEssential(DM dm, PetscReal time, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void *ctx, Vec locX) 784d71ae5a4SJacob Faibussowitsch { 7850163fd50SMatthew G. Knepley PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 78655f2e967SMatthew G. Knepley void **ctxs; 787d7ddef95SMatthew G. Knepley PetscInt numFields; 788d7ddef95SMatthew G. Knepley 789d7ddef95SMatthew G. Knepley PetscFunctionBegin; 7909566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 7919566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 792d7ddef95SMatthew G. Knepley funcs[field] = func; 793d7ddef95SMatthew G. Knepley ctxs[field] = ctx; 7949566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX)); 7959566063dSJacob Faibussowitsch PetscCall(PetscFree2(funcs, ctxs)); 796d7ddef95SMatthew G. Knepley PetscFunctionReturn(0); 797d7ddef95SMatthew G. Knepley } 798d7ddef95SMatthew G. Knepley 799b278463cSMatthew G. Knepley /*@C 800ece3a9fcSMatthew G. Knepley DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector using a function of the coordinates and field data 801b278463cSMatthew G. Knepley 802b278463cSMatthew G. Knepley Input Parameters: 803*a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 804b278463cSMatthew G. Knepley . time - The time 805b278463cSMatthew G. Knepley . locU - A local vector with the input solution values 806b278463cSMatthew G. Knepley . field - The field to constrain 8071c531cf8SMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 8081c531cf8SMatthew G. Knepley . comps - An array of constrained component numbers, or NULL for all components 809*a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 810*a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 811b278463cSMatthew G. Knepley . ids - An array of ids for constrained points 812b278463cSMatthew G. Knepley . func - A pointwise function giving boundary values 813b278463cSMatthew G. Knepley - ctx - An optional user context for bcFunc 814b278463cSMatthew G. Knepley 815b278463cSMatthew G. Knepley Output Parameter: 816b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values 817b278463cSMatthew G. Knepley 818b278463cSMatthew G. Knepley Level: developer 819b278463cSMatthew G. Knepley 820*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()` 821b278463cSMatthew G. Knepley @*/ 822d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValuesEssentialField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void *ctx, Vec locX) 823d71ae5a4SJacob Faibussowitsch { 8249371c9d4SSatish Balay void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]); 825c60e475cSMatthew G. Knepley void **ctxs; 826c60e475cSMatthew G. Knepley PetscInt numFields; 827c60e475cSMatthew G. Knepley 828c60e475cSMatthew G. Knepley PetscFunctionBegin; 8299566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 8309566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 831c60e475cSMatthew G. Knepley funcs[field] = func; 832c60e475cSMatthew G. Knepley ctxs[field] = ctx; 8339566063dSJacob Faibussowitsch PetscCall(DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX)); 8349566063dSJacob Faibussowitsch PetscCall(PetscFree2(funcs, ctxs)); 835c60e475cSMatthew G. Knepley PetscFunctionReturn(0); 836c60e475cSMatthew G. Knepley } 837c60e475cSMatthew G. Knepley 838b278463cSMatthew G. Knepley /*@C 839d5b43468SJose E. Roman DMPlexInsertBoundaryValuesEssentialBdField - Insert boundary values into a local vector using a function of the coordinates and boundary field data 840ece3a9fcSMatthew G. Knepley 841ece3a9fcSMatthew G. Knepley Collective on dm 842ece3a9fcSMatthew G. Knepley 843ece3a9fcSMatthew G. Knepley Input Parameters: 844*a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 845ece3a9fcSMatthew G. Knepley . time - The time 846ece3a9fcSMatthew G. Knepley . locU - A local vector with the input solution values 847ece3a9fcSMatthew G. Knepley . field - The field to constrain 848ece3a9fcSMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 849ece3a9fcSMatthew G. Knepley . comps - An array of constrained component numbers, or NULL for all components 850*a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 851*a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 852ece3a9fcSMatthew G. Knepley . ids - An array of ids for constrained points 853ece3a9fcSMatthew G. Knepley . func - A pointwise function giving boundary values, the calling sequence is given in DMProjectBdFieldLabelLocal() 854ece3a9fcSMatthew G. Knepley - ctx - An optional user context for bcFunc 855ece3a9fcSMatthew G. Knepley 856ece3a9fcSMatthew G. Knepley Output Parameter: 857ece3a9fcSMatthew G. Knepley . locX - A local vector to receive the boundary values 858ece3a9fcSMatthew G. Knepley 859ece3a9fcSMatthew G. Knepley Level: developer 860ece3a9fcSMatthew G. Knepley 861*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectBdFieldLabelLocal()`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()` 862ece3a9fcSMatthew G. Knepley @*/ 863d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValuesEssentialBdField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void *ctx, Vec locX) 864d71ae5a4SJacob Faibussowitsch { 8659371c9d4SSatish Balay void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]); 866ece3a9fcSMatthew G. Knepley void **ctxs; 867ece3a9fcSMatthew G. Knepley PetscInt numFields; 868ece3a9fcSMatthew G. Knepley 869ece3a9fcSMatthew G. Knepley PetscFunctionBegin; 8709566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 8719566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 872ece3a9fcSMatthew G. Knepley funcs[field] = func; 873ece3a9fcSMatthew G. Knepley ctxs[field] = ctx; 8749566063dSJacob Faibussowitsch PetscCall(DMProjectBdFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX)); 8759566063dSJacob Faibussowitsch PetscCall(PetscFree2(funcs, ctxs)); 876ece3a9fcSMatthew G. Knepley PetscFunctionReturn(0); 877ece3a9fcSMatthew G. Knepley } 878ece3a9fcSMatthew G. Knepley 879ece3a9fcSMatthew G. Knepley /*@C 880b278463cSMatthew G. Knepley DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector 881b278463cSMatthew G. Knepley 882b278463cSMatthew G. Knepley Input Parameters: 883*a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 884b278463cSMatthew G. Knepley . time - The time 885b278463cSMatthew G. Knepley . faceGeometry - A vector with the FVM face geometry information 886b278463cSMatthew G. Knepley . cellGeometry - A vector with the FVM cell geometry information 887b278463cSMatthew G. Knepley . Grad - A vector with the FVM cell gradient information 888b278463cSMatthew G. Knepley . field - The field to constrain 8891c531cf8SMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 8901c531cf8SMatthew G. Knepley . comps - An array of constrained component numbers, or NULL for all components 891*a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 892*a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 893b278463cSMatthew G. Knepley . ids - An array of ids for constrained points 894b278463cSMatthew G. Knepley . func - A pointwise function giving boundary values 895b278463cSMatthew G. Knepley - ctx - An optional user context for bcFunc 896b278463cSMatthew G. Knepley 897b278463cSMatthew G. Knepley Output Parameter: 898b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values 899b278463cSMatthew G. Knepley 900b278463cSMatthew G. Knepley Level: developer 901b278463cSMatthew G. Knepley 902*a1cb98faSBarry Smith Note: 903*a1cb98faSBarry Smith This implementation currently ignores the numcomps/comps argument from `DMAddBoundary()` 904*a1cb98faSBarry Smith 905*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()` 906b278463cSMatthew G. Knepley @*/ 907d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValuesRiemann(DM dm, PetscReal time, Vec faceGeometry, Vec cellGeometry, Vec Grad, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *), void *ctx, Vec locX) 908d71ae5a4SJacob Faibussowitsch { 90961f58d28SMatthew G. Knepley PetscDS prob; 910da97024aSMatthew G. Knepley PetscSF sf; 911d7ddef95SMatthew G. Knepley DM dmFace, dmCell, dmGrad; 91220369375SToby Isaac const PetscScalar *facegeom, *cellgeom = NULL, *grad; 913da97024aSMatthew G. Knepley const PetscInt *leaves; 914d7ddef95SMatthew G. Knepley PetscScalar *x, *fx; 915520b3818SMatthew G. Knepley PetscInt dim, nleaves, loc, fStart, fEnd, pdim, i; 9165f80ce2aSJacob Faibussowitsch PetscErrorCode ierru = 0; 917d7ddef95SMatthew G. Knepley 918d7ddef95SMatthew G. Knepley PetscFunctionBegin; 9199566063dSJacob Faibussowitsch PetscCall(DMGetPointSF(dm, &sf)); 9209566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL)); 921da97024aSMatthew G. Knepley nleaves = PetscMax(0, nleaves); 9229566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 9239566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 9249566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 9259566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 9269566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 92720369375SToby Isaac if (cellGeometry) { 9289566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 9299566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 93020369375SToby Isaac } 931d7ddef95SMatthew G. Knepley if (Grad) { 932c0a6632aSMatthew G. Knepley PetscFV fv; 933c0a6632aSMatthew G. Knepley 9349566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fv)); 9359566063dSJacob Faibussowitsch PetscCall(VecGetDM(Grad, &dmGrad)); 9369566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Grad, &grad)); 9379566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 9389566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx)); 939d7ddef95SMatthew G. Knepley } 9409566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX, &x)); 941d7ddef95SMatthew G. Knepley for (i = 0; i < numids; ++i) { 942d7ddef95SMatthew G. Knepley IS faceIS; 943d7ddef95SMatthew G. Knepley const PetscInt *faces; 944d7ddef95SMatthew G. Knepley PetscInt numFaces, f; 945d7ddef95SMatthew G. Knepley 9469566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, ids[i], &faceIS)); 947d7ddef95SMatthew G. Knepley if (!faceIS) continue; /* No points with that id on this process */ 9489566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(faceIS, &numFaces)); 9499566063dSJacob Faibussowitsch PetscCall(ISGetIndices(faceIS, &faces)); 950d7ddef95SMatthew G. Knepley for (f = 0; f < numFaces; ++f) { 951d7ddef95SMatthew G. Knepley const PetscInt face = faces[f], *cells; 952640bce14SSatish Balay PetscFVFaceGeom *fg; 953d7ddef95SMatthew G. Knepley 954d7ddef95SMatthew G. Knepley if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */ 9559566063dSJacob Faibussowitsch PetscCall(PetscFindInt(face, nleaves, (PetscInt *)leaves, &loc)); 956da97024aSMatthew G. Knepley if (loc >= 0) continue; 9579566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 9589566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 959d7ddef95SMatthew G. Knepley if (Grad) { 960640bce14SSatish Balay PetscFVCellGeom *cg; 961640bce14SSatish Balay PetscScalar *cx, *cgrad; 962d7ddef95SMatthew G. Knepley PetscScalar *xG; 963d7ddef95SMatthew G. Knepley PetscReal dx[3]; 964d7ddef95SMatthew G. Knepley PetscInt d; 965d7ddef95SMatthew G. Knepley 9669566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg)); 9679566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &cx)); 9689566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad)); 9699566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG)); 970d7ddef95SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx); 971d7ddef95SMatthew G. Knepley for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d * dim], dx); 9729566063dSJacob Faibussowitsch PetscCall((*func)(time, fg->centroid, fg->normal, fx, xG, ctx)); 973d7ddef95SMatthew G. Knepley } else { 974640bce14SSatish Balay PetscScalar *xI; 975d7ddef95SMatthew G. Knepley PetscScalar *xG; 976d7ddef95SMatthew G. Knepley 9779566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &xI)); 9789566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG)); 979e735a8a9SMatthew G. Knepley ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx); 980e735a8a9SMatthew G. Knepley if (ierru) { 9819566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(faceIS, &faces)); 9829566063dSJacob Faibussowitsch PetscCall(ISDestroy(&faceIS)); 983e735a8a9SMatthew G. Knepley goto cleanup; 984e735a8a9SMatthew G. Knepley } 985d7ddef95SMatthew G. Knepley } 986d7ddef95SMatthew G. Knepley } 9879566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(faceIS, &faces)); 9889566063dSJacob Faibussowitsch PetscCall(ISDestroy(&faceIS)); 989d7ddef95SMatthew G. Knepley } 990e735a8a9SMatthew G. Knepley cleanup: 9919566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX, &x)); 992d7ddef95SMatthew G. Knepley if (Grad) { 9939566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx)); 9949566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Grad, &grad)); 995d7ddef95SMatthew G. Knepley } 9969566063dSJacob Faibussowitsch if (cellGeometry) PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 9979566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 9989566063dSJacob Faibussowitsch PetscCall(ierru); 999d7ddef95SMatthew G. Knepley PetscFunctionReturn(0); 1000d7ddef95SMatthew G. Knepley } 1001d7ddef95SMatthew G. Knepley 1002d71ae5a4SJacob Faibussowitsch static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 1003d71ae5a4SJacob Faibussowitsch { 10040c364540SMatthew G. Knepley PetscInt c; 10050c364540SMatthew G. Knepley for (c = 0; c < Nc; ++c) u[c] = 0.0; 10060c364540SMatthew G. Knepley return 0; 10070c364540SMatthew G. Knepley } 10080c364540SMatthew G. Knepley 1009d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1010d71ae5a4SJacob Faibussowitsch { 10110c364540SMatthew G. Knepley PetscObject isZero; 1012e5e52638SMatthew G. Knepley PetscDS prob; 1013d7ddef95SMatthew G. Knepley PetscInt numBd, b; 101455f2e967SMatthew G. Knepley 101555f2e967SMatthew G. Knepley PetscFunctionBegin; 10169566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 10179566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 10189566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero)); 101955f2e967SMatthew G. Knepley for (b = 0; b < numBd; ++b) { 102045480ffeSMatthew G. Knepley PetscWeakForm wf; 1021f971fd6bSMatthew G. Knepley DMBoundaryConditionType type; 102245480ffeSMatthew G. Knepley const char *name; 1023d7ddef95SMatthew G. Knepley DMLabel label; 10241c531cf8SMatthew G. Knepley PetscInt field, Nc; 10251c531cf8SMatthew G. Knepley const PetscInt *comps; 1026d7ddef95SMatthew G. Knepley PetscObject obj; 1027d7ddef95SMatthew G. Knepley PetscClassId id; 102845480ffeSMatthew G. Knepley void (*bvfunc)(void); 1029d7ddef95SMatthew G. Knepley PetscInt numids; 1030d7ddef95SMatthew G. Knepley const PetscInt *ids; 103155f2e967SMatthew G. Knepley void *ctx; 103255f2e967SMatthew G. Knepley 10339566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx)); 1034f971fd6bSMatthew G. Knepley if (insertEssential != (type & DM_BC_ESSENTIAL)) continue; 10359566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 10369566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 1037d7ddef95SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 1038c60e475cSMatthew G. Knepley switch (type) { 1039c60e475cSMatthew G. Knepley /* for FEM, there is no insertion to be done for non-essential boundary conditions */ 10409371c9d4SSatish Balay case DM_BC_ESSENTIAL: { 104145480ffeSMatthew G. Knepley PetscSimplePointFunc func = (PetscSimplePointFunc)bvfunc; 104245480ffeSMatthew G. Knepley 104345480ffeSMatthew G. Knepley if (isZero) func = zero; 10449566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 10459566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func, ctx, locX)); 10469566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 10479371c9d4SSatish Balay } break; 10489371c9d4SSatish Balay case DM_BC_ESSENTIAL_FIELD: { 104945480ffeSMatthew G. Knepley PetscPointFunc func = (PetscPointFunc)bvfunc; 105045480ffeSMatthew G. Knepley 10519566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 10529566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func, ctx, locX)); 10539566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 10549371c9d4SSatish Balay } break; 1055d71ae5a4SJacob Faibussowitsch default: 1056d71ae5a4SJacob Faibussowitsch break; 1057c60e475cSMatthew G. Knepley } 1058d7ddef95SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 105945480ffeSMatthew G. Knepley { 106045480ffeSMatthew G. Knepley PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *) = (PetscErrorCode(*)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *))bvfunc; 106145480ffeSMatthew G. Knepley 106243ea7facSMatthew G. Knepley if (!faceGeomFVM) continue; 10639566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids, func, ctx, locX)); 106445480ffeSMatthew G. Knepley } 106563a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 106655f2e967SMatthew G. Knepley } 106755f2e967SMatthew G. Knepley PetscFunctionReturn(0); 106855f2e967SMatthew G. Knepley } 106955f2e967SMatthew G. Knepley 1070d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1071d71ae5a4SJacob Faibussowitsch { 107256cf3b9cSMatthew G. Knepley PetscObject isZero; 107356cf3b9cSMatthew G. Knepley PetscDS prob; 107456cf3b9cSMatthew G. Knepley PetscInt numBd, b; 107556cf3b9cSMatthew G. Knepley 107656cf3b9cSMatthew G. Knepley PetscFunctionBegin; 107756cf3b9cSMatthew G. Knepley if (!locX) PetscFunctionReturn(0); 10789566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 10799566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 10809566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero)); 108156cf3b9cSMatthew G. Knepley for (b = 0; b < numBd; ++b) { 108245480ffeSMatthew G. Knepley PetscWeakForm wf; 108356cf3b9cSMatthew G. Knepley DMBoundaryConditionType type; 108445480ffeSMatthew G. Knepley const char *name; 108556cf3b9cSMatthew G. Knepley DMLabel label; 108656cf3b9cSMatthew G. Knepley PetscInt field, Nc; 108756cf3b9cSMatthew G. Knepley const PetscInt *comps; 108856cf3b9cSMatthew G. Knepley PetscObject obj; 108956cf3b9cSMatthew G. Knepley PetscClassId id; 109056cf3b9cSMatthew G. Knepley PetscInt numids; 109156cf3b9cSMatthew G. Knepley const PetscInt *ids; 109245480ffeSMatthew G. Knepley void (*bvfunc)(void); 109356cf3b9cSMatthew G. Knepley void *ctx; 109456cf3b9cSMatthew G. Knepley 10959566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, NULL, &bvfunc, &ctx)); 109656cf3b9cSMatthew G. Knepley if (insertEssential != (type & DM_BC_ESSENTIAL)) continue; 10979566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 10989566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 109956cf3b9cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 110056cf3b9cSMatthew G. Knepley switch (type) { 110156cf3b9cSMatthew G. Knepley /* for FEM, there is no insertion to be done for non-essential boundary conditions */ 11029371c9d4SSatish Balay case DM_BC_ESSENTIAL: { 110345480ffeSMatthew G. Knepley PetscSimplePointFunc func_t = (PetscSimplePointFunc)bvfunc; 110445480ffeSMatthew G. Knepley 110545480ffeSMatthew G. Knepley if (isZero) func_t = zero; 11069566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 11079566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func_t, ctx, locX)); 11089566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 11099371c9d4SSatish Balay } break; 11109371c9d4SSatish Balay case DM_BC_ESSENTIAL_FIELD: { 111145480ffeSMatthew G. Knepley PetscPointFunc func_t = (PetscPointFunc)bvfunc; 111245480ffeSMatthew G. Knepley 11139566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 11149566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func_t, ctx, locX)); 11159566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 11169371c9d4SSatish Balay } break; 1117d71ae5a4SJacob Faibussowitsch default: 1118d71ae5a4SJacob Faibussowitsch break; 111956cf3b9cSMatthew G. Knepley } 112063a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 112156cf3b9cSMatthew G. Knepley } 112256cf3b9cSMatthew G. Knepley PetscFunctionReturn(0); 112356cf3b9cSMatthew G. Knepley } 112456cf3b9cSMatthew G. Knepley 1125f1d73a7aSMatthew G. Knepley /*@ 1126f1d73a7aSMatthew G. Knepley DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector 1127f1d73a7aSMatthew G. Knepley 1128ed808b8fSJed Brown Not Collective 1129ed808b8fSJed Brown 1130f1d73a7aSMatthew G. Knepley Input Parameters: 1131*a1cb98faSBarry Smith + dm - The `DM` 1132f1d73a7aSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions 1133f1d73a7aSMatthew G. Knepley . time - The time 1134f1d73a7aSMatthew G. Knepley . faceGeomFVM - Face geometry data for FV discretizations 1135f1d73a7aSMatthew G. Knepley . cellGeomFVM - Cell geometry data for FV discretizations 1136f1d73a7aSMatthew G. Knepley - gradFVM - Gradient reconstruction data for FV discretizations 1137f1d73a7aSMatthew G. Knepley 1138f1d73a7aSMatthew G. Knepley Output Parameters: 1139f1d73a7aSMatthew G. Knepley . locX - Solution updated with boundary values 1140f1d73a7aSMatthew G. Knepley 1141ed808b8fSJed Brown Level: intermediate 1142f1d73a7aSMatthew G. Knepley 1143*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`, `DMAddBoundary()` 1144f1d73a7aSMatthew G. Knepley @*/ 1145d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1146d71ae5a4SJacob Faibussowitsch { 1147f1d73a7aSMatthew G. Knepley PetscFunctionBegin; 1148f1d73a7aSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1149064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 1150ad540459SPierre Jolivet if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5); 1151ad540459SPierre Jolivet if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6); 1152ad540459SPierre Jolivet if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7); 1153cac4c232SBarry Smith PetscTryMethod(dm, "DMPlexInsertBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX, time, faceGeomFVM, cellGeomFVM, gradFVM)); 1154f1d73a7aSMatthew G. Knepley PetscFunctionReturn(0); 1155f1d73a7aSMatthew G. Knepley } 1156f1d73a7aSMatthew G. Knepley 115756cf3b9cSMatthew G. Knepley /*@ 1158a5b23f4aSJose E. Roman DMPlexInsertTimeDerivativeBoundaryValues - Puts coefficients which represent boundary values of the time derivative into the local solution vector 115956cf3b9cSMatthew G. Knepley 116056cf3b9cSMatthew G. Knepley Input Parameters: 1161*a1cb98faSBarry Smith + dm - The `DM` 116256cf3b9cSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions 116356cf3b9cSMatthew G. Knepley . time - The time 116456cf3b9cSMatthew G. Knepley . faceGeomFVM - Face geometry data for FV discretizations 116556cf3b9cSMatthew G. Knepley . cellGeomFVM - Cell geometry data for FV discretizations 116656cf3b9cSMatthew G. Knepley - gradFVM - Gradient reconstruction data for FV discretizations 116756cf3b9cSMatthew G. Knepley 116856cf3b9cSMatthew G. Knepley Output Parameters: 116956cf3b9cSMatthew G. Knepley . locX_t - Solution updated with boundary values 117056cf3b9cSMatthew G. Knepley 117156cf3b9cSMatthew G. Knepley Level: developer 117256cf3b9cSMatthew G. Knepley 1173*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()` 117456cf3b9cSMatthew G. Knepley @*/ 1175d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues(DM dm, PetscBool insertEssential, Vec locX_t, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1176d71ae5a4SJacob Faibussowitsch { 117756cf3b9cSMatthew G. Knepley PetscFunctionBegin; 117856cf3b9cSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1179ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 3); 1180ad540459SPierre Jolivet if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5); 1181ad540459SPierre Jolivet if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6); 1182ad540459SPierre Jolivet if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7); 1183cac4c232SBarry Smith PetscTryMethod(dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX_t, time, faceGeomFVM, cellGeomFVM, gradFVM)); 118456cf3b9cSMatthew G. Knepley PetscFunctionReturn(0); 118556cf3b9cSMatthew G. Knepley } 118656cf3b9cSMatthew G. Knepley 1187d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1188d71ae5a4SJacob Faibussowitsch { 1189574a98acSMatthew G. Knepley Vec localX; 1190574a98acSMatthew G. Knepley 1191574a98acSMatthew G. Knepley PetscFunctionBegin; 11929566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 11939566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL)); 11949566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 11959566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 11969566063dSJacob Faibussowitsch PetscCall(DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff)); 11979566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 1198574a98acSMatthew G. Knepley PetscFunctionReturn(0); 1199574a98acSMatthew G. Knepley } 1200574a98acSMatthew G. Knepley 1201574a98acSMatthew G. Knepley /*@C 1202ca3d3a14SMatthew G. Knepley DMComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 1203574a98acSMatthew G. Knepley 1204d083f849SBarry Smith Collective on dm 1205c0f8e1fdSMatthew G. Knepley 1206574a98acSMatthew G. Knepley Input Parameters: 1207*a1cb98faSBarry Smith + dm - The `DM` 1208574a98acSMatthew G. Knepley . time - The time 1209574a98acSMatthew G. Knepley . funcs - The functions to evaluate for each field component 1210574a98acSMatthew G. Knepley . ctxs - Optional array of contexts to pass to each function, or NULL. 1211574a98acSMatthew G. Knepley - localX - The coefficient vector u_h, a local vector 1212574a98acSMatthew G. Knepley 1213574a98acSMatthew G. Knepley Output Parameter: 1214574a98acSMatthew G. Knepley . diff - The diff ||u - u_h||_2 1215574a98acSMatthew G. Knepley 1216574a98acSMatthew G. Knepley Level: developer 1217574a98acSMatthew G. Knepley 1218*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1219574a98acSMatthew G. Knepley @*/ 1220d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff) 1221d71ae5a4SJacob Faibussowitsch { 12220f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1223ca3d3a14SMatthew G. Knepley DM tdm; 1224ca3d3a14SMatthew G. Knepley Vec tv; 1225cb1e1211SMatthew G Knepley PetscSection section; 1226c5bbbd5bSMatthew G. Knepley PetscQuadrature quad; 12274bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 122815496722SMatthew G. Knepley PetscScalar *funcVal, *interpolant; 12294bee2e38SMatthew G. Knepley PetscReal *coords, *gcoords; 1230cb1e1211SMatthew G Knepley PetscReal localDiff = 0.0; 12317318780aSToby Isaac const PetscReal *quadWeights; 1232412e9a14SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, c, field, fieldOffset; 1233ca3d3a14SMatthew G. Knepley PetscBool transform; 1234cb1e1211SMatthew G Knepley 1235cb1e1211SMatthew G Knepley PetscFunctionBegin; 12369566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 12379566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 12382a4e142eSMatthew G. Knepley fegeom.dimEmbed = coordDim; 12399566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 12409566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 12419566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 12429566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 12439566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 1244cb1e1211SMatthew G Knepley for (field = 0; field < numFields; ++field) { 124515496722SMatthew G. Knepley PetscObject obj; 124615496722SMatthew G. Knepley PetscClassId id; 1247c5bbbd5bSMatthew G. Knepley PetscInt Nc; 1248c5bbbd5bSMatthew G. Knepley 12499566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 12509566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 125115496722SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 125215496722SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 125315496722SMatthew G. Knepley 12549566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 12559566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 125615496722SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 125715496722SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 125815496722SMatthew G. Knepley 12599566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 12609566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 126163a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1262c5bbbd5bSMatthew G. Knepley numComponents += Nc; 1263cb1e1211SMatthew G Knepley } 12649566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 126563a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 12669566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 12679566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 12689566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 1269cb1e1211SMatthew G Knepley for (c = cStart; c < cEnd; ++c) { 1270a1e44745SMatthew G. Knepley PetscScalar *x = NULL; 1271cb1e1211SMatthew G Knepley PetscReal elemDiff = 0.0; 12729c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1273cb1e1211SMatthew G Knepley 12749566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 12759566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x)); 1276cb1e1211SMatthew G Knepley 127715496722SMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 127815496722SMatthew G. Knepley PetscObject obj; 127915496722SMatthew G. Knepley PetscClassId id; 1280c110b1eeSGeoffrey Irving void *const ctx = ctxs ? ctxs[field] : NULL; 128115496722SMatthew G. Knepley PetscInt Nb, Nc, q, fc; 1282cb1e1211SMatthew G Knepley 12839566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 12849566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 12859371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 12869371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 12879371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 12889371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 12899371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 12909371c9d4SSatish Balay Nb = 1; 12919371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1292cb1e1211SMatthew G Knepley if (debug) { 1293cb1e1211SMatthew G Knepley char title[1024]; 129463a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 12959566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1296cb1e1211SMatthew G Knepley } 12977318780aSToby Isaac for (q = 0; q < Nq; ++q) { 12982a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1299d0609cedSBarry Smith PetscErrorCode ierr; 13002a4e142eSMatthew G. Knepley 13012a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 13022a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 13032a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 13042a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 130563a3b9bcSJacob Faibussowitsch PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", point %" PetscInt_FMT, (double)fegeom.detJ[q], c, q); 1306d3a7d86cSMatthew G. Knepley if (transform) { 1307d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * Nq]; 13089566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx)); 1309d3a7d86cSMatthew G. Knepley } else { 1310d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * q]; 1311d3a7d86cSMatthew G. Knepley } 13129566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(funcVal, Nc)); 1313ca3d3a14SMatthew G. Knepley ierr = (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx); 1314e735a8a9SMatthew G. Knepley if (ierr) { 13159566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 13169566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 13179566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1318e735a8a9SMatthew G. Knepley } 13199566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 13209566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 13219566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 13222df84da0SMatthew G. Knepley else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 132315496722SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1324beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 13259371c9d4SSatish Balay if (debug) 13269371c9d4SSatish Balay PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " field %" PetscInt_FMT ",%" PetscInt_FMT " point %g %g %g diff %g (%g, %g)\n", c, field, fc, (double)(coordDim > 0 ? coords[coordDim * q] : 0.), (double)(coordDim > 1 ? coords[coordDim * q + 1] : 0.), (double)(coordDim > 2 ? coords[coordDim * q + 2] : 0.), 13279371c9d4SSatish Balay (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]), (double)PetscRealPart(interpolant[fc]), (double)PetscRealPart(funcVal[fc]))); 13284bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1329cb1e1211SMatthew G Knepley } 1330cb1e1211SMatthew G Knepley } 13319c3cf19fSMatthew G. Knepley fieldOffset += Nb; 1332beaa55a6SMatthew G. Knepley qc += Nc; 1333cb1e1211SMatthew G Knepley } 13349566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 13359566063dSJacob Faibussowitsch if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 1336cb1e1211SMatthew G Knepley localDiff += elemDiff; 1337cb1e1211SMatthew G Knepley } 13389566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 13391c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 1340cb1e1211SMatthew G Knepley *diff = PetscSqrtReal(*diff); 1341cb1e1211SMatthew G Knepley PetscFunctionReturn(0); 1342cb1e1211SMatthew G Knepley } 1343cb1e1211SMatthew G Knepley 1344d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2GradientDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff) 1345d71ae5a4SJacob Faibussowitsch { 13460f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1347ca3d3a14SMatthew G. Knepley DM tdm; 1348cb1e1211SMatthew G Knepley PetscSection section; 134940e14135SMatthew G. Knepley PetscQuadrature quad; 1350ca3d3a14SMatthew G. Knepley Vec localX, tv; 13519c3cf19fSMatthew G. Knepley PetscScalar *funcVal, *interpolant; 13522a4e142eSMatthew G. Knepley const PetscReal *quadWeights; 13534bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 13544bee2e38SMatthew G. Knepley PetscReal *coords, *gcoords; 135540e14135SMatthew G. Knepley PetscReal localDiff = 0.0; 1356485ad865SMatthew G. Knepley PetscInt dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset; 1357ca3d3a14SMatthew G. Knepley PetscBool transform; 1358cb1e1211SMatthew G Knepley 1359cb1e1211SMatthew G Knepley PetscFunctionBegin; 13609566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 13619566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 13624bee2e38SMatthew G. Knepley fegeom.dimEmbed = coordDim; 13639566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 13649566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 13659566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 13669566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 13679566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 13689566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 13699566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 13709566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 1371652b88e8SMatthew G. Knepley for (field = 0; field < numFields; ++field) { 13720f2d7e86SMatthew G. Knepley PetscFE fe; 137340e14135SMatthew G. Knepley PetscInt Nc; 1374652b88e8SMatthew G. Knepley 13759566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe)); 13769566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 13779566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 137840e14135SMatthew G. Knepley numComponents += Nc; 1379652b88e8SMatthew G. Knepley } 13809566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 138163a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 13829566063dSJacob Faibussowitsch /* PetscCall(DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX)); */ 13839566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(numComponents, &funcVal, coordDim * Nq, &coords, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ, numComponents * coordDim, &interpolant, Nq, &fegeom.detJ)); 13849566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 138540e14135SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 138640e14135SMatthew G. Knepley PetscScalar *x = NULL; 138740e14135SMatthew G. Knepley PetscReal elemDiff = 0.0; 13889c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1389652b88e8SMatthew G. Knepley 13909566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 13919566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x)); 139240e14135SMatthew G. Knepley 13939c3cf19fSMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 13940f2d7e86SMatthew G. Knepley PetscFE fe; 139551259fa3SMatthew G. Knepley void *const ctx = ctxs ? ctxs[field] : NULL; 13969c3cf19fSMatthew G. Knepley PetscInt Nb, Nc, q, fc; 139740e14135SMatthew G. Knepley 13989566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe)); 13999566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 14009566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 140140e14135SMatthew G. Knepley if (debug) { 140240e14135SMatthew G. Knepley char title[1024]; 14039566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 14049566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1405652b88e8SMatthew G. Knepley } 14069c3cf19fSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 14072a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1408d0609cedSBarry Smith PetscErrorCode ierr; 14092a4e142eSMatthew G. Knepley 14102a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 14112a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 14122a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 14132a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 14142df84da0SMatthew G. Knepley PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", quadrature points %" PetscInt_FMT, (double)fegeom.detJ[q], c, q); 1415d3a7d86cSMatthew G. Knepley if (transform) { 1416d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * Nq]; 14179566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx)); 1418d3a7d86cSMatthew G. Knepley } else { 1419d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * q]; 1420d3a7d86cSMatthew G. Knepley } 14219566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(funcVal, Nc)); 14224bee2e38SMatthew G. Knepley ierr = (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx); 1423e735a8a9SMatthew G. Knepley if (ierr) { 14249566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 14259566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 14269566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ)); 1427e735a8a9SMatthew G. Knepley } 14289566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 14299566063dSJacob Faibussowitsch PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[fieldOffset], &qgeom, q, interpolant)); 14304bee2e38SMatthew G. Knepley /* Overwrite with the dot product if the normal is given */ 14314bee2e38SMatthew G. Knepley if (n) { 14324bee2e38SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 14334bee2e38SMatthew G. Knepley PetscScalar sum = 0.0; 14344bee2e38SMatthew G. Knepley PetscInt d; 14354bee2e38SMatthew G. Knepley for (d = 0; d < dim; ++d) sum += interpolant[fc * dim + d] * n[d]; 14364bee2e38SMatthew G. Knepley interpolant[fc] = sum; 14374bee2e38SMatthew G. Knepley } 14384bee2e38SMatthew G. Knepley } 14399c3cf19fSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1440beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 144163a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " fieldDer %" PetscInt_FMT ",%" PetscInt_FMT " diff %g\n", c, field, fc, (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]))); 14424bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 144340e14135SMatthew G. Knepley } 144440e14135SMatthew G. Knepley } 14459c3cf19fSMatthew G. Knepley fieldOffset += Nb; 14469c3cf19fSMatthew G. Knepley qc += Nc; 144740e14135SMatthew G. Knepley } 14489566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 144963a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 145040e14135SMatthew G. Knepley localDiff += elemDiff; 145140e14135SMatthew G. Knepley } 14529566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ)); 14539566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 14541c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 145540e14135SMatthew G. Knepley *diff = PetscSqrtReal(*diff); 1456cb1e1211SMatthew G Knepley PetscFunctionReturn(0); 1457cb1e1211SMatthew G Knepley } 1458cb1e1211SMatthew G Knepley 1459d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1460d71ae5a4SJacob Faibussowitsch { 14610f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1462ca3d3a14SMatthew G. Knepley DM tdm; 1463083401c6SMatthew G. Knepley DMLabel depthLabel; 146473d901b8SMatthew G. Knepley PetscSection section; 1465ca3d3a14SMatthew G. Knepley Vec localX, tv; 146673d901b8SMatthew G. Knepley PetscReal *localDiff; 1467083401c6SMatthew G. Knepley PetscInt dim, depth, dE, Nf, f, Nds, s; 1468ca3d3a14SMatthew G. Knepley PetscBool transform; 146973d901b8SMatthew G. Knepley 147073d901b8SMatthew G. Knepley PetscFunctionBegin; 14719566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 14729566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dE)); 14739566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 14749566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 14759566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 14769566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 14779566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 14789566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 14799566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 14809566063dSJacob Faibussowitsch PetscCall(DMLabelGetNumValues(depthLabel, &depth)); 1481083401c6SMatthew G. Knepley 14829566063dSJacob Faibussowitsch PetscCall(VecSet(localX, 0.0)); 14839566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 14849566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 14859566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 14869566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 14879566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(Nf, &localDiff)); 1488083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 1489083401c6SMatthew G. Knepley PetscDS ds; 1490083401c6SMatthew G. Knepley DMLabel label; 1491083401c6SMatthew G. Knepley IS fieldIS, pointIS; 1492083401c6SMatthew G. Knepley const PetscInt *fields, *points = NULL; 1493083401c6SMatthew G. Knepley PetscQuadrature quad; 1494083401c6SMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1495083401c6SMatthew G. Knepley PetscFEGeom fegeom; 1496083401c6SMatthew G. Knepley PetscReal *coords, *gcoords; 1497083401c6SMatthew G. Knepley PetscScalar *funcVal, *interpolant; 14985fedec97SMatthew G. Knepley PetscBool isCohesive; 1499083401c6SMatthew G. Knepley PetscInt qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf; 150073d901b8SMatthew G. Knepley 15019566063dSJacob Faibussowitsch PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds)); 15029566063dSJacob Faibussowitsch PetscCall(ISGetIndices(fieldIS, &fields)); 15039566063dSJacob Faibussowitsch PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 15049566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &dsNf)); 15059566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(ds, &totNc)); 15069566063dSJacob Faibussowitsch PetscCall(PetscDSGetQuadrature(ds, &quad)); 15079566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 150863a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != totNc), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, totNc); 15099566063dSJacob Faibussowitsch PetscCall(PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE * (Nq + 1), &coords, Nq, &fegeom.detJ, dE * dE * Nq, &fegeom.J, dE * dE * Nq, &fegeom.invJ)); 1510083401c6SMatthew G. Knepley if (!label) { 15119566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1512083401c6SMatthew G. Knepley } else { 15139566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 15149566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &cEnd)); 15159566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 1516083401c6SMatthew G. Knepley } 151773d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1518083401c6SMatthew G. Knepley const PetscInt cell = points ? points[c] : c; 151973d901b8SMatthew G. Knepley PetscScalar *x = NULL; 15205fedec97SMatthew G. Knepley const PetscInt *cone; 15215fedec97SMatthew G. Knepley PetscInt qc = 0, fOff = 0, dep; 152273d901b8SMatthew G. Knepley 15239566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(depthLabel, cell, &dep)); 1524083401c6SMatthew G. Knepley if (dep != depth - 1) continue; 15255fedec97SMatthew G. Knepley if (isCohesive) { 15269566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 15279566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 152896959cd1SMatthew G. Knepley } else { 15299566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 153096959cd1SMatthew G. Knepley } 15319566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, localX, cell, NULL, &x)); 15325fedec97SMatthew G. Knepley for (f = 0; f < dsNf; ++f) { 153315496722SMatthew G. Knepley PetscObject obj; 153415496722SMatthew G. Knepley PetscClassId id; 1535083401c6SMatthew G. Knepley void *const ctx = ctxs ? ctxs[fields[f]] : NULL; 153615496722SMatthew G. Knepley PetscInt Nb, Nc, q, fc; 153715496722SMatthew G. Knepley PetscReal elemDiff = 0.0; 15385fedec97SMatthew G. Knepley PetscBool cohesive; 153915496722SMatthew G. Knepley 15409566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 15415fedec97SMatthew G. Knepley if (isCohesive && !cohesive) continue; 15429566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 15439566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 15449371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 15459371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 15469371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 15479371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 15489371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 15499371c9d4SSatish Balay Nb = 1; 15509371c9d4SSatish Balay } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 155173d901b8SMatthew G. Knepley if (debug) { 155273d901b8SMatthew G. Knepley char title[1024]; 155363a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, fields[f])); 15549566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(cell, title, Nb, &x[fOff])); 155573d901b8SMatthew G. Knepley } 15567318780aSToby Isaac for (q = 0; q < Nq; ++q) { 15572a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1558d0609cedSBarry Smith PetscErrorCode ierr; 15592a4e142eSMatthew G. Knepley 15602a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 1561083401c6SMatthew G. Knepley qgeom.J = &fegeom.J[q * dE * dE]; 1562083401c6SMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * dE * dE]; 15632a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 156463a3b9bcSJacob Faibussowitsch PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for cell %" PetscInt_FMT ", quadrature point %" PetscInt_FMT, (double)fegeom.detJ[q], cell, q); 1565d3a7d86cSMatthew G. Knepley if (transform) { 1566083401c6SMatthew G. Knepley gcoords = &coords[dE * Nq]; 15679566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE * q], PETSC_TRUE, dE, &coords[dE * q], gcoords, dm->transformCtx)); 1568d3a7d86cSMatthew G. Knepley } else { 1569083401c6SMatthew G. Knepley gcoords = &coords[dE * q]; 1570d3a7d86cSMatthew G. Knepley } 15712df84da0SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) funcVal[fc] = 0.; 1572083401c6SMatthew G. Knepley ierr = (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx); 1573e735a8a9SMatthew G. Knepley if (ierr) { 15749566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 15759566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 15769566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1577e735a8a9SMatthew G. Knepley } 15789566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[dE * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 157996959cd1SMatthew G. Knepley /* Call once for each face, except for lagrange field */ 15809566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fOff], &qgeom, q, interpolant)); 15819566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fOff], q, interpolant)); 158263a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 158315496722SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1584beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 15859371c9d4SSatish Balay if (debug) 15869371c9d4SSatish Balay PetscCall(PetscPrintf(PETSC_COMM_SELF, " cell %" PetscInt_FMT " field %" PetscInt_FMT ",%" PetscInt_FMT " point %g %g %g diff %g\n", cell, fields[f], fc, (double)(dE > 0 ? coords[dE * q] : 0.), (double)(dE > 1 ? coords[dE * q + 1] : 0.), (double)(dE > 2 ? coords[dE * q + 2] : 0.), 15879371c9d4SSatish Balay (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]))); 15884bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 158973d901b8SMatthew G. Knepley } 159073d901b8SMatthew G. Knepley } 1591083401c6SMatthew G. Knepley fOff += Nb; 15929c3cf19fSMatthew G. Knepley qc += Nc; 1593083401c6SMatthew G. Knepley localDiff[fields[f]] += elemDiff; 159463a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " cell %" PetscInt_FMT " field %" PetscInt_FMT " cum diff %g\n", cell, fields[f], (double)localDiff[fields[f]])); 159573d901b8SMatthew G. Knepley } 15969566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 1597083401c6SMatthew G. Knepley } 1598083401c6SMatthew G. Knepley if (label) { 15999566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 16009566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 1601083401c6SMatthew G. Knepley } 16029566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(fieldIS, &fields)); 16039566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 160473d901b8SMatthew G. Knepley } 16059566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 16061c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 16079566063dSJacob Faibussowitsch PetscCall(PetscFree(localDiff)); 1608083401c6SMatthew G. Knepley for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]); 160973d901b8SMatthew G. Knepley PetscFunctionReturn(0); 161073d901b8SMatthew G. Knepley } 161173d901b8SMatthew G. Knepley 1612e729f68cSMatthew G. Knepley /*@C 1613e729f68cSMatthew G. Knepley DMPlexComputeL2DiffVec - This function computes the cellwise L_2 difference between a function u and an FEM interpolant solution u_h, and stores it in a Vec. 1614e729f68cSMatthew G. Knepley 1615d083f849SBarry Smith Collective on dm 1616c0f8e1fdSMatthew G. Knepley 1617e729f68cSMatthew G. Knepley Input Parameters: 1618*a1cb98faSBarry Smith + dm - The `DM` 16190163fd50SMatthew G. Knepley . time - The time 1620ca3eba1bSToby Isaac . funcs - The functions to evaluate for each field component: NULL means that component does not contribute to error calculation 1621e729f68cSMatthew G. Knepley . ctxs - Optional array of contexts to pass to each function, or NULL. 1622e729f68cSMatthew G. Knepley - X - The coefficient vector u_h 1623e729f68cSMatthew G. Knepley 1624e729f68cSMatthew G. Knepley Output Parameter: 1625e729f68cSMatthew G. Knepley . D - A Vec which holds the difference ||u - u_h||_2 for each cell 1626e729f68cSMatthew G. Knepley 1627e729f68cSMatthew G. Knepley Level: developer 1628e729f68cSMatthew G. Knepley 1629*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1630e729f68cSMatthew G. Knepley @*/ 1631d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D) 1632d71ae5a4SJacob Faibussowitsch { 1633e729f68cSMatthew G. Knepley PetscSection section; 1634e729f68cSMatthew G. Knepley PetscQuadrature quad; 1635e729f68cSMatthew G. Knepley Vec localX; 16364bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 1637e729f68cSMatthew G. Knepley PetscScalar *funcVal, *interpolant; 16384bee2e38SMatthew G. Knepley PetscReal *coords; 1639e729f68cSMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1640485ad865SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset; 1641e729f68cSMatthew G. Knepley 1642e729f68cSMatthew G. Knepley PetscFunctionBegin; 16439566063dSJacob Faibussowitsch PetscCall(VecSet(D, 0.0)); 16449566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 16459566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 16469566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 16479566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 16489566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 16499566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 16509566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 16519566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1652e729f68cSMatthew G. Knepley for (field = 0; field < numFields; ++field) { 1653e729f68cSMatthew G. Knepley PetscObject obj; 1654e729f68cSMatthew G. Knepley PetscClassId id; 1655e729f68cSMatthew G. Knepley PetscInt Nc; 1656e729f68cSMatthew G. Knepley 16579566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 16589566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 1659e729f68cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 1660e729f68cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 1661e729f68cSMatthew G. Knepley 16629566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 16639566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1664e729f68cSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 1665e729f68cSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 1666e729f68cSMatthew G. Knepley 16679566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 16689566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 166963a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1670e729f68cSMatthew G. Knepley numComponents += Nc; 1671e729f68cSMatthew G. Knepley } 16729566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 167363a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 16749566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 16759566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1676e729f68cSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1677e729f68cSMatthew G. Knepley PetscScalar *x = NULL; 16786f288a59SMatthew G. Knepley PetscScalar elemDiff = 0.0; 16799c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1680e729f68cSMatthew G. Knepley 16819566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 16829566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x)); 1683e729f68cSMatthew G. Knepley 1684e729f68cSMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1685e729f68cSMatthew G. Knepley PetscObject obj; 1686e729f68cSMatthew G. Knepley PetscClassId id; 1687e729f68cSMatthew G. Knepley void *const ctx = ctxs ? ctxs[field] : NULL; 1688e729f68cSMatthew G. Knepley PetscInt Nb, Nc, q, fc; 1689e729f68cSMatthew G. Knepley 16909566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 16919566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 16929371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 16939371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 16949371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 16959371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 16969371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 16979371c9d4SSatish Balay Nb = 1; 16989371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 169923f34ed2SToby Isaac if (funcs[field]) { 17007318780aSToby Isaac for (q = 0; q < Nq; ++q) { 17012a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 17022a4e142eSMatthew G. Knepley 17032a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 17042a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 17052a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 17062a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 170763a3b9bcSJacob Faibussowitsch PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", quadrature points %" PetscInt_FMT, (double)fegeom.detJ[q], c, q); 17089566063dSJacob Faibussowitsch PetscCall((*funcs[field])(coordDim, time, &coords[q * coordDim], Nc, funcVal, ctx)); 1709c3e24edfSBarry Smith #if defined(needs_fix_with_return_code_argument) 1710e735a8a9SMatthew G. Knepley if (ierr) { 17119566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 17129566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 17139566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 1714e735a8a9SMatthew G. Knepley } 1715c3e24edfSBarry Smith #endif 17169566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 17179566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 171863a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1719e729f68cSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1720beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 17214bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1722e729f68cSMatthew G. Knepley } 1723e729f68cSMatthew G. Knepley } 172423f34ed2SToby Isaac } 1725beaa55a6SMatthew G. Knepley fieldOffset += Nb; 17269c3cf19fSMatthew G. Knepley qc += Nc; 1727e729f68cSMatthew G. Knepley } 17289566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 17299566063dSJacob Faibussowitsch PetscCall(VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES)); 1730e729f68cSMatthew G. Knepley } 17319566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 17329566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 17339566063dSJacob Faibussowitsch PetscCall(VecSqrtAbs(D)); 1734e729f68cSMatthew G. Knepley PetscFunctionReturn(0); 1735e729f68cSMatthew G. Knepley } 1736e729f68cSMatthew G. Knepley 17375f0b18bfSMatthew G. Knepley /*@ 17385f0b18bfSMatthew G. Knepley DMPlexComputeClementInterpolant - This function computes the L2 projection of the cellwise values of a function u onto P1, and stores it in a Vec. 17395f0b18bfSMatthew G. Knepley 17405f0b18bfSMatthew G. Knepley Collective on dm 17415f0b18bfSMatthew G. Knepley 17425f0b18bfSMatthew G. Knepley Input Parameters: 1743*a1cb98faSBarry Smith + dm - The `DM` 17445f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h 17455f0b18bfSMatthew G. Knepley 17465f0b18bfSMatthew G. Knepley Output Parameter: 1747*a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the function 17485f0b18bfSMatthew G. Knepley 17495f0b18bfSMatthew G. Knepley Level: developer 17505f0b18bfSMatthew G. Knepley 1751*a1cb98faSBarry Smith Note: 1752*a1cb98faSBarry Smith $ u_h(v_i) = \sum_{T_i \in support(v_i)} |T_i| u_h(T_i) / \sum_{T_i \in support(v_i)} |T_i| $ where $ |T_i| $ is the cell volume 1753*a1cb98faSBarry Smith 1754*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 17555f0b18bfSMatthew G. Knepley @*/ 1756d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeClementInterpolant(DM dm, Vec locX, Vec locC) 1757d71ae5a4SJacob Faibussowitsch { 17585f0b18bfSMatthew G. Knepley PetscInt debug = ((DM_Plex *)dm->data)->printFEM; 17595f0b18bfSMatthew G. Knepley DM dmc; 17605f0b18bfSMatthew G. Knepley PetscQuadrature quad; 17615f0b18bfSMatthew G. Knepley PetscScalar *interpolant, *valsum; 17625f0b18bfSMatthew G. Knepley PetscFEGeom fegeom; 17635f0b18bfSMatthew G. Knepley PetscReal *coords; 17645f0b18bfSMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 17655f0b18bfSMatthew G. Knepley PetscInt dim, cdim, Nf, f, Nc = 0, Nq, qNc, cStart, cEnd, vStart, vEnd, v; 17665f0b18bfSMatthew G. Knepley 17675f0b18bfSMatthew G. Knepley PetscFunctionBegin; 17689566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 17699566063dSJacob Faibussowitsch PetscCall(VecGetDM(locC, &dmc)); 17709566063dSJacob Faibussowitsch PetscCall(VecSet(locC, 0.0)); 17719566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 17729566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 17735f0b18bfSMatthew G. Knepley fegeom.dimEmbed = cdim; 17749566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 17755f0b18bfSMatthew G. Knepley PetscCheck(Nf > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 17765f0b18bfSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 17775f0b18bfSMatthew G. Knepley PetscObject obj; 17785f0b18bfSMatthew G. Knepley PetscClassId id; 17795f0b18bfSMatthew G. Knepley PetscInt fNc; 17805f0b18bfSMatthew G. Knepley 17819566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, f, NULL, &obj)); 17829566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 17835f0b18bfSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 17845f0b18bfSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 17855f0b18bfSMatthew G. Knepley 17869566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 17879566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &fNc)); 17885f0b18bfSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 17895f0b18bfSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 17905f0b18bfSMatthew G. Knepley 17919566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 17929566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &fNc)); 179363a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 17945f0b18bfSMatthew G. Knepley Nc += fNc; 17955f0b18bfSMatthew G. Knepley } 17969566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 179763a3b9bcSJacob Faibussowitsch PetscCheck(qNc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " > 1", qNc); 17989566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(Nc * 2, &valsum, Nc, &interpolant, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ)); 17999566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 18009566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 18015f0b18bfSMatthew G. Knepley for (v = vStart; v < vEnd; ++v) { 18025f0b18bfSMatthew G. Knepley PetscScalar volsum = 0.0; 18035f0b18bfSMatthew G. Knepley PetscInt *star = NULL; 18045f0b18bfSMatthew G. Knepley PetscInt starSize, st, fc; 18055f0b18bfSMatthew G. Knepley 18069566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(valsum, Nc)); 18079566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 18085f0b18bfSMatthew G. Knepley for (st = 0; st < starSize * 2; st += 2) { 18095f0b18bfSMatthew G. Knepley const PetscInt cell = star[st]; 18105f0b18bfSMatthew G. Knepley PetscScalar *val = &valsum[Nc]; 18115f0b18bfSMatthew G. Knepley PetscScalar *x = NULL; 18125f0b18bfSMatthew G. Knepley PetscReal vol = 0.0; 18135f0b18bfSMatthew G. Knepley PetscInt foff = 0; 18145f0b18bfSMatthew G. Knepley 18155f0b18bfSMatthew G. Knepley if ((cell < cStart) || (cell >= cEnd)) continue; 18169566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 18179566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 18185f0b18bfSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 18195f0b18bfSMatthew G. Knepley PetscObject obj; 18205f0b18bfSMatthew G. Knepley PetscClassId id; 18215f0b18bfSMatthew G. Knepley PetscInt Nb, fNc, q; 18225f0b18bfSMatthew G. Knepley 18239566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(val, Nc)); 18249566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, f, NULL, &obj)); 18259566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 18269371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 18279371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &fNc)); 18289371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 18299371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 18309371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &fNc)); 18319371c9d4SSatish Balay Nb = 1; 18329371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 18335f0b18bfSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 18345f0b18bfSMatthew G. Knepley const PetscReal wt = quadWeights[q] * fegeom.detJ[q]; 18355f0b18bfSMatthew G. Knepley PetscFEGeom qgeom; 18365f0b18bfSMatthew G. Knepley 18375f0b18bfSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 18385f0b18bfSMatthew G. Knepley qgeom.J = &fegeom.J[q * cdim * cdim]; 18395f0b18bfSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * cdim * cdim]; 18405f0b18bfSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 184163a3b9bcSJacob Faibussowitsch PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", quadrature points %" PetscInt_FMT, (double)fegeom.detJ[q], cell, q); 18429566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[foff], &qgeom, q, interpolant)); 184363a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 18445f0b18bfSMatthew G. Knepley for (fc = 0; fc < fNc; ++fc) val[foff + fc] += interpolant[fc] * wt; 18455f0b18bfSMatthew G. Knepley vol += wt; 18465f0b18bfSMatthew G. Knepley } 18475f0b18bfSMatthew G. Knepley foff += Nb; 18485f0b18bfSMatthew G. Knepley } 18499566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 18505f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) valsum[fc] += val[fc]; 18515f0b18bfSMatthew G. Knepley volsum += vol; 18525f0b18bfSMatthew G. Knepley if (debug) { 18539566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " value: [", v, cell)); 18545f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 18559566063dSJacob Faibussowitsch if (fc) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 18569566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(val[fc]))); 18575f0b18bfSMatthew G. Knepley } 18589566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 18595f0b18bfSMatthew G. Knepley } 18605f0b18bfSMatthew G. Knepley } 18615f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) valsum[fc] /= volsum; 18629566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 18639566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dmc, NULL, locC, v, valsum, INSERT_VALUES)); 18645f0b18bfSMatthew G. Knepley } 18659566063dSJacob Faibussowitsch PetscCall(PetscFree6(valsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 18665f0b18bfSMatthew G. Knepley PetscFunctionReturn(0); 18675f0b18bfSMatthew G. Knepley } 18685f0b18bfSMatthew G. Knepley 18695f0b18bfSMatthew G. Knepley /*@ 18701555c271SMatthew G. Knepley DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1, and stores it in a Vec. 18711555c271SMatthew G. Knepley 1872d083f849SBarry Smith Collective on dm 1873c0f8e1fdSMatthew G. Knepley 18741555c271SMatthew G. Knepley Input Parameters: 1875*a1cb98faSBarry Smith + dm - The `DM` 18765f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h 18771555c271SMatthew G. Knepley 18781555c271SMatthew G. Knepley Output Parameter: 1879*a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the gradient 18801555c271SMatthew G. Knepley 18811555c271SMatthew G. Knepley Level: developer 18821555c271SMatthew G. Knepley 1883*a1cb98faSBarry Smith Note: 1884*a1cb98faSBarry Smith $\nabla u_h(v_i) = \sum_{T_i \in support(v_i)} |T_i| \nabla u_h(T_i) / \sum_{T_i \in support(v_i)} |T_i| $ where $ |T_i| $ is the cell volume 1885*a1cb98faSBarry Smith 1886*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 18871555c271SMatthew G. Knepley @*/ 1888d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC) 1889d71ae5a4SJacob Faibussowitsch { 1890db1066baSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 1891db1066baSMatthew G. Knepley PetscInt debug = mesh->printFEM; 18921555c271SMatthew G. Knepley DM dmC; 18931555c271SMatthew G. Knepley PetscQuadrature quad; 18941555c271SMatthew G. Knepley PetscScalar *interpolant, *gradsum; 18954bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 18964bee2e38SMatthew G. Knepley PetscReal *coords; 18971555c271SMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1898485ad865SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset; 18991555c271SMatthew G. Knepley 19001555c271SMatthew G. Knepley PetscFunctionBegin; 19019566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 19029566063dSJacob Faibussowitsch PetscCall(VecGetDM(locC, &dmC)); 19039566063dSJacob Faibussowitsch PetscCall(VecSet(locC, 0.0)); 19049566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 19059566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 19064bee2e38SMatthew G. Knepley fegeom.dimEmbed = coordDim; 19079566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 19085f80ce2aSJacob Faibussowitsch PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 19091555c271SMatthew G. Knepley for (field = 0; field < numFields; ++field) { 19101555c271SMatthew G. Knepley PetscObject obj; 19111555c271SMatthew G. Knepley PetscClassId id; 19121555c271SMatthew G. Knepley PetscInt Nc; 19131555c271SMatthew G. Knepley 19149566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 19159566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 19161555c271SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 19171555c271SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 19181555c271SMatthew G. Knepley 19199566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 19209566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 19211555c271SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 19221555c271SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 19231555c271SMatthew G. Knepley 19249566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 19259566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 192663a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 19271555c271SMatthew G. Knepley numComponents += Nc; 19281555c271SMatthew G. Knepley } 19299566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 193063a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 19319566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(coordDim * numComponents * 2, &gradsum, coordDim * numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 19329566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 19339566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 19341555c271SMatthew G. Knepley for (v = vStart; v < vEnd; ++v) { 19351555c271SMatthew G. Knepley PetscScalar volsum = 0.0; 19361555c271SMatthew G. Knepley PetscInt *star = NULL; 19371555c271SMatthew G. Knepley PetscInt starSize, st, d, fc; 19381555c271SMatthew G. Knepley 19399566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(gradsum, coordDim * numComponents)); 19409566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 19411555c271SMatthew G. Knepley for (st = 0; st < starSize * 2; st += 2) { 19421555c271SMatthew G. Knepley const PetscInt cell = star[st]; 19431555c271SMatthew G. Knepley PetscScalar *grad = &gradsum[coordDim * numComponents]; 19441555c271SMatthew G. Knepley PetscScalar *x = NULL; 19451555c271SMatthew G. Knepley PetscReal vol = 0.0; 19461555c271SMatthew G. Knepley 19471555c271SMatthew G. Knepley if ((cell < cStart) || (cell >= cEnd)) continue; 19489566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 19499566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 19501555c271SMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 19511555c271SMatthew G. Knepley PetscObject obj; 19521555c271SMatthew G. Knepley PetscClassId id; 19531555c271SMatthew G. Knepley PetscInt Nb, Nc, q, qc = 0; 19541555c271SMatthew G. Knepley 19559566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(grad, coordDim * numComponents)); 19569566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 19579566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 19589371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 19599371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 19609371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 19619371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 19629371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 19639371c9d4SSatish Balay Nb = 1; 19649371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 19651555c271SMatthew G. Knepley for (q = 0; q < Nq; ++q) { 19662a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 19672a4e142eSMatthew G. Knepley 19682a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 19692a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 19702a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 19712a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 197263a3b9bcSJacob Faibussowitsch PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", quadrature points %" PetscInt_FMT, (double)fegeom.detJ[q], cell, q); 19739566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolateGradient_Static((PetscFE)obj, 1, &x[fieldOffset], &qgeom, q, interpolant)); 197463a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 19751555c271SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 197653d2db2dSJoe Wallwork const PetscReal wt = quadWeights[q * qNc + qc]; 19771555c271SMatthew G. Knepley 19784bee2e38SMatthew G. Knepley for (d = 0; d < coordDim; ++d) grad[fc * coordDim + d] += interpolant[fc * dim + d] * wt * fegeom.detJ[q]; 19791555c271SMatthew G. Knepley } 19804bee2e38SMatthew G. Knepley vol += quadWeights[q * qNc] * fegeom.detJ[q]; 19811555c271SMatthew G. Knepley } 19821555c271SMatthew G. Knepley fieldOffset += Nb; 19831555c271SMatthew G. Knepley qc += Nc; 19841555c271SMatthew G. Knepley } 19859566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 1986f8527842SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 1987ad540459SPierre Jolivet for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] += grad[fc * coordDim + d]; 1988f8527842SMatthew G. Knepley } 1989f8527842SMatthew G. Knepley volsum += vol; 1990db1066baSMatthew G. Knepley if (debug) { 19919566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " gradient: [", v, cell)); 19921555c271SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 19931555c271SMatthew G. Knepley for (d = 0; d < coordDim; ++d) { 19949566063dSJacob Faibussowitsch if (fc || d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 19959566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc * coordDim + d]))); 19961555c271SMatthew G. Knepley } 19971555c271SMatthew G. Knepley } 19989566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 1999db1066baSMatthew G. Knepley } 20001555c271SMatthew G. Knepley } 20011555c271SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 20021555c271SMatthew G. Knepley for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] /= volsum; 20031555c271SMatthew G. Knepley } 20049566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 20059566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES)); 20061555c271SMatthew G. Knepley } 20079566063dSJacob Faibussowitsch PetscCall(PetscFree6(gradsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 20081555c271SMatthew G. Knepley PetscFunctionReturn(0); 20091555c271SMatthew G. Knepley } 20101555c271SMatthew G. Knepley 2011d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user) 2012d71ae5a4SJacob Faibussowitsch { 2013338f77d5SMatthew G. Knepley DM dmAux = NULL; 201461aaff12SToby Isaac PetscDS prob, probAux = NULL; 201573d901b8SMatthew G. Knepley PetscSection section, sectionAux; 2016338f77d5SMatthew G. Knepley Vec locX, locA; 2017c330f8ffSToby Isaac PetscInt dim, numCells = cEnd - cStart, c, f; 2018c330f8ffSToby Isaac PetscBool useFVM = PETSC_FALSE; 2019338f77d5SMatthew G. Knepley /* DS */ 2020338f77d5SMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x, numConstants; 2021338f77d5SMatthew G. Knepley PetscInt NfAux, totDimAux, *aOff; 2022338f77d5SMatthew G. Knepley PetscScalar *u, *a; 2023338f77d5SMatthew G. Knepley const PetscScalar *constants; 2024338f77d5SMatthew G. Knepley /* Geometry */ 2025c330f8ffSToby Isaac PetscFEGeom *cgeomFEM; 2026338f77d5SMatthew G. Knepley DM dmGrad; 2027c330f8ffSToby Isaac PetscQuadrature affineQuad = NULL; 2028338f77d5SMatthew G. Knepley Vec cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 2029b5a3613cSMatthew G. Knepley PetscFVCellGeom *cgeomFVM; 2030338f77d5SMatthew G. Knepley const PetscScalar *lgrad; 2031b7260050SToby Isaac PetscInt maxDegree; 2032c330f8ffSToby Isaac DMField coordField; 2033c330f8ffSToby Isaac IS cellIS; 203473d901b8SMatthew G. Knepley 203573d901b8SMatthew G. Knepley PetscFunctionBegin; 20369566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 20379566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 20389566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 20399566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 2040338f77d5SMatthew G. Knepley /* Determine which discretizations we have */ 2041b5a3613cSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2042b5a3613cSMatthew G. Knepley PetscObject obj; 2043b5a3613cSMatthew G. Knepley PetscClassId id; 2044b5a3613cSMatthew G. Knepley 20459566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 20469566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2047338f77d5SMatthew G. Knepley if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE; 2048338f77d5SMatthew G. Knepley } 2049338f77d5SMatthew G. Knepley /* Get local solution with boundary values */ 20509566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &locX)); 20519566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 20529566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 20539566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 2054338f77d5SMatthew G. Knepley /* Read DS information */ 20559566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 20569566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 20579566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 20589566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, numCells, cStart, 1, &cellIS)); 20599566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 2060338f77d5SMatthew G. Knepley /* Read Auxiliary DS information */ 20619566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 20629a2a23afSMatthew G. Knepley if (locA) { 20639566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 20649566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 20659566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 20669566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 20679566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 20689566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 2069338f77d5SMatthew G. Knepley } 2070338f77d5SMatthew G. Knepley /* Allocate data arrays */ 20719566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numCells * totDim, &u)); 20729566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 2073338f77d5SMatthew G. Knepley /* Read out geometry */ 20749566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 20759566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 2076b7260050SToby Isaac if (maxDegree <= 1) { 20779566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 207848a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &cgeomFEM)); 2079b5a3613cSMatthew G. Knepley } 2080b5a3613cSMatthew G. Knepley if (useFVM) { 2081338f77d5SMatthew G. Knepley PetscFV fv = NULL; 2082b5a3613cSMatthew G. Knepley Vec grad; 2083b5a3613cSMatthew G. Knepley PetscInt fStart, fEnd; 2084b5a3613cSMatthew G. Knepley PetscBool compGrad; 2085b5a3613cSMatthew G. Knepley 2086338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2087338f77d5SMatthew G. Knepley PetscObject obj; 2088338f77d5SMatthew G. Knepley PetscClassId id; 2089338f77d5SMatthew G. Knepley 20909566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 20919566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 20929371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 20939371c9d4SSatish Balay fv = (PetscFV)obj; 20949371c9d4SSatish Balay break; 20959371c9d4SSatish Balay } 2096338f77d5SMatthew G. Knepley } 20979566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &compGrad)); 20989566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, PETSC_TRUE)); 20999566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM)); 21009566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad)); 21019566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, compGrad)); 21029566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 2103b5a3613cSMatthew G. Knepley /* Reconstruct and limit cell gradients */ 21049566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 21059566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmGrad, &grad)); 21069566063dSJacob Faibussowitsch PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 2107b5a3613cSMatthew G. Knepley /* Communicate gradient values */ 21089566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 21099566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 21109566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 21119566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 2112b5a3613cSMatthew G. Knepley /* Handle non-essential (e.g. outflow) boundary values */ 21139566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad)); 21149566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 2115b5a3613cSMatthew G. Knepley } 2116338f77d5SMatthew G. Knepley /* Read out data from inputs */ 211773d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 211873d901b8SMatthew G. Knepley PetscScalar *x = NULL; 211973d901b8SMatthew G. Knepley PetscInt i; 212073d901b8SMatthew G. Knepley 21219566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, c, NULL, &x)); 21220f2d7e86SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 21239566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x)); 212473d901b8SMatthew G. Knepley if (dmAux) { 21259566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x)); 21260f2d7e86SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 21279566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x)); 212873d901b8SMatthew G. Knepley } 212973d901b8SMatthew G. Knepley } 2130338f77d5SMatthew G. Knepley /* Do integration for each field */ 213173d901b8SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2132c1f031eeSMatthew G. Knepley PetscObject obj; 2133c1f031eeSMatthew G. Knepley PetscClassId id; 2134c1f031eeSMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 213573d901b8SMatthew G. Knepley 21369566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 21379566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2138c1f031eeSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 2139c1f031eeSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2140c1f031eeSMatthew G. Knepley PetscQuadrature q; 2141c330f8ffSToby Isaac PetscFEGeom *chunkGeom = NULL; 2142c1f031eeSMatthew G. Knepley PetscInt Nq, Nb; 2143c1f031eeSMatthew G. Knepley 21449566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 21459566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 21469566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 21479566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 2148c1f031eeSMatthew G. Knepley blockSize = Nb * Nq; 214973d901b8SMatthew G. Knepley batchSize = numBlocks * blockSize; 21509566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 215173d901b8SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 215273d901b8SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 215373d901b8SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 215473d901b8SMatthew G. Knepley offset = numCells - Nr; 215548a46eb9SPierre Jolivet if (!affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, q, PETSC_FALSE, &cgeomFEM)); 21569566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 21579566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral)); 21589566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &chunkGeom)); 21599566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset * totDim], probAux, &a[offset * totDimAux], &cintegral[offset * Nf])); 21609566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &chunkGeom)); 216148a46eb9SPierre Jolivet if (!affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 2162c1f031eeSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 2163c1f031eeSMatthew G. Knepley PetscInt foff; 2164420e96edSMatthew G. Knepley PetscPointFunc obj_func; 2165b69edc29SMatthew G. Knepley PetscScalar lint; 2166c1f031eeSMatthew G. Knepley 21679566063dSJacob Faibussowitsch PetscCall(PetscDSGetObjective(prob, f, &obj_func)); 21689566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, f, &foff)); 2169c1f031eeSMatthew G. Knepley if (obj_func) { 2170c1f031eeSMatthew G. Knepley for (c = 0; c < numCells; ++c) { 2171b5a3613cSMatthew G. Knepley PetscScalar *u_x; 2172b5a3613cSMatthew G. Knepley 21739566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x)); 2174338f77d5SMatthew G. Knepley obj_func(dim, Nf, NfAux, uOff, uOff_x, &u[totDim * c + foff], NULL, u_x, aOff, NULL, &a[totDimAux * c], NULL, NULL, 0.0, cgeomFVM[c].centroid, numConstants, constants, &lint); 2175338f77d5SMatthew G. Knepley cintegral[c * Nf + f] += PetscRealPart(lint) * cgeomFVM[c].volume; 217673d901b8SMatthew G. Knepley } 2177c1f031eeSMatthew G. Knepley } 217863a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 2179c1f031eeSMatthew G. Knepley } 2180338f77d5SMatthew G. Knepley /* Cleanup data arrays */ 2181b5a3613cSMatthew G. Knepley if (useFVM) { 21829566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 21839566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 21849566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 21859566063dSJacob Faibussowitsch PetscCall(VecDestroy(&faceGeometryFVM)); 21869566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cellGeometryFVM)); 21879566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dmGrad)); 2188b5a3613cSMatthew G. Knepley } 21899566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscFree(a)); 21909566063dSJacob Faibussowitsch PetscCall(PetscFree(u)); 2191338f77d5SMatthew G. Knepley /* Cleanup */ 219248a46eb9SPierre Jolivet if (affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 21939566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 21949566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 21959566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &locX)); 2196338f77d5SMatthew G. Knepley PetscFunctionReturn(0); 2197338f77d5SMatthew G. Knepley } 2198338f77d5SMatthew G. Knepley 2199338f77d5SMatthew G. Knepley /*@ 2200338f77d5SMatthew G. Knepley DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user 2201338f77d5SMatthew G. Knepley 2202338f77d5SMatthew G. Knepley Input Parameters: 2203338f77d5SMatthew G. Knepley + dm - The mesh 2204338f77d5SMatthew G. Knepley . X - Global input vector 2205338f77d5SMatthew G. Knepley - user - The user context 2206338f77d5SMatthew G. Knepley 2207338f77d5SMatthew G. Knepley Output Parameter: 2208338f77d5SMatthew G. Knepley . integral - Integral for each field 2209338f77d5SMatthew G. Knepley 2210338f77d5SMatthew G. Knepley Level: developer 2211338f77d5SMatthew G. Knepley 2212*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2213338f77d5SMatthew G. Knepley @*/ 2214d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user) 2215d71ae5a4SJacob Faibussowitsch { 2216338f77d5SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2217b8feb594SMatthew G. Knepley PetscScalar *cintegral, *lintegral; 2218412e9a14SMatthew G. Knepley PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 2219338f77d5SMatthew G. Knepley 2220338f77d5SMatthew G. Knepley PetscFunctionBegin; 2221338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2222338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2223dadcf809SJacob Faibussowitsch PetscValidScalarPointer(integral, 3); 22249566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 22259566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 22269566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 22279566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2228338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 22299566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &lintegral, (cEnd - cStart) * Nf, &cintegral)); 22309566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user)); 2231338f77d5SMatthew G. Knepley /* Sum up values */ 2232338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2233338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 2234338f77d5SMatthew G. Knepley 22359566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 2236b8feb594SMatthew G. Knepley for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c * Nf + f]; 2237338f77d5SMatthew G. Knepley } 22381c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 223973d901b8SMatthew G. Knepley if (mesh->printFEM) { 22409566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Integral:")); 22419566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), " %g", (double)PetscRealPart(integral[f]))); 22429566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "\n")); 224373d901b8SMatthew G. Knepley } 22449566063dSJacob Faibussowitsch PetscCall(PetscFree2(lintegral, cintegral)); 22459566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2246338f77d5SMatthew G. Knepley PetscFunctionReturn(0); 2247338f77d5SMatthew G. Knepley } 2248338f77d5SMatthew G. Knepley 2249338f77d5SMatthew G. Knepley /*@ 2250338f77d5SMatthew G. Knepley DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user 2251338f77d5SMatthew G. Knepley 2252338f77d5SMatthew G. Knepley Input Parameters: 2253338f77d5SMatthew G. Knepley + dm - The mesh 2254338f77d5SMatthew G. Knepley . X - Global input vector 2255338f77d5SMatthew G. Knepley - user - The user context 2256338f77d5SMatthew G. Knepley 2257338f77d5SMatthew G. Knepley Output Parameter: 2258338f77d5SMatthew G. Knepley . integral - Cellwise integrals for each field 2259338f77d5SMatthew G. Knepley 2260338f77d5SMatthew G. Knepley Level: developer 2261338f77d5SMatthew G. Knepley 2262*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2263338f77d5SMatthew G. Knepley @*/ 2264d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user) 2265d71ae5a4SJacob Faibussowitsch { 2266338f77d5SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2267338f77d5SMatthew G. Knepley DM dmF; 2268338f77d5SMatthew G. Knepley PetscSection sectionF; 2269338f77d5SMatthew G. Knepley PetscScalar *cintegral, *af; 2270412e9a14SMatthew G. Knepley PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 2271338f77d5SMatthew G. Knepley 2272338f77d5SMatthew G. Knepley PetscFunctionBegin; 2273338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2274338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2275338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(F, VEC_CLASSID, 3); 22769566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 22779566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 22789566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 22799566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2280338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 22819566063dSJacob Faibussowitsch PetscCall(PetscCalloc1((cEnd - cStart) * Nf, &cintegral)); 22829566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user)); 2283338f77d5SMatthew G. Knepley /* Put values in F*/ 22849566063dSJacob Faibussowitsch PetscCall(VecGetDM(F, &dmF)); 22859566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmF, §ionF)); 22869566063dSJacob Faibussowitsch PetscCall(VecGetArray(F, &af)); 2287338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2288338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 2289338f77d5SMatthew G. Knepley PetscInt dof, off; 2290338f77d5SMatthew G. Knepley 22919566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 22929566063dSJacob Faibussowitsch PetscCall(PetscSectionGetDof(sectionF, cell, &dof)); 22939566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(sectionF, cell, &off)); 229463a3b9bcSJacob Faibussowitsch PetscCheck(dof == Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %" PetscInt_FMT " != %" PetscInt_FMT, dof, Nf); 2295338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) af[off + f] = cintegral[c * Nf + f]; 2296338f77d5SMatthew G. Knepley } 22979566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(F, &af)); 22989566063dSJacob Faibussowitsch PetscCall(PetscFree(cintegral)); 22999566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 230073d901b8SMatthew G. Knepley PetscFunctionReturn(0); 230173d901b8SMatthew G. Knepley } 230273d901b8SMatthew G. Knepley 2303d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS, void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), PetscScalar *fintegral, void *user) 2304d71ae5a4SJacob Faibussowitsch { 23059b6f715bSMatthew G. Knepley DM plex = NULL, plexA = NULL; 2306a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 23079b6f715bSMatthew G. Knepley PetscDS prob, probAux = NULL; 23089b6f715bSMatthew G. Knepley PetscSection section, sectionAux = NULL; 23099b6f715bSMatthew G. Knepley Vec locA = NULL; 23109b6f715bSMatthew G. Knepley DMField coordField; 23119b6f715bSMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x; 23129b6f715bSMatthew G. Knepley PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL; 23139b6f715bSMatthew G. Knepley PetscScalar *u, *a = NULL; 231464c72086SMatthew G. Knepley const PetscScalar *constants; 23159b6f715bSMatthew G. Knepley PetscInt numConstants, f; 231664c72086SMatthew G. Knepley 231764c72086SMatthew G. Knepley PetscFunctionBegin; 23189566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 23199566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 23209566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 23219566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 23229566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 232364c72086SMatthew G. Knepley /* Determine which discretizations we have */ 23249b6f715bSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 232564c72086SMatthew G. Knepley PetscObject obj; 232664c72086SMatthew G. Knepley PetscClassId id; 232764c72086SMatthew G. Knepley 23289566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 23299566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 233063a3b9bcSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not supported for FVM (field %" PetscInt_FMT ")", f); 233164c72086SMatthew G. Knepley } 233264c72086SMatthew G. Knepley /* Read DS information */ 23339566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 23349566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 23359566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 23369566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 233764c72086SMatthew G. Knepley /* Read Auxiliary DS information */ 23389566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 23399b6f715bSMatthew G. Knepley if (locA) { 23409b6f715bSMatthew G. Knepley DM dmAux; 23419b6f715bSMatthew G. Knepley 23429566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 23439566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 23449566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 23459566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 23469566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 23479566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 23489566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 23499566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 235064c72086SMatthew G. Knepley } 23519b6f715bSMatthew G. Knepley /* Integrate over points */ 23529b6f715bSMatthew G. Knepley { 23539b6f715bSMatthew G. Knepley PetscFEGeom *fgeom, *chunkGeom = NULL; 2354b7260050SToby Isaac PetscInt maxDegree; 23559b6f715bSMatthew G. Knepley PetscQuadrature qGeom = NULL; 23569b6f715bSMatthew G. Knepley const PetscInt *points; 23579b6f715bSMatthew G. Knepley PetscInt numFaces, face, Nq, field; 23589b6f715bSMatthew G. Knepley PetscInt numChunks, chunkSize, chunk, Nr, offset; 235964c72086SMatthew G. Knepley 23609566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 23619566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 23629566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFaces * totDim, &u, locA ? numFaces * totDimAux : 0, &a)); 23639566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 236464c72086SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 236564c72086SMatthew G. Knepley PetscFE fe; 236664c72086SMatthew G. Knepley 23679566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe)); 23689566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 23699b6f715bSMatthew G. Knepley if (!qGeom) { 23709566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 23719566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 23729b6f715bSMatthew G. Knepley } 23739566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 23749566063dSJacob Faibussowitsch PetscCall(DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 23759b6f715bSMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 2376f15274beSMatthew Knepley const PetscInt point = points[face], *support; 23779b6f715bSMatthew G. Knepley PetscScalar *x = NULL; 2378f15274beSMatthew Knepley PetscInt i; 23799b6f715bSMatthew G. Knepley 23809566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 23819566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 23829b6f715bSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 23839566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 23849b6f715bSMatthew G. Knepley if (locA) { 23859b6f715bSMatthew G. Knepley PetscInt subp; 23869566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 23879566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 23889b6f715bSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[f * totDimAux + i] = x[i]; 23899566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 23909b6f715bSMatthew G. Knepley } 23919b6f715bSMatthew G. Knepley } 23929b6f715bSMatthew G. Knepley /* Get blocking */ 23939b6f715bSMatthew G. Knepley { 23949b6f715bSMatthew G. Knepley PetscQuadrature q; 23959b6f715bSMatthew G. Knepley PetscInt numBatches, batchSize, numBlocks, blockSize; 23969b6f715bSMatthew G. Knepley PetscInt Nq, Nb; 23979b6f715bSMatthew G. Knepley 23989566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 23999566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 24009566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 24019566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 240264c72086SMatthew G. Knepley blockSize = Nb * Nq; 240364c72086SMatthew G. Knepley batchSize = numBlocks * blockSize; 24049b6f715bSMatthew G. Knepley chunkSize = numBatches * batchSize; 24059566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 24069b6f715bSMatthew G. Knepley numChunks = numFaces / chunkSize; 24079b6f715bSMatthew G. Knepley Nr = numFaces % chunkSize; 240864c72086SMatthew G. Knepley offset = numFaces - Nr; 240964c72086SMatthew G. Knepley } 24109b6f715bSMatthew G. Knepley /* Do integration for each field */ 24119b6f715bSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 24129566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, chunk * chunkSize, (chunk + 1) * chunkSize, &chunkGeom)); 24139566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral)); 24149566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 241564c72086SMatthew G. Knepley } 24169566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 24179566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset * totDim], probAux, a ? &a[offset * totDimAux] : NULL, &fintegral[offset * Nf])); 24189566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 241964c72086SMatthew G. Knepley /* Cleanup data arrays */ 24209566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 24219566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 24229566063dSJacob Faibussowitsch PetscCall(PetscFree2(u, a)); 24239566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 242464c72086SMatthew G. Knepley } 242564c72086SMatthew G. Knepley } 24269566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 24279566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 24289b6f715bSMatthew G. Knepley PetscFunctionReturn(0); 24299b6f715bSMatthew G. Knepley } 24309b6f715bSMatthew G. Knepley 24319b6f715bSMatthew G. Knepley /*@ 24329b6f715bSMatthew G. Knepley DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user 24339b6f715bSMatthew G. Knepley 24349b6f715bSMatthew G. Knepley Input Parameters: 24359b6f715bSMatthew G. Knepley + dm - The mesh 24369b6f715bSMatthew G. Knepley . X - Global input vector 2437*a1cb98faSBarry Smith . label - The boundary `DMLabel` 2438*a1cb98faSBarry Smith . numVals - The number of label values to use, or `PETSC_DETERMINE` for all values 2439*a1cb98faSBarry Smith . vals - The label values to use, or NULL for all values 244067b8a455SSatish Balay . func - The function to integrate along the boundary 24419b6f715bSMatthew G. Knepley - user - The user context 24429b6f715bSMatthew G. Knepley 24439b6f715bSMatthew G. Knepley Output Parameter: 24449b6f715bSMatthew G. Knepley . integral - Integral for each field 24459b6f715bSMatthew G. Knepley 24469b6f715bSMatthew G. Knepley Level: developer 24479b6f715bSMatthew G. Knepley 2448*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeIntegralFEM()`, `DMPlexComputeBdResidualFEM()` 24499b6f715bSMatthew G. Knepley @*/ 2450d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), PetscScalar *integral, void *user) 2451d71ae5a4SJacob Faibussowitsch { 24529b6f715bSMatthew G. Knepley Vec locX; 24539b6f715bSMatthew G. Knepley PetscSection section; 24549b6f715bSMatthew G. Knepley DMLabel depthLabel; 24559b6f715bSMatthew G. Knepley IS facetIS; 24569b6f715bSMatthew G. Knepley PetscInt dim, Nf, f, v; 24579b6f715bSMatthew G. Knepley 24589b6f715bSMatthew G. Knepley PetscFunctionBegin; 24599b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 24609b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 24619b6f715bSMatthew G. Knepley PetscValidPointer(label, 3); 2462dadcf809SJacob Faibussowitsch if (vals) PetscValidIntPointer(vals, 5); 2463dadcf809SJacob Faibussowitsch PetscValidScalarPointer(integral, 7); 24649566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 24659566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 24669566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 24679566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 24689566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 24699566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 24709b6f715bSMatthew G. Knepley /* Get local solution with boundary values */ 24719566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &locX)); 24729566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 24739566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 24749566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 24759b6f715bSMatthew G. Knepley /* Loop over label values */ 24769566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(integral, Nf)); 24779b6f715bSMatthew G. Knepley for (v = 0; v < numVals; ++v) { 24789b6f715bSMatthew G. Knepley IS pointIS; 24799b6f715bSMatthew G. Knepley PetscInt numFaces, face; 24809b6f715bSMatthew G. Knepley PetscScalar *fintegral; 24819b6f715bSMatthew G. Knepley 24829566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, vals[v], &pointIS)); 24839b6f715bSMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 24849b6f715bSMatthew G. Knepley { 24859b6f715bSMatthew G. Knepley IS isectIS; 24869b6f715bSMatthew G. Knepley 24879b6f715bSMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 24889566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 24899566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 24909b6f715bSMatthew G. Knepley pointIS = isectIS; 24919b6f715bSMatthew G. Knepley } 24929566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 24939566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numFaces * Nf, &fintegral)); 24949566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user)); 24959b6f715bSMatthew G. Knepley /* Sum point contributions into integral */ 24969371c9d4SSatish Balay for (f = 0; f < Nf; ++f) 24979371c9d4SSatish Balay for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face * Nf + f]; 24989566063dSJacob Faibussowitsch PetscCall(PetscFree(fintegral)); 24999566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 25009b6f715bSMatthew G. Knepley } 25019566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &locX)); 25029566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 25039566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 250464c72086SMatthew G. Knepley PetscFunctionReturn(0); 250564c72086SMatthew G. Knepley } 250664c72086SMatthew G. Knepley 2507d69c5d34SMatthew G. Knepley /*@ 2508*a1cb98faSBarry Smith DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse `DM` to a uniformly refined `DM`. 2509d69c5d34SMatthew G. Knepley 2510d69c5d34SMatthew G. Knepley Input Parameters: 2511cf51de39SMatthew G. Knepley + dmc - The coarse mesh 2512cf51de39SMatthew G. Knepley . dmf - The fine mesh 2513cf51de39SMatthew G. Knepley . isRefined - Flag indicating regular refinement, rather than the same topology 2514d69c5d34SMatthew G. Knepley - user - The user context 2515d69c5d34SMatthew G. Knepley 2516d69c5d34SMatthew G. Knepley Output Parameter: 2517934789fcSMatthew G. Knepley . In - The interpolation matrix 2518d69c5d34SMatthew G. Knepley 2519d69c5d34SMatthew G. Knepley Level: developer 2520d69c5d34SMatthew G. Knepley 2521*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()` 2522d69c5d34SMatthew G. Knepley @*/ 2523d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user) 2524d71ae5a4SJacob Faibussowitsch { 2525d69c5d34SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmc->data; 2526d69c5d34SMatthew G. Knepley const char *name = "Interpolator"; 2527d69c5d34SMatthew G. Knepley PetscFE *feRef; 252897c42addSMatthew G. Knepley PetscFV *fvRef; 2529d69c5d34SMatthew G. Knepley PetscSection fsection, fglobalSection; 2530d69c5d34SMatthew G. Knepley PetscSection csection, cglobalSection; 2531d69c5d34SMatthew G. Knepley PetscScalar *elemMat; 2532485ad865SMatthew G. Knepley PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c; 25332ea9c922SToby Isaac PetscInt cTotDim = 0, rTotDim = 0; 2534d69c5d34SMatthew G. Knepley 2535d69c5d34SMatthew G. Knepley PetscFunctionBegin; 25369566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 25379566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 25389566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 25399566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 25409566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 25419566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 25429566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 25439566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 25449566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &feRef, Nf, &fvRef)); 2545d69c5d34SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 25462ea9c922SToby Isaac PetscObject obj, objc; 25472ea9c922SToby Isaac PetscClassId id, idc; 25482ea9c922SToby Isaac PetscInt rNb = 0, Nc = 0, cNb = 0; 2549d69c5d34SMatthew G. Knepley 25509566063dSJacob Faibussowitsch PetscCall(DMGetField(dmf, f, NULL, &obj)); 25519566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 255297c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 255397c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 255497c42addSMatthew G. Knepley 2555cf51de39SMatthew G. Knepley if (isRefined) { 25569566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 2557cf51de39SMatthew G. Knepley } else { 25589566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fe)); 2559cf51de39SMatthew G. Knepley feRef[f] = fe; 2560cf51de39SMatthew G. Knepley } 25619566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &rNb)); 25629566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 256397c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 256497c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 256597c42addSMatthew G. Knepley PetscDualSpace Q; 256697c42addSMatthew G. Knepley 2567cf51de39SMatthew G. Knepley if (isRefined) { 25689566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 2569cf51de39SMatthew G. Knepley } else { 25709566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fv)); 2571cf51de39SMatthew G. Knepley fvRef[f] = fv; 2572cf51de39SMatthew G. Knepley } 25739566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 25749566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &rNb)); 25759566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 25769566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 257797c42addSMatthew G. Knepley } 25789566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, f, NULL, &objc)); 25799566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(objc, &idc)); 25802ea9c922SToby Isaac if (idc == PETSCFE_CLASSID) { 25812ea9c922SToby Isaac PetscFE fe = (PetscFE)objc; 25822ea9c922SToby Isaac 25839566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cNb)); 25842ea9c922SToby Isaac } else if (id == PETSCFV_CLASSID) { 25852ea9c922SToby Isaac PetscFV fv = (PetscFV)obj; 25862ea9c922SToby Isaac PetscDualSpace Q; 25872ea9c922SToby Isaac 25889566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 25899566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &cNb)); 2590d69c5d34SMatthew G. Knepley } 25912ea9c922SToby Isaac rTotDim += rNb; 25922ea9c922SToby Isaac cTotDim += cNb; 25932ea9c922SToby Isaac } 25949566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(rTotDim * cTotDim, &elemMat)); 25959566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, rTotDim * cTotDim)); 2596d69c5d34SMatthew G. Knepley for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 2597d69c5d34SMatthew G. Knepley PetscDualSpace Qref; 2598d69c5d34SMatthew G. Knepley PetscQuadrature f; 2599d69c5d34SMatthew G. Knepley const PetscReal *qpoints, *qweights; 2600d69c5d34SMatthew G. Knepley PetscReal *points; 2601d69c5d34SMatthew G. Knepley PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 2602d69c5d34SMatthew G. Knepley 2603d69c5d34SMatthew G. Knepley /* Compose points from all dual basis functionals */ 260497c42addSMatthew G. Knepley if (feRef[fieldI]) { 26059566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[fieldI], &Qref)); 26069566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[fieldI], &Nc)); 260797c42addSMatthew G. Knepley } else { 26089566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[fieldI], &Qref)); 26099566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[fieldI], &Nc)); 261097c42addSMatthew G. Knepley } 26119566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Qref, &fpdim)); 2612d69c5d34SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 26139566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 26149566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL)); 2615d69c5d34SMatthew G. Knepley npoints += Np; 2616d69c5d34SMatthew G. Knepley } 26179566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints * dim, &points)); 2618d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 26199566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 26209566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL)); 26219371c9d4SSatish Balay for (p = 0; p < Np; ++p, ++k) 26229371c9d4SSatish Balay for (d = 0; d < dim; ++d) points[k * dim + d] = qpoints[p * dim + d]; 2623d69c5d34SMatthew G. Knepley } 2624d69c5d34SMatthew G. Knepley 2625d69c5d34SMatthew G. Knepley for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 262697c42addSMatthew G. Knepley PetscObject obj; 262797c42addSMatthew G. Knepley PetscClassId id; 26289c3cf19fSMatthew G. Knepley PetscInt NcJ = 0, cpdim = 0, j, qNc; 2629d69c5d34SMatthew G. Knepley 26309566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, fieldJ, NULL, &obj)); 26319566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 263297c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 263397c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2634ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 2635d69c5d34SMatthew G. Knepley 2636d69c5d34SMatthew G. Knepley /* Evaluate basis at points */ 26379566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &NcJ)); 26389566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 2639ffe73a53SMatthew G. Knepley /* For now, fields only interpolate themselves */ 2640ffe73a53SMatthew G. Knepley if (fieldI == fieldJ) { 264163a3b9bcSJacob Faibussowitsch PetscCheck(Nc == NcJ, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, Nc, NcJ); 26429566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation(fe, 1, npoints, points, 0, &T)); 2643d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 26449566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 26459566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 264663a3b9bcSJacob Faibussowitsch PetscCheck(qNc == NcJ, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, qNc, NcJ); 2647d69c5d34SMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 264836a6d9c0SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2649d172c84bSMatthew G. Knepley /* 2650d172c84bSMatthew G. Knepley cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field 2651d172c84bSMatthew G. Knepley offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields 2652d172c84bSMatthew G. Knepley fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals 2653d172c84bSMatthew G. Knepley qNC, Nc, Ncj, c: Number of components in this field 2654d172c84bSMatthew G. Knepley Np, p: Number of quad points in the fine grid functional i 2655d172c84bSMatthew G. Knepley k: i*Np + p, overall point number for the interpolation 2656d172c84bSMatthew G. Knepley */ 2657ef0bb6c7SMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += T->T[0][k * cpdim * NcJ + j * Nc + c] * qweights[p * qNc + c]; 265836a6d9c0SMatthew G. Knepley } 2659d69c5d34SMatthew G. Knepley } 2660d69c5d34SMatthew G. Knepley } 26619566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 2662ffe73a53SMatthew G. Knepley } 266397c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 266497c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 266597c42addSMatthew G. Knepley 266697c42addSMatthew G. Knepley /* Evaluate constant function at points */ 26679566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcJ)); 266897c42addSMatthew G. Knepley cpdim = 1; 266997c42addSMatthew G. Knepley /* For now, fields only interpolate themselves */ 267097c42addSMatthew G. Knepley if (fieldI == fieldJ) { 267163a3b9bcSJacob Faibussowitsch PetscCheck(Nc == NcJ, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, Nc, NcJ); 267297c42addSMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 26739566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 26749566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 267563a3b9bcSJacob Faibussowitsch PetscCheck(qNc == NcJ, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, qNc, NcJ); 267697c42addSMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 267797c42addSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2678458eb97cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += 1.0 * qweights[p * qNc + c]; 267997c42addSMatthew G. Knepley } 268097c42addSMatthew G. Knepley } 268197c42addSMatthew G. Knepley } 268297c42addSMatthew G. Knepley } 268397c42addSMatthew G. Knepley } 2684d172c84bSMatthew G. Knepley offsetJ += cpdim; 2685d69c5d34SMatthew G. Knepley } 2686d172c84bSMatthew G. Knepley offsetI += fpdim; 26879566063dSJacob Faibussowitsch PetscCall(PetscFree(points)); 2688d69c5d34SMatthew G. Knepley } 26899566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat)); 26907f5b169aSMatthew G. Knepley /* Preallocate matrix */ 26917f5b169aSMatthew G. Knepley { 2692c094ef40SMatthew G. Knepley Mat preallocator; 2693c094ef40SMatthew G. Knepley PetscScalar *vals; 2694c094ef40SMatthew G. Knepley PetscInt *cellCIndices, *cellFIndices; 2695c094ef40SMatthew G. Knepley PetscInt locRows, locCols, cell; 26967f5b169aSMatthew G. Knepley 26979566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 26989566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &preallocator)); 26999566063dSJacob Faibussowitsch PetscCall(MatSetType(preallocator, MATPREALLOCATOR)); 27009566063dSJacob Faibussowitsch PetscCall(MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 27019566063dSJacob Faibussowitsch PetscCall(MatSetUp(preallocator)); 27029566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(rTotDim * cTotDim, &vals, cTotDim, &cellCIndices, rTotDim, &cellFIndices)); 27037f5b169aSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2704cf51de39SMatthew G. Knepley if (isRefined) { 27059566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices)); 27069566063dSJacob Faibussowitsch PetscCall(MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES)); 2707cf51de39SMatthew G. Knepley } else { 27089566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, preallocator, cell, vals, INSERT_VALUES)); 2709cf51de39SMatthew G. Knepley } 27107f5b169aSMatthew G. Knepley } 27119566063dSJacob Faibussowitsch PetscCall(PetscFree3(vals, cellCIndices, cellFIndices)); 27129566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY)); 27139566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY)); 27149566063dSJacob Faibussowitsch PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In)); 27159566063dSJacob Faibussowitsch PetscCall(MatDestroy(&preallocator)); 27167f5b169aSMatthew G. Knepley } 27177f5b169aSMatthew G. Knepley /* Fill matrix */ 27189566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(In)); 2719d69c5d34SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 2720cf51de39SMatthew G. Knepley if (isRefined) { 27219566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES)); 2722cf51de39SMatthew G. Knepley } else { 27239566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES)); 2724cf51de39SMatthew G. Knepley } 2725d69c5d34SMatthew G. Knepley } 27269566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&feRef[f])); 27279566063dSJacob Faibussowitsch PetscCall(PetscFree2(feRef, fvRef)); 27289566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 27299566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 27309566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 27319318fe57SMatthew G. Knepley if (mesh->printFEM > 1) { 27329566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name)); 27339566063dSJacob Faibussowitsch PetscCall(MatChop(In, 1.0e-10)); 27349566063dSJacob Faibussowitsch PetscCall(MatView(In, NULL)); 2735d69c5d34SMatthew G. Knepley } 27369566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 2737d69c5d34SMatthew G. Knepley PetscFunctionReturn(0); 2738d69c5d34SMatthew G. Knepley } 27396c73c22cSMatthew G. Knepley 2740d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user) 2741d71ae5a4SJacob Faibussowitsch { 2742bd041c0cSMatthew G. Knepley SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "Laziness"); 2743bd041c0cSMatthew G. Knepley } 2744bd041c0cSMatthew G. Knepley 274568132eb9SMatthew G. Knepley /*@ 2746*a1cb98faSBarry Smith DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse `DM` to a non-nested fine `DM`. 274768132eb9SMatthew G. Knepley 274868132eb9SMatthew G. Knepley Input Parameters: 274968132eb9SMatthew G. Knepley + dmf - The fine mesh 275068132eb9SMatthew G. Knepley . dmc - The coarse mesh 275168132eb9SMatthew G. Knepley - user - The user context 275268132eb9SMatthew G. Knepley 275368132eb9SMatthew G. Knepley Output Parameter: 275468132eb9SMatthew G. Knepley . In - The interpolation matrix 275568132eb9SMatthew G. Knepley 275668132eb9SMatthew G. Knepley Level: developer 275768132eb9SMatthew G. Knepley 2758*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()` 275968132eb9SMatthew G. Knepley @*/ 2760d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user) 2761d71ae5a4SJacob Faibussowitsch { 276264e98e1dSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 276364e98e1dSMatthew G. Knepley const char *name = "Interpolator"; 27644ef9d792SMatthew G. Knepley PetscDS prob; 2765a0806964SMatthew G. Knepley Mat interp; 2766a0806964SMatthew G. Knepley PetscSection fsection, globalFSection; 2767a0806964SMatthew G. Knepley PetscSection csection, globalCSection; 2768a0806964SMatthew G. Knepley PetscInt locRows, locCols; 27694ef9d792SMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 27704ef9d792SMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 27714ef9d792SMatthew G. Knepley PetscScalar *elemMat; 2772a0806964SMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell, s; 27734ef9d792SMatthew G. Knepley 27744ef9d792SMatthew G. Knepley PetscFunctionBegin; 27759566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 27769566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 27779566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 27789566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 27799566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 27809566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 27819566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 27829566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 27839566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 27849566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 27859566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 2786a0806964SMatthew G. Knepley PetscCall(DMPlexGetSimplexOrBoxCells(dmf, 0, &cStart, &cEnd)); 27879566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 27889566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 27894ef9d792SMatthew G. Knepley 2790a0806964SMatthew G. Knepley PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 2791a0806964SMatthew G. Knepley PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &interp)); 2792a0806964SMatthew G. Knepley PetscCall(MatSetType(interp, MATPREALLOCATOR)); 2793a0806964SMatthew G. Knepley PetscCall(MatSetSizes(interp, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 2794a0806964SMatthew G. Knepley PetscCall(MatSetUp(interp)); 2795a0806964SMatthew G. Knepley for (s = 0; s < 2; ++s) { 27964ef9d792SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 27974ef9d792SMatthew G. Knepley PetscObject obj; 27984ef9d792SMatthew G. Knepley PetscClassId id; 2799c0d7054bSMatthew G. Knepley PetscDualSpace Q = NULL; 2800ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 28014ef9d792SMatthew G. Knepley PetscQuadrature f; 28024ef9d792SMatthew G. Knepley const PetscReal *qpoints, *qweights; 2803d0f6233fSMatthew G. Knepley PetscInt Nc, qNc, Np, fpdim, off, i, d; 28044ef9d792SMatthew G. Knepley 2805d0f6233fSMatthew G. Knepley PetscCall(PetscDSGetFieldOffset(prob, field, &off)); 28069566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 28079566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 28084ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 28094ef9d792SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 28104ef9d792SMatthew G. Knepley 28119566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(fe, &Q)); 28129566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 2813a0806964SMatthew G. Knepley if (s) PetscCall(PetscFECreateTabulation(fe, 1, 1, x, 0, &T)); 28144ef9d792SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 28154ef9d792SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 28164ef9d792SMatthew G. Knepley 28179566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 28184ef9d792SMatthew G. Knepley Nc = 1; 281963a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 28209566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fpdim)); 28214ef9d792SMatthew G. Knepley /* For each fine grid cell */ 28224ef9d792SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 28234ef9d792SMatthew G. Knepley PetscInt *findices, *cindices; 28244ef9d792SMatthew G. Knepley PetscInt numFIndices, numCIndices; 28254ef9d792SMatthew G. Knepley 28269566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 28279566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 2828d0f6233fSMatthew G. Knepley PetscCheck(numFIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %" PetscInt_FMT " != %" PetscInt_FMT " dual basis vecs", numFIndices, totDim); 28294ef9d792SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 28304ef9d792SMatthew G. Knepley Vec pointVec; 28314ef9d792SMatthew G. Knepley PetscScalar *pV; 283212111d7cSToby Isaac PetscSF coarseCellSF = NULL; 28333a93e3b7SToby Isaac const PetscSFNode *coarseCells; 2834d0f6233fSMatthew G. Knepley PetscInt numCoarseCells, cpdim, row = findices[i + off], q, c, j; 28354ef9d792SMatthew G. Knepley 28364ef9d792SMatthew G. Knepley /* Get points from the dual basis functional quadrature */ 28379566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Q, i, &f)); 28389566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights)); 283963a3b9bcSJacob Faibussowitsch PetscCheck(qNc == Nc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, qNc, Nc); 28409566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np * dim, &pointVec)); 28419566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 28429566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 28434ef9d792SMatthew G. Knepley for (q = 0; q < Np; ++q) { 2844c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 2845c330f8ffSToby Isaac 28464ef9d792SMatthew G. Knepley /* Transform point to real space */ 2847c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 28484ef9d792SMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 28494ef9d792SMatthew G. Knepley } 28509566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 28514ef9d792SMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 28521555c271SMatthew G. Knepley /* OPT: Read this out from preallocation information */ 28539566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 28544ef9d792SMatthew G. Knepley /* Update preallocation info */ 28559566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 28565f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Np, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 28579566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 28584ef9d792SMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2859826eb36dSMatthew G. Knepley PetscReal pVReal[3]; 2860c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 2861826eb36dSMatthew G. Knepley 28629566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 2863a0806964SMatthew G. Knepley if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetDimension((PetscFE)obj, &cpdim)); 2864a0806964SMatthew G. Knepley else cpdim = 1; 2865a0806964SMatthew G. Knepley 2866a0806964SMatthew G. Knepley if (s) { 28674ef9d792SMatthew G. Knepley /* Transform points from real space to coarse reference space */ 28689566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 2869e2d86523SMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 2870c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 28714ef9d792SMatthew G. Knepley 28724ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 28734ef9d792SMatthew G. Knepley /* Evaluate coarse basis on contained point */ 2874a0806964SMatthew G. Knepley PetscCall(PetscFEComputeTabulation((PetscFE)obj, 1, x, 0, T)); 28759566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 28764ef9d792SMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 28774ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2878ef0bb6c7SMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * qweights[ccell * qNc + c]; 28794ef9d792SMatthew G. Knepley } 28804ef9d792SMatthew G. Knepley } else { 28814ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 28829c3cf19fSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * qweights[ccell * qNc + c]; 28834ef9d792SMatthew G. Knepley } 28844ef9d792SMatthew G. Knepley } 28859566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 2886a0806964SMatthew G. Knepley } 2887a0806964SMatthew G. Knepley /* Update interpolator */ 2888d0f6233fSMatthew G. Knepley PetscCheck(numCIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, totDim); 2889a0806964SMatthew G. Knepley PetscCall(MatSetValues(interp, 1, &row, cpdim, &cindices[off], elemMat, INSERT_VALUES)); 28909566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 28914ef9d792SMatthew G. Knepley } 28929566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 28939566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 28949566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 28954ef9d792SMatthew G. Knepley } 28969566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 28974ef9d792SMatthew G. Knepley } 2898a0806964SMatthew G. Knepley if (s && id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 2899a0806964SMatthew G. Knepley } 2900a0806964SMatthew G. Knepley if (!s) { 2901a0806964SMatthew G. Knepley PetscCall(MatAssemblyBegin(interp, MAT_FINAL_ASSEMBLY)); 2902a0806964SMatthew G. Knepley PetscCall(MatAssemblyEnd(interp, MAT_FINAL_ASSEMBLY)); 2903a0806964SMatthew G. Knepley PetscCall(MatPreallocatorPreallocate(interp, PETSC_TRUE, In)); 2904a0806964SMatthew G. Knepley PetscCall(MatDestroy(&interp)); 2905a0806964SMatthew G. Knepley interp = In; 2906a0806964SMatthew G. Knepley } 29074ef9d792SMatthew G. Knepley } 29089566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 29099566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 29109566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 29119566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 29129566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 29139566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 29144ef9d792SMatthew G. Knepley PetscFunctionReturn(0); 29154ef9d792SMatthew G. Knepley } 29164ef9d792SMatthew G. Knepley 291746fa42a0SMatthew G. Knepley /*@ 2918*a1cb98faSBarry Smith DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse `DM` to a non-nested fine `DM`. 2919bd041c0cSMatthew G. Knepley 2920bd041c0cSMatthew G. Knepley Input Parameters: 2921bd041c0cSMatthew G. Knepley + dmf - The fine mesh 2922bd041c0cSMatthew G. Knepley . dmc - The coarse mesh 2923bd041c0cSMatthew G. Knepley - user - The user context 2924bd041c0cSMatthew G. Knepley 2925bd041c0cSMatthew G. Knepley Output Parameter: 2926bd041c0cSMatthew G. Knepley . mass - The mass matrix 2927bd041c0cSMatthew G. Knepley 2928bd041c0cSMatthew G. Knepley Level: developer 2929bd041c0cSMatthew G. Knepley 2930*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeMassMatrixNested()`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()` 2931bd041c0cSMatthew G. Knepley @*/ 2932d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user) 2933d71ae5a4SJacob Faibussowitsch { 2934bd041c0cSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 2935bd041c0cSMatthew G. Knepley const char *name = "Mass Matrix"; 2936bd041c0cSMatthew G. Knepley PetscDS prob; 2937bd041c0cSMatthew G. Knepley PetscSection fsection, csection, globalFSection, globalCSection; 2938e8f14785SLisandro Dalcin PetscHSetIJ ht; 2939bd041c0cSMatthew G. Knepley PetscLayout rLayout; 2940bd041c0cSMatthew G. Knepley PetscInt *dnz, *onz; 2941bd041c0cSMatthew G. Knepley PetscInt locRows, rStart, rEnd; 2942bd041c0cSMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 2943bd041c0cSMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 2944bd041c0cSMatthew G. Knepley PetscScalar *elemMat; 2945bd041c0cSMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 2946bd041c0cSMatthew G. Knepley 2947bd041c0cSMatthew G. Knepley PetscFunctionBegin; 29489566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 29499566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 29509566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 29519566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 29529566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 29539566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 29549566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 29559566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 29569566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 29579566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 29589566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 29599566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 29609566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 2961bd041c0cSMatthew G. Knepley 29629566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mass, &locRows, NULL)); 29639566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)mass), &rLayout)); 29649566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 29659566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 29669566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(rLayout)); 29679566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd)); 29689566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&rLayout)); 29699566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz)); 29709566063dSJacob Faibussowitsch PetscCall(PetscHSetIJCreate(&ht)); 2971bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 2972bd041c0cSMatthew G. Knepley PetscObject obj; 2973bd041c0cSMatthew G. Knepley PetscClassId id; 2974bd041c0cSMatthew G. Knepley PetscQuadrature quad; 2975bd041c0cSMatthew G. Knepley const PetscReal *qpoints; 2976bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 2977bd041c0cSMatthew G. Knepley 29789566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 29799566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 29809566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 29819566063dSJacob Faibussowitsch else PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 29829566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL)); 2983bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 2984bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2985bd041c0cSMatthew G. Knepley Vec pointVec; 2986bd041c0cSMatthew G. Knepley PetscScalar *pV; 2987bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 2988bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 2989bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, q, c; 2990bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 2991bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 2992bd041c0cSMatthew G. Knepley 29939566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 29949566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 2995bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 29969566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 29979566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 29989566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 2999bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3000c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3001c330f8ffSToby Isaac 3002bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3003c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3004bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3005bd041c0cSMatthew G. Knepley } 30069566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3007bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 30089566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 30099566063dSJacob Faibussowitsch PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view")); 3010bd041c0cSMatthew G. Knepley /* Update preallocation info */ 30119566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 30125f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 3013bd041c0cSMatthew G. Knepley { 3014e8f14785SLisandro Dalcin PetscHashIJKey key; 3015e8f14785SLisandro Dalcin PetscBool missing; 3016bd041c0cSMatthew G. Knepley 3017bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 3018e8f14785SLisandro Dalcin key.i = findices[i]; 3019e8f14785SLisandro Dalcin if (key.i >= 0) { 3020bd041c0cSMatthew G. Knepley /* Get indices for coarse elements */ 3021bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 30229566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3023bd041c0cSMatthew G. Knepley for (c = 0; c < numCIndices; ++c) { 3024e8f14785SLisandro Dalcin key.j = cindices[c]; 3025e8f14785SLisandro Dalcin if (key.j < 0) continue; 30269566063dSJacob Faibussowitsch PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 3027bd041c0cSMatthew G. Knepley if (missing) { 3028e8f14785SLisandro Dalcin if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i - rStart]; 3029e8f14785SLisandro Dalcin else ++onz[key.i - rStart]; 3030bd041c0cSMatthew G. Knepley } 3031bd041c0cSMatthew G. Knepley } 30329566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3033bd041c0cSMatthew G. Knepley } 3034bd041c0cSMatthew G. Knepley } 3035bd041c0cSMatthew G. Knepley } 3036bd041c0cSMatthew G. Knepley } 30379566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 30389566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 30399566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3040bd041c0cSMatthew G. Knepley } 3041bd041c0cSMatthew G. Knepley } 30429566063dSJacob Faibussowitsch PetscCall(PetscHSetIJDestroy(&ht)); 30439566063dSJacob Faibussowitsch PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 30449566063dSJacob Faibussowitsch PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 30459566063dSJacob Faibussowitsch PetscCall(PetscFree2(dnz, onz)); 3046bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3047bd041c0cSMatthew G. Knepley PetscObject obj; 3048bd041c0cSMatthew G. Knepley PetscClassId id; 3049ef0bb6c7SMatthew G. Knepley PetscTabulation T, Tfine; 3050bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3051bd041c0cSMatthew G. Knepley const PetscReal *qpoints, *qweights; 3052bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3053bd041c0cSMatthew G. Knepley 30549566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 30559566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 3056ef0bb6c7SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 30579566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 30589566063dSJacob Faibussowitsch PetscCall(PetscFEGetCellTabulation((PetscFE)obj, 1, &Tfine)); 30599566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, 1, x, 0, &T)); 3060ef0bb6c7SMatthew G. Knepley } else { 30619566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 3062ef0bb6c7SMatthew G. Knepley } 30639566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights)); 3064bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3065bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3066bd041c0cSMatthew G. Knepley Vec pointVec; 3067bd041c0cSMatthew G. Knepley PetscScalar *pV; 3068bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3069bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3070bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, cpdim, q, c, j; 3071bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3072bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3073bd041c0cSMatthew G. Knepley 30749566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 30759566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3076bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 30779566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 30789566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 30799566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3080bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3081c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3082c330f8ffSToby Isaac 3083bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3084c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3085bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3086bd041c0cSMatthew G. Knepley } 30879566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3088bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 30899566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 3090bd041c0cSMatthew G. Knepley /* Update matrix */ 30919566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 30925f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 30939566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3094bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3095bd041c0cSMatthew G. Knepley PetscReal pVReal[3]; 3096c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3097c330f8ffSToby Isaac 30989566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3099bd041c0cSMatthew G. Knepley /* Transform points from real space to coarse reference space */ 31009566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3101bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 3102c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 3103bd041c0cSMatthew G. Knepley 3104bd041c0cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 3105bd041c0cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 3106bd041c0cSMatthew G. Knepley 3107bd041c0cSMatthew G. Knepley /* Evaluate coarse basis on contained point */ 31089566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 31099566063dSJacob Faibussowitsch PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T)); 3110bd041c0cSMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 3111bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 31129566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3113bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3114ef0bb6c7SMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * Tfine->T[0][(ccell * numFIndices + i) * Nc + c] * qweights[ccell * Nc + c] * detJ; 3115bd041c0cSMatthew G. Knepley } 3116bd041c0cSMatthew G. Knepley /* Update interpolator */ 31179566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 311863a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 31199566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3120bd041c0cSMatthew G. Knepley } 3121bd041c0cSMatthew G. Knepley } else { 3122bd041c0cSMatthew G. Knepley cpdim = 1; 3123bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 31249566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3125bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3126bd041c0cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * 1.0 * qweights[ccell * Nc + c] * detJ; 3127bd041c0cSMatthew G. Knepley } 3128bd041c0cSMatthew G. Knepley /* Update interpolator */ 31299566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 313063a3b9bcSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Nq: %" PetscInt_FMT " %" PetscInt_FMT " Nf: %" PetscInt_FMT " %" PetscInt_FMT " Nc: %" PetscInt_FMT " %" PetscInt_FMT "\n", ccell, Nq, i, numFIndices, j, numCIndices)); 313163a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 31329566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3133bd041c0cSMatthew G. Knepley } 3134bd041c0cSMatthew G. Knepley } 31359566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3136bd041c0cSMatthew G. Knepley } 31379566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 31389566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 31399566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 31409566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3141bd041c0cSMatthew G. Knepley } 31429566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3143bd041c0cSMatthew G. Knepley } 31449566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 31459566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 31469566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 31479566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 31489566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 3149bd041c0cSMatthew G. Knepley PetscFunctionReturn(0); 3150bd041c0cSMatthew G. Knepley } 3151bd041c0cSMatthew G. Knepley 3152bd041c0cSMatthew G. Knepley /*@ 315346fa42a0SMatthew G. Knepley DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns 315446fa42a0SMatthew G. Knepley 315546fa42a0SMatthew G. Knepley Input Parameters: 315646fa42a0SMatthew G. Knepley + dmc - The coarse mesh 315746fa42a0SMatthew G. Knepley - dmf - The fine mesh 315846fa42a0SMatthew G. Knepley - user - The user context 315946fa42a0SMatthew G. Knepley 316046fa42a0SMatthew G. Knepley Output Parameter: 316146fa42a0SMatthew G. Knepley . sc - The mapping 316246fa42a0SMatthew G. Knepley 316346fa42a0SMatthew G. Knepley Level: developer 316446fa42a0SMatthew G. Knepley 3165*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()` 316646fa42a0SMatthew G. Knepley @*/ 3167d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 3168d71ae5a4SJacob Faibussowitsch { 3169e9d4ef1bSMatthew G. Knepley PetscDS prob; 31707c927364SMatthew G. Knepley PetscFE *feRef; 317197c42addSMatthew G. Knepley PetscFV *fvRef; 31727c927364SMatthew G. Knepley Vec fv, cv; 31737c927364SMatthew G. Knepley IS fis, cis; 31747c927364SMatthew G. Knepley PetscSection fsection, fglobalSection, csection, cglobalSection; 31757c927364SMatthew G. Knepley PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 3176485ad865SMatthew G. Knepley PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m; 31776f3d3cbcSMatthew G. Knepley PetscBool *needAvg; 31787c927364SMatthew G. Knepley 31797c927364SMatthew G. Knepley PetscFunctionBegin; 31809566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 31819566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 31829566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 31839566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 31849566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 31859566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 31869566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 31879566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 31889566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 31899566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nf, &feRef, Nf, &fvRef, Nf, &needAvg)); 31907c927364SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 319197c42addSMatthew G. Knepley PetscObject obj; 319297c42addSMatthew G. Knepley PetscClassId id; 3193aa7890ccSMatthew G. Knepley PetscInt fNb = 0, Nc = 0; 31947c927364SMatthew G. Knepley 31959566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 31969566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 319797c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 319897c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 31996f3d3cbcSMatthew G. Knepley PetscSpace sp; 32009b2fc754SMatthew G. Knepley PetscInt maxDegree; 320197c42addSMatthew G. Knepley 32029566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 32039566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &fNb)); 32049566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 32059566063dSJacob Faibussowitsch PetscCall(PetscFEGetBasisSpace(fe, &sp)); 32069566063dSJacob Faibussowitsch PetscCall(PetscSpaceGetDegree(sp, NULL, &maxDegree)); 32079b2fc754SMatthew G. Knepley if (!maxDegree) needAvg[f] = PETSC_TRUE; 320897c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 320997c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 321097c42addSMatthew G. Knepley PetscDualSpace Q; 321197c42addSMatthew G. Knepley 32129566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 32139566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 32149566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fNb)); 32159566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 32166f3d3cbcSMatthew G. Knepley needAvg[f] = PETSC_TRUE; 321797c42addSMatthew G. Knepley } 3218d172c84bSMatthew G. Knepley fTotDim += fNb; 32197c927364SMatthew G. Knepley } 32209566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &cTotDim)); 32219566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(cTotDim, &cmap)); 32227c927364SMatthew G. Knepley for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 32237c927364SMatthew G. Knepley PetscFE feC; 322497c42addSMatthew G. Knepley PetscFV fvC; 32257c927364SMatthew G. Knepley PetscDualSpace QF, QC; 3226d172c84bSMatthew G. Knepley PetscInt order = -1, NcF, NcC, fpdim, cpdim; 32277c927364SMatthew G. Knepley 322897c42addSMatthew G. Knepley if (feRef[field]) { 32299566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&feC)); 32309566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feC, &NcC)); 32319566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[field], &NcF)); 32329566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[field], &QF)); 32339566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetOrder(QF, &order)); 32349566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 32359566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feC, &QC)); 32369566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 323797c42addSMatthew G. Knepley } else { 32389566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fvC)); 32399566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvC, &NcC)); 32409566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[field], &NcF)); 32419566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[field], &QF)); 32429566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 32439566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvC, &QC)); 32449566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 324597c42addSMatthew G. Knepley } 324663a3b9bcSJacob Faibussowitsch PetscCheck(NcF == NcC, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, NcF, NcC); 32477c927364SMatthew G. Knepley for (c = 0; c < cpdim; ++c) { 32487c927364SMatthew G. Knepley PetscQuadrature cfunc; 3249d172c84bSMatthew G. Knepley const PetscReal *cqpoints, *cqweights; 3250d172c84bSMatthew G. Knepley PetscInt NqcC, NpC; 325197c42addSMatthew G. Knepley PetscBool found = PETSC_FALSE; 32527c927364SMatthew G. Knepley 32539566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QC, c, &cfunc)); 32549566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights)); 325563a3b9bcSJacob Faibussowitsch PetscCheck(NqcC == NcC, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %" PetscInt_FMT " must match number of field components %" PetscInt_FMT, NqcC, NcC); 32561dca8a05SBarry Smith PetscCheck(NpC == 1 || !feRef[field], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 32577c927364SMatthew G. Knepley for (f = 0; f < fpdim; ++f) { 32587c927364SMatthew G. Knepley PetscQuadrature ffunc; 3259d172c84bSMatthew G. Knepley const PetscReal *fqpoints, *fqweights; 32607c927364SMatthew G. Knepley PetscReal sum = 0.0; 3261d172c84bSMatthew G. Knepley PetscInt NqcF, NpF; 32627c927364SMatthew G. Knepley 32639566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QF, f, &ffunc)); 32649566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights)); 326563a3b9bcSJacob Faibussowitsch PetscCheck(NqcF == NcF, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %" PetscInt_FMT " must match number of field components %" PetscInt_FMT, NqcF, NcF); 32667c927364SMatthew G. Knepley if (NpC != NpF) continue; 32677c927364SMatthew G. Knepley for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 32687c927364SMatthew G. Knepley if (sum > 1.0e-9) continue; 3269d172c84bSMatthew G. Knepley for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d] * fqweights[d]); 3270d172c84bSMatthew G. Knepley if (sum < 1.0e-9) continue; 3271d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + f; 327297c42addSMatthew G. Knepley found = PETSC_TRUE; 32737c927364SMatthew G. Knepley break; 32747c927364SMatthew G. Knepley } 327597c42addSMatthew G. Knepley if (!found) { 327697c42addSMatthew G. Knepley /* TODO We really want the average here, but some asshole put VecScatter in the interface */ 3277d172c84bSMatthew G. Knepley if (fvRef[field] || (feRef[field] && order == 0)) { 3278d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + 0; 327997c42addSMatthew G. Knepley } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection"); 328097c42addSMatthew G. Knepley } 32817c927364SMatthew G. Knepley } 3282d172c84bSMatthew G. Knepley offsetC += cpdim; 3283d172c84bSMatthew G. Knepley offsetF += fpdim; 32847c927364SMatthew G. Knepley } 32859371c9d4SSatish Balay for (f = 0; f < Nf; ++f) { 32869371c9d4SSatish Balay PetscCall(PetscFEDestroy(&feRef[f])); 32879371c9d4SSatish Balay PetscCall(PetscFVDestroy(&fvRef[f])); 32889371c9d4SSatish Balay } 32899566063dSJacob Faibussowitsch PetscCall(PetscFree3(feRef, fvRef, needAvg)); 32907c927364SMatthew G. Knepley 32919566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmf, &fv)); 32929566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmc, &cv)); 32939566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(cv, &startC, &endC)); 32949566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(cglobalSection, &m)); 32959566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(cTotDim, &cellCIndices, fTotDim, &cellFIndices)); 32969566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &cindices)); 32979566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &findices)); 32987c927364SMatthew G. Knepley for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 32997c927364SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 33009566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices)); 33017c927364SMatthew G. Knepley for (d = 0; d < cTotDim; ++d) { 33020bd915a7SMatthew G. Knepley if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue; 330363a3b9bcSJacob Faibussowitsch PetscCheck(!(findices[cellCIndices[d] - startC] >= 0) || !(findices[cellCIndices[d] - startC] != cellFIndices[cmap[d]]), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Coarse dof %" PetscInt_FMT " maps to both %" PetscInt_FMT " and %" PetscInt_FMT, cindices[cellCIndices[d] - startC], findices[cellCIndices[d] - startC], cellFIndices[cmap[d]]); 33047c927364SMatthew G. Knepley cindices[cellCIndices[d] - startC] = cellCIndices[d]; 33057c927364SMatthew G. Knepley findices[cellCIndices[d] - startC] = cellFIndices[cmap[d]]; 33067c927364SMatthew G. Knepley } 33077c927364SMatthew G. Knepley } 33089566063dSJacob Faibussowitsch PetscCall(PetscFree(cmap)); 33099566063dSJacob Faibussowitsch PetscCall(PetscFree2(cellCIndices, cellFIndices)); 33107c927364SMatthew G. Knepley 33119566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis)); 33129566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis)); 33139566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(cv, cis, fv, fis, sc)); 33149566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cis)); 33159566063dSJacob Faibussowitsch PetscCall(ISDestroy(&fis)); 33169566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmf, &fv)); 33179566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmc, &cv)); 33189566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 3319cb1e1211SMatthew G Knepley PetscFunctionReturn(0); 3320cb1e1211SMatthew G Knepley } 3321a1cf66bbSMatthew G. Knepley 33222f856554SMatthew G. Knepley /*@C 33232f856554SMatthew G. Knepley DMPlexGetCellFields - Retrieve the field values values for a chunk of cells 33242f856554SMatthew G. Knepley 33252f856554SMatthew G. Knepley Input Parameters: 3326*a1cb98faSBarry Smith + dm - The `DM` 33272f856554SMatthew G. Knepley . cellIS - The cells to include 33282f856554SMatthew G. Knepley . locX - A local vector with the solution fields 33292f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 33302f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 33312f856554SMatthew G. Knepley 33322f856554SMatthew G. Knepley Output Parameters: 33332f856554SMatthew G. Knepley + u - The field coefficients 33342f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 33352f856554SMatthew G. Knepley - a - The auxiliary field coefficients 33362f856554SMatthew G. Knepley 33372f856554SMatthew G. Knepley Level: developer 33382f856554SMatthew G. Knepley 3339*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 33402f856554SMatthew G. Knepley @*/ 3341d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3342d71ae5a4SJacob Faibussowitsch { 33432f856554SMatthew G. Knepley DM plex, plexA = NULL; 3344a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 33452f856554SMatthew G. Knepley PetscSection section, sectionAux; 33462f856554SMatthew G. Knepley PetscDS prob; 33472f856554SMatthew G. Knepley const PetscInt *cells; 33482f856554SMatthew G. Knepley PetscInt cStart, cEnd, numCells, totDim, totDimAux, c; 33492f856554SMatthew G. Knepley 33502f856554SMatthew G. Knepley PetscFunctionBegin; 33512f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3352064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 3353ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); 3354ad540459SPierre Jolivet if (locA) PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); 3355064a246eSJacob Faibussowitsch PetscValidPointer(u, 6); 3356064a246eSJacob Faibussowitsch PetscValidPointer(u_t, 7); 3357064a246eSJacob Faibussowitsch PetscValidPointer(a, 8); 33589566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 33599566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 33609566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 33619566063dSJacob Faibussowitsch PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob)); 33629566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 33632f856554SMatthew G. Knepley if (locA) { 33642f856554SMatthew G. Knepley DM dmAux; 33652f856554SMatthew G. Knepley PetscDS probAux; 33662f856554SMatthew G. Knepley 33679566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 33689566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 33699566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 33709566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 33719566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 33729566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 33732f856554SMatthew G. Knepley } 33742f856554SMatthew G. Knepley numCells = cEnd - cStart; 33759566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 33769371c9d4SSatish Balay if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 3377ad540459SPierre Jolivet else *u_t = NULL; 33789371c9d4SSatish Balay if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 3379ad540459SPierre Jolivet else *a = NULL; 33802f856554SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 33812f856554SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 33822f856554SMatthew G. Knepley const PetscInt cind = c - cStart; 33832f856554SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a; 33842f856554SMatthew G. Knepley PetscInt i; 33852f856554SMatthew G. Knepley 33869566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x)); 33872f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul[cind * totDim + i] = x[i]; 33889566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x)); 33892f856554SMatthew G. Knepley if (locX_t) { 33909566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t)); 33912f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul_t[cind * totDim + i] = x_t[i]; 33929566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t)); 33932f856554SMatthew G. Knepley } 33942f856554SMatthew G. Knepley if (locA) { 33952f856554SMatthew G. Knepley PetscInt subcell; 33969566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 33979566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 33982f856554SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) al[cind * totDimAux + i] = x[i]; 33999566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 34002f856554SMatthew G. Knepley } 34012f856554SMatthew G. Knepley } 34029566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 34039566063dSJacob Faibussowitsch if (locA) PetscCall(DMDestroy(&plexA)); 34049566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 34052f856554SMatthew G. Knepley PetscFunctionReturn(0); 34062f856554SMatthew G. Knepley } 34072f856554SMatthew G. Knepley 34082f856554SMatthew G. Knepley /*@C 34092f856554SMatthew G. Knepley DMPlexRestoreCellFields - Restore the field values values for a chunk of cells 34102f856554SMatthew G. Knepley 34112f856554SMatthew G. Knepley Input Parameters: 3412*a1cb98faSBarry Smith + dm - The `DM` 34132f856554SMatthew G. Knepley . cellIS - The cells to include 34142f856554SMatthew G. Knepley . locX - A local vector with the solution fields 34152f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 34162f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 34172f856554SMatthew G. Knepley 34182f856554SMatthew G. Knepley Output Parameters: 34192f856554SMatthew G. Knepley + u - The field coefficients 34202f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 34212f856554SMatthew G. Knepley - a - The auxiliary field coefficients 34222f856554SMatthew G. Knepley 34232f856554SMatthew G. Knepley Level: developer 34242f856554SMatthew G. Knepley 3425*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 34262f856554SMatthew G. Knepley @*/ 3427d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3428d71ae5a4SJacob Faibussowitsch { 34292f856554SMatthew G. Knepley PetscFunctionBegin; 34309566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u)); 34319566063dSJacob Faibussowitsch if (locX_t) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t)); 34329566063dSJacob Faibussowitsch if (locA) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a)); 34332f856554SMatthew G. Knepley PetscFunctionReturn(0); 34342f856554SMatthew G. Knepley } 34352f856554SMatthew G. Knepley 3436faff4f7fSMatthew G. Knepley /* 3437faff4f7fSMatthew G. Knepley Get the auxiliary field vectors for the negative side (s = 0) and positive side (s = 1) of the interfaace 3438faff4f7fSMatthew G. Knepley */ 3439d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetHybridAuxFields(DM dm, DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[]) 3440d71ae5a4SJacob Faibussowitsch { 344104c51a94SMatthew G. Knepley DM plexA[2]; 3442148442b3SMatthew G. Knepley DMEnclosureType encAux[2]; 344304c51a94SMatthew G. Knepley PetscSection sectionAux[2]; 34446528b96dSMatthew G. Knepley const PetscInt *cells; 3445148442b3SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, s, totDimAux[2]; 34466528b96dSMatthew G. Knepley 34476528b96dSMatthew G. Knepley PetscFunctionBegin; 3448148442b3SMatthew G. Knepley PetscValidPointer(locA, 5); 344904c51a94SMatthew G. Knepley if (!locA[0] || !locA[1]) PetscFunctionReturn(0); 3450148442b3SMatthew G. Knepley PetscValidPointer(dmAux, 2); 3451148442b3SMatthew G. Knepley PetscValidPointer(dsAux, 3); 3452148442b3SMatthew G. Knepley PetscValidPointer(a, 6); 34539566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 34546528b96dSMatthew G. Knepley numCells = cEnd - cStart; 3455148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 3456148442b3SMatthew G. Knepley PetscValidHeaderSpecific(dmAux[s], DM_CLASSID, 2); 3457148442b3SMatthew G. Knepley PetscValidHeaderSpecific(dsAux[s], PETSCDS_CLASSID, 3); 3458148442b3SMatthew G. Knepley PetscValidHeaderSpecific(locA[s], VEC_CLASSID, 5); 34599566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dmAux[s], &plexA[s], PETSC_FALSE)); 34609566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux[s], dm, &encAux[s])); 34619566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux[s], §ionAux[s])); 34629566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[s], &totDimAux[s])); 34639566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dmAux[s], numCells * totDimAux[s], MPIU_SCALAR, &a[s])); 346404c51a94SMatthew G. Knepley } 3465148442b3SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 34666528b96dSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 34676528b96dSMatthew G. Knepley const PetscInt cind = c - cStart; 34686528b96dSMatthew G. Knepley const PetscInt *cone, *ornt; 34696528b96dSMatthew G. Knepley 34709566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 34719566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 3472148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 34735fedec97SMatthew G. Knepley const PetscInt *support; 3474148442b3SMatthew G. Knepley PetscScalar *x = NULL, *al = a[s]; 3475148442b3SMatthew G. Knepley const PetscInt tdA = totDimAux[s]; 34765fedec97SMatthew G. Knepley PetscInt ssize, scell; 3477148442b3SMatthew G. Knepley PetscInt subface, Na, i; 34786528b96dSMatthew G. Knepley 34799566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[s], &support)); 34809566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[s], &ssize)); 348163a3b9bcSJacob Faibussowitsch PetscCheck(ssize == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " from cell %" PetscInt_FMT " has support size %" PetscInt_FMT " != 2", cone[s], cell, ssize); 34825fedec97SMatthew G. Knepley if (support[0] == cell) scell = support[1]; 34835fedec97SMatthew G. Knepley else if (support[1] == cell) scell = support[0]; 348463a3b9bcSJacob Faibussowitsch else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[s], cell); 34855fedec97SMatthew G. Knepley 34869566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA[s], dm, encAux[s], scell, &subface)); 34879566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x)); 34886528b96dSMatthew G. Knepley for (i = 0; i < Na; ++i) al[cind * tdA + i] = x[i]; 34899566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x)); 34906528b96dSMatthew G. Knepley } 34916528b96dSMatthew G. Knepley } 34929566063dSJacob Faibussowitsch for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexA[s])); 34939566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 34946528b96dSMatthew G. Knepley PetscFunctionReturn(0); 34956528b96dSMatthew G. Knepley } 34966528b96dSMatthew G. Knepley 3497d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexRestoreHybridAuxFields(DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[]) 3498d71ae5a4SJacob Faibussowitsch { 34996528b96dSMatthew G. Knepley PetscFunctionBegin; 350004c51a94SMatthew G. Knepley if (!locA[0] || !locA[1]) PetscFunctionReturn(0); 35019566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dmAux[0], 0, MPIU_SCALAR, &a[0])); 35029566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dmAux[1], 0, MPIU_SCALAR, &a[1])); 35036528b96dSMatthew G. Knepley PetscFunctionReturn(0); 35046528b96dSMatthew G. Knepley } 35056528b96dSMatthew G. Knepley 35062f856554SMatthew G. Knepley /*@C 35072f856554SMatthew G. Knepley DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 35082f856554SMatthew G. Knepley 35092f856554SMatthew G. Knepley Input Parameters: 3510*a1cb98faSBarry Smith + dm - The `DM` 35112f856554SMatthew G. Knepley . fStart - The first face to include 35122f856554SMatthew G. Knepley . fEnd - The first face to exclude 35132f856554SMatthew G. Knepley . locX - A local vector with the solution fields 35142f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 35152f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 35162f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 35172f856554SMatthew G. Knepley - locaGrad - A local vector with field gradients, or NULL 35182f856554SMatthew G. Knepley 35192f856554SMatthew G. Knepley Output Parameters: 35202f856554SMatthew G. Knepley + Nface - The number of faces with field values 35212f856554SMatthew G. Knepley . uL - The field values at the left side of the face 35222f856554SMatthew G. Knepley - uR - The field values at the right side of the face 35232f856554SMatthew G. Knepley 35242f856554SMatthew G. Knepley Level: developer 35252f856554SMatthew G. Knepley 3526*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 35272f856554SMatthew G. Knepley @*/ 3528d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFaceFields(DM dm, PetscInt fStart, PetscInt fEnd, Vec locX, Vec locX_t, Vec faceGeometry, Vec cellGeometry, Vec locGrad, PetscInt *Nface, PetscScalar **uL, PetscScalar **uR) 3529d71ae5a4SJacob Faibussowitsch { 35302f856554SMatthew G. Knepley DM dmFace, dmCell, dmGrad = NULL; 35312f856554SMatthew G. Knepley PetscSection section; 35322f856554SMatthew G. Knepley PetscDS prob; 35332f856554SMatthew G. Knepley DMLabel ghostLabel; 35342f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 35352f856554SMatthew G. Knepley PetscBool *isFE; 35362f856554SMatthew G. Knepley PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 35372f856554SMatthew G. Knepley 35382f856554SMatthew G. Knepley PetscFunctionBegin; 35392f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 35402f856554SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3541ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5); 35422f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 35432f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 3544ad540459SPierre Jolivet if (locGrad) PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8); 3545064a246eSJacob Faibussowitsch PetscValidPointer(uL, 10); 3546064a246eSJacob Faibussowitsch PetscValidPointer(uR, 11); 35479566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 35489566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 35499566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 35509566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 35519566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(prob, &Nc)); 35529566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nf, &isFE)); 35532f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 35542f856554SMatthew G. Knepley PetscObject obj; 35552f856554SMatthew G. Knepley PetscClassId id; 35562f856554SMatthew G. Knepley 35579566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 35589566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 35599371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 35609371c9d4SSatish Balay isFE[f] = PETSC_TRUE; 35619371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 35629371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 35639371c9d4SSatish Balay } else { 35649371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 35659371c9d4SSatish Balay } 35662f856554SMatthew G. Knepley } 35679566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 35689566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locX, &x)); 35699566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 35709566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 35719566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 35729566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 35732f856554SMatthew G. Knepley if (locGrad) { 35749566063dSJacob Faibussowitsch PetscCall(VecGetDM(locGrad, &dmGrad)); 35759566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 35762f856554SMatthew G. Knepley } 35779566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uL)); 35789566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uR)); 35792f856554SMatthew G. Knepley /* Right now just eat the extra work for FE (could make a cell loop) */ 35802f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 35812f856554SMatthew G. Knepley const PetscInt *cells; 35822f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 35832f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 35842f856554SMatthew G. Knepley PetscScalar *xL, *xR, *gL, *gR; 35852f856554SMatthew G. Knepley PetscScalar *uLl = *uL, *uRl = *uR; 35862f856554SMatthew G. Knepley PetscInt ghost, nsupp, nchild; 35872f856554SMatthew G. Knepley 35889566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 35899566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 35909566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 35912f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 35929566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 35939566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 35949566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 35959566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 35962f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 35972f856554SMatthew G. Knepley PetscInt off; 35982f856554SMatthew G. Knepley 35999566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffset(prob, f, &off)); 36002f856554SMatthew G. Knepley if (isFE[f]) { 36012f856554SMatthew G. Knepley const PetscInt *cone; 36022f856554SMatthew G. Knepley PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 36032f856554SMatthew G. Knepley 36042f856554SMatthew G. Knepley xL = xR = NULL; 36059566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 36069566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL)); 36079566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR)); 36089566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[0], &cone)); 36099566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL)); 36109371c9d4SSatish Balay for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) 36119371c9d4SSatish Balay if (cone[faceLocL] == face) break; 36129566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[1], &cone)); 36139566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR)); 36149371c9d4SSatish Balay for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) 36159371c9d4SSatish Balay if (cone[faceLocR] == face) break; 36161dca8a05SBarry Smith PetscCheck(faceLocL != coneSizeL || faceLocR != coneSizeR, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %" PetscInt_FMT " in cone of cell %" PetscInt_FMT " or cell %" PetscInt_FMT, face, cells[0], cells[1]); 36172f856554SMatthew G. Knepley /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 36182f856554SMatthew G. Knepley /* TODO: this is a hack that might not be right for nonconforming */ 36192f856554SMatthew G. Knepley if (faceLocL < coneSizeL) { 36209566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface * Nc + off])); 36219566063dSJacob Faibussowitsch if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 36222f856554SMatthew G. Knepley else { 36239371c9d4SSatish Balay for (d = 0; d < comp; ++d) uRl[iface * Nc + off + d] = uLl[iface * Nc + off + d]; 36249371c9d4SSatish Balay } 36259371c9d4SSatish Balay } else { 36269566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 36279566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 36282f856554SMatthew G. Knepley for (d = 0; d < comp; ++d) uLl[iface * Nc + off + d] = uRl[iface * Nc + off + d]; 36292f856554SMatthew G. Knepley } 36309566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL)); 36319566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR)); 36322f856554SMatthew G. Knepley } else { 36332f856554SMatthew G. Knepley PetscFV fv; 36342f856554SMatthew G. Knepley PetscInt numComp, c; 36352f856554SMatthew G. Knepley 36369566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *)&fv)); 36379566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &numComp)); 36389566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL)); 36399566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR)); 36402f856554SMatthew G. Knepley if (dmGrad) { 36412f856554SMatthew G. Knepley PetscReal dxL[3], dxR[3]; 36422f856554SMatthew G. Knepley 36439566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL)); 36449566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR)); 36452f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 36462f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 36472f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 36482f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c * dim], dxL); 36492f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c * dim], dxR); 36502f856554SMatthew G. Knepley } 36512f856554SMatthew G. Knepley } else { 36522f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 36532f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c]; 36542f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c]; 36552f856554SMatthew G. Knepley } 36562f856554SMatthew G. Knepley } 36572f856554SMatthew G. Knepley } 36582f856554SMatthew G. Knepley } 36592f856554SMatthew G. Knepley ++iface; 36602f856554SMatthew G. Knepley } 36612f856554SMatthew G. Knepley *Nface = iface; 36629566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locX, &x)); 36639566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 36649566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 366548a46eb9SPierre Jolivet if (locGrad) PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 36669566063dSJacob Faibussowitsch PetscCall(PetscFree(isFE)); 36672f856554SMatthew G. Knepley PetscFunctionReturn(0); 36682f856554SMatthew G. Knepley } 36692f856554SMatthew G. Knepley 36702f856554SMatthew G. Knepley /*@C 36712f856554SMatthew G. Knepley DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 36722f856554SMatthew G. Knepley 36732f856554SMatthew G. Knepley Input Parameters: 3674*a1cb98faSBarry Smith + dm - The `DM` 36752f856554SMatthew G. Knepley . fStart - The first face to include 36762f856554SMatthew G. Knepley . fEnd - The first face to exclude 36772f856554SMatthew G. Knepley . locX - A local vector with the solution fields 36782f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 36792f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 36802f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 36812f856554SMatthew G. Knepley - locaGrad - A local vector with field gradients, or NULL 36822f856554SMatthew G. Knepley 36832f856554SMatthew G. Knepley Output Parameters: 36842f856554SMatthew G. Knepley + Nface - The number of faces with field values 36852f856554SMatthew G. Knepley . uL - The field values at the left side of the face 36862f856554SMatthew G. Knepley - uR - The field values at the right side of the face 36872f856554SMatthew G. Knepley 36882f856554SMatthew G. Knepley Level: developer 36892f856554SMatthew G. Knepley 3690*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 36912f856554SMatthew G. Knepley @*/ 3692d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreFaceFields(DM dm, PetscInt fStart, PetscInt fEnd, Vec locX, Vec locX_t, Vec faceGeometry, Vec cellGeometry, Vec locGrad, PetscInt *Nface, PetscScalar **uL, PetscScalar **uR) 3693d71ae5a4SJacob Faibussowitsch { 36942f856554SMatthew G. Knepley PetscFunctionBegin; 36959566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL)); 36969566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR)); 36972f856554SMatthew G. Knepley PetscFunctionReturn(0); 36982f856554SMatthew G. Knepley } 36992f856554SMatthew G. Knepley 37002f856554SMatthew G. Knepley /*@C 37012f856554SMatthew G. Knepley DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 37022f856554SMatthew G. Knepley 37032f856554SMatthew G. Knepley Input Parameters: 3704*a1cb98faSBarry Smith + dm - The `DM` 37052f856554SMatthew G. Knepley . fStart - The first face to include 37062f856554SMatthew G. Knepley . fEnd - The first face to exclude 37072f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 37082f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 37092f856554SMatthew G. Knepley 37102f856554SMatthew G. Knepley Output Parameters: 37112f856554SMatthew G. Knepley + Nface - The number of faces with field values 37122f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 37132f856554SMatthew G. Knepley - vol - The cell volume 37142f856554SMatthew G. Knepley 37152f856554SMatthew G. Knepley Level: developer 37162f856554SMatthew G. Knepley 3717*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 37182f856554SMatthew G. Knepley @*/ 3719d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3720d71ae5a4SJacob Faibussowitsch { 37212f856554SMatthew G. Knepley DM dmFace, dmCell; 37222f856554SMatthew G. Knepley DMLabel ghostLabel; 37232f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom; 37242f856554SMatthew G. Knepley PetscInt dim, numFaces = fEnd - fStart, iface, face; 37252f856554SMatthew G. Knepley 37262f856554SMatthew G. Knepley PetscFunctionBegin; 37272f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 37282f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 37292f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 3730064a246eSJacob Faibussowitsch PetscValidPointer(fgeom, 7); 3731064a246eSJacob Faibussowitsch PetscValidPointer(vol, 8); 37329566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 37339566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 37349566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 37359566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 37369566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 37379566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 37389566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(numFaces, fgeom)); 37399566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * 2, MPIU_SCALAR, vol)); 37402f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 37412f856554SMatthew G. Knepley const PetscInt *cells; 37422f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 37432f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 37442f856554SMatthew G. Knepley PetscFVFaceGeom *fgeoml = *fgeom; 37452f856554SMatthew G. Knepley PetscReal *voll = *vol; 37462f856554SMatthew G. Knepley PetscInt ghost, d, nchild, nsupp; 37472f856554SMatthew G. Knepley 37489566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 37499566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 37509566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 37512f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 37529566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 37539566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 37549566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 37559566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 37562f856554SMatthew G. Knepley for (d = 0; d < dim; ++d) { 37572f856554SMatthew G. Knepley fgeoml[iface].centroid[d] = fg->centroid[d]; 37582f856554SMatthew G. Knepley fgeoml[iface].normal[d] = fg->normal[d]; 37592f856554SMatthew G. Knepley } 37602f856554SMatthew G. Knepley voll[iface * 2 + 0] = cgL->volume; 37612f856554SMatthew G. Knepley voll[iface * 2 + 1] = cgR->volume; 37622f856554SMatthew G. Knepley ++iface; 37632f856554SMatthew G. Knepley } 37642f856554SMatthew G. Knepley *Nface = iface; 37659566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 37669566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 37672f856554SMatthew G. Knepley PetscFunctionReturn(0); 37682f856554SMatthew G. Knepley } 37692f856554SMatthew G. Knepley 37702f856554SMatthew G. Knepley /*@C 37712f856554SMatthew G. Knepley DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 37722f856554SMatthew G. Knepley 37732f856554SMatthew G. Knepley Input Parameters: 3774*a1cb98faSBarry Smith + dm - The `DM` 37752f856554SMatthew G. Knepley . fStart - The first face to include 37762f856554SMatthew G. Knepley . fEnd - The first face to exclude 37772f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 37782f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 37792f856554SMatthew G. Knepley 37802f856554SMatthew G. Knepley Output Parameters: 37812f856554SMatthew G. Knepley + Nface - The number of faces with field values 37822f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 37832f856554SMatthew G. Knepley - vol - The cell volume 37842f856554SMatthew G. Knepley 37852f856554SMatthew G. Knepley Level: developer 37862f856554SMatthew G. Knepley 3787*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 37882f856554SMatthew G. Knepley @*/ 3789d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3790d71ae5a4SJacob Faibussowitsch { 37912f856554SMatthew G. Knepley PetscFunctionBegin; 37929566063dSJacob Faibussowitsch PetscCall(PetscFree(*fgeom)); 37939566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol)); 37942f856554SMatthew G. Knepley PetscFunctionReturn(0); 37952f856554SMatthew G. Knepley } 37962f856554SMatthew G. Knepley 3797d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3798d71ae5a4SJacob Faibussowitsch { 3799a1cf66bbSMatthew G. Knepley char composeStr[33] = {0}; 3800a1cf66bbSMatthew G. Knepley PetscObjectId id; 3801a1cf66bbSMatthew G. Knepley PetscContainer container; 3802a1cf66bbSMatthew G. Knepley 3803a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 38049566063dSJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)quad, &id)); 380563a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id)); 38069566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container)); 3807a1cf66bbSMatthew G. Knepley if (container) { 38089566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(container, (void **)geom)); 3809a1cf66bbSMatthew G. Knepley } else { 38109566063dSJacob Faibussowitsch PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 38119566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 38129566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(container, (void *)*geom)); 38139566063dSJacob Faibussowitsch PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom)); 38149566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container)); 38159566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&container)); 3816a1cf66bbSMatthew G. Knepley } 3817a1cf66bbSMatthew G. Knepley PetscFunctionReturn(0); 3818a1cf66bbSMatthew G. Knepley } 3819a1cf66bbSMatthew G. Knepley 3820d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3821d71ae5a4SJacob Faibussowitsch { 3822a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 3823a1cf66bbSMatthew G. Knepley *geom = NULL; 3824a1cf66bbSMatthew G. Knepley PetscFunctionReturn(0); 3825a1cf66bbSMatthew G. Knepley } 3826a1cf66bbSMatthew G. Knepley 3827d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 3828d71ae5a4SJacob Faibussowitsch { 382992d50984SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 383092d50984SMatthew G. Knepley const char *name = "Residual"; 383192d50984SMatthew G. Knepley DM dmAux = NULL; 383292d50984SMatthew G. Knepley DMLabel ghostLabel = NULL; 383392d50984SMatthew G. Knepley PetscDS prob = NULL; 383492d50984SMatthew G. Knepley PetscDS probAux = NULL; 383592d50984SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 383692d50984SMatthew G. Knepley PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 383792d50984SMatthew G. Knepley DMField coordField = NULL; 3838c0006e53SPatrick Farrell Vec locA; 3839c0006e53SPatrick Farrell PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 384092d50984SMatthew G. Knepley IS chunkIS; 384192d50984SMatthew G. Knepley const PetscInt *cells; 384292d50984SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 3843364207b6SKarl Rupp PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 384492d50984SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 384506ad1575SMatthew G. Knepley PetscFormKey key; 384692d50984SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 384792d50984SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 384892d50984SMatthew G. Knepley 384992d50984SMatthew G. Knepley PetscFunctionBegin; 38509566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 385192d50984SMatthew G. Knepley /* FEM+FVM */ 385292d50984SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 38539566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 38549566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 38559566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 38569566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 38579566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 385892d50984SMatthew G. Knepley if (locA) { 38599566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 38609566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 38619566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 386292d50984SMatthew G. Knepley } 386392d50984SMatthew G. Knepley /* 2: Get geometric data */ 386492d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 386592d50984SMatthew G. Knepley PetscObject obj; 386692d50984SMatthew G. Knepley PetscClassId id; 386792d50984SMatthew G. Knepley PetscBool fimp; 386892d50984SMatthew G. Knepley 38699566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 387092d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 38719566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 38729566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 3873ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 38745f80ce2aSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Use of FVM with PCPATCH not yet implemented"); 387592d50984SMatthew G. Knepley } 387692d50984SMatthew G. Knepley if (useFEM) { 38779566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 38789566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 387992d50984SMatthew G. Knepley if (maxDegree <= 1) { 38809566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 388148a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 388292d50984SMatthew G. Knepley } else { 38839566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 388492d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 388592d50984SMatthew G. Knepley PetscObject obj; 388692d50984SMatthew G. Knepley PetscClassId id; 388792d50984SMatthew G. Knepley PetscBool fimp; 388892d50984SMatthew G. Knepley 38899566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 389092d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 38919566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 38929566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 389392d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 389492d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 389592d50984SMatthew G. Knepley 38969566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 38979566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 38989566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 389992d50984SMatthew G. Knepley } 390092d50984SMatthew G. Knepley } 390192d50984SMatthew G. Knepley } 390292d50984SMatthew G. Knepley } 390392d50984SMatthew G. Knepley /* Loop over chunks */ 39049566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 39059566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 39069566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 390792d50984SMatthew G. Knepley numCells = cEnd - cStart; 390892d50984SMatthew G. Knepley numChunks = 1; 390992d50984SMatthew G. Knepley cellChunkSize = numCells / numChunks; 391092d50984SMatthew G. Knepley numChunks = PetscMin(1, numCells); 39116528b96dSMatthew G. Knepley key.label = NULL; 39126528b96dSMatthew G. Knepley key.value = 0; 391306ad1575SMatthew G. Knepley key.part = 0; 391492d50984SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 3915c0006e53SPatrick Farrell PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 3916c0006e53SPatrick Farrell PetscReal *vol = NULL; 3917c0006e53SPatrick Farrell PetscFVFaceGeom *fgeom = NULL; 391892d50984SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 3919c0006e53SPatrick Farrell PetscInt numFaces = 0; 392092d50984SMatthew G. Knepley 392192d50984SMatthew G. Knepley /* Extract field coefficients */ 392292d50984SMatthew G. Knepley if (useFEM) { 39239566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 39249566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 39259566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 39269566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 392792d50984SMatthew G. Knepley } 392892d50984SMatthew G. Knepley /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */ 392992d50984SMatthew G. Knepley /* Loop over fields */ 393092d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 393192d50984SMatthew G. Knepley PetscObject obj; 393292d50984SMatthew G. Knepley PetscClassId id; 393392d50984SMatthew G. Knepley PetscBool fimp; 393492d50984SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 393592d50984SMatthew G. Knepley 39366528b96dSMatthew G. Knepley key.field = f; 39379566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 393892d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 39399566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 39409566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 394192d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 394292d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 394392d50984SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 394492d50984SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 394592d50984SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 394692d50984SMatthew G. Knepley PetscInt Nq, Nb; 394792d50984SMatthew G. Knepley 39489566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 39499566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 39509566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 395192d50984SMatthew G. Knepley blockSize = Nb; 395292d50984SMatthew G. Knepley batchSize = numBlocks * blockSize; 39539566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 395492d50984SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 395592d50984SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 395692d50984SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 395792d50984SMatthew G. Knepley offset = numCells - Nr; 395892d50984SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 395992d50984SMatthew G. Knepley /* For FV, I think we use a P0 basis and the cell coefficients (for subdivided cells, we can tweak the basis tabulation to be the indicator function) */ 39609566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 39619566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 39629566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 39639566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, &elemVec[offset * totDim])); 39649566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 396592d50984SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 396692d50984SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 396792d50984SMatthew G. Knepley 396892d50984SMatthew G. Knepley Ne = numFaces; 396992d50984SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 397092d50984SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 39719566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 397263a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 397392d50984SMatthew G. Knepley } 397492d50984SMatthew G. Knepley /* Loop over domain */ 397592d50984SMatthew G. Knepley if (useFEM) { 397692d50984SMatthew G. Knepley /* Add elemVec to locX */ 397792d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 397892d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 397992d50984SMatthew G. Knepley const PetscInt cind = c - cStart; 398092d50984SMatthew G. Knepley 39819566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 398292d50984SMatthew G. Knepley if (ghostLabel) { 398392d50984SMatthew G. Knepley PetscInt ghostVal; 398492d50984SMatthew G. Knepley 39859566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 398692d50984SMatthew G. Knepley if (ghostVal > 0) continue; 398792d50984SMatthew G. Knepley } 39889566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 398992d50984SMatthew G. Knepley } 399092d50984SMatthew G. Knepley } 399192d50984SMatthew G. Knepley /* Handle time derivative */ 399292d50984SMatthew G. Knepley if (locX_t) { 399392d50984SMatthew G. Knepley PetscScalar *x_t, *fa; 399492d50984SMatthew G. Knepley 39959566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 39969566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 399792d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 399892d50984SMatthew G. Knepley PetscFV fv; 399992d50984SMatthew G. Knepley PetscObject obj; 400092d50984SMatthew G. Knepley PetscClassId id; 400192d50984SMatthew G. Knepley PetscInt pdim, d; 400292d50984SMatthew G. Knepley 40039566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 40049566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 400592d50984SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 400692d50984SMatthew G. Knepley fv = (PetscFV)obj; 40079566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 400892d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 400992d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 401092d50984SMatthew G. Knepley PetscScalar *u_t, *r; 401192d50984SMatthew G. Knepley 401292d50984SMatthew G. Knepley if (ghostLabel) { 401392d50984SMatthew G. Knepley PetscInt ghostVal; 401492d50984SMatthew G. Knepley 40159566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 401692d50984SMatthew G. Knepley if (ghostVal > 0) continue; 401792d50984SMatthew G. Knepley } 40189566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 40199566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 402092d50984SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 402192d50984SMatthew G. Knepley } 402292d50984SMatthew G. Knepley } 40239566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 40249566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 402592d50984SMatthew G. Knepley } 402692d50984SMatthew G. Knepley if (useFEM) { 40279566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 40289566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 402992d50984SMatthew G. Knepley } 403092d50984SMatthew G. Knepley } 40319566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 40329566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 403392d50984SMatthew G. Knepley /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 403492d50984SMatthew G. Knepley if (useFEM) { 403592d50984SMatthew G. Knepley if (maxDegree <= 1) { 40369566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 40379566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 403892d50984SMatthew G. Knepley } else { 403992d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 40409566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 40419566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 404292d50984SMatthew G. Knepley } 40439566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 404492d50984SMatthew G. Knepley } 404592d50984SMatthew G. Knepley } 40469566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 404792d50984SMatthew G. Knepley PetscFunctionReturn(0); 404892d50984SMatthew G. Knepley } 404992d50984SMatthew G. Knepley 4050a1cf66bbSMatthew G. Knepley /* 4051a1cf66bbSMatthew G. Knepley We always assemble JacP, and if the matrix is different from Jac and two different sets of point functions are provided, we also assemble Jac 4052a1cf66bbSMatthew G. Knepley 4053a1cf66bbSMatthew G. Knepley X - The local solution vector 4054a5b23f4aSJose E. Roman X_t - The local solution time derivative vector, or NULL 4055a1cf66bbSMatthew G. Knepley */ 4056d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx) 4057d71ae5a4SJacob Faibussowitsch { 4058a1cf66bbSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 4059a1cf66bbSMatthew G. Knepley const char *name = "Jacobian", *nameP = "JacobianPre"; 4060a1cf66bbSMatthew G. Knepley DM dmAux = NULL; 4061a1cf66bbSMatthew G. Knepley PetscDS prob, probAux = NULL; 4062a1cf66bbSMatthew G. Knepley PetscSection sectionAux = NULL; 4063a1cf66bbSMatthew G. Knepley Vec A; 4064a1cf66bbSMatthew G. Knepley DMField coordField; 4065a1cf66bbSMatthew G. Knepley PetscFEGeom *cgeomFEM; 4066a1cf66bbSMatthew G. Knepley PetscQuadrature qGeom = NULL; 4067a1cf66bbSMatthew G. Knepley Mat J = Jac, JP = JacP; 4068a1cf66bbSMatthew G. Knepley PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 4069e432b41dSStefano Zampini PetscBool hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE; 4070a1cf66bbSMatthew G. Knepley const PetscInt *cells; 407106ad1575SMatthew G. Knepley PetscFormKey key; 40729b2fc754SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 4073a1cf66bbSMatthew G. Knepley 4074a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 40759566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 40769566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 40779566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 40789566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 40799566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A)); 40809a2a23afSMatthew G. Knepley if (A) { 40819566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 40829566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 40839566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 4084a1cf66bbSMatthew G. Knepley } 4085a1cf66bbSMatthew G. Knepley /* Get flags */ 40869566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 40879566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4088a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4089a1cf66bbSMatthew G. Knepley PetscObject disc; 4090a1cf66bbSMatthew G. Knepley PetscClassId id; 40919566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc)); 40929566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(disc, &id)); 40939371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 40949371c9d4SSatish Balay isFE[fieldI] = PETSC_TRUE; 40959371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 40969371c9d4SSatish Balay hasFV = PETSC_TRUE; 40979371c9d4SSatish Balay isFE[fieldI] = PETSC_FALSE; 40989371c9d4SSatish Balay } 4099a1cf66bbSMatthew G. Knepley } 41009566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 41019566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 41029566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 4103a1cf66bbSMatthew G. Knepley assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 4104a1cf66bbSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 41059566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */ 41069566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 41079566063dSJacob Faibussowitsch if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4108a1cf66bbSMatthew G. Knepley /* Compute batch sizes */ 4109a1cf66bbSMatthew G. Knepley if (isFE[0]) { 4110a1cf66bbSMatthew G. Knepley PetscFE fe; 4111a1cf66bbSMatthew G. Knepley PetscQuadrature q; 4112a1cf66bbSMatthew G. Knepley PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 4113a1cf66bbSMatthew G. Knepley 41149566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 41159566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 41169566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL)); 41179566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 41189566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4119a1cf66bbSMatthew G. Knepley blockSize = Nb * numQuadPoints; 4120a1cf66bbSMatthew G. Knepley batchSize = numBlocks * blockSize; 4121a1cf66bbSMatthew G. Knepley chunkSize = numBatches * batchSize; 4122a1cf66bbSMatthew G. Knepley numChunks = numCells / chunkSize + numCells % chunkSize; 41239566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4124a1cf66bbSMatthew G. Knepley } else { 4125a1cf66bbSMatthew G. Knepley chunkSize = numCells; 4126a1cf66bbSMatthew G. Knepley numChunks = 1; 4127a1cf66bbSMatthew G. Knepley } 4128a1cf66bbSMatthew G. Knepley /* Get work space */ 4129a1cf66bbSMatthew G. Knepley wsz = (((X ? 1 : 0) + (X_t ? 1 : 0) + (dmAux ? 1 : 0)) * totDim + ((hasJac ? 1 : 0) + (hasPrec ? 1 : 0) + (hasDyn ? 1 : 0)) * totDim * totDim) * chunkSize; 41309566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work)); 41319566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(work, wsz)); 4132a1cf66bbSMatthew G. Knepley off = 0; 4133a1cf66bbSMatthew G. Knepley u = X ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4134a1cf66bbSMatthew G. Knepley u_t = X_t ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4135a1cf66bbSMatthew G. Knepley a = dmAux ? (sz = chunkSize * totDimAux, off += sz, work + off - sz) : NULL; 4136a1cf66bbSMatthew G. Knepley elemMat = hasJac ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4137a1cf66bbSMatthew G. Knepley elemMatP = hasPrec ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4138a1cf66bbSMatthew G. Knepley elemMatD = hasDyn ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 413963a3b9bcSJacob Faibussowitsch PetscCheck(off == wsz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %" PetscInt_FMT " should be %" PetscInt_FMT, off, wsz); 4140a1cf66bbSMatthew G. Knepley /* Setup geometry */ 41419566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 41429566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 41439566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 4144a1cf66bbSMatthew G. Knepley if (!qGeom) { 4145a1cf66bbSMatthew G. Knepley PetscFE fe; 4146a1cf66bbSMatthew G. Knepley 41479566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 41489566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 41499566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 4150a1cf66bbSMatthew G. Knepley } 41519566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4152a1cf66bbSMatthew G. Knepley /* Compute volume integrals */ 41539566063dSJacob Faibussowitsch if (assembleJac) PetscCall(MatZeroEntries(J)); 41549566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(JP)); 41556528b96dSMatthew G. Knepley key.label = NULL; 41566528b96dSMatthew G. Knepley key.value = 0; 415706ad1575SMatthew G. Knepley key.part = 0; 4158a1cf66bbSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 4159a1cf66bbSMatthew G. Knepley const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 4160a1cf66bbSMatthew G. Knepley PetscInt c; 4161a1cf66bbSMatthew G. Knepley 4162a1cf66bbSMatthew G. Knepley /* Extract values */ 4163a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4164a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4165a1cf66bbSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 4166a1cf66bbSMatthew G. Knepley PetscInt i; 4167a1cf66bbSMatthew G. Knepley 4168a1cf66bbSMatthew G. Knepley if (X) { 41699566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 4170a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 41719566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 4172a1cf66bbSMatthew G. Knepley } 4173a1cf66bbSMatthew G. Knepley if (X_t) { 41749566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 4175a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[c * totDim + i] = x_t[i]; 41769566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 4177a1cf66bbSMatthew G. Knepley } 4178a1cf66bbSMatthew G. Knepley if (dmAux) { 41799566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4180a1cf66bbSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 41819566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4182a1cf66bbSMatthew G. Knepley } 4183a1cf66bbSMatthew G. Knepley } 4184a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4185a1cf66bbSMatthew G. Knepley PetscFE fe; 41869566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 4187a1cf66bbSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 41886528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 41899566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat)); 41909566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP)); 41919566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD)); 4192a1cf66bbSMatthew G. Knepley } 4193a1cf66bbSMatthew G. Knepley /* For finite volume, add the identity */ 4194a1cf66bbSMatthew G. Knepley if (!isFE[fieldI]) { 4195a1cf66bbSMatthew G. Knepley PetscFV fv; 4196a1cf66bbSMatthew G. Knepley PetscInt eOffset = 0, Nc, fc, foff; 4197a1cf66bbSMatthew G. Knepley 41989566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff)); 41999566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 42009566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 4201a1cf66bbSMatthew G. Knepley for (c = 0; c < chunkSize; ++c, eOffset += totDim * totDim) { 4202a1cf66bbSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 4203a1cf66bbSMatthew G. Knepley const PetscInt i = foff + fc; 4204ad540459SPierre Jolivet if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 4205ad540459SPierre Jolivet if (hasPrec) elemMatP[eOffset + i * totDim + i] = 1.0; 4206a1cf66bbSMatthew G. Knepley } 4207a1cf66bbSMatthew G. Knepley } 4208a1cf66bbSMatthew G. Knepley } 4209a1cf66bbSMatthew G. Knepley } 4210a1cf66bbSMatthew G. Knepley /* Add contribution from X_t */ 42119371c9d4SSatish Balay if (hasDyn) { 42129371c9d4SSatish Balay for (c = 0; c < chunkSize * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 42139371c9d4SSatish Balay } 4214a1cf66bbSMatthew G. Knepley /* Insert values into matrix */ 4215a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4216a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4217a1cf66bbSMatthew G. Knepley if (mesh->printFEM > 1) { 42189566063dSJacob Faibussowitsch if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c - cStart) * totDim * totDim])); 42199566063dSJacob Faibussowitsch if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c - cStart) * totDim * totDim])); 4220a1cf66bbSMatthew G. Knepley } 42219566063dSJacob Faibussowitsch if (assembleJac) PetscCall(DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 42229566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4223a1cf66bbSMatthew G. Knepley } 4224a1cf66bbSMatthew G. Knepley } 4225a1cf66bbSMatthew G. Knepley /* Cleanup */ 42269566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 42279566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 42289566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 42299566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 42309566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, ((1 + (X_t ? 1 : 0) + (dmAux ? 1 : 0)) * totDim + ((hasJac ? 1 : 0) + (hasPrec ? 1 : 0) + (hasDyn ? 1 : 0)) * totDim * totDim) * chunkSize, MPIU_SCALAR, &work)); 4231a1cf66bbSMatthew G. Knepley /* Compute boundary integrals */ 42329566063dSJacob Faibussowitsch /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */ 4233a1cf66bbSMatthew G. Knepley /* Assemble matrix */ 42349371c9d4SSatish Balay if (assembleJac) { 42359371c9d4SSatish Balay PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 42369371c9d4SSatish Balay PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 42379371c9d4SSatish Balay } 42389371c9d4SSatish Balay PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 42399371c9d4SSatish Balay PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 42409566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 4241a1cf66bbSMatthew G. Knepley PetscFunctionReturn(0); 4242a1cf66bbSMatthew G. Knepley } 42433e9753d6SMatthew G. Knepley 42443e9753d6SMatthew G. Knepley /******** FEM Assembly Function ********/ 42453e9753d6SMatthew G. Knepley 4246d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy) 4247d71ae5a4SJacob Faibussowitsch { 42483e9753d6SMatthew G. Knepley PetscBool isPlex; 42493e9753d6SMatthew G. Knepley 42503e9753d6SMatthew G. Knepley PetscFunctionBegin; 42519566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 42523e9753d6SMatthew G. Knepley if (isPlex) { 42533e9753d6SMatthew G. Knepley *plex = dm; 42549566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 42553e9753d6SMatthew G. Knepley } else { 42569566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 42573e9753d6SMatthew G. Knepley if (!*plex) { 42589566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 42599566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 42601baa6e33SBarry Smith if (copy) PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 42613e9753d6SMatthew G. Knepley } else { 42629566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)*plex)); 42633e9753d6SMatthew G. Knepley } 42643e9753d6SMatthew G. Knepley } 42653e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 42663e9753d6SMatthew G. Knepley } 42673e9753d6SMatthew G. Knepley 42683e9753d6SMatthew G. Knepley /*@ 42693e9753d6SMatthew G. Knepley DMPlexGetGeometryFVM - Return precomputed geometric data 42703e9753d6SMatthew G. Knepley 4271*a1cb98faSBarry Smith Collective on dm 42723e9753d6SMatthew G. Knepley 42733e9753d6SMatthew G. Knepley Input Parameter: 4274*a1cb98faSBarry Smith . dm - The `DM` 42753e9753d6SMatthew G. Knepley 42763e9753d6SMatthew G. Knepley Output Parameters: 42773e9753d6SMatthew G. Knepley + facegeom - The values precomputed from face geometry 42783e9753d6SMatthew G. Knepley . cellgeom - The values precomputed from cell geometry 42793e9753d6SMatthew G. Knepley - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell 42803e9753d6SMatthew G. Knepley 42813e9753d6SMatthew G. Knepley Level: developer 42823e9753d6SMatthew G. Knepley 4283*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMTSSetRHSFunctionLocal()` 42843e9753d6SMatthew G. Knepley @*/ 4285d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius) 4286d71ae5a4SJacob Faibussowitsch { 42873e9753d6SMatthew G. Knepley DM plex; 42883e9753d6SMatthew G. Knepley 42893e9753d6SMatthew G. Knepley PetscFunctionBegin; 42903e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 42919566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 42929566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL)); 42939566063dSJacob Faibussowitsch if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius)); 42949566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 42953e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 42963e9753d6SMatthew G. Knepley } 42973e9753d6SMatthew G. Knepley 42983e9753d6SMatthew G. Knepley /*@ 42993e9753d6SMatthew G. Knepley DMPlexGetGradientDM - Return gradient data layout 43003e9753d6SMatthew G. Knepley 4301*a1cb98faSBarry Smith Collective on dm 43023e9753d6SMatthew G. Knepley 43033e9753d6SMatthew G. Knepley Input Parameters: 4304*a1cb98faSBarry Smith + dm - The `DM` 43053e9753d6SMatthew G. Knepley - fv - The PetscFV 43063e9753d6SMatthew G. Knepley 43073e9753d6SMatthew G. Knepley Output Parameter: 43083e9753d6SMatthew G. Knepley . dmGrad - The layout for gradient values 43093e9753d6SMatthew G. Knepley 43103e9753d6SMatthew G. Knepley Level: developer 43113e9753d6SMatthew G. Knepley 4312*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetGeometryFVM()` 43133e9753d6SMatthew G. Knepley @*/ 4314d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad) 4315d71ae5a4SJacob Faibussowitsch { 43163e9753d6SMatthew G. Knepley DM plex; 43173e9753d6SMatthew G. Knepley PetscBool computeGradients; 43183e9753d6SMatthew G. Knepley 43193e9753d6SMatthew G. Knepley PetscFunctionBegin; 43203e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 43213e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 43223e9753d6SMatthew G. Knepley PetscValidPointer(dmGrad, 3); 43239566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &computeGradients)); 43249371c9d4SSatish Balay if (!computeGradients) { 43259371c9d4SSatish Balay *dmGrad = NULL; 43269371c9d4SSatish Balay PetscFunctionReturn(0); 43279371c9d4SSatish Balay } 43289566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 43299566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad)); 43309566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 43313e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 43323e9753d6SMatthew G. Knepley } 43333e9753d6SMatthew G. Knepley 4334d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdResidual_Single_Internal(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF, DMField coordField, IS facetIS) 4335d71ae5a4SJacob Faibussowitsch { 43363e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 43373e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL; 43383e9753d6SMatthew G. Knepley DMEnclosureType encAux; 43393e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 43403e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 43413e9753d6SMatthew G. Knepley Vec locA = NULL; 43423e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL; 43433e9753d6SMatthew G. Knepley PetscInt totDim, totDimAux = 0; 43443e9753d6SMatthew G. Knepley 43453e9753d6SMatthew G. Knepley PetscFunctionBegin; 43469566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 43479566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 43489566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 43499566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 43509566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 43513e9753d6SMatthew G. Knepley if (locA) { 43523e9753d6SMatthew G. Knepley DM dmAux; 43533e9753d6SMatthew G. Knepley 43549566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 43559566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 43569566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 43579566063dSJacob Faibussowitsch PetscCall(DMGetDS(plexA, &probAux)); 43589566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 43599566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 43603e9753d6SMatthew G. Knepley } 43610c290148SMatthew G. Knepley { 43623e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 43633e9753d6SMatthew G. Knepley PetscInt maxDegree; 43643e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 43653e9753d6SMatthew G. Knepley IS pointIS; 43663e9753d6SMatthew G. Knepley const PetscInt *points; 43673e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 43683e9753d6SMatthew G. Knepley 43699566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 43700c290148SMatthew G. Knepley if (!pointIS) goto end; /* No points with that id on this process */ 43713e9753d6SMatthew G. Knepley { 43723e9753d6SMatthew G. Knepley IS isectIS; 43733e9753d6SMatthew G. Knepley 43743e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 43759566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 43769566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 43773e9753d6SMatthew G. Knepley pointIS = isectIS; 43783e9753d6SMatthew G. Knepley } 43799566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 43809566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 43819566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim, &elemVec, locA ? numFaces * totDimAux : 0, &a)); 43829566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 438348a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 43843e9753d6SMatthew G. Knepley if (!qGeom) { 43853e9753d6SMatthew G. Knepley PetscFE fe; 43863e9753d6SMatthew G. Knepley 43879566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 43889566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 43899566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 43903e9753d6SMatthew G. Knepley } 43919566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 43929566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 43933e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 4394f15274beSMatthew Knepley const PetscInt point = points[face], *support; 43953e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 4396f15274beSMatthew Knepley PetscInt i; 43973e9753d6SMatthew G. Knepley 43989566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 43999566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 44003e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 44019566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 44023e9753d6SMatthew G. Knepley if (locX_t) { 44039566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 44043e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 44059566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 44063e9753d6SMatthew G. Knepley } 44073e9753d6SMatthew G. Knepley if (locA) { 44083e9753d6SMatthew G. Knepley PetscInt subp; 44093e9753d6SMatthew G. Knepley 44109566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 44119566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 44123e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 44139566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 44143e9753d6SMatthew G. Knepley } 44153e9753d6SMatthew G. Knepley } 44169566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numFaces * totDim)); 44173e9753d6SMatthew G. Knepley { 44183e9753d6SMatthew G. Knepley PetscFE fe; 44193e9753d6SMatthew G. Knepley PetscInt Nb; 44203e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 44213e9753d6SMatthew G. Knepley /* Conforming batches */ 44223e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 44233e9753d6SMatthew G. Knepley /* Remainder */ 44243e9753d6SMatthew G. Knepley PetscInt Nr, offset; 44253e9753d6SMatthew G. Knepley 44269566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 44279566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 44289566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 44293e9753d6SMatthew G. Knepley /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */ 44303e9753d6SMatthew G. Knepley blockSize = Nb; 44313e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 44329566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 44333e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 44343e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 44353e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 44363e9753d6SMatthew G. Knepley offset = numFaces - Nr; 44379566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 44389566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 44399566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 44409566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 44419566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, &elemVec[offset * totDim])); 44429566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 44433e9753d6SMatthew G. Knepley } 44443e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 44453e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 44463e9753d6SMatthew G. Knepley 44479566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face * totDim])); 44489566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 44499566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face * totDim], ADD_ALL_VALUES)); 44503e9753d6SMatthew G. Knepley } 44519566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 44529566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 44539566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 44549566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 44559566063dSJacob Faibussowitsch PetscCall(PetscFree4(u, u_t, elemVec, a)); 44563e9753d6SMatthew G. Knepley } 44570c290148SMatthew G. Knepley end: 44589566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 44599566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexA)); 44603e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 44613e9753d6SMatthew G. Knepley } 44623e9753d6SMatthew G. Knepley 4463d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF) 4464d71ae5a4SJacob Faibussowitsch { 44653e9753d6SMatthew G. Knepley DMField coordField; 44663e9753d6SMatthew G. Knepley DMLabel depthLabel; 44673e9753d6SMatthew G. Knepley IS facetIS; 44683e9753d6SMatthew G. Knepley PetscInt dim; 44693e9753d6SMatthew G. Knepley 44703e9753d6SMatthew G. Knepley PetscFunctionBegin; 44719566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 44729566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 44739566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 44749566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 44759566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 44769566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 44773e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 44783e9753d6SMatthew G. Knepley } 44793e9753d6SMatthew G. Knepley 4480d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4481d71ae5a4SJacob Faibussowitsch { 44823e9753d6SMatthew G. Knepley PetscDS prob; 44833e9753d6SMatthew G. Knepley PetscInt numBd, bd; 44843e9753d6SMatthew G. Knepley DMField coordField = NULL; 44853e9753d6SMatthew G. Knepley IS facetIS = NULL; 44863e9753d6SMatthew G. Knepley DMLabel depthLabel; 44873e9753d6SMatthew G. Knepley PetscInt dim; 44883e9753d6SMatthew G. Knepley 44893e9753d6SMatthew G. Knepley PetscFunctionBegin; 44909566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 44919566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 44929566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 44939566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 44949566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 44953e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 449645480ffeSMatthew G. Knepley PetscWeakForm wf; 44973e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 44983e9753d6SMatthew G. Knepley DMLabel label; 44993e9753d6SMatthew G. Knepley const PetscInt *values; 45000c290148SMatthew G. Knepley PetscInt field, numValues, v; 45013e9753d6SMatthew G. Knepley PetscObject obj; 45023e9753d6SMatthew G. Knepley PetscClassId id; 45030c290148SMatthew G. Knepley PetscFormKey key; 45043e9753d6SMatthew G. Knepley 45059566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL)); 45063d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 45079566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 45089566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 45093d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 45103e9753d6SMatthew G. Knepley if (!facetIS) { 45113e9753d6SMatthew G. Knepley DMLabel depthLabel; 45123e9753d6SMatthew G. Knepley PetscInt dim; 45133e9753d6SMatthew G. Knepley 45149566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 45159566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 45169566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 45173e9753d6SMatthew G. Knepley } 45189566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 45190c290148SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 45200c290148SMatthew G. Knepley key.label = label; 45210c290148SMatthew G. Knepley key.value = values[v]; 45220c290148SMatthew G. Knepley key.field = field; 45230c290148SMatthew G. Knepley key.part = 0; 45249566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 45250c290148SMatthew G. Knepley } 45263e9753d6SMatthew G. Knepley } 45279566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 45283e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 45293e9753d6SMatthew G. Knepley } 45303e9753d6SMatthew G. Knepley 4531d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4532d71ae5a4SJacob Faibussowitsch { 45333e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 45343e9753d6SMatthew G. Knepley const char *name = "Residual"; 45353e9753d6SMatthew G. Knepley DM dmAux = NULL; 45363e9753d6SMatthew G. Knepley DM dmGrad = NULL; 45373e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 45386528b96dSMatthew G. Knepley PetscDS ds = NULL; 45396528b96dSMatthew G. Knepley PetscDS dsAux = NULL; 45403e9753d6SMatthew G. Knepley PetscSection section = NULL; 45413e9753d6SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 45423e9753d6SMatthew G. Knepley PetscBool useFVM = PETSC_FALSE; 45433e9753d6SMatthew G. Knepley PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 45443e9753d6SMatthew G. Knepley PetscFV fvm = NULL; 45453e9753d6SMatthew G. Knepley PetscFVCellGeom *cgeomFVM = NULL; 45463e9753d6SMatthew G. Knepley PetscFVFaceGeom *fgeomFVM = NULL; 45473e9753d6SMatthew G. Knepley DMField coordField = NULL; 45483e9753d6SMatthew G. Knepley Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL; 45493e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t, *a, *uL, *uR; 45503e9753d6SMatthew G. Knepley IS chunkIS; 45513e9753d6SMatthew G. Knepley const PetscInt *cells; 45523e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 45533e9753d6SMatthew G. Knepley PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd; 45543e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 45553e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 45563e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 45573e9753d6SMatthew G. Knepley 45583e9753d6SMatthew G. Knepley PetscFunctionBegin; 4559e04ae0b4SMatthew G. Knepley if (!cellIS) PetscFunctionReturn(0); 45609566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 45613e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 45623e9753d6SMatthew G. Knepley /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */ 45633e9753d6SMatthew G. Knepley /* FEM+FVM */ 45649566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 45659566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 45663e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 45679566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 45689566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 45699566063dSJacob Faibussowitsch PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds)); 45709566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 45719566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 45729566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 45733e9753d6SMatthew G. Knepley if (locA) { 45743e9753d6SMatthew G. Knepley PetscInt subcell; 45759566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 45761059d808SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell)); 45779566063dSJacob Faibussowitsch PetscCall(DMGetCellDS(dmAux, subcell, &dsAux)); 45789566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 45793e9753d6SMatthew G. Knepley } 45803e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 45813e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 45823e9753d6SMatthew G. Knepley PetscObject obj; 45833e9753d6SMatthew G. Knepley PetscClassId id; 45843e9753d6SMatthew G. Knepley PetscBool fimp; 45853e9753d6SMatthew G. Knepley 45869566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 45873e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 45889566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 45899566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 4590ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 45919371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 45929371c9d4SSatish Balay useFVM = PETSC_TRUE; 45939371c9d4SSatish Balay fvm = (PetscFV)obj; 45949371c9d4SSatish Balay } 45953e9753d6SMatthew G. Knepley } 45963e9753d6SMatthew G. Knepley if (useFEM) { 45979566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 45989566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 45993e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 46009566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 460148a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 46023e9753d6SMatthew G. Knepley } else { 46039566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 46043e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 46053e9753d6SMatthew G. Knepley PetscObject obj; 46063e9753d6SMatthew G. Knepley PetscClassId id; 46073e9753d6SMatthew G. Knepley PetscBool fimp; 46083e9753d6SMatthew G. Knepley 46099566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 46103e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 46119566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 46129566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 46133e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 46143e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 46153e9753d6SMatthew G. Knepley 46169566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 46179566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 46189566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 46193e9753d6SMatthew G. Knepley } 46203e9753d6SMatthew G. Knepley } 46213e9753d6SMatthew G. Knepley } 46223e9753d6SMatthew G. Knepley } 46233e9753d6SMatthew G. Knepley if (useFVM) { 46249566063dSJacob Faibussowitsch PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 46259566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometryFVM, (const PetscScalar **)&fgeomFVM)); 46269566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 46273e9753d6SMatthew G. Knepley /* Reconstruct and limit cell gradients */ 46289566063dSJacob Faibussowitsch PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad)); 46293e9753d6SMatthew G. Knepley if (dmGrad) { 46309566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 46319566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmGrad, &grad)); 46329566063dSJacob Faibussowitsch PetscCall(DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 46333e9753d6SMatthew G. Knepley /* Communicate gradient values */ 46349566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 46359566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 46369566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 46379566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 46383e9753d6SMatthew G. Knepley } 46393e9753d6SMatthew G. Knepley /* Handle non-essential (e.g. outflow) boundary values */ 46409566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad)); 46413e9753d6SMatthew G. Knepley } 46423e9753d6SMatthew G. Knepley /* Loop over chunks */ 46439566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 46443e9753d6SMatthew G. Knepley numCells = cEnd - cStart; 46453e9753d6SMatthew G. Knepley numChunks = 1; 46463e9753d6SMatthew G. Knepley cellChunkSize = numCells / numChunks; 46473e9753d6SMatthew G. Knepley faceChunkSize = (fEnd - fStart) / numChunks; 46483e9753d6SMatthew G. Knepley numChunks = PetscMin(1, numCells); 46493e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 46503e9753d6SMatthew G. Knepley PetscScalar *elemVec, *fluxL, *fluxR; 46513e9753d6SMatthew G. Knepley PetscReal *vol; 46523e9753d6SMatthew G. Knepley PetscFVFaceGeom *fgeom; 46533e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 46543e9753d6SMatthew G. Knepley PetscInt fS = fStart + chunk * faceChunkSize, fE = PetscMin(fS + faceChunkSize, fEnd), numFaces = 0, face; 46553e9753d6SMatthew G. Knepley 46563e9753d6SMatthew G. Knepley /* Extract field coefficients */ 46573e9753d6SMatthew G. Knepley if (useFEM) { 46589566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 46599566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 46609566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 46619566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 46623e9753d6SMatthew G. Knepley } 46633e9753d6SMatthew G. Knepley if (useFVM) { 46649566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 46659566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 46669566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 46679566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 46689566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxL, numFaces * totDim)); 46699566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxR, numFaces * totDim)); 46703e9753d6SMatthew G. Knepley } 46713e9753d6SMatthew G. Knepley /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */ 46723e9753d6SMatthew G. Knepley /* Loop over fields */ 46733e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 46743e9753d6SMatthew G. Knepley PetscObject obj; 46753e9753d6SMatthew G. Knepley PetscClassId id; 46763e9753d6SMatthew G. Knepley PetscBool fimp; 46773e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 46783e9753d6SMatthew G. Knepley 46796528b96dSMatthew G. Knepley key.field = f; 46809566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 46813e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 46829566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 46839566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 46843e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 46853e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 46863e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 46873e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 46883e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 46893e9753d6SMatthew G. Knepley PetscInt Nq, Nb; 46903e9753d6SMatthew G. Knepley 46919566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 46929566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 46939566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 46943e9753d6SMatthew G. Knepley blockSize = Nb; 46953e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 46969566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 46973e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 46983e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 46993e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 47003e9753d6SMatthew G. Knepley offset = numCells - Nr; 47013e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 47023e9753d6SMatthew G. Knepley /* For FV, I think we use a P0 basis and the cell coefficients (for subdivided cells, we can tweak the basis tabulation to be the indicator function) */ 47039566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 47049566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec)); 47059566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 47069566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux, &a[offset * totDimAux], t, &elemVec[offset * totDim])); 47079566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 47083e9753d6SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 47093e9753d6SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 47103e9753d6SMatthew G. Knepley 47113e9753d6SMatthew G. Knepley Ne = numFaces; 47123e9753d6SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 47133e9753d6SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 47149566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 471563a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 47163e9753d6SMatthew G. Knepley } 47173e9753d6SMatthew G. Knepley /* Loop over domain */ 47183e9753d6SMatthew G. Knepley if (useFEM) { 47193e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 47203e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 47213e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 47223e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 47233e9753d6SMatthew G. Knepley 47249566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 47253e9753d6SMatthew G. Knepley if (ghostLabel) { 47263e9753d6SMatthew G. Knepley PetscInt ghostVal; 47273e9753d6SMatthew G. Knepley 47289566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 47293e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 47303e9753d6SMatthew G. Knepley } 47319566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 47323e9753d6SMatthew G. Knepley } 47333e9753d6SMatthew G. Knepley } 47343e9753d6SMatthew G. Knepley if (useFVM) { 47353e9753d6SMatthew G. Knepley PetscScalar *fa; 47363e9753d6SMatthew G. Knepley PetscInt iface; 47373e9753d6SMatthew G. Knepley 47389566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 47393e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 47403e9753d6SMatthew G. Knepley PetscFV fv; 47413e9753d6SMatthew G. Knepley PetscObject obj; 47423e9753d6SMatthew G. Knepley PetscClassId id; 47433e9753d6SMatthew G. Knepley PetscInt foff, pdim; 47443e9753d6SMatthew G. Knepley 47459566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 47469566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(ds, f, &foff)); 47479566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 47483e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 47493e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 47509566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 47513e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 47523e9753d6SMatthew G. Knepley for (face = fS, iface = 0; face < fE; ++face) { 47533e9753d6SMatthew G. Knepley const PetscInt *scells; 47543e9753d6SMatthew G. Knepley PetscScalar *fL = NULL, *fR = NULL; 47553e9753d6SMatthew G. Knepley PetscInt ghost, d, nsupp, nchild; 47563e9753d6SMatthew G. Knepley 47579566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 47589566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 47599566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 47603e9753d6SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 47619566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &scells)); 47629566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[0], &ghost)); 47639566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL)); 47649566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[1], &ghost)); 47659566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR)); 47663e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) { 47673e9753d6SMatthew G. Knepley if (fL) fL[d] -= fluxL[iface * totDim + foff + d]; 47683e9753d6SMatthew G. Knepley if (fR) fR[d] += fluxR[iface * totDim + foff + d]; 47693e9753d6SMatthew G. Knepley } 47703e9753d6SMatthew G. Knepley ++iface; 47713e9753d6SMatthew G. Knepley } 47723e9753d6SMatthew G. Knepley } 47739566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 47743e9753d6SMatthew G. Knepley } 47753e9753d6SMatthew G. Knepley /* Handle time derivative */ 47763e9753d6SMatthew G. Knepley if (locX_t) { 47773e9753d6SMatthew G. Knepley PetscScalar *x_t, *fa; 47783e9753d6SMatthew G. Knepley 47799566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 47809566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 47813e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 47823e9753d6SMatthew G. Knepley PetscFV fv; 47833e9753d6SMatthew G. Knepley PetscObject obj; 47843e9753d6SMatthew G. Knepley PetscClassId id; 47853e9753d6SMatthew G. Knepley PetscInt pdim, d; 47863e9753d6SMatthew G. Knepley 47879566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 47889566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 47893e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 47903e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 47919566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 47923e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 47933e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 47943e9753d6SMatthew G. Knepley PetscScalar *u_t, *r; 47953e9753d6SMatthew G. Knepley 47963e9753d6SMatthew G. Knepley if (ghostLabel) { 47973e9753d6SMatthew G. Knepley PetscInt ghostVal; 47983e9753d6SMatthew G. Knepley 47999566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 48003e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 48013e9753d6SMatthew G. Knepley } 48029566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 48039566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 48043e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 48053e9753d6SMatthew G. Knepley } 48063e9753d6SMatthew G. Knepley } 48079566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 48089566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 48093e9753d6SMatthew G. Knepley } 48103e9753d6SMatthew G. Knepley if (useFEM) { 48119566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 48129566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 48133e9753d6SMatthew G. Knepley } 48143e9753d6SMatthew G. Knepley if (useFVM) { 48159566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 48169566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 48179566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 48189566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 48199566063dSJacob Faibussowitsch if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 48203e9753d6SMatthew G. Knepley } 48213e9753d6SMatthew G. Knepley } 48229566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 48239566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 48243e9753d6SMatthew G. Knepley 48253e9753d6SMatthew G. Knepley if (useFEM) { 48269566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user)); 48273e9753d6SMatthew G. Knepley 48283e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 48299566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 48309566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 48313e9753d6SMatthew G. Knepley } else { 48323e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 48339566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 48349566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 48353e9753d6SMatthew G. Knepley } 48369566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 48373e9753d6SMatthew G. Knepley } 48383e9753d6SMatthew G. Knepley } 48393e9753d6SMatthew G. Knepley 48403e9753d6SMatthew G. Knepley /* FEM */ 48413e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 48423e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 48433e9753d6SMatthew G. Knepley /* 3: Handle boundary values */ 48443e9753d6SMatthew G. Knepley /* 4: Loop over domain */ 48453e9753d6SMatthew G. Knepley /* Extract coefficients */ 48463e9753d6SMatthew G. Knepley /* Loop over fields */ 48473e9753d6SMatthew G. Knepley /* Set tiling for FE*/ 48483e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec */ 48493e9753d6SMatthew G. Knepley /* Loop over subdomain */ 48503e9753d6SMatthew G. Knepley /* Loop over quad points */ 48513e9753d6SMatthew G. Knepley /* Transform coords to real space */ 48523e9753d6SMatthew G. Knepley /* Evaluate field and aux fields at point */ 48533e9753d6SMatthew G. Knepley /* Evaluate residual at point */ 48543e9753d6SMatthew G. Knepley /* Transform residual to real space */ 48553e9753d6SMatthew G. Knepley /* Add residual to elemVec */ 48563e9753d6SMatthew G. Knepley /* Loop over domain */ 48573e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 48583e9753d6SMatthew G. Knepley 48593e9753d6SMatthew G. Knepley /* FVM */ 48603e9753d6SMatthew G. Knepley /* Get geometric data */ 48613e9753d6SMatthew G. Knepley /* If using gradients */ 48623e9753d6SMatthew G. Knepley /* Compute gradient data */ 48633e9753d6SMatthew G. Knepley /* Loop over domain faces */ 48643e9753d6SMatthew G. Knepley /* Count computational faces */ 48653e9753d6SMatthew G. Knepley /* Reconstruct cell gradient */ 48663e9753d6SMatthew G. Knepley /* Loop over domain cells */ 48673e9753d6SMatthew G. Knepley /* Limit cell gradients */ 48683e9753d6SMatthew G. Knepley /* Handle boundary values */ 48693e9753d6SMatthew G. Knepley /* Loop over domain faces */ 48703e9753d6SMatthew G. Knepley /* Read out field, centroid, normal, volume for each side of face */ 48713e9753d6SMatthew G. Knepley /* Riemann solve over faces */ 48723e9753d6SMatthew G. Knepley /* Loop over domain faces */ 48733e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 48743e9753d6SMatthew G. Knepley /* TODO Change printFEM to printDisc here */ 48753e9753d6SMatthew G. Knepley if (mesh->printFEM) { 48763e9753d6SMatthew G. Knepley Vec locFbc; 48773e9753d6SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 48783e9753d6SMatthew G. Knepley PetscScalar *zeroes; 48793e9753d6SMatthew G. Knepley 48809566063dSJacob Faibussowitsch PetscCall(VecDuplicate(locF, &locFbc)); 48819566063dSJacob Faibussowitsch PetscCall(VecCopy(locF, locFbc)); 48829566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 48839566063dSJacob Faibussowitsch PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 48849566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(maxDof, &zeroes)); 488548a46eb9SPierre Jolivet for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 48869566063dSJacob Faibussowitsch PetscCall(PetscFree(zeroes)); 48879566063dSJacob Faibussowitsch PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 48889566063dSJacob Faibussowitsch PetscCall(VecDestroy(&locFbc)); 48893e9753d6SMatthew G. Knepley } 48909566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 48913e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 48923e9753d6SMatthew G. Knepley } 48933e9753d6SMatthew G. Knepley 48946528b96dSMatthew G. Knepley /* 48956528b96dSMatthew G. Knepley 1) Allow multiple kernels for BdResidual for hybrid DS 48966528b96dSMatthew G. Knepley 48976528b96dSMatthew G. Knepley DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux 48986528b96dSMatthew G. Knepley 48996528b96dSMatthew G. Knepley DONE 3) Change DMGetCellFields() to get different aux data a[] for each side 49006528b96dSMatthew G. Knepley - I think I just need to replace a[] with the closure from each face 49016528b96dSMatthew G. Knepley 49026528b96dSMatthew G. Knepley 4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before 49036528b96dSMatthew G. Knepley */ 4904d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4905d71ae5a4SJacob Faibussowitsch { 49063e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 49073e9753d6SMatthew G. Knepley const char *name = "Hybrid Residual"; 490804c51a94SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 49093e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 49106528b96dSMatthew G. Knepley PetscDS ds = NULL; 49116528b96dSMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 491204c51a94SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 4913b2ab40e6SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 49143e9753d6SMatthew G. Knepley PetscSection section = NULL; 49153e9753d6SMatthew G. Knepley DMField coordField = NULL; 4916b2ab40e6SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 49173e9753d6SMatthew G. Knepley PetscScalar *elemVec; 49183e9753d6SMatthew G. Knepley IS chunkIS; 49193e9753d6SMatthew G. Knepley const PetscInt *cells; 49203e9753d6SMatthew G. Knepley PetscInt *faces; 49213e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 49226528b96dSMatthew G. Knepley PetscInt Nf, f, totDim, totDimAux[3], numChunks, cellChunkSize, chunk; 49233e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 49243e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 49253e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 49263e9753d6SMatthew G. Knepley 49273e9753d6SMatthew G. Knepley PetscFunctionBegin; 49285fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 49295fedec97SMatthew G. Knepley const char *name; 49309566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 493163a3b9bcSJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Form keys for each side of a cohesive surface must be different (%s, %" PetscInt_FMT ", %" PetscInt_FMT ")", name, key[0].value, key[0].part); 49325fedec97SMatthew G. Knepley } 49339566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 49343e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 49353e9753d6SMatthew G. Knepley /* FEM */ 49369566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 49379566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 49383e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 49399566063dSJacob Faibussowitsch PetscCall(DMGetSection(dm, §ion)); 49409566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 49411059d808SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds)); 49429566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 49439566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 49449566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 494504c51a94SMatthew G. Knepley if (locA[2]) { 49461059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 49471059d808SMatthew G. Knepley 49489566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 49491059d808SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2])); 49509566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 49516528b96dSMatthew G. Knepley { 49526528b96dSMatthew G. Knepley const PetscInt *cone; 49536528b96dSMatthew G. Knepley PetscInt c; 49546528b96dSMatthew G. Knepley 49551059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 49566528b96dSMatthew G. Knepley for (c = 0; c < 2; ++c) { 49576528b96dSMatthew G. Knepley const PetscInt *support; 49586528b96dSMatthew G. Knepley PetscInt ssize, s; 49596528b96dSMatthew G. Knepley 49609566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 49619566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 49621059d808SMatthew G. Knepley PetscCheck(ssize == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " from cell %" PetscInt_FMT " has support size %" PetscInt_FMT " != 2", cone[c], cellStart, ssize); 49631059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 49641059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 49651059d808SMatthew G. Knepley else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[c], cellStart); 49669566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 4967c75bfeddSPierre Jolivet PetscCheck(locA[c], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must have auxiliary vector for (%p, %" PetscInt_FMT ", %" PetscInt_FMT ")", (void *)key[c].label, key[c].value, key[c].part); 49689566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 4969ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 49709566063dSJacob Faibussowitsch PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c])); 49719566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 49726528b96dSMatthew G. Knepley } 49736528b96dSMatthew G. Knepley } 49743e9753d6SMatthew G. Knepley } 49753e9753d6SMatthew G. Knepley /* 2: Setup geometric data */ 49769566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 49779566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 49783e9753d6SMatthew G. Knepley if (maxDegree > 1) { 49799566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 49803e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 49813e9753d6SMatthew G. Knepley PetscFE fe; 49823e9753d6SMatthew G. Knepley 49839566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 49843e9753d6SMatthew G. Knepley if (fe) { 49859566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 49869566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 49873e9753d6SMatthew G. Knepley } 49883e9753d6SMatthew G. Knepley } 49893e9753d6SMatthew G. Knepley } 49903e9753d6SMatthew G. Knepley /* Loop over chunks */ 49913e9753d6SMatthew G. Knepley cellChunkSize = numCells; 49923e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 4993a4158a15SMatthew G. Knepley PetscCall(PetscCalloc1(1 * cellChunkSize, &faces)); 4994a4158a15SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 49953e9753d6SMatthew G. Knepley /* Extract field coefficients */ 49963e9753d6SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 49979566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 49989566063dSJacob Faibussowitsch PetscCall(DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a)); 49999566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVec)); 50003e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 50013e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 50023e9753d6SMatthew G. Knepley 50039566063dSJacob Faibussowitsch PetscCall(PetscMemzero(elemVec, cellChunkSize * totDim * sizeof(PetscScalar))); 50043e9753d6SMatthew G. Knepley /* Get faces */ 50053e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 50063e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 50073e9753d6SMatthew G. Knepley const PetscInt *cone; 50089566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 5009a4158a15SMatthew G. Knepley faces[0 * cellChunkSize + (c - cS)] = cone[0]; 5010a4158a15SMatthew G. Knepley /*faces[1*cellChunkSize+(c-cS)] = cone[1];*/ 50113e9753d6SMatthew G. Knepley } 5012a4158a15SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 1 * cellChunkSize, faces, PETSC_USE_POINTER)); 50133e9753d6SMatthew G. Knepley /* Get geometric data */ 50143e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 50159566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 50169566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 50173e9753d6SMatthew G. Knepley } else { 50183e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 50199566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 50203e9753d6SMatthew G. Knepley } 50213e9753d6SMatthew G. Knepley } 50223e9753d6SMatthew G. Knepley /* Loop over fields */ 50233e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 50243e9753d6SMatthew G. Knepley PetscFE fe; 50253e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 5026148442b3SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 50273e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 50283e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 50295fedec97SMatthew G. Knepley PetscBool isCohesiveField; 50303e9753d6SMatthew G. Knepley 50319566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 50323e9753d6SMatthew G. Knepley if (!fe) continue; 50339566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 50349566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 50359566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 50363e9753d6SMatthew G. Knepley blockSize = Nb; 50373e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 50389566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 50393e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 50403e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 50413e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 50423e9753d6SMatthew G. Knepley offset = numCells - Nr; 50439566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 50449566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &remGeom)); 50459566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 50465fedec97SMatthew G. Knepley chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE; 50476528b96dSMatthew G. Knepley key[0].field = f; 50486528b96dSMatthew G. Knepley key[1].field = f; 50495fedec97SMatthew G. Knepley key[2].field = f; 50509566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridResidual(ds, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVec)); 50519566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridResidual(ds, key[0], 0, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, &elemVec[offset * totDim])); 50529566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridResidual(ds, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVec)); 50539566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridResidual(ds, key[1], 1, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, &elemVec[offset * totDim])); 50549566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridResidual(ds, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVec)); 50559566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridResidual(ds, key[2], 2, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, &elemVec[offset * totDim])); 50569566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 50579566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 50583e9753d6SMatthew G. Knepley } 50593e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 50603e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 50613e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 50623e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 50633e9753d6SMatthew G. Knepley 50649566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 50653e9753d6SMatthew G. Knepley if (ghostLabel) { 50663e9753d6SMatthew G. Knepley PetscInt ghostVal; 50673e9753d6SMatthew G. Knepley 50689566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 50693e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 50703e9753d6SMatthew G. Knepley } 50719566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 50723e9753d6SMatthew G. Knepley } 50733e9753d6SMatthew G. Knepley } 50749566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 50759566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a)); 50769566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 50779566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 50789566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 50799566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 50803e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 50819566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 50829566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 50833e9753d6SMatthew G. Knepley } else { 50843e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 50859566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 50869566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 50873e9753d6SMatthew G. Knepley } 50889566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 50893e9753d6SMatthew G. Knepley } 50909566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 50913e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 50923e9753d6SMatthew G. Knepley } 50933e9753d6SMatthew G. Knepley 5094d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdJacobian_Single_Internal(DM dm, PetscReal t, PetscWeakForm wf, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt fieldI, Vec locX, Vec locX_t, PetscReal X_tShift, Mat Jac, Mat JacP, DMField coordField, IS facetIS) 5095d71ae5a4SJacob Faibussowitsch { 50963e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 50973e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL, tdm; 50983e9753d6SMatthew G. Knepley DMEnclosureType encAux; 50993e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 51003e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 5101e432b41dSStefano Zampini PetscSection globalSection; 51023e9753d6SMatthew G. Knepley Vec locA = NULL, tv; 51033e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL; 51043e9753d6SMatthew G. Knepley PetscInt v; 51053e9753d6SMatthew G. Knepley PetscInt Nf, totDim, totDimAux = 0; 5106e432b41dSStefano Zampini PetscBool transform; 51073e9753d6SMatthew G. Knepley 51083e9753d6SMatthew G. Knepley PetscFunctionBegin; 51099566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 51109566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 51119566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 51129566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 51139566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 51149566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 51159566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 51169566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 51179566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA)); 51183e9753d6SMatthew G. Knepley if (locA) { 51193e9753d6SMatthew G. Knepley DM dmAux; 51203e9753d6SMatthew G. Knepley 51219566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 51229566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 51239566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 51249566063dSJacob Faibussowitsch PetscCall(DMGetDS(plexA, &probAux)); 51259566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 51269566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 51273e9753d6SMatthew G. Knepley } 51283e9753d6SMatthew G. Knepley 51299566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 51303e9753d6SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 51313e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 51323e9753d6SMatthew G. Knepley PetscInt maxDegree; 51333e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 51343e9753d6SMatthew G. Knepley IS pointIS; 51353e9753d6SMatthew G. Knepley const PetscInt *points; 513606ad1575SMatthew G. Knepley PetscFormKey key; 51373e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 51383e9753d6SMatthew G. Knepley 513945480ffeSMatthew G. Knepley key.label = label; 514045480ffeSMatthew G. Knepley key.value = values[v]; 514106ad1575SMatthew G. Knepley key.part = 0; 51429566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 51433e9753d6SMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 51443e9753d6SMatthew G. Knepley { 51453e9753d6SMatthew G. Knepley IS isectIS; 51463e9753d6SMatthew G. Knepley 51473e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */ 51489566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 51499566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 51503e9753d6SMatthew G. Knepley pointIS = isectIS; 51513e9753d6SMatthew G. Knepley } 51529566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 51539566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 51549566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim * totDim, &elemMat, locA ? numFaces * totDimAux : 0, &a)); 51559566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 515648a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 51573e9753d6SMatthew G. Knepley if (!qGeom) { 51583e9753d6SMatthew G. Knepley PetscFE fe; 51593e9753d6SMatthew G. Knepley 51609566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 51619566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 51629566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 51633e9753d6SMatthew G. Knepley } 51649566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 51659566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 51663e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 5167f15274beSMatthew Knepley const PetscInt point = points[face], *support; 51683e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 5169f15274beSMatthew Knepley PetscInt i; 51703e9753d6SMatthew G. Knepley 51719566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 51729566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 51733e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 51749566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 51753e9753d6SMatthew G. Knepley if (locX_t) { 51769566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 51773e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 51789566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 51793e9753d6SMatthew G. Knepley } 51803e9753d6SMatthew G. Knepley if (locA) { 51813e9753d6SMatthew G. Knepley PetscInt subp; 51829566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 51839566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 51843e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 51859566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 51863e9753d6SMatthew G. Knepley } 51873e9753d6SMatthew G. Knepley } 51889566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, numFaces * totDim * totDim)); 51893e9753d6SMatthew G. Knepley { 51903e9753d6SMatthew G. Knepley PetscFE fe; 51913e9753d6SMatthew G. Knepley PetscInt Nb; 51923e9753d6SMatthew G. Knepley /* Conforming batches */ 51933e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 51943e9753d6SMatthew G. Knepley /* Remainder */ 51953e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 51963e9753d6SMatthew G. Knepley PetscInt fieldJ, Nr, offset; 51973e9753d6SMatthew G. Knepley 51989566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 51999566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 52009566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 52013e9753d6SMatthew G. Knepley blockSize = Nb; 52023e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 52039566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 52043e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 52053e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 52063e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 52073e9753d6SMatthew G. Knepley offset = numFaces - Nr; 52089566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 52093e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 521045480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 52119566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 52123e9753d6SMatthew G. Knepley } 52139566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 52143e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 521545480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 52169566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMat[offset * totDim * totDim])); 52173e9753d6SMatthew G. Knepley } 52189566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 52193e9753d6SMatthew G. Knepley } 52203e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 52213e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 52223e9753d6SMatthew G. Knepley 52233e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 52249566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 52259566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face * totDim * totDim])); 52269566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim])); 52279566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, support[0], &elemMat[face * totDim * totDim], ADD_VALUES)); 52283e9753d6SMatthew G. Knepley } 52299566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 52309566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 52319566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 52329566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 52339566063dSJacob Faibussowitsch PetscCall(PetscFree4(u, u_t, elemMat, a)); 52343e9753d6SMatthew G. Knepley } 52359566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 52369566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 52373e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 52383e9753d6SMatthew G. Knepley } 52393e9753d6SMatthew G. Knepley 5240d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdJacobianSingle(DM dm, PetscReal t, PetscWeakForm wf, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, PetscReal X_tShift, Mat Jac, Mat JacP) 5241d71ae5a4SJacob Faibussowitsch { 52423e9753d6SMatthew G. Knepley DMField coordField; 52433e9753d6SMatthew G. Knepley DMLabel depthLabel; 52443e9753d6SMatthew G. Knepley IS facetIS; 52453e9753d6SMatthew G. Knepley PetscInt dim; 52463e9753d6SMatthew G. Knepley 52473e9753d6SMatthew G. Knepley PetscFunctionBegin; 52489566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 52499566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 52509566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 52519566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 52529566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 52539566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 52543e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 52553e9753d6SMatthew G. Knepley } 52563e9753d6SMatthew G. Knepley 5257d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user) 5258d71ae5a4SJacob Faibussowitsch { 52593e9753d6SMatthew G. Knepley PetscDS prob; 52603e9753d6SMatthew G. Knepley PetscInt dim, numBd, bd; 52613e9753d6SMatthew G. Knepley DMLabel depthLabel; 52623e9753d6SMatthew G. Knepley DMField coordField = NULL; 52633e9753d6SMatthew G. Knepley IS facetIS; 52643e9753d6SMatthew G. Knepley 52653e9753d6SMatthew G. Knepley PetscFunctionBegin; 52669566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 52679566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 52689566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 52699566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 52709566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 52719566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 52723e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 527345480ffeSMatthew G. Knepley PetscWeakForm wf; 52743e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 52753e9753d6SMatthew G. Knepley DMLabel label; 52763e9753d6SMatthew G. Knepley const PetscInt *values; 52773e9753d6SMatthew G. Knepley PetscInt fieldI, numValues; 52783e9753d6SMatthew G. Knepley PetscObject obj; 52793e9753d6SMatthew G. Knepley PetscClassId id; 52803e9753d6SMatthew G. Knepley 52819566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL)); 52823d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 52839566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj)); 52849566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 52853d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 52869566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 52873e9753d6SMatthew G. Knepley } 52889566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 52893e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 52903e9753d6SMatthew G. Knepley } 52913e9753d6SMatthew G. Knepley 5292d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeJacobian_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *user) 5293d71ae5a4SJacob Faibussowitsch { 52943e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 52953e9753d6SMatthew G. Knepley const char *name = "Jacobian"; 52969a2a23afSMatthew G. Knepley DM dmAux = NULL, plex, tdm; 52973e9753d6SMatthew G. Knepley DMEnclosureType encAux; 52983e9753d6SMatthew G. Knepley Vec A, tv; 52993e9753d6SMatthew G. Knepley DMField coordField; 53003e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 5301e432b41dSStefano Zampini PetscSection section, globalSection, sectionAux; 53023e9753d6SMatthew G. Knepley PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL; 53033e9753d6SMatthew G. Knepley const PetscInt *cells; 53043e9753d6SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 530528351e22SJed Brown PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 5306e04ae0b4SMatthew G. Knepley PetscBool hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform; 53073e9753d6SMatthew G. Knepley 53083e9753d6SMatthew G. Knepley PetscFunctionBegin; 5309e04ae0b4SMatthew G. Knepley if (!cellIS) goto end; 53109566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 53119566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 53129566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 53139566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 53149566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 53159566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 53169566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 53179566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 53189566063dSJacob Faibussowitsch PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob)); 53199566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 53209566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 53219566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 53229566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 53233e9753d6SMatthew G. Knepley /* user passed in the same matrix, avoid double contributions and 53243e9753d6SMatthew G. Knepley only assemble the Jacobian */ 53253e9753d6SMatthew G. Knepley if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE; 53269566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 53273e9753d6SMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 53289566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 53299a2a23afSMatthew G. Knepley if (A) { 53309566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 53319566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 53329566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plex)); 53339566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plex, §ionAux)); 53349566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 53359566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 53363e9753d6SMatthew G. Knepley } 53379566063dSJacob Faibussowitsch PetscCall(PetscMalloc5(numCells * totDim, &u, X_t ? numCells * totDim : 0, &u_t, hasJac ? numCells * totDim * totDim : 0, &elemMat, hasPrec ? numCells * totDim * totDim : 0, &elemMatP, hasDyn ? numCells * totDim * totDim : 0, &elemMatD)); 53389566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 53399566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 53403e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 53413e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 53423e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 53433e9753d6SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 53443e9753d6SMatthew G. Knepley PetscInt i; 53453e9753d6SMatthew G. Knepley 53469566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 53473e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 53489566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 53493e9753d6SMatthew G. Knepley if (X_t) { 53509566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 53513e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 53529566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 53533e9753d6SMatthew G. Knepley } 53543e9753d6SMatthew G. Knepley if (dmAux) { 53553e9753d6SMatthew G. Knepley PetscInt subcell; 53569566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 53579566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x)); 53583e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 53599566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x)); 53603e9753d6SMatthew G. Knepley } 53613e9753d6SMatthew G. Knepley } 53629566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 53639566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells * totDim * totDim)); 53649566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 53653e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 53663e9753d6SMatthew G. Knepley PetscClassId id; 53673e9753d6SMatthew G. Knepley PetscFE fe; 53683e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 53693e9753d6SMatthew G. Knepley PetscInt Nb; 53703e9753d6SMatthew G. Knepley /* Conforming batches */ 53713e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 53723e9753d6SMatthew G. Knepley /* Remainder */ 53733e9753d6SMatthew G. Knepley PetscInt Nr, offset, Nq; 53743e9753d6SMatthew G. Knepley PetscInt maxDegree; 53753e9753d6SMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 53763e9753d6SMatthew G. Knepley 53779566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 53789566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 53799371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 53809371c9d4SSatish Balay hasFV = PETSC_TRUE; 53819371c9d4SSatish Balay continue; 53829371c9d4SSatish Balay } 53839566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 53849566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 53859566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 538648a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 53873e9753d6SMatthew G. Knepley if (!qGeom) { 53889566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 53899566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 53903e9753d6SMatthew G. Knepley } 53919566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 53929566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 53933e9753d6SMatthew G. Knepley blockSize = Nb; 53943e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 53959566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 53963e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 53973e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 53983e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 53993e9753d6SMatthew G. Knepley offset = numCells - Nr; 54009566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 54019566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 54023e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 54036528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 54043e9753d6SMatthew G. Knepley if (hasJac) { 54059566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 54069566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMat[offset * totDim * totDim])); 54073e9753d6SMatthew G. Knepley } 54083e9753d6SMatthew G. Knepley if (hasPrec) { 54099566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP)); 54109566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMatP[offset * totDim * totDim])); 54113e9753d6SMatthew G. Knepley } 54123e9753d6SMatthew G. Knepley if (hasDyn) { 54139566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 54149566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMatD[offset * totDim * totDim])); 54153e9753d6SMatthew G. Knepley } 54163e9753d6SMatthew G. Knepley } 54179566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 54189566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 54199566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 54209566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 54213e9753d6SMatthew G. Knepley } 54223e9753d6SMatthew G. Knepley /* Add contribution from X_t */ 54239371c9d4SSatish Balay if (hasDyn) { 54249371c9d4SSatish Balay for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 54259371c9d4SSatish Balay } 54263e9753d6SMatthew G. Knepley if (hasFV) { 54273e9753d6SMatthew G. Knepley PetscClassId id; 54283e9753d6SMatthew G. Knepley PetscFV fv; 54293e9753d6SMatthew G. Knepley PetscInt offsetI, NcI, NbI = 1, fc, f; 54303e9753d6SMatthew G. Knepley 54313e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 54329566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 54339566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI)); 54349566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fv, &id)); 54353e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 54363e9753d6SMatthew G. Knepley /* Put in the identity */ 54379566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcI)); 54383e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 54393e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 54403e9753d6SMatthew G. Knepley const PetscInt eOffset = cind * totDim * totDim; 54413e9753d6SMatthew G. Knepley for (fc = 0; fc < NcI; ++fc) { 54423e9753d6SMatthew G. Knepley for (f = 0; f < NbI; ++f) { 54433e9753d6SMatthew G. Knepley const PetscInt i = offsetI + f * NcI + fc; 54443e9753d6SMatthew G. Knepley if (hasPrec) { 5445ad540459SPierre Jolivet if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 54463e9753d6SMatthew G. Knepley elemMatP[eOffset + i * totDim + i] = 1.0; 54479371c9d4SSatish Balay } else { 54489371c9d4SSatish Balay elemMat[eOffset + i * totDim + i] = 1.0; 54499371c9d4SSatish Balay } 54503e9753d6SMatthew G. Knepley } 54513e9753d6SMatthew G. Knepley } 54523e9753d6SMatthew G. Knepley } 54533e9753d6SMatthew G. Knepley } 54543e9753d6SMatthew G. Knepley /* No allocated space for FV stuff, so ignore the zero entries */ 54559566063dSJacob Faibussowitsch PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); 54563e9753d6SMatthew G. Knepley } 54573e9753d6SMatthew G. Knepley /* Insert values into matrix */ 54583e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 54593e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 54603e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 54613e9753d6SMatthew G. Knepley 54623e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 54639566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * totDim])); 54643e9753d6SMatthew G. Knepley if (hasPrec) { 54653e9753d6SMatthew G. Knepley if (hasJac) { 54669566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 54679566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 54683e9753d6SMatthew G. Knepley } 54699566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim])); 54709566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES)); 54713e9753d6SMatthew G. Knepley } else { 54723e9753d6SMatthew G. Knepley if (hasJac) { 54739566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 54749566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 54753e9753d6SMatthew G. Knepley } 54763e9753d6SMatthew G. Knepley } 54773e9753d6SMatthew G. Knepley } 54789566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 54799566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 54809566063dSJacob Faibussowitsch PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, elemMatD)); 54813e9753d6SMatthew G. Knepley if (dmAux) { 54829566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 54839566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 54843e9753d6SMatthew G. Knepley } 54853e9753d6SMatthew G. Knepley /* Compute boundary integrals */ 54869566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user)); 54873e9753d6SMatthew G. Knepley /* Assemble matrix */ 54889371c9d4SSatish Balay end : { 5489e04ae0b4SMatthew G. Knepley PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp; 5490e04ae0b4SMatthew G. Knepley 5491e04ae0b4SMatthew G. Knepley PetscCallMPI(MPI_Allreduce(&assOp, &gassOp, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 54923e9753d6SMatthew G. Knepley if (hasJac && hasPrec) { 54939566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 54949566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 54953e9753d6SMatthew G. Knepley } 5496e04ae0b4SMatthew G. Knepley } 54979566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 54989566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 54999566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 55003e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 55013e9753d6SMatthew G. Knepley } 55023e9753d6SMatthew G. Knepley 5503d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeJacobian_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, void *user) 5504d71ae5a4SJacob Faibussowitsch { 55053e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 55063e9753d6SMatthew G. Knepley const char *name = "Hybrid Jacobian"; 5507148442b3SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 5508148442b3SMatthew G. Knepley DMLabel ghostLabel = NULL; 55093e9753d6SMatthew G. Knepley DM plex = NULL; 55103e9753d6SMatthew G. Knepley DM plexA = NULL; 5511148442b3SMatthew G. Knepley PetscDS ds = NULL; 5512148442b3SMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 5513148442b3SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 55143e9753d6SMatthew G. Knepley PetscSection section = NULL; 5515148442b3SMatthew G. Knepley PetscSection sectionAux[3] = {NULL, NULL, NULL}; 55163e9753d6SMatthew G. Knepley DMField coordField = NULL; 5517148442b3SMatthew G. Knepley PetscScalar *u = NULL, *u_t, *a[3]; 55183e9753d6SMatthew G. Knepley PetscScalar *elemMat, *elemMatP; 5519e432b41dSStefano Zampini PetscSection globalSection; 55203e9753d6SMatthew G. Knepley IS chunkIS; 55213e9753d6SMatthew G. Knepley const PetscInt *cells; 55223e9753d6SMatthew G. Knepley PetscInt *faces; 55233e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 5524148442b3SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, totDim, totDimAux[3], numChunks, cellChunkSize, chunk; 55253e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 55263e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 55273e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 5528e432b41dSStefano Zampini PetscBool hasBdJac, hasBdPrec; 55293e9753d6SMatthew G. Knepley 55303e9753d6SMatthew G. Knepley PetscFunctionBegin; 55315fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 55325fedec97SMatthew G. Knepley const char *name; 55339566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 553463a3b9bcSJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Form keys for each side of a cohesive surface must be different (%s, %" PetscInt_FMT ", %" PetscInt_FMT ")", name, key[0].value, key[0].part); 55355fedec97SMatthew G. Knepley } 55369566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 55379566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 55389566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 55399566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 55409566063dSJacob Faibussowitsch PetscCall(DMGetSection(dm, §ion)); 55419566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 55429566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 55431059d808SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds)); 55449566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 55459566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 55469566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac)); 55479566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec)); 55489566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 5549148442b3SMatthew G. Knepley if (locA[2]) { 55501059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 55511059d808SMatthew G. Knepley 55529566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 55539566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA)); 55549566063dSJacob Faibussowitsch PetscCall(DMGetSection(dmAux[2], §ionAux[2])); 55551059d808SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2])); 55569566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 5557148442b3SMatthew G. Knepley { 5558148442b3SMatthew G. Knepley const PetscInt *cone; 5559148442b3SMatthew G. Knepley PetscInt c; 5560148442b3SMatthew G. Knepley 55611059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 5562148442b3SMatthew G. Knepley for (c = 0; c < 2; ++c) { 5563148442b3SMatthew G. Knepley const PetscInt *support; 5564148442b3SMatthew G. Knepley PetscInt ssize, s; 5565148442b3SMatthew G. Knepley 55669566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 55679566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 55681059d808SMatthew G. Knepley PetscCheck(ssize == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " from cell %" PetscInt_FMT " has support size %" PetscInt_FMT " != 2", cone[c], cellStart, ssize); 55691059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 55701059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 55711059d808SMatthew G. Knepley else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[c], cellStart); 55729566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 55739566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5574ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 55759566063dSJacob Faibussowitsch PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c])); 55769566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 5577148442b3SMatthew G. Knepley } 5578148442b3SMatthew G. Knepley } 55793e9753d6SMatthew G. Knepley } 55809566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 55819566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 55823e9753d6SMatthew G. Knepley if (maxDegree > 1) { 55833e9753d6SMatthew G. Knepley PetscInt f; 55849566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 55853e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 55863e9753d6SMatthew G. Knepley PetscFE fe; 55873e9753d6SMatthew G. Knepley 55889566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 55893e9753d6SMatthew G. Knepley if (fe) { 55909566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 55919566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 55923e9753d6SMatthew G. Knepley } 55933e9753d6SMatthew G. Knepley } 55943e9753d6SMatthew G. Knepley } 55953e9753d6SMatthew G. Knepley cellChunkSize = numCells; 55963e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 5597a4158a15SMatthew G. Knepley PetscCall(PetscCalloc1(1 * cellChunkSize, &faces)); 5598a4158a15SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 55999566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 56009566063dSJacob Faibussowitsch PetscCall(DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a)); 56019566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMat)); 56029566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatP)); 56033e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 56043e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 56053e9753d6SMatthew G. Knepley 56069566063dSJacob Faibussowitsch if (hasBdJac) PetscCall(PetscMemzero(elemMat, numCells * totDim * totDim * sizeof(PetscScalar))); 56079566063dSJacob Faibussowitsch if (hasBdPrec) PetscCall(PetscMemzero(elemMatP, numCells * totDim * totDim * sizeof(PetscScalar))); 56083e9753d6SMatthew G. Knepley /* Get faces */ 56093e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 56103e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 56113e9753d6SMatthew G. Knepley const PetscInt *cone; 56129566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(plex, cell, &cone)); 5613a4158a15SMatthew G. Knepley faces[0 * cellChunkSize + (c - cS)] = cone[0]; 5614a4158a15SMatthew G. Knepley /*faces[2*cellChunkSize+(c-cS)] = cone[1];*/ 56153e9753d6SMatthew G. Knepley } 5616a4158a15SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 1 * cellChunkSize, faces, PETSC_USE_POINTER)); 56173e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 56189566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 56199566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 56203e9753d6SMatthew G. Knepley } else { 56213e9753d6SMatthew G. Knepley PetscInt f; 56223e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 56239566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 56243e9753d6SMatthew G. Knepley } 56253e9753d6SMatthew G. Knepley } 56263e9753d6SMatthew G. Knepley 56273e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 56283e9753d6SMatthew G. Knepley PetscFE feI; 56293e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI]; 56303e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 56313e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI]; 56323e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 56335fedec97SMatthew G. Knepley PetscBool isCohesiveField; 56343e9753d6SMatthew G. Knepley 56359566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI)); 56363e9753d6SMatthew G. Knepley if (!feI) continue; 56379566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches)); 56389566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 56399566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feI, &Nb)); 56403e9753d6SMatthew G. Knepley blockSize = Nb; 56413e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 56429566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches)); 56433e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 56443e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 56453e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 56463e9753d6SMatthew G. Knepley offset = numCells - Nr; 56479566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 56489566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &remGeom)); 56499566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField)); 56503e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 56513e9753d6SMatthew G. Knepley PetscFE feJ; 56523e9753d6SMatthew G. Knepley 56539566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ)); 56543e9753d6SMatthew G. Knepley if (!feJ) continue; 5655148442b3SMatthew G. Knepley key[0].field = fieldI * Nf + fieldJ; 5656148442b3SMatthew G. Knepley key[1].field = fieldI * Nf + fieldJ; 56575fedec97SMatthew G. Knepley key[2].field = fieldI * Nf + fieldJ; 5658148442b3SMatthew G. Knepley if (hasBdJac) { 56599566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMat)); 56609566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[0], 0, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMat[offset * totDim * totDim])); 56619566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMat)); 56629566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[1], 1, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMat[offset * totDim * totDim])); 5663148442b3SMatthew G. Knepley } 5664148442b3SMatthew G. Knepley if (hasBdPrec) { 56659566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatP)); 56669566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[0], 0, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatP[offset * totDim * totDim])); 56679566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatP)); 56689566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[1], 1, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatP[offset * totDim * totDim])); 5669148442b3SMatthew G. Knepley } 56705fedec97SMatthew G. Knepley if (hasBdJac) { 56719566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMat)); 56729566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[2], 2, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMat[offset * totDim * totDim])); 5673148442b3SMatthew G. Knepley } 56745fedec97SMatthew G. Knepley if (hasBdPrec) { 56759566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatP)); 56769566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[2], 2, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatP[offset * totDim * totDim])); 56773e9753d6SMatthew G. Knepley } 56783e9753d6SMatthew G. Knepley } 56799566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 56809566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 56813e9753d6SMatthew G. Knepley } 56823e9753d6SMatthew G. Knepley /* Insert values into matrix */ 56833e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 56843e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 56853e9753d6SMatthew G. Knepley const PetscInt cind = c - cS; 56863e9753d6SMatthew G. Knepley 56873e9753d6SMatthew G. Knepley if (hasBdPrec) { 56883e9753d6SMatthew G. Knepley if (hasBdJac) { 56899566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 56909566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosure(plex, section, globalSection, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 56913e9753d6SMatthew G. Knepley } 56929566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim])); 56939566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES)); 56943e9753d6SMatthew G. Knepley } else if (hasBdJac) { 56959566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 56969566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 56973e9753d6SMatthew G. Knepley } 56983e9753d6SMatthew G. Knepley } 56993e9753d6SMatthew G. Knepley } 57009566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 57019566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a)); 57029566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMat)); 57039566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatP)); 57049566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 57059566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 57069566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 57073e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 57089566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 57099566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 57103e9753d6SMatthew G. Knepley } else { 57113e9753d6SMatthew G. Knepley PetscInt f; 57123e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 57139566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 57149566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 57153e9753d6SMatthew G. Knepley } 57169566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 57173e9753d6SMatthew G. Knepley } 57189566063dSJacob Faibussowitsch if (dmAux[2]) PetscCall(DMDestroy(&plexA)); 57199566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 57209566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 57213e9753d6SMatthew G. Knepley PetscFunctionReturn(0); 57223e9753d6SMatthew G. Knepley } 57238e3a2eefSMatthew G. Knepley 57248e3a2eefSMatthew G. Knepley /* 57258e3a2eefSMatthew G. Knepley DMPlexComputeJacobian_Action_Internal - Form the local portion of the Jacobian action Z = J(X) Y at the local solution X using pointwise functions specified by the user. 57268e3a2eefSMatthew G. Knepley 57278e3a2eefSMatthew G. Knepley Input Parameters: 57288e3a2eefSMatthew G. Knepley + dm - The mesh 57298e3a2eefSMatthew G. Knepley . key - The PetscWeakFormKey indcating where integration should happen 573006ad1575SMatthew G. Knepley . cellIS - The cells to integrate over 57318e3a2eefSMatthew G. Knepley . t - The time 57328e3a2eefSMatthew G. Knepley . X_tShift - The multiplier for the Jacobian with repsect to X_t 57338e3a2eefSMatthew G. Knepley . X - Local solution vector 57348e3a2eefSMatthew G. Knepley . X_t - Time-derivative of the local solution vector 57358e3a2eefSMatthew G. Knepley . Y - Local input vector 573606ad1575SMatthew G. Knepley - user - the user context 57378e3a2eefSMatthew G. Knepley 57388e3a2eefSMatthew G. Knepley Output Parameter: 57398e3a2eefSMatthew G. Knepley . Z - Local output vector 57408e3a2eefSMatthew G. Knepley 57418e3a2eefSMatthew G. Knepley Note: 57428e3a2eefSMatthew G. Knepley We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 57438e3a2eefSMatthew G. Knepley like a GPU, or vectorize on a multicore machine. 57448e3a2eefSMatthew G. Knepley */ 5745d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeJacobian_Action_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Vec Y, Vec Z, void *user) 5746d71ae5a4SJacob Faibussowitsch { 57478e3a2eefSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 57488e3a2eefSMatthew G. Knepley const char *name = "Jacobian"; 57498e3a2eefSMatthew G. Knepley DM dmAux = NULL, plex, plexAux = NULL; 57508e3a2eefSMatthew G. Knepley DMEnclosureType encAux; 57518e3a2eefSMatthew G. Knepley Vec A; 57528e3a2eefSMatthew G. Knepley DMField coordField; 57538e3a2eefSMatthew G. Knepley PetscDS prob, probAux = NULL; 57548e3a2eefSMatthew G. Knepley PetscQuadrature quad; 57558e3a2eefSMatthew G. Knepley PetscSection section, globalSection, sectionAux; 57568e3a2eefSMatthew G. Knepley PetscScalar *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z; 57578e3a2eefSMatthew G. Knepley const PetscInt *cells; 57588e3a2eefSMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 57598e3a2eefSMatthew G. Knepley PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 57608e3a2eefSMatthew G. Knepley PetscBool hasDyn; 57618e3a2eefSMatthew G. Knepley 57628e3a2eefSMatthew G. Knepley PetscFunctionBegin; 57639566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 57649566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 57658e3a2eefSMatthew G. Knepley if (!cellIS) { 57668e3a2eefSMatthew G. Knepley PetscInt depth; 57678e3a2eefSMatthew G. Knepley 57689566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepth(plex, &depth)); 57699566063dSJacob Faibussowitsch PetscCall(DMGetStratumIS(plex, "dim", depth, &cellIS)); 57709566063dSJacob Faibussowitsch if (!cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &cellIS)); 57718e3a2eefSMatthew G. Knepley } else { 57729566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)cellIS)); 57738e3a2eefSMatthew G. Knepley } 57749566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 57759566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 57769566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 57779566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 57789566063dSJacob Faibussowitsch PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob)); 57799566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 57809566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 57819566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 57828e3a2eefSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 57839566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 57848e3a2eefSMatthew G. Knepley if (A) { 57859566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 57869566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 57879566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexAux)); 57889566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexAux, §ionAux)); 57899566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 57909566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 57918e3a2eefSMatthew G. Knepley } 57929566063dSJacob Faibussowitsch PetscCall(VecSet(Z, 0.0)); 57939566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(numCells * totDim, &u, X_t ? numCells * totDim : 0, &u_t, numCells * totDim * totDim, &elemMat, hasDyn ? numCells * totDim * totDim : 0, &elemMatD, numCells * totDim, &y, totDim, &z)); 57949566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 57959566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 57968e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 57978e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 57988e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 57998e3a2eefSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 58008e3a2eefSMatthew G. Knepley PetscInt i; 58018e3a2eefSMatthew G. Knepley 58029566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X, cell, NULL, &x)); 58038e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 58049566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x)); 58058e3a2eefSMatthew G. Knepley if (X_t) { 58069566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t)); 58078e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 58089566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t)); 58098e3a2eefSMatthew G. Knepley } 58108e3a2eefSMatthew G. Knepley if (dmAux) { 58118e3a2eefSMatthew G. Knepley PetscInt subcell; 58129566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 58139566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 58148e3a2eefSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 58159566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 58168e3a2eefSMatthew G. Knepley } 58179566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x)); 58188e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) y[cind * totDim + i] = x[i]; 58199566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x)); 58208e3a2eefSMatthew G. Knepley } 58219566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 58229566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 58238e3a2eefSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 58248e3a2eefSMatthew G. Knepley PetscFE fe; 58258e3a2eefSMatthew G. Knepley PetscInt Nb; 58268e3a2eefSMatthew G. Knepley /* Conforming batches */ 58278e3a2eefSMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 58288e3a2eefSMatthew G. Knepley /* Remainder */ 58298e3a2eefSMatthew G. Knepley PetscInt Nr, offset, Nq; 58308e3a2eefSMatthew G. Knepley PetscQuadrature qGeom = NULL; 58318e3a2eefSMatthew G. Knepley PetscInt maxDegree; 58328e3a2eefSMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 58338e3a2eefSMatthew G. Knepley 58349566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 58359566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 58369566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 58379566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 58389566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 58399566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 58408e3a2eefSMatthew G. Knepley if (!qGeom) { 58419566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 58429566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 58438e3a2eefSMatthew G. Knepley } 58449566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 58459566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 58468e3a2eefSMatthew G. Knepley blockSize = Nb; 58478e3a2eefSMatthew G. Knepley batchSize = numBlocks * blockSize; 58489566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 58498e3a2eefSMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 58508e3a2eefSMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 58518e3a2eefSMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 58528e3a2eefSMatthew G. Knepley offset = numCells - Nr; 58539566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 58549566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 58558e3a2eefSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 58568e3a2eefSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 58579566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 58589566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMat[offset * totDim * totDim])); 58598e3a2eefSMatthew G. Knepley if (hasDyn) { 58609566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 58619566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMatD[offset * totDim * totDim])); 58628e3a2eefSMatthew G. Knepley } 58638e3a2eefSMatthew G. Knepley } 58649566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 58659566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 58669566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 58679566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 58688e3a2eefSMatthew G. Knepley } 58698e3a2eefSMatthew G. Knepley if (hasDyn) { 58708e3a2eefSMatthew G. Knepley for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 58718e3a2eefSMatthew G. Knepley } 58728e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 58738e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 58748e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 58758e3a2eefSMatthew G. Knepley const PetscBLASInt M = totDim, one = 1; 58768e3a2eefSMatthew G. Knepley const PetscScalar a = 1.0, b = 0.0; 58778e3a2eefSMatthew G. Knepley 5878792fecdfSBarry Smith PetscCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind * totDim * totDim], &M, &y[cind * totDim], &one, &b, z, &one)); 58798e3a2eefSMatthew G. Knepley if (mesh->printFEM > 1) { 58809566063dSJacob Faibussowitsch PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 58819566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind * totDim])); 58829566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Z", totDim, z)); 58838e3a2eefSMatthew G. Knepley } 58849566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES)); 58858e3a2eefSMatthew G. Knepley } 58869566063dSJacob Faibussowitsch PetscCall(PetscFree6(u, u_t, elemMat, elemMatD, y, z)); 58878e3a2eefSMatthew G. Knepley if (mesh->printFEM) { 58889566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n")); 58899566063dSJacob Faibussowitsch PetscCall(VecView(Z, NULL)); 58908e3a2eefSMatthew G. Knepley } 58911059d808SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 58929566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 58939566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 58949566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexAux)); 58959566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 58969566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 58978e3a2eefSMatthew G. Knepley PetscFunctionReturn(0); 58988e3a2eefSMatthew G. Knepley } 5899