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 } 463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 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)); 553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 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 } 783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 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; 853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 869b6f715bSMatthew G. Knepley } 879b6f715bSMatthew G. Knepley 8846fa42a0SMatthew G. Knepley /*@ 8946fa42a0SMatthew G. Knepley DMPlexGetScale - Get the scale for the specified fundamental unit 9046fa42a0SMatthew G. Knepley 9120f4b53cSBarry Smith Not Collective 9246fa42a0SMatthew G. Knepley 934165533cSJose E. Roman Input Parameters: 94a1cb98faSBarry 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 1021cc06b55SBarry Smith .seealso: [](ch_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); 1104f572ea9SToby Isaac PetscAssertPointer(scale, 3); 111cb1e1211SMatthew G Knepley *scale = mesh->scale[unit]; 1123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 113cb1e1211SMatthew G Knepley } 114cb1e1211SMatthew G Knepley 11546fa42a0SMatthew G. Knepley /*@ 11646fa42a0SMatthew G. Knepley DMPlexSetScale - Set the scale for the specified fundamental unit 11746fa42a0SMatthew G. Knepley 11820f4b53cSBarry Smith Not Collective 11946fa42a0SMatthew G. Knepley 1204165533cSJose E. Roman Input Parameters: 121a1cb98faSBarry 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 1271cc06b55SBarry Smith .seealso: [](ch_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; 1363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 137cb1e1211SMatthew G Knepley } 138cb1e1211SMatthew G Knepley 139d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetUseCeed_Plex(DM dm, PetscBool *useCeed) 140d2b2dc1eSMatthew G. Knepley { 141d2b2dc1eSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 142d2b2dc1eSMatthew G. Knepley 143d2b2dc1eSMatthew G. Knepley PetscFunctionBegin; 144d2b2dc1eSMatthew G. Knepley *useCeed = mesh->useCeed; 145d2b2dc1eSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 146d2b2dc1eSMatthew G. Knepley } 147d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexSetUseCeed_Plex(DM dm, PetscBool useCeed) 148d2b2dc1eSMatthew G. Knepley { 149d2b2dc1eSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 150d2b2dc1eSMatthew G. Knepley 151d2b2dc1eSMatthew G. Knepley PetscFunctionBegin; 152d2b2dc1eSMatthew G. Knepley mesh->useCeed = useCeed; 153d2b2dc1eSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 154d2b2dc1eSMatthew G. Knepley } 155d2b2dc1eSMatthew G. Knepley 156d2b2dc1eSMatthew G. Knepley /*@ 157d2b2dc1eSMatthew G. Knepley DMPlexGetUseCeed - Get flag for using the LibCEED backend 158d2b2dc1eSMatthew G. Knepley 159d2b2dc1eSMatthew G. Knepley Not collective 160d2b2dc1eSMatthew G. Knepley 161d2b2dc1eSMatthew G. Knepley Input Parameter: 162d2b2dc1eSMatthew G. Knepley . dm - The `DM` 163d2b2dc1eSMatthew G. Knepley 164d2b2dc1eSMatthew G. Knepley Output Parameter: 165d2b2dc1eSMatthew G. Knepley . useCeed - The flag 166d2b2dc1eSMatthew G. Knepley 167d2b2dc1eSMatthew G. Knepley Level: intermediate 168d2b2dc1eSMatthew G. Knepley 169d2b2dc1eSMatthew G. Knepley .seealso: `DMPlexSetUseCeed()` 170d2b2dc1eSMatthew G. Knepley @*/ 171d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetUseCeed(DM dm, PetscBool *useCeed) 172d2b2dc1eSMatthew G. Knepley { 173d2b2dc1eSMatthew G. Knepley PetscFunctionBegin; 174d2b2dc1eSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 175d2b2dc1eSMatthew G. Knepley PetscAssertPointer(useCeed, 2); 176d2b2dc1eSMatthew G. Knepley *useCeed = PETSC_FALSE; 177d2b2dc1eSMatthew G. Knepley PetscTryMethod(dm, "DMPlexGetUseCeed_C", (DM, PetscBool *), (dm, useCeed)); 178d2b2dc1eSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 179d2b2dc1eSMatthew G. Knepley } 180d2b2dc1eSMatthew G. Knepley 181d2b2dc1eSMatthew G. Knepley /*@ 182d2b2dc1eSMatthew G. Knepley DMPlexSetUseCeed - Set flag for using the LibCEED backend 183d2b2dc1eSMatthew G. Knepley 184d2b2dc1eSMatthew G. Knepley Not collective 185d2b2dc1eSMatthew G. Knepley 186d2b2dc1eSMatthew G. Knepley Input Parameters: 187d2b2dc1eSMatthew G. Knepley + dm - The `DM` 188d2b2dc1eSMatthew G. Knepley - useCeed - The flag 189d2b2dc1eSMatthew G. Knepley 190d2b2dc1eSMatthew G. Knepley Level: intermediate 191d2b2dc1eSMatthew G. Knepley 192*fe8e7dddSPierre Jolivet .seealso: `DMPlexGetUseCeed()` 193d2b2dc1eSMatthew G. Knepley @*/ 194d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexSetUseCeed(DM dm, PetscBool useCeed) 195d2b2dc1eSMatthew G. Knepley { 196d2b2dc1eSMatthew G. Knepley PetscFunctionBegin; 197d2b2dc1eSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 198d2b2dc1eSMatthew G. Knepley PetscValidLogicalCollectiveBool(dm, useCeed, 2); 199d2b2dc1eSMatthew G. Knepley PetscUseMethod(dm, "DMPlexSetUseCeed_C", (DM, PetscBool), (dm, useCeed)); 200d2b2dc1eSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 201d2b2dc1eSMatthew G. Knepley } 202d2b2dc1eSMatthew G. Knepley 203e8e188d2SZach Atkins /*@ 204e8e188d2SZach Atkins DMPlexGetUseMatClosurePermutation - Get flag for using a closure permutation for matrix insertion 205e8e188d2SZach Atkins 206e8e188d2SZach Atkins Not collective 207e8e188d2SZach Atkins 208e8e188d2SZach Atkins Input Parameter: 209e8e188d2SZach Atkins . dm - The `DM` 210e8e188d2SZach Atkins 211e8e188d2SZach Atkins Output Parameter: 212e8e188d2SZach Atkins . useClPerm - The flag 213e8e188d2SZach Atkins 214e8e188d2SZach Atkins Level: intermediate 215e8e188d2SZach Atkins 216e8e188d2SZach Atkins .seealso: `DMPlexSetUseMatClosurePermutation()` 217e8e188d2SZach Atkins @*/ 218e8e188d2SZach Atkins PetscErrorCode DMPlexGetUseMatClosurePermutation(DM dm, PetscBool *useClPerm) 219e8e188d2SZach Atkins { 220e8e188d2SZach Atkins DM_Plex *mesh = (DM_Plex *)dm->data; 221e8e188d2SZach Atkins 222e8e188d2SZach Atkins PetscFunctionBegin; 223e8e188d2SZach Atkins PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 224e8e188d2SZach Atkins PetscAssertPointer(useClPerm, 2); 225e8e188d2SZach Atkins *useClPerm = mesh->useMatClPerm; 226e8e188d2SZach Atkins PetscFunctionReturn(PETSC_SUCCESS); 227e8e188d2SZach Atkins } 228e8e188d2SZach Atkins 229e8e188d2SZach Atkins /*@ 230e8e188d2SZach Atkins DMPlexSetUseMatClosurePermutation - Set flag for using a closure permutation for matrix insertion 231e8e188d2SZach Atkins 232e8e188d2SZach Atkins Not collective 233e8e188d2SZach Atkins 234e8e188d2SZach Atkins Input Parameters: 235e8e188d2SZach Atkins + dm - The `DM` 236e8e188d2SZach Atkins - useClPerm - The flag 237e8e188d2SZach Atkins 238e8e188d2SZach Atkins Level: intermediate 239e8e188d2SZach Atkins 240e8e188d2SZach Atkins .seealso: `DMPlexGetUseMatClosurePermutation()` 241e8e188d2SZach Atkins @*/ 242e8e188d2SZach Atkins PetscErrorCode DMPlexSetUseMatClosurePermutation(DM dm, PetscBool useClPerm) 243e8e188d2SZach Atkins { 244e8e188d2SZach Atkins DM_Plex *mesh = (DM_Plex *)dm->data; 245e8e188d2SZach Atkins 246e8e188d2SZach Atkins PetscFunctionBegin; 247e8e188d2SZach Atkins PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 248e8e188d2SZach Atkins PetscValidLogicalCollectiveBool(dm, useClPerm, 2); 249e8e188d2SZach Atkins mesh->useMatClPerm = useClPerm; 250e8e188d2SZach Atkins PetscFunctionReturn(PETSC_SUCCESS); 251e8e188d2SZach Atkins } 252e8e188d2SZach Atkins 253d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nc, PetscScalar *mode, void *ctx) 254d71ae5a4SJacob Faibussowitsch { 2559371c9d4SSatish Balay const PetscInt eps[3][3][3] = { 2569371c9d4SSatish Balay {{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, 2579371c9d4SSatish Balay {{0, 0, -1}, {0, 0, 0}, {1, 0, 0} }, 2589371c9d4SSatish Balay {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0} } 2599371c9d4SSatish Balay }; 260026175e5SToby Isaac PetscInt *ctxInt = (PetscInt *)ctx; 261ad917190SMatthew G. Knepley PetscInt dim2 = ctxInt[0]; 262026175e5SToby Isaac PetscInt d = ctxInt[1]; 263026175e5SToby Isaac PetscInt i, j, k = dim > 2 ? d - dim : d; 264026175e5SToby Isaac 265ad917190SMatthew G. Knepley PetscFunctionBegin; 26663a3b9bcSJacob Faibussowitsch PetscCheck(dim == dim2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %" PetscInt_FMT " does not match context dimension %" PetscInt_FMT, dim, dim2); 267026175e5SToby Isaac for (i = 0; i < dim; i++) mode[i] = 0.; 268026175e5SToby Isaac if (d < dim) { 26912adca46SMatthew G. Knepley mode[d] = 1.; /* Translation along axis d */ 270ad917190SMatthew G. Knepley } else { 271026175e5SToby Isaac for (i = 0; i < dim; i++) { 2729371c9d4SSatish Balay for (j = 0; j < dim; j++) { mode[j] += eps[i][j][k] * X[i]; /* Rotation about axis d */ } 273026175e5SToby Isaac } 274026175e5SToby Isaac } 2753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 276026175e5SToby Isaac } 277026175e5SToby Isaac 278cc4e42d9SMartin Diehl /*@ 27912adca46SMatthew G. Knepley DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation 280cb1e1211SMatthew G Knepley 28120f4b53cSBarry Smith Collective 282cb1e1211SMatthew G Knepley 2834165533cSJose E. Roman Input Parameters: 284a1cb98faSBarry Smith + dm - the `DM` 28556cf3b9cSMatthew G. Knepley - field - The field number for the rigid body space, or 0 for the default 286cb1e1211SMatthew G Knepley 2874165533cSJose E. Roman Output Parameter: 288cb1e1211SMatthew G Knepley . sp - the null space 289cb1e1211SMatthew G Knepley 290cb1e1211SMatthew G Knepley Level: advanced 291cb1e1211SMatthew G Knepley 292a1cb98faSBarry Smith Note: 293a1cb98faSBarry Smith This is necessary to provide a suitable coarse space for algebraic multigrid 294a1cb98faSBarry Smith 2951cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`, `PCGAMG` 296cb1e1211SMatthew G Knepley @*/ 297d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscInt field, MatNullSpace *sp) 298d71ae5a4SJacob Faibussowitsch { 29956cf3b9cSMatthew G. Knepley PetscErrorCode (**func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *); 300cb1e1211SMatthew G Knepley MPI_Comm comm; 301026175e5SToby Isaac Vec mode[6]; 302026175e5SToby Isaac PetscSection section, globalSection; 30356cf3b9cSMatthew G. Knepley PetscInt dim, dimEmbed, Nf, n, m, mmin, d, i, j; 304db14aad5SMatthew G. Knepley void **ctxs; 305cb1e1211SMatthew G Knepley 306cb1e1211SMatthew G Knepley PetscFunctionBegin; 3079566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3089566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 3099566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 3109566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 31163a3b9bcSJacob Faibussowitsch PetscCheck(!Nf || !(field < 0 || field >= Nf), comm, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", field, Nf); 31256cf3b9cSMatthew G. Knepley if (dim == 1 && Nf < 2) { 3139566063dSJacob Faibussowitsch PetscCall(MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp)); 3143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 315cb1e1211SMatthew G Knepley } 3169566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 3179566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 3189566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n)); 319db14aad5SMatthew G. Knepley PetscCall(PetscCalloc2(Nf, &func, Nf, &ctxs)); 320b247467aSMatthew G. Knepley m = (dim * (dim + 1)) / 2; 3219566063dSJacob Faibussowitsch PetscCall(VecCreate(comm, &mode[0])); 3229566063dSJacob Faibussowitsch PetscCall(VecSetType(mode[0], dm->vectype)); 3239566063dSJacob Faibussowitsch PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE)); 3249566063dSJacob Faibussowitsch PetscCall(VecSetUp(mode[0])); 3259566063dSJacob Faibussowitsch PetscCall(VecGetSize(mode[0], &n)); 326b247467aSMatthew G. Knepley mmin = PetscMin(m, n); 32756cf3b9cSMatthew G. Knepley func[field] = DMPlexProjectRigidBody_Private; 3289566063dSJacob Faibussowitsch for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i])); 329026175e5SToby Isaac for (d = 0; d < m; d++) { 330330485fdSToby Isaac PetscInt ctx[2]; 331cb1e1211SMatthew G Knepley 332db14aad5SMatthew G. Knepley ctxs[field] = (void *)(&ctx[0]); 3339d8fbdeaSMatthew G. Knepley ctx[0] = dimEmbed; 334330485fdSToby Isaac ctx[1] = d; 335db14aad5SMatthew G. Knepley PetscCall(DMProjectFunction(dm, 0.0, func, ctxs, INSERT_VALUES, mode[d])); 336cb1e1211SMatthew G Knepley } 3373b2202bfSJacob Faibussowitsch /* Orthonormalize system */ 338b50a2c0aSJacob Faibussowitsch for (i = 0; i < mmin; ++i) { 339b77f2eeeSJacob Faibussowitsch PetscScalar dots[6]; 340b50a2c0aSJacob Faibussowitsch 3419566063dSJacob Faibussowitsch PetscCall(VecNormalize(mode[i], NULL)); 3429566063dSJacob Faibussowitsch PetscCall(VecMDot(mode[i], mmin - i - 1, mode + i + 1, dots + i + 1)); 343b50a2c0aSJacob Faibussowitsch for (j = i + 1; j < mmin; ++j) { 344b77f2eeeSJacob Faibussowitsch dots[j] *= -1.0; 3459566063dSJacob Faibussowitsch PetscCall(VecAXPY(mode[j], dots[j], mode[i])); 346b50a2c0aSJacob Faibussowitsch } 347cb1e1211SMatthew G Knepley } 3489566063dSJacob Faibussowitsch PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp)); 3499566063dSJacob Faibussowitsch for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i])); 350db14aad5SMatthew G. Knepley PetscCall(PetscFree2(func, ctxs)); 3513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 352cb1e1211SMatthew G Knepley } 353cb1e1211SMatthew G Knepley 354cc4e42d9SMartin Diehl /*@ 35512adca46SMatthew G. Knepley DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation 35612adca46SMatthew G. Knepley 35720f4b53cSBarry Smith Collective 35812adca46SMatthew G. Knepley 3594165533cSJose E. Roman Input Parameters: 360a1cb98faSBarry Smith + dm - the `DM` 36112adca46SMatthew G. Knepley . nb - The number of bodies 362a1cb98faSBarry Smith . label - The `DMLabel` marking each domain 36312adca46SMatthew G. Knepley . nids - The number of ids per body 36412adca46SMatthew G. Knepley - ids - An array of the label ids in sequence for each domain 36512adca46SMatthew G. Knepley 3664165533cSJose E. Roman Output Parameter: 36712adca46SMatthew G. Knepley . sp - the null space 36812adca46SMatthew G. Knepley 36912adca46SMatthew G. Knepley Level: advanced 37012adca46SMatthew G. Knepley 371a1cb98faSBarry Smith Note: 372a1cb98faSBarry Smith This is necessary to provide a suitable coarse space for algebraic multigrid 373a1cb98faSBarry Smith 3741cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()` 37512adca46SMatthew G. Knepley @*/ 376d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp) 377d71ae5a4SJacob Faibussowitsch { 37812adca46SMatthew G. Knepley MPI_Comm comm; 37912adca46SMatthew G. Knepley PetscSection section, globalSection; 38012adca46SMatthew G. Knepley Vec *mode; 38112adca46SMatthew G. Knepley PetscScalar *dots; 38212adca46SMatthew G. Knepley PetscInt dim, dimEmbed, n, m, b, d, i, j, off; 38312adca46SMatthew G. Knepley 38412adca46SMatthew G. Knepley PetscFunctionBegin; 3859566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3869566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 3879566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 3889566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 3899566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 3909566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n)); 39112adca46SMatthew G. Knepley m = nb * (dim * (dim + 1)) / 2; 3929566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(m, &mode, m, &dots)); 3939566063dSJacob Faibussowitsch PetscCall(VecCreate(comm, &mode[0])); 3949566063dSJacob Faibussowitsch PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE)); 3959566063dSJacob Faibussowitsch PetscCall(VecSetUp(mode[0])); 3969566063dSJacob Faibussowitsch for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i])); 39712adca46SMatthew G. Knepley for (b = 0, off = 0; b < nb; ++b) { 39812adca46SMatthew G. Knepley for (d = 0; d < m / nb; ++d) { 39912adca46SMatthew G. Knepley PetscInt ctx[2]; 40012adca46SMatthew G. Knepley PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private; 40112adca46SMatthew G. Knepley void *voidctx = (void *)(&ctx[0]); 40212adca46SMatthew G. Knepley 40312adca46SMatthew G. Knepley ctx[0] = dimEmbed; 40412adca46SMatthew G. Knepley ctx[1] = d; 4059566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d])); 40612adca46SMatthew G. Knepley off += nids[b]; 40712adca46SMatthew G. Knepley } 40812adca46SMatthew G. Knepley } 4093b2202bfSJacob Faibussowitsch /* Orthonormalize system */ 410606c1a1cSJacob Faibussowitsch for (i = 0; i < m; ++i) { 411b77f2eeeSJacob Faibussowitsch PetscScalar dots[6]; 4125a0e29b9SJacob Faibussowitsch 4139566063dSJacob Faibussowitsch PetscCall(VecNormalize(mode[i], NULL)); 4149566063dSJacob Faibussowitsch PetscCall(VecMDot(mode[i], m - i - 1, mode + i + 1, dots + i + 1)); 4155a0e29b9SJacob Faibussowitsch for (j = i + 1; j < m; ++j) { 416b77f2eeeSJacob Faibussowitsch dots[j] *= -1.0; 4179566063dSJacob Faibussowitsch PetscCall(VecAXPY(mode[j], dots[j], mode[i])); 4185a0e29b9SJacob Faibussowitsch } 41912adca46SMatthew G. Knepley } 4209566063dSJacob Faibussowitsch PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp)); 4219566063dSJacob Faibussowitsch for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i])); 4229566063dSJacob Faibussowitsch PetscCall(PetscFree2(mode, dots)); 4233ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 42412adca46SMatthew G. Knepley } 42512adca46SMatthew G. Knepley 426b29cfa1cSToby Isaac /*@ 427b29cfa1cSToby Isaac DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs 428b29cfa1cSToby Isaac are computed by associating the basis function with one of the mesh points in its transitively-closed support, and 429a4e35b19SJacob Faibussowitsch evaluating the dual space basis of that point. 430b29cfa1cSToby Isaac 431b29cfa1cSToby Isaac Input Parameters: 432a1cb98faSBarry Smith + dm - the `DMPLEX` object 433b29cfa1cSToby Isaac - height - the maximum projection height >= 0 434b29cfa1cSToby Isaac 435b29cfa1cSToby Isaac Level: advanced 436b29cfa1cSToby Isaac 437a4e35b19SJacob Faibussowitsch Notes: 438a4e35b19SJacob Faibussowitsch A basis function is associated with the point in its transitively-closed support whose mesh 439a4e35b19SJacob Faibussowitsch height is highest (w.r.t. DAG height), but not greater than the maximum projection height, 440a4e35b19SJacob Faibussowitsch which is set with this function. By default, the maximum projection height is zero, which 441a4e35b19SJacob Faibussowitsch means that only mesh cells are used to project basis functions. A height of one, for 442a4e35b19SJacob Faibussowitsch example, evaluates a cell-interior basis functions using its cells dual space basis, but all 443a4e35b19SJacob Faibussowitsch other basis functions with the dual space basis of a face. 444a4e35b19SJacob Faibussowitsch 4451cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()` 446b29cfa1cSToby Isaac @*/ 447d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height) 448d71ae5a4SJacob Faibussowitsch { 449b29cfa1cSToby Isaac DM_Plex *plex = (DM_Plex *)dm->data; 450b29cfa1cSToby Isaac 451b29cfa1cSToby Isaac PetscFunctionBegin; 452b29cfa1cSToby Isaac PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 453b29cfa1cSToby Isaac plex->maxProjectionHeight = height; 4543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 455b29cfa1cSToby Isaac } 456b29cfa1cSToby Isaac 457b29cfa1cSToby Isaac /*@ 458b29cfa1cSToby Isaac DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in 459b29cfa1cSToby Isaac DMPlexProjectXXXLocal() functions. 460b29cfa1cSToby Isaac 4612fe279fdSBarry Smith Input Parameter: 462a1cb98faSBarry Smith . dm - the `DMPLEX` object 463b29cfa1cSToby Isaac 4642fe279fdSBarry Smith Output Parameter: 465b29cfa1cSToby Isaac . height - the maximum projection height 466b29cfa1cSToby Isaac 467b29cfa1cSToby Isaac Level: intermediate 468b29cfa1cSToby Isaac 4691cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()` 470b29cfa1cSToby Isaac @*/ 471d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height) 472d71ae5a4SJacob Faibussowitsch { 473b29cfa1cSToby Isaac DM_Plex *plex = (DM_Plex *)dm->data; 474b29cfa1cSToby Isaac 475b29cfa1cSToby Isaac PetscFunctionBegin; 476b29cfa1cSToby Isaac PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 477b29cfa1cSToby Isaac *height = plex->maxProjectionHeight; 4783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 479b29cfa1cSToby Isaac } 480b29cfa1cSToby Isaac 481ca3d3a14SMatthew G. Knepley typedef struct { 482ca3d3a14SMatthew G. Knepley PetscReal alpha; /* The first Euler angle, and in 2D the only one */ 483ca3d3a14SMatthew G. Knepley PetscReal beta; /* The second Euler angle */ 484ca3d3a14SMatthew G. Knepley PetscReal gamma; /* The third Euler angle */ 485ca3d3a14SMatthew G. Knepley PetscInt dim; /* The dimension of R */ 486ca3d3a14SMatthew G. Knepley PetscScalar *R; /* The rotation matrix, transforming a vector in the local basis to the global basis */ 487ca3d3a14SMatthew G. Knepley PetscScalar *RT; /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */ 488ca3d3a14SMatthew G. Knepley } RotCtx; 489ca3d3a14SMatthew G. Knepley 490ca3d3a14SMatthew G. Knepley /* 491ca3d3a14SMatthew G. Knepley Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that 492ca3d3a14SMatthew 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: 493ca3d3a14SMatthew 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. 494ca3d3a14SMatthew 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. 495ca3d3a14SMatthew G. Knepley $ The XYZ system rotates a third time about the z axis by gamma. 496ca3d3a14SMatthew G. Knepley */ 497d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, void *ctx) 498d71ae5a4SJacob Faibussowitsch { 499ca3d3a14SMatthew G. Knepley RotCtx *rc = (RotCtx *)ctx; 500ca3d3a14SMatthew G. Knepley PetscInt dim = rc->dim; 501ca3d3a14SMatthew G. Knepley PetscReal c1, s1, c2, s2, c3, s3; 502ca3d3a14SMatthew G. Knepley 503ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 5049566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(PetscSqr(dim), &rc->R, PetscSqr(dim), &rc->RT)); 505ca3d3a14SMatthew G. Knepley switch (dim) { 506ca3d3a14SMatthew G. Knepley case 2: 5079371c9d4SSatish Balay c1 = PetscCosReal(rc->alpha); 5089371c9d4SSatish Balay s1 = PetscSinReal(rc->alpha); 5099371c9d4SSatish Balay rc->R[0] = c1; 5109371c9d4SSatish Balay rc->R[1] = s1; 5119371c9d4SSatish Balay rc->R[2] = -s1; 5129371c9d4SSatish Balay rc->R[3] = c1; 5139566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim))); 514b458e8f1SJose E. Roman DMPlex_Transpose2D_Internal(rc->RT); 515ca3d3a14SMatthew G. Knepley break; 516ca3d3a14SMatthew G. Knepley case 3: 5179371c9d4SSatish Balay c1 = PetscCosReal(rc->alpha); 5189371c9d4SSatish Balay s1 = PetscSinReal(rc->alpha); 5199371c9d4SSatish Balay c2 = PetscCosReal(rc->beta); 5209371c9d4SSatish Balay s2 = PetscSinReal(rc->beta); 5219371c9d4SSatish Balay c3 = PetscCosReal(rc->gamma); 5229371c9d4SSatish Balay s3 = PetscSinReal(rc->gamma); 5239371c9d4SSatish Balay rc->R[0] = c1 * c3 - c2 * s1 * s3; 5249371c9d4SSatish Balay rc->R[1] = c3 * s1 + c1 * c2 * s3; 5259371c9d4SSatish Balay rc->R[2] = s2 * s3; 5269371c9d4SSatish Balay rc->R[3] = -c1 * s3 - c2 * c3 * s1; 5279371c9d4SSatish Balay rc->R[4] = c1 * c2 * c3 - s1 * s3; 5289371c9d4SSatish Balay rc->R[5] = c3 * s2; 5299371c9d4SSatish Balay rc->R[6] = s1 * s2; 5309371c9d4SSatish Balay rc->R[7] = -c1 * s2; 5319371c9d4SSatish Balay rc->R[8] = c2; 5329566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim))); 533b458e8f1SJose E. Roman DMPlex_Transpose3D_Internal(rc->RT); 534ca3d3a14SMatthew G. Knepley break; 535d71ae5a4SJacob Faibussowitsch default: 536d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim); 537ca3d3a14SMatthew G. Knepley } 5383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 539ca3d3a14SMatthew G. Knepley } 540ca3d3a14SMatthew G. Knepley 541d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, void *ctx) 542d71ae5a4SJacob Faibussowitsch { 543ca3d3a14SMatthew G. Knepley RotCtx *rc = (RotCtx *)ctx; 544ca3d3a14SMatthew G. Knepley 545ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 5469566063dSJacob Faibussowitsch PetscCall(PetscFree2(rc->R, rc->RT)); 5479566063dSJacob Faibussowitsch PetscCall(PetscFree(rc)); 5483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 549ca3d3a14SMatthew G. Knepley } 550ca3d3a14SMatthew G. Knepley 551d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm, const PetscReal x[], PetscBool l2g, const PetscScalar **A, void *ctx) 552d71ae5a4SJacob Faibussowitsch { 553ca3d3a14SMatthew G. Knepley RotCtx *rc = (RotCtx *)ctx; 554ca3d3a14SMatthew G. Knepley 555ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 5564f572ea9SToby Isaac PetscAssertPointer(ctx, 5); 5579371c9d4SSatish Balay if (l2g) { 5589371c9d4SSatish Balay *A = rc->R; 5599371c9d4SSatish Balay } else { 5609371c9d4SSatish Balay *A = rc->RT; 5619371c9d4SSatish Balay } 5623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 563ca3d3a14SMatthew G. Knepley } 564ca3d3a14SMatthew G. Knepley 565d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformApplyReal_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscReal *y, PetscReal *z, void *ctx) 566d71ae5a4SJacob Faibussowitsch { 567ec277c0fSMatthew G. Knepley PetscFunctionBegin; 568ab6a9622SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX) 569ab6a9622SMatthew G. Knepley switch (dim) { 5709371c9d4SSatish Balay case 2: { 57127104ee2SJacob Faibussowitsch PetscScalar yt[2] = {y[0], y[1]}, zt[2] = {0.0, 0.0}; 572ab6a9622SMatthew G. Knepley 5739566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx)); 5749371c9d4SSatish Balay z[0] = PetscRealPart(zt[0]); 5759371c9d4SSatish Balay z[1] = PetscRealPart(zt[1]); 5769371c9d4SSatish Balay } break; 5779371c9d4SSatish Balay case 3: { 57827104ee2SJacob Faibussowitsch PetscScalar yt[3] = {y[0], y[1], y[2]}, zt[3] = {0.0, 0.0, 0.0}; 579ab6a9622SMatthew G. Knepley 5809566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx)); 5819371c9d4SSatish Balay z[0] = PetscRealPart(zt[0]); 5829371c9d4SSatish Balay z[1] = PetscRealPart(zt[1]); 5839371c9d4SSatish Balay z[2] = PetscRealPart(zt[2]); 5849371c9d4SSatish Balay } break; 585ab6a9622SMatthew G. Knepley } 586ab6a9622SMatthew G. Knepley #else 5879566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx)); 588ab6a9622SMatthew G. Knepley #endif 5893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 590ab6a9622SMatthew G. Knepley } 591ab6a9622SMatthew G. Knepley 592d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, void *ctx) 593d71ae5a4SJacob Faibussowitsch { 594ca3d3a14SMatthew G. Knepley const PetscScalar *A; 595ca3d3a14SMatthew G. Knepley 596ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 5979566063dSJacob Faibussowitsch PetscCall((*dm->transformGetMatrix)(dm, x, l2g, &A, ctx)); 598ca3d3a14SMatthew G. Knepley switch (dim) { 599d71ae5a4SJacob Faibussowitsch case 2: 600d71ae5a4SJacob Faibussowitsch DMPlex_Mult2D_Internal(A, 1, y, z); 601d71ae5a4SJacob Faibussowitsch break; 602d71ae5a4SJacob Faibussowitsch case 3: 603d71ae5a4SJacob Faibussowitsch DMPlex_Mult3D_Internal(A, 1, y, z); 604d71ae5a4SJacob Faibussowitsch break; 605ca3d3a14SMatthew G. Knepley } 6063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 607ca3d3a14SMatthew G. Knepley } 608ca3d3a14SMatthew G. Knepley 609d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a) 610d71ae5a4SJacob Faibussowitsch { 611ca3d3a14SMatthew G. Knepley PetscSection ts; 612ca3d3a14SMatthew G. Knepley const PetscScalar *ta, *tva; 613ca3d3a14SMatthew G. Knepley PetscInt dof; 614ca3d3a14SMatthew G. Knepley 615ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 6169566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(tdm, &ts)); 6179566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof)); 6189566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(tv, &ta)); 6199566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(tdm, p, f, ta, &tva)); 620ca3d3a14SMatthew G. Knepley if (l2g) { 621ca3d3a14SMatthew G. Knepley switch (dof) { 622d71ae5a4SJacob Faibussowitsch case 4: 623d71ae5a4SJacob Faibussowitsch DMPlex_Mult2D_Internal(tva, 1, a, a); 624d71ae5a4SJacob Faibussowitsch break; 625d71ae5a4SJacob Faibussowitsch case 9: 626d71ae5a4SJacob Faibussowitsch DMPlex_Mult3D_Internal(tva, 1, a, a); 627d71ae5a4SJacob Faibussowitsch break; 628ca3d3a14SMatthew G. Knepley } 629ca3d3a14SMatthew G. Knepley } else { 630ca3d3a14SMatthew G. Knepley switch (dof) { 631d71ae5a4SJacob Faibussowitsch case 4: 632d71ae5a4SJacob Faibussowitsch DMPlex_MultTranspose2D_Internal(tva, 1, a, a); 633d71ae5a4SJacob Faibussowitsch break; 634d71ae5a4SJacob Faibussowitsch case 9: 635d71ae5a4SJacob Faibussowitsch DMPlex_MultTranspose3D_Internal(tva, 1, a, a); 636d71ae5a4SJacob Faibussowitsch break; 637ca3d3a14SMatthew G. Knepley } 638ca3d3a14SMatthew G. Knepley } 6399566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(tv, &ta)); 6403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 641ca3d3a14SMatthew G. Knepley } 642ca3d3a14SMatthew G. Knepley 643d71ae5a4SJacob 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) 644d71ae5a4SJacob Faibussowitsch { 645ca3d3a14SMatthew G. Knepley PetscSection s, ts; 646ca3d3a14SMatthew G. Knepley const PetscScalar *ta, *tvaf, *tvag; 647ca3d3a14SMatthew G. Knepley PetscInt fdof, gdof, fpdof, gpdof; 648ca3d3a14SMatthew G. Knepley 649ca3d3a14SMatthew G. Knepley PetscFunctionBeginHot; 6509566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 6519566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(tdm, &ts)); 6529566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, pf, f, &fpdof)); 6539566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, pg, g, &gpdof)); 6549566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(ts, pf, f, &fdof)); 6559566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(ts, pg, g, &gdof)); 6569566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(tv, &ta)); 6579566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(tdm, pf, f, ta, &tvaf)); 6589566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(tdm, pg, g, ta, &tvag)); 659ca3d3a14SMatthew G. Knepley if (l2g) { 660ca3d3a14SMatthew G. Knepley switch (fdof) { 661d71ae5a4SJacob Faibussowitsch case 4: 662d71ae5a4SJacob Faibussowitsch DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a); 663d71ae5a4SJacob Faibussowitsch break; 664d71ae5a4SJacob Faibussowitsch case 9: 665d71ae5a4SJacob Faibussowitsch DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a); 666d71ae5a4SJacob Faibussowitsch break; 667ca3d3a14SMatthew G. Knepley } 668ca3d3a14SMatthew G. Knepley switch (gdof) { 669d71ae5a4SJacob Faibussowitsch case 4: 670d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a); 671d71ae5a4SJacob Faibussowitsch break; 672d71ae5a4SJacob Faibussowitsch case 9: 673d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a); 674d71ae5a4SJacob Faibussowitsch break; 675ca3d3a14SMatthew G. Knepley } 676ca3d3a14SMatthew G. Knepley } else { 677ca3d3a14SMatthew G. Knepley switch (fdof) { 678d71ae5a4SJacob Faibussowitsch case 4: 679d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a); 680d71ae5a4SJacob Faibussowitsch break; 681d71ae5a4SJacob Faibussowitsch case 9: 682d71ae5a4SJacob Faibussowitsch DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a); 683d71ae5a4SJacob Faibussowitsch break; 684ca3d3a14SMatthew G. Knepley } 685ca3d3a14SMatthew G. Knepley switch (gdof) { 686d71ae5a4SJacob Faibussowitsch case 4: 687d71ae5a4SJacob Faibussowitsch DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a); 688d71ae5a4SJacob Faibussowitsch break; 689d71ae5a4SJacob Faibussowitsch case 9: 690d71ae5a4SJacob Faibussowitsch DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a); 691d71ae5a4SJacob Faibussowitsch break; 692ca3d3a14SMatthew G. Knepley } 693ca3d3a14SMatthew G. Knepley } 6949566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(tv, &ta)); 6953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 696ca3d3a14SMatthew G. Knepley } 697ca3d3a14SMatthew G. Knepley 698d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a) 699d71ae5a4SJacob Faibussowitsch { 700ca3d3a14SMatthew G. Knepley PetscSection s; 701ca3d3a14SMatthew G. Knepley PetscSection clSection; 702ca3d3a14SMatthew G. Knepley IS clPoints; 703ca3d3a14SMatthew G. Knepley const PetscInt *clp; 704ca3d3a14SMatthew G. Knepley PetscInt *points = NULL; 705ca3d3a14SMatthew G. Knepley PetscInt Nf, f, Np, cp, dof, d = 0; 706ca3d3a14SMatthew G. Knepley 707ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 7089566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 7099566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &Nf)); 71007218a29SMatthew G. Knepley PetscCall(DMPlexGetCompressedClosure(dm, s, p, 0, &Np, &points, &clSection, &clPoints, &clp)); 711ca3d3a14SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 712ca3d3a14SMatthew G. Knepley for (cp = 0; cp < Np * 2; cp += 2) { 7139566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, points[cp], f, &dof)); 714ca3d3a14SMatthew G. Knepley if (!dof) continue; 7159566063dSJacob Faibussowitsch if (fieldActive[f]) PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d])); 716ca3d3a14SMatthew G. Knepley d += dof; 717ca3d3a14SMatthew G. Knepley } 718ca3d3a14SMatthew G. Knepley } 7199566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 7203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 721ca3d3a14SMatthew G. Knepley } 722ca3d3a14SMatthew G. Knepley 723d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a) 724d71ae5a4SJacob Faibussowitsch { 725ca3d3a14SMatthew G. Knepley PetscSection s; 726ca3d3a14SMatthew G. Knepley PetscSection clSection; 727ca3d3a14SMatthew G. Knepley IS clPoints; 728ca3d3a14SMatthew G. Knepley const PetscInt *clp; 729ca3d3a14SMatthew G. Knepley PetscInt *points = NULL; 7308bdb3c71SMatthew G. Knepley PetscInt Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0; 731ca3d3a14SMatthew G. Knepley 732ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 7339566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 7349566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &Nf)); 73507218a29SMatthew G. Knepley PetscCall(DMPlexGetCompressedClosure(dm, s, p, 0, &Np, &points, &clSection, &clPoints, &clp)); 736ca3d3a14SMatthew G. Knepley for (f = 0, r = 0; f < Nf; ++f) { 737ca3d3a14SMatthew G. Knepley for (cpf = 0; cpf < Np * 2; cpf += 2) { 7389566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, points[cpf], f, &fdof)); 739ca3d3a14SMatthew G. Knepley for (g = 0, c = 0; g < Nf; ++g) { 740ca3d3a14SMatthew G. Knepley for (cpg = 0; cpg < Np * 2; cpg += 2) { 7419566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, points[cpg], g, &gdof)); 7429566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformFieldTensor_Internal(dm, tdm, tv, points[cpf], f, points[cpg], g, l2g, lda, &a[r * lda + c])); 743ca3d3a14SMatthew G. Knepley c += gdof; 744ca3d3a14SMatthew G. Knepley } 745ca3d3a14SMatthew G. Knepley } 74663a3b9bcSJacob Faibussowitsch PetscCheck(c == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of columns %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda); 747ca3d3a14SMatthew G. Knepley r += fdof; 748ca3d3a14SMatthew G. Knepley } 749ca3d3a14SMatthew G. Knepley } 75063a3b9bcSJacob Faibussowitsch PetscCheck(r == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of rows %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda); 7519566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 7523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 753ca3d3a14SMatthew G. Knepley } 754ca3d3a14SMatthew G. Knepley 755d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g) 756d71ae5a4SJacob Faibussowitsch { 757ca3d3a14SMatthew G. Knepley DM tdm; 758ca3d3a14SMatthew G. Knepley Vec tv; 759ca3d3a14SMatthew G. Knepley PetscSection ts, s; 760ca3d3a14SMatthew G. Knepley const PetscScalar *ta; 761ca3d3a14SMatthew G. Knepley PetscScalar *a, *va; 762ca3d3a14SMatthew G. Knepley PetscInt pStart, pEnd, p, Nf, f; 763ca3d3a14SMatthew G. Knepley 764ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 7659566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 7669566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 7679566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(tdm, &ts)); 7689566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 7699566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 7709566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &Nf)); 7719566063dSJacob Faibussowitsch PetscCall(VecGetArray(lv, &a)); 7729566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(tv, &ta)); 773ca3d3a14SMatthew G. Knepley for (p = pStart; p < pEnd; ++p) { 774ca3d3a14SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 7759566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, p, f, a, &va)); 7769566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va)); 777ca3d3a14SMatthew G. Knepley } 778ca3d3a14SMatthew G. Knepley } 7799566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(lv, &a)); 7809566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(tv, &ta)); 7813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 782ca3d3a14SMatthew G. Knepley } 783ca3d3a14SMatthew G. Knepley 784ca3d3a14SMatthew G. Knepley /*@ 785ca3d3a14SMatthew G. Knepley DMPlexGlobalToLocalBasis - Transform the values in the given local vector from the global basis to the local basis 786ca3d3a14SMatthew G. Knepley 787ca3d3a14SMatthew G. Knepley Input Parameters: 788a1cb98faSBarry Smith + dm - The `DM` 789ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the global basis 790ca3d3a14SMatthew G. Knepley 7912fe279fdSBarry Smith Output Parameter: 792ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the local basis 793ca3d3a14SMatthew G. Knepley 794ca3d3a14SMatthew G. Knepley Level: developer 795ca3d3a14SMatthew G. Knepley 796a1cb98faSBarry Smith Note: 797a1cb98faSBarry 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. 798a1cb98faSBarry Smith 7991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexLocalToGlobalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()` 800ca3d3a14SMatthew G. Knepley @*/ 801d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv) 802d71ae5a4SJacob Faibussowitsch { 803ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 804ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 805ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(lv, VEC_CLASSID, 2); 8069566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE)); 8073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 808ca3d3a14SMatthew G. Knepley } 809ca3d3a14SMatthew G. Knepley 810ca3d3a14SMatthew G. Knepley /*@ 811ca3d3a14SMatthew G. Knepley DMPlexLocalToGlobalBasis - Transform the values in the given local vector from the local basis to the global basis 812ca3d3a14SMatthew G. Knepley 813ca3d3a14SMatthew G. Knepley Input Parameters: 814a1cb98faSBarry Smith + dm - The `DM` 815ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the local basis 816ca3d3a14SMatthew G. Knepley 8172fe279fdSBarry Smith Output Parameter: 818ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the global basis 819ca3d3a14SMatthew G. Knepley 820ca3d3a14SMatthew G. Knepley Level: developer 821ca3d3a14SMatthew G. Knepley 822a1cb98faSBarry Smith Note: 823a1cb98faSBarry 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. 824a1cb98faSBarry Smith 8251cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()` 826ca3d3a14SMatthew G. Knepley @*/ 827d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv) 828d71ae5a4SJacob Faibussowitsch { 829ca3d3a14SMatthew G. Knepley PetscFunctionBegin; 830ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 831ca3d3a14SMatthew G. Knepley PetscValidHeaderSpecific(lv, VEC_CLASSID, 2); 8329566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE)); 8333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 834ca3d3a14SMatthew G. Knepley } 835ca3d3a14SMatthew G. Knepley 836ca3d3a14SMatthew G. Knepley /*@ 837ca3d3a14SMatthew G. Knepley DMPlexCreateBasisRotation - Create an internal transformation from the global basis, used to specify boundary conditions 838ca3d3a14SMatthew G. Knepley and global solutions, to a local basis, appropriate for discretization integrals and assembly. 839ca3d3a14SMatthew G. Knepley 840ca3d3a14SMatthew G. Knepley Input Parameters: 841a1cb98faSBarry Smith + dm - The `DM` 842ca3d3a14SMatthew G. Knepley . alpha - The first Euler angle, and in 2D the only one 843ca3d3a14SMatthew G. Knepley . beta - The second Euler angle 844f0fc11ceSJed Brown - gamma - The third Euler angle 845ca3d3a14SMatthew G. Knepley 846ca3d3a14SMatthew G. Knepley Level: developer 847ca3d3a14SMatthew G. Knepley 848a1cb98faSBarry Smith Note: 849a1cb98faSBarry Smith Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that 850a1cb98faSBarry 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 851a1cb98faSBarry Smith .vb 852a1cb98faSBarry 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. 853a1cb98faSBarry 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. 854a1cb98faSBarry Smith The XYZ system rotates a third time about the z axis by gamma. 855a1cb98faSBarry Smith .ve 856a1cb98faSBarry Smith 8571cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()` 858ca3d3a14SMatthew G. Knepley @*/ 859d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma) 860d71ae5a4SJacob Faibussowitsch { 861ca3d3a14SMatthew G. Knepley RotCtx *rc; 862ca3d3a14SMatthew G. Knepley PetscInt cdim; 863ca3d3a14SMatthew G. Knepley 864362febeeSStefano Zampini PetscFunctionBegin; 8659566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 8669566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(1, &rc)); 867ca3d3a14SMatthew G. Knepley dm->transformCtx = rc; 868ca3d3a14SMatthew G. Knepley dm->transformSetUp = DMPlexBasisTransformSetUp_Rotation_Internal; 869ca3d3a14SMatthew G. Knepley dm->transformDestroy = DMPlexBasisTransformDestroy_Rotation_Internal; 870ca3d3a14SMatthew G. Knepley dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal; 871ca3d3a14SMatthew G. Knepley rc->dim = cdim; 872ca3d3a14SMatthew G. Knepley rc->alpha = alpha; 873ca3d3a14SMatthew G. Knepley rc->beta = beta; 874ca3d3a14SMatthew G. Knepley rc->gamma = gamma; 8759566063dSJacob Faibussowitsch PetscCall((*dm->transformSetUp)(dm, dm->transformCtx)); 8769566063dSJacob Faibussowitsch PetscCall(DMConstructBasisTransform_Internal(dm)); 8773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 878ca3d3a14SMatthew G. Knepley } 879ca3d3a14SMatthew G. Knepley 880b278463cSMatthew G. Knepley /*@C 881ece3a9fcSMatthew G. Knepley DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector using a function of the coordinates 882b278463cSMatthew G. Knepley 883b278463cSMatthew G. Knepley Input Parameters: 884a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 885b278463cSMatthew G. Knepley . time - The time 886b278463cSMatthew G. Knepley . field - The field to constrain 8871c531cf8SMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 88820f4b53cSBarry Smith . comps - An array of constrained component numbers, or `NULL` for all components 889a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 890a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 891b278463cSMatthew G. Knepley . ids - An array of ids for constrained points 892b278463cSMatthew G. Knepley . func - A pointwise function giving boundary values 893b278463cSMatthew G. Knepley - ctx - An optional user context for bcFunc 894b278463cSMatthew G. Knepley 895b278463cSMatthew G. Knepley Output Parameter: 896b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values 897b278463cSMatthew G. Knepley 898b278463cSMatthew G. Knepley Level: developer 899b278463cSMatthew G. Knepley 9001cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLabel`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()` 901b278463cSMatthew G. Knepley @*/ 902d71ae5a4SJacob 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) 903d71ae5a4SJacob Faibussowitsch { 9040163fd50SMatthew G. Knepley PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 90555f2e967SMatthew G. Knepley void **ctxs; 906d7ddef95SMatthew G. Knepley PetscInt numFields; 907d7ddef95SMatthew G. Knepley 908d7ddef95SMatthew G. Knepley PetscFunctionBegin; 9099566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 9109566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 911d7ddef95SMatthew G. Knepley funcs[field] = func; 912d7ddef95SMatthew G. Knepley ctxs[field] = ctx; 9139566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX)); 9149566063dSJacob Faibussowitsch PetscCall(PetscFree2(funcs, ctxs)); 9153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 916d7ddef95SMatthew G. Knepley } 917d7ddef95SMatthew G. Knepley 918b278463cSMatthew G. Knepley /*@C 919ece3a9fcSMatthew G. Knepley DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector using a function of the coordinates and field data 920b278463cSMatthew G. Knepley 921b278463cSMatthew G. Knepley Input Parameters: 922a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 923b278463cSMatthew G. Knepley . time - The time 924b278463cSMatthew G. Knepley . locU - A local vector with the input solution values 925b278463cSMatthew G. Knepley . field - The field to constrain 9261c531cf8SMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 92720f4b53cSBarry Smith . comps - An array of constrained component numbers, or `NULL` for all components 928a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 929a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 930b278463cSMatthew G. Knepley . ids - An array of ids for constrained points 931b278463cSMatthew G. Knepley . func - A pointwise function giving boundary values 932b278463cSMatthew G. Knepley - ctx - An optional user context for bcFunc 933b278463cSMatthew G. Knepley 934b278463cSMatthew G. Knepley Output Parameter: 935b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values 936b278463cSMatthew G. Knepley 937b278463cSMatthew G. Knepley Level: developer 938b278463cSMatthew G. Knepley 9391cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()` 940b278463cSMatthew G. Knepley @*/ 941d71ae5a4SJacob 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) 942d71ae5a4SJacob Faibussowitsch { 9439371c9d4SSatish 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[]); 944c60e475cSMatthew G. Knepley void **ctxs; 945c60e475cSMatthew G. Knepley PetscInt numFields; 946c60e475cSMatthew G. Knepley 947c60e475cSMatthew G. Knepley PetscFunctionBegin; 9489566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 9499566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 950c60e475cSMatthew G. Knepley funcs[field] = func; 951c60e475cSMatthew G. Knepley ctxs[field] = ctx; 9529566063dSJacob Faibussowitsch PetscCall(DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX)); 9539566063dSJacob Faibussowitsch PetscCall(PetscFree2(funcs, ctxs)); 9543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 955c60e475cSMatthew G. Knepley } 956c60e475cSMatthew G. Knepley 957b278463cSMatthew G. Knepley /*@C 958d5b43468SJose E. Roman DMPlexInsertBoundaryValuesEssentialBdField - Insert boundary values into a local vector using a function of the coordinates and boundary field data 959ece3a9fcSMatthew G. Knepley 96020f4b53cSBarry Smith Collective 961ece3a9fcSMatthew G. Knepley 962ece3a9fcSMatthew G. Knepley Input Parameters: 963a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 964ece3a9fcSMatthew G. Knepley . time - The time 965ece3a9fcSMatthew G. Knepley . locU - A local vector with the input solution values 966ece3a9fcSMatthew G. Knepley . field - The field to constrain 967ece3a9fcSMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 96820f4b53cSBarry Smith . comps - An array of constrained component numbers, or `NULL` for all components 969a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 970a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 971ece3a9fcSMatthew G. Knepley . ids - An array of ids for constrained points 97220f4b53cSBarry Smith . func - A pointwise function giving boundary values, the calling sequence is given in `DMProjectBdFieldLabelLocal()` 97320f4b53cSBarry Smith - ctx - An optional user context for `func` 974ece3a9fcSMatthew G. Knepley 975ece3a9fcSMatthew G. Knepley Output Parameter: 976ece3a9fcSMatthew G. Knepley . locX - A local vector to receive the boundary values 977ece3a9fcSMatthew G. Knepley 978ece3a9fcSMatthew G. Knepley Level: developer 979ece3a9fcSMatthew G. Knepley 9801cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectBdFieldLabelLocal()`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()` 981ece3a9fcSMatthew G. Knepley @*/ 982d71ae5a4SJacob 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) 983d71ae5a4SJacob Faibussowitsch { 9849371c9d4SSatish 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[]); 985ece3a9fcSMatthew G. Knepley void **ctxs; 986ece3a9fcSMatthew G. Knepley PetscInt numFields; 987ece3a9fcSMatthew G. Knepley 988ece3a9fcSMatthew G. Knepley PetscFunctionBegin; 9899566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 9909566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 991ece3a9fcSMatthew G. Knepley funcs[field] = func; 992ece3a9fcSMatthew G. Knepley ctxs[field] = ctx; 9939566063dSJacob Faibussowitsch PetscCall(DMProjectBdFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX)); 9949566063dSJacob Faibussowitsch PetscCall(PetscFree2(funcs, ctxs)); 9953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 996ece3a9fcSMatthew G. Knepley } 997ece3a9fcSMatthew G. Knepley 998ece3a9fcSMatthew G. Knepley /*@C 999b278463cSMatthew G. Knepley DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector 1000b278463cSMatthew G. Knepley 1001b278463cSMatthew G. Knepley Input Parameters: 1002a1cb98faSBarry Smith + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 1003b278463cSMatthew G. Knepley . time - The time 1004b278463cSMatthew G. Knepley . faceGeometry - A vector with the FVM face geometry information 1005b278463cSMatthew G. Knepley . cellGeometry - A vector with the FVM cell geometry information 1006b278463cSMatthew G. Knepley . Grad - A vector with the FVM cell gradient information 1007b278463cSMatthew G. Knepley . field - The field to constrain 10081c531cf8SMatthew G. Knepley . Nc - The number of constrained field components, or 0 for all components 100920f4b53cSBarry Smith . comps - An array of constrained component numbers, or `NULL` for all components 1010a1cb98faSBarry Smith . label - The `DMLabel` defining constrained points 1011a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points 1012b278463cSMatthew G. Knepley . ids - An array of ids for constrained points 1013b278463cSMatthew G. Knepley . func - A pointwise function giving boundary values 1014b278463cSMatthew G. Knepley - ctx - An optional user context for bcFunc 1015b278463cSMatthew G. Knepley 1016b278463cSMatthew G. Knepley Output Parameter: 1017b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values 1018b278463cSMatthew G. Knepley 1019b278463cSMatthew G. Knepley Level: developer 1020b278463cSMatthew G. Knepley 1021a1cb98faSBarry Smith Note: 1022a1cb98faSBarry Smith This implementation currently ignores the numcomps/comps argument from `DMAddBoundary()` 1023a1cb98faSBarry Smith 10241cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()` 1025b278463cSMatthew G. Knepley @*/ 1026d71ae5a4SJacob 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) 1027d71ae5a4SJacob Faibussowitsch { 102861f58d28SMatthew G. Knepley PetscDS prob; 1029da97024aSMatthew G. Knepley PetscSF sf; 1030d7ddef95SMatthew G. Knepley DM dmFace, dmCell, dmGrad; 103120369375SToby Isaac const PetscScalar *facegeom, *cellgeom = NULL, *grad; 1032da97024aSMatthew G. Knepley const PetscInt *leaves; 1033d7ddef95SMatthew G. Knepley PetscScalar *x, *fx; 1034520b3818SMatthew G. Knepley PetscInt dim, nleaves, loc, fStart, fEnd, pdim, i; 10353ba16761SJacob Faibussowitsch PetscErrorCode ierru = PETSC_SUCCESS; 1036d7ddef95SMatthew G. Knepley 1037d7ddef95SMatthew G. Knepley PetscFunctionBegin; 10389566063dSJacob Faibussowitsch PetscCall(DMGetPointSF(dm, &sf)); 10399566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL)); 1040da97024aSMatthew G. Knepley nleaves = PetscMax(0, nleaves); 10419566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 10429566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 10439566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 10449566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 10459566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 104620369375SToby Isaac if (cellGeometry) { 10479566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 10489566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 104920369375SToby Isaac } 1050d7ddef95SMatthew G. Knepley if (Grad) { 1051c0a6632aSMatthew G. Knepley PetscFV fv; 1052c0a6632aSMatthew G. Knepley 10539566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fv)); 10549566063dSJacob Faibussowitsch PetscCall(VecGetDM(Grad, &dmGrad)); 10559566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Grad, &grad)); 10569566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 10579566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx)); 1058d7ddef95SMatthew G. Knepley } 10599566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX, &x)); 1060d7ddef95SMatthew G. Knepley for (i = 0; i < numids; ++i) { 1061d7ddef95SMatthew G. Knepley IS faceIS; 1062d7ddef95SMatthew G. Knepley const PetscInt *faces; 1063d7ddef95SMatthew G. Knepley PetscInt numFaces, f; 1064d7ddef95SMatthew G. Knepley 10659566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, ids[i], &faceIS)); 1066d7ddef95SMatthew G. Knepley if (!faceIS) continue; /* No points with that id on this process */ 10679566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(faceIS, &numFaces)); 10689566063dSJacob Faibussowitsch PetscCall(ISGetIndices(faceIS, &faces)); 1069d7ddef95SMatthew G. Knepley for (f = 0; f < numFaces; ++f) { 1070d7ddef95SMatthew G. Knepley const PetscInt face = faces[f], *cells; 1071640bce14SSatish Balay PetscFVFaceGeom *fg; 1072d7ddef95SMatthew G. Knepley 1073d7ddef95SMatthew G. Knepley if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */ 10749566063dSJacob Faibussowitsch PetscCall(PetscFindInt(face, nleaves, (PetscInt *)leaves, &loc)); 1075da97024aSMatthew G. Knepley if (loc >= 0) continue; 10769566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 10779566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 1078d7ddef95SMatthew G. Knepley if (Grad) { 1079640bce14SSatish Balay PetscFVCellGeom *cg; 1080640bce14SSatish Balay PetscScalar *cx, *cgrad; 1081d7ddef95SMatthew G. Knepley PetscScalar *xG; 1082d7ddef95SMatthew G. Knepley PetscReal dx[3]; 1083d7ddef95SMatthew G. Knepley PetscInt d; 1084d7ddef95SMatthew G. Knepley 10859566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg)); 10869566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &cx)); 10879566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad)); 10889566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG)); 1089d7ddef95SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx); 1090d7ddef95SMatthew G. Knepley for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d * dim], dx); 10919566063dSJacob Faibussowitsch PetscCall((*func)(time, fg->centroid, fg->normal, fx, xG, ctx)); 1092d7ddef95SMatthew G. Knepley } else { 1093640bce14SSatish Balay PetscScalar *xI; 1094d7ddef95SMatthew G. Knepley PetscScalar *xG; 1095d7ddef95SMatthew G. Knepley 10969566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &xI)); 10979566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG)); 1098e735a8a9SMatthew G. Knepley ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx); 1099e735a8a9SMatthew G. Knepley if (ierru) { 11009566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(faceIS, &faces)); 11019566063dSJacob Faibussowitsch PetscCall(ISDestroy(&faceIS)); 1102e735a8a9SMatthew G. Knepley goto cleanup; 1103e735a8a9SMatthew G. Knepley } 1104d7ddef95SMatthew G. Knepley } 1105d7ddef95SMatthew G. Knepley } 11069566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(faceIS, &faces)); 11079566063dSJacob Faibussowitsch PetscCall(ISDestroy(&faceIS)); 1108d7ddef95SMatthew G. Knepley } 1109e735a8a9SMatthew G. Knepley cleanup: 11109566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX, &x)); 1111d7ddef95SMatthew G. Knepley if (Grad) { 11129566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx)); 11139566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Grad, &grad)); 1114d7ddef95SMatthew G. Knepley } 11159566063dSJacob Faibussowitsch if (cellGeometry) PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 11169566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 11179566063dSJacob Faibussowitsch PetscCall(ierru); 11183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1119d7ddef95SMatthew G. Knepley } 1120d7ddef95SMatthew G. Knepley 1121d71ae5a4SJacob Faibussowitsch static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 1122d71ae5a4SJacob Faibussowitsch { 11230c364540SMatthew G. Knepley PetscInt c; 11240c364540SMatthew G. Knepley for (c = 0; c < Nc; ++c) u[c] = 0.0; 11253ba16761SJacob Faibussowitsch return PETSC_SUCCESS; 11260c364540SMatthew G. Knepley } 11270c364540SMatthew G. Knepley 1128d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1129d71ae5a4SJacob Faibussowitsch { 11300c364540SMatthew G. Knepley PetscObject isZero; 1131e5e52638SMatthew G. Knepley PetscDS prob; 1132d7ddef95SMatthew G. Knepley PetscInt numBd, b; 113355f2e967SMatthew G. Knepley 113455f2e967SMatthew G. Knepley PetscFunctionBegin; 11359566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 11369566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 11379566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero)); 113855f2e967SMatthew G. Knepley for (b = 0; b < numBd; ++b) { 113945480ffeSMatthew G. Knepley PetscWeakForm wf; 1140f971fd6bSMatthew G. Knepley DMBoundaryConditionType type; 114145480ffeSMatthew G. Knepley const char *name; 1142d7ddef95SMatthew G. Knepley DMLabel label; 11431c531cf8SMatthew G. Knepley PetscInt field, Nc; 11441c531cf8SMatthew G. Knepley const PetscInt *comps; 1145d7ddef95SMatthew G. Knepley PetscObject obj; 1146d7ddef95SMatthew G. Knepley PetscClassId id; 114745480ffeSMatthew G. Knepley void (*bvfunc)(void); 1148d7ddef95SMatthew G. Knepley PetscInt numids; 1149d7ddef95SMatthew G. Knepley const PetscInt *ids; 115055f2e967SMatthew G. Knepley void *ctx; 115155f2e967SMatthew G. Knepley 11529566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx)); 1153f971fd6bSMatthew G. Knepley if (insertEssential != (type & DM_BC_ESSENTIAL)) continue; 11549566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 11559566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 1156d7ddef95SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 1157c60e475cSMatthew G. Knepley switch (type) { 1158c60e475cSMatthew G. Knepley /* for FEM, there is no insertion to be done for non-essential boundary conditions */ 11599371c9d4SSatish Balay case DM_BC_ESSENTIAL: { 116045480ffeSMatthew G. Knepley PetscSimplePointFunc func = (PetscSimplePointFunc)bvfunc; 116145480ffeSMatthew G. Knepley 116245480ffeSMatthew G. Knepley if (isZero) func = zero; 11639566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 11649566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func, ctx, locX)); 11659566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 11669371c9d4SSatish Balay } break; 11679371c9d4SSatish Balay case DM_BC_ESSENTIAL_FIELD: { 116845480ffeSMatthew G. Knepley PetscPointFunc func = (PetscPointFunc)bvfunc; 116945480ffeSMatthew G. Knepley 11709566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 11719566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func, ctx, locX)); 11729566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 11739371c9d4SSatish Balay } break; 1174d71ae5a4SJacob Faibussowitsch default: 1175d71ae5a4SJacob Faibussowitsch break; 1176c60e475cSMatthew G. Knepley } 1177d7ddef95SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 117845480ffeSMatthew G. Knepley { 117945480ffeSMatthew G. Knepley PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *) = (PetscErrorCode(*)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *))bvfunc; 118045480ffeSMatthew G. Knepley 118143ea7facSMatthew G. Knepley if (!faceGeomFVM) continue; 11829566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids, func, ctx, locX)); 118345480ffeSMatthew G. Knepley } 118463a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 118555f2e967SMatthew G. Knepley } 11863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 118755f2e967SMatthew G. Knepley } 118855f2e967SMatthew G. Knepley 1189d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1190d71ae5a4SJacob Faibussowitsch { 119156cf3b9cSMatthew G. Knepley PetscObject isZero; 119256cf3b9cSMatthew G. Knepley PetscDS prob; 119356cf3b9cSMatthew G. Knepley PetscInt numBd, b; 119456cf3b9cSMatthew G. Knepley 119556cf3b9cSMatthew G. Knepley PetscFunctionBegin; 11963ba16761SJacob Faibussowitsch if (!locX) PetscFunctionReturn(PETSC_SUCCESS); 11979566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 11989566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 11999566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero)); 120056cf3b9cSMatthew G. Knepley for (b = 0; b < numBd; ++b) { 120145480ffeSMatthew G. Knepley PetscWeakForm wf; 120256cf3b9cSMatthew G. Knepley DMBoundaryConditionType type; 120345480ffeSMatthew G. Knepley const char *name; 120456cf3b9cSMatthew G. Knepley DMLabel label; 120556cf3b9cSMatthew G. Knepley PetscInt field, Nc; 120656cf3b9cSMatthew G. Knepley const PetscInt *comps; 120756cf3b9cSMatthew G. Knepley PetscObject obj; 120856cf3b9cSMatthew G. Knepley PetscClassId id; 120956cf3b9cSMatthew G. Knepley PetscInt numids; 121056cf3b9cSMatthew G. Knepley const PetscInt *ids; 121145480ffeSMatthew G. Knepley void (*bvfunc)(void); 121256cf3b9cSMatthew G. Knepley void *ctx; 121356cf3b9cSMatthew G. Knepley 12149566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, NULL, &bvfunc, &ctx)); 121556cf3b9cSMatthew G. Knepley if (insertEssential != (type & DM_BC_ESSENTIAL)) continue; 12169566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 12179566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 121856cf3b9cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 121956cf3b9cSMatthew G. Knepley switch (type) { 122056cf3b9cSMatthew G. Knepley /* for FEM, there is no insertion to be done for non-essential boundary conditions */ 12219371c9d4SSatish Balay case DM_BC_ESSENTIAL: { 122245480ffeSMatthew G. Knepley PetscSimplePointFunc func_t = (PetscSimplePointFunc)bvfunc; 122345480ffeSMatthew G. Knepley 122445480ffeSMatthew G. Knepley if (isZero) func_t = zero; 12259566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 12269566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func_t, ctx, locX)); 12279566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 12289371c9d4SSatish Balay } break; 12299371c9d4SSatish Balay case DM_BC_ESSENTIAL_FIELD: { 123045480ffeSMatthew G. Knepley PetscPointFunc func_t = (PetscPointFunc)bvfunc; 123145480ffeSMatthew G. Knepley 12329566063dSJacob Faibussowitsch PetscCall(DMPlexLabelAddCells(dm, label)); 12339566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func_t, ctx, locX)); 12349566063dSJacob Faibussowitsch PetscCall(DMPlexLabelClearCells(dm, label)); 12359371c9d4SSatish Balay } break; 1236d71ae5a4SJacob Faibussowitsch default: 1237d71ae5a4SJacob Faibussowitsch break; 123856cf3b9cSMatthew G. Knepley } 123963a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 124056cf3b9cSMatthew G. Knepley } 12413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 124256cf3b9cSMatthew G. Knepley } 124356cf3b9cSMatthew G. Knepley 1244f1d73a7aSMatthew G. Knepley /*@ 1245f1d73a7aSMatthew G. Knepley DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector 1246f1d73a7aSMatthew G. Knepley 1247ed808b8fSJed Brown Not Collective 1248ed808b8fSJed Brown 1249f1d73a7aSMatthew G. Knepley Input Parameters: 1250a1cb98faSBarry Smith + dm - The `DM` 1251f1d73a7aSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions 1252f1d73a7aSMatthew G. Knepley . time - The time 1253f1d73a7aSMatthew G. Knepley . faceGeomFVM - Face geometry data for FV discretizations 1254f1d73a7aSMatthew G. Knepley . cellGeomFVM - Cell geometry data for FV discretizations 1255f1d73a7aSMatthew G. Knepley - gradFVM - Gradient reconstruction data for FV discretizations 1256f1d73a7aSMatthew G. Knepley 12572fe279fdSBarry Smith Output Parameter: 1258f1d73a7aSMatthew G. Knepley . locX - Solution updated with boundary values 1259f1d73a7aSMatthew G. Knepley 1260ed808b8fSJed Brown Level: intermediate 1261f1d73a7aSMatthew G. Knepley 12621cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`, `DMAddBoundary()` 1263f1d73a7aSMatthew G. Knepley @*/ 1264d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1265d71ae5a4SJacob Faibussowitsch { 1266f1d73a7aSMatthew G. Knepley PetscFunctionBegin; 1267f1d73a7aSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1268064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 1269ad540459SPierre Jolivet if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5); 1270ad540459SPierre Jolivet if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6); 1271ad540459SPierre Jolivet if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7); 1272cac4c232SBarry Smith PetscTryMethod(dm, "DMPlexInsertBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX, time, faceGeomFVM, cellGeomFVM, gradFVM)); 12733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1274f1d73a7aSMatthew G. Knepley } 1275f1d73a7aSMatthew G. Knepley 127656cf3b9cSMatthew G. Knepley /*@ 1277a5b23f4aSJose E. Roman DMPlexInsertTimeDerivativeBoundaryValues - Puts coefficients which represent boundary values of the time derivative into the local solution vector 127856cf3b9cSMatthew G. Knepley 127956cf3b9cSMatthew G. Knepley Input Parameters: 1280a1cb98faSBarry Smith + dm - The `DM` 128156cf3b9cSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions 128256cf3b9cSMatthew G. Knepley . time - The time 128356cf3b9cSMatthew G. Knepley . faceGeomFVM - Face geometry data for FV discretizations 128456cf3b9cSMatthew G. Knepley . cellGeomFVM - Cell geometry data for FV discretizations 128556cf3b9cSMatthew G. Knepley - gradFVM - Gradient reconstruction data for FV discretizations 128656cf3b9cSMatthew G. Knepley 12872fe279fdSBarry Smith Output Parameter: 128856cf3b9cSMatthew G. Knepley . locX_t - Solution updated with boundary values 128956cf3b9cSMatthew G. Knepley 129056cf3b9cSMatthew G. Knepley Level: developer 129156cf3b9cSMatthew G. Knepley 12921cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()` 129356cf3b9cSMatthew G. Knepley @*/ 1294d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues(DM dm, PetscBool insertEssential, Vec locX_t, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1295d71ae5a4SJacob Faibussowitsch { 129656cf3b9cSMatthew G. Knepley PetscFunctionBegin; 129756cf3b9cSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1298ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 3); 1299ad540459SPierre Jolivet if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5); 1300ad540459SPierre Jolivet if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6); 1301ad540459SPierre Jolivet if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7); 1302cac4c232SBarry Smith PetscTryMethod(dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX_t, time, faceGeomFVM, cellGeomFVM, gradFVM)); 13033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 130456cf3b9cSMatthew G. Knepley } 130556cf3b9cSMatthew G. Knepley 1306d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1307d71ae5a4SJacob Faibussowitsch { 1308574a98acSMatthew G. Knepley Vec localX; 1309574a98acSMatthew G. Knepley 1310574a98acSMatthew G. Knepley PetscFunctionBegin; 13119566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 13129566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL)); 13139566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 13149566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 13159566063dSJacob Faibussowitsch PetscCall(DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff)); 13169566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 13173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1318574a98acSMatthew G. Knepley } 1319574a98acSMatthew G. Knepley 1320574a98acSMatthew G. Knepley /*@C 132160225df5SJacob Faibussowitsch DMPlexComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 1322574a98acSMatthew G. Knepley 132320f4b53cSBarry Smith Collective 1324c0f8e1fdSMatthew G. Knepley 1325574a98acSMatthew G. Knepley Input Parameters: 1326a1cb98faSBarry Smith + dm - The `DM` 1327574a98acSMatthew G. Knepley . time - The time 1328574a98acSMatthew G. Knepley . funcs - The functions to evaluate for each field component 132920f4b53cSBarry Smith . ctxs - Optional array of contexts to pass to each function, or `NULL`. 1330574a98acSMatthew G. Knepley - localX - The coefficient vector u_h, a local vector 1331574a98acSMatthew G. Knepley 1332574a98acSMatthew G. Knepley Output Parameter: 1333574a98acSMatthew G. Knepley . diff - The diff ||u - u_h||_2 1334574a98acSMatthew G. Knepley 1335574a98acSMatthew G. Knepley Level: developer 1336574a98acSMatthew G. Knepley 13371cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1338574a98acSMatthew G. Knepley @*/ 1339d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff) 1340d71ae5a4SJacob Faibussowitsch { 13410f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1342ca3d3a14SMatthew G. Knepley DM tdm; 1343ca3d3a14SMatthew G. Knepley Vec tv; 1344cb1e1211SMatthew G Knepley PetscSection section; 1345c5bbbd5bSMatthew G. Knepley PetscQuadrature quad; 13464bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 134715496722SMatthew G. Knepley PetscScalar *funcVal, *interpolant; 13484bee2e38SMatthew G. Knepley PetscReal *coords, *gcoords; 1349cb1e1211SMatthew G Knepley PetscReal localDiff = 0.0; 13507318780aSToby Isaac const PetscReal *quadWeights; 1351412e9a14SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, c, field, fieldOffset; 1352ca3d3a14SMatthew G. Knepley PetscBool transform; 1353cb1e1211SMatthew G Knepley 1354cb1e1211SMatthew G Knepley PetscFunctionBegin; 13559566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 13569566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 13572a4e142eSMatthew G. Knepley fegeom.dimEmbed = coordDim; 13589566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 13599566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 13609566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 13619566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 13629566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 1363eae3dc7dSJacob Faibussowitsch PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 1364cb1e1211SMatthew G Knepley for (field = 0; field < numFields; ++field) { 136515496722SMatthew G. Knepley PetscObject obj; 136615496722SMatthew G. Knepley PetscClassId id; 1367c5bbbd5bSMatthew G. Knepley PetscInt Nc; 1368c5bbbd5bSMatthew G. Knepley 13699566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 13709566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 137115496722SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 137215496722SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 137315496722SMatthew G. Knepley 13749566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 13759566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 137615496722SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 137715496722SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 137815496722SMatthew G. Knepley 13799566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 13809566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 138163a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1382c5bbbd5bSMatthew G. Knepley numComponents += Nc; 1383cb1e1211SMatthew G Knepley } 13849566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 138563a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 1386c9cb6370SYANG Zongze PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * (Nq + 1), &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 13879566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 13889566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 1389cb1e1211SMatthew G Knepley for (c = cStart; c < cEnd; ++c) { 1390a1e44745SMatthew G. Knepley PetscScalar *x = NULL; 1391cb1e1211SMatthew G Knepley PetscReal elemDiff = 0.0; 13929c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1393cb1e1211SMatthew G Knepley 13949566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1395e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 1396cb1e1211SMatthew G Knepley 139715496722SMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 139815496722SMatthew G. Knepley PetscObject obj; 139915496722SMatthew G. Knepley PetscClassId id; 1400c110b1eeSGeoffrey Irving void *const ctx = ctxs ? ctxs[field] : NULL; 140115496722SMatthew G. Knepley PetscInt Nb, Nc, q, fc; 1402cb1e1211SMatthew G Knepley 14039566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 14049566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 14059371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 14069371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 14079371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 14089371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 14099371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 14109371c9d4SSatish Balay Nb = 1; 14119371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1412cb1e1211SMatthew G Knepley if (debug) { 1413cb1e1211SMatthew G Knepley char title[1024]; 141463a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 14159566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1416cb1e1211SMatthew G Knepley } 14177318780aSToby Isaac for (q = 0; q < Nq; ++q) { 14182a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1419d0609cedSBarry Smith PetscErrorCode ierr; 14202a4e142eSMatthew G. Knepley 14212a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 14222a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 14232a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 14242a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 142563a3b9bcSJacob 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); 1426d3a7d86cSMatthew G. Knepley if (transform) { 1427d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * Nq]; 14289566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx)); 1429d3a7d86cSMatthew G. Knepley } else { 1430d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * q]; 1431d3a7d86cSMatthew G. Knepley } 14329566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(funcVal, Nc)); 1433ca3d3a14SMatthew G. Knepley ierr = (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx); 1434e735a8a9SMatthew G. Knepley if (ierr) { 14359566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 14369566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 14379566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1438e735a8a9SMatthew G. Knepley } 14399566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 14409566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 14419566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 14422df84da0SMatthew G. Knepley else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 144315496722SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1444beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 14459371c9d4SSatish Balay if (debug) 14469371c9d4SSatish 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.), 14479371c9d4SSatish Balay (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]), (double)PetscRealPart(interpolant[fc]), (double)PetscRealPart(funcVal[fc]))); 14484bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1449cb1e1211SMatthew G Knepley } 1450cb1e1211SMatthew G Knepley } 14519c3cf19fSMatthew G. Knepley fieldOffset += Nb; 1452beaa55a6SMatthew G. Knepley qc += Nc; 1453cb1e1211SMatthew G Knepley } 14549566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 14559566063dSJacob Faibussowitsch if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 1456cb1e1211SMatthew G Knepley localDiff += elemDiff; 1457cb1e1211SMatthew G Knepley } 14589566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 14591c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 1460cb1e1211SMatthew G Knepley *diff = PetscSqrtReal(*diff); 14613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1462cb1e1211SMatthew G Knepley } 1463cb1e1211SMatthew G Knepley 1464d71ae5a4SJacob 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) 1465d71ae5a4SJacob Faibussowitsch { 14660f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1467ca3d3a14SMatthew G. Knepley DM tdm; 1468cb1e1211SMatthew G Knepley PetscSection section; 146940e14135SMatthew G. Knepley PetscQuadrature quad; 1470ca3d3a14SMatthew G. Knepley Vec localX, tv; 14719c3cf19fSMatthew G. Knepley PetscScalar *funcVal, *interpolant; 14722a4e142eSMatthew G. Knepley const PetscReal *quadWeights; 14734bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 14744bee2e38SMatthew G. Knepley PetscReal *coords, *gcoords; 147540e14135SMatthew G. Knepley PetscReal localDiff = 0.0; 1476485ad865SMatthew G. Knepley PetscInt dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset; 1477ca3d3a14SMatthew G. Knepley PetscBool transform; 1478cb1e1211SMatthew G Knepley 1479cb1e1211SMatthew G Knepley PetscFunctionBegin; 14809566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 14819566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 14824bee2e38SMatthew G. Knepley fegeom.dimEmbed = coordDim; 14839566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 14849566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 14859566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 14869566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 14879566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 14889566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 14899566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 14909566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 1491652b88e8SMatthew G. Knepley for (field = 0; field < numFields; ++field) { 14920f2d7e86SMatthew G. Knepley PetscFE fe; 149340e14135SMatthew G. Knepley PetscInt Nc; 1494652b88e8SMatthew G. Knepley 14959566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe)); 14969566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 14979566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 149840e14135SMatthew G. Knepley numComponents += Nc; 1499652b88e8SMatthew G. Knepley } 15009566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 150163a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 15029566063dSJacob Faibussowitsch /* PetscCall(DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX)); */ 1503c9cb6370SYANG Zongze PetscCall(PetscMalloc6(numComponents, &funcVal, coordDim * (Nq + 1), &coords, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ, numComponents * coordDim, &interpolant, Nq, &fegeom.detJ)); 15049566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 150540e14135SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 150640e14135SMatthew G. Knepley PetscScalar *x = NULL; 150740e14135SMatthew G. Knepley PetscReal elemDiff = 0.0; 15089c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1509652b88e8SMatthew G. Knepley 15109566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1511e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 151240e14135SMatthew G. Knepley 15139c3cf19fSMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 15140f2d7e86SMatthew G. Knepley PetscFE fe; 151551259fa3SMatthew G. Knepley void *const ctx = ctxs ? ctxs[field] : NULL; 15169c3cf19fSMatthew G. Knepley PetscInt Nb, Nc, q, fc; 151740e14135SMatthew G. Knepley 15189566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe)); 15199566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 15209566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 152140e14135SMatthew G. Knepley if (debug) { 152240e14135SMatthew G. Knepley char title[1024]; 15239566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 15249566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1525652b88e8SMatthew G. Knepley } 15269c3cf19fSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 15272a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1528d0609cedSBarry Smith PetscErrorCode ierr; 15292a4e142eSMatthew G. Knepley 15302a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 15312a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 15322a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 15332a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 15342df84da0SMatthew 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); 1535d3a7d86cSMatthew G. Knepley if (transform) { 1536d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * Nq]; 15379566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx)); 1538d3a7d86cSMatthew G. Knepley } else { 1539d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * q]; 1540d3a7d86cSMatthew G. Knepley } 15419566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(funcVal, Nc)); 15424bee2e38SMatthew G. Knepley ierr = (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx); 1543e735a8a9SMatthew G. Knepley if (ierr) { 15449566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 15459566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 15469566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ)); 1547e735a8a9SMatthew G. Knepley } 15489566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 15499566063dSJacob Faibussowitsch PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[fieldOffset], &qgeom, q, interpolant)); 15504bee2e38SMatthew G. Knepley /* Overwrite with the dot product if the normal is given */ 15514bee2e38SMatthew G. Knepley if (n) { 15524bee2e38SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 15534bee2e38SMatthew G. Knepley PetscScalar sum = 0.0; 15544bee2e38SMatthew G. Knepley PetscInt d; 15554bee2e38SMatthew G. Knepley for (d = 0; d < dim; ++d) sum += interpolant[fc * dim + d] * n[d]; 15564bee2e38SMatthew G. Knepley interpolant[fc] = sum; 15574bee2e38SMatthew G. Knepley } 15584bee2e38SMatthew G. Knepley } 15599c3cf19fSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1560beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 156163a3b9bcSJacob 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]))); 15624bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 156340e14135SMatthew G. Knepley } 156440e14135SMatthew G. Knepley } 15659c3cf19fSMatthew G. Knepley fieldOffset += Nb; 15669c3cf19fSMatthew G. Knepley qc += Nc; 156740e14135SMatthew G. Knepley } 15689566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 156963a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 157040e14135SMatthew G. Knepley localDiff += elemDiff; 157140e14135SMatthew G. Knepley } 15729566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ)); 15739566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 15741c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 157540e14135SMatthew G. Knepley *diff = PetscSqrtReal(*diff); 15763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1577cb1e1211SMatthew G Knepley } 1578cb1e1211SMatthew G Knepley 1579d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1580d71ae5a4SJacob Faibussowitsch { 15810f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1582ca3d3a14SMatthew G. Knepley DM tdm; 1583083401c6SMatthew G. Knepley DMLabel depthLabel; 158473d901b8SMatthew G. Knepley PetscSection section; 1585ca3d3a14SMatthew G. Knepley Vec localX, tv; 158673d901b8SMatthew G. Knepley PetscReal *localDiff; 1587083401c6SMatthew G. Knepley PetscInt dim, depth, dE, Nf, f, Nds, s; 1588ca3d3a14SMatthew G. Knepley PetscBool transform; 158973d901b8SMatthew G. Knepley 159073d901b8SMatthew G. Knepley PetscFunctionBegin; 15919566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 15929566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dE)); 15939566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 15949566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 15959566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 15969566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 15979566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 15989566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 15999566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 16009566063dSJacob Faibussowitsch PetscCall(DMLabelGetNumValues(depthLabel, &depth)); 1601083401c6SMatthew G. Knepley 16029566063dSJacob Faibussowitsch PetscCall(VecSet(localX, 0.0)); 16039566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 16049566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 16059566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 16069566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 16079566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(Nf, &localDiff)); 1608083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 1609083401c6SMatthew G. Knepley PetscDS ds; 1610083401c6SMatthew G. Knepley DMLabel label; 1611083401c6SMatthew G. Knepley IS fieldIS, pointIS; 1612083401c6SMatthew G. Knepley const PetscInt *fields, *points = NULL; 1613083401c6SMatthew G. Knepley PetscQuadrature quad; 1614083401c6SMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1615083401c6SMatthew G. Knepley PetscFEGeom fegeom; 1616083401c6SMatthew G. Knepley PetscReal *coords, *gcoords; 1617083401c6SMatthew G. Knepley PetscScalar *funcVal, *interpolant; 16185fedec97SMatthew G. Knepley PetscBool isCohesive; 1619083401c6SMatthew G. Knepley PetscInt qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf; 162073d901b8SMatthew G. Knepley 162107218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 16229566063dSJacob Faibussowitsch PetscCall(ISGetIndices(fieldIS, &fields)); 16239566063dSJacob Faibussowitsch PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 16249566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &dsNf)); 16259566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(ds, &totNc)); 16269566063dSJacob Faibussowitsch PetscCall(PetscDSGetQuadrature(ds, &quad)); 16279566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 162863a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != totNc), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, totNc); 16299566063dSJacob Faibussowitsch PetscCall(PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE * (Nq + 1), &coords, Nq, &fegeom.detJ, dE * dE * Nq, &fegeom.J, dE * dE * Nq, &fegeom.invJ)); 1630083401c6SMatthew G. Knepley if (!label) { 16319566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1632083401c6SMatthew G. Knepley } else { 16339566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 16349566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &cEnd)); 16359566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 1636083401c6SMatthew G. Knepley } 163773d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1638083401c6SMatthew G. Knepley const PetscInt cell = points ? points[c] : c; 163973d901b8SMatthew G. Knepley PetscScalar *x = NULL; 16405fedec97SMatthew G. Knepley const PetscInt *cone; 16415fedec97SMatthew G. Knepley PetscInt qc = 0, fOff = 0, dep; 164273d901b8SMatthew G. Knepley 16439566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(depthLabel, cell, &dep)); 1644083401c6SMatthew G. Knepley if (dep != depth - 1) continue; 16455fedec97SMatthew G. Knepley if (isCohesive) { 16469566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 16479566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 164896959cd1SMatthew G. Knepley } else { 16499566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 165096959cd1SMatthew G. Knepley } 1651e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, cell, 0, NULL, &x)); 16525fedec97SMatthew G. Knepley for (f = 0; f < dsNf; ++f) { 165315496722SMatthew G. Knepley PetscObject obj; 165415496722SMatthew G. Knepley PetscClassId id; 1655083401c6SMatthew G. Knepley void *const ctx = ctxs ? ctxs[fields[f]] : NULL; 165615496722SMatthew G. Knepley PetscInt Nb, Nc, q, fc; 165715496722SMatthew G. Knepley PetscReal elemDiff = 0.0; 16585fedec97SMatthew G. Knepley PetscBool cohesive; 165915496722SMatthew G. Knepley 16609566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 16619566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 16629566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 16639371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 16649371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 16659371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 16669371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 16679371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 16689371c9d4SSatish Balay Nb = 1; 16699371c9d4SSatish Balay } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 1670c82db6dbSMatthew G. Knepley if (isCohesive && !cohesive) { 1671c82db6dbSMatthew G. Knepley fOff += Nb * 2; 1672c82db6dbSMatthew G. Knepley qc += Nc; 1673c82db6dbSMatthew G. Knepley continue; 1674c82db6dbSMatthew G. Knepley } 167573d901b8SMatthew G. Knepley if (debug) { 167673d901b8SMatthew G. Knepley char title[1024]; 167763a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, fields[f])); 16789566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(cell, title, Nb, &x[fOff])); 167973d901b8SMatthew G. Knepley } 16807318780aSToby Isaac for (q = 0; q < Nq; ++q) { 16812a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1682d0609cedSBarry Smith PetscErrorCode ierr; 16832a4e142eSMatthew G. Knepley 16842a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 1685083401c6SMatthew G. Knepley qgeom.J = &fegeom.J[q * dE * dE]; 1686083401c6SMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * dE * dE]; 16872a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 168863a3b9bcSJacob 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); 1689d3a7d86cSMatthew G. Knepley if (transform) { 1690083401c6SMatthew G. Knepley gcoords = &coords[dE * Nq]; 16919566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE * q], PETSC_TRUE, dE, &coords[dE * q], gcoords, dm->transformCtx)); 1692d3a7d86cSMatthew G. Knepley } else { 1693083401c6SMatthew G. Knepley gcoords = &coords[dE * q]; 1694d3a7d86cSMatthew G. Knepley } 16952df84da0SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) funcVal[fc] = 0.; 1696083401c6SMatthew G. Knepley ierr = (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx); 1697e735a8a9SMatthew G. Knepley if (ierr) { 16989566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 16999566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 17009566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1701e735a8a9SMatthew G. Knepley } 17029566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[dE * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 170396959cd1SMatthew G. Knepley /* Call once for each face, except for lagrange field */ 17049566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fOff], &qgeom, q, interpolant)); 17059566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fOff], q, interpolant)); 170663a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 170715496722SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1708beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 17099371c9d4SSatish Balay if (debug) 17109371c9d4SSatish 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.), 17119371c9d4SSatish Balay (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]))); 17124bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 171373d901b8SMatthew G. Knepley } 171473d901b8SMatthew G. Knepley } 1715083401c6SMatthew G. Knepley fOff += Nb; 17169c3cf19fSMatthew G. Knepley qc += Nc; 1717083401c6SMatthew G. Knepley localDiff[fields[f]] += elemDiff; 171863a3b9bcSJacob 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]])); 171973d901b8SMatthew G. Knepley } 17209566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 1721083401c6SMatthew G. Knepley } 1722083401c6SMatthew G. Knepley if (label) { 17239566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 17249566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 1725083401c6SMatthew G. Knepley } 17269566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(fieldIS, &fields)); 17279566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 172873d901b8SMatthew G. Knepley } 17299566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 17301c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 17319566063dSJacob Faibussowitsch PetscCall(PetscFree(localDiff)); 1732083401c6SMatthew G. Knepley for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]); 17333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 173473d901b8SMatthew G. Knepley } 173573d901b8SMatthew G. Knepley 1736e729f68cSMatthew G. Knepley /*@C 1737e729f68cSMatthew 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. 1738e729f68cSMatthew G. Knepley 173920f4b53cSBarry Smith Collective 1740c0f8e1fdSMatthew G. Knepley 1741e729f68cSMatthew G. Knepley Input Parameters: 1742a1cb98faSBarry Smith + dm - The `DM` 17430163fd50SMatthew G. Knepley . time - The time 174420f4b53cSBarry Smith . funcs - The functions to evaluate for each field component: `NULL` means that component does not contribute to error calculation 174520f4b53cSBarry Smith . ctxs - Optional array of contexts to pass to each function, or `NULL`. 1746e729f68cSMatthew G. Knepley - X - The coefficient vector u_h 1747e729f68cSMatthew G. Knepley 1748e729f68cSMatthew G. Knepley Output Parameter: 174920f4b53cSBarry Smith . D - A `Vec` which holds the difference ||u - u_h||_2 for each cell 1750e729f68cSMatthew G. Knepley 1751e729f68cSMatthew G. Knepley Level: developer 1752e729f68cSMatthew G. Knepley 17531cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1754e729f68cSMatthew G. Knepley @*/ 1755d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D) 1756d71ae5a4SJacob Faibussowitsch { 1757e729f68cSMatthew G. Knepley PetscSection section; 1758e729f68cSMatthew G. Knepley PetscQuadrature quad; 1759e729f68cSMatthew G. Knepley Vec localX; 17604bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 1761e729f68cSMatthew G. Knepley PetscScalar *funcVal, *interpolant; 17624bee2e38SMatthew G. Knepley PetscReal *coords; 1763e729f68cSMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1764485ad865SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset; 1765e729f68cSMatthew G. Knepley 1766e729f68cSMatthew G. Knepley PetscFunctionBegin; 17679566063dSJacob Faibussowitsch PetscCall(VecSet(D, 0.0)); 17689566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 17699566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 17709566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 17719566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 17729566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 17739566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 17749566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 17759566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1776e729f68cSMatthew G. Knepley for (field = 0; field < numFields; ++field) { 1777e729f68cSMatthew G. Knepley PetscObject obj; 1778e729f68cSMatthew G. Knepley PetscClassId id; 1779e729f68cSMatthew G. Knepley PetscInt Nc; 1780e729f68cSMatthew G. Knepley 17819566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 17829566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 1783e729f68cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 1784e729f68cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 1785e729f68cSMatthew G. Knepley 17869566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 17879566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1788e729f68cSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 1789e729f68cSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 1790e729f68cSMatthew G. Knepley 17919566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 17929566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 179363a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1794e729f68cSMatthew G. Knepley numComponents += Nc; 1795e729f68cSMatthew G. Knepley } 17969566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 179763a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 17989566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 17999566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1800e729f68cSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1801e729f68cSMatthew G. Knepley PetscScalar *x = NULL; 18026f288a59SMatthew G. Knepley PetscScalar elemDiff = 0.0; 18039c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1804e729f68cSMatthew G. Knepley 18059566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1806e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 1807e729f68cSMatthew G. Knepley 1808e729f68cSMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1809e729f68cSMatthew G. Knepley PetscObject obj; 1810e729f68cSMatthew G. Knepley PetscClassId id; 1811e729f68cSMatthew G. Knepley void *const ctx = ctxs ? ctxs[field] : NULL; 1812e729f68cSMatthew G. Knepley PetscInt Nb, Nc, q, fc; 1813e729f68cSMatthew G. Knepley 18149566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 18159566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 18169371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 18179371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 18189371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 18199371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 18209371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 18219371c9d4SSatish Balay Nb = 1; 18229371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 182323f34ed2SToby Isaac if (funcs[field]) { 18247318780aSToby Isaac for (q = 0; q < Nq; ++q) { 18252a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 18262a4e142eSMatthew G. Knepley 18272a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 18282a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 18292a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 18302a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 183163a3b9bcSJacob 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); 18329566063dSJacob Faibussowitsch PetscCall((*funcs[field])(coordDim, time, &coords[q * coordDim], Nc, funcVal, ctx)); 1833c3e24edfSBarry Smith #if defined(needs_fix_with_return_code_argument) 1834e735a8a9SMatthew G. Knepley if (ierr) { 18359566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 18369566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 18379566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 1838e735a8a9SMatthew G. Knepley } 1839c3e24edfSBarry Smith #endif 18409566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 18419566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 184263a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1843e729f68cSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1844beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 18454bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1846e729f68cSMatthew G. Knepley } 1847e729f68cSMatthew G. Knepley } 184823f34ed2SToby Isaac } 1849beaa55a6SMatthew G. Knepley fieldOffset += Nb; 18509c3cf19fSMatthew G. Knepley qc += Nc; 1851e729f68cSMatthew G. Knepley } 18529566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 18539566063dSJacob Faibussowitsch PetscCall(VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES)); 1854e729f68cSMatthew G. Knepley } 18559566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 18569566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 18579566063dSJacob Faibussowitsch PetscCall(VecSqrtAbs(D)); 18583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1859e729f68cSMatthew G. Knepley } 1860e729f68cSMatthew G. Knepley 18615f0b18bfSMatthew G. Knepley /*@ 186220f4b53cSBarry Smith DMPlexComputeClementInterpolant - This function computes the L2 projection of the cellwise values of a function u onto P1 18635f0b18bfSMatthew G. Knepley 186420f4b53cSBarry Smith Collective 18655f0b18bfSMatthew G. Knepley 18665f0b18bfSMatthew G. Knepley Input Parameters: 1867a1cb98faSBarry Smith + dm - The `DM` 18685f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h 18695f0b18bfSMatthew G. Knepley 18705f0b18bfSMatthew G. Knepley Output Parameter: 1871a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the function 18725f0b18bfSMatthew G. Knepley 18735f0b18bfSMatthew G. Knepley Level: developer 18745f0b18bfSMatthew G. Knepley 1875a1cb98faSBarry Smith Note: 1876a1cb98faSBarry 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 1877a1cb98faSBarry Smith 18781cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 18795f0b18bfSMatthew G. Knepley @*/ 1880d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeClementInterpolant(DM dm, Vec locX, Vec locC) 1881d71ae5a4SJacob Faibussowitsch { 18825f0b18bfSMatthew G. Knepley PetscInt debug = ((DM_Plex *)dm->data)->printFEM; 18835f0b18bfSMatthew G. Knepley DM dmc; 18845f0b18bfSMatthew G. Knepley PetscQuadrature quad; 18855f0b18bfSMatthew G. Knepley PetscScalar *interpolant, *valsum; 18865f0b18bfSMatthew G. Knepley PetscFEGeom fegeom; 18875f0b18bfSMatthew G. Knepley PetscReal *coords; 18885f0b18bfSMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 18895f0b18bfSMatthew G. Knepley PetscInt dim, cdim, Nf, f, Nc = 0, Nq, qNc, cStart, cEnd, vStart, vEnd, v; 18905f0b18bfSMatthew G. Knepley 18915f0b18bfSMatthew G. Knepley PetscFunctionBegin; 18929566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 18939566063dSJacob Faibussowitsch PetscCall(VecGetDM(locC, &dmc)); 18949566063dSJacob Faibussowitsch PetscCall(VecSet(locC, 0.0)); 18959566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 18969566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 18975f0b18bfSMatthew G. Knepley fegeom.dimEmbed = cdim; 18989566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 18995f0b18bfSMatthew G. Knepley PetscCheck(Nf > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 19005f0b18bfSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 19015f0b18bfSMatthew G. Knepley PetscObject obj; 19025f0b18bfSMatthew G. Knepley PetscClassId id; 19035f0b18bfSMatthew G. Knepley PetscInt fNc; 19045f0b18bfSMatthew G. Knepley 19059566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, f, NULL, &obj)); 19069566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 19075f0b18bfSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 19085f0b18bfSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 19095f0b18bfSMatthew G. Knepley 19109566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 19119566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &fNc)); 19125f0b18bfSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 19135f0b18bfSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 19145f0b18bfSMatthew G. Knepley 19159566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 19169566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &fNc)); 191763a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 19185f0b18bfSMatthew G. Knepley Nc += fNc; 19195f0b18bfSMatthew G. Knepley } 19209566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 192163a3b9bcSJacob Faibussowitsch PetscCheck(qNc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " > 1", qNc); 19229566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(Nc * 2, &valsum, Nc, &interpolant, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ)); 19239566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 19249566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 19255f0b18bfSMatthew G. Knepley for (v = vStart; v < vEnd; ++v) { 19265f0b18bfSMatthew G. Knepley PetscScalar volsum = 0.0; 19275f0b18bfSMatthew G. Knepley PetscInt *star = NULL; 19285f0b18bfSMatthew G. Knepley PetscInt starSize, st, fc; 19295f0b18bfSMatthew G. Knepley 19309566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(valsum, Nc)); 19319566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 19325f0b18bfSMatthew G. Knepley for (st = 0; st < starSize * 2; st += 2) { 19335f0b18bfSMatthew G. Knepley const PetscInt cell = star[st]; 19345f0b18bfSMatthew G. Knepley PetscScalar *val = &valsum[Nc]; 19355f0b18bfSMatthew G. Knepley PetscScalar *x = NULL; 19365f0b18bfSMatthew G. Knepley PetscReal vol = 0.0; 19375f0b18bfSMatthew G. Knepley PetscInt foff = 0; 19385f0b18bfSMatthew G. Knepley 19395f0b18bfSMatthew G. Knepley if ((cell < cStart) || (cell >= cEnd)) continue; 19409566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 19419566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 19425f0b18bfSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 19435f0b18bfSMatthew G. Knepley PetscObject obj; 19445f0b18bfSMatthew G. Knepley PetscClassId id; 19455f0b18bfSMatthew G. Knepley PetscInt Nb, fNc, q; 19465f0b18bfSMatthew G. Knepley 19479566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(val, Nc)); 19489566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, f, NULL, &obj)); 19499566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 19509371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 19519371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &fNc)); 19529371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 19539371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 19549371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &fNc)); 19559371c9d4SSatish Balay Nb = 1; 19569371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 19575f0b18bfSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 19585f0b18bfSMatthew G. Knepley const PetscReal wt = quadWeights[q] * fegeom.detJ[q]; 19595f0b18bfSMatthew G. Knepley PetscFEGeom qgeom; 19605f0b18bfSMatthew G. Knepley 19615f0b18bfSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 19625f0b18bfSMatthew G. Knepley qgeom.J = &fegeom.J[q * cdim * cdim]; 19635f0b18bfSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * cdim * cdim]; 19645f0b18bfSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 196563a3b9bcSJacob 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); 19669566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[foff], &qgeom, q, interpolant)); 196763a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 19685f0b18bfSMatthew G. Knepley for (fc = 0; fc < fNc; ++fc) val[foff + fc] += interpolant[fc] * wt; 19695f0b18bfSMatthew G. Knepley vol += wt; 19705f0b18bfSMatthew G. Knepley } 19715f0b18bfSMatthew G. Knepley foff += Nb; 19725f0b18bfSMatthew G. Knepley } 19739566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 19745f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) valsum[fc] += val[fc]; 19755f0b18bfSMatthew G. Knepley volsum += vol; 19765f0b18bfSMatthew G. Knepley if (debug) { 19779566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " value: [", v, cell)); 19785f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 19799566063dSJacob Faibussowitsch if (fc) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 19809566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(val[fc]))); 19815f0b18bfSMatthew G. Knepley } 19829566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 19835f0b18bfSMatthew G. Knepley } 19845f0b18bfSMatthew G. Knepley } 19855f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) valsum[fc] /= volsum; 19869566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 19879566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dmc, NULL, locC, v, valsum, INSERT_VALUES)); 19885f0b18bfSMatthew G. Knepley } 19899566063dSJacob Faibussowitsch PetscCall(PetscFree6(valsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 19903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 19915f0b18bfSMatthew G. Knepley } 19925f0b18bfSMatthew G. Knepley 19935f0b18bfSMatthew G. Knepley /*@ 199420f4b53cSBarry Smith DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1 19951555c271SMatthew G. Knepley 199620f4b53cSBarry Smith Collective 1997c0f8e1fdSMatthew G. Knepley 19981555c271SMatthew G. Knepley Input Parameters: 1999a1cb98faSBarry Smith + dm - The `DM` 20005f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h 20011555c271SMatthew G. Knepley 20021555c271SMatthew G. Knepley Output Parameter: 2003a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the gradient 20041555c271SMatthew G. Knepley 20051555c271SMatthew G. Knepley Level: developer 20061555c271SMatthew G. Knepley 2007a1cb98faSBarry Smith Note: 2008a1cb98faSBarry 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 2009a1cb98faSBarry Smith 20101cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 20111555c271SMatthew G. Knepley @*/ 2012d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC) 2013d71ae5a4SJacob Faibussowitsch { 2014db1066baSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2015db1066baSMatthew G. Knepley PetscInt debug = mesh->printFEM; 20161555c271SMatthew G. Knepley DM dmC; 20171555c271SMatthew G. Knepley PetscQuadrature quad; 20181555c271SMatthew G. Knepley PetscScalar *interpolant, *gradsum; 20194bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 20204bee2e38SMatthew G. Knepley PetscReal *coords; 20211555c271SMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 2022485ad865SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset; 20231555c271SMatthew G. Knepley 20241555c271SMatthew G. Knepley PetscFunctionBegin; 20259566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 20269566063dSJacob Faibussowitsch PetscCall(VecGetDM(locC, &dmC)); 20279566063dSJacob Faibussowitsch PetscCall(VecSet(locC, 0.0)); 20289566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 20299566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 20304bee2e38SMatthew G. Knepley fegeom.dimEmbed = coordDim; 20319566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 20325f80ce2aSJacob Faibussowitsch PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 20331555c271SMatthew G. Knepley for (field = 0; field < numFields; ++field) { 20341555c271SMatthew G. Knepley PetscObject obj; 20351555c271SMatthew G. Knepley PetscClassId id; 20361555c271SMatthew G. Knepley PetscInt Nc; 20371555c271SMatthew G. Knepley 20389566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 20399566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 20401555c271SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 20411555c271SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 20421555c271SMatthew G. Knepley 20439566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 20449566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 20451555c271SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 20461555c271SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 20471555c271SMatthew G. Knepley 20489566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 20499566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 205063a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 20511555c271SMatthew G. Knepley numComponents += Nc; 20521555c271SMatthew G. Knepley } 20539566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 205463a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 20559566063dSJacob 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)); 20569566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 20579566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 20581555c271SMatthew G. Knepley for (v = vStart; v < vEnd; ++v) { 20591555c271SMatthew G. Knepley PetscScalar volsum = 0.0; 20601555c271SMatthew G. Knepley PetscInt *star = NULL; 20611555c271SMatthew G. Knepley PetscInt starSize, st, d, fc; 20621555c271SMatthew G. Knepley 20639566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(gradsum, coordDim * numComponents)); 20649566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 20651555c271SMatthew G. Knepley for (st = 0; st < starSize * 2; st += 2) { 20661555c271SMatthew G. Knepley const PetscInt cell = star[st]; 20671555c271SMatthew G. Knepley PetscScalar *grad = &gradsum[coordDim * numComponents]; 20681555c271SMatthew G. Knepley PetscScalar *x = NULL; 20691555c271SMatthew G. Knepley PetscReal vol = 0.0; 20701555c271SMatthew G. Knepley 20711555c271SMatthew G. Knepley if ((cell < cStart) || (cell >= cEnd)) continue; 20729566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 20739566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 20741555c271SMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 20751555c271SMatthew G. Knepley PetscObject obj; 20761555c271SMatthew G. Knepley PetscClassId id; 20771555c271SMatthew G. Knepley PetscInt Nb, Nc, q, qc = 0; 20781555c271SMatthew G. Knepley 20799566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(grad, coordDim * numComponents)); 20809566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 20819566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 20829371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 20839371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 20849371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 20859371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 20869371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 20879371c9d4SSatish Balay Nb = 1; 20889371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 20891555c271SMatthew G. Knepley for (q = 0; q < Nq; ++q) { 20902a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 20912a4e142eSMatthew G. Knepley 20922a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 20932a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 20942a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 20952a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 209663a3b9bcSJacob 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); 20979566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolateGradient_Static((PetscFE)obj, 1, &x[fieldOffset], &qgeom, q, interpolant)); 209863a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 20991555c271SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 210053d2db2dSJoe Wallwork const PetscReal wt = quadWeights[q * qNc + qc]; 21011555c271SMatthew G. Knepley 21024bee2e38SMatthew G. Knepley for (d = 0; d < coordDim; ++d) grad[fc * coordDim + d] += interpolant[fc * dim + d] * wt * fegeom.detJ[q]; 21031555c271SMatthew G. Knepley } 21044bee2e38SMatthew G. Knepley vol += quadWeights[q * qNc] * fegeom.detJ[q]; 21051555c271SMatthew G. Knepley } 21061555c271SMatthew G. Knepley fieldOffset += Nb; 21071555c271SMatthew G. Knepley qc += Nc; 21081555c271SMatthew G. Knepley } 21099566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 2110f8527842SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 2111ad540459SPierre Jolivet for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] += grad[fc * coordDim + d]; 2112f8527842SMatthew G. Knepley } 2113f8527842SMatthew G. Knepley volsum += vol; 2114db1066baSMatthew G. Knepley if (debug) { 21159566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " gradient: [", v, cell)); 21161555c271SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 21171555c271SMatthew G. Knepley for (d = 0; d < coordDim; ++d) { 21189566063dSJacob Faibussowitsch if (fc || d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 21199566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc * coordDim + d]))); 21201555c271SMatthew G. Knepley } 21211555c271SMatthew G. Knepley } 21229566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 2123db1066baSMatthew G. Knepley } 21241555c271SMatthew G. Knepley } 21251555c271SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 21261555c271SMatthew G. Knepley for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] /= volsum; 21271555c271SMatthew G. Knepley } 21289566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 21299566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES)); 21301555c271SMatthew G. Knepley } 21319566063dSJacob Faibussowitsch PetscCall(PetscFree6(gradsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 21323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 21331555c271SMatthew G. Knepley } 21341555c271SMatthew G. Knepley 2135d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user) 2136d71ae5a4SJacob Faibussowitsch { 2137338f77d5SMatthew G. Knepley DM dmAux = NULL; 213861aaff12SToby Isaac PetscDS prob, probAux = NULL; 213973d901b8SMatthew G. Knepley PetscSection section, sectionAux; 2140338f77d5SMatthew G. Knepley Vec locX, locA; 2141c330f8ffSToby Isaac PetscInt dim, numCells = cEnd - cStart, c, f; 2142c330f8ffSToby Isaac PetscBool useFVM = PETSC_FALSE; 2143338f77d5SMatthew G. Knepley /* DS */ 2144338f77d5SMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x, numConstants; 2145338f77d5SMatthew G. Knepley PetscInt NfAux, totDimAux, *aOff; 2146338f77d5SMatthew G. Knepley PetscScalar *u, *a; 2147338f77d5SMatthew G. Knepley const PetscScalar *constants; 2148338f77d5SMatthew G. Knepley /* Geometry */ 2149c330f8ffSToby Isaac PetscFEGeom *cgeomFEM; 2150338f77d5SMatthew G. Knepley DM dmGrad; 2151c330f8ffSToby Isaac PetscQuadrature affineQuad = NULL; 2152338f77d5SMatthew G. Knepley Vec cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 2153b5a3613cSMatthew G. Knepley PetscFVCellGeom *cgeomFVM; 2154338f77d5SMatthew G. Knepley const PetscScalar *lgrad; 2155b7260050SToby Isaac PetscInt maxDegree; 2156c330f8ffSToby Isaac DMField coordField; 2157c330f8ffSToby Isaac IS cellIS; 215873d901b8SMatthew G. Knepley 215973d901b8SMatthew G. Knepley PetscFunctionBegin; 21609566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 21619566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 21629566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 21639566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 2164338f77d5SMatthew G. Knepley /* Determine which discretizations we have */ 2165b5a3613cSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2166b5a3613cSMatthew G. Knepley PetscObject obj; 2167b5a3613cSMatthew G. Knepley PetscClassId id; 2168b5a3613cSMatthew G. Knepley 21699566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 21709566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2171338f77d5SMatthew G. Knepley if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE; 2172338f77d5SMatthew G. Knepley } 2173338f77d5SMatthew G. Knepley /* Get local solution with boundary values */ 21749566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &locX)); 21759566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 21769566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 21779566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 2178338f77d5SMatthew G. Knepley /* Read DS information */ 21799566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 21809566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 21819566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 21829566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, numCells, cStart, 1, &cellIS)); 21839566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 2184338f77d5SMatthew G. Knepley /* Read Auxiliary DS information */ 21859566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 21869a2a23afSMatthew G. Knepley if (locA) { 21879566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 21889566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 21899566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 21909566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 21919566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 21929566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 2193338f77d5SMatthew G. Knepley } 2194338f77d5SMatthew G. Knepley /* Allocate data arrays */ 21959566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numCells * totDim, &u)); 21969566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 2197338f77d5SMatthew G. Knepley /* Read out geometry */ 21989566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 21999566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 2200b7260050SToby Isaac if (maxDegree <= 1) { 22019566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 220248a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &cgeomFEM)); 2203b5a3613cSMatthew G. Knepley } 2204b5a3613cSMatthew G. Knepley if (useFVM) { 2205338f77d5SMatthew G. Knepley PetscFV fv = NULL; 2206b5a3613cSMatthew G. Knepley Vec grad; 2207b5a3613cSMatthew G. Knepley PetscInt fStart, fEnd; 2208b5a3613cSMatthew G. Knepley PetscBool compGrad; 2209b5a3613cSMatthew G. Knepley 2210338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2211338f77d5SMatthew G. Knepley PetscObject obj; 2212338f77d5SMatthew G. Knepley PetscClassId id; 2213338f77d5SMatthew G. Knepley 22149566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 22159566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 22169371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 22179371c9d4SSatish Balay fv = (PetscFV)obj; 22189371c9d4SSatish Balay break; 22199371c9d4SSatish Balay } 2220338f77d5SMatthew G. Knepley } 22219566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &compGrad)); 22229566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, PETSC_TRUE)); 22239566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM)); 22249566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad)); 22259566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, compGrad)); 22269566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 2227b5a3613cSMatthew G. Knepley /* Reconstruct and limit cell gradients */ 22289566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 22299566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmGrad, &grad)); 22309566063dSJacob Faibussowitsch PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 2231b5a3613cSMatthew G. Knepley /* Communicate gradient values */ 22329566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 22339566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 22349566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 22359566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 2236b5a3613cSMatthew G. Knepley /* Handle non-essential (e.g. outflow) boundary values */ 22379566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad)); 22389566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 2239b5a3613cSMatthew G. Knepley } 2240338f77d5SMatthew G. Knepley /* Read out data from inputs */ 224173d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 224273d901b8SMatthew G. Knepley PetscScalar *x = NULL; 224373d901b8SMatthew G. Knepley PetscInt i; 224473d901b8SMatthew G. Knepley 22459566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, c, NULL, &x)); 22460f2d7e86SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 22479566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x)); 224873d901b8SMatthew G. Knepley if (dmAux) { 22499566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x)); 22500f2d7e86SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 22519566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x)); 225273d901b8SMatthew G. Knepley } 225373d901b8SMatthew G. Knepley } 2254338f77d5SMatthew G. Knepley /* Do integration for each field */ 225573d901b8SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2256c1f031eeSMatthew G. Knepley PetscObject obj; 2257c1f031eeSMatthew G. Knepley PetscClassId id; 2258c1f031eeSMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 225973d901b8SMatthew G. Knepley 22609566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 22619566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2262c1f031eeSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 2263c1f031eeSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2264c1f031eeSMatthew G. Knepley PetscQuadrature q; 2265c330f8ffSToby Isaac PetscFEGeom *chunkGeom = NULL; 2266c1f031eeSMatthew G. Knepley PetscInt Nq, Nb; 2267c1f031eeSMatthew G. Knepley 22689566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 22699566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 22709566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 22719566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 2272c1f031eeSMatthew G. Knepley blockSize = Nb * Nq; 227373d901b8SMatthew G. Knepley batchSize = numBlocks * blockSize; 22749566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 227573d901b8SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 227673d901b8SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 227773d901b8SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 227873d901b8SMatthew G. Knepley offset = numCells - Nr; 227948a46eb9SPierre Jolivet if (!affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, q, PETSC_FALSE, &cgeomFEM)); 22809566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 22819566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral)); 22829566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &chunkGeom)); 22839566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset * totDim], probAux, &a[offset * totDimAux], &cintegral[offset * Nf])); 22849566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &chunkGeom)); 228548a46eb9SPierre Jolivet if (!affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 2286c1f031eeSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 2287c1f031eeSMatthew G. Knepley PetscInt foff; 2288420e96edSMatthew G. Knepley PetscPointFunc obj_func; 2289b69edc29SMatthew G. Knepley PetscScalar lint; 2290c1f031eeSMatthew G. Knepley 22919566063dSJacob Faibussowitsch PetscCall(PetscDSGetObjective(prob, f, &obj_func)); 22929566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, f, &foff)); 2293c1f031eeSMatthew G. Knepley if (obj_func) { 2294c1f031eeSMatthew G. Knepley for (c = 0; c < numCells; ++c) { 2295b5a3613cSMatthew G. Knepley PetscScalar *u_x; 2296b5a3613cSMatthew G. Knepley 22979566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x)); 2298338f77d5SMatthew 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); 2299338f77d5SMatthew G. Knepley cintegral[c * Nf + f] += PetscRealPart(lint) * cgeomFVM[c].volume; 230073d901b8SMatthew G. Knepley } 2301c1f031eeSMatthew G. Knepley } 230263a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 2303c1f031eeSMatthew G. Knepley } 2304338f77d5SMatthew G. Knepley /* Cleanup data arrays */ 2305b5a3613cSMatthew G. Knepley if (useFVM) { 23069566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 23079566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 23089566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 23099566063dSJacob Faibussowitsch PetscCall(VecDestroy(&faceGeometryFVM)); 23109566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cellGeometryFVM)); 23119566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dmGrad)); 2312b5a3613cSMatthew G. Knepley } 23139566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscFree(a)); 23149566063dSJacob Faibussowitsch PetscCall(PetscFree(u)); 2315338f77d5SMatthew G. Knepley /* Cleanup */ 231648a46eb9SPierre Jolivet if (affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 23179566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 23189566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 23199566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &locX)); 23203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2321338f77d5SMatthew G. Knepley } 2322338f77d5SMatthew G. Knepley 2323338f77d5SMatthew G. Knepley /*@ 2324338f77d5SMatthew G. Knepley DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user 2325338f77d5SMatthew G. Knepley 2326338f77d5SMatthew G. Knepley Input Parameters: 2327338f77d5SMatthew G. Knepley + dm - The mesh 2328338f77d5SMatthew G. Knepley . X - Global input vector 2329338f77d5SMatthew G. Knepley - user - The user context 2330338f77d5SMatthew G. Knepley 2331338f77d5SMatthew G. Knepley Output Parameter: 2332338f77d5SMatthew G. Knepley . integral - Integral for each field 2333338f77d5SMatthew G. Knepley 2334338f77d5SMatthew G. Knepley Level: developer 2335338f77d5SMatthew G. Knepley 23361cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2337338f77d5SMatthew G. Knepley @*/ 2338d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user) 2339d71ae5a4SJacob Faibussowitsch { 2340338f77d5SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2341b8feb594SMatthew G. Knepley PetscScalar *cintegral, *lintegral; 2342412e9a14SMatthew G. Knepley PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 2343338f77d5SMatthew G. Knepley 2344338f77d5SMatthew G. Knepley PetscFunctionBegin; 2345338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2346338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 23474f572ea9SToby Isaac PetscAssertPointer(integral, 3); 23489566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 23499566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 23509566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 23519566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2352338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 23539566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &lintegral, (cEnd - cStart) * Nf, &cintegral)); 23549566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user)); 2355338f77d5SMatthew G. Knepley /* Sum up values */ 2356338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2357338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 2358338f77d5SMatthew G. Knepley 23599566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 2360b8feb594SMatthew G. Knepley for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c * Nf + f]; 2361338f77d5SMatthew G. Knepley } 23621c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 236373d901b8SMatthew G. Knepley if (mesh->printFEM) { 23649566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Integral:")); 23659566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), " %g", (double)PetscRealPart(integral[f]))); 23669566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "\n")); 236773d901b8SMatthew G. Knepley } 23689566063dSJacob Faibussowitsch PetscCall(PetscFree2(lintegral, cintegral)); 23699566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 23703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2371338f77d5SMatthew G. Knepley } 2372338f77d5SMatthew G. Knepley 2373338f77d5SMatthew G. Knepley /*@ 2374338f77d5SMatthew G. Knepley DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user 2375338f77d5SMatthew G. Knepley 2376338f77d5SMatthew G. Knepley Input Parameters: 2377338f77d5SMatthew G. Knepley + dm - The mesh 2378338f77d5SMatthew G. Knepley . X - Global input vector 2379338f77d5SMatthew G. Knepley - user - The user context 2380338f77d5SMatthew G. Knepley 2381338f77d5SMatthew G. Knepley Output Parameter: 238260225df5SJacob Faibussowitsch . F - Cellwise integrals for each field 2383338f77d5SMatthew G. Knepley 2384338f77d5SMatthew G. Knepley Level: developer 2385338f77d5SMatthew G. Knepley 23861cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2387338f77d5SMatthew G. Knepley @*/ 2388d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user) 2389d71ae5a4SJacob Faibussowitsch { 2390338f77d5SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2391338f77d5SMatthew G. Knepley DM dmF; 2392338f77d5SMatthew G. Knepley PetscSection sectionF; 2393338f77d5SMatthew G. Knepley PetscScalar *cintegral, *af; 2394412e9a14SMatthew G. Knepley PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 2395338f77d5SMatthew G. Knepley 2396338f77d5SMatthew G. Knepley PetscFunctionBegin; 2397338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2398338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2399338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(F, VEC_CLASSID, 3); 24009566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 24019566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 24029566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 24039566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2404338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 24059566063dSJacob Faibussowitsch PetscCall(PetscCalloc1((cEnd - cStart) * Nf, &cintegral)); 24069566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user)); 2407338f77d5SMatthew G. Knepley /* Put values in F*/ 24089566063dSJacob Faibussowitsch PetscCall(VecGetDM(F, &dmF)); 24099566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmF, §ionF)); 24109566063dSJacob Faibussowitsch PetscCall(VecGetArray(F, &af)); 2411338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2412338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 2413338f77d5SMatthew G. Knepley PetscInt dof, off; 2414338f77d5SMatthew G. Knepley 24159566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 24169566063dSJacob Faibussowitsch PetscCall(PetscSectionGetDof(sectionF, cell, &dof)); 24179566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(sectionF, cell, &off)); 241863a3b9bcSJacob Faibussowitsch PetscCheck(dof == Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %" PetscInt_FMT " != %" PetscInt_FMT, dof, Nf); 2419338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) af[off + f] = cintegral[c * Nf + f]; 2420338f77d5SMatthew G. Knepley } 24219566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(F, &af)); 24229566063dSJacob Faibussowitsch PetscCall(PetscFree(cintegral)); 24239566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 24243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 242573d901b8SMatthew G. Knepley } 242673d901b8SMatthew G. Knepley 2427d71ae5a4SJacob 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) 2428d71ae5a4SJacob Faibussowitsch { 24299b6f715bSMatthew G. Knepley DM plex = NULL, plexA = NULL; 2430a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 24319b6f715bSMatthew G. Knepley PetscDS prob, probAux = NULL; 24329b6f715bSMatthew G. Knepley PetscSection section, sectionAux = NULL; 24339b6f715bSMatthew G. Knepley Vec locA = NULL; 24349b6f715bSMatthew G. Knepley DMField coordField; 24359b6f715bSMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x; 24369b6f715bSMatthew G. Knepley PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL; 24379b6f715bSMatthew G. Knepley PetscScalar *u, *a = NULL; 243864c72086SMatthew G. Knepley const PetscScalar *constants; 24399b6f715bSMatthew G. Knepley PetscInt numConstants, f; 244064c72086SMatthew G. Knepley 244164c72086SMatthew G. Knepley PetscFunctionBegin; 24429566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 24439566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 24449566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 24459566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 24469566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 244764c72086SMatthew G. Knepley /* Determine which discretizations we have */ 24489b6f715bSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 244964c72086SMatthew G. Knepley PetscObject obj; 245064c72086SMatthew G. Knepley PetscClassId id; 245164c72086SMatthew G. Knepley 24529566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 24539566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 245463a3b9bcSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not supported for FVM (field %" PetscInt_FMT ")", f); 245564c72086SMatthew G. Knepley } 245664c72086SMatthew G. Knepley /* Read DS information */ 24579566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 24589566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 24599566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 24609566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 246164c72086SMatthew G. Knepley /* Read Auxiliary DS information */ 24629566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 24639b6f715bSMatthew G. Knepley if (locA) { 24649b6f715bSMatthew G. Knepley DM dmAux; 24659b6f715bSMatthew G. Knepley 24669566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 24679566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 24689566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 24699566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 24709566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 24719566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 24729566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 24739566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 247464c72086SMatthew G. Knepley } 24759b6f715bSMatthew G. Knepley /* Integrate over points */ 24769b6f715bSMatthew G. Knepley { 24779b6f715bSMatthew G. Knepley PetscFEGeom *fgeom, *chunkGeom = NULL; 2478b7260050SToby Isaac PetscInt maxDegree; 24799b6f715bSMatthew G. Knepley PetscQuadrature qGeom = NULL; 24809b6f715bSMatthew G. Knepley const PetscInt *points; 24819b6f715bSMatthew G. Knepley PetscInt numFaces, face, Nq, field; 24829b6f715bSMatthew G. Knepley PetscInt numChunks, chunkSize, chunk, Nr, offset; 248364c72086SMatthew G. Knepley 24849566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 24859566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 24869566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFaces * totDim, &u, locA ? numFaces * totDimAux : 0, &a)); 24879566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 248864c72086SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 248964c72086SMatthew G. Knepley PetscFE fe; 249064c72086SMatthew G. Knepley 24919566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe)); 24929566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 24939b6f715bSMatthew G. Knepley if (!qGeom) { 24949566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 24959566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 24969b6f715bSMatthew G. Knepley } 24979566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 24989566063dSJacob Faibussowitsch PetscCall(DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 24999b6f715bSMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 2500f15274beSMatthew Knepley const PetscInt point = points[face], *support; 25019b6f715bSMatthew G. Knepley PetscScalar *x = NULL; 2502f15274beSMatthew Knepley PetscInt i; 25039b6f715bSMatthew G. Knepley 25049566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 25059566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 25069b6f715bSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 25079566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 25089b6f715bSMatthew G. Knepley if (locA) { 25099b6f715bSMatthew G. Knepley PetscInt subp; 25109566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 25119566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 25129b6f715bSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[f * totDimAux + i] = x[i]; 25139566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 25149b6f715bSMatthew G. Knepley } 25159b6f715bSMatthew G. Knepley } 25169b6f715bSMatthew G. Knepley /* Get blocking */ 25179b6f715bSMatthew G. Knepley { 25189b6f715bSMatthew G. Knepley PetscQuadrature q; 25199b6f715bSMatthew G. Knepley PetscInt numBatches, batchSize, numBlocks, blockSize; 25209b6f715bSMatthew G. Knepley PetscInt Nq, Nb; 25219b6f715bSMatthew G. Knepley 25229566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 25239566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 25249566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 25259566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 252664c72086SMatthew G. Knepley blockSize = Nb * Nq; 252764c72086SMatthew G. Knepley batchSize = numBlocks * blockSize; 25289b6f715bSMatthew G. Knepley chunkSize = numBatches * batchSize; 25299566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 25309b6f715bSMatthew G. Knepley numChunks = numFaces / chunkSize; 25319b6f715bSMatthew G. Knepley Nr = numFaces % chunkSize; 253264c72086SMatthew G. Knepley offset = numFaces - Nr; 253364c72086SMatthew G. Knepley } 25349b6f715bSMatthew G. Knepley /* Do integration for each field */ 25359b6f715bSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 25369566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, chunk * chunkSize, (chunk + 1) * chunkSize, &chunkGeom)); 25379566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral)); 25389566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 253964c72086SMatthew G. Knepley } 25409566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 25419566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset * totDim], probAux, a ? &a[offset * totDimAux] : NULL, &fintegral[offset * Nf])); 25429566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 254364c72086SMatthew G. Knepley /* Cleanup data arrays */ 25449566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 25459566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 25469566063dSJacob Faibussowitsch PetscCall(PetscFree2(u, a)); 25479566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 254864c72086SMatthew G. Knepley } 254964c72086SMatthew G. Knepley } 25509566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 25519566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 25523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 25539b6f715bSMatthew G. Knepley } 25549b6f715bSMatthew G. Knepley 255560225df5SJacob Faibussowitsch /*@C 25569b6f715bSMatthew G. Knepley DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user 25579b6f715bSMatthew G. Knepley 25589b6f715bSMatthew G. Knepley Input Parameters: 25599b6f715bSMatthew G. Knepley + dm - The mesh 25609b6f715bSMatthew G. Knepley . X - Global input vector 2561a1cb98faSBarry Smith . label - The boundary `DMLabel` 2562a1cb98faSBarry Smith . numVals - The number of label values to use, or `PETSC_DETERMINE` for all values 2563a1cb98faSBarry Smith . vals - The label values to use, or NULL for all values 256467b8a455SSatish Balay . func - The function to integrate along the boundary 25659b6f715bSMatthew G. Knepley - user - The user context 25669b6f715bSMatthew G. Knepley 25679b6f715bSMatthew G. Knepley Output Parameter: 25689b6f715bSMatthew G. Knepley . integral - Integral for each field 25699b6f715bSMatthew G. Knepley 25709b6f715bSMatthew G. Knepley Level: developer 25719b6f715bSMatthew G. Knepley 25721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeIntegralFEM()`, `DMPlexComputeBdResidualFEM()` 25739b6f715bSMatthew G. Knepley @*/ 2574d71ae5a4SJacob 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) 2575d71ae5a4SJacob Faibussowitsch { 25769b6f715bSMatthew G. Knepley Vec locX; 25779b6f715bSMatthew G. Knepley PetscSection section; 25789b6f715bSMatthew G. Knepley DMLabel depthLabel; 25799b6f715bSMatthew G. Knepley IS facetIS; 25809b6f715bSMatthew G. Knepley PetscInt dim, Nf, f, v; 25819b6f715bSMatthew G. Knepley 25829b6f715bSMatthew G. Knepley PetscFunctionBegin; 25839b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 25849b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2585292bffcbSToby Isaac PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 25864f572ea9SToby Isaac if (vals) PetscAssertPointer(vals, 5); 25874f572ea9SToby Isaac PetscAssertPointer(integral, 7); 25889566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 25899566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 25909566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 25919566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 25929566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 25939566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 25949b6f715bSMatthew G. Knepley /* Get local solution with boundary values */ 25959566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &locX)); 25969566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 25979566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 25989566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 25999b6f715bSMatthew G. Knepley /* Loop over label values */ 26009566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(integral, Nf)); 26019b6f715bSMatthew G. Knepley for (v = 0; v < numVals; ++v) { 26029b6f715bSMatthew G. Knepley IS pointIS; 26039b6f715bSMatthew G. Knepley PetscInt numFaces, face; 26049b6f715bSMatthew G. Knepley PetscScalar *fintegral; 26059b6f715bSMatthew G. Knepley 26069566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, vals[v], &pointIS)); 26079b6f715bSMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 26089b6f715bSMatthew G. Knepley { 26099b6f715bSMatthew G. Knepley IS isectIS; 26109b6f715bSMatthew G. Knepley 26119b6f715bSMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 26129566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 26139566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 26149b6f715bSMatthew G. Knepley pointIS = isectIS; 26159b6f715bSMatthew G. Knepley } 26169566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 26179566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numFaces * Nf, &fintegral)); 26189566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user)); 26199b6f715bSMatthew G. Knepley /* Sum point contributions into integral */ 26209371c9d4SSatish Balay for (f = 0; f < Nf; ++f) 26219371c9d4SSatish Balay for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face * Nf + f]; 26229566063dSJacob Faibussowitsch PetscCall(PetscFree(fintegral)); 26239566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 26249b6f715bSMatthew G. Knepley } 26259566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &locX)); 26269566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 26279566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 26283ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 262964c72086SMatthew G. Knepley } 263064c72086SMatthew G. Knepley 2631d69c5d34SMatthew G. Knepley /*@ 2632a1cb98faSBarry Smith DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse `DM` to a uniformly refined `DM`. 2633d69c5d34SMatthew G. Knepley 2634d69c5d34SMatthew G. Knepley Input Parameters: 2635cf51de39SMatthew G. Knepley + dmc - The coarse mesh 2636cf51de39SMatthew G. Knepley . dmf - The fine mesh 2637cf51de39SMatthew G. Knepley . isRefined - Flag indicating regular refinement, rather than the same topology 2638d69c5d34SMatthew G. Knepley - user - The user context 2639d69c5d34SMatthew G. Knepley 2640d69c5d34SMatthew G. Knepley Output Parameter: 2641934789fcSMatthew G. Knepley . In - The interpolation matrix 2642d69c5d34SMatthew G. Knepley 2643d69c5d34SMatthew G. Knepley Level: developer 2644d69c5d34SMatthew G. Knepley 26451cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()` 2646d69c5d34SMatthew G. Knepley @*/ 2647d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user) 2648d71ae5a4SJacob Faibussowitsch { 2649d69c5d34SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmc->data; 2650d69c5d34SMatthew G. Knepley const char *name = "Interpolator"; 2651d69c5d34SMatthew G. Knepley PetscFE *feRef; 265297c42addSMatthew G. Knepley PetscFV *fvRef; 2653d69c5d34SMatthew G. Knepley PetscSection fsection, fglobalSection; 2654d69c5d34SMatthew G. Knepley PetscSection csection, cglobalSection; 2655d69c5d34SMatthew G. Knepley PetscScalar *elemMat; 2656485ad865SMatthew G. Knepley PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c; 26572ea9c922SToby Isaac PetscInt cTotDim = 0, rTotDim = 0; 2658d69c5d34SMatthew G. Knepley 2659d69c5d34SMatthew G. Knepley PetscFunctionBegin; 26609566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 26619566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 26629566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 26639566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 26649566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 26659566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 26669566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 26679566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 26689566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &feRef, Nf, &fvRef)); 2669d69c5d34SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 26702ea9c922SToby Isaac PetscObject obj, objc; 26712ea9c922SToby Isaac PetscClassId id, idc; 26722ea9c922SToby Isaac PetscInt rNb = 0, Nc = 0, cNb = 0; 2673d69c5d34SMatthew G. Knepley 26749566063dSJacob Faibussowitsch PetscCall(DMGetField(dmf, f, NULL, &obj)); 26759566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 267697c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 267797c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 267897c42addSMatthew G. Knepley 2679cf51de39SMatthew G. Knepley if (isRefined) { 26809566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 2681cf51de39SMatthew G. Knepley } else { 26829566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fe)); 2683cf51de39SMatthew G. Knepley feRef[f] = fe; 2684cf51de39SMatthew G. Knepley } 26859566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &rNb)); 26869566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 268797c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 268897c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 268997c42addSMatthew G. Knepley PetscDualSpace Q; 269097c42addSMatthew G. Knepley 2691cf51de39SMatthew G. Knepley if (isRefined) { 26929566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 2693cf51de39SMatthew G. Knepley } else { 26949566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fv)); 2695cf51de39SMatthew G. Knepley fvRef[f] = fv; 2696cf51de39SMatthew G. Knepley } 26979566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 26989566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &rNb)); 26999566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 27009566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 270197c42addSMatthew G. Knepley } 27029566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, f, NULL, &objc)); 27039566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(objc, &idc)); 27042ea9c922SToby Isaac if (idc == PETSCFE_CLASSID) { 27052ea9c922SToby Isaac PetscFE fe = (PetscFE)objc; 27062ea9c922SToby Isaac 27079566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cNb)); 27082ea9c922SToby Isaac } else if (id == PETSCFV_CLASSID) { 27092ea9c922SToby Isaac PetscFV fv = (PetscFV)obj; 27102ea9c922SToby Isaac PetscDualSpace Q; 27112ea9c922SToby Isaac 27129566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 27139566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &cNb)); 2714d69c5d34SMatthew G. Knepley } 27152ea9c922SToby Isaac rTotDim += rNb; 27162ea9c922SToby Isaac cTotDim += cNb; 27172ea9c922SToby Isaac } 27189566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(rTotDim * cTotDim, &elemMat)); 27199566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, rTotDim * cTotDim)); 2720d69c5d34SMatthew G. Knepley for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 2721d69c5d34SMatthew G. Knepley PetscDualSpace Qref; 2722d69c5d34SMatthew G. Knepley PetscQuadrature f; 2723d69c5d34SMatthew G. Knepley const PetscReal *qpoints, *qweights; 2724d69c5d34SMatthew G. Knepley PetscReal *points; 2725d69c5d34SMatthew G. Knepley PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 2726d69c5d34SMatthew G. Knepley 2727d69c5d34SMatthew G. Knepley /* Compose points from all dual basis functionals */ 272897c42addSMatthew G. Knepley if (feRef[fieldI]) { 27299566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[fieldI], &Qref)); 27309566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[fieldI], &Nc)); 273197c42addSMatthew G. Knepley } else { 27329566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[fieldI], &Qref)); 27339566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[fieldI], &Nc)); 273497c42addSMatthew G. Knepley } 27359566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Qref, &fpdim)); 2736d69c5d34SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 27379566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 27389566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL)); 2739d69c5d34SMatthew G. Knepley npoints += Np; 2740d69c5d34SMatthew G. Knepley } 27419566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints * dim, &points)); 2742d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 27439566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 27449566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL)); 27459371c9d4SSatish Balay for (p = 0; p < Np; ++p, ++k) 27469371c9d4SSatish Balay for (d = 0; d < dim; ++d) points[k * dim + d] = qpoints[p * dim + d]; 2747d69c5d34SMatthew G. Knepley } 2748d69c5d34SMatthew G. Knepley 2749d69c5d34SMatthew G. Knepley for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 275097c42addSMatthew G. Knepley PetscObject obj; 275197c42addSMatthew G. Knepley PetscClassId id; 27529c3cf19fSMatthew G. Knepley PetscInt NcJ = 0, cpdim = 0, j, qNc; 2753d69c5d34SMatthew G. Knepley 27549566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, fieldJ, NULL, &obj)); 27559566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 275697c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 275797c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2758ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 2759d69c5d34SMatthew G. Knepley 2760d69c5d34SMatthew G. Knepley /* Evaluate basis at points */ 27619566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &NcJ)); 27629566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 2763ffe73a53SMatthew G. Knepley /* For now, fields only interpolate themselves */ 2764ffe73a53SMatthew G. Knepley if (fieldI == fieldJ) { 276563a3b9bcSJacob 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); 27669566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation(fe, 1, npoints, points, 0, &T)); 2767d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 27689566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 27699566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 277063a3b9bcSJacob 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); 2771d69c5d34SMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 277236a6d9c0SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2773d172c84bSMatthew G. Knepley /* 2774d172c84bSMatthew G. Knepley cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field 2775d172c84bSMatthew G. Knepley offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields 2776d172c84bSMatthew G. Knepley fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals 2777d172c84bSMatthew G. Knepley qNC, Nc, Ncj, c: Number of components in this field 2778d172c84bSMatthew G. Knepley Np, p: Number of quad points in the fine grid functional i 2779d172c84bSMatthew G. Knepley k: i*Np + p, overall point number for the interpolation 2780d172c84bSMatthew G. Knepley */ 2781ef0bb6c7SMatthew 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]; 278236a6d9c0SMatthew G. Knepley } 2783d69c5d34SMatthew G. Knepley } 2784d69c5d34SMatthew G. Knepley } 27859566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 2786ffe73a53SMatthew G. Knepley } 278797c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 278897c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 278997c42addSMatthew G. Knepley 279097c42addSMatthew G. Knepley /* Evaluate constant function at points */ 27919566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcJ)); 279297c42addSMatthew G. Knepley cpdim = 1; 279397c42addSMatthew G. Knepley /* For now, fields only interpolate themselves */ 279497c42addSMatthew G. Knepley if (fieldI == fieldJ) { 279563a3b9bcSJacob 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); 279697c42addSMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 27979566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 27989566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 279963a3b9bcSJacob 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); 280097c42addSMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 280197c42addSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2802458eb97cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += 1.0 * qweights[p * qNc + c]; 280397c42addSMatthew G. Knepley } 280497c42addSMatthew G. Knepley } 280597c42addSMatthew G. Knepley } 280697c42addSMatthew G. Knepley } 280797c42addSMatthew G. Knepley } 2808d172c84bSMatthew G. Knepley offsetJ += cpdim; 2809d69c5d34SMatthew G. Knepley } 2810d172c84bSMatthew G. Knepley offsetI += fpdim; 28119566063dSJacob Faibussowitsch PetscCall(PetscFree(points)); 2812d69c5d34SMatthew G. Knepley } 28139566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat)); 28147f5b169aSMatthew G. Knepley /* Preallocate matrix */ 28157f5b169aSMatthew G. Knepley { 2816c094ef40SMatthew G. Knepley Mat preallocator; 2817c094ef40SMatthew G. Knepley PetscScalar *vals; 2818c094ef40SMatthew G. Knepley PetscInt *cellCIndices, *cellFIndices; 2819c094ef40SMatthew G. Knepley PetscInt locRows, locCols, cell; 28207f5b169aSMatthew G. Knepley 28219566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 28229566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &preallocator)); 28239566063dSJacob Faibussowitsch PetscCall(MatSetType(preallocator, MATPREALLOCATOR)); 28249566063dSJacob Faibussowitsch PetscCall(MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 28259566063dSJacob Faibussowitsch PetscCall(MatSetUp(preallocator)); 28269566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(rTotDim * cTotDim, &vals, cTotDim, &cellCIndices, rTotDim, &cellFIndices)); 28277f5b169aSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2828cf51de39SMatthew G. Knepley if (isRefined) { 28299566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices)); 28309566063dSJacob Faibussowitsch PetscCall(MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES)); 2831cf51de39SMatthew G. Knepley } else { 2832e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, preallocator, cell, vals, INSERT_VALUES)); 2833cf51de39SMatthew G. Knepley } 28347f5b169aSMatthew G. Knepley } 28359566063dSJacob Faibussowitsch PetscCall(PetscFree3(vals, cellCIndices, cellFIndices)); 28369566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY)); 28379566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY)); 28389566063dSJacob Faibussowitsch PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In)); 28399566063dSJacob Faibussowitsch PetscCall(MatDestroy(&preallocator)); 28407f5b169aSMatthew G. Knepley } 28417f5b169aSMatthew G. Knepley /* Fill matrix */ 28429566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(In)); 2843d69c5d34SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 2844cf51de39SMatthew G. Knepley if (isRefined) { 28459566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES)); 2846cf51de39SMatthew G. Knepley } else { 2847e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, In, c, elemMat, INSERT_VALUES)); 2848cf51de39SMatthew G. Knepley } 2849d69c5d34SMatthew G. Knepley } 28509566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&feRef[f])); 28519566063dSJacob Faibussowitsch PetscCall(PetscFree2(feRef, fvRef)); 28529566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 28539566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 28549566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 28559318fe57SMatthew G. Knepley if (mesh->printFEM > 1) { 28569566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name)); 28572ce66baaSPierre Jolivet PetscCall(MatFilter(In, 1.0e-10, PETSC_FALSE, PETSC_FALSE)); 28589566063dSJacob Faibussowitsch PetscCall(MatView(In, NULL)); 2859d69c5d34SMatthew G. Knepley } 28609566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 28613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2862d69c5d34SMatthew G. Knepley } 28636c73c22cSMatthew G. Knepley 2864d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user) 2865d71ae5a4SJacob Faibussowitsch { 2866bd041c0cSMatthew G. Knepley SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "Laziness"); 2867bd041c0cSMatthew G. Knepley } 2868bd041c0cSMatthew G. Knepley 286968132eb9SMatthew G. Knepley /*@ 2870a1cb98faSBarry Smith DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse `DM` to a non-nested fine `DM`. 287168132eb9SMatthew G. Knepley 287268132eb9SMatthew G. Knepley Input Parameters: 287368132eb9SMatthew G. Knepley + dmf - The fine mesh 287468132eb9SMatthew G. Knepley . dmc - The coarse mesh 287568132eb9SMatthew G. Knepley - user - The user context 287668132eb9SMatthew G. Knepley 287768132eb9SMatthew G. Knepley Output Parameter: 287868132eb9SMatthew G. Knepley . In - The interpolation matrix 287968132eb9SMatthew G. Knepley 288068132eb9SMatthew G. Knepley Level: developer 288168132eb9SMatthew G. Knepley 28821cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()` 288368132eb9SMatthew G. Knepley @*/ 2884d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user) 2885d71ae5a4SJacob Faibussowitsch { 288664e98e1dSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 288764e98e1dSMatthew G. Knepley const char *name = "Interpolator"; 28884ef9d792SMatthew G. Knepley PetscDS prob; 2889a0806964SMatthew G. Knepley Mat interp; 2890a0806964SMatthew G. Knepley PetscSection fsection, globalFSection; 2891a0806964SMatthew G. Knepley PetscSection csection, globalCSection; 2892a0806964SMatthew G. Knepley PetscInt locRows, locCols; 28934ef9d792SMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 28944ef9d792SMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 28954ef9d792SMatthew G. Knepley PetscScalar *elemMat; 2896a0806964SMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell, s; 28974ef9d792SMatthew G. Knepley 28984ef9d792SMatthew G. Knepley PetscFunctionBegin; 28999566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 29009566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 29019566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 29029566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 29039566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 29049566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 29059566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 29069566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 29079566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 29089566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 29099566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 2910a0806964SMatthew G. Knepley PetscCall(DMPlexGetSimplexOrBoxCells(dmf, 0, &cStart, &cEnd)); 29119566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 29129566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 29134ef9d792SMatthew G. Knepley 2914a0806964SMatthew G. Knepley PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 2915a0806964SMatthew G. Knepley PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &interp)); 2916a0806964SMatthew G. Knepley PetscCall(MatSetType(interp, MATPREALLOCATOR)); 2917a0806964SMatthew G. Knepley PetscCall(MatSetSizes(interp, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 2918a0806964SMatthew G. Knepley PetscCall(MatSetUp(interp)); 2919a0806964SMatthew G. Knepley for (s = 0; s < 2; ++s) { 29204ef9d792SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 29214ef9d792SMatthew G. Knepley PetscObject obj; 29224ef9d792SMatthew G. Knepley PetscClassId id; 2923c0d7054bSMatthew G. Knepley PetscDualSpace Q = NULL; 2924ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 29254ef9d792SMatthew G. Knepley PetscQuadrature f; 29264ef9d792SMatthew G. Knepley const PetscReal *qpoints, *qweights; 2927d0f6233fSMatthew G. Knepley PetscInt Nc, qNc, Np, fpdim, off, i, d; 29284ef9d792SMatthew G. Knepley 2929d0f6233fSMatthew G. Knepley PetscCall(PetscDSGetFieldOffset(prob, field, &off)); 29309566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 29319566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 29324ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 29334ef9d792SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 29344ef9d792SMatthew G. Knepley 29359566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(fe, &Q)); 29369566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 2937a0806964SMatthew G. Knepley if (s) PetscCall(PetscFECreateTabulation(fe, 1, 1, x, 0, &T)); 29384ef9d792SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 29394ef9d792SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 29404ef9d792SMatthew G. Knepley 29419566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 29424ef9d792SMatthew G. Knepley Nc = 1; 294363a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 29449566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fpdim)); 29454ef9d792SMatthew G. Knepley /* For each fine grid cell */ 29464ef9d792SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 29474ef9d792SMatthew G. Knepley PetscInt *findices, *cindices; 29484ef9d792SMatthew G. Knepley PetscInt numFIndices, numCIndices; 29494ef9d792SMatthew G. Knepley 29509566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 29519566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 2952d0f6233fSMatthew 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); 29534ef9d792SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 29544ef9d792SMatthew G. Knepley Vec pointVec; 29554ef9d792SMatthew G. Knepley PetscScalar *pV; 295612111d7cSToby Isaac PetscSF coarseCellSF = NULL; 29573a93e3b7SToby Isaac const PetscSFNode *coarseCells; 2958d0f6233fSMatthew G. Knepley PetscInt numCoarseCells, cpdim, row = findices[i + off], q, c, j; 29594ef9d792SMatthew G. Knepley 29604ef9d792SMatthew G. Knepley /* Get points from the dual basis functional quadrature */ 29619566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Q, i, &f)); 29629566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights)); 296363a3b9bcSJacob 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); 29649566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np * dim, &pointVec)); 29659566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 29669566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 29674ef9d792SMatthew G. Knepley for (q = 0; q < Np; ++q) { 2968c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 2969c330f8ffSToby Isaac 29704ef9d792SMatthew G. Knepley /* Transform point to real space */ 2971c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 29724ef9d792SMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 29734ef9d792SMatthew G. Knepley } 29749566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 29754ef9d792SMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 29761555c271SMatthew G. Knepley /* OPT: Read this out from preallocation information */ 29779566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 29784ef9d792SMatthew G. Knepley /* Update preallocation info */ 29799566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 29805f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Np, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 29819566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 29824ef9d792SMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2983826eb36dSMatthew G. Knepley PetscReal pVReal[3]; 2984c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 2985826eb36dSMatthew G. Knepley 29869566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 2987a0806964SMatthew G. Knepley if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetDimension((PetscFE)obj, &cpdim)); 2988a0806964SMatthew G. Knepley else cpdim = 1; 2989a0806964SMatthew G. Knepley 2990a0806964SMatthew G. Knepley if (s) { 29914ef9d792SMatthew G. Knepley /* Transform points from real space to coarse reference space */ 29929566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 2993e2d86523SMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 2994c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 29954ef9d792SMatthew G. Knepley 29964ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 29974ef9d792SMatthew G. Knepley /* Evaluate coarse basis on contained point */ 2998a0806964SMatthew G. Knepley PetscCall(PetscFEComputeTabulation((PetscFE)obj, 1, x, 0, T)); 29999566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 30004ef9d792SMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 30014ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3002ef0bb6c7SMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * qweights[ccell * qNc + c]; 30034ef9d792SMatthew G. Knepley } 30044ef9d792SMatthew G. Knepley } else { 30054ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 30069c3cf19fSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * qweights[ccell * qNc + c]; 30074ef9d792SMatthew G. Knepley } 30084ef9d792SMatthew G. Knepley } 30099566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 3010a0806964SMatthew G. Knepley } 3011a0806964SMatthew G. Knepley /* Update interpolator */ 3012d0f6233fSMatthew G. Knepley PetscCheck(numCIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, totDim); 3013a0806964SMatthew G. Knepley PetscCall(MatSetValues(interp, 1, &row, cpdim, &cindices[off], elemMat, INSERT_VALUES)); 30149566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 30154ef9d792SMatthew G. Knepley } 30169566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 30179566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 30189566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 30194ef9d792SMatthew G. Knepley } 30209566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 30214ef9d792SMatthew G. Knepley } 3022a0806964SMatthew G. Knepley if (s && id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3023a0806964SMatthew G. Knepley } 3024a0806964SMatthew G. Knepley if (!s) { 3025a0806964SMatthew G. Knepley PetscCall(MatAssemblyBegin(interp, MAT_FINAL_ASSEMBLY)); 3026a0806964SMatthew G. Knepley PetscCall(MatAssemblyEnd(interp, MAT_FINAL_ASSEMBLY)); 3027a0806964SMatthew G. Knepley PetscCall(MatPreallocatorPreallocate(interp, PETSC_TRUE, In)); 3028a0806964SMatthew G. Knepley PetscCall(MatDestroy(&interp)); 3029a0806964SMatthew G. Knepley interp = In; 3030a0806964SMatthew G. Knepley } 30314ef9d792SMatthew G. Knepley } 30329566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 30339566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 30349566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 30359566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 30369566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 30379566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 30383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 30394ef9d792SMatthew G. Knepley } 30404ef9d792SMatthew G. Knepley 304146fa42a0SMatthew G. Knepley /*@ 3042a1cb98faSBarry Smith DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse `DM` to a non-nested fine `DM`. 3043bd041c0cSMatthew G. Knepley 3044bd041c0cSMatthew G. Knepley Input Parameters: 3045bd041c0cSMatthew G. Knepley + dmf - The fine mesh 3046bd041c0cSMatthew G. Knepley . dmc - The coarse mesh 3047bd041c0cSMatthew G. Knepley - user - The user context 3048bd041c0cSMatthew G. Knepley 3049bd041c0cSMatthew G. Knepley Output Parameter: 3050bd041c0cSMatthew G. Knepley . mass - The mass matrix 3051bd041c0cSMatthew G. Knepley 3052bd041c0cSMatthew G. Knepley Level: developer 3053bd041c0cSMatthew G. Knepley 30541cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeMassMatrixNested()`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()` 3055bd041c0cSMatthew G. Knepley @*/ 3056d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user) 3057d71ae5a4SJacob Faibussowitsch { 3058bd041c0cSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 3059bd041c0cSMatthew G. Knepley const char *name = "Mass Matrix"; 3060bd041c0cSMatthew G. Knepley PetscDS prob; 3061bd041c0cSMatthew G. Knepley PetscSection fsection, csection, globalFSection, globalCSection; 3062e8f14785SLisandro Dalcin PetscHSetIJ ht; 3063bd041c0cSMatthew G. Knepley PetscLayout rLayout; 3064bd041c0cSMatthew G. Knepley PetscInt *dnz, *onz; 3065bd041c0cSMatthew G. Knepley PetscInt locRows, rStart, rEnd; 3066bd041c0cSMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 3067bd041c0cSMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 3068bd041c0cSMatthew G. Knepley PetscScalar *elemMat; 3069bd041c0cSMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 3070bd041c0cSMatthew G. Knepley 3071bd041c0cSMatthew G. Knepley PetscFunctionBegin; 30729566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 30739566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 30749566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 30759566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 30769566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 30779566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 30789566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 30799566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 30809566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 30819566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 30829566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 30839566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 30849566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 3085bd041c0cSMatthew G. Knepley 30869566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mass, &locRows, NULL)); 30879566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)mass), &rLayout)); 30889566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 30899566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 30909566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(rLayout)); 30919566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd)); 30929566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&rLayout)); 30939566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz)); 30949566063dSJacob Faibussowitsch PetscCall(PetscHSetIJCreate(&ht)); 3095bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3096bd041c0cSMatthew G. Knepley PetscObject obj; 3097bd041c0cSMatthew G. Knepley PetscClassId id; 3098bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3099bd041c0cSMatthew G. Knepley const PetscReal *qpoints; 3100bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3101bd041c0cSMatthew G. Knepley 31029566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 31039566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 31049566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 31059566063dSJacob Faibussowitsch else PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 31069566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL)); 3107bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3108bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3109bd041c0cSMatthew G. Knepley Vec pointVec; 3110bd041c0cSMatthew G. Knepley PetscScalar *pV; 3111bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3112bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3113bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, q, c; 3114bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3115bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3116bd041c0cSMatthew G. Knepley 31179566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 31189566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3119bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 31209566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 31219566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 31229566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3123bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3124c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3125c330f8ffSToby Isaac 3126bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3127c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3128bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3129bd041c0cSMatthew G. Knepley } 31309566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3131bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 31329566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 31339566063dSJacob Faibussowitsch PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view")); 3134bd041c0cSMatthew G. Knepley /* Update preallocation info */ 31359566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 31365f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 3137bd041c0cSMatthew G. Knepley { 3138e8f14785SLisandro Dalcin PetscHashIJKey key; 3139e8f14785SLisandro Dalcin PetscBool missing; 3140bd041c0cSMatthew G. Knepley 3141bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 3142e8f14785SLisandro Dalcin key.i = findices[i]; 3143e8f14785SLisandro Dalcin if (key.i >= 0) { 3144bd041c0cSMatthew G. Knepley /* Get indices for coarse elements */ 3145bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 31469566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3147bd041c0cSMatthew G. Knepley for (c = 0; c < numCIndices; ++c) { 3148e8f14785SLisandro Dalcin key.j = cindices[c]; 3149e8f14785SLisandro Dalcin if (key.j < 0) continue; 31509566063dSJacob Faibussowitsch PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 3151bd041c0cSMatthew G. Knepley if (missing) { 3152e8f14785SLisandro Dalcin if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i - rStart]; 3153e8f14785SLisandro Dalcin else ++onz[key.i - rStart]; 3154bd041c0cSMatthew G. Knepley } 3155bd041c0cSMatthew G. Knepley } 31569566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3157bd041c0cSMatthew G. Knepley } 3158bd041c0cSMatthew G. Knepley } 3159bd041c0cSMatthew G. Knepley } 3160bd041c0cSMatthew G. Knepley } 31619566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 31629566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 31639566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3164bd041c0cSMatthew G. Knepley } 3165bd041c0cSMatthew G. Knepley } 31669566063dSJacob Faibussowitsch PetscCall(PetscHSetIJDestroy(&ht)); 31679566063dSJacob Faibussowitsch PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 31689566063dSJacob Faibussowitsch PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 31699566063dSJacob Faibussowitsch PetscCall(PetscFree2(dnz, onz)); 3170bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3171bd041c0cSMatthew G. Knepley PetscObject obj; 3172bd041c0cSMatthew G. Knepley PetscClassId id; 3173ef0bb6c7SMatthew G. Knepley PetscTabulation T, Tfine; 3174bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3175bd041c0cSMatthew G. Knepley const PetscReal *qpoints, *qweights; 3176bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3177bd041c0cSMatthew G. Knepley 31789566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 31799566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 3180ef0bb6c7SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 31819566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 31829566063dSJacob Faibussowitsch PetscCall(PetscFEGetCellTabulation((PetscFE)obj, 1, &Tfine)); 31839566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, 1, x, 0, &T)); 3184ef0bb6c7SMatthew G. Knepley } else { 31859566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 3186ef0bb6c7SMatthew G. Knepley } 31879566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights)); 3188bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3189bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3190bd041c0cSMatthew G. Knepley Vec pointVec; 3191bd041c0cSMatthew G. Knepley PetscScalar *pV; 3192bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3193bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3194bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, cpdim, q, c, j; 3195bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3196bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3197bd041c0cSMatthew G. Knepley 31989566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 31999566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3200bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 32019566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 32029566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 32039566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3204bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3205c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3206c330f8ffSToby Isaac 3207bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3208c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3209bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3210bd041c0cSMatthew G. Knepley } 32119566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3212bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 32139566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 3214bd041c0cSMatthew G. Knepley /* Update matrix */ 32159566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 32165f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 32179566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3218bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3219bd041c0cSMatthew G. Knepley PetscReal pVReal[3]; 3220c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3221c330f8ffSToby Isaac 32229566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3223bd041c0cSMatthew G. Knepley /* Transform points from real space to coarse reference space */ 32249566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3225bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 3226c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 3227bd041c0cSMatthew G. Knepley 3228bd041c0cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 3229bd041c0cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 3230bd041c0cSMatthew G. Knepley 3231bd041c0cSMatthew G. Knepley /* Evaluate coarse basis on contained point */ 32329566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 32339566063dSJacob Faibussowitsch PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T)); 3234bd041c0cSMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 3235bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 32369566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3237bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3238ef0bb6c7SMatthew 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; 3239bd041c0cSMatthew G. Knepley } 3240bd041c0cSMatthew G. Knepley /* Update interpolator */ 32419566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 324263a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 32439566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3244bd041c0cSMatthew G. Knepley } 3245bd041c0cSMatthew G. Knepley } else { 3246bd041c0cSMatthew G. Knepley cpdim = 1; 3247bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 32489566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3249bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3250bd041c0cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * 1.0 * qweights[ccell * Nc + c] * detJ; 3251bd041c0cSMatthew G. Knepley } 3252bd041c0cSMatthew G. Knepley /* Update interpolator */ 32539566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 325463a3b9bcSJacob 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)); 325563a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 32569566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3257bd041c0cSMatthew G. Knepley } 3258bd041c0cSMatthew G. Knepley } 32599566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3260bd041c0cSMatthew G. Knepley } 32619566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 32629566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 32639566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 32649566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3265bd041c0cSMatthew G. Knepley } 32669566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3267bd041c0cSMatthew G. Knepley } 32689566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 32699566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 32709566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 32719566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 32729566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 32733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3274bd041c0cSMatthew G. Knepley } 3275bd041c0cSMatthew G. Knepley 3276bd041c0cSMatthew G. Knepley /*@ 327746fa42a0SMatthew G. Knepley DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns 327846fa42a0SMatthew G. Knepley 327946fa42a0SMatthew G. Knepley Input Parameters: 328046fa42a0SMatthew G. Knepley + dmc - The coarse mesh 328160225df5SJacob Faibussowitsch . dmf - The fine mesh 328246fa42a0SMatthew G. Knepley - user - The user context 328346fa42a0SMatthew G. Knepley 328446fa42a0SMatthew G. Knepley Output Parameter: 328546fa42a0SMatthew G. Knepley . sc - The mapping 328646fa42a0SMatthew G. Knepley 328746fa42a0SMatthew G. Knepley Level: developer 328846fa42a0SMatthew G. Knepley 32891cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()` 329046fa42a0SMatthew G. Knepley @*/ 3291d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 3292d71ae5a4SJacob Faibussowitsch { 3293e9d4ef1bSMatthew G. Knepley PetscDS prob; 32947c927364SMatthew G. Knepley PetscFE *feRef; 329597c42addSMatthew G. Knepley PetscFV *fvRef; 32967c927364SMatthew G. Knepley Vec fv, cv; 32977c927364SMatthew G. Knepley IS fis, cis; 32987c927364SMatthew G. Knepley PetscSection fsection, fglobalSection, csection, cglobalSection; 32997c927364SMatthew G. Knepley PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 3300485ad865SMatthew G. Knepley PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m; 33016f3d3cbcSMatthew G. Knepley PetscBool *needAvg; 33027c927364SMatthew G. Knepley 33037c927364SMatthew G. Knepley PetscFunctionBegin; 33049566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 33059566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 33069566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 33079566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 33089566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 33099566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 33109566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 33119566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 33129566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 33139566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nf, &feRef, Nf, &fvRef, Nf, &needAvg)); 33147c927364SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 331597c42addSMatthew G. Knepley PetscObject obj; 331697c42addSMatthew G. Knepley PetscClassId id; 3317aa7890ccSMatthew G. Knepley PetscInt fNb = 0, Nc = 0; 33187c927364SMatthew G. Knepley 33199566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 33209566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 332197c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 332297c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 33236f3d3cbcSMatthew G. Knepley PetscSpace sp; 33249b2fc754SMatthew G. Knepley PetscInt maxDegree; 332597c42addSMatthew G. Knepley 33269566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 33279566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &fNb)); 33289566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 33299566063dSJacob Faibussowitsch PetscCall(PetscFEGetBasisSpace(fe, &sp)); 33309566063dSJacob Faibussowitsch PetscCall(PetscSpaceGetDegree(sp, NULL, &maxDegree)); 33319b2fc754SMatthew G. Knepley if (!maxDegree) needAvg[f] = PETSC_TRUE; 333297c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 333397c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 333497c42addSMatthew G. Knepley PetscDualSpace Q; 333597c42addSMatthew G. Knepley 33369566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 33379566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 33389566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fNb)); 33399566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 33406f3d3cbcSMatthew G. Knepley needAvg[f] = PETSC_TRUE; 334197c42addSMatthew G. Knepley } 3342d172c84bSMatthew G. Knepley fTotDim += fNb; 33437c927364SMatthew G. Knepley } 33449566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &cTotDim)); 33459566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(cTotDim, &cmap)); 33467c927364SMatthew G. Knepley for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 33477c927364SMatthew G. Knepley PetscFE feC; 334897c42addSMatthew G. Knepley PetscFV fvC; 33497c927364SMatthew G. Knepley PetscDualSpace QF, QC; 3350d172c84bSMatthew G. Knepley PetscInt order = -1, NcF, NcC, fpdim, cpdim; 33517c927364SMatthew G. Knepley 335297c42addSMatthew G. Knepley if (feRef[field]) { 33539566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&feC)); 33549566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feC, &NcC)); 33559566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[field], &NcF)); 33569566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[field], &QF)); 33579566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetOrder(QF, &order)); 33589566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 33599566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feC, &QC)); 33609566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 336197c42addSMatthew G. Knepley } else { 33629566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fvC)); 33639566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvC, &NcC)); 33649566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[field], &NcF)); 33659566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[field], &QF)); 33669566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 33679566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvC, &QC)); 33689566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 336997c42addSMatthew G. Knepley } 337063a3b9bcSJacob 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); 33717c927364SMatthew G. Knepley for (c = 0; c < cpdim; ++c) { 33727c927364SMatthew G. Knepley PetscQuadrature cfunc; 3373d172c84bSMatthew G. Knepley const PetscReal *cqpoints, *cqweights; 3374d172c84bSMatthew G. Knepley PetscInt NqcC, NpC; 337597c42addSMatthew G. Knepley PetscBool found = PETSC_FALSE; 33767c927364SMatthew G. Knepley 33779566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QC, c, &cfunc)); 33789566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights)); 337963a3b9bcSJacob 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); 33801dca8a05SBarry Smith PetscCheck(NpC == 1 || !feRef[field], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 33817c927364SMatthew G. Knepley for (f = 0; f < fpdim; ++f) { 33827c927364SMatthew G. Knepley PetscQuadrature ffunc; 3383d172c84bSMatthew G. Knepley const PetscReal *fqpoints, *fqweights; 33847c927364SMatthew G. Knepley PetscReal sum = 0.0; 3385d172c84bSMatthew G. Knepley PetscInt NqcF, NpF; 33867c927364SMatthew G. Knepley 33879566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QF, f, &ffunc)); 33889566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights)); 338963a3b9bcSJacob 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); 33907c927364SMatthew G. Knepley if (NpC != NpF) continue; 33917c927364SMatthew G. Knepley for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 33927c927364SMatthew G. Knepley if (sum > 1.0e-9) continue; 3393d172c84bSMatthew G. Knepley for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d] * fqweights[d]); 3394d172c84bSMatthew G. Knepley if (sum < 1.0e-9) continue; 3395d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + f; 339697c42addSMatthew G. Knepley found = PETSC_TRUE; 33977c927364SMatthew G. Knepley break; 33987c927364SMatthew G. Knepley } 339997c42addSMatthew G. Knepley if (!found) { 340097c42addSMatthew G. Knepley /* TODO We really want the average here, but some asshole put VecScatter in the interface */ 3401d172c84bSMatthew G. Knepley if (fvRef[field] || (feRef[field] && order == 0)) { 3402d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + 0; 340397c42addSMatthew G. Knepley } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection"); 340497c42addSMatthew G. Knepley } 34057c927364SMatthew G. Knepley } 3406d172c84bSMatthew G. Knepley offsetC += cpdim; 3407d172c84bSMatthew G. Knepley offsetF += fpdim; 34087c927364SMatthew G. Knepley } 34099371c9d4SSatish Balay for (f = 0; f < Nf; ++f) { 34109371c9d4SSatish Balay PetscCall(PetscFEDestroy(&feRef[f])); 34119371c9d4SSatish Balay PetscCall(PetscFVDestroy(&fvRef[f])); 34129371c9d4SSatish Balay } 34139566063dSJacob Faibussowitsch PetscCall(PetscFree3(feRef, fvRef, needAvg)); 34147c927364SMatthew G. Knepley 34159566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmf, &fv)); 34169566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmc, &cv)); 34179566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(cv, &startC, &endC)); 34189566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(cglobalSection, &m)); 34199566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(cTotDim, &cellCIndices, fTotDim, &cellFIndices)); 34209566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &cindices)); 34219566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &findices)); 34227c927364SMatthew G. Knepley for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 34237c927364SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 34249566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices)); 34257c927364SMatthew G. Knepley for (d = 0; d < cTotDim; ++d) { 34260bd915a7SMatthew G. Knepley if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue; 3427d2457c26SMatthew G. Knepley PetscCheck(!(findices[cellCIndices[d] - startC] >= 0) || !(findices[cellCIndices[d] - startC] != cellFIndices[cmap[d]]), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell %" PetscInt_FMT " Coarse dof %" PetscInt_FMT " maps to both %" PetscInt_FMT " and %" PetscInt_FMT, c, cindices[cellCIndices[d] - startC], findices[cellCIndices[d] - startC], cellFIndices[cmap[d]]); 34287c927364SMatthew G. Knepley cindices[cellCIndices[d] - startC] = cellCIndices[d]; 34297c927364SMatthew G. Knepley findices[cellCIndices[d] - startC] = cellFIndices[cmap[d]]; 34307c927364SMatthew G. Knepley } 34317c927364SMatthew G. Knepley } 34329566063dSJacob Faibussowitsch PetscCall(PetscFree(cmap)); 34339566063dSJacob Faibussowitsch PetscCall(PetscFree2(cellCIndices, cellFIndices)); 34347c927364SMatthew G. Knepley 34359566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis)); 34369566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis)); 34379566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(cv, cis, fv, fis, sc)); 34389566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cis)); 34399566063dSJacob Faibussowitsch PetscCall(ISDestroy(&fis)); 34409566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmf, &fv)); 34419566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmc, &cv)); 34429566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 34433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3444cb1e1211SMatthew G Knepley } 3445a1cf66bbSMatthew G. Knepley 34462f856554SMatthew G. Knepley /*@C 34472f856554SMatthew G. Knepley DMPlexGetCellFields - Retrieve the field values values for a chunk of cells 34482f856554SMatthew G. Knepley 34492f856554SMatthew G. Knepley Input Parameters: 3450a1cb98faSBarry Smith + dm - The `DM` 34512f856554SMatthew G. Knepley . cellIS - The cells to include 34522f856554SMatthew G. Knepley . locX - A local vector with the solution fields 34532f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 34542f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 34552f856554SMatthew G. Knepley 34562f856554SMatthew G. Knepley Output Parameters: 34572f856554SMatthew G. Knepley + u - The field coefficients 34582f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 34592f856554SMatthew G. Knepley - a - The auxiliary field coefficients 34602f856554SMatthew G. Knepley 34612f856554SMatthew G. Knepley Level: developer 34622f856554SMatthew G. Knepley 34631cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 34642f856554SMatthew G. Knepley @*/ 3465d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3466d71ae5a4SJacob Faibussowitsch { 34672f856554SMatthew G. Knepley DM plex, plexA = NULL; 3468a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 34692f856554SMatthew G. Knepley PetscSection section, sectionAux; 34702f856554SMatthew G. Knepley PetscDS prob; 34712f856554SMatthew G. Knepley const PetscInt *cells; 34722f856554SMatthew G. Knepley PetscInt cStart, cEnd, numCells, totDim, totDimAux, c; 34732f856554SMatthew G. Knepley 34742f856554SMatthew G. Knepley PetscFunctionBegin; 34752f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3476064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 3477ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); 3478ad540459SPierre Jolivet if (locA) PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); 34794f572ea9SToby Isaac PetscAssertPointer(u, 6); 34804f572ea9SToby Isaac PetscAssertPointer(u_t, 7); 34814f572ea9SToby Isaac PetscAssertPointer(a, 8); 34829566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 34839566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 34849566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 348507218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 34869566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 34872f856554SMatthew G. Knepley if (locA) { 34882f856554SMatthew G. Knepley DM dmAux; 34892f856554SMatthew G. Knepley PetscDS probAux; 34902f856554SMatthew G. Knepley 34919566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 34929566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 34939566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 34949566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 34959566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 34969566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 34972f856554SMatthew G. Knepley } 34982f856554SMatthew G. Knepley numCells = cEnd - cStart; 34999566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 35009371c9d4SSatish Balay if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 3501ad540459SPierre Jolivet else *u_t = NULL; 35029371c9d4SSatish Balay if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 3503ad540459SPierre Jolivet else *a = NULL; 35042f856554SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 35052f856554SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 35062f856554SMatthew G. Knepley const PetscInt cind = c - cStart; 35072f856554SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a; 35082f856554SMatthew G. Knepley PetscInt i; 35092f856554SMatthew G. Knepley 35109566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x)); 35112f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul[cind * totDim + i] = x[i]; 35129566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x)); 35132f856554SMatthew G. Knepley if (locX_t) { 35149566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t)); 35152f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul_t[cind * totDim + i] = x_t[i]; 35169566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t)); 35172f856554SMatthew G. Knepley } 35182f856554SMatthew G. Knepley if (locA) { 35192f856554SMatthew G. Knepley PetscInt subcell; 35209566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 35219566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 35222f856554SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) al[cind * totDimAux + i] = x[i]; 35239566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 35242f856554SMatthew G. Knepley } 35252f856554SMatthew G. Knepley } 35269566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 35279566063dSJacob Faibussowitsch if (locA) PetscCall(DMDestroy(&plexA)); 35289566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 35293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 35302f856554SMatthew G. Knepley } 35312f856554SMatthew G. Knepley 35322f856554SMatthew G. Knepley /*@C 35332f856554SMatthew G. Knepley DMPlexRestoreCellFields - Restore the field values values for a chunk of cells 35342f856554SMatthew G. Knepley 35352f856554SMatthew G. Knepley Input Parameters: 3536a1cb98faSBarry Smith + dm - The `DM` 35372f856554SMatthew G. Knepley . cellIS - The cells to include 35382f856554SMatthew G. Knepley . locX - A local vector with the solution fields 35392f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 35402f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 35412f856554SMatthew G. Knepley 35422f856554SMatthew G. Knepley Output Parameters: 35432f856554SMatthew G. Knepley + u - The field coefficients 35442f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 35452f856554SMatthew G. Knepley - a - The auxiliary field coefficients 35462f856554SMatthew G. Knepley 35472f856554SMatthew G. Knepley Level: developer 35482f856554SMatthew G. Knepley 35491cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 35502f856554SMatthew G. Knepley @*/ 3551d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3552d71ae5a4SJacob Faibussowitsch { 35532f856554SMatthew G. Knepley PetscFunctionBegin; 35549566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u)); 35559566063dSJacob Faibussowitsch if (locX_t) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t)); 35569566063dSJacob Faibussowitsch if (locA) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a)); 35573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 35582f856554SMatthew G. Knepley } 35592f856554SMatthew G. Knepley 3560a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexGetHybridCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3561d71ae5a4SJacob Faibussowitsch { 356207218a29SMatthew G. Knepley DM plex, plexA = NULL; 356307218a29SMatthew G. Knepley DMEnclosureType encAux; 356407218a29SMatthew G. Knepley PetscSection section, sectionAux; 356507218a29SMatthew G. Knepley PetscDS ds, dsIn; 35666528b96dSMatthew G. Knepley const PetscInt *cells; 356707218a29SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, totDim, totDimAux, Nf, f; 35686528b96dSMatthew G. Knepley 35696528b96dSMatthew G. Knepley PetscFunctionBegin; 357007218a29SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 357107218a29SMatthew G. Knepley PetscValidHeaderSpecific(cellIS, IS_CLASSID, 2); 357207218a29SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 357307218a29SMatthew G. Knepley if (locX_t) { PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); } 357407218a29SMatthew G. Knepley if (locA) { PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); } 35754f572ea9SToby Isaac PetscAssertPointer(u, 6); 35764f572ea9SToby Isaac PetscAssertPointer(u_t, 7); 35774f572ea9SToby Isaac PetscAssertPointer(a, 8); 357807218a29SMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 357907218a29SMatthew G. Knepley numCells = cEnd - cStart; 358007218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 358107218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dm, §ion)); 358207218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 358307218a29SMatthew G. Knepley PetscCall(PetscDSGetNumFields(dsIn, &Nf)); 358407218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDim)); 358507218a29SMatthew G. Knepley if (locA) { 358607218a29SMatthew G. Knepley DM dmAux; 358707218a29SMatthew G. Knepley PetscDS probAux; 358807218a29SMatthew G. Knepley 358907218a29SMatthew G. Knepley PetscCall(VecGetDM(locA, &dmAux)); 359007218a29SMatthew G. Knepley PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 359107218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 359207218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dmAux, §ionAux)); 359307218a29SMatthew G. Knepley PetscCall(DMGetDS(dmAux, &probAux)); 359407218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 359507218a29SMatthew G. Knepley } 359607218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 359707218a29SMatthew G. Knepley if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 359807218a29SMatthew G. Knepley else { 359907218a29SMatthew G. Knepley *u_t = NULL; 360007218a29SMatthew G. Knepley } 360107218a29SMatthew G. Knepley if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 360207218a29SMatthew G. Knepley else { 360307218a29SMatthew G. Knepley *a = NULL; 360407218a29SMatthew G. Knepley } 360507218a29SMatthew G. Knepley // Loop over cohesive cells 360607218a29SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 360707218a29SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 360807218a29SMatthew G. Knepley const PetscInt cind = c - cStart; 360974a0c561SMatthew G. Knepley PetscScalar *xf = NULL, *xc = NULL, *x = NULL, *xf_t = NULL, *xc_t = NULL; 361074a0c561SMatthew G. Knepley PetscScalar *ul = &(*u)[cind * totDim], *ul_t = u_t ? &(*u_t)[cind * totDim] : NULL; 361107218a29SMatthew G. Knepley const PetscInt *cone, *ornt; 361207218a29SMatthew G. Knepley PetscInt Nx = 0, Nxf, s; 361307218a29SMatthew G. Knepley 361407218a29SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cell, &cone)); 361507218a29SMatthew G. Knepley PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 361607218a29SMatthew G. Knepley // Put in cohesive unknowns 361707218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, &Nxf, &xf)); 361874a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &xf_t)); 361907218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 362007218a29SMatthew G. Knepley PetscInt fdofIn, foff, foffIn; 362107218a29SMatthew G. Knepley PetscBool cohesive; 362207218a29SMatthew G. Knepley 362307218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 362407218a29SMatthew G. Knepley if (!cohesive) continue; 362507218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn)); 362607218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(ds, f, &foff)); 362707218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn)); 362807218a29SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + i] = xf[foff + i]; 362974a0c561SMatthew G. Knepley if (locX_t) 363074a0c561SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + i] = xf_t[foff + i]; 363107218a29SMatthew G. Knepley Nx += fdofIn; 363207218a29SMatthew G. Knepley } 363307218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, &Nxf, &xf)); 363474a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &xf_t)); 363507218a29SMatthew G. Knepley // Loop over sides of surface 363607218a29SMatthew G. Knepley for (s = 0; s < 2; ++s) { 363707218a29SMatthew G. Knepley const PetscInt *support; 363807218a29SMatthew G. Knepley const PetscInt face = cone[s]; 363907218a29SMatthew G. Knepley PetscInt ssize, ncell, Nxc; 364007218a29SMatthew G. Knepley 364107218a29SMatthew G. Knepley // I don't think I need the face to have 0 orientation in the hybrid cell 364207218a29SMatthew G. Knepley //PetscCheck(!ornt[s], PETSC_COMM_SELF, PETSC_ERR_SUP, "Face %" PetscInt_FMT " in hybrid cell %" PetscInt_FMT " has orientation %" PetscInt_FMT " != 0", face, cell, ornt[s]); 364307218a29SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, face, &support)); 364407218a29SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, face, &ssize)); 364507218a29SMatthew G. Knepley if (support[0] == cell) ncell = support[1]; 364607218a29SMatthew G. Knepley else if (support[1] == cell) ncell = support[0]; 364707218a29SMatthew G. Knepley else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", face, cell); 364807218a29SMatthew G. Knepley // Get closure of both face and cell, stick in cell for normal fields and face for cohesive fields 364907218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, ncell, &Nxc, &xc)); 365074a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, ncell, NULL, &xc_t)); 365107218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 365207218a29SMatthew G. Knepley PetscInt fdofIn, foffIn; 365307218a29SMatthew G. Knepley PetscBool cohesive; 365407218a29SMatthew G. Knepley 365507218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 365607218a29SMatthew G. Knepley if (cohesive) continue; 365707218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn)); 365807218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn)); 365907218a29SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + s * fdofIn + i] = xc[foffIn + i]; 366074a0c561SMatthew G. Knepley if (locX_t) 366174a0c561SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + s * fdofIn + i] = xc_t[foffIn + i]; 366207218a29SMatthew G. Knepley Nx += fdofIn; 366307218a29SMatthew G. Knepley } 366407218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, ncell, &Nxc, &xc)); 366574a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, ncell, NULL, &xc_t)); 366607218a29SMatthew G. Knepley } 366707218a29SMatthew G. Knepley PetscCheck(Nx == totDim, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Closure size %" PetscInt_FMT " for cell %" PetscInt_FMT " does not match DS size %" PetscInt_FMT, Nx, cell, totDim); 366807218a29SMatthew G. Knepley 366907218a29SMatthew G. Knepley if (locA) { 367007218a29SMatthew G. Knepley PetscScalar *al = &(*a)[cind * totDimAux]; 367107218a29SMatthew G. Knepley PetscInt subcell; 367207218a29SMatthew G. Knepley 367307218a29SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 367407218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, &Nx, &x)); 367507218a29SMatthew G. Knepley PetscCheck(Nx == totDimAux, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Closure size %" PetscInt_FMT " for subcell %" PetscInt_FMT "does not match DS size %" PetscInt_FMT, Nx, subcell, totDimAux); 367607218a29SMatthew G. Knepley for (PetscInt i = 0; i < totDimAux; ++i) al[i] = x[i]; 367707218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, &Nx, &x)); 367807218a29SMatthew G. Knepley } 367907218a29SMatthew G. Knepley } 368007218a29SMatthew G. Knepley PetscCall(DMDestroy(&plex)); 368107218a29SMatthew G. Knepley PetscCall(DMDestroy(&plexA)); 368207218a29SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 368307218a29SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 368407218a29SMatthew G. Knepley } 368507218a29SMatthew G. Knepley 368607218a29SMatthew G. Knepley /* 36873e2b0218SMatthew G. Knepley DMPlexGetHybridFields - Get the field values for the negative side (s = 0) and positive side (s = 1) of the interface 368807218a29SMatthew G. Knepley 368907218a29SMatthew G. Knepley Input Parameters: 369007218a29SMatthew G. Knepley + dm - The full domain DM 369107218a29SMatthew G. Knepley . dmX - An array of DM for the field, say an auxiliary DM, indexed by s 369207218a29SMatthew G. Knepley . dsX - An array of PetscDS for the field, indexed by s 369307218a29SMatthew G. Knepley . cellIS - The interface cells for which we want values 369407218a29SMatthew G. Knepley . locX - An array of local vectors with the field values, indexed by s 369507218a29SMatthew G. Knepley - useCell - Flag to have values come from neighboring cell rather than endcap face 369607218a29SMatthew G. Knepley 369707218a29SMatthew G. Knepley Output Parameter: 369807218a29SMatthew G. Knepley . x - An array of field values, indexed by s 369907218a29SMatthew G. Knepley 370007218a29SMatthew G. Knepley Note: 370176fbde31SPierre Jolivet The arrays in `x` will be allocated using `DMGetWorkArray()`, and must be returned using `DMPlexRestoreHybridFields()`. 370207218a29SMatthew G. Knepley 370307218a29SMatthew G. Knepley Level: advanced 370407218a29SMatthew G. Knepley 370576fbde31SPierre Jolivet .seealso: `DMPlexRestoreHybridFields()`, `DMGetWorkArray()` 370607218a29SMatthew G. Knepley */ 370707218a29SMatthew G. Knepley static PetscErrorCode DMPlexGetHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[]) 370807218a29SMatthew G. Knepley { 370907218a29SMatthew G. Knepley DM plexX[2]; 371007218a29SMatthew G. Knepley DMEnclosureType encX[2]; 371107218a29SMatthew G. Knepley PetscSection sectionX[2]; 371207218a29SMatthew G. Knepley const PetscInt *cells; 371307218a29SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, s, totDimX[2]; 371407218a29SMatthew G. Knepley 371507218a29SMatthew G. Knepley PetscFunctionBegin; 37164f572ea9SToby Isaac PetscAssertPointer(locX, 5); 371707218a29SMatthew G. Knepley if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS); 37184f572ea9SToby Isaac PetscAssertPointer(dmX, 2); 37194f572ea9SToby Isaac PetscAssertPointer(dsX, 3); 372007218a29SMatthew G. Knepley PetscValidHeaderSpecific(cellIS, IS_CLASSID, 4); 37214f572ea9SToby Isaac PetscAssertPointer(x, 7); 37229566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 37236528b96dSMatthew G. Knepley numCells = cEnd - cStart; 3724148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 372507218a29SMatthew G. Knepley PetscValidHeaderSpecific(dmX[s], DM_CLASSID, 2); 372607218a29SMatthew G. Knepley PetscValidHeaderSpecific(dsX[s], PETSCDS_CLASSID, 3); 372707218a29SMatthew G. Knepley PetscValidHeaderSpecific(locX[s], VEC_CLASSID, 5); 372807218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dmX[s], &plexX[s], PETSC_FALSE)); 372907218a29SMatthew G. Knepley PetscCall(DMGetEnclosureRelation(dmX[s], dm, &encX[s])); 373007218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dmX[s], §ionX[s])); 373107218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsX[s], &totDimX[s])); 373207218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dmX[s], numCells * totDimX[s], MPIU_SCALAR, &x[s])); 373304c51a94SMatthew G. Knepley } 3734148442b3SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 37356528b96dSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 37366528b96dSMatthew G. Knepley const PetscInt cind = c - cStart; 37376528b96dSMatthew G. Knepley const PetscInt *cone, *ornt; 37386528b96dSMatthew G. Knepley 37399566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 37409566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 374107218a29SMatthew G. Knepley //PetscCheck(!ornt[0], PETSC_COMM_SELF, PETSC_ERR_SUP, "Face %" PetscInt_FMT " in hybrid cell %" PetscInt_FMT " has orientation %" PetscInt_FMT " != 0", cone[0], cell, ornt[0]); 3742148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 374307218a29SMatthew G. Knepley const PetscInt tdX = totDimX[s]; 374407218a29SMatthew G. Knepley PetscScalar *closure = NULL, *xl = &x[s][cind * tdX]; 374507218a29SMatthew G. Knepley PetscInt face = cone[s], point = face, subpoint, Nx, i; 374607218a29SMatthew G. Knepley 374707218a29SMatthew G. Knepley if (useCell) { 37485fedec97SMatthew G. Knepley const PetscInt *support; 374907218a29SMatthew G. Knepley PetscInt ssize; 37506528b96dSMatthew G. Knepley 375107218a29SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, face, &support)); 375207218a29SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, face, &ssize)); 375307218a29SMatthew 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", face, cell, ssize); 375407218a29SMatthew G. Knepley if (support[0] == cell) point = support[1]; 375507218a29SMatthew G. Knepley else if (support[1] == cell) point = support[0]; 375607218a29SMatthew G. Knepley else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", face, cell); 375707218a29SMatthew G. Knepley } 375807218a29SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexX[s], dm, encX[s], point, &subpoint)); 3759e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(plexX[s], sectionX[s], PETSC_FALSE, locX[s], subpoint, ornt[s], &Nx, &closure)); 376007218a29SMatthew G. Knepley PetscCheck(Nx == tdX, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Closure size %" PetscInt_FMT " for subpoint %" PetscInt_FMT " does not match DS size %" PetscInt_FMT, Nx, subpoint, tdX); 376107218a29SMatthew G. Knepley for (i = 0; i < Nx; ++i) xl[i] = closure[i]; 376207218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexX[s], sectionX[s], locX[s], subpoint, &Nx, &closure)); 37636528b96dSMatthew G. Knepley } 37646528b96dSMatthew G. Knepley } 376507218a29SMatthew G. Knepley for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexX[s])); 37669566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 37673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 37686528b96dSMatthew G. Knepley } 37696528b96dSMatthew G. Knepley 377007218a29SMatthew G. Knepley static PetscErrorCode DMPlexRestoreHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[]) 3771d71ae5a4SJacob Faibussowitsch { 37726528b96dSMatthew G. Knepley PetscFunctionBegin; 377307218a29SMatthew G. Knepley if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS); 377407218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dmX[0], 0, MPIU_SCALAR, &x[0])); 377507218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dmX[1], 0, MPIU_SCALAR, &x[1])); 37763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 37776528b96dSMatthew G. Knepley } 37786528b96dSMatthew G. Knepley 37792f856554SMatthew G. Knepley /*@C 37802f856554SMatthew G. Knepley DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 37812f856554SMatthew G. Knepley 37822f856554SMatthew G. Knepley Input Parameters: 3783a1cb98faSBarry Smith + dm - The `DM` 37842f856554SMatthew G. Knepley . fStart - The first face to include 37852f856554SMatthew G. Knepley . fEnd - The first face to exclude 37862f856554SMatthew G. Knepley . locX - A local vector with the solution fields 37872f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 37882f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 37892f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 379060225df5SJacob Faibussowitsch - locGrad - A local vector with field gradients, or NULL 37912f856554SMatthew G. Knepley 37922f856554SMatthew G. Knepley Output Parameters: 37932f856554SMatthew G. Knepley + Nface - The number of faces with field values 37942f856554SMatthew G. Knepley . uL - The field values at the left side of the face 37952f856554SMatthew G. Knepley - uR - The field values at the right side of the face 37962f856554SMatthew G. Knepley 37972f856554SMatthew G. Knepley Level: developer 37982f856554SMatthew G. Knepley 37991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 38002f856554SMatthew G. Knepley @*/ 3801d71ae5a4SJacob 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) 3802d71ae5a4SJacob Faibussowitsch { 38032f856554SMatthew G. Knepley DM dmFace, dmCell, dmGrad = NULL; 38042f856554SMatthew G. Knepley PetscSection section; 38052f856554SMatthew G. Knepley PetscDS prob; 38062f856554SMatthew G. Knepley DMLabel ghostLabel; 38072f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 38082f856554SMatthew G. Knepley PetscBool *isFE; 38092f856554SMatthew G. Knepley PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 38102f856554SMatthew G. Knepley 38112f856554SMatthew G. Knepley PetscFunctionBegin; 38122f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 38132f856554SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3814ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5); 38152f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 38162f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 3817ad540459SPierre Jolivet if (locGrad) PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8); 38184f572ea9SToby Isaac PetscAssertPointer(uL, 10); 38194f572ea9SToby Isaac PetscAssertPointer(uR, 11); 38209566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 38219566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 38229566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 38239566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 38249566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(prob, &Nc)); 38259566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nf, &isFE)); 38262f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 38272f856554SMatthew G. Knepley PetscObject obj; 38282f856554SMatthew G. Knepley PetscClassId id; 38292f856554SMatthew G. Knepley 38309566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 38319566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 38329371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 38339371c9d4SSatish Balay isFE[f] = PETSC_TRUE; 38349371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 38359371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 38369371c9d4SSatish Balay } else { 38379371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 38389371c9d4SSatish Balay } 38392f856554SMatthew G. Knepley } 38409566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 38419566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locX, &x)); 38429566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 38439566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 38449566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 38459566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 38462f856554SMatthew G. Knepley if (locGrad) { 38479566063dSJacob Faibussowitsch PetscCall(VecGetDM(locGrad, &dmGrad)); 38489566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 38492f856554SMatthew G. Knepley } 38509566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uL)); 38519566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uR)); 38522f856554SMatthew G. Knepley /* Right now just eat the extra work for FE (could make a cell loop) */ 38532f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 38542f856554SMatthew G. Knepley const PetscInt *cells; 38552f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 38562f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 38572f856554SMatthew G. Knepley PetscScalar *xL, *xR, *gL, *gR; 38582f856554SMatthew G. Knepley PetscScalar *uLl = *uL, *uRl = *uR; 38592f856554SMatthew G. Knepley PetscInt ghost, nsupp, nchild; 38602f856554SMatthew G. Knepley 38619566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 38629566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 38639566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 38642f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 38659566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 38669566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 38679566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 38689566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 38692f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 38702f856554SMatthew G. Knepley PetscInt off; 38712f856554SMatthew G. Knepley 38729566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffset(prob, f, &off)); 38732f856554SMatthew G. Knepley if (isFE[f]) { 38742f856554SMatthew G. Knepley const PetscInt *cone; 38752f856554SMatthew G. Knepley PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 38762f856554SMatthew G. Knepley 38772f856554SMatthew G. Knepley xL = xR = NULL; 38789566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 38799566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL)); 38809566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR)); 38819566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[0], &cone)); 38829566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL)); 38839371c9d4SSatish Balay for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) 38849371c9d4SSatish Balay if (cone[faceLocL] == face) break; 38859566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[1], &cone)); 38869566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR)); 38879371c9d4SSatish Balay for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) 38889371c9d4SSatish Balay if (cone[faceLocR] == face) break; 38891dca8a05SBarry 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]); 38902f856554SMatthew G. Knepley /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 38912f856554SMatthew G. Knepley /* TODO: this is a hack that might not be right for nonconforming */ 38922f856554SMatthew G. Knepley if (faceLocL < coneSizeL) { 38939566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface * Nc + off])); 38949566063dSJacob Faibussowitsch if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 38952f856554SMatthew G. Knepley else { 38969371c9d4SSatish Balay for (d = 0; d < comp; ++d) uRl[iface * Nc + off + d] = uLl[iface * Nc + off + d]; 38979371c9d4SSatish Balay } 38989371c9d4SSatish Balay } else { 38999566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 39009566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 39012f856554SMatthew G. Knepley for (d = 0; d < comp; ++d) uLl[iface * Nc + off + d] = uRl[iface * Nc + off + d]; 39022f856554SMatthew G. Knepley } 39039566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL)); 39049566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR)); 39052f856554SMatthew G. Knepley } else { 39062f856554SMatthew G. Knepley PetscFV fv; 39072f856554SMatthew G. Knepley PetscInt numComp, c; 39082f856554SMatthew G. Knepley 39099566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *)&fv)); 39109566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &numComp)); 39119566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL)); 39129566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR)); 39132f856554SMatthew G. Knepley if (dmGrad) { 39142f856554SMatthew G. Knepley PetscReal dxL[3], dxR[3]; 39152f856554SMatthew G. Knepley 39169566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL)); 39179566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR)); 39182f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 39192f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 39202f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 39212f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c * dim], dxL); 39222f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c * dim], dxR); 39232f856554SMatthew G. Knepley } 39242f856554SMatthew G. Knepley } else { 39252f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 39262f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c]; 39272f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c]; 39282f856554SMatthew G. Knepley } 39292f856554SMatthew G. Knepley } 39302f856554SMatthew G. Knepley } 39312f856554SMatthew G. Knepley } 39322f856554SMatthew G. Knepley ++iface; 39332f856554SMatthew G. Knepley } 39342f856554SMatthew G. Knepley *Nface = iface; 39359566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locX, &x)); 39369566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 39379566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 393848a46eb9SPierre Jolivet if (locGrad) PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 39399566063dSJacob Faibussowitsch PetscCall(PetscFree(isFE)); 39403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 39412f856554SMatthew G. Knepley } 39422f856554SMatthew G. Knepley 39432f856554SMatthew G. Knepley /*@C 39442f856554SMatthew G. Knepley DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 39452f856554SMatthew G. Knepley 39462f856554SMatthew G. Knepley Input Parameters: 3947a1cb98faSBarry Smith + dm - The `DM` 39482f856554SMatthew G. Knepley . fStart - The first face to include 39492f856554SMatthew G. Knepley . fEnd - The first face to exclude 39502f856554SMatthew G. Knepley . locX - A local vector with the solution fields 39512f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 39522f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 39532f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 395460225df5SJacob Faibussowitsch - locGrad - A local vector with field gradients, or NULL 39552f856554SMatthew G. Knepley 39562f856554SMatthew G. Knepley Output Parameters: 39572f856554SMatthew G. Knepley + Nface - The number of faces with field values 39582f856554SMatthew G. Knepley . uL - The field values at the left side of the face 39592f856554SMatthew G. Knepley - uR - The field values at the right side of the face 39602f856554SMatthew G. Knepley 39612f856554SMatthew G. Knepley Level: developer 39622f856554SMatthew G. Knepley 39631cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 39642f856554SMatthew G. Knepley @*/ 3965d71ae5a4SJacob 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) 3966d71ae5a4SJacob Faibussowitsch { 39672f856554SMatthew G. Knepley PetscFunctionBegin; 39689566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL)); 39699566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR)); 39703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 39712f856554SMatthew G. Knepley } 39722f856554SMatthew G. Knepley 39732f856554SMatthew G. Knepley /*@C 39742f856554SMatthew G. Knepley DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 39752f856554SMatthew G. Knepley 39762f856554SMatthew G. Knepley Input Parameters: 3977a1cb98faSBarry Smith + dm - The `DM` 39782f856554SMatthew G. Knepley . fStart - The first face to include 39792f856554SMatthew G. Knepley . fEnd - The first face to exclude 39802f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 39812f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 39822f856554SMatthew G. Knepley 39832f856554SMatthew G. Knepley Output Parameters: 39842f856554SMatthew G. Knepley + Nface - The number of faces with field values 39852f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 39862f856554SMatthew G. Knepley - vol - The cell volume 39872f856554SMatthew G. Knepley 39882f856554SMatthew G. Knepley Level: developer 39892f856554SMatthew G. Knepley 39901cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 39912f856554SMatthew G. Knepley @*/ 3992d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3993d71ae5a4SJacob Faibussowitsch { 39942f856554SMatthew G. Knepley DM dmFace, dmCell; 39952f856554SMatthew G. Knepley DMLabel ghostLabel; 39962f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom; 39972f856554SMatthew G. Knepley PetscInt dim, numFaces = fEnd - fStart, iface, face; 39982f856554SMatthew G. Knepley 39992f856554SMatthew G. Knepley PetscFunctionBegin; 40002f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 40012f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 40022f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 40034f572ea9SToby Isaac PetscAssertPointer(fgeom, 7); 40044f572ea9SToby Isaac PetscAssertPointer(vol, 8); 40059566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 40069566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 40079566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 40089566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 40099566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 40109566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 40119566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(numFaces, fgeom)); 40129566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * 2, MPIU_SCALAR, vol)); 40132f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 40142f856554SMatthew G. Knepley const PetscInt *cells; 40152f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 40162f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 40172f856554SMatthew G. Knepley PetscFVFaceGeom *fgeoml = *fgeom; 40182f856554SMatthew G. Knepley PetscReal *voll = *vol; 40192f856554SMatthew G. Knepley PetscInt ghost, d, nchild, nsupp; 40202f856554SMatthew G. Knepley 40219566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 40229566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 40239566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 40242f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 40259566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 40269566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 40279566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 40289566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 40292f856554SMatthew G. Knepley for (d = 0; d < dim; ++d) { 40302f856554SMatthew G. Knepley fgeoml[iface].centroid[d] = fg->centroid[d]; 40312f856554SMatthew G. Knepley fgeoml[iface].normal[d] = fg->normal[d]; 40322f856554SMatthew G. Knepley } 40332f856554SMatthew G. Knepley voll[iface * 2 + 0] = cgL->volume; 40342f856554SMatthew G. Knepley voll[iface * 2 + 1] = cgR->volume; 40352f856554SMatthew G. Knepley ++iface; 40362f856554SMatthew G. Knepley } 40372f856554SMatthew G. Knepley *Nface = iface; 40389566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 40399566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 40403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 40412f856554SMatthew G. Knepley } 40422f856554SMatthew G. Knepley 40432f856554SMatthew G. Knepley /*@C 40442f856554SMatthew G. Knepley DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 40452f856554SMatthew G. Knepley 40462f856554SMatthew G. Knepley Input Parameters: 4047a1cb98faSBarry Smith + dm - The `DM` 40482f856554SMatthew G. Knepley . fStart - The first face to include 40492f856554SMatthew G. Knepley . fEnd - The first face to exclude 40502f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 40512f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 40522f856554SMatthew G. Knepley 40532f856554SMatthew G. Knepley Output Parameters: 40542f856554SMatthew G. Knepley + Nface - The number of faces with field values 40552f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 40562f856554SMatthew G. Knepley - vol - The cell volume 40572f856554SMatthew G. Knepley 40582f856554SMatthew G. Knepley Level: developer 40592f856554SMatthew G. Knepley 40601cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 40612f856554SMatthew G. Knepley @*/ 4062d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 4063d71ae5a4SJacob Faibussowitsch { 40642f856554SMatthew G. Knepley PetscFunctionBegin; 40659566063dSJacob Faibussowitsch PetscCall(PetscFree(*fgeom)); 40669566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol)); 40673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 40682f856554SMatthew G. Knepley } 40692f856554SMatthew G. Knepley 4070d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 4071d71ae5a4SJacob Faibussowitsch { 4072a1cf66bbSMatthew G. Knepley char composeStr[33] = {0}; 4073a1cf66bbSMatthew G. Knepley PetscObjectId id; 4074a1cf66bbSMatthew G. Knepley PetscContainer container; 4075a1cf66bbSMatthew G. Knepley 4076a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 40779566063dSJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)quad, &id)); 407863a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id)); 40799566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container)); 4080a1cf66bbSMatthew G. Knepley if (container) { 40819566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(container, (void **)geom)); 4082a1cf66bbSMatthew G. Knepley } else { 40839566063dSJacob Faibussowitsch PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 40849566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 40859566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(container, (void *)*geom)); 40869566063dSJacob Faibussowitsch PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom)); 40879566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container)); 40889566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&container)); 4089a1cf66bbSMatthew G. Knepley } 40903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4091a1cf66bbSMatthew G. Knepley } 4092a1cf66bbSMatthew G. Knepley 4093d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 4094d71ae5a4SJacob Faibussowitsch { 4095a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 4096a1cf66bbSMatthew G. Knepley *geom = NULL; 40973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4098a1cf66bbSMatthew G. Knepley } 4099a1cf66bbSMatthew G. Knepley 4100d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 4101d71ae5a4SJacob Faibussowitsch { 410292d50984SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 410392d50984SMatthew G. Knepley const char *name = "Residual"; 410492d50984SMatthew G. Knepley DM dmAux = NULL; 410592d50984SMatthew G. Knepley DMLabel ghostLabel = NULL; 410692d50984SMatthew G. Knepley PetscDS prob = NULL; 410792d50984SMatthew G. Knepley PetscDS probAux = NULL; 410892d50984SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 410992d50984SMatthew G. Knepley PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 411092d50984SMatthew G. Knepley DMField coordField = NULL; 4111c0006e53SPatrick Farrell Vec locA; 4112c0006e53SPatrick Farrell PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 411392d50984SMatthew G. Knepley IS chunkIS; 411492d50984SMatthew G. Knepley const PetscInt *cells; 411592d50984SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 4116364207b6SKarl Rupp PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 411792d50984SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 411806ad1575SMatthew G. Knepley PetscFormKey key; 411992d50984SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 412092d50984SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 412192d50984SMatthew G. Knepley 412292d50984SMatthew G. Knepley PetscFunctionBegin; 41239566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 412492d50984SMatthew G. Knepley /* FEM+FVM */ 412592d50984SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 41269566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 41279566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 41289566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 41299566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 41309566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 413192d50984SMatthew G. Knepley if (locA) { 41329566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 41339566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 41349566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 413592d50984SMatthew G. Knepley } 413692d50984SMatthew G. Knepley /* 2: Get geometric data */ 413792d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 413892d50984SMatthew G. Knepley PetscObject obj; 413992d50984SMatthew G. Knepley PetscClassId id; 414092d50984SMatthew G. Knepley PetscBool fimp; 414192d50984SMatthew G. Knepley 41429566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 414392d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 41449566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 41459566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 4146ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 41475f80ce2aSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Use of FVM with PCPATCH not yet implemented"); 414892d50984SMatthew G. Knepley } 414992d50984SMatthew G. Knepley if (useFEM) { 41509566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 41519566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 415292d50984SMatthew G. Knepley if (maxDegree <= 1) { 41539566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 415448a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 415592d50984SMatthew G. Knepley } else { 41569566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 415792d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 415892d50984SMatthew G. Knepley PetscObject obj; 415992d50984SMatthew G. Knepley PetscClassId id; 416092d50984SMatthew G. Knepley PetscBool fimp; 416192d50984SMatthew G. Knepley 41629566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 416392d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 41649566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 41659566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 416692d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 416792d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 416892d50984SMatthew G. Knepley 41699566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 41709566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 41719566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 417292d50984SMatthew G. Knepley } 417392d50984SMatthew G. Knepley } 417492d50984SMatthew G. Knepley } 417592d50984SMatthew G. Knepley } 417692d50984SMatthew G. Knepley /* Loop over chunks */ 41779566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 41789566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 41799566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 418092d50984SMatthew G. Knepley numCells = cEnd - cStart; 418192d50984SMatthew G. Knepley numChunks = 1; 418292d50984SMatthew G. Knepley cellChunkSize = numCells / numChunks; 418392d50984SMatthew G. Knepley numChunks = PetscMin(1, numCells); 41846528b96dSMatthew G. Knepley key.label = NULL; 41856528b96dSMatthew G. Knepley key.value = 0; 418606ad1575SMatthew G. Knepley key.part = 0; 418792d50984SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 4188c0006e53SPatrick Farrell PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 4189c0006e53SPatrick Farrell PetscReal *vol = NULL; 4190c0006e53SPatrick Farrell PetscFVFaceGeom *fgeom = NULL; 419192d50984SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 4192c0006e53SPatrick Farrell PetscInt numFaces = 0; 419392d50984SMatthew G. Knepley 419492d50984SMatthew G. Knepley /* Extract field coefficients */ 419592d50984SMatthew G. Knepley if (useFEM) { 41969566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 41979566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 41989566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 41999566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 420092d50984SMatthew G. Knepley } 420192d50984SMatthew 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 */ 420292d50984SMatthew G. Knepley /* Loop over fields */ 420392d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 420492d50984SMatthew G. Knepley PetscObject obj; 420592d50984SMatthew G. Knepley PetscClassId id; 420692d50984SMatthew G. Knepley PetscBool fimp; 420792d50984SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 420892d50984SMatthew G. Knepley 42096528b96dSMatthew G. Knepley key.field = f; 42109566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 421192d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 42129566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 42139566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 421492d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 421592d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 421692d50984SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 421792d50984SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 421892d50984SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 421992d50984SMatthew G. Knepley PetscInt Nq, Nb; 422092d50984SMatthew G. Knepley 42219566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 42229566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 42239566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 422492d50984SMatthew G. Knepley blockSize = Nb; 422592d50984SMatthew G. Knepley batchSize = numBlocks * blockSize; 42269566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 422792d50984SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 422892d50984SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 422992d50984SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 423092d50984SMatthew G. Knepley offset = numCells - Nr; 423192d50984SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 423292d50984SMatthew 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) */ 42339566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 42349566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 42359566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 42369566063dSJacob 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])); 42379566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 423892d50984SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 423992d50984SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 424092d50984SMatthew G. Knepley 424192d50984SMatthew G. Knepley Ne = numFaces; 424292d50984SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 424392d50984SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 42449566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 424563a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 424692d50984SMatthew G. Knepley } 424792d50984SMatthew G. Knepley /* Loop over domain */ 424892d50984SMatthew G. Knepley if (useFEM) { 424992d50984SMatthew G. Knepley /* Add elemVec to locX */ 425092d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 425192d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 425292d50984SMatthew G. Knepley const PetscInt cind = c - cStart; 425392d50984SMatthew G. Knepley 42549566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 425592d50984SMatthew G. Knepley if (ghostLabel) { 425692d50984SMatthew G. Knepley PetscInt ghostVal; 425792d50984SMatthew G. Knepley 42589566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 425992d50984SMatthew G. Knepley if (ghostVal > 0) continue; 426092d50984SMatthew G. Knepley } 42619566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 426292d50984SMatthew G. Knepley } 426392d50984SMatthew G. Knepley } 426492d50984SMatthew G. Knepley /* Handle time derivative */ 426592d50984SMatthew G. Knepley if (locX_t) { 426692d50984SMatthew G. Knepley PetscScalar *x_t, *fa; 426792d50984SMatthew G. Knepley 42689566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 42699566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 427092d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 427192d50984SMatthew G. Knepley PetscFV fv; 427292d50984SMatthew G. Knepley PetscObject obj; 427392d50984SMatthew G. Knepley PetscClassId id; 427492d50984SMatthew G. Knepley PetscInt pdim, d; 427592d50984SMatthew G. Knepley 42769566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 42779566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 427892d50984SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 427992d50984SMatthew G. Knepley fv = (PetscFV)obj; 42809566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 428192d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 428292d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 428392d50984SMatthew G. Knepley PetscScalar *u_t, *r; 428492d50984SMatthew G. Knepley 428592d50984SMatthew G. Knepley if (ghostLabel) { 428692d50984SMatthew G. Knepley PetscInt ghostVal; 428792d50984SMatthew G. Knepley 42889566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 428992d50984SMatthew G. Knepley if (ghostVal > 0) continue; 429092d50984SMatthew G. Knepley } 42919566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 42929566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 429392d50984SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 429492d50984SMatthew G. Knepley } 429592d50984SMatthew G. Knepley } 42969566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 42979566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 429892d50984SMatthew G. Knepley } 429992d50984SMatthew G. Knepley if (useFEM) { 43009566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 43019566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 430292d50984SMatthew G. Knepley } 430392d50984SMatthew G. Knepley } 43049566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 43059566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 430692d50984SMatthew G. Knepley /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 430792d50984SMatthew G. Knepley if (useFEM) { 430892d50984SMatthew G. Knepley if (maxDegree <= 1) { 43099566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 43109566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 431192d50984SMatthew G. Knepley } else { 431292d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 43139566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 43149566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 431592d50984SMatthew G. Knepley } 43169566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 431792d50984SMatthew G. Knepley } 431892d50984SMatthew G. Knepley } 43199566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 43203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 432192d50984SMatthew G. Knepley } 432292d50984SMatthew G. Knepley 4323a1cf66bbSMatthew G. Knepley /* 4324a1cf66bbSMatthew 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 4325a1cf66bbSMatthew G. Knepley 4326a1cf66bbSMatthew G. Knepley X - The local solution vector 4327a5b23f4aSJose E. Roman X_t - The local solution time derivative vector, or NULL 4328a1cf66bbSMatthew G. Knepley */ 4329d71ae5a4SJacob 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) 4330d71ae5a4SJacob Faibussowitsch { 4331a1cf66bbSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 4332a1cf66bbSMatthew G. Knepley const char *name = "Jacobian", *nameP = "JacobianPre"; 4333a1cf66bbSMatthew G. Knepley DM dmAux = NULL; 4334a1cf66bbSMatthew G. Knepley PetscDS prob, probAux = NULL; 4335a1cf66bbSMatthew G. Knepley PetscSection sectionAux = NULL; 4336a1cf66bbSMatthew G. Knepley Vec A; 4337a1cf66bbSMatthew G. Knepley DMField coordField; 4338a1cf66bbSMatthew G. Knepley PetscFEGeom *cgeomFEM; 4339a1cf66bbSMatthew G. Knepley PetscQuadrature qGeom = NULL; 4340a1cf66bbSMatthew G. Knepley Mat J = Jac, JP = JacP; 4341a1cf66bbSMatthew G. Knepley PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 4342e432b41dSStefano Zampini PetscBool hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE; 4343a1cf66bbSMatthew G. Knepley const PetscInt *cells; 434406ad1575SMatthew G. Knepley PetscFormKey key; 43459b2fc754SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 4346a1cf66bbSMatthew G. Knepley 4347a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 43489566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 43499566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 43509566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 43519566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 43529566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A)); 43539a2a23afSMatthew G. Knepley if (A) { 43549566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 43559566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 43569566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 4357a1cf66bbSMatthew G. Knepley } 4358a1cf66bbSMatthew G. Knepley /* Get flags */ 43599566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 43609566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4361a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4362a1cf66bbSMatthew G. Knepley PetscObject disc; 4363a1cf66bbSMatthew G. Knepley PetscClassId id; 43649566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc)); 43659566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(disc, &id)); 43669371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 43679371c9d4SSatish Balay isFE[fieldI] = PETSC_TRUE; 43689371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 43699371c9d4SSatish Balay hasFV = PETSC_TRUE; 43709371c9d4SSatish Balay isFE[fieldI] = PETSC_FALSE; 43719371c9d4SSatish Balay } 4372a1cf66bbSMatthew G. Knepley } 43739566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 43749566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 43759566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 4376a1cf66bbSMatthew G. Knepley assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 4377a1cf66bbSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 43789566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */ 43799566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 43809566063dSJacob Faibussowitsch if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4381a1cf66bbSMatthew G. Knepley /* Compute batch sizes */ 4382a1cf66bbSMatthew G. Knepley if (isFE[0]) { 4383a1cf66bbSMatthew G. Knepley PetscFE fe; 4384a1cf66bbSMatthew G. Knepley PetscQuadrature q; 4385a1cf66bbSMatthew G. Knepley PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 4386a1cf66bbSMatthew G. Knepley 43879566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 43889566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 43899566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL)); 43909566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 43919566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4392a1cf66bbSMatthew G. Knepley blockSize = Nb * numQuadPoints; 4393a1cf66bbSMatthew G. Knepley batchSize = numBlocks * blockSize; 4394a1cf66bbSMatthew G. Knepley chunkSize = numBatches * batchSize; 4395a1cf66bbSMatthew G. Knepley numChunks = numCells / chunkSize + numCells % chunkSize; 43969566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4397a1cf66bbSMatthew G. Knepley } else { 4398a1cf66bbSMatthew G. Knepley chunkSize = numCells; 4399a1cf66bbSMatthew G. Knepley numChunks = 1; 4400a1cf66bbSMatthew G. Knepley } 4401a1cf66bbSMatthew G. Knepley /* Get work space */ 4402a1cf66bbSMatthew 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; 44039566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work)); 44049566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(work, wsz)); 4405a1cf66bbSMatthew G. Knepley off = 0; 4406a1cf66bbSMatthew G. Knepley u = X ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4407a1cf66bbSMatthew G. Knepley u_t = X_t ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4408a1cf66bbSMatthew G. Knepley a = dmAux ? (sz = chunkSize * totDimAux, off += sz, work + off - sz) : NULL; 4409a1cf66bbSMatthew G. Knepley elemMat = hasJac ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4410a1cf66bbSMatthew G. Knepley elemMatP = hasPrec ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4411a1cf66bbSMatthew G. Knepley elemMatD = hasDyn ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 441263a3b9bcSJacob Faibussowitsch PetscCheck(off == wsz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %" PetscInt_FMT " should be %" PetscInt_FMT, off, wsz); 4413a1cf66bbSMatthew G. Knepley /* Setup geometry */ 44149566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 44159566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 44169566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 4417a1cf66bbSMatthew G. Knepley if (!qGeom) { 4418a1cf66bbSMatthew G. Knepley PetscFE fe; 4419a1cf66bbSMatthew G. Knepley 44209566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 44219566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 44229566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 4423a1cf66bbSMatthew G. Knepley } 44249566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4425a1cf66bbSMatthew G. Knepley /* Compute volume integrals */ 44269566063dSJacob Faibussowitsch if (assembleJac) PetscCall(MatZeroEntries(J)); 44279566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(JP)); 44286528b96dSMatthew G. Knepley key.label = NULL; 44296528b96dSMatthew G. Knepley key.value = 0; 443006ad1575SMatthew G. Knepley key.part = 0; 4431a1cf66bbSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 4432a1cf66bbSMatthew G. Knepley const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 4433a1cf66bbSMatthew G. Knepley PetscInt c; 4434a1cf66bbSMatthew G. Knepley 4435a1cf66bbSMatthew G. Knepley /* Extract values */ 4436a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4437a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4438a1cf66bbSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 4439a1cf66bbSMatthew G. Knepley PetscInt i; 4440a1cf66bbSMatthew G. Knepley 4441a1cf66bbSMatthew G. Knepley if (X) { 44429566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 4443a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 44449566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 4445a1cf66bbSMatthew G. Knepley } 4446a1cf66bbSMatthew G. Knepley if (X_t) { 44479566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 4448a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[c * totDim + i] = x_t[i]; 44499566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 4450a1cf66bbSMatthew G. Knepley } 4451a1cf66bbSMatthew G. Knepley if (dmAux) { 44529566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4453a1cf66bbSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 44549566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4455a1cf66bbSMatthew G. Knepley } 4456a1cf66bbSMatthew G. Knepley } 4457a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4458a1cf66bbSMatthew G. Knepley PetscFE fe; 44599566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 4460a1cf66bbSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 44616528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 44629566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat)); 44639566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP)); 44649566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD)); 4465a1cf66bbSMatthew G. Knepley } 4466a1cf66bbSMatthew G. Knepley /* For finite volume, add the identity */ 4467a1cf66bbSMatthew G. Knepley if (!isFE[fieldI]) { 4468a1cf66bbSMatthew G. Knepley PetscFV fv; 4469a1cf66bbSMatthew G. Knepley PetscInt eOffset = 0, Nc, fc, foff; 4470a1cf66bbSMatthew G. Knepley 44719566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff)); 44729566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 44739566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 4474a1cf66bbSMatthew G. Knepley for (c = 0; c < chunkSize; ++c, eOffset += totDim * totDim) { 4475a1cf66bbSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 4476a1cf66bbSMatthew G. Knepley const PetscInt i = foff + fc; 4477ad540459SPierre Jolivet if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 4478ad540459SPierre Jolivet if (hasPrec) elemMatP[eOffset + i * totDim + i] = 1.0; 4479a1cf66bbSMatthew G. Knepley } 4480a1cf66bbSMatthew G. Knepley } 4481a1cf66bbSMatthew G. Knepley } 4482a1cf66bbSMatthew G. Knepley } 4483a1cf66bbSMatthew G. Knepley /* Add contribution from X_t */ 44849371c9d4SSatish Balay if (hasDyn) { 44859371c9d4SSatish Balay for (c = 0; c < chunkSize * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 44869371c9d4SSatish Balay } 4487a1cf66bbSMatthew G. Knepley /* Insert values into matrix */ 4488a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4489a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4490a1cf66bbSMatthew G. Knepley if (mesh->printFEM > 1) { 44919566063dSJacob Faibussowitsch if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c - cStart) * totDim * totDim])); 44929566063dSJacob Faibussowitsch if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c - cStart) * totDim * totDim])); 4493a1cf66bbSMatthew G. Knepley } 4494e8e188d2SZach Atkins if (assembleJac) PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4495e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JP, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4496a1cf66bbSMatthew G. Knepley } 4497a1cf66bbSMatthew G. Knepley } 4498a1cf66bbSMatthew G. Knepley /* Cleanup */ 44999566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 45009566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 45019566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 45029566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 45039566063dSJacob 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)); 4504a1cf66bbSMatthew G. Knepley /* Compute boundary integrals */ 45059566063dSJacob Faibussowitsch /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */ 4506a1cf66bbSMatthew G. Knepley /* Assemble matrix */ 45079371c9d4SSatish Balay if (assembleJac) { 45089371c9d4SSatish Balay PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 45099371c9d4SSatish Balay PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 45109371c9d4SSatish Balay } 45119371c9d4SSatish Balay PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 45129371c9d4SSatish Balay PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 45139566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 45143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4515a1cf66bbSMatthew G. Knepley } 45163e9753d6SMatthew G. Knepley 45173e9753d6SMatthew G. Knepley /******** FEM Assembly Function ********/ 45183e9753d6SMatthew G. Knepley 4519d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy) 4520d71ae5a4SJacob Faibussowitsch { 45213e9753d6SMatthew G. Knepley PetscBool isPlex; 45223e9753d6SMatthew G. Knepley 45233e9753d6SMatthew G. Knepley PetscFunctionBegin; 45249566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 45253e9753d6SMatthew G. Knepley if (isPlex) { 45263e9753d6SMatthew G. Knepley *plex = dm; 45279566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 45283e9753d6SMatthew G. Knepley } else { 45299566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 45303e9753d6SMatthew G. Knepley if (!*plex) { 45319566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 45329566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 45331baa6e33SBarry Smith if (copy) PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 45343e9753d6SMatthew G. Knepley } else { 45359566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)*plex)); 45363e9753d6SMatthew G. Knepley } 45373e9753d6SMatthew G. Knepley } 45383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 45393e9753d6SMatthew G. Knepley } 45403e9753d6SMatthew G. Knepley 45413e9753d6SMatthew G. Knepley /*@ 45423e9753d6SMatthew G. Knepley DMPlexGetGeometryFVM - Return precomputed geometric data 45433e9753d6SMatthew G. Knepley 454420f4b53cSBarry Smith Collective 45453e9753d6SMatthew G. Knepley 45463e9753d6SMatthew G. Knepley Input Parameter: 4547a1cb98faSBarry Smith . dm - The `DM` 45483e9753d6SMatthew G. Knepley 45493e9753d6SMatthew G. Knepley Output Parameters: 45503e9753d6SMatthew G. Knepley + facegeom - The values precomputed from face geometry 45513e9753d6SMatthew G. Knepley . cellgeom - The values precomputed from cell geometry 45523e9753d6SMatthew G. Knepley - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell 45533e9753d6SMatthew G. Knepley 45543e9753d6SMatthew G. Knepley Level: developer 45553e9753d6SMatthew G. Knepley 45561cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMTSSetRHSFunctionLocal()` 45573e9753d6SMatthew G. Knepley @*/ 4558d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius) 4559d71ae5a4SJacob Faibussowitsch { 45603e9753d6SMatthew G. Knepley DM plex; 45613e9753d6SMatthew G. Knepley 45623e9753d6SMatthew G. Knepley PetscFunctionBegin; 45633e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 45649566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 45659566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL)); 45669566063dSJacob Faibussowitsch if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius)); 45679566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 45683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 45693e9753d6SMatthew G. Knepley } 45703e9753d6SMatthew G. Knepley 45713e9753d6SMatthew G. Knepley /*@ 45723e9753d6SMatthew G. Knepley DMPlexGetGradientDM - Return gradient data layout 45733e9753d6SMatthew G. Knepley 457420f4b53cSBarry Smith Collective 45753e9753d6SMatthew G. Knepley 45763e9753d6SMatthew G. Knepley Input Parameters: 4577a1cb98faSBarry Smith + dm - The `DM` 457820f4b53cSBarry Smith - fv - The `PetscFV` 45793e9753d6SMatthew G. Knepley 45803e9753d6SMatthew G. Knepley Output Parameter: 45813e9753d6SMatthew G. Knepley . dmGrad - The layout for gradient values 45823e9753d6SMatthew G. Knepley 45833e9753d6SMatthew G. Knepley Level: developer 45843e9753d6SMatthew G. Knepley 45851cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetGeometryFVM()` 45863e9753d6SMatthew G. Knepley @*/ 4587d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad) 4588d71ae5a4SJacob Faibussowitsch { 45893e9753d6SMatthew G. Knepley DM plex; 45903e9753d6SMatthew G. Knepley PetscBool computeGradients; 45913e9753d6SMatthew G. Knepley 45923e9753d6SMatthew G. Knepley PetscFunctionBegin; 45933e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 45943e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 45954f572ea9SToby Isaac PetscAssertPointer(dmGrad, 3); 45969566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &computeGradients)); 45979371c9d4SSatish Balay if (!computeGradients) { 45989371c9d4SSatish Balay *dmGrad = NULL; 45993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 46009371c9d4SSatish Balay } 46019566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 46029566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad)); 46039566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 46043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 46053e9753d6SMatthew G. Knepley } 46063e9753d6SMatthew G. Knepley 4607d71ae5a4SJacob 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) 4608d71ae5a4SJacob Faibussowitsch { 46093e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 46103e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL; 46113e9753d6SMatthew G. Knepley DMEnclosureType encAux; 46123e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 46133e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 46143e9753d6SMatthew G. Knepley Vec locA = NULL; 46153e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL; 46163e9753d6SMatthew G. Knepley PetscInt totDim, totDimAux = 0; 46173e9753d6SMatthew G. Knepley 46183e9753d6SMatthew G. Knepley PetscFunctionBegin; 46199566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 46209566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 46219566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 46229566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 46239566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 46243e9753d6SMatthew G. Knepley if (locA) { 46253e9753d6SMatthew G. Knepley DM dmAux; 46263e9753d6SMatthew G. Knepley 46279566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 46289566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 46299566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 46309566063dSJacob Faibussowitsch PetscCall(DMGetDS(plexA, &probAux)); 46319566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 46329566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 46333e9753d6SMatthew G. Knepley } 46340c290148SMatthew G. Knepley { 46353e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 46363e9753d6SMatthew G. Knepley PetscInt maxDegree; 46373e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 46383e9753d6SMatthew G. Knepley IS pointIS; 46393e9753d6SMatthew G. Knepley const PetscInt *points; 46403e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 46413e9753d6SMatthew G. Knepley 46429566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 46430c290148SMatthew G. Knepley if (!pointIS) goto end; /* No points with that id on this process */ 46443e9753d6SMatthew G. Knepley { 46453e9753d6SMatthew G. Knepley IS isectIS; 46463e9753d6SMatthew G. Knepley 46473e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 46489566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 46499566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 46503e9753d6SMatthew G. Knepley pointIS = isectIS; 46513e9753d6SMatthew G. Knepley } 46529566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 46539566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 46549566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim, &elemVec, locA ? numFaces * totDimAux : 0, &a)); 46559566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 465648a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 46573e9753d6SMatthew G. Knepley if (!qGeom) { 46583e9753d6SMatthew G. Knepley PetscFE fe; 46593e9753d6SMatthew G. Knepley 46609566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 46619566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 46629566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 46633e9753d6SMatthew G. Knepley } 46649566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 46659566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 46663e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 4667f15274beSMatthew Knepley const PetscInt point = points[face], *support; 46683e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 4669f15274beSMatthew Knepley PetscInt i; 46703e9753d6SMatthew G. Knepley 46719566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 46729566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 46733e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 46749566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 46753e9753d6SMatthew G. Knepley if (locX_t) { 46769566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 46773e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 46789566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 46793e9753d6SMatthew G. Knepley } 46803e9753d6SMatthew G. Knepley if (locA) { 46813e9753d6SMatthew G. Knepley PetscInt subp; 46823e9753d6SMatthew G. Knepley 46839566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 46849566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 46853e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 46869566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 46873e9753d6SMatthew G. Knepley } 46883e9753d6SMatthew G. Knepley } 46899566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numFaces * totDim)); 46903e9753d6SMatthew G. Knepley { 46913e9753d6SMatthew G. Knepley PetscFE fe; 46923e9753d6SMatthew G. Knepley PetscInt Nb; 46933e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 46943e9753d6SMatthew G. Knepley /* Conforming batches */ 46953e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 46963e9753d6SMatthew G. Knepley /* Remainder */ 46973e9753d6SMatthew G. Knepley PetscInt Nr, offset; 46983e9753d6SMatthew G. Knepley 46999566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 47009566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 47019566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 47023e9753d6SMatthew G. Knepley /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */ 47033e9753d6SMatthew G. Knepley blockSize = Nb; 47043e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 47059566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 47063e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 47073e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 47083e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 47093e9753d6SMatthew G. Knepley offset = numFaces - Nr; 47109566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 47119566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 47129566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 47139566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 47149566063dSJacob 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])); 47159566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 47163e9753d6SMatthew G. Knepley } 47173e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 47183e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 47193e9753d6SMatthew G. Knepley 47209566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face * totDim])); 47219566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 47229566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face * totDim], ADD_ALL_VALUES)); 47233e9753d6SMatthew G. Knepley } 47249566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 47259566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 47269566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 47279566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 47289566063dSJacob Faibussowitsch PetscCall(PetscFree4(u, u_t, elemVec, a)); 47293e9753d6SMatthew G. Knepley } 47300c290148SMatthew G. Knepley end: 47319566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 47329566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexA)); 47333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 47343e9753d6SMatthew G. Knepley } 47353e9753d6SMatthew G. Knepley 4736d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF) 4737d71ae5a4SJacob Faibussowitsch { 47383e9753d6SMatthew G. Knepley DMField coordField; 47393e9753d6SMatthew G. Knepley DMLabel depthLabel; 47403e9753d6SMatthew G. Knepley IS facetIS; 47413e9753d6SMatthew G. Knepley PetscInt dim; 47423e9753d6SMatthew G. Knepley 47433e9753d6SMatthew G. Knepley PetscFunctionBegin; 47449566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 47459566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 47469566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 47479566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 47489566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 47499566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 47503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 47513e9753d6SMatthew G. Knepley } 47523e9753d6SMatthew G. Knepley 4753a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4754d71ae5a4SJacob Faibussowitsch { 47553e9753d6SMatthew G. Knepley PetscDS prob; 47563e9753d6SMatthew G. Knepley PetscInt numBd, bd; 47573e9753d6SMatthew G. Knepley DMField coordField = NULL; 47583e9753d6SMatthew G. Knepley IS facetIS = NULL; 47593e9753d6SMatthew G. Knepley DMLabel depthLabel; 47603e9753d6SMatthew G. Knepley PetscInt dim; 47613e9753d6SMatthew G. Knepley 47623e9753d6SMatthew G. Knepley PetscFunctionBegin; 47639566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 47649566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 47659566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 47669566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 47679566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 47683e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 476945480ffeSMatthew G. Knepley PetscWeakForm wf; 47703e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 47713e9753d6SMatthew G. Knepley DMLabel label; 47723e9753d6SMatthew G. Knepley const PetscInt *values; 47730c290148SMatthew G. Knepley PetscInt field, numValues, v; 47743e9753d6SMatthew G. Knepley PetscObject obj; 47753e9753d6SMatthew G. Knepley PetscClassId id; 47760c290148SMatthew G. Knepley PetscFormKey key; 47773e9753d6SMatthew G. Knepley 47789566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL)); 47793d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 47809566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 47819566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 47823d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 47833e9753d6SMatthew G. Knepley if (!facetIS) { 47843e9753d6SMatthew G. Knepley DMLabel depthLabel; 47853e9753d6SMatthew G. Knepley PetscInt dim; 47863e9753d6SMatthew G. Knepley 47879566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 47889566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 47899566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 47903e9753d6SMatthew G. Knepley } 47919566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 47920c290148SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 47930c290148SMatthew G. Knepley key.label = label; 47940c290148SMatthew G. Knepley key.value = values[v]; 47950c290148SMatthew G. Knepley key.field = field; 47960c290148SMatthew G. Knepley key.part = 0; 47979566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 47980c290148SMatthew G. Knepley } 47993e9753d6SMatthew G. Knepley } 48009566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 48013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 48023e9753d6SMatthew G. Knepley } 48033e9753d6SMatthew G. Knepley 4804d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4805d71ae5a4SJacob Faibussowitsch { 48063e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 48073e9753d6SMatthew G. Knepley const char *name = "Residual"; 48083e9753d6SMatthew G. Knepley DM dmAux = NULL; 48093e9753d6SMatthew G. Knepley DM dmGrad = NULL; 48103e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 48116528b96dSMatthew G. Knepley PetscDS ds = NULL; 48126528b96dSMatthew G. Knepley PetscDS dsAux = NULL; 48133e9753d6SMatthew G. Knepley PetscSection section = NULL; 48143e9753d6SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 48153e9753d6SMatthew G. Knepley PetscBool useFVM = PETSC_FALSE; 48163e9753d6SMatthew G. Knepley PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 48173e9753d6SMatthew G. Knepley PetscFV fvm = NULL; 48183e9753d6SMatthew G. Knepley PetscFVCellGeom *cgeomFVM = NULL; 48193e9753d6SMatthew G. Knepley PetscFVFaceGeom *fgeomFVM = NULL; 48203e9753d6SMatthew G. Knepley DMField coordField = NULL; 48213e9753d6SMatthew G. Knepley Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL; 48223e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t, *a, *uL, *uR; 48233e9753d6SMatthew G. Knepley IS chunkIS; 48243e9753d6SMatthew G. Knepley const PetscInt *cells; 48253e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 48263e9753d6SMatthew G. Knepley PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd; 48273e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 48283e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 48293e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 48303e9753d6SMatthew G. Knepley 48313e9753d6SMatthew G. Knepley PetscFunctionBegin; 48323ba16761SJacob Faibussowitsch if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 4833437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 48343ba16761SJacob Faibussowitsch if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 48359566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 48363e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 48373e9753d6SMatthew G. Knepley /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */ 48383e9753d6SMatthew G. Knepley /* FEM+FVM */ 48399566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 48403e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 48419566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 48429566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 484307218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, NULL)); 48449566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 48459566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 48469566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 48473e9753d6SMatthew G. Knepley if (locA) { 48483e9753d6SMatthew G. Knepley PetscInt subcell; 48499566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 48501059d808SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell)); 485107218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux, subcell, &dsAux, NULL)); 48529566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 48533e9753d6SMatthew G. Knepley } 48543e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 48553e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 48563e9753d6SMatthew G. Knepley PetscObject obj; 48573e9753d6SMatthew G. Knepley PetscClassId id; 48583e9753d6SMatthew G. Knepley PetscBool fimp; 48593e9753d6SMatthew G. Knepley 48609566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 48613e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 48629566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 48639566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 4864ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 48659371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 48669371c9d4SSatish Balay useFVM = PETSC_TRUE; 48679371c9d4SSatish Balay fvm = (PetscFV)obj; 48689371c9d4SSatish Balay } 48693e9753d6SMatthew G. Knepley } 48703e9753d6SMatthew G. Knepley if (useFEM) { 48719566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 48729566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 48733e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 48749566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 487548a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 48763e9753d6SMatthew G. Knepley } else { 48779566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 48783e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 48793e9753d6SMatthew G. Knepley PetscObject obj; 48803e9753d6SMatthew G. Knepley PetscClassId id; 48813e9753d6SMatthew G. Knepley PetscBool fimp; 48823e9753d6SMatthew G. Knepley 48839566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 48843e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 48859566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 48869566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 48873e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 48883e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 48893e9753d6SMatthew G. Knepley 48909566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 48919566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 48929566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 48933e9753d6SMatthew G. Knepley } 48943e9753d6SMatthew G. Knepley } 48953e9753d6SMatthew G. Knepley } 48963e9753d6SMatthew G. Knepley } 48973e9753d6SMatthew G. Knepley if (useFVM) { 48989566063dSJacob Faibussowitsch PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 48999566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometryFVM, (const PetscScalar **)&fgeomFVM)); 49009566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 49013e9753d6SMatthew G. Knepley /* Reconstruct and limit cell gradients */ 49029566063dSJacob Faibussowitsch PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad)); 49033e9753d6SMatthew G. Knepley if (dmGrad) { 49049566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 49059566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmGrad, &grad)); 49069566063dSJacob Faibussowitsch PetscCall(DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 49073e9753d6SMatthew G. Knepley /* Communicate gradient values */ 49089566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 49099566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 49109566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 49119566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 49123e9753d6SMatthew G. Knepley } 49133e9753d6SMatthew G. Knepley /* Handle non-essential (e.g. outflow) boundary values */ 49149566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad)); 49153e9753d6SMatthew G. Knepley } 49163e9753d6SMatthew G. Knepley /* Loop over chunks */ 49179566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 49183e9753d6SMatthew G. Knepley numCells = cEnd - cStart; 49193e9753d6SMatthew G. Knepley numChunks = 1; 49203e9753d6SMatthew G. Knepley cellChunkSize = numCells / numChunks; 49213e9753d6SMatthew G. Knepley faceChunkSize = (fEnd - fStart) / numChunks; 49223e9753d6SMatthew G. Knepley numChunks = PetscMin(1, numCells); 49233e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 49243e9753d6SMatthew G. Knepley PetscScalar *elemVec, *fluxL, *fluxR; 49253e9753d6SMatthew G. Knepley PetscReal *vol; 49263e9753d6SMatthew G. Knepley PetscFVFaceGeom *fgeom; 49273e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 49283e9753d6SMatthew G. Knepley PetscInt fS = fStart + chunk * faceChunkSize, fE = PetscMin(fS + faceChunkSize, fEnd), numFaces = 0, face; 49293e9753d6SMatthew G. Knepley 49303e9753d6SMatthew G. Knepley /* Extract field coefficients */ 49313e9753d6SMatthew G. Knepley if (useFEM) { 49329566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 49339566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 49349566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 49359566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 49363e9753d6SMatthew G. Knepley } 49373e9753d6SMatthew G. Knepley if (useFVM) { 49389566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 49399566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 49409566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 49419566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 49429566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxL, numFaces * totDim)); 49439566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxR, numFaces * totDim)); 49443e9753d6SMatthew G. Knepley } 49453e9753d6SMatthew 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 */ 49463e9753d6SMatthew G. Knepley /* Loop over fields */ 49473e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 49483e9753d6SMatthew G. Knepley PetscObject obj; 49493e9753d6SMatthew G. Knepley PetscClassId id; 49503e9753d6SMatthew G. Knepley PetscBool fimp; 49513e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 49523e9753d6SMatthew G. Knepley 49536528b96dSMatthew G. Knepley key.field = f; 49549566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 49553e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 49569566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 49579566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 49583e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 49593e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 49603e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 49613e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 49623e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 49633e9753d6SMatthew G. Knepley PetscInt Nq, Nb; 49643e9753d6SMatthew G. Knepley 49659566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 49669566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 49679566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 49683e9753d6SMatthew G. Knepley blockSize = Nb; 49693e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 49709566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 49713e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 49723e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 49733e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 49743e9753d6SMatthew G. Knepley offset = numCells - Nr; 49753e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 49763e9753d6SMatthew 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) */ 49779566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 49789566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec)); 49799566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 4980072f5ffdSStefano Zampini PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux, a ? &a[offset * totDimAux] : NULL, t, &elemVec[offset * totDim])); 49819566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 49823e9753d6SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 49833e9753d6SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 49843e9753d6SMatthew G. Knepley 49853e9753d6SMatthew G. Knepley Ne = numFaces; 49863e9753d6SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 49873e9753d6SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 49889566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 498963a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 49903e9753d6SMatthew G. Knepley } 49913e9753d6SMatthew G. Knepley /* Loop over domain */ 49923e9753d6SMatthew G. Knepley if (useFEM) { 49933e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 49943e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 49953e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 49963e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 49973e9753d6SMatthew G. Knepley 49989566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 49993e9753d6SMatthew G. Knepley if (ghostLabel) { 50003e9753d6SMatthew G. Knepley PetscInt ghostVal; 50013e9753d6SMatthew G. Knepley 50029566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 50033e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 50043e9753d6SMatthew G. Knepley } 50059566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 50063e9753d6SMatthew G. Knepley } 50073e9753d6SMatthew G. Knepley } 50083e9753d6SMatthew G. Knepley if (useFVM) { 50093e9753d6SMatthew G. Knepley PetscScalar *fa; 50103e9753d6SMatthew G. Knepley PetscInt iface; 50113e9753d6SMatthew G. Knepley 50129566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 50133e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 50143e9753d6SMatthew G. Knepley PetscFV fv; 50153e9753d6SMatthew G. Knepley PetscObject obj; 50163e9753d6SMatthew G. Knepley PetscClassId id; 50173e9753d6SMatthew G. Knepley PetscInt foff, pdim; 50183e9753d6SMatthew G. Knepley 50199566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 50209566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(ds, f, &foff)); 50219566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 50223e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 50233e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 50249566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 50253e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 50263e9753d6SMatthew G. Knepley for (face = fS, iface = 0; face < fE; ++face) { 50273e9753d6SMatthew G. Knepley const PetscInt *scells; 50283e9753d6SMatthew G. Knepley PetscScalar *fL = NULL, *fR = NULL; 50293e9753d6SMatthew G. Knepley PetscInt ghost, d, nsupp, nchild; 50303e9753d6SMatthew G. Knepley 50319566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 50329566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 50339566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 50343e9753d6SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 50359566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &scells)); 50369566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[0], &ghost)); 50379566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL)); 50389566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[1], &ghost)); 50399566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR)); 50403e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) { 50413e9753d6SMatthew G. Knepley if (fL) fL[d] -= fluxL[iface * totDim + foff + d]; 50423e9753d6SMatthew G. Knepley if (fR) fR[d] += fluxR[iface * totDim + foff + d]; 50433e9753d6SMatthew G. Knepley } 50443e9753d6SMatthew G. Knepley ++iface; 50453e9753d6SMatthew G. Knepley } 50463e9753d6SMatthew G. Knepley } 50479566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 50483e9753d6SMatthew G. Knepley } 50493e9753d6SMatthew G. Knepley /* Handle time derivative */ 50503e9753d6SMatthew G. Knepley if (locX_t) { 50513e9753d6SMatthew G. Knepley PetscScalar *x_t, *fa; 50523e9753d6SMatthew G. Knepley 50539566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 50549566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 50553e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 50563e9753d6SMatthew G. Knepley PetscFV fv; 50573e9753d6SMatthew G. Knepley PetscObject obj; 50583e9753d6SMatthew G. Knepley PetscClassId id; 50593e9753d6SMatthew G. Knepley PetscInt pdim, d; 50603e9753d6SMatthew G. Knepley 50619566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 50629566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 50633e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 50643e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 50659566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 50663e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 50673e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 50683e9753d6SMatthew G. Knepley PetscScalar *u_t, *r; 50693e9753d6SMatthew G. Knepley 50703e9753d6SMatthew G. Knepley if (ghostLabel) { 50713e9753d6SMatthew G. Knepley PetscInt ghostVal; 50723e9753d6SMatthew G. Knepley 50739566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 50743e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 50753e9753d6SMatthew G. Knepley } 50769566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 50779566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 50783e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 50793e9753d6SMatthew G. Knepley } 50803e9753d6SMatthew G. Knepley } 50819566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 50829566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 50833e9753d6SMatthew G. Knepley } 50843e9753d6SMatthew G. Knepley if (useFEM) { 50859566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 50869566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 50873e9753d6SMatthew G. Knepley } 50883e9753d6SMatthew G. Knepley if (useFVM) { 50899566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 50909566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 50919566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 50929566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 50939566063dSJacob Faibussowitsch if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 50943e9753d6SMatthew G. Knepley } 50953e9753d6SMatthew G. Knepley } 50969566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 50979566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 50983e9753d6SMatthew G. Knepley 50993e9753d6SMatthew G. Knepley if (useFEM) { 51009566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user)); 51013e9753d6SMatthew G. Knepley 51023e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 51039566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 51049566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 51053e9753d6SMatthew G. Knepley } else { 51063e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 51079566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 51089566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 51093e9753d6SMatthew G. Knepley } 51109566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 51113e9753d6SMatthew G. Knepley } 51123e9753d6SMatthew G. Knepley } 51133e9753d6SMatthew G. Knepley 51143e9753d6SMatthew G. Knepley /* FEM */ 51153e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 51163e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 51173e9753d6SMatthew G. Knepley /* 3: Handle boundary values */ 51183e9753d6SMatthew G. Knepley /* 4: Loop over domain */ 51193e9753d6SMatthew G. Knepley /* Extract coefficients */ 51203e9753d6SMatthew G. Knepley /* Loop over fields */ 51213e9753d6SMatthew G. Knepley /* Set tiling for FE*/ 51223e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec */ 51233e9753d6SMatthew G. Knepley /* Loop over subdomain */ 51243e9753d6SMatthew G. Knepley /* Loop over quad points */ 51253e9753d6SMatthew G. Knepley /* Transform coords to real space */ 51263e9753d6SMatthew G. Knepley /* Evaluate field and aux fields at point */ 51273e9753d6SMatthew G. Knepley /* Evaluate residual at point */ 51283e9753d6SMatthew G. Knepley /* Transform residual to real space */ 51293e9753d6SMatthew G. Knepley /* Add residual to elemVec */ 51303e9753d6SMatthew G. Knepley /* Loop over domain */ 51313e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 51323e9753d6SMatthew G. Knepley 51333e9753d6SMatthew G. Knepley /* FVM */ 51343e9753d6SMatthew G. Knepley /* Get geometric data */ 51353e9753d6SMatthew G. Knepley /* If using gradients */ 51363e9753d6SMatthew G. Knepley /* Compute gradient data */ 51373e9753d6SMatthew G. Knepley /* Loop over domain faces */ 51383e9753d6SMatthew G. Knepley /* Count computational faces */ 51393e9753d6SMatthew G. Knepley /* Reconstruct cell gradient */ 51403e9753d6SMatthew G. Knepley /* Loop over domain cells */ 51413e9753d6SMatthew G. Knepley /* Limit cell gradients */ 51423e9753d6SMatthew G. Knepley /* Handle boundary values */ 51433e9753d6SMatthew G. Knepley /* Loop over domain faces */ 51443e9753d6SMatthew G. Knepley /* Read out field, centroid, normal, volume for each side of face */ 51453e9753d6SMatthew G. Knepley /* Riemann solve over faces */ 51463e9753d6SMatthew G. Knepley /* Loop over domain faces */ 51473e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 51483e9753d6SMatthew G. Knepley /* TODO Change printFEM to printDisc here */ 51493e9753d6SMatthew G. Knepley if (mesh->printFEM) { 51503e9753d6SMatthew G. Knepley Vec locFbc; 51513e9753d6SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 51523e9753d6SMatthew G. Knepley PetscScalar *zeroes; 51533e9753d6SMatthew G. Knepley 51549566063dSJacob Faibussowitsch PetscCall(VecDuplicate(locF, &locFbc)); 51559566063dSJacob Faibussowitsch PetscCall(VecCopy(locF, locFbc)); 51569566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 51579566063dSJacob Faibussowitsch PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 51589566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(maxDof, &zeroes)); 515948a46eb9SPierre Jolivet for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 51609566063dSJacob Faibussowitsch PetscCall(PetscFree(zeroes)); 51619566063dSJacob Faibussowitsch PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 51629566063dSJacob Faibussowitsch PetscCall(VecDestroy(&locFbc)); 51633e9753d6SMatthew G. Knepley } 51649566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 51653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 51663e9753d6SMatthew G. Knepley } 51673e9753d6SMatthew G. Knepley 51686528b96dSMatthew G. Knepley /* 51696528b96dSMatthew G. Knepley 1) Allow multiple kernels for BdResidual for hybrid DS 51706528b96dSMatthew G. Knepley 51716528b96dSMatthew G. Knepley DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux 51726528b96dSMatthew G. Knepley 51736528b96dSMatthew G. Knepley DONE 3) Change DMGetCellFields() to get different aux data a[] for each side 51746528b96dSMatthew G. Knepley - I think I just need to replace a[] with the closure from each face 51756528b96dSMatthew G. Knepley 51766528b96dSMatthew G. Knepley 4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before 51776528b96dSMatthew G. Knepley */ 5178d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 5179d71ae5a4SJacob Faibussowitsch { 51803e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 51813e9753d6SMatthew G. Knepley const char *name = "Hybrid Residual"; 518204c51a94SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 51833e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 51846528b96dSMatthew G. Knepley PetscDS ds = NULL; 518507218a29SMatthew G. Knepley PetscDS dsIn = NULL; 51866528b96dSMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 518704c51a94SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 518807218a29SMatthew G. Knepley DM dmScale[3] = {NULL, NULL, NULL}; 518907218a29SMatthew G. Knepley PetscDS dsScale[3] = {NULL, NULL, NULL}; 519007218a29SMatthew G. Knepley Vec locS[3] = {NULL, NULL, NULL}; 51913e9753d6SMatthew G. Knepley PetscSection section = NULL; 51923e9753d6SMatthew G. Knepley DMField coordField = NULL; 519307218a29SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 519407218a29SMatthew G. Knepley PetscScalar *s[3] = {NULL, NULL, NULL}; 5195b2ab40e6SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 519607218a29SMatthew G. Knepley PetscScalar *elemVecNeg, *elemVecPos, *elemVecCoh; 51973e9753d6SMatthew G. Knepley IS chunkIS; 51983e9753d6SMatthew G. Knepley const PetscInt *cells; 51993e9753d6SMatthew G. Knepley PetscInt *faces; 52003e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 52013e2b0218SMatthew G. Knepley PetscInt Nf, f, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk; 52023e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 52033e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 52043e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 52053e9753d6SMatthew G. Knepley 52063e9753d6SMatthew G. Knepley PetscFunctionBegin; 52073ba16761SJacob Faibussowitsch if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 5208437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5209437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 52103ba16761SJacob Faibussowitsch if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 52115fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 52125fedec97SMatthew G. Knepley const char *name; 52139566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 521463a3b9bcSJacob 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); 52155fedec97SMatthew G. Knepley } 52169566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 52173e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 52183e9753d6SMatthew G. Knepley /* FEM */ 52193e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 52209566063dSJacob Faibussowitsch PetscCall(DMGetSection(dm, §ion)); 52219566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 522207218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 52239566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 52249566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 522507218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn)); 52269566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 522704c51a94SMatthew G. Knepley if (locA[2]) { 52281059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 52291059d808SMatthew G. Knepley 52309566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 523107218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL)); 52329566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 52336528b96dSMatthew G. Knepley { 52346528b96dSMatthew G. Knepley const PetscInt *cone; 52356528b96dSMatthew G. Knepley PetscInt c; 52366528b96dSMatthew G. Knepley 52371059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 52386528b96dSMatthew G. Knepley for (c = 0; c < 2; ++c) { 52396528b96dSMatthew G. Knepley const PetscInt *support; 52406528b96dSMatthew G. Knepley PetscInt ssize, s; 52416528b96dSMatthew G. Knepley 52429566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 52439566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 52441059d808SMatthew 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); 52451059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 52461059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 52471059d808SMatthew 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); 52489566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 5249c75bfeddSPierre 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); 52509566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5251ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 525207218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL)); 52539566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 52546528b96dSMatthew G. Knepley } 52556528b96dSMatthew G. Knepley } 52563e9753d6SMatthew G. Knepley } 525707218a29SMatthew G. Knepley /* Handle mass matrix scaling 525807218a29SMatthew G. Knepley The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */ 525907218a29SMatthew G. Knepley PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2])); 526007218a29SMatthew G. Knepley if (locS[2]) { 52613e2b0218SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 526207218a29SMatthew G. Knepley PetscInt Nb, Nbs; 526307218a29SMatthew G. Knepley 526407218a29SMatthew G. Knepley PetscCall(VecGetDM(locS[2], &dmScale[2])); 52653e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[2], cellStart, &dsScale[2], NULL)); 52663e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2])); 526707218a29SMatthew G. Knepley // BRAD: This is not set correctly 526807218a29SMatthew G. Knepley key[2].field = 2; 526907218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb)); 527007218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs)); 527107218a29SMatthew G. Knepley PetscCheck(Nb == Nbs, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Field %" PetscInt_FMT " of size %" PetscInt_FMT " cannot be scaled by field of size %" PetscInt_FMT, key[2].field, Nb, Nbs); 52723e2b0218SMatthew G. Knepley { 52733e2b0218SMatthew G. Knepley const PetscInt *cone; 52743e2b0218SMatthew G. Knepley PetscInt c; 52753e2b0218SMatthew G. Knepley 52763e2b0218SMatthew G. Knepley locS[1] = locS[0] = locS[2]; 52773e2b0218SMatthew G. Knepley dmScale[1] = dmScale[0] = dmScale[2]; 52783e2b0218SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 52793e2b0218SMatthew G. Knepley for (c = 0; c < 2; ++c) { 52803e2b0218SMatthew G. Knepley const PetscInt *support; 52813e2b0218SMatthew G. Knepley PetscInt ssize, s; 52823e2b0218SMatthew G. Knepley 52833e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 52843e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 52853e2b0218SMatthew 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); 52863e2b0218SMatthew G. Knepley if (support[0] == cellStart) s = 1; 52873e2b0218SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 52883e2b0218SMatthew 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); 52893e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL)); 52903e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c])); 52913e2b0218SMatthew G. Knepley } 52923e2b0218SMatthew G. Knepley } 529307218a29SMatthew G. Knepley } 52943e9753d6SMatthew G. Knepley /* 2: Setup geometric data */ 52959566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 52969566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 52973e9753d6SMatthew G. Knepley if (maxDegree > 1) { 52989566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 52993e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 53003e9753d6SMatthew G. Knepley PetscFE fe; 53013e9753d6SMatthew G. Knepley 53029566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 53033e9753d6SMatthew G. Knepley if (fe) { 53049566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 53059566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 53063e9753d6SMatthew G. Knepley } 53073e9753d6SMatthew G. Knepley } 53083e9753d6SMatthew G. Knepley } 53093e9753d6SMatthew G. Knepley /* Loop over chunks */ 53103e9753d6SMatthew G. Knepley cellChunkSize = numCells; 53113e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 531207218a29SMatthew G. Knepley PetscCall(PetscCalloc1(2 * cellChunkSize, &faces)); 531307218a29SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 53143e9753d6SMatthew G. Knepley /* Extract field coefficients */ 53153e9753d6SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 531607218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 531707218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 53183e2b0218SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 531907218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecNeg)); 532007218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecPos)); 532107218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecCoh)); 53223e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 53233e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 53243e9753d6SMatthew G. Knepley 532507218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecNeg, cellChunkSize * totDim)); 532607218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecPos, cellChunkSize * totDim)); 532707218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecCoh, cellChunkSize * totDim)); 53283e9753d6SMatthew G. Knepley /* Get faces */ 53293e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 53303e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 53313e9753d6SMatthew G. Knepley const PetscInt *cone; 53329566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 533307218a29SMatthew G. Knepley faces[(c - cS) * 2 + 0] = cone[0]; 533407218a29SMatthew G. Knepley faces[(c - cS) * 2 + 1] = cone[1]; 53353e9753d6SMatthew G. Knepley } 533607218a29SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER)); 53373e9753d6SMatthew G. Knepley /* Get geometric data */ 53383e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 53399566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 53409566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 53413e9753d6SMatthew G. Knepley } else { 53423e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 53439566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 53443e9753d6SMatthew G. Knepley } 53453e9753d6SMatthew G. Knepley } 53463e9753d6SMatthew G. Knepley /* Loop over fields */ 53473e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 53483e9753d6SMatthew G. Knepley PetscFE fe; 53493e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 5350148442b3SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 53513e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 53523e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 53535fedec97SMatthew G. Knepley PetscBool isCohesiveField; 53543e9753d6SMatthew G. Knepley 53559566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 53563e9753d6SMatthew G. Knepley if (!fe) continue; 53579566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 53589566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 53599566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 53603e9753d6SMatthew G. Knepley blockSize = Nb; 53613e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 53629566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 53633e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 53643e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 53653e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 53663e9753d6SMatthew G. Knepley offset = numCells - Nr; 536707218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom)); 536807218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom)); 53699566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 53705fedec97SMatthew G. Knepley chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE; 53716528b96dSMatthew G. Knepley key[0].field = f; 53726528b96dSMatthew G. Knepley key[1].field = f; 53735fedec97SMatthew G. Knepley key[2].field = f; 537407218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVecNeg)); 537507218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, &elemVecNeg[offset * totDim])); 537607218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVecPos)); 537707218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, &elemVecPos[offset * totDim])); 537807218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVecCoh)); 537907218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, &elemVecCoh[offset * totDim])); 53809566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 53819566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 53823e9753d6SMatthew G. Knepley } 53833e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 53843e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 53853e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 53863e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 538707218a29SMatthew G. Knepley PetscInt i; 53883e9753d6SMatthew G. Knepley 538907218a29SMatthew G. Knepley /* Scale element values */ 539007218a29SMatthew G. Knepley if (locS[0]) { 53913e2b0218SMatthew G. Knepley PetscInt Nb, off = cind * totDim, soff = cind * totDimScale[0]; 539207218a29SMatthew G. Knepley PetscBool cohesive; 539307218a29SMatthew G. Knepley 539407218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 539507218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, f, &Nb)); 539607218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 539707218a29SMatthew G. Knepley if (f == key[2].field) { 539807218a29SMatthew G. Knepley PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields"); 539907218a29SMatthew G. Knepley // No cohesive scaling field is currently input 540007218a29SMatthew G. Knepley for (i = 0; i < Nb; ++i) elemVecCoh[off + i] += s[0][soff + i] * elemVecNeg[off + i] + s[1][soff + i] * elemVecPos[off + i]; 540107218a29SMatthew G. Knepley off += Nb; 540207218a29SMatthew G. Knepley } else { 540307218a29SMatthew G. Knepley const PetscInt N = cohesive ? Nb : Nb * 2; 540407218a29SMatthew G. Knepley 540507218a29SMatthew G. Knepley for (i = 0; i < N; ++i) elemVecCoh[off + i] += elemVecNeg[off + i] + elemVecPos[off + i]; 540607218a29SMatthew G. Knepley off += N; 540707218a29SMatthew G. Knepley } 540807218a29SMatthew G. Knepley } 540907218a29SMatthew G. Knepley } else { 541007218a29SMatthew G. Knepley for (i = cind * totDim; i < (cind + 1) * totDim; ++i) elemVecCoh[i] += elemVecNeg[i] + elemVecPos[i]; 541107218a29SMatthew G. Knepley } 541207218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVecCoh[cind * totDim])); 54133e9753d6SMatthew G. Knepley if (ghostLabel) { 54143e9753d6SMatthew G. Knepley PetscInt ghostVal; 54153e9753d6SMatthew G. Knepley 54169566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 54173e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 54183e9753d6SMatthew G. Knepley } 541907218a29SMatthew G. Knepley PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVecCoh[cind * totDim], ADD_ALL_VALUES)); 54203e9753d6SMatthew G. Knepley } 54213e9753d6SMatthew G. Knepley } 54229566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 542307218a29SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 54243e2b0218SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 542507218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecNeg)); 542607218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecPos)); 542707218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecCoh)); 54289566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 54299566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 54309566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 54313e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 54329566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 54339566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 54343e9753d6SMatthew G. Knepley } else { 54353e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 54369566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 54379566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 54383e9753d6SMatthew G. Knepley } 54399566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 54403e9753d6SMatthew G. Knepley } 544185cc2951SMatthew G. Knepley if (mesh->printFEM) { 544285cc2951SMatthew G. Knepley Vec locFbc; 544385cc2951SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 544485cc2951SMatthew G. Knepley PetscScalar *zeroes; 544585cc2951SMatthew G. Knepley 544685cc2951SMatthew G. Knepley PetscCall(VecDuplicate(locF, &locFbc)); 544785cc2951SMatthew G. Knepley PetscCall(VecCopy(locF, locFbc)); 544885cc2951SMatthew G. Knepley PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 544985cc2951SMatthew G. Knepley PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 545085cc2951SMatthew G. Knepley PetscCall(PetscCalloc1(maxDof, &zeroes)); 545185cc2951SMatthew G. Knepley for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 545285cc2951SMatthew G. Knepley PetscCall(PetscFree(zeroes)); 545385cc2951SMatthew G. Knepley PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 545485cc2951SMatthew G. Knepley PetscCall(VecDestroy(&locFbc)); 545585cc2951SMatthew G. Knepley } 54569566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 54573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 54583e9753d6SMatthew G. Knepley } 54593e9753d6SMatthew G. Knepley 5460a4e35b19SJacob Faibussowitsch static 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) 5461d71ae5a4SJacob Faibussowitsch { 54623e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 54633e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL, tdm; 54643e9753d6SMatthew G. Knepley DMEnclosureType encAux; 54653e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 54663e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 5467e432b41dSStefano Zampini PetscSection globalSection; 54683e9753d6SMatthew G. Knepley Vec locA = NULL, tv; 54693e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL; 54703e9753d6SMatthew G. Knepley PetscInt v; 54713e9753d6SMatthew G. Knepley PetscInt Nf, totDim, totDimAux = 0; 5472e432b41dSStefano Zampini PetscBool transform; 54733e9753d6SMatthew G. Knepley 54743e9753d6SMatthew G. Knepley PetscFunctionBegin; 54759566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 54769566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 54779566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 54789566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 54799566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 54809566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 54819566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 54829566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 54839566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA)); 54843e9753d6SMatthew G. Knepley if (locA) { 54853e9753d6SMatthew G. Knepley DM dmAux; 54863e9753d6SMatthew G. Knepley 54879566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 54889566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 54899566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 54909566063dSJacob Faibussowitsch PetscCall(DMGetDS(plexA, &probAux)); 54919566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 54929566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 54933e9753d6SMatthew G. Knepley } 54943e9753d6SMatthew G. Knepley 54959566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 54963e9753d6SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 54973e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 54983e9753d6SMatthew G. Knepley PetscInt maxDegree; 54993e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 55003e9753d6SMatthew G. Knepley IS pointIS; 55013e9753d6SMatthew G. Knepley const PetscInt *points; 550206ad1575SMatthew G. Knepley PetscFormKey key; 55033e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 55043e9753d6SMatthew G. Knepley 550545480ffeSMatthew G. Knepley key.label = label; 550645480ffeSMatthew G. Knepley key.value = values[v]; 550706ad1575SMatthew G. Knepley key.part = 0; 55089566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 55093e9753d6SMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 55103e9753d6SMatthew G. Knepley { 55113e9753d6SMatthew G. Knepley IS isectIS; 55123e9753d6SMatthew G. Knepley 55133e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */ 55149566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 55159566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 55163e9753d6SMatthew G. Knepley pointIS = isectIS; 55173e9753d6SMatthew G. Knepley } 55189566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 55199566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 55209566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim * totDim, &elemMat, locA ? numFaces * totDimAux : 0, &a)); 55219566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 552248a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 55233e9753d6SMatthew G. Knepley if (!qGeom) { 55243e9753d6SMatthew G. Knepley PetscFE fe; 55253e9753d6SMatthew G. Knepley 55269566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 55279566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 55289566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 55293e9753d6SMatthew G. Knepley } 55309566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 55319566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 55323e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 5533f15274beSMatthew Knepley const PetscInt point = points[face], *support; 55343e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 5535f15274beSMatthew Knepley PetscInt i; 55363e9753d6SMatthew G. Knepley 55379566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 55389566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 55393e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 55409566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 55413e9753d6SMatthew G. Knepley if (locX_t) { 55429566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 55433e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 55449566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 55453e9753d6SMatthew G. Knepley } 55463e9753d6SMatthew G. Knepley if (locA) { 55473e9753d6SMatthew G. Knepley PetscInt subp; 55489566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 55499566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 55503e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 55519566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 55523e9753d6SMatthew G. Knepley } 55533e9753d6SMatthew G. Knepley } 55549566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, numFaces * totDim * totDim)); 55553e9753d6SMatthew G. Knepley { 55563e9753d6SMatthew G. Knepley PetscFE fe; 55573e9753d6SMatthew G. Knepley PetscInt Nb; 55583e9753d6SMatthew G. Knepley /* Conforming batches */ 55593e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 55603e9753d6SMatthew G. Knepley /* Remainder */ 55613e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 55623e9753d6SMatthew G. Knepley PetscInt fieldJ, Nr, offset; 55633e9753d6SMatthew G. Knepley 55649566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 55659566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 55669566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 55673e9753d6SMatthew G. Knepley blockSize = Nb; 55683e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 55699566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 55703e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 55713e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 55723e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 55733e9753d6SMatthew G. Knepley offset = numFaces - Nr; 55749566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 55753e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 557645480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 55779566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 55783e9753d6SMatthew G. Knepley } 55799566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 55803e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 558145480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 55829566063dSJacob 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])); 55833e9753d6SMatthew G. Knepley } 55849566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 55853e9753d6SMatthew G. Knepley } 55863e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 55873e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 55883e9753d6SMatthew G. Knepley 55893e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 55909566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 55919566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face * totDim * totDim])); 55929566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim])); 5593e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, support[0], &elemMat[face * totDim * totDim], ADD_VALUES)); 55943e9753d6SMatthew G. Knepley } 55959566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 55969566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 55979566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 55989566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 55999566063dSJacob Faibussowitsch PetscCall(PetscFree4(u, u_t, elemMat, a)); 56003e9753d6SMatthew G. Knepley } 56019566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 56029566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 56033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 56043e9753d6SMatthew G. Knepley } 56053e9753d6SMatthew G. Knepley 5606d71ae5a4SJacob 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) 5607d71ae5a4SJacob Faibussowitsch { 56083e9753d6SMatthew G. Knepley DMField coordField; 56093e9753d6SMatthew G. Knepley DMLabel depthLabel; 56103e9753d6SMatthew G. Knepley IS facetIS; 56113e9753d6SMatthew G. Knepley PetscInt dim; 56123e9753d6SMatthew G. Knepley 56133e9753d6SMatthew G. Knepley PetscFunctionBegin; 56149566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 56159566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 56169566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 56179566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 56189566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 56199566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 56203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 56213e9753d6SMatthew G. Knepley } 56223e9753d6SMatthew G. Knepley 5623a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user) 5624d71ae5a4SJacob Faibussowitsch { 56253e9753d6SMatthew G. Knepley PetscDS prob; 56263e9753d6SMatthew G. Knepley PetscInt dim, numBd, bd; 56273e9753d6SMatthew G. Knepley DMLabel depthLabel; 56283e9753d6SMatthew G. Knepley DMField coordField = NULL; 56293e9753d6SMatthew G. Knepley IS facetIS; 56303e9753d6SMatthew G. Knepley 56313e9753d6SMatthew G. Knepley PetscFunctionBegin; 56329566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 56339566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 56349566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 56359566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 56369566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 56379566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 56383e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 563945480ffeSMatthew G. Knepley PetscWeakForm wf; 56403e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 56413e9753d6SMatthew G. Knepley DMLabel label; 56423e9753d6SMatthew G. Knepley const PetscInt *values; 56433e9753d6SMatthew G. Knepley PetscInt fieldI, numValues; 56443e9753d6SMatthew G. Knepley PetscObject obj; 56453e9753d6SMatthew G. Knepley PetscClassId id; 56463e9753d6SMatthew G. Knepley 56479566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL)); 56483d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 56499566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj)); 56509566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 56513d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 56529566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 56533e9753d6SMatthew G. Knepley } 56549566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 56553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 56563e9753d6SMatthew G. Knepley } 56573e9753d6SMatthew G. Knepley 5658d71ae5a4SJacob 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) 5659d71ae5a4SJacob Faibussowitsch { 56603e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 56613e9753d6SMatthew G. Knepley const char *name = "Jacobian"; 56629a2a23afSMatthew G. Knepley DM dmAux = NULL, plex, tdm; 56633e9753d6SMatthew G. Knepley DMEnclosureType encAux; 56643e9753d6SMatthew G. Knepley Vec A, tv; 56653e9753d6SMatthew G. Knepley DMField coordField; 56663e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 5667e432b41dSStefano Zampini PetscSection section, globalSection, sectionAux; 56683e9753d6SMatthew G. Knepley PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL; 56693e9753d6SMatthew G. Knepley const PetscInt *cells; 56703e9753d6SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 567128351e22SJed Brown PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 5672e04ae0b4SMatthew G. Knepley PetscBool hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform; 56733e9753d6SMatthew G. Knepley 56743e9753d6SMatthew G. Knepley PetscFunctionBegin; 5675af18b51aSmarkadams4 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 5676e04ae0b4SMatthew G. Knepley if (!cellIS) goto end; 56779566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5678437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 5679437e83fbSMatthew G. Knepley if (cStart >= cEnd) goto end; 56809566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 56819566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 56829566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 56839566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 56849566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 568507218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 56869566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 56879566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 56889566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 56899566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 56903e9753d6SMatthew G. Knepley /* user passed in the same matrix, avoid double contributions and 56913e9753d6SMatthew G. Knepley only assemble the Jacobian */ 56923e9753d6SMatthew G. Knepley if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE; 56939566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 56943e9753d6SMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 56959566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 56969a2a23afSMatthew G. Knepley if (A) { 56979566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 56989566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 56999566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plex)); 57009566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plex, §ionAux)); 57019566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 57029566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 57033e9753d6SMatthew G. Knepley } 57049566063dSJacob 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)); 57059566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 57069566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 57073e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 57083e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 57093e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 57103e9753d6SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 57113e9753d6SMatthew G. Knepley PetscInt i; 57123e9753d6SMatthew G. Knepley 57139566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 57143e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 57159566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 57163e9753d6SMatthew G. Knepley if (X_t) { 57179566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 57183e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 57199566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 57203e9753d6SMatthew G. Knepley } 57213e9753d6SMatthew G. Knepley if (dmAux) { 57223e9753d6SMatthew G. Knepley PetscInt subcell; 57239566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 57249566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x)); 57253e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 57269566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x)); 57273e9753d6SMatthew G. Knepley } 57283e9753d6SMatthew G. Knepley } 57299566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 57309566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells * totDim * totDim)); 57319566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 57323e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 57333e9753d6SMatthew G. Knepley PetscClassId id; 57343e9753d6SMatthew G. Knepley PetscFE fe; 57353e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 57363e9753d6SMatthew G. Knepley PetscInt Nb; 57373e9753d6SMatthew G. Knepley /* Conforming batches */ 57383e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 57393e9753d6SMatthew G. Knepley /* Remainder */ 57403e9753d6SMatthew G. Knepley PetscInt Nr, offset, Nq; 57413e9753d6SMatthew G. Knepley PetscInt maxDegree; 57423e9753d6SMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 57433e9753d6SMatthew G. Knepley 57449566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 57459566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 57469371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 57479371c9d4SSatish Balay hasFV = PETSC_TRUE; 57489371c9d4SSatish Balay continue; 57499371c9d4SSatish Balay } 57509566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 57519566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 57529566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 575348a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 57543e9753d6SMatthew G. Knepley if (!qGeom) { 57559566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 57569566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 57573e9753d6SMatthew G. Knepley } 57589566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 57599566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 57603e9753d6SMatthew G. Knepley blockSize = Nb; 57613e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 57629566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 57633e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 57643e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 57653e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 57663e9753d6SMatthew G. Knepley offset = numCells - Nr; 57679566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 57689566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 57693e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 57706528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 57713e9753d6SMatthew G. Knepley if (hasJac) { 57729566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5773072f5ffdSStefano Zampini PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMat[offset * totDim * totDim])); 57743e9753d6SMatthew G. Knepley } 57753e9753d6SMatthew G. Knepley if (hasPrec) { 57769566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP)); 5777072f5ffdSStefano Zampini PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMatP[offset * totDim * totDim])); 57783e9753d6SMatthew G. Knepley } 57793e9753d6SMatthew G. Knepley if (hasDyn) { 57809566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 5781072f5ffdSStefano Zampini PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMatD[offset * totDim * totDim])); 57823e9753d6SMatthew G. Knepley } 57833e9753d6SMatthew G. Knepley } 57849566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 57859566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 57869566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 57879566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 57883e9753d6SMatthew G. Knepley } 57893e9753d6SMatthew G. Knepley /* Add contribution from X_t */ 57909371c9d4SSatish Balay if (hasDyn) { 57919371c9d4SSatish Balay for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 57929371c9d4SSatish Balay } 57933e9753d6SMatthew G. Knepley if (hasFV) { 57943e9753d6SMatthew G. Knepley PetscClassId id; 57953e9753d6SMatthew G. Knepley PetscFV fv; 57963e9753d6SMatthew G. Knepley PetscInt offsetI, NcI, NbI = 1, fc, f; 57973e9753d6SMatthew G. Knepley 57983e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 57999566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 58009566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI)); 58019566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fv, &id)); 58023e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 58033e9753d6SMatthew G. Knepley /* Put in the identity */ 58049566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcI)); 58053e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 58063e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 58073e9753d6SMatthew G. Knepley const PetscInt eOffset = cind * totDim * totDim; 58083e9753d6SMatthew G. Knepley for (fc = 0; fc < NcI; ++fc) { 58093e9753d6SMatthew G. Knepley for (f = 0; f < NbI; ++f) { 58103e9753d6SMatthew G. Knepley const PetscInt i = offsetI + f * NcI + fc; 58113e9753d6SMatthew G. Knepley if (hasPrec) { 5812ad540459SPierre Jolivet if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 58133e9753d6SMatthew G. Knepley elemMatP[eOffset + i * totDim + i] = 1.0; 58149371c9d4SSatish Balay } else { 58159371c9d4SSatish Balay elemMat[eOffset + i * totDim + i] = 1.0; 58169371c9d4SSatish Balay } 58173e9753d6SMatthew G. Knepley } 58183e9753d6SMatthew G. Knepley } 58193e9753d6SMatthew G. Knepley } 58203e9753d6SMatthew G. Knepley } 58213e9753d6SMatthew G. Knepley /* No allocated space for FV stuff, so ignore the zero entries */ 58229566063dSJacob Faibussowitsch PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); 58233e9753d6SMatthew G. Knepley } 58243e9753d6SMatthew G. Knepley /* Insert values into matrix */ 58253e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 58263e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 58273e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 58283e9753d6SMatthew G. Knepley 58293e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 58309566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * totDim])); 58313e9753d6SMatthew G. Knepley if (hasPrec) { 58323e9753d6SMatthew G. Knepley if (hasJac) { 58339566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5834e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 58353e9753d6SMatthew G. Knepley } 58369566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim])); 58379566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES)); 58383e9753d6SMatthew G. Knepley } else { 58393e9753d6SMatthew G. Knepley if (hasJac) { 58409566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5841e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 58423e9753d6SMatthew G. Knepley } 58433e9753d6SMatthew G. Knepley } 58443e9753d6SMatthew G. Knepley } 58459566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 58469566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 58479566063dSJacob Faibussowitsch PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, elemMatD)); 58483e9753d6SMatthew G. Knepley if (dmAux) { 58499566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 58509566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 58513e9753d6SMatthew G. Knepley } 58523e9753d6SMatthew G. Knepley /* Compute boundary integrals */ 58539566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user)); 58543e9753d6SMatthew G. Knepley /* Assemble matrix */ 58559371c9d4SSatish Balay end : { 5856e04ae0b4SMatthew G. Knepley PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp; 5857e04ae0b4SMatthew G. Knepley 5858712fec58SPierre Jolivet PetscCall(MPIU_Allreduce(&assOp, &gassOp, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 58593e9753d6SMatthew G. Knepley if (hasJac && hasPrec) { 58609566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 58619566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 58623e9753d6SMatthew G. Knepley } 5863e04ae0b4SMatthew G. Knepley } 58649566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 58659566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 58669566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 58673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 58683e9753d6SMatthew G. Knepley } 58693e9753d6SMatthew G. Knepley 5870d71ae5a4SJacob 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) 5871d71ae5a4SJacob Faibussowitsch { 58723e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 58733e9753d6SMatthew G. Knepley const char *name = "Hybrid Jacobian"; 5874148442b3SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 5875148442b3SMatthew G. Knepley DMLabel ghostLabel = NULL; 58763e9753d6SMatthew G. Knepley DM plex = NULL; 58773e9753d6SMatthew G. Knepley DM plexA = NULL; 5878148442b3SMatthew G. Knepley PetscDS ds = NULL; 587907218a29SMatthew G. Knepley PetscDS dsIn = NULL; 5880148442b3SMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 5881148442b3SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 588207218a29SMatthew G. Knepley DM dmScale[3] = {NULL, NULL, NULL}; 588307218a29SMatthew G. Knepley PetscDS dsScale[3] = {NULL, NULL, NULL}; 588407218a29SMatthew G. Knepley Vec locS[3] = {NULL, NULL, NULL}; 58853e9753d6SMatthew G. Knepley PetscSection section = NULL; 5886148442b3SMatthew G. Knepley PetscSection sectionAux[3] = {NULL, NULL, NULL}; 58873e9753d6SMatthew G. Knepley DMField coordField = NULL; 588807218a29SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 588907218a29SMatthew G. Knepley PetscScalar *s[3] = {NULL, NULL, NULL}; 589007218a29SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 589107218a29SMatthew G. Knepley PetscScalar *elemMatNeg, *elemMatPos, *elemMatCoh; 589207218a29SMatthew G. Knepley PetscScalar *elemMatNegP, *elemMatPosP, *elemMatCohP; 5893e432b41dSStefano Zampini PetscSection globalSection; 58943e9753d6SMatthew G. Knepley IS chunkIS; 58953e9753d6SMatthew G. Knepley const PetscInt *cells; 58963e9753d6SMatthew G. Knepley PetscInt *faces; 58973e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 58983e2b0218SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk; 58993e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 59003e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 59013e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 5902e432b41dSStefano Zampini PetscBool hasBdJac, hasBdPrec; 59033e9753d6SMatthew G. Knepley 59043e9753d6SMatthew G. Knepley PetscFunctionBegin; 59053ba16761SJacob Faibussowitsch if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 5906437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5907437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 59083ba16761SJacob Faibussowitsch if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 59095fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 59105fedec97SMatthew G. Knepley const char *name; 59119566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 591263a3b9bcSJacob 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); 59135fedec97SMatthew G. Knepley } 59149566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 59159566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 59169566063dSJacob Faibussowitsch PetscCall(DMGetSection(dm, §ion)); 59179566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 59189566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 591907218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 59209566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 59219566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 592207218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn)); 59239566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac)); 59249566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec)); 59259566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 5926148442b3SMatthew G. Knepley if (locA[2]) { 59271059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 59281059d808SMatthew G. Knepley 59299566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 59309566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA)); 59319566063dSJacob Faibussowitsch PetscCall(DMGetSection(dmAux[2], §ionAux[2])); 593207218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL)); 59339566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 5934148442b3SMatthew G. Knepley { 5935148442b3SMatthew G. Knepley const PetscInt *cone; 5936148442b3SMatthew G. Knepley PetscInt c; 5937148442b3SMatthew G. Knepley 59381059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 5939148442b3SMatthew G. Knepley for (c = 0; c < 2; ++c) { 5940148442b3SMatthew G. Knepley const PetscInt *support; 5941148442b3SMatthew G. Knepley PetscInt ssize, s; 5942148442b3SMatthew G. Knepley 59439566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 59449566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 59451059d808SMatthew 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); 59461059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 59471059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 59481059d808SMatthew 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); 59499566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 59509566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5951ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 595207218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL)); 59539566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 5954148442b3SMatthew G. Knepley } 5955148442b3SMatthew G. Knepley } 59563e9753d6SMatthew G. Knepley } 595707218a29SMatthew G. Knepley /* Handle mass matrix scaling 595807218a29SMatthew G. Knepley The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */ 595907218a29SMatthew G. Knepley PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2])); 596007218a29SMatthew G. Knepley if (locS[2]) { 59613e2b0218SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 596207218a29SMatthew G. Knepley PetscInt Nb, Nbs; 596307218a29SMatthew G. Knepley 596407218a29SMatthew G. Knepley PetscCall(VecGetDM(locS[2], &dmScale[2])); 596507218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[2], cells ? cells[cStart] : cStart, &dsScale[2], NULL)); 59663e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2])); 596707218a29SMatthew G. Knepley // BRAD: This is not set correctly 596807218a29SMatthew G. Knepley key[2].field = 2; 596907218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb)); 597007218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs)); 597107218a29SMatthew G. Knepley PetscCheck(Nb == Nbs, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Field %" PetscInt_FMT " of size %" PetscInt_FMT " cannot be scaled by field of size %" PetscInt_FMT, key[2].field, Nb, Nbs); 59723e2b0218SMatthew G. Knepley { 59733e2b0218SMatthew G. Knepley const PetscInt *cone; 59743e2b0218SMatthew G. Knepley PetscInt c; 59753e2b0218SMatthew G. Knepley 59763e2b0218SMatthew G. Knepley locS[1] = locS[0] = locS[2]; 59773e2b0218SMatthew G. Knepley dmScale[1] = dmScale[0] = dmScale[2]; 59783e2b0218SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 59793e2b0218SMatthew G. Knepley for (c = 0; c < 2; ++c) { 59803e2b0218SMatthew G. Knepley const PetscInt *support; 59813e2b0218SMatthew G. Knepley PetscInt ssize, s; 59823e2b0218SMatthew G. Knepley 59833e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 59843e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 59853e2b0218SMatthew 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); 59863e2b0218SMatthew G. Knepley if (support[0] == cellStart) s = 1; 59873e2b0218SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 59883e2b0218SMatthew 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); 59893e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL)); 59903e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c])); 59913e2b0218SMatthew G. Knepley } 59923e2b0218SMatthew G. Knepley } 599307218a29SMatthew G. Knepley } 599407218a29SMatthew G. Knepley /* 2: Setup geometric data */ 59959566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 59969566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 59973e9753d6SMatthew G. Knepley if (maxDegree > 1) { 59983e9753d6SMatthew G. Knepley PetscInt f; 59999566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 60003e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 60013e9753d6SMatthew G. Knepley PetscFE fe; 60023e9753d6SMatthew G. Knepley 60039566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 60043e9753d6SMatthew G. Knepley if (fe) { 60059566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 60069566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 60073e9753d6SMatthew G. Knepley } 60083e9753d6SMatthew G. Knepley } 60093e9753d6SMatthew G. Knepley } 601007218a29SMatthew G. Knepley /* Loop over chunks */ 60113e9753d6SMatthew G. Knepley cellChunkSize = numCells; 60123e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 601307218a29SMatthew G. Knepley PetscCall(PetscCalloc1(2 * cellChunkSize, &faces)); 6014a4158a15SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 601507218a29SMatthew G. Knepley /* Extract field coefficients */ 601607218a29SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 601707218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 601807218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 60198bf0a22dSMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 602007218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg)); 602107218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos)); 602207218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh)); 602307218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP)); 602407218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP)); 602507218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP)); 60263e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 60273e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 60283e9753d6SMatthew G. Knepley 602907218a29SMatthew G. Knepley if (hasBdJac) { 603007218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatNeg, cellChunkSize * totDim * totDim)); 603107218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatPos, cellChunkSize * totDim * totDim)); 603207218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatCoh, cellChunkSize * totDim * totDim)); 603307218a29SMatthew G. Knepley } 603407218a29SMatthew G. Knepley if (hasBdPrec) { 603507218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatNegP, cellChunkSize * totDim * totDim)); 603607218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatPosP, cellChunkSize * totDim * totDim)); 603707218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatCohP, cellChunkSize * totDim * totDim)); 603807218a29SMatthew G. Knepley } 60393e9753d6SMatthew G. Knepley /* Get faces */ 60403e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 60413e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 60423e9753d6SMatthew G. Knepley const PetscInt *cone; 60439566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(plex, cell, &cone)); 604407218a29SMatthew G. Knepley faces[(c - cS) * 2 + 0] = cone[0]; 604507218a29SMatthew G. Knepley faces[(c - cS) * 2 + 1] = cone[1]; 60463e9753d6SMatthew G. Knepley } 604707218a29SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER)); 60483e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 60499566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 60509566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 60513e9753d6SMatthew G. Knepley } else { 60523e9753d6SMatthew G. Knepley PetscInt f; 60533e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 60549566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 60553e9753d6SMatthew G. Knepley } 60563e9753d6SMatthew G. Knepley } 60573e9753d6SMatthew G. Knepley 60583e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 60593e9753d6SMatthew G. Knepley PetscFE feI; 60603e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI]; 60613e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 60623e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI]; 60633e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 60645fedec97SMatthew G. Knepley PetscBool isCohesiveField; 60653e9753d6SMatthew G. Knepley 60669566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI)); 60673e9753d6SMatthew G. Knepley if (!feI) continue; 60689566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches)); 60699566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 60709566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feI, &Nb)); 60713e9753d6SMatthew G. Knepley blockSize = Nb; 60723e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 60739566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches)); 60743e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 60753e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 60763e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 60773e9753d6SMatthew G. Knepley offset = numCells - Nr; 607807218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom)); 607907218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom)); 60809566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField)); 60813e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 60823e9753d6SMatthew G. Knepley PetscFE feJ; 60833e9753d6SMatthew G. Knepley 60849566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ)); 60853e9753d6SMatthew G. Knepley if (!feJ) continue; 6086148442b3SMatthew G. Knepley key[0].field = fieldI * Nf + fieldJ; 6087148442b3SMatthew G. Knepley key[1].field = fieldI * Nf + fieldJ; 60885fedec97SMatthew G. Knepley key[2].field = fieldI * Nf + fieldJ; 6089148442b3SMatthew G. Knepley if (hasBdJac) { 609007218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatNeg)); 609107218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatNeg[offset * totDim * totDim])); 609207218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatPos)); 609307218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatPos[offset * totDim * totDim])); 6094148442b3SMatthew G. Knepley } 6095148442b3SMatthew G. Knepley if (hasBdPrec) { 609607218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatNegP)); 609707218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[0], 0, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatNegP[offset * totDim * totDim])); 609807218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatPosP)); 609907218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[1], 1, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatPosP[offset * totDim * totDim])); 6100148442b3SMatthew G. Knepley } 61015fedec97SMatthew G. Knepley if (hasBdJac) { 610207218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatCoh)); 610307218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatCoh[offset * totDim * totDim])); 6104148442b3SMatthew G. Knepley } 61055fedec97SMatthew G. Knepley if (hasBdPrec) { 610607218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatCohP)); 610707218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[2], 2, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatCohP[offset * totDim * totDim])); 61083e9753d6SMatthew G. Knepley } 61093e9753d6SMatthew G. Knepley } 61109566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 61119566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 61123e9753d6SMatthew G. Knepley } 61133e9753d6SMatthew G. Knepley /* Insert values into matrix */ 61143e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 61153e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 611607218a29SMatthew G. Knepley const PetscInt cind = c - cS, coff = cind * totDim * totDim; 611707218a29SMatthew G. Knepley PetscInt i, j; 61183e9753d6SMatthew G. Knepley 611907218a29SMatthew G. Knepley /* Scale element values */ 612007218a29SMatthew G. Knepley if (locS[0]) { 61213e2b0218SMatthew G. Knepley PetscInt Nb, soff = cind * totDimScale[0], off = 0; 612207218a29SMatthew G. Knepley PetscBool cohesive; 612307218a29SMatthew G. Knepley 612407218a29SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 612507218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, fieldI, &Nb)); 612607218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(ds, fieldI, &cohesive)); 612707218a29SMatthew G. Knepley 612807218a29SMatthew G. Knepley if (fieldI == key[2].field) { 612907218a29SMatthew G. Knepley PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields"); 61308bf0a22dSMatthew G. Knepley for (i = 0; i < Nb; ++i) { 613107218a29SMatthew G. Knepley for (j = 0; j < totDim; ++j) elemMatCoh[coff + (off + i) * totDim + j] += s[0][soff + i] * elemMatNeg[coff + (off + i) * totDim + j] + s[1][soff + i] * elemMatPos[coff + (off + i) * totDim + j]; 61328bf0a22dSMatthew G. Knepley if (hasBdPrec) 61338bf0a22dSMatthew G. Knepley for (j = 0; j < totDim; ++j) elemMatCohP[coff + (off + i) * totDim + j] += s[0][soff + i] * elemMatNegP[coff + (off + i) * totDim + j] + s[1][soff + i] * elemMatPosP[coff + (off + i) * totDim + j]; 61348bf0a22dSMatthew G. Knepley } 613507218a29SMatthew G. Knepley off += Nb; 613607218a29SMatthew G. Knepley } else { 613707218a29SMatthew G. Knepley const PetscInt N = cohesive ? Nb : Nb * 2; 613807218a29SMatthew G. Knepley 61398bf0a22dSMatthew G. Knepley for (i = 0; i < N; ++i) { 614007218a29SMatthew G. Knepley for (j = 0; j < totDim; ++j) elemMatCoh[coff + (off + i) * totDim + j] += elemMatNeg[coff + (off + i) * totDim + j] + elemMatPos[coff + (off + i) * totDim + j]; 61418bf0a22dSMatthew G. Knepley if (hasBdPrec) 61428bf0a22dSMatthew G. Knepley for (j = 0; j < totDim; ++j) elemMatCohP[coff + (off + i) * totDim + j] += elemMatNegP[coff + (off + i) * totDim + j] + elemMatPosP[coff + (off + i) * totDim + j]; 61438bf0a22dSMatthew G. Knepley } 614407218a29SMatthew G. Knepley off += N; 614507218a29SMatthew G. Knepley } 614607218a29SMatthew G. Knepley } 614707218a29SMatthew G. Knepley } else { 614807218a29SMatthew G. Knepley for (i = 0; i < totDim * totDim; ++i) elemMatCoh[coff + i] += elemMatNeg[coff + i] + elemMatPos[coff + i]; 61498bf0a22dSMatthew G. Knepley if (hasBdPrec) 61508bf0a22dSMatthew G. Knepley for (i = 0; i < totDim * totDim; ++i) elemMatCohP[coff + i] += elemMatNegP[coff + i] + elemMatPosP[coff + i]; 615107218a29SMatthew G. Knepley } 61523e9753d6SMatthew G. Knepley if (hasBdPrec) { 61533e9753d6SMatthew G. Knepley if (hasBdJac) { 615407218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim])); 6155e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES)); 61563e9753d6SMatthew G. Knepley } 615707218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCohP[cind * totDim * totDim])); 615807218a29SMatthew G. Knepley PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatCohP[cind * totDim * totDim], ADD_VALUES)); 61593e9753d6SMatthew G. Knepley } else if (hasBdJac) { 616007218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim])); 6161e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES)); 61623e9753d6SMatthew G. Knepley } 61633e9753d6SMatthew G. Knepley } 61643e9753d6SMatthew G. Knepley } 61659566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 616607218a29SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 616707218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg)); 616807218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos)); 616907218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh)); 617007218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP)); 617107218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP)); 617207218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP)); 61739566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 61749566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 61759566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 61763e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 61779566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 61789566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 61793e9753d6SMatthew G. Knepley } else { 61803e9753d6SMatthew G. Knepley PetscInt f; 61813e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 61829566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 61839566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 61843e9753d6SMatthew G. Knepley } 61859566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 61863e9753d6SMatthew G. Knepley } 61879566063dSJacob Faibussowitsch if (dmAux[2]) PetscCall(DMDestroy(&plexA)); 61889566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 61899566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 61903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 61913e9753d6SMatthew G. Knepley } 61928e3a2eefSMatthew G. Knepley 61938e3a2eefSMatthew G. Knepley /* 61948e3a2eefSMatthew 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. 61958e3a2eefSMatthew G. Knepley 61968e3a2eefSMatthew G. Knepley Input Parameters: 61978e3a2eefSMatthew G. Knepley + dm - The mesh 6198baca6076SPierre Jolivet . key - The PetscWeakFormKey indicating where integration should happen 619906ad1575SMatthew G. Knepley . cellIS - The cells to integrate over 62008e3a2eefSMatthew G. Knepley . t - The time 6201145b44c9SPierre Jolivet . X_tShift - The multiplier for the Jacobian with respect to X_t 62028e3a2eefSMatthew G. Knepley . X - Local solution vector 62038e3a2eefSMatthew G. Knepley . X_t - Time-derivative of the local solution vector 62048e3a2eefSMatthew G. Knepley . Y - Local input vector 620506ad1575SMatthew G. Knepley - user - the user context 62068e3a2eefSMatthew G. Knepley 62078e3a2eefSMatthew G. Knepley Output Parameter: 62088e3a2eefSMatthew G. Knepley . Z - Local output vector 62098e3a2eefSMatthew G. Knepley 62108e3a2eefSMatthew G. Knepley Note: 62118e3a2eefSMatthew G. Knepley We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 62128e3a2eefSMatthew G. Knepley like a GPU, or vectorize on a multicore machine. 62138e3a2eefSMatthew G. Knepley */ 6214d71ae5a4SJacob 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) 6215d71ae5a4SJacob Faibussowitsch { 62168e3a2eefSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 62178e3a2eefSMatthew G. Knepley const char *name = "Jacobian"; 62188e3a2eefSMatthew G. Knepley DM dmAux = NULL, plex, plexAux = NULL; 62198e3a2eefSMatthew G. Knepley DMEnclosureType encAux; 62208e3a2eefSMatthew G. Knepley Vec A; 62218e3a2eefSMatthew G. Knepley DMField coordField; 62228e3a2eefSMatthew G. Knepley PetscDS prob, probAux = NULL; 62238e3a2eefSMatthew G. Knepley PetscQuadrature quad; 62248e3a2eefSMatthew G. Knepley PetscSection section, globalSection, sectionAux; 62258e3a2eefSMatthew G. Knepley PetscScalar *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z; 62268e3a2eefSMatthew G. Knepley const PetscInt *cells; 62278e3a2eefSMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 62288e3a2eefSMatthew G. Knepley PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 62298e3a2eefSMatthew G. Knepley PetscBool hasDyn; 62308e3a2eefSMatthew G. Knepley 62318e3a2eefSMatthew G. Knepley PetscFunctionBegin; 623221d77094SMatthew G. Knepley if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 62339566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 62349566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 62359566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 62369566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 62379566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 62389566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 623907218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 62409566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 62419566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 62429566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 62438e3a2eefSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 62449566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 62458e3a2eefSMatthew G. Knepley if (A) { 62469566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 62479566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 62489566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexAux)); 62499566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexAux, §ionAux)); 62509566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 62519566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 62528e3a2eefSMatthew G. Knepley } 62539566063dSJacob Faibussowitsch PetscCall(VecSet(Z, 0.0)); 62549566063dSJacob 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)); 62559566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 62569566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 62578e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 62588e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 62598e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 62608e3a2eefSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 62618e3a2eefSMatthew G. Knepley PetscInt i; 62628e3a2eefSMatthew G. Knepley 62639566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X, cell, NULL, &x)); 62648e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 62659566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x)); 62668e3a2eefSMatthew G. Knepley if (X_t) { 62679566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t)); 62688e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 62699566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t)); 62708e3a2eefSMatthew G. Knepley } 62718e3a2eefSMatthew G. Knepley if (dmAux) { 62728e3a2eefSMatthew G. Knepley PetscInt subcell; 62739566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 62749566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 62758e3a2eefSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 62769566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 62778e3a2eefSMatthew G. Knepley } 62789566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x)); 62798e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) y[cind * totDim + i] = x[i]; 62809566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x)); 62818e3a2eefSMatthew G. Knepley } 62829566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 62839566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 62848e3a2eefSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 62858e3a2eefSMatthew G. Knepley PetscFE fe; 62868e3a2eefSMatthew G. Knepley PetscInt Nb; 62878e3a2eefSMatthew G. Knepley /* Conforming batches */ 62888e3a2eefSMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 62898e3a2eefSMatthew G. Knepley /* Remainder */ 62908e3a2eefSMatthew G. Knepley PetscInt Nr, offset, Nq; 62918e3a2eefSMatthew G. Knepley PetscQuadrature qGeom = NULL; 62928e3a2eefSMatthew G. Knepley PetscInt maxDegree; 62938e3a2eefSMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 62948e3a2eefSMatthew G. Knepley 62959566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 62969566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 62979566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 62989566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 62999566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 63009566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 63018e3a2eefSMatthew G. Knepley if (!qGeom) { 63029566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 63039566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 63048e3a2eefSMatthew G. Knepley } 63059566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 63069566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 63078e3a2eefSMatthew G. Knepley blockSize = Nb; 63088e3a2eefSMatthew G. Knepley batchSize = numBlocks * blockSize; 63099566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 63108e3a2eefSMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 63118e3a2eefSMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 63128e3a2eefSMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 63138e3a2eefSMatthew G. Knepley offset = numCells - Nr; 63149566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 63159566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 63168e3a2eefSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 63178e3a2eefSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 63189566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 63199566063dSJacob 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])); 63208e3a2eefSMatthew G. Knepley if (hasDyn) { 63219566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 63229566063dSJacob 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])); 63238e3a2eefSMatthew G. Knepley } 63248e3a2eefSMatthew G. Knepley } 63259566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 63269566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 63279566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 63289566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 63298e3a2eefSMatthew G. Knepley } 63308e3a2eefSMatthew G. Knepley if (hasDyn) { 63318e3a2eefSMatthew G. Knepley for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 63328e3a2eefSMatthew G. Knepley } 63338e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 63348e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 63358e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 63368e3a2eefSMatthew G. Knepley const PetscBLASInt M = totDim, one = 1; 63378e3a2eefSMatthew G. Knepley const PetscScalar a = 1.0, b = 0.0; 63388e3a2eefSMatthew G. Knepley 6339792fecdfSBarry Smith PetscCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind * totDim * totDim], &M, &y[cind * totDim], &one, &b, z, &one)); 63408e3a2eefSMatthew G. Knepley if (mesh->printFEM > 1) { 63419566063dSJacob Faibussowitsch PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 63429566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind * totDim])); 63439566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Z", totDim, z)); 63448e3a2eefSMatthew G. Knepley } 63459566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES)); 63468e3a2eefSMatthew G. Knepley } 63479566063dSJacob Faibussowitsch PetscCall(PetscFree6(u, u_t, elemMat, elemMatD, y, z)); 63488e3a2eefSMatthew G. Knepley if (mesh->printFEM) { 63499566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n")); 63509566063dSJacob Faibussowitsch PetscCall(VecView(Z, NULL)); 63518e3a2eefSMatthew G. Knepley } 63521059d808SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 63539566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 63549566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexAux)); 63559566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 63569566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 63573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 63588e3a2eefSMatthew G. Knepley } 6359