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 192fe8e7dddSPierre 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); 13026c51210dSStefano Zampini PetscTryMethod(dm, "DMPlexInsertTimeDerivativeBoundaryValues_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 13065962854dSMatthew G. Knepley // Handle non-essential (e.g. outflow) boundary values 13075962854dSMatthew G. Knepley PetscErrorCode DMPlexInsertBoundaryValuesFVM(DM dm, PetscFV fv, Vec locX, PetscReal time, Vec *locGradient) 13085962854dSMatthew G. Knepley { 13095962854dSMatthew G. Knepley DM dmGrad; 13105962854dSMatthew G. Knepley Vec cellGeometryFVM, faceGeometryFVM, locGrad = NULL; 13115962854dSMatthew G. Knepley 13125962854dSMatthew G. Knepley PetscFunctionBegin; 13135962854dSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 13145962854dSMatthew G. Knepley PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 13155962854dSMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 13165962854dSMatthew G. Knepley if (locGradient) { 13175962854dSMatthew G. Knepley PetscAssertPointer(locGradient, 5); 13185962854dSMatthew G. Knepley *locGradient = NULL; 13195962854dSMatthew G. Knepley } 13205962854dSMatthew G. Knepley PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 13215962854dSMatthew G. Knepley /* Reconstruct and limit cell gradients */ 13225962854dSMatthew G. Knepley PetscCall(DMPlexGetGradientDM(dm, fv, &dmGrad)); 13235962854dSMatthew G. Knepley if (dmGrad) { 13245962854dSMatthew G. Knepley Vec grad; 13255962854dSMatthew G. Knepley PetscInt fStart, fEnd; 13265962854dSMatthew G. Knepley 13275962854dSMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 13285962854dSMatthew G. Knepley PetscCall(DMGetGlobalVector(dmGrad, &grad)); 13295962854dSMatthew G. Knepley PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 13305962854dSMatthew G. Knepley /* Communicate gradient values */ 13315962854dSMatthew G. Knepley PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 13325962854dSMatthew G. Knepley PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 13335962854dSMatthew G. Knepley PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 13345962854dSMatthew G. Knepley PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 13355962854dSMatthew G. Knepley } 13365962854dSMatthew G. Knepley PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad)); 13375962854dSMatthew G. Knepley if (locGradient) *locGradient = locGrad; 13385962854dSMatthew G. Knepley else if (locGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 13395962854dSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 13405962854dSMatthew G. Knepley } 13415962854dSMatthew G. Knepley 1342d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1343d71ae5a4SJacob Faibussowitsch { 1344574a98acSMatthew G. Knepley Vec localX; 1345574a98acSMatthew G. Knepley 1346574a98acSMatthew G. Knepley PetscFunctionBegin; 13479566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 13489566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL)); 13499566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 13509566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 13519566063dSJacob Faibussowitsch PetscCall(DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff)); 13529566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 13533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1354574a98acSMatthew G. Knepley } 1355574a98acSMatthew G. Knepley 1356574a98acSMatthew G. Knepley /*@C 135760225df5SJacob Faibussowitsch DMPlexComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 1358574a98acSMatthew G. Knepley 135920f4b53cSBarry Smith Collective 1360c0f8e1fdSMatthew G. Knepley 1361574a98acSMatthew G. Knepley Input Parameters: 1362a1cb98faSBarry Smith + dm - The `DM` 1363574a98acSMatthew G. Knepley . time - The time 1364574a98acSMatthew G. Knepley . funcs - The functions to evaluate for each field component 136520f4b53cSBarry Smith . ctxs - Optional array of contexts to pass to each function, or `NULL`. 1366574a98acSMatthew G. Knepley - localX - The coefficient vector u_h, a local vector 1367574a98acSMatthew G. Knepley 1368574a98acSMatthew G. Knepley Output Parameter: 1369574a98acSMatthew G. Knepley . diff - The diff ||u - u_h||_2 1370574a98acSMatthew G. Knepley 1371574a98acSMatthew G. Knepley Level: developer 1372574a98acSMatthew G. Knepley 13731cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1374574a98acSMatthew G. Knepley @*/ 1375d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff) 1376d71ae5a4SJacob Faibussowitsch { 13770f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1378ca3d3a14SMatthew G. Knepley DM tdm; 1379ca3d3a14SMatthew G. Knepley Vec tv; 1380cb1e1211SMatthew G Knepley PetscSection section; 1381c5bbbd5bSMatthew G. Knepley PetscQuadrature quad; 13824bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 138315496722SMatthew G. Knepley PetscScalar *funcVal, *interpolant; 13844bee2e38SMatthew G. Knepley PetscReal *coords, *gcoords; 1385cb1e1211SMatthew G Knepley PetscReal localDiff = 0.0; 13867318780aSToby Isaac const PetscReal *quadWeights; 1387412e9a14SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, c, field, fieldOffset; 1388ca3d3a14SMatthew G. Knepley PetscBool transform; 1389cb1e1211SMatthew G Knepley 1390cb1e1211SMatthew G Knepley PetscFunctionBegin; 13919566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 13929566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 13932a4e142eSMatthew G. Knepley fegeom.dimEmbed = coordDim; 13949566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 13959566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 13969566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 13979566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 13989566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 1399eae3dc7dSJacob Faibussowitsch PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 1400cb1e1211SMatthew G Knepley for (field = 0; field < numFields; ++field) { 140115496722SMatthew G. Knepley PetscObject obj; 140215496722SMatthew G. Knepley PetscClassId id; 1403c5bbbd5bSMatthew G. Knepley PetscInt Nc; 1404c5bbbd5bSMatthew G. Knepley 14059566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 14069566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 140715496722SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 140815496722SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 140915496722SMatthew G. Knepley 14109566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 14119566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 141215496722SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 141315496722SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 141415496722SMatthew G. Knepley 14159566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 14169566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 141763a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1418c5bbbd5bSMatthew G. Knepley numComponents += Nc; 1419cb1e1211SMatthew G Knepley } 14209566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 142163a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 1422c9cb6370SYANG Zongze PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * (Nq + 1), &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 14239566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 14249566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 1425cb1e1211SMatthew G Knepley for (c = cStart; c < cEnd; ++c) { 1426a1e44745SMatthew G. Knepley PetscScalar *x = NULL; 1427cb1e1211SMatthew G Knepley PetscReal elemDiff = 0.0; 14289c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1429cb1e1211SMatthew G Knepley 14309566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1431e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 1432cb1e1211SMatthew G Knepley 143315496722SMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 143415496722SMatthew G. Knepley PetscObject obj; 143515496722SMatthew G. Knepley PetscClassId id; 1436c110b1eeSGeoffrey Irving void *const ctx = ctxs ? ctxs[field] : NULL; 143715496722SMatthew G. Knepley PetscInt Nb, Nc, q, fc; 1438cb1e1211SMatthew G Knepley 14399566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 14409566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 14419371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 14429371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 14439371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 14449371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 14459371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 14469371c9d4SSatish Balay Nb = 1; 14479371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1448cb1e1211SMatthew G Knepley if (debug) { 1449cb1e1211SMatthew G Knepley char title[1024]; 145063a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 14519566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1452cb1e1211SMatthew G Knepley } 14537318780aSToby Isaac for (q = 0; q < Nq; ++q) { 14542a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1455d0609cedSBarry Smith PetscErrorCode ierr; 14562a4e142eSMatthew G. Knepley 14572a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 14582a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 14592a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 14602a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 146163a3b9bcSJacob 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); 1462d3a7d86cSMatthew G. Knepley if (transform) { 1463d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * Nq]; 14649566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx)); 1465d3a7d86cSMatthew G. Knepley } else { 1466d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * q]; 1467d3a7d86cSMatthew G. Knepley } 14689566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(funcVal, Nc)); 1469ca3d3a14SMatthew G. Knepley ierr = (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx); 1470e735a8a9SMatthew G. Knepley if (ierr) { 14719566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 14729566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 14739566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1474e735a8a9SMatthew G. Knepley } 14759566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 14769566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 14779566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 14782df84da0SMatthew G. Knepley else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 147915496722SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1480beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 14819371c9d4SSatish Balay if (debug) 14829371c9d4SSatish 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.), 14839371c9d4SSatish Balay (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]), (double)PetscRealPart(interpolant[fc]), (double)PetscRealPart(funcVal[fc]))); 14844bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1485cb1e1211SMatthew G Knepley } 1486cb1e1211SMatthew G Knepley } 14879c3cf19fSMatthew G. Knepley fieldOffset += Nb; 1488beaa55a6SMatthew G. Knepley qc += Nc; 1489cb1e1211SMatthew G Knepley } 14909566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 14919566063dSJacob Faibussowitsch if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 1492cb1e1211SMatthew G Knepley localDiff += elemDiff; 1493cb1e1211SMatthew G Knepley } 14949566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 14951c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 1496cb1e1211SMatthew G Knepley *diff = PetscSqrtReal(*diff); 14973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1498cb1e1211SMatthew G Knepley } 1499cb1e1211SMatthew G Knepley 1500d71ae5a4SJacob 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) 1501d71ae5a4SJacob Faibussowitsch { 15020f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1503ca3d3a14SMatthew G. Knepley DM tdm; 1504cb1e1211SMatthew G Knepley PetscSection section; 150540e14135SMatthew G. Knepley PetscQuadrature quad; 1506ca3d3a14SMatthew G. Knepley Vec localX, tv; 15079c3cf19fSMatthew G. Knepley PetscScalar *funcVal, *interpolant; 15082a4e142eSMatthew G. Knepley const PetscReal *quadWeights; 15094bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 15104bee2e38SMatthew G. Knepley PetscReal *coords, *gcoords; 151140e14135SMatthew G. Knepley PetscReal localDiff = 0.0; 1512485ad865SMatthew G. Knepley PetscInt dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset; 1513ca3d3a14SMatthew G. Knepley PetscBool transform; 1514cb1e1211SMatthew G Knepley 1515cb1e1211SMatthew G Knepley PetscFunctionBegin; 15169566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 15179566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 15184bee2e38SMatthew G. Knepley fegeom.dimEmbed = coordDim; 15199566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 15209566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 15219566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 15229566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 15239566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 15249566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 15259566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 15269566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 1527652b88e8SMatthew G. Knepley for (field = 0; field < numFields; ++field) { 15280f2d7e86SMatthew G. Knepley PetscFE fe; 152940e14135SMatthew G. Knepley PetscInt Nc; 1530652b88e8SMatthew G. Knepley 15319566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe)); 15329566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 15339566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 153440e14135SMatthew G. Knepley numComponents += Nc; 1535652b88e8SMatthew G. Knepley } 15369566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 153763a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 15389566063dSJacob Faibussowitsch /* PetscCall(DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX)); */ 1539c9cb6370SYANG 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)); 15409566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 154140e14135SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 154240e14135SMatthew G. Knepley PetscScalar *x = NULL; 154340e14135SMatthew G. Knepley PetscReal elemDiff = 0.0; 15449c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1545652b88e8SMatthew G. Knepley 15469566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1547e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 154840e14135SMatthew G. Knepley 15499c3cf19fSMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 15500f2d7e86SMatthew G. Knepley PetscFE fe; 155151259fa3SMatthew G. Knepley void *const ctx = ctxs ? ctxs[field] : NULL; 15529c3cf19fSMatthew G. Knepley PetscInt Nb, Nc, q, fc; 155340e14135SMatthew G. Knepley 15549566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe)); 15559566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 15569566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 155740e14135SMatthew G. Knepley if (debug) { 155840e14135SMatthew G. Knepley char title[1024]; 15599566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 15609566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1561652b88e8SMatthew G. Knepley } 15629c3cf19fSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 15632a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1564d0609cedSBarry Smith PetscErrorCode ierr; 15652a4e142eSMatthew G. Knepley 15662a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 15672a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 15682a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 15692a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 15702df84da0SMatthew 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); 1571d3a7d86cSMatthew G. Knepley if (transform) { 1572d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * Nq]; 15739566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx)); 1574d3a7d86cSMatthew G. Knepley } else { 1575d3a7d86cSMatthew G. Knepley gcoords = &coords[coordDim * q]; 1576d3a7d86cSMatthew G. Knepley } 15779566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(funcVal, Nc)); 15784bee2e38SMatthew G. Knepley ierr = (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx); 1579e735a8a9SMatthew G. Knepley if (ierr) { 15809566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 15819566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 15829566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ)); 1583e735a8a9SMatthew G. Knepley } 15849566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 15859566063dSJacob Faibussowitsch PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[fieldOffset], &qgeom, q, interpolant)); 15864bee2e38SMatthew G. Knepley /* Overwrite with the dot product if the normal is given */ 15874bee2e38SMatthew G. Knepley if (n) { 15884bee2e38SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 15894bee2e38SMatthew G. Knepley PetscScalar sum = 0.0; 15904bee2e38SMatthew G. Knepley PetscInt d; 15914bee2e38SMatthew G. Knepley for (d = 0; d < dim; ++d) sum += interpolant[fc * dim + d] * n[d]; 15924bee2e38SMatthew G. Knepley interpolant[fc] = sum; 15934bee2e38SMatthew G. Knepley } 15944bee2e38SMatthew G. Knepley } 15959c3cf19fSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1596beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 159763a3b9bcSJacob 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]))); 15984bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 159940e14135SMatthew G. Knepley } 160040e14135SMatthew G. Knepley } 16019c3cf19fSMatthew G. Knepley fieldOffset += Nb; 16029c3cf19fSMatthew G. Knepley qc += Nc; 160340e14135SMatthew G. Knepley } 16049566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 160563a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 160640e14135SMatthew G. Knepley localDiff += elemDiff; 160740e14135SMatthew G. Knepley } 16089566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ)); 16099566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 16101c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 161140e14135SMatthew G. Knepley *diff = PetscSqrtReal(*diff); 16123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1613cb1e1211SMatthew G Knepley } 1614cb1e1211SMatthew G Knepley 1615d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1616d71ae5a4SJacob Faibussowitsch { 16170f09c10fSMatthew G. Knepley const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1618ca3d3a14SMatthew G. Knepley DM tdm; 1619083401c6SMatthew G. Knepley DMLabel depthLabel; 162073d901b8SMatthew G. Knepley PetscSection section; 1621ca3d3a14SMatthew G. Knepley Vec localX, tv; 162273d901b8SMatthew G. Knepley PetscReal *localDiff; 1623083401c6SMatthew G. Knepley PetscInt dim, depth, dE, Nf, f, Nds, s; 1624ca3d3a14SMatthew G. Knepley PetscBool transform; 162573d901b8SMatthew G. Knepley 162673d901b8SMatthew G. Knepley PetscFunctionBegin; 16279566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 16289566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &dE)); 16299566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 16309566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 16319566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 16329566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 16339566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 16349566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 16359566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 16369566063dSJacob Faibussowitsch PetscCall(DMLabelGetNumValues(depthLabel, &depth)); 1637083401c6SMatthew G. Knepley 16389566063dSJacob Faibussowitsch PetscCall(VecSet(localX, 0.0)); 16399566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 16409566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 16419566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 16429566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 16439566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(Nf, &localDiff)); 1644083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 1645083401c6SMatthew G. Knepley PetscDS ds; 1646083401c6SMatthew G. Knepley DMLabel label; 1647083401c6SMatthew G. Knepley IS fieldIS, pointIS; 1648083401c6SMatthew G. Knepley const PetscInt *fields, *points = NULL; 1649083401c6SMatthew G. Knepley PetscQuadrature quad; 1650083401c6SMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1651083401c6SMatthew G. Knepley PetscFEGeom fegeom; 1652083401c6SMatthew G. Knepley PetscReal *coords, *gcoords; 1653083401c6SMatthew G. Knepley PetscScalar *funcVal, *interpolant; 16545fedec97SMatthew G. Knepley PetscBool isCohesive; 1655083401c6SMatthew G. Knepley PetscInt qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf; 165673d901b8SMatthew G. Knepley 165707218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 16589566063dSJacob Faibussowitsch PetscCall(ISGetIndices(fieldIS, &fields)); 16599566063dSJacob Faibussowitsch PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 16609566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &dsNf)); 16619566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(ds, &totNc)); 16629566063dSJacob Faibussowitsch PetscCall(PetscDSGetQuadrature(ds, &quad)); 16639566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 166463a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != totNc), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, totNc); 16659566063dSJacob Faibussowitsch PetscCall(PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE * (Nq + 1), &coords, Nq, &fegeom.detJ, dE * dE * Nq, &fegeom.J, dE * dE * Nq, &fegeom.invJ)); 1666083401c6SMatthew G. Knepley if (!label) { 16679566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1668083401c6SMatthew G. Knepley } else { 16699566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 16709566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &cEnd)); 16719566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 1672083401c6SMatthew G. Knepley } 167373d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1674083401c6SMatthew G. Knepley const PetscInt cell = points ? points[c] : c; 167573d901b8SMatthew G. Knepley PetscScalar *x = NULL; 16765fedec97SMatthew G. Knepley const PetscInt *cone; 16775fedec97SMatthew G. Knepley PetscInt qc = 0, fOff = 0, dep; 167873d901b8SMatthew G. Knepley 16799566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(depthLabel, cell, &dep)); 1680083401c6SMatthew G. Knepley if (dep != depth - 1) continue; 16815fedec97SMatthew G. Knepley if (isCohesive) { 16829566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 16839566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 168496959cd1SMatthew G. Knepley } else { 16859566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 168696959cd1SMatthew G. Knepley } 1687e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, cell, 0, NULL, &x)); 16885fedec97SMatthew G. Knepley for (f = 0; f < dsNf; ++f) { 168915496722SMatthew G. Knepley PetscObject obj; 169015496722SMatthew G. Knepley PetscClassId id; 1691083401c6SMatthew G. Knepley void *const ctx = ctxs ? ctxs[fields[f]] : NULL; 169215496722SMatthew G. Knepley PetscInt Nb, Nc, q, fc; 169315496722SMatthew G. Knepley PetscReal elemDiff = 0.0; 16945fedec97SMatthew G. Knepley PetscBool cohesive; 169515496722SMatthew G. Knepley 16969566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 16979566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 16989566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 16999371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 17009371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 17019371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 17029371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 17039371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 17049371c9d4SSatish Balay Nb = 1; 17059371c9d4SSatish Balay } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 1706c82db6dbSMatthew G. Knepley if (isCohesive && !cohesive) { 1707c82db6dbSMatthew G. Knepley fOff += Nb * 2; 1708c82db6dbSMatthew G. Knepley qc += Nc; 1709c82db6dbSMatthew G. Knepley continue; 1710c82db6dbSMatthew G. Knepley } 171173d901b8SMatthew G. Knepley if (debug) { 171273d901b8SMatthew G. Knepley char title[1024]; 171363a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, fields[f])); 17149566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(cell, title, Nb, &x[fOff])); 171573d901b8SMatthew G. Knepley } 17167318780aSToby Isaac for (q = 0; q < Nq; ++q) { 17172a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 1718d0609cedSBarry Smith PetscErrorCode ierr; 17192a4e142eSMatthew G. Knepley 17202a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 1721083401c6SMatthew G. Knepley qgeom.J = &fegeom.J[q * dE * dE]; 1722083401c6SMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * dE * dE]; 17232a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 172463a3b9bcSJacob 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); 1725d3a7d86cSMatthew G. Knepley if (transform) { 1726083401c6SMatthew G. Knepley gcoords = &coords[dE * Nq]; 17279566063dSJacob Faibussowitsch PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE * q], PETSC_TRUE, dE, &coords[dE * q], gcoords, dm->transformCtx)); 1728d3a7d86cSMatthew G. Knepley } else { 1729083401c6SMatthew G. Knepley gcoords = &coords[dE * q]; 1730d3a7d86cSMatthew G. Knepley } 17312df84da0SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) funcVal[fc] = 0.; 1732083401c6SMatthew G. Knepley ierr = (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx); 1733e735a8a9SMatthew G. Knepley if (ierr) { 17349566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 17359566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 17369566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1737e735a8a9SMatthew G. Knepley } 17389566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[dE * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 173996959cd1SMatthew G. Knepley /* Call once for each face, except for lagrange field */ 17409566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fOff], &qgeom, q, interpolant)); 17419566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fOff], q, interpolant)); 174263a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 174315496722SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1744beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 17459371c9d4SSatish Balay if (debug) 17469371c9d4SSatish 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.), 17479371c9d4SSatish Balay (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]))); 17484bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 174973d901b8SMatthew G. Knepley } 175073d901b8SMatthew G. Knepley } 1751083401c6SMatthew G. Knepley fOff += Nb; 17529c3cf19fSMatthew G. Knepley qc += Nc; 1753083401c6SMatthew G. Knepley localDiff[fields[f]] += elemDiff; 175463a3b9bcSJacob 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]])); 175573d901b8SMatthew G. Knepley } 17569566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 1757083401c6SMatthew G. Knepley } 1758083401c6SMatthew G. Knepley if (label) { 17599566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 17609566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 1761083401c6SMatthew G. Knepley } 17629566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(fieldIS, &fields)); 17639566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 176473d901b8SMatthew G. Knepley } 17659566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 17661c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 17679566063dSJacob Faibussowitsch PetscCall(PetscFree(localDiff)); 1768083401c6SMatthew G. Knepley for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]); 17693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 177073d901b8SMatthew G. Knepley } 177173d901b8SMatthew G. Knepley 1772e729f68cSMatthew G. Knepley /*@C 1773e729f68cSMatthew 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. 1774e729f68cSMatthew G. Knepley 177520f4b53cSBarry Smith Collective 1776c0f8e1fdSMatthew G. Knepley 1777e729f68cSMatthew G. Knepley Input Parameters: 1778a1cb98faSBarry Smith + dm - The `DM` 17790163fd50SMatthew G. Knepley . time - The time 178020f4b53cSBarry Smith . funcs - The functions to evaluate for each field component: `NULL` means that component does not contribute to error calculation 178120f4b53cSBarry Smith . ctxs - Optional array of contexts to pass to each function, or `NULL`. 1782e729f68cSMatthew G. Knepley - X - The coefficient vector u_h 1783e729f68cSMatthew G. Knepley 1784e729f68cSMatthew G. Knepley Output Parameter: 178520f4b53cSBarry Smith . D - A `Vec` which holds the difference ||u - u_h||_2 for each cell 1786e729f68cSMatthew G. Knepley 1787e729f68cSMatthew G. Knepley Level: developer 1788e729f68cSMatthew G. Knepley 17891cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1790e729f68cSMatthew G. Knepley @*/ 1791d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D) 1792d71ae5a4SJacob Faibussowitsch { 1793e729f68cSMatthew G. Knepley PetscSection section; 1794e729f68cSMatthew G. Knepley PetscQuadrature quad; 1795e729f68cSMatthew G. Knepley Vec localX; 17964bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 1797e729f68cSMatthew G. Knepley PetscScalar *funcVal, *interpolant; 17984bee2e38SMatthew G. Knepley PetscReal *coords; 1799e729f68cSMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 1800485ad865SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset; 1801e729f68cSMatthew G. Knepley 1802e729f68cSMatthew G. Knepley PetscFunctionBegin; 18039566063dSJacob Faibussowitsch PetscCall(VecSet(D, 0.0)); 18049566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 18059566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 18069566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 18079566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &numFields)); 18089566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &localX)); 18099566063dSJacob Faibussowitsch PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 18109566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 18119566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1812e729f68cSMatthew G. Knepley for (field = 0; field < numFields; ++field) { 1813e729f68cSMatthew G. Knepley PetscObject obj; 1814e729f68cSMatthew G. Knepley PetscClassId id; 1815e729f68cSMatthew G. Knepley PetscInt Nc; 1816e729f68cSMatthew G. Knepley 18179566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 18189566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 1819e729f68cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 1820e729f68cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 1821e729f68cSMatthew G. Knepley 18229566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 18239566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1824e729f68cSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 1825e729f68cSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 1826e729f68cSMatthew G. Knepley 18279566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 18289566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 182963a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1830e729f68cSMatthew G. Knepley numComponents += Nc; 1831e729f68cSMatthew G. Knepley } 18329566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 183363a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 18349566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 18359566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1836e729f68cSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1837e729f68cSMatthew G. Knepley PetscScalar *x = NULL; 18386f288a59SMatthew G. Knepley PetscScalar elemDiff = 0.0; 18399c3cf19fSMatthew G. Knepley PetscInt qc = 0; 1840e729f68cSMatthew G. Knepley 18419566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1842e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x)); 1843e729f68cSMatthew G. Knepley 1844e729f68cSMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1845e729f68cSMatthew G. Knepley PetscObject obj; 1846e729f68cSMatthew G. Knepley PetscClassId id; 1847e729f68cSMatthew G. Knepley void *const ctx = ctxs ? ctxs[field] : NULL; 1848e729f68cSMatthew G. Knepley PetscInt Nb, Nc, q, fc; 1849e729f68cSMatthew G. Knepley 18509566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 18519566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 18529371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 18539371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 18549371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 18559371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 18569371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 18579371c9d4SSatish Balay Nb = 1; 18589371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 185923f34ed2SToby Isaac if (funcs[field]) { 18607318780aSToby Isaac for (q = 0; q < Nq; ++q) { 18612a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 18622a4e142eSMatthew G. Knepley 18632a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 18642a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 18652a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 18662a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 186763a3b9bcSJacob 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); 18689566063dSJacob Faibussowitsch PetscCall((*funcs[field])(coordDim, time, &coords[q * coordDim], Nc, funcVal, ctx)); 1869c3e24edfSBarry Smith #if defined(needs_fix_with_return_code_argument) 1870e735a8a9SMatthew G. Knepley if (ierr) { 18719566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 18729566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 18739566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 1874e735a8a9SMatthew G. Knepley } 1875c3e24edfSBarry Smith #endif 18769566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 18779566063dSJacob Faibussowitsch else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 187863a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1879e729f68cSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 1880beaa55a6SMatthew G. Knepley const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 18814bee2e38SMatthew G. Knepley elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1882e729f68cSMatthew G. Knepley } 1883e729f68cSMatthew G. Knepley } 188423f34ed2SToby Isaac } 1885beaa55a6SMatthew G. Knepley fieldOffset += Nb; 18869c3cf19fSMatthew G. Knepley qc += Nc; 1887e729f68cSMatthew G. Knepley } 18889566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 18899566063dSJacob Faibussowitsch PetscCall(VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES)); 1890e729f68cSMatthew G. Knepley } 18919566063dSJacob Faibussowitsch PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 18929566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &localX)); 18939566063dSJacob Faibussowitsch PetscCall(VecSqrtAbs(D)); 18943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1895e729f68cSMatthew G. Knepley } 1896e729f68cSMatthew G. Knepley 18975f0b18bfSMatthew G. Knepley /*@ 189820f4b53cSBarry Smith DMPlexComputeClementInterpolant - This function computes the L2 projection of the cellwise values of a function u onto P1 18995f0b18bfSMatthew G. Knepley 190020f4b53cSBarry Smith Collective 19015f0b18bfSMatthew G. Knepley 19025f0b18bfSMatthew G. Knepley Input Parameters: 1903a1cb98faSBarry Smith + dm - The `DM` 19045f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h 19055f0b18bfSMatthew G. Knepley 19065f0b18bfSMatthew G. Knepley Output Parameter: 1907a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the function 19085f0b18bfSMatthew G. Knepley 19095f0b18bfSMatthew G. Knepley Level: developer 19105f0b18bfSMatthew G. Knepley 1911a1cb98faSBarry Smith Note: 1912a1cb98faSBarry 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 1913a1cb98faSBarry Smith 19141cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 19155f0b18bfSMatthew G. Knepley @*/ 1916d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeClementInterpolant(DM dm, Vec locX, Vec locC) 1917d71ae5a4SJacob Faibussowitsch { 19185f0b18bfSMatthew G. Knepley PetscInt debug = ((DM_Plex *)dm->data)->printFEM; 19195f0b18bfSMatthew G. Knepley DM dmc; 19205f0b18bfSMatthew G. Knepley PetscQuadrature quad; 19215f0b18bfSMatthew G. Knepley PetscScalar *interpolant, *valsum; 19225f0b18bfSMatthew G. Knepley PetscFEGeom fegeom; 19235f0b18bfSMatthew G. Knepley PetscReal *coords; 19245f0b18bfSMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 19255f0b18bfSMatthew G. Knepley PetscInt dim, cdim, Nf, f, Nc = 0, Nq, qNc, cStart, cEnd, vStart, vEnd, v; 19265f0b18bfSMatthew G. Knepley 19275f0b18bfSMatthew G. Knepley PetscFunctionBegin; 19289566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 19299566063dSJacob Faibussowitsch PetscCall(VecGetDM(locC, &dmc)); 19309566063dSJacob Faibussowitsch PetscCall(VecSet(locC, 0.0)); 19319566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 19329566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 19335f0b18bfSMatthew G. Knepley fegeom.dimEmbed = cdim; 19349566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 19355f0b18bfSMatthew G. Knepley PetscCheck(Nf > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 19365f0b18bfSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 19375f0b18bfSMatthew G. Knepley PetscObject obj; 19385f0b18bfSMatthew G. Knepley PetscClassId id; 19395f0b18bfSMatthew G. Knepley PetscInt fNc; 19405f0b18bfSMatthew G. Knepley 19419566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, f, NULL, &obj)); 19429566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 19435f0b18bfSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 19445f0b18bfSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 19455f0b18bfSMatthew G. Knepley 19469566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 19479566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &fNc)); 19485f0b18bfSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 19495f0b18bfSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 19505f0b18bfSMatthew G. Knepley 19519566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 19529566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &fNc)); 195363a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 19545f0b18bfSMatthew G. Knepley Nc += fNc; 19555f0b18bfSMatthew G. Knepley } 19569566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 195763a3b9bcSJacob Faibussowitsch PetscCheck(qNc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " > 1", qNc); 19589566063dSJacob Faibussowitsch PetscCall(PetscMalloc6(Nc * 2, &valsum, Nc, &interpolant, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ)); 19599566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 19609566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 19615f0b18bfSMatthew G. Knepley for (v = vStart; v < vEnd; ++v) { 19625f0b18bfSMatthew G. Knepley PetscScalar volsum = 0.0; 19635f0b18bfSMatthew G. Knepley PetscInt *star = NULL; 19645f0b18bfSMatthew G. Knepley PetscInt starSize, st, fc; 19655f0b18bfSMatthew G. Knepley 19669566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(valsum, Nc)); 19679566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 19685f0b18bfSMatthew G. Knepley for (st = 0; st < starSize * 2; st += 2) { 19695f0b18bfSMatthew G. Knepley const PetscInt cell = star[st]; 19705f0b18bfSMatthew G. Knepley PetscScalar *val = &valsum[Nc]; 19715f0b18bfSMatthew G. Knepley PetscScalar *x = NULL; 19725f0b18bfSMatthew G. Knepley PetscReal vol = 0.0; 19735f0b18bfSMatthew G. Knepley PetscInt foff = 0; 19745f0b18bfSMatthew G. Knepley 19755f0b18bfSMatthew G. Knepley if ((cell < cStart) || (cell >= cEnd)) continue; 19769566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 19779566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 19785f0b18bfSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 19795f0b18bfSMatthew G. Knepley PetscObject obj; 19805f0b18bfSMatthew G. Knepley PetscClassId id; 19815f0b18bfSMatthew G. Knepley PetscInt Nb, fNc, q; 19825f0b18bfSMatthew G. Knepley 19839566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(val, Nc)); 19849566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, f, NULL, &obj)); 19859566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 19869371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 19879371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &fNc)); 19889371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 19899371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 19909371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &fNc)); 19919371c9d4SSatish Balay Nb = 1; 19929371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 19935f0b18bfSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 19945f0b18bfSMatthew G. Knepley const PetscReal wt = quadWeights[q] * fegeom.detJ[q]; 19955f0b18bfSMatthew G. Knepley PetscFEGeom qgeom; 19965f0b18bfSMatthew G. Knepley 19975f0b18bfSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 19985f0b18bfSMatthew G. Knepley qgeom.J = &fegeom.J[q * cdim * cdim]; 19995f0b18bfSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * cdim * cdim]; 20005f0b18bfSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 200163a3b9bcSJacob 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); 20029566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[foff], &qgeom, q, interpolant)); 200363a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 20045f0b18bfSMatthew G. Knepley for (fc = 0; fc < fNc; ++fc) val[foff + fc] += interpolant[fc] * wt; 20055f0b18bfSMatthew G. Knepley vol += wt; 20065f0b18bfSMatthew G. Knepley } 20075f0b18bfSMatthew G. Knepley foff += Nb; 20085f0b18bfSMatthew G. Knepley } 20099566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 20105f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) valsum[fc] += val[fc]; 20115f0b18bfSMatthew G. Knepley volsum += vol; 20125f0b18bfSMatthew G. Knepley if (debug) { 20139566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " value: [", v, cell)); 20145f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 20159566063dSJacob Faibussowitsch if (fc) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 20169566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(val[fc]))); 20175f0b18bfSMatthew G. Knepley } 20189566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 20195f0b18bfSMatthew G. Knepley } 20205f0b18bfSMatthew G. Knepley } 20215f0b18bfSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) valsum[fc] /= volsum; 20229566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 20239566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dmc, NULL, locC, v, valsum, INSERT_VALUES)); 20245f0b18bfSMatthew G. Knepley } 20259566063dSJacob Faibussowitsch PetscCall(PetscFree6(valsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 20263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 20275f0b18bfSMatthew G. Knepley } 20285f0b18bfSMatthew G. Knepley 20295f0b18bfSMatthew G. Knepley /*@ 203020f4b53cSBarry Smith DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1 20311555c271SMatthew G. Knepley 203220f4b53cSBarry Smith Collective 2033c0f8e1fdSMatthew G. Knepley 20341555c271SMatthew G. Knepley Input Parameters: 2035a1cb98faSBarry Smith + dm - The `DM` 20365f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h 20371555c271SMatthew G. Knepley 20381555c271SMatthew G. Knepley Output Parameter: 2039a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the gradient 20401555c271SMatthew G. Knepley 20411555c271SMatthew G. Knepley Level: developer 20421555c271SMatthew G. Knepley 2043a1cb98faSBarry Smith Note: 2044a1cb98faSBarry 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 2045a1cb98faSBarry Smith 20461cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 20471555c271SMatthew G. Knepley @*/ 2048d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC) 2049d71ae5a4SJacob Faibussowitsch { 2050db1066baSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2051db1066baSMatthew G. Knepley PetscInt debug = mesh->printFEM; 20521555c271SMatthew G. Knepley DM dmC; 20531555c271SMatthew G. Knepley PetscQuadrature quad; 20541555c271SMatthew G. Knepley PetscScalar *interpolant, *gradsum; 20554bee2e38SMatthew G. Knepley PetscFEGeom fegeom; 20564bee2e38SMatthew G. Knepley PetscReal *coords; 20571555c271SMatthew G. Knepley const PetscReal *quadPoints, *quadWeights; 2058485ad865SMatthew G. Knepley PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset; 20591555c271SMatthew G. Knepley 20601555c271SMatthew G. Knepley PetscFunctionBegin; 20619566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 20629566063dSJacob Faibussowitsch PetscCall(VecGetDM(locC, &dmC)); 20639566063dSJacob Faibussowitsch PetscCall(VecSet(locC, 0.0)); 20649566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 20659566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 20664bee2e38SMatthew G. Knepley fegeom.dimEmbed = coordDim; 20679566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &numFields)); 20685f80ce2aSJacob Faibussowitsch PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 20691555c271SMatthew G. Knepley for (field = 0; field < numFields; ++field) { 20701555c271SMatthew G. Knepley PetscObject obj; 20711555c271SMatthew G. Knepley PetscClassId id; 20721555c271SMatthew G. Knepley PetscInt Nc; 20731555c271SMatthew G. Knepley 20749566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 20759566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 20761555c271SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 20771555c271SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 20781555c271SMatthew G. Knepley 20799566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 20809566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 20811555c271SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 20821555c271SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 20831555c271SMatthew G. Knepley 20849566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature(fv, &quad)); 20859566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 208663a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 20871555c271SMatthew G. Knepley numComponents += Nc; 20881555c271SMatthew G. Knepley } 20899566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 209063a3b9bcSJacob Faibussowitsch PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 20919566063dSJacob 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)); 20929566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 20939566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 20941555c271SMatthew G. Knepley for (v = vStart; v < vEnd; ++v) { 20951555c271SMatthew G. Knepley PetscScalar volsum = 0.0; 20961555c271SMatthew G. Knepley PetscInt *star = NULL; 20971555c271SMatthew G. Knepley PetscInt starSize, st, d, fc; 20981555c271SMatthew G. Knepley 20999566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(gradsum, coordDim * numComponents)); 21009566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 21011555c271SMatthew G. Knepley for (st = 0; st < starSize * 2; st += 2) { 21021555c271SMatthew G. Knepley const PetscInt cell = star[st]; 21031555c271SMatthew G. Knepley PetscScalar *grad = &gradsum[coordDim * numComponents]; 21041555c271SMatthew G. Knepley PetscScalar *x = NULL; 21051555c271SMatthew G. Knepley PetscReal vol = 0.0; 21061555c271SMatthew G. Knepley 21071555c271SMatthew G. Knepley if ((cell < cStart) || (cell >= cEnd)) continue; 21089566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 21099566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 21101555c271SMatthew G. Knepley for (field = 0, fieldOffset = 0; field < numFields; ++field) { 21111555c271SMatthew G. Knepley PetscObject obj; 21121555c271SMatthew G. Knepley PetscClassId id; 21131555c271SMatthew G. Knepley PetscInt Nb, Nc, q, qc = 0; 21141555c271SMatthew G. Knepley 21159566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(grad, coordDim * numComponents)); 21169566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, field, NULL, &obj)); 21179566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 21189371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 21199371c9d4SSatish Balay PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 21209371c9d4SSatish Balay PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 21219371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 21229371c9d4SSatish Balay PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 21239371c9d4SSatish Balay Nb = 1; 21249371c9d4SSatish Balay } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 21251555c271SMatthew G. Knepley for (q = 0; q < Nq; ++q) { 21262a4e142eSMatthew G. Knepley PetscFEGeom qgeom; 21272a4e142eSMatthew G. Knepley 21282a4e142eSMatthew G. Knepley qgeom.dimEmbed = fegeom.dimEmbed; 21292a4e142eSMatthew G. Knepley qgeom.J = &fegeom.J[q * coordDim * coordDim]; 21302a4e142eSMatthew G. Knepley qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 21312a4e142eSMatthew G. Knepley qgeom.detJ = &fegeom.detJ[q]; 213263a3b9bcSJacob 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); 21339566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolateGradient_Static((PetscFE)obj, 1, &x[fieldOffset], &qgeom, q, interpolant)); 213463a3b9bcSJacob Faibussowitsch else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 21351555c271SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 213653d2db2dSJoe Wallwork const PetscReal wt = quadWeights[q * qNc + qc]; 21371555c271SMatthew G. Knepley 21384bee2e38SMatthew G. Knepley for (d = 0; d < coordDim; ++d) grad[fc * coordDim + d] += interpolant[fc * dim + d] * wt * fegeom.detJ[q]; 21391555c271SMatthew G. Knepley } 21404bee2e38SMatthew G. Knepley vol += quadWeights[q * qNc] * fegeom.detJ[q]; 21411555c271SMatthew G. Knepley } 21421555c271SMatthew G. Knepley fieldOffset += Nb; 21431555c271SMatthew G. Knepley qc += Nc; 21441555c271SMatthew G. Knepley } 21459566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 2146f8527842SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 2147ad540459SPierre Jolivet for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] += grad[fc * coordDim + d]; 2148f8527842SMatthew G. Knepley } 2149f8527842SMatthew G. Knepley volsum += vol; 2150db1066baSMatthew G. Knepley if (debug) { 21519566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " gradient: [", v, cell)); 21521555c271SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 21531555c271SMatthew G. Knepley for (d = 0; d < coordDim; ++d) { 21549566063dSJacob Faibussowitsch if (fc || d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 21559566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc * coordDim + d]))); 21561555c271SMatthew G. Knepley } 21571555c271SMatthew G. Knepley } 21589566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 2159db1066baSMatthew G. Knepley } 21601555c271SMatthew G. Knepley } 21611555c271SMatthew G. Knepley for (fc = 0; fc < numComponents; ++fc) { 21621555c271SMatthew G. Knepley for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] /= volsum; 21631555c271SMatthew G. Knepley } 21649566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 21659566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES)); 21661555c271SMatthew G. Knepley } 21679566063dSJacob Faibussowitsch PetscCall(PetscFree6(gradsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 21683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 21691555c271SMatthew G. Knepley } 21701555c271SMatthew G. Knepley 21716493148fSStefano Zampini PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec locX, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user) 2172d71ae5a4SJacob Faibussowitsch { 2173338f77d5SMatthew G. Knepley DM dmAux = NULL; 217461aaff12SToby Isaac PetscDS prob, probAux = NULL; 217573d901b8SMatthew G. Knepley PetscSection section, sectionAux; 21766493148fSStefano Zampini Vec locA; 2177c330f8ffSToby Isaac PetscInt dim, numCells = cEnd - cStart, c, f; 2178c330f8ffSToby Isaac PetscBool useFVM = PETSC_FALSE; 2179338f77d5SMatthew G. Knepley /* DS */ 2180338f77d5SMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x, numConstants; 2181338f77d5SMatthew G. Knepley PetscInt NfAux, totDimAux, *aOff; 2182*8e3a54c0SPierre Jolivet PetscScalar *u, *a = NULL; 2183338f77d5SMatthew G. Knepley const PetscScalar *constants; 2184338f77d5SMatthew G. Knepley /* Geometry */ 2185c330f8ffSToby Isaac PetscFEGeom *cgeomFEM; 2186338f77d5SMatthew G. Knepley DM dmGrad; 2187c330f8ffSToby Isaac PetscQuadrature affineQuad = NULL; 2188338f77d5SMatthew G. Knepley Vec cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 2189b5a3613cSMatthew G. Knepley PetscFVCellGeom *cgeomFVM; 2190338f77d5SMatthew G. Knepley const PetscScalar *lgrad; 2191b7260050SToby Isaac PetscInt maxDegree; 2192c330f8ffSToby Isaac DMField coordField; 2193c330f8ffSToby Isaac IS cellIS; 219473d901b8SMatthew G. Knepley 219573d901b8SMatthew G. Knepley PetscFunctionBegin; 21969566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 21979566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 21989566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 21999566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 2200338f77d5SMatthew G. Knepley /* Determine which discretizations we have */ 2201b5a3613cSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2202b5a3613cSMatthew G. Knepley PetscObject obj; 2203b5a3613cSMatthew G. Knepley PetscClassId id; 2204b5a3613cSMatthew G. Knepley 22059566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 22069566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2207338f77d5SMatthew G. Knepley if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE; 2208338f77d5SMatthew G. Knepley } 2209338f77d5SMatthew G. Knepley /* Read DS information */ 22109566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 22119566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 22129566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 22139566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, numCells, cStart, 1, &cellIS)); 22149566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 2215338f77d5SMatthew G. Knepley /* Read Auxiliary DS information */ 22169566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 22179a2a23afSMatthew G. Knepley if (locA) { 22189566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 22199566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 22209566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 22219566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 22229566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 22239566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 2224338f77d5SMatthew G. Knepley } 2225338f77d5SMatthew G. Knepley /* Allocate data arrays */ 22269566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numCells * totDim, &u)); 22279566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 2228338f77d5SMatthew G. Knepley /* Read out geometry */ 22299566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 22309566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 2231b7260050SToby Isaac if (maxDegree <= 1) { 22329566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 223348a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &cgeomFEM)); 2234b5a3613cSMatthew G. Knepley } 2235b5a3613cSMatthew G. Knepley if (useFVM) { 2236338f77d5SMatthew G. Knepley PetscFV fv = NULL; 2237b5a3613cSMatthew G. Knepley Vec grad; 2238b5a3613cSMatthew G. Knepley PetscInt fStart, fEnd; 2239b5a3613cSMatthew G. Knepley PetscBool compGrad; 2240b5a3613cSMatthew G. Knepley 2241338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2242338f77d5SMatthew G. Knepley PetscObject obj; 2243338f77d5SMatthew G. Knepley PetscClassId id; 2244338f77d5SMatthew G. Knepley 22459566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 22469566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 22479371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 22489371c9d4SSatish Balay fv = (PetscFV)obj; 22499371c9d4SSatish Balay break; 22509371c9d4SSatish Balay } 2251338f77d5SMatthew G. Knepley } 22529566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &compGrad)); 22539566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, PETSC_TRUE)); 22549566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM)); 22559566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad)); 22569566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, compGrad)); 22579566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 2258b5a3613cSMatthew G. Knepley /* Reconstruct and limit cell gradients */ 22599566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 22609566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmGrad, &grad)); 22619566063dSJacob Faibussowitsch PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 2262b5a3613cSMatthew G. Knepley /* Communicate gradient values */ 22639566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 22649566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 22659566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 22669566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 2267b5a3613cSMatthew G. Knepley /* Handle non-essential (e.g. outflow) boundary values */ 22689566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad)); 22699566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 2270b5a3613cSMatthew G. Knepley } 2271338f77d5SMatthew G. Knepley /* Read out data from inputs */ 227273d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 227373d901b8SMatthew G. Knepley PetscScalar *x = NULL; 227473d901b8SMatthew G. Knepley PetscInt i; 227573d901b8SMatthew G. Knepley 22769566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, c, NULL, &x)); 22770f2d7e86SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 22789566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x)); 227973d901b8SMatthew G. Knepley if (dmAux) { 22809566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x)); 22810f2d7e86SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 22829566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x)); 228373d901b8SMatthew G. Knepley } 228473d901b8SMatthew G. Knepley } 2285338f77d5SMatthew G. Knepley /* Do integration for each field */ 228673d901b8SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2287c1f031eeSMatthew G. Knepley PetscObject obj; 2288c1f031eeSMatthew G. Knepley PetscClassId id; 2289c1f031eeSMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 229073d901b8SMatthew G. Knepley 22919566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 22929566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2293c1f031eeSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 2294c1f031eeSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2295c1f031eeSMatthew G. Knepley PetscQuadrature q; 2296c330f8ffSToby Isaac PetscFEGeom *chunkGeom = NULL; 2297c1f031eeSMatthew G. Knepley PetscInt Nq, Nb; 2298c1f031eeSMatthew G. Knepley 22999566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 23009566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 23019566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 23029566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 2303c1f031eeSMatthew G. Knepley blockSize = Nb * Nq; 230473d901b8SMatthew G. Knepley batchSize = numBlocks * blockSize; 23059566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 230673d901b8SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 230773d901b8SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 230873d901b8SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 230973d901b8SMatthew G. Knepley offset = numCells - Nr; 231048a46eb9SPierre Jolivet if (!affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, q, PETSC_FALSE, &cgeomFEM)); 23119566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 23129566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral)); 23139566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &chunkGeom)); 2314*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset * totDim], probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), &cintegral[offset * Nf])); 23159566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &chunkGeom)); 231648a46eb9SPierre Jolivet if (!affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 2317c1f031eeSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 2318c1f031eeSMatthew G. Knepley PetscInt foff; 2319420e96edSMatthew G. Knepley PetscPointFunc obj_func; 2320b69edc29SMatthew G. Knepley PetscScalar lint; 2321c1f031eeSMatthew G. Knepley 23229566063dSJacob Faibussowitsch PetscCall(PetscDSGetObjective(prob, f, &obj_func)); 23239566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, f, &foff)); 2324c1f031eeSMatthew G. Knepley if (obj_func) { 2325c1f031eeSMatthew G. Knepley for (c = 0; c < numCells; ++c) { 2326b5a3613cSMatthew G. Knepley PetscScalar *u_x; 2327b5a3613cSMatthew G. Knepley 23289566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x)); 2329338f77d5SMatthew 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); 2330338f77d5SMatthew G. Knepley cintegral[c * Nf + f] += PetscRealPart(lint) * cgeomFVM[c].volume; 233173d901b8SMatthew G. Knepley } 2332c1f031eeSMatthew G. Knepley } 233363a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 2334c1f031eeSMatthew G. Knepley } 2335338f77d5SMatthew G. Knepley /* Cleanup data arrays */ 2336b5a3613cSMatthew G. Knepley if (useFVM) { 23379566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 23389566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 23399566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 23409566063dSJacob Faibussowitsch PetscCall(VecDestroy(&faceGeometryFVM)); 23419566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cellGeometryFVM)); 23429566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dmGrad)); 2343b5a3613cSMatthew G. Knepley } 23449566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscFree(a)); 23459566063dSJacob Faibussowitsch PetscCall(PetscFree(u)); 2346338f77d5SMatthew G. Knepley /* Cleanup */ 234748a46eb9SPierre Jolivet if (affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 23489566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 23499566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 23503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2351338f77d5SMatthew G. Knepley } 2352338f77d5SMatthew G. Knepley 2353338f77d5SMatthew G. Knepley /*@ 2354338f77d5SMatthew G. Knepley DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user 2355338f77d5SMatthew G. Knepley 2356338f77d5SMatthew G. Knepley Input Parameters: 2357338f77d5SMatthew G. Knepley + dm - The mesh 2358338f77d5SMatthew G. Knepley . X - Global input vector 2359338f77d5SMatthew G. Knepley - user - The user context 2360338f77d5SMatthew G. Knepley 2361338f77d5SMatthew G. Knepley Output Parameter: 2362338f77d5SMatthew G. Knepley . integral - Integral for each field 2363338f77d5SMatthew G. Knepley 2364338f77d5SMatthew G. Knepley Level: developer 2365338f77d5SMatthew G. Knepley 23661cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2367338f77d5SMatthew G. Knepley @*/ 2368d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user) 2369d71ae5a4SJacob Faibussowitsch { 2370338f77d5SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2371b8feb594SMatthew G. Knepley PetscScalar *cintegral, *lintegral; 2372412e9a14SMatthew G. Knepley PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 23736493148fSStefano Zampini Vec locX; 2374338f77d5SMatthew G. Knepley 2375338f77d5SMatthew G. Knepley PetscFunctionBegin; 2376338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2377338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 23784f572ea9SToby Isaac PetscAssertPointer(integral, 3); 23799566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 23809566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 23819566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 23829566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2383338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 23849566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &lintegral, (cEnd - cStart) * Nf, &cintegral)); 23856493148fSStefano Zampini /* Get local solution with boundary values */ 23866493148fSStefano Zampini PetscCall(DMGetLocalVector(dm, &locX)); 23876493148fSStefano Zampini PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 23886493148fSStefano Zampini PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 23896493148fSStefano Zampini PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 23906493148fSStefano Zampini PetscCall(DMPlexComputeIntegral_Internal(dm, locX, cStart, cEnd, cintegral, user)); 23916493148fSStefano Zampini PetscCall(DMRestoreLocalVector(dm, &locX)); 2392338f77d5SMatthew G. Knepley /* Sum up values */ 2393338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2394338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 2395338f77d5SMatthew G. Knepley 23969566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 2397b8feb594SMatthew G. Knepley for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c * Nf + f]; 2398338f77d5SMatthew G. Knepley } 23991c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 240073d901b8SMatthew G. Knepley if (mesh->printFEM) { 24019566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Integral:")); 24029566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), " %g", (double)PetscRealPart(integral[f]))); 24039566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "\n")); 240473d901b8SMatthew G. Knepley } 24059566063dSJacob Faibussowitsch PetscCall(PetscFree2(lintegral, cintegral)); 24069566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 24073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2408338f77d5SMatthew G. Knepley } 2409338f77d5SMatthew G. Knepley 2410338f77d5SMatthew G. Knepley /*@ 2411338f77d5SMatthew G. Knepley DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user 2412338f77d5SMatthew G. Knepley 2413338f77d5SMatthew G. Knepley Input Parameters: 2414338f77d5SMatthew G. Knepley + dm - The mesh 2415338f77d5SMatthew G. Knepley . X - Global input vector 2416338f77d5SMatthew G. Knepley - user - The user context 2417338f77d5SMatthew G. Knepley 2418338f77d5SMatthew G. Knepley Output Parameter: 241960225df5SJacob Faibussowitsch . F - Cellwise integrals for each field 2420338f77d5SMatthew G. Knepley 2421338f77d5SMatthew G. Knepley Level: developer 2422338f77d5SMatthew G. Knepley 24231cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2424338f77d5SMatthew G. Knepley @*/ 2425d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user) 2426d71ae5a4SJacob Faibussowitsch { 2427338f77d5SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2428338f77d5SMatthew G. Knepley DM dmF; 2429338f77d5SMatthew G. Knepley PetscSection sectionF; 2430338f77d5SMatthew G. Knepley PetscScalar *cintegral, *af; 2431412e9a14SMatthew G. Knepley PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 24326493148fSStefano Zampini Vec locX; 2433338f77d5SMatthew G. Knepley 2434338f77d5SMatthew G. Knepley PetscFunctionBegin; 2435338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2436338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2437338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(F, VEC_CLASSID, 3); 24389566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 24399566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 24409566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 24419566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2442338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 24439566063dSJacob Faibussowitsch PetscCall(PetscCalloc1((cEnd - cStart) * Nf, &cintegral)); 24446493148fSStefano Zampini /* Get local solution with boundary values */ 24456493148fSStefano Zampini PetscCall(DMGetLocalVector(dm, &locX)); 24466493148fSStefano Zampini PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 24476493148fSStefano Zampini PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 24486493148fSStefano Zampini PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 24496493148fSStefano Zampini PetscCall(DMPlexComputeIntegral_Internal(dm, locX, cStart, cEnd, cintegral, user)); 24506493148fSStefano Zampini PetscCall(DMRestoreLocalVector(dm, &locX)); 2451338f77d5SMatthew G. Knepley /* Put values in F */ 24529566063dSJacob Faibussowitsch PetscCall(VecGetDM(F, &dmF)); 24539566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmF, §ionF)); 24549566063dSJacob Faibussowitsch PetscCall(VecGetArray(F, &af)); 2455338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2456338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 2457338f77d5SMatthew G. Knepley PetscInt dof, off; 2458338f77d5SMatthew G. Knepley 24599566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 24609566063dSJacob Faibussowitsch PetscCall(PetscSectionGetDof(sectionF, cell, &dof)); 24619566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(sectionF, cell, &off)); 246263a3b9bcSJacob Faibussowitsch PetscCheck(dof == Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %" PetscInt_FMT " != %" PetscInt_FMT, dof, Nf); 2463338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) af[off + f] = cintegral[c * Nf + f]; 2464338f77d5SMatthew G. Knepley } 24659566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(F, &af)); 24669566063dSJacob Faibussowitsch PetscCall(PetscFree(cintegral)); 24679566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 24683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 246973d901b8SMatthew G. Knepley } 247073d901b8SMatthew G. Knepley 2471d71ae5a4SJacob 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) 2472d71ae5a4SJacob Faibussowitsch { 24739b6f715bSMatthew G. Knepley DM plex = NULL, plexA = NULL; 2474a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 24759b6f715bSMatthew G. Knepley PetscDS prob, probAux = NULL; 24769b6f715bSMatthew G. Knepley PetscSection section, sectionAux = NULL; 24779b6f715bSMatthew G. Knepley Vec locA = NULL; 24789b6f715bSMatthew G. Knepley DMField coordField; 24799b6f715bSMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x; 24809b6f715bSMatthew G. Knepley PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL; 24819b6f715bSMatthew G. Knepley PetscScalar *u, *a = NULL; 248264c72086SMatthew G. Knepley const PetscScalar *constants; 24839b6f715bSMatthew G. Knepley PetscInt numConstants, f; 248464c72086SMatthew G. Knepley 248564c72086SMatthew G. Knepley PetscFunctionBegin; 24869566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 24879566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 24889566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 24899566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 24909566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 249164c72086SMatthew G. Knepley /* Determine which discretizations we have */ 24929b6f715bSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 249364c72086SMatthew G. Knepley PetscObject obj; 249464c72086SMatthew G. Knepley PetscClassId id; 249564c72086SMatthew G. Knepley 24969566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 24979566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 249863a3b9bcSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not supported for FVM (field %" PetscInt_FMT ")", f); 249964c72086SMatthew G. Knepley } 250064c72086SMatthew G. Knepley /* Read DS information */ 25019566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 25029566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 25039566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 25049566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 250564c72086SMatthew G. Knepley /* Read Auxiliary DS information */ 25069566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 25079b6f715bSMatthew G. Knepley if (locA) { 25089b6f715bSMatthew G. Knepley DM dmAux; 25099b6f715bSMatthew G. Knepley 25109566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 25119566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 25129566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 25139566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 25149566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 25159566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 25169566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 25179566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 251864c72086SMatthew G. Knepley } 25199b6f715bSMatthew G. Knepley /* Integrate over points */ 25209b6f715bSMatthew G. Knepley { 25219b6f715bSMatthew G. Knepley PetscFEGeom *fgeom, *chunkGeom = NULL; 2522b7260050SToby Isaac PetscInt maxDegree; 25239b6f715bSMatthew G. Knepley PetscQuadrature qGeom = NULL; 25249b6f715bSMatthew G. Knepley const PetscInt *points; 25259b6f715bSMatthew G. Knepley PetscInt numFaces, face, Nq, field; 25269b6f715bSMatthew G. Knepley PetscInt numChunks, chunkSize, chunk, Nr, offset; 252764c72086SMatthew G. Knepley 25289566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 25299566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 25309566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFaces * totDim, &u, locA ? numFaces * totDimAux : 0, &a)); 25319566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 253264c72086SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 253364c72086SMatthew G. Knepley PetscFE fe; 253464c72086SMatthew G. Knepley 25359566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe)); 25369566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 25379b6f715bSMatthew G. Knepley if (!qGeom) { 25389566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 25399566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 25409b6f715bSMatthew G. Knepley } 25419566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 25429566063dSJacob Faibussowitsch PetscCall(DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 25439b6f715bSMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 2544f15274beSMatthew Knepley const PetscInt point = points[face], *support; 25459b6f715bSMatthew G. Knepley PetscScalar *x = NULL; 2546f15274beSMatthew Knepley PetscInt i; 25479b6f715bSMatthew G. Knepley 25489566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 25499566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 25509b6f715bSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 25519566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 25529b6f715bSMatthew G. Knepley if (locA) { 25539b6f715bSMatthew G. Knepley PetscInt subp; 25549566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 25559566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 25569b6f715bSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[f * totDimAux + i] = x[i]; 25579566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 25589b6f715bSMatthew G. Knepley } 25599b6f715bSMatthew G. Knepley } 25609b6f715bSMatthew G. Knepley /* Get blocking */ 25619b6f715bSMatthew G. Knepley { 25629b6f715bSMatthew G. Knepley PetscQuadrature q; 25639b6f715bSMatthew G. Knepley PetscInt numBatches, batchSize, numBlocks, blockSize; 25649b6f715bSMatthew G. Knepley PetscInt Nq, Nb; 25659b6f715bSMatthew G. Knepley 25669566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 25679566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 25689566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 25699566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 257064c72086SMatthew G. Knepley blockSize = Nb * Nq; 257164c72086SMatthew G. Knepley batchSize = numBlocks * blockSize; 25729b6f715bSMatthew G. Knepley chunkSize = numBatches * batchSize; 25739566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 25749b6f715bSMatthew G. Knepley numChunks = numFaces / chunkSize; 25759b6f715bSMatthew G. Knepley Nr = numFaces % chunkSize; 257664c72086SMatthew G. Knepley offset = numFaces - Nr; 257764c72086SMatthew G. Knepley } 25789b6f715bSMatthew G. Knepley /* Do integration for each field */ 25799b6f715bSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 25809566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, chunk * chunkSize, (chunk + 1) * chunkSize, &chunkGeom)); 25819566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral)); 25829566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 258364c72086SMatthew G. Knepley } 25849566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 2585*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset * totDim], probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), &fintegral[offset * Nf])); 25869566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 258764c72086SMatthew G. Knepley /* Cleanup data arrays */ 25889566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 25899566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 25909566063dSJacob Faibussowitsch PetscCall(PetscFree2(u, a)); 25919566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 259264c72086SMatthew G. Knepley } 259364c72086SMatthew G. Knepley } 25949566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 25959566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 25963ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 25979b6f715bSMatthew G. Knepley } 25989b6f715bSMatthew G. Knepley 259960225df5SJacob Faibussowitsch /*@C 26009b6f715bSMatthew G. Knepley DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user 26019b6f715bSMatthew G. Knepley 26029b6f715bSMatthew G. Knepley Input Parameters: 26039b6f715bSMatthew G. Knepley + dm - The mesh 26049b6f715bSMatthew G. Knepley . X - Global input vector 2605a1cb98faSBarry Smith . label - The boundary `DMLabel` 2606a1cb98faSBarry Smith . numVals - The number of label values to use, or `PETSC_DETERMINE` for all values 2607a1cb98faSBarry Smith . vals - The label values to use, or NULL for all values 260867b8a455SSatish Balay . func - The function to integrate along the boundary 26099b6f715bSMatthew G. Knepley - user - The user context 26109b6f715bSMatthew G. Knepley 26119b6f715bSMatthew G. Knepley Output Parameter: 26129b6f715bSMatthew G. Knepley . integral - Integral for each field 26139b6f715bSMatthew G. Knepley 26149b6f715bSMatthew G. Knepley Level: developer 26159b6f715bSMatthew G. Knepley 26161cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeIntegralFEM()`, `DMPlexComputeBdResidualFEM()` 26179b6f715bSMatthew G. Knepley @*/ 2618d71ae5a4SJacob 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) 2619d71ae5a4SJacob Faibussowitsch { 26209b6f715bSMatthew G. Knepley Vec locX; 26219b6f715bSMatthew G. Knepley PetscSection section; 26229b6f715bSMatthew G. Knepley DMLabel depthLabel; 26239b6f715bSMatthew G. Knepley IS facetIS; 26249b6f715bSMatthew G. Knepley PetscInt dim, Nf, f, v; 26259b6f715bSMatthew G. Knepley 26269b6f715bSMatthew G. Knepley PetscFunctionBegin; 26279b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 26289b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2629292bffcbSToby Isaac PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 26304f572ea9SToby Isaac if (vals) PetscAssertPointer(vals, 5); 26314f572ea9SToby Isaac PetscAssertPointer(integral, 7); 26329566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 26339566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 26349566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 26359566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 26369566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 26379566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 26389b6f715bSMatthew G. Knepley /* Get local solution with boundary values */ 26399566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &locX)); 26409566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 26419566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 26429566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 26439b6f715bSMatthew G. Knepley /* Loop over label values */ 26449566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(integral, Nf)); 26459b6f715bSMatthew G. Knepley for (v = 0; v < numVals; ++v) { 26469b6f715bSMatthew G. Knepley IS pointIS; 26479b6f715bSMatthew G. Knepley PetscInt numFaces, face; 26489b6f715bSMatthew G. Knepley PetscScalar *fintegral; 26499b6f715bSMatthew G. Knepley 26509566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, vals[v], &pointIS)); 26519b6f715bSMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 26529b6f715bSMatthew G. Knepley { 26539b6f715bSMatthew G. Knepley IS isectIS; 26549b6f715bSMatthew G. Knepley 26559b6f715bSMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 26569566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 26579566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 26589b6f715bSMatthew G. Knepley pointIS = isectIS; 26599b6f715bSMatthew G. Knepley } 26609566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 26619566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numFaces * Nf, &fintegral)); 26629566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user)); 26639b6f715bSMatthew G. Knepley /* Sum point contributions into integral */ 26649371c9d4SSatish Balay for (f = 0; f < Nf; ++f) 26659371c9d4SSatish Balay for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face * Nf + f]; 26669566063dSJacob Faibussowitsch PetscCall(PetscFree(fintegral)); 26679566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 26689b6f715bSMatthew G. Knepley } 26699566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &locX)); 26709566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 26719566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 26723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 267364c72086SMatthew G. Knepley } 267464c72086SMatthew G. Knepley 2675d69c5d34SMatthew G. Knepley /*@ 2676a1cb98faSBarry Smith DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse `DM` to a uniformly refined `DM`. 2677d69c5d34SMatthew G. Knepley 2678d69c5d34SMatthew G. Knepley Input Parameters: 2679cf51de39SMatthew G. Knepley + dmc - The coarse mesh 2680cf51de39SMatthew G. Knepley . dmf - The fine mesh 2681cf51de39SMatthew G. Knepley . isRefined - Flag indicating regular refinement, rather than the same topology 2682d69c5d34SMatthew G. Knepley - user - The user context 2683d69c5d34SMatthew G. Knepley 2684d69c5d34SMatthew G. Knepley Output Parameter: 2685934789fcSMatthew G. Knepley . In - The interpolation matrix 2686d69c5d34SMatthew G. Knepley 2687d69c5d34SMatthew G. Knepley Level: developer 2688d69c5d34SMatthew G. Knepley 26891cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()` 2690d69c5d34SMatthew G. Knepley @*/ 2691d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user) 2692d71ae5a4SJacob Faibussowitsch { 2693d69c5d34SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmc->data; 2694d69c5d34SMatthew G. Knepley const char *name = "Interpolator"; 2695d69c5d34SMatthew G. Knepley PetscFE *feRef; 269697c42addSMatthew G. Knepley PetscFV *fvRef; 2697d69c5d34SMatthew G. Knepley PetscSection fsection, fglobalSection; 2698d69c5d34SMatthew G. Knepley PetscSection csection, cglobalSection; 2699d69c5d34SMatthew G. Knepley PetscScalar *elemMat; 2700485ad865SMatthew G. Knepley PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c; 27012ea9c922SToby Isaac PetscInt cTotDim = 0, rTotDim = 0; 2702d69c5d34SMatthew G. Knepley 2703d69c5d34SMatthew G. Knepley PetscFunctionBegin; 27049566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 27059566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 27069566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 27079566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 27089566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 27099566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 27109566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 27119566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 27129566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &feRef, Nf, &fvRef)); 2713d69c5d34SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 27142ea9c922SToby Isaac PetscObject obj, objc; 27152ea9c922SToby Isaac PetscClassId id, idc; 27162ea9c922SToby Isaac PetscInt rNb = 0, Nc = 0, cNb = 0; 2717d69c5d34SMatthew G. Knepley 27189566063dSJacob Faibussowitsch PetscCall(DMGetField(dmf, f, NULL, &obj)); 27199566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 272097c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 272197c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 272297c42addSMatthew G. Knepley 2723cf51de39SMatthew G. Knepley if (isRefined) { 27249566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 2725cf51de39SMatthew G. Knepley } else { 27269566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fe)); 2727cf51de39SMatthew G. Knepley feRef[f] = fe; 2728cf51de39SMatthew G. Knepley } 27299566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &rNb)); 27309566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 273197c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 273297c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 273397c42addSMatthew G. Knepley PetscDualSpace Q; 273497c42addSMatthew G. Knepley 2735cf51de39SMatthew G. Knepley if (isRefined) { 27369566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 2737cf51de39SMatthew G. Knepley } else { 27389566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fv)); 2739cf51de39SMatthew G. Knepley fvRef[f] = fv; 2740cf51de39SMatthew G. Knepley } 27419566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 27429566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &rNb)); 27439566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 27449566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 274597c42addSMatthew G. Knepley } 27469566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, f, NULL, &objc)); 27479566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(objc, &idc)); 27482ea9c922SToby Isaac if (idc == PETSCFE_CLASSID) { 27492ea9c922SToby Isaac PetscFE fe = (PetscFE)objc; 27502ea9c922SToby Isaac 27519566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cNb)); 27522ea9c922SToby Isaac } else if (id == PETSCFV_CLASSID) { 27532ea9c922SToby Isaac PetscFV fv = (PetscFV)obj; 27542ea9c922SToby Isaac PetscDualSpace Q; 27552ea9c922SToby Isaac 27569566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 27579566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &cNb)); 2758d69c5d34SMatthew G. Knepley } 27592ea9c922SToby Isaac rTotDim += rNb; 27602ea9c922SToby Isaac cTotDim += cNb; 27612ea9c922SToby Isaac } 27629566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(rTotDim * cTotDim, &elemMat)); 27639566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, rTotDim * cTotDim)); 2764d69c5d34SMatthew G. Knepley for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 2765d69c5d34SMatthew G. Knepley PetscDualSpace Qref; 2766d69c5d34SMatthew G. Knepley PetscQuadrature f; 2767d69c5d34SMatthew G. Knepley const PetscReal *qpoints, *qweights; 2768d69c5d34SMatthew G. Knepley PetscReal *points; 2769d69c5d34SMatthew G. Knepley PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 2770d69c5d34SMatthew G. Knepley 2771d69c5d34SMatthew G. Knepley /* Compose points from all dual basis functionals */ 277297c42addSMatthew G. Knepley if (feRef[fieldI]) { 27739566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[fieldI], &Qref)); 27749566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[fieldI], &Nc)); 277597c42addSMatthew G. Knepley } else { 27769566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[fieldI], &Qref)); 27779566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[fieldI], &Nc)); 277897c42addSMatthew G. Knepley } 27799566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Qref, &fpdim)); 2780d69c5d34SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 27819566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 27829566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL)); 2783d69c5d34SMatthew G. Knepley npoints += Np; 2784d69c5d34SMatthew G. Knepley } 27859566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints * dim, &points)); 2786d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 27879566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 27889566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL)); 27899371c9d4SSatish Balay for (p = 0; p < Np; ++p, ++k) 27909371c9d4SSatish Balay for (d = 0; d < dim; ++d) points[k * dim + d] = qpoints[p * dim + d]; 2791d69c5d34SMatthew G. Knepley } 2792d69c5d34SMatthew G. Knepley 2793d69c5d34SMatthew G. Knepley for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 279497c42addSMatthew G. Knepley PetscObject obj; 279597c42addSMatthew G. Knepley PetscClassId id; 27969c3cf19fSMatthew G. Knepley PetscInt NcJ = 0, cpdim = 0, j, qNc; 2797d69c5d34SMatthew G. Knepley 27989566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, fieldJ, NULL, &obj)); 27999566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 280097c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 280197c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2802ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 2803d69c5d34SMatthew G. Knepley 2804d69c5d34SMatthew G. Knepley /* Evaluate basis at points */ 28059566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &NcJ)); 28069566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 2807ffe73a53SMatthew G. Knepley /* For now, fields only interpolate themselves */ 2808ffe73a53SMatthew G. Knepley if (fieldI == fieldJ) { 280963a3b9bcSJacob 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); 28109566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation(fe, 1, npoints, points, 0, &T)); 2811d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 28129566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 28139566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 281463a3b9bcSJacob 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); 2815d69c5d34SMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 281636a6d9c0SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2817d172c84bSMatthew G. Knepley /* 2818d172c84bSMatthew G. Knepley cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field 2819d172c84bSMatthew G. Knepley offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields 2820d172c84bSMatthew G. Knepley fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals 2821d172c84bSMatthew G. Knepley qNC, Nc, Ncj, c: Number of components in this field 2822d172c84bSMatthew G. Knepley Np, p: Number of quad points in the fine grid functional i 2823d172c84bSMatthew G. Knepley k: i*Np + p, overall point number for the interpolation 2824d172c84bSMatthew G. Knepley */ 2825ef0bb6c7SMatthew 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]; 282636a6d9c0SMatthew G. Knepley } 2827d69c5d34SMatthew G. Knepley } 2828d69c5d34SMatthew G. Knepley } 28299566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 2830ffe73a53SMatthew G. Knepley } 283197c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 283297c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 283397c42addSMatthew G. Knepley 283497c42addSMatthew G. Knepley /* Evaluate constant function at points */ 28359566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcJ)); 283697c42addSMatthew G. Knepley cpdim = 1; 283797c42addSMatthew G. Knepley /* For now, fields only interpolate themselves */ 283897c42addSMatthew G. Knepley if (fieldI == fieldJ) { 283963a3b9bcSJacob 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); 284097c42addSMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 28419566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 28429566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 284363a3b9bcSJacob 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); 284497c42addSMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 284597c42addSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2846458eb97cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += 1.0 * qweights[p * qNc + c]; 284797c42addSMatthew G. Knepley } 284897c42addSMatthew G. Knepley } 284997c42addSMatthew G. Knepley } 285097c42addSMatthew G. Knepley } 285197c42addSMatthew G. Knepley } 2852d172c84bSMatthew G. Knepley offsetJ += cpdim; 2853d69c5d34SMatthew G. Knepley } 2854d172c84bSMatthew G. Knepley offsetI += fpdim; 28559566063dSJacob Faibussowitsch PetscCall(PetscFree(points)); 2856d69c5d34SMatthew G. Knepley } 28579566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat)); 28587f5b169aSMatthew G. Knepley /* Preallocate matrix */ 28597f5b169aSMatthew G. Knepley { 2860c094ef40SMatthew G. Knepley Mat preallocator; 2861c094ef40SMatthew G. Knepley PetscScalar *vals; 2862c094ef40SMatthew G. Knepley PetscInt *cellCIndices, *cellFIndices; 2863c094ef40SMatthew G. Knepley PetscInt locRows, locCols, cell; 28647f5b169aSMatthew G. Knepley 28659566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 28669566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &preallocator)); 28679566063dSJacob Faibussowitsch PetscCall(MatSetType(preallocator, MATPREALLOCATOR)); 28689566063dSJacob Faibussowitsch PetscCall(MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 28699566063dSJacob Faibussowitsch PetscCall(MatSetUp(preallocator)); 28709566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(rTotDim * cTotDim, &vals, cTotDim, &cellCIndices, rTotDim, &cellFIndices)); 28717f5b169aSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2872cf51de39SMatthew G. Knepley if (isRefined) { 28739566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices)); 28749566063dSJacob Faibussowitsch PetscCall(MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES)); 2875cf51de39SMatthew G. Knepley } else { 2876e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, preallocator, cell, vals, INSERT_VALUES)); 2877cf51de39SMatthew G. Knepley } 28787f5b169aSMatthew G. Knepley } 28799566063dSJacob Faibussowitsch PetscCall(PetscFree3(vals, cellCIndices, cellFIndices)); 28809566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY)); 28819566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY)); 28829566063dSJacob Faibussowitsch PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In)); 28839566063dSJacob Faibussowitsch PetscCall(MatDestroy(&preallocator)); 28847f5b169aSMatthew G. Knepley } 28857f5b169aSMatthew G. Knepley /* Fill matrix */ 28869566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(In)); 2887d69c5d34SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 2888cf51de39SMatthew G. Knepley if (isRefined) { 28899566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES)); 2890cf51de39SMatthew G. Knepley } else { 2891e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, In, c, elemMat, INSERT_VALUES)); 2892cf51de39SMatthew G. Knepley } 2893d69c5d34SMatthew G. Knepley } 28949566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&feRef[f])); 28959566063dSJacob Faibussowitsch PetscCall(PetscFree2(feRef, fvRef)); 28969566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 28979566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 28989566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 28999318fe57SMatthew G. Knepley if (mesh->printFEM > 1) { 29009566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name)); 29012ce66baaSPierre Jolivet PetscCall(MatFilter(In, 1.0e-10, PETSC_FALSE, PETSC_FALSE)); 29029566063dSJacob Faibussowitsch PetscCall(MatView(In, NULL)); 2903d69c5d34SMatthew G. Knepley } 29049566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 29053ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2906d69c5d34SMatthew G. Knepley } 29076c73c22cSMatthew G. Knepley 2908d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user) 2909d71ae5a4SJacob Faibussowitsch { 2910bd041c0cSMatthew G. Knepley SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "Laziness"); 2911bd041c0cSMatthew G. Knepley } 2912bd041c0cSMatthew G. Knepley 291368132eb9SMatthew G. Knepley /*@ 2914a1cb98faSBarry Smith DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse `DM` to a non-nested fine `DM`. 291568132eb9SMatthew G. Knepley 291668132eb9SMatthew G. Knepley Input Parameters: 291768132eb9SMatthew G. Knepley + dmf - The fine mesh 291868132eb9SMatthew G. Knepley . dmc - The coarse mesh 291968132eb9SMatthew G. Knepley - user - The user context 292068132eb9SMatthew G. Knepley 292168132eb9SMatthew G. Knepley Output Parameter: 292268132eb9SMatthew G. Knepley . In - The interpolation matrix 292368132eb9SMatthew G. Knepley 292468132eb9SMatthew G. Knepley Level: developer 292568132eb9SMatthew G. Knepley 29261cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()` 292768132eb9SMatthew G. Knepley @*/ 2928d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user) 2929d71ae5a4SJacob Faibussowitsch { 293064e98e1dSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 293164e98e1dSMatthew G. Knepley const char *name = "Interpolator"; 29324ef9d792SMatthew G. Knepley PetscDS prob; 2933a0806964SMatthew G. Knepley Mat interp; 2934a0806964SMatthew G. Knepley PetscSection fsection, globalFSection; 2935a0806964SMatthew G. Knepley PetscSection csection, globalCSection; 2936a0806964SMatthew G. Knepley PetscInt locRows, locCols; 29374ef9d792SMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 29384ef9d792SMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 29394ef9d792SMatthew G. Knepley PetscScalar *elemMat; 2940a0806964SMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell, s; 29414ef9d792SMatthew G. Knepley 29424ef9d792SMatthew G. Knepley PetscFunctionBegin; 29439566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 29449566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 29459566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 29469566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 29479566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 29489566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 29499566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 29509566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 29519566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 29529566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 29539566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 2954a0806964SMatthew G. Knepley PetscCall(DMPlexGetSimplexOrBoxCells(dmf, 0, &cStart, &cEnd)); 29559566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 29569566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 29574ef9d792SMatthew G. Knepley 2958a0806964SMatthew G. Knepley PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 2959a0806964SMatthew G. Knepley PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &interp)); 2960a0806964SMatthew G. Knepley PetscCall(MatSetType(interp, MATPREALLOCATOR)); 2961a0806964SMatthew G. Knepley PetscCall(MatSetSizes(interp, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 2962a0806964SMatthew G. Knepley PetscCall(MatSetUp(interp)); 2963a0806964SMatthew G. Knepley for (s = 0; s < 2; ++s) { 29644ef9d792SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 29654ef9d792SMatthew G. Knepley PetscObject obj; 29664ef9d792SMatthew G. Knepley PetscClassId id; 2967c0d7054bSMatthew G. Knepley PetscDualSpace Q = NULL; 2968ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 29694ef9d792SMatthew G. Knepley PetscQuadrature f; 29704ef9d792SMatthew G. Knepley const PetscReal *qpoints, *qweights; 2971d0f6233fSMatthew G. Knepley PetscInt Nc, qNc, Np, fpdim, off, i, d; 29724ef9d792SMatthew G. Knepley 2973d0f6233fSMatthew G. Knepley PetscCall(PetscDSGetFieldOffset(prob, field, &off)); 29749566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 29759566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 29764ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 29774ef9d792SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 29784ef9d792SMatthew G. Knepley 29799566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(fe, &Q)); 29809566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 2981a0806964SMatthew G. Knepley if (s) PetscCall(PetscFECreateTabulation(fe, 1, 1, x, 0, &T)); 29824ef9d792SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 29834ef9d792SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 29844ef9d792SMatthew G. Knepley 29859566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 29864ef9d792SMatthew G. Knepley Nc = 1; 298763a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 29889566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fpdim)); 29894ef9d792SMatthew G. Knepley /* For each fine grid cell */ 29904ef9d792SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 29914ef9d792SMatthew G. Knepley PetscInt *findices, *cindices; 29924ef9d792SMatthew G. Knepley PetscInt numFIndices, numCIndices; 29934ef9d792SMatthew G. Knepley 29949566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 29959566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 2996d0f6233fSMatthew 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); 29974ef9d792SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 29984ef9d792SMatthew G. Knepley Vec pointVec; 29994ef9d792SMatthew G. Knepley PetscScalar *pV; 300012111d7cSToby Isaac PetscSF coarseCellSF = NULL; 30013a93e3b7SToby Isaac const PetscSFNode *coarseCells; 3002d0f6233fSMatthew G. Knepley PetscInt numCoarseCells, cpdim, row = findices[i + off], q, c, j; 30034ef9d792SMatthew G. Knepley 30044ef9d792SMatthew G. Knepley /* Get points from the dual basis functional quadrature */ 30059566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Q, i, &f)); 30069566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights)); 300763a3b9bcSJacob 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); 30089566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np * dim, &pointVec)); 30099566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 30109566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 30114ef9d792SMatthew G. Knepley for (q = 0; q < Np; ++q) { 3012c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3013c330f8ffSToby Isaac 30144ef9d792SMatthew G. Knepley /* Transform point to real space */ 3015c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 30164ef9d792SMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 30174ef9d792SMatthew G. Knepley } 30189566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 30194ef9d792SMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 30201555c271SMatthew G. Knepley /* OPT: Read this out from preallocation information */ 30219566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 30224ef9d792SMatthew G. Knepley /* Update preallocation info */ 30239566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 30245f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Np, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 30259566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 30264ef9d792SMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3027826eb36dSMatthew G. Knepley PetscReal pVReal[3]; 3028c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3029826eb36dSMatthew G. Knepley 30309566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3031a0806964SMatthew G. Knepley if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetDimension((PetscFE)obj, &cpdim)); 3032a0806964SMatthew G. Knepley else cpdim = 1; 3033a0806964SMatthew G. Knepley 3034a0806964SMatthew G. Knepley if (s) { 30354ef9d792SMatthew G. Knepley /* Transform points from real space to coarse reference space */ 30369566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3037e2d86523SMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 3038c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 30394ef9d792SMatthew G. Knepley 30404ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 30414ef9d792SMatthew G. Knepley /* Evaluate coarse basis on contained point */ 3042a0806964SMatthew G. Knepley PetscCall(PetscFEComputeTabulation((PetscFE)obj, 1, x, 0, T)); 30439566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 30444ef9d792SMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 30454ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3046ef0bb6c7SMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * qweights[ccell * qNc + c]; 30474ef9d792SMatthew G. Knepley } 30484ef9d792SMatthew G. Knepley } else { 30494ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 30509c3cf19fSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * qweights[ccell * qNc + c]; 30514ef9d792SMatthew G. Knepley } 30524ef9d792SMatthew G. Knepley } 30539566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 3054a0806964SMatthew G. Knepley } 3055a0806964SMatthew G. Knepley /* Update interpolator */ 3056d0f6233fSMatthew G. Knepley PetscCheck(numCIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, totDim); 3057a0806964SMatthew G. Knepley PetscCall(MatSetValues(interp, 1, &row, cpdim, &cindices[off], elemMat, INSERT_VALUES)); 30589566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 30594ef9d792SMatthew G. Knepley } 30609566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 30619566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 30629566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 30634ef9d792SMatthew G. Knepley } 30649566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 30654ef9d792SMatthew G. Knepley } 3066a0806964SMatthew G. Knepley if (s && id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3067a0806964SMatthew G. Knepley } 3068a0806964SMatthew G. Knepley if (!s) { 3069a0806964SMatthew G. Knepley PetscCall(MatAssemblyBegin(interp, MAT_FINAL_ASSEMBLY)); 3070a0806964SMatthew G. Knepley PetscCall(MatAssemblyEnd(interp, MAT_FINAL_ASSEMBLY)); 3071a0806964SMatthew G. Knepley PetscCall(MatPreallocatorPreallocate(interp, PETSC_TRUE, In)); 3072a0806964SMatthew G. Knepley PetscCall(MatDestroy(&interp)); 3073a0806964SMatthew G. Knepley interp = In; 3074a0806964SMatthew G. Knepley } 30754ef9d792SMatthew G. Knepley } 30769566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 30779566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 30789566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 30799566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 30809566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 30819566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 30823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 30834ef9d792SMatthew G. Knepley } 30844ef9d792SMatthew G. Knepley 308546fa42a0SMatthew G. Knepley /*@ 3086a1cb98faSBarry Smith DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse `DM` to a non-nested fine `DM`. 3087bd041c0cSMatthew G. Knepley 3088bd041c0cSMatthew G. Knepley Input Parameters: 3089bd041c0cSMatthew G. Knepley + dmf - The fine mesh 3090bd041c0cSMatthew G. Knepley . dmc - The coarse mesh 3091bd041c0cSMatthew G. Knepley - user - The user context 3092bd041c0cSMatthew G. Knepley 3093bd041c0cSMatthew G. Knepley Output Parameter: 3094bd041c0cSMatthew G. Knepley . mass - The mass matrix 3095bd041c0cSMatthew G. Knepley 3096bd041c0cSMatthew G. Knepley Level: developer 3097bd041c0cSMatthew G. Knepley 30981cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeMassMatrixNested()`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()` 3099bd041c0cSMatthew G. Knepley @*/ 3100d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user) 3101d71ae5a4SJacob Faibussowitsch { 3102bd041c0cSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 3103bd041c0cSMatthew G. Knepley const char *name = "Mass Matrix"; 3104bd041c0cSMatthew G. Knepley PetscDS prob; 3105bd041c0cSMatthew G. Knepley PetscSection fsection, csection, globalFSection, globalCSection; 3106e8f14785SLisandro Dalcin PetscHSetIJ ht; 3107bd041c0cSMatthew G. Knepley PetscLayout rLayout; 3108bd041c0cSMatthew G. Knepley PetscInt *dnz, *onz; 3109bd041c0cSMatthew G. Knepley PetscInt locRows, rStart, rEnd; 3110bd041c0cSMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 3111bd041c0cSMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 3112bd041c0cSMatthew G. Knepley PetscScalar *elemMat; 3113bd041c0cSMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 3114bd041c0cSMatthew G. Knepley 3115bd041c0cSMatthew G. Knepley PetscFunctionBegin; 31169566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 31179566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 31189566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 31199566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 31209566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 31219566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 31229566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 31239566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 31249566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 31259566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 31269566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 31279566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 31289566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 3129bd041c0cSMatthew G. Knepley 31309566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mass, &locRows, NULL)); 31319566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)mass), &rLayout)); 31329566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 31339566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 31349566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(rLayout)); 31359566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd)); 31369566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&rLayout)); 31379566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz)); 31389566063dSJacob Faibussowitsch PetscCall(PetscHSetIJCreate(&ht)); 3139bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3140bd041c0cSMatthew G. Knepley PetscObject obj; 3141bd041c0cSMatthew G. Knepley PetscClassId id; 3142bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3143bd041c0cSMatthew G. Knepley const PetscReal *qpoints; 3144bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3145bd041c0cSMatthew G. Knepley 31469566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 31479566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 31489566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 31499566063dSJacob Faibussowitsch else PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 31509566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL)); 3151bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3152bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3153bd041c0cSMatthew G. Knepley Vec pointVec; 3154bd041c0cSMatthew G. Knepley PetscScalar *pV; 3155bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3156bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3157bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, q, c; 3158bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3159bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3160bd041c0cSMatthew G. Knepley 31619566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 31629566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3163bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 31649566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 31659566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 31669566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3167bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3168c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3169c330f8ffSToby Isaac 3170bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3171c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3172bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3173bd041c0cSMatthew G. Knepley } 31749566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3175bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 31769566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 31779566063dSJacob Faibussowitsch PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view")); 3178bd041c0cSMatthew G. Knepley /* Update preallocation info */ 31799566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 31805f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 3181bd041c0cSMatthew G. Knepley { 3182e8f14785SLisandro Dalcin PetscHashIJKey key; 3183e8f14785SLisandro Dalcin PetscBool missing; 3184bd041c0cSMatthew G. Knepley 3185bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 3186e8f14785SLisandro Dalcin key.i = findices[i]; 3187e8f14785SLisandro Dalcin if (key.i >= 0) { 3188bd041c0cSMatthew G. Knepley /* Get indices for coarse elements */ 3189bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 31909566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3191bd041c0cSMatthew G. Knepley for (c = 0; c < numCIndices; ++c) { 3192e8f14785SLisandro Dalcin key.j = cindices[c]; 3193e8f14785SLisandro Dalcin if (key.j < 0) continue; 31949566063dSJacob Faibussowitsch PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 3195bd041c0cSMatthew G. Knepley if (missing) { 3196e8f14785SLisandro Dalcin if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i - rStart]; 3197e8f14785SLisandro Dalcin else ++onz[key.i - rStart]; 3198bd041c0cSMatthew G. Knepley } 3199bd041c0cSMatthew G. Knepley } 32009566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3201bd041c0cSMatthew G. Knepley } 3202bd041c0cSMatthew G. Knepley } 3203bd041c0cSMatthew G. Knepley } 3204bd041c0cSMatthew G. Knepley } 32059566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 32069566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 32079566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3208bd041c0cSMatthew G. Knepley } 3209bd041c0cSMatthew G. Knepley } 32109566063dSJacob Faibussowitsch PetscCall(PetscHSetIJDestroy(&ht)); 32119566063dSJacob Faibussowitsch PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 32129566063dSJacob Faibussowitsch PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 32139566063dSJacob Faibussowitsch PetscCall(PetscFree2(dnz, onz)); 3214bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3215bd041c0cSMatthew G. Knepley PetscObject obj; 3216bd041c0cSMatthew G. Knepley PetscClassId id; 3217ef0bb6c7SMatthew G. Knepley PetscTabulation T, Tfine; 3218bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3219bd041c0cSMatthew G. Knepley const PetscReal *qpoints, *qweights; 3220bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3221bd041c0cSMatthew G. Knepley 32229566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 32239566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 3224ef0bb6c7SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 32259566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 32269566063dSJacob Faibussowitsch PetscCall(PetscFEGetCellTabulation((PetscFE)obj, 1, &Tfine)); 32279566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, 1, x, 0, &T)); 3228ef0bb6c7SMatthew G. Knepley } else { 32299566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 3230ef0bb6c7SMatthew G. Knepley } 32319566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights)); 3232bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3233bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3234bd041c0cSMatthew G. Knepley Vec pointVec; 3235bd041c0cSMatthew G. Knepley PetscScalar *pV; 3236bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3237bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3238bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, cpdim, q, c, j; 3239bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3240bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3241bd041c0cSMatthew G. Knepley 32429566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 32439566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3244bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 32459566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 32469566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 32479566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3248bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3249c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3250c330f8ffSToby Isaac 3251bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3252c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3253bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3254bd041c0cSMatthew G. Knepley } 32559566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3256bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 32579566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 3258bd041c0cSMatthew G. Knepley /* Update matrix */ 32599566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 32605f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 32619566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3262bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3263bd041c0cSMatthew G. Knepley PetscReal pVReal[3]; 3264c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3265c330f8ffSToby Isaac 32669566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3267bd041c0cSMatthew G. Knepley /* Transform points from real space to coarse reference space */ 32689566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3269bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 3270c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 3271bd041c0cSMatthew G. Knepley 3272bd041c0cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 3273bd041c0cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 3274bd041c0cSMatthew G. Knepley 3275bd041c0cSMatthew G. Knepley /* Evaluate coarse basis on contained point */ 32769566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 32779566063dSJacob Faibussowitsch PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T)); 3278bd041c0cSMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 3279bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 32809566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3281bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3282ef0bb6c7SMatthew 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; 3283bd041c0cSMatthew G. Knepley } 3284bd041c0cSMatthew G. Knepley /* Update interpolator */ 32859566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 328663a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 32879566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3288bd041c0cSMatthew G. Knepley } 3289bd041c0cSMatthew G. Knepley } else { 3290bd041c0cSMatthew G. Knepley cpdim = 1; 3291bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 32929566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3293bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3294bd041c0cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * 1.0 * qweights[ccell * Nc + c] * detJ; 3295bd041c0cSMatthew G. Knepley } 3296bd041c0cSMatthew G. Knepley /* Update interpolator */ 32979566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 329863a3b9bcSJacob 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)); 329963a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 33009566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3301bd041c0cSMatthew G. Knepley } 3302bd041c0cSMatthew G. Knepley } 33039566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3304bd041c0cSMatthew G. Knepley } 33059566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 33069566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 33079566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 33089566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3309bd041c0cSMatthew G. Knepley } 33109566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3311bd041c0cSMatthew G. Knepley } 33129566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 33139566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 33149566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 33159566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 33169566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 33173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3318bd041c0cSMatthew G. Knepley } 3319bd041c0cSMatthew G. Knepley 3320bd041c0cSMatthew G. Knepley /*@ 332146fa42a0SMatthew G. Knepley DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns 332246fa42a0SMatthew G. Knepley 332346fa42a0SMatthew G. Knepley Input Parameters: 332446fa42a0SMatthew G. Knepley + dmc - The coarse mesh 332560225df5SJacob Faibussowitsch . dmf - The fine mesh 332646fa42a0SMatthew G. Knepley - user - The user context 332746fa42a0SMatthew G. Knepley 332846fa42a0SMatthew G. Knepley Output Parameter: 332946fa42a0SMatthew G. Knepley . sc - The mapping 333046fa42a0SMatthew G. Knepley 333146fa42a0SMatthew G. Knepley Level: developer 333246fa42a0SMatthew G. Knepley 33331cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()` 333446fa42a0SMatthew G. Knepley @*/ 3335d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 3336d71ae5a4SJacob Faibussowitsch { 3337e9d4ef1bSMatthew G. Knepley PetscDS prob; 33387c927364SMatthew G. Knepley PetscFE *feRef; 333997c42addSMatthew G. Knepley PetscFV *fvRef; 33407c927364SMatthew G. Knepley Vec fv, cv; 33417c927364SMatthew G. Knepley IS fis, cis; 33427c927364SMatthew G. Knepley PetscSection fsection, fglobalSection, csection, cglobalSection; 33437c927364SMatthew G. Knepley PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 3344485ad865SMatthew G. Knepley PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m; 33456f3d3cbcSMatthew G. Knepley PetscBool *needAvg; 33467c927364SMatthew G. Knepley 33477c927364SMatthew G. Knepley PetscFunctionBegin; 33489566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 33499566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 33509566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 33519566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 33529566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 33539566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 33549566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 33559566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 33569566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 33579566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nf, &feRef, Nf, &fvRef, Nf, &needAvg)); 33587c927364SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 335997c42addSMatthew G. Knepley PetscObject obj; 336097c42addSMatthew G. Knepley PetscClassId id; 3361aa7890ccSMatthew G. Knepley PetscInt fNb = 0, Nc = 0; 33627c927364SMatthew G. Knepley 33639566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 33649566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 336597c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 336697c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 33676f3d3cbcSMatthew G. Knepley PetscSpace sp; 33689b2fc754SMatthew G. Knepley PetscInt maxDegree; 336997c42addSMatthew G. Knepley 33709566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 33719566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &fNb)); 33729566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 33739566063dSJacob Faibussowitsch PetscCall(PetscFEGetBasisSpace(fe, &sp)); 33749566063dSJacob Faibussowitsch PetscCall(PetscSpaceGetDegree(sp, NULL, &maxDegree)); 33759b2fc754SMatthew G. Knepley if (!maxDegree) needAvg[f] = PETSC_TRUE; 337697c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 337797c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 337897c42addSMatthew G. Knepley PetscDualSpace Q; 337997c42addSMatthew G. Knepley 33809566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 33819566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 33829566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fNb)); 33839566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 33846f3d3cbcSMatthew G. Knepley needAvg[f] = PETSC_TRUE; 338597c42addSMatthew G. Knepley } 3386d172c84bSMatthew G. Knepley fTotDim += fNb; 33877c927364SMatthew G. Knepley } 33889566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &cTotDim)); 33899566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(cTotDim, &cmap)); 33907c927364SMatthew G. Knepley for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 33917c927364SMatthew G. Knepley PetscFE feC; 339297c42addSMatthew G. Knepley PetscFV fvC; 33937c927364SMatthew G. Knepley PetscDualSpace QF, QC; 3394d172c84bSMatthew G. Knepley PetscInt order = -1, NcF, NcC, fpdim, cpdim; 33957c927364SMatthew G. Knepley 339697c42addSMatthew G. Knepley if (feRef[field]) { 33979566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&feC)); 33989566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feC, &NcC)); 33999566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[field], &NcF)); 34009566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[field], &QF)); 34019566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetOrder(QF, &order)); 34029566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 34039566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feC, &QC)); 34049566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 340597c42addSMatthew G. Knepley } else { 34069566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fvC)); 34079566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvC, &NcC)); 34089566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[field], &NcF)); 34099566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[field], &QF)); 34109566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 34119566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvC, &QC)); 34129566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 341397c42addSMatthew G. Knepley } 341463a3b9bcSJacob 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); 34157c927364SMatthew G. Knepley for (c = 0; c < cpdim; ++c) { 34167c927364SMatthew G. Knepley PetscQuadrature cfunc; 3417d172c84bSMatthew G. Knepley const PetscReal *cqpoints, *cqweights; 3418d172c84bSMatthew G. Knepley PetscInt NqcC, NpC; 341997c42addSMatthew G. Knepley PetscBool found = PETSC_FALSE; 34207c927364SMatthew G. Knepley 34219566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QC, c, &cfunc)); 34229566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights)); 342363a3b9bcSJacob 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); 34241dca8a05SBarry Smith PetscCheck(NpC == 1 || !feRef[field], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 34257c927364SMatthew G. Knepley for (f = 0; f < fpdim; ++f) { 34267c927364SMatthew G. Knepley PetscQuadrature ffunc; 3427d172c84bSMatthew G. Knepley const PetscReal *fqpoints, *fqweights; 34287c927364SMatthew G. Knepley PetscReal sum = 0.0; 3429d172c84bSMatthew G. Knepley PetscInt NqcF, NpF; 34307c927364SMatthew G. Knepley 34319566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QF, f, &ffunc)); 34329566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights)); 343363a3b9bcSJacob 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); 34347c927364SMatthew G. Knepley if (NpC != NpF) continue; 34357c927364SMatthew G. Knepley for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 34367c927364SMatthew G. Knepley if (sum > 1.0e-9) continue; 3437d172c84bSMatthew G. Knepley for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d] * fqweights[d]); 3438d172c84bSMatthew G. Knepley if (sum < 1.0e-9) continue; 3439d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + f; 344097c42addSMatthew G. Knepley found = PETSC_TRUE; 34417c927364SMatthew G. Knepley break; 34427c927364SMatthew G. Knepley } 344397c42addSMatthew G. Knepley if (!found) { 344497c42addSMatthew G. Knepley /* TODO We really want the average here, but some asshole put VecScatter in the interface */ 3445d172c84bSMatthew G. Knepley if (fvRef[field] || (feRef[field] && order == 0)) { 3446d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + 0; 344797c42addSMatthew G. Knepley } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection"); 344897c42addSMatthew G. Knepley } 34497c927364SMatthew G. Knepley } 3450d172c84bSMatthew G. Knepley offsetC += cpdim; 3451d172c84bSMatthew G. Knepley offsetF += fpdim; 34527c927364SMatthew G. Knepley } 34539371c9d4SSatish Balay for (f = 0; f < Nf; ++f) { 34549371c9d4SSatish Balay PetscCall(PetscFEDestroy(&feRef[f])); 34559371c9d4SSatish Balay PetscCall(PetscFVDestroy(&fvRef[f])); 34569371c9d4SSatish Balay } 34579566063dSJacob Faibussowitsch PetscCall(PetscFree3(feRef, fvRef, needAvg)); 34587c927364SMatthew G. Knepley 34599566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmf, &fv)); 34609566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmc, &cv)); 34619566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(cv, &startC, &endC)); 34629566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(cglobalSection, &m)); 34639566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(cTotDim, &cellCIndices, fTotDim, &cellFIndices)); 34649566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &cindices)); 34659566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &findices)); 34667c927364SMatthew G. Knepley for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 34677c927364SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 34689566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices)); 34697c927364SMatthew G. Knepley for (d = 0; d < cTotDim; ++d) { 34700bd915a7SMatthew G. Knepley if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue; 3471d2457c26SMatthew 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]]); 34727c927364SMatthew G. Knepley cindices[cellCIndices[d] - startC] = cellCIndices[d]; 34737c927364SMatthew G. Knepley findices[cellCIndices[d] - startC] = cellFIndices[cmap[d]]; 34747c927364SMatthew G. Knepley } 34757c927364SMatthew G. Knepley } 34769566063dSJacob Faibussowitsch PetscCall(PetscFree(cmap)); 34779566063dSJacob Faibussowitsch PetscCall(PetscFree2(cellCIndices, cellFIndices)); 34787c927364SMatthew G. Knepley 34799566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis)); 34809566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis)); 34819566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(cv, cis, fv, fis, sc)); 34829566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cis)); 34839566063dSJacob Faibussowitsch PetscCall(ISDestroy(&fis)); 34849566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmf, &fv)); 34859566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmc, &cv)); 34869566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 34873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3488cb1e1211SMatthew G Knepley } 3489a1cf66bbSMatthew G. Knepley 34902f856554SMatthew G. Knepley /*@C 34912f856554SMatthew G. Knepley DMPlexGetCellFields - Retrieve the field values values for a chunk of cells 34922f856554SMatthew G. Knepley 34932f856554SMatthew G. Knepley Input Parameters: 3494a1cb98faSBarry Smith + dm - The `DM` 34952f856554SMatthew G. Knepley . cellIS - The cells to include 34962f856554SMatthew G. Knepley . locX - A local vector with the solution fields 34972f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 34982f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 34992f856554SMatthew G. Knepley 35002f856554SMatthew G. Knepley Output Parameters: 35012f856554SMatthew G. Knepley + u - The field coefficients 35022f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 35032f856554SMatthew G. Knepley - a - The auxiliary field coefficients 35042f856554SMatthew G. Knepley 35052f856554SMatthew G. Knepley Level: developer 35062f856554SMatthew G. Knepley 35071cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 35082f856554SMatthew G. Knepley @*/ 3509d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3510d71ae5a4SJacob Faibussowitsch { 35112f856554SMatthew G. Knepley DM plex, plexA = NULL; 3512a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 35132f856554SMatthew G. Knepley PetscSection section, sectionAux; 35142f856554SMatthew G. Knepley PetscDS prob; 35152f856554SMatthew G. Knepley const PetscInt *cells; 35162f856554SMatthew G. Knepley PetscInt cStart, cEnd, numCells, totDim, totDimAux, c; 35172f856554SMatthew G. Knepley 35182f856554SMatthew G. Knepley PetscFunctionBegin; 35192f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3520064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 3521ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); 3522ad540459SPierre Jolivet if (locA) PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); 35234f572ea9SToby Isaac PetscAssertPointer(u, 6); 35244f572ea9SToby Isaac PetscAssertPointer(u_t, 7); 35254f572ea9SToby Isaac PetscAssertPointer(a, 8); 35269566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 35279566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 35289566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 352907218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 35309566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 35312f856554SMatthew G. Knepley if (locA) { 35322f856554SMatthew G. Knepley DM dmAux; 35332f856554SMatthew G. Knepley PetscDS probAux; 35342f856554SMatthew G. Knepley 35359566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 35369566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 35379566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 35389566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 35399566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 35409566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 35412f856554SMatthew G. Knepley } 35422f856554SMatthew G. Knepley numCells = cEnd - cStart; 35439566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 35449371c9d4SSatish Balay if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 3545ad540459SPierre Jolivet else *u_t = NULL; 35469371c9d4SSatish Balay if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 3547ad540459SPierre Jolivet else *a = NULL; 35482f856554SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 35492f856554SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 35502f856554SMatthew G. Knepley const PetscInt cind = c - cStart; 35512f856554SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a; 35522f856554SMatthew G. Knepley PetscInt i; 35532f856554SMatthew G. Knepley 35549566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x)); 35552f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul[cind * totDim + i] = x[i]; 35569566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x)); 35572f856554SMatthew G. Knepley if (locX_t) { 35589566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t)); 35592f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul_t[cind * totDim + i] = x_t[i]; 35609566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t)); 35612f856554SMatthew G. Knepley } 35622f856554SMatthew G. Knepley if (locA) { 35632f856554SMatthew G. Knepley PetscInt subcell; 35649566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 35659566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 35662f856554SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) al[cind * totDimAux + i] = x[i]; 35679566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 35682f856554SMatthew G. Knepley } 35692f856554SMatthew G. Knepley } 35709566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 35719566063dSJacob Faibussowitsch if (locA) PetscCall(DMDestroy(&plexA)); 35729566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 35733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 35742f856554SMatthew G. Knepley } 35752f856554SMatthew G. Knepley 35762f856554SMatthew G. Knepley /*@C 35772f856554SMatthew G. Knepley DMPlexRestoreCellFields - Restore the field values values for a chunk of cells 35782f856554SMatthew G. Knepley 35792f856554SMatthew G. Knepley Input Parameters: 3580a1cb98faSBarry Smith + dm - The `DM` 35812f856554SMatthew G. Knepley . cellIS - The cells to include 35822f856554SMatthew G. Knepley . locX - A local vector with the solution fields 35832f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 35842f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 35852f856554SMatthew G. Knepley 35862f856554SMatthew G. Knepley Output Parameters: 35872f856554SMatthew G. Knepley + u - The field coefficients 35882f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 35892f856554SMatthew G. Knepley - a - The auxiliary field coefficients 35902f856554SMatthew G. Knepley 35912f856554SMatthew G. Knepley Level: developer 35922f856554SMatthew G. Knepley 35931cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 35942f856554SMatthew G. Knepley @*/ 3595d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3596d71ae5a4SJacob Faibussowitsch { 35972f856554SMatthew G. Knepley PetscFunctionBegin; 35989566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u)); 35999566063dSJacob Faibussowitsch if (locX_t) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t)); 36009566063dSJacob Faibussowitsch if (locA) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a)); 36013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 36022f856554SMatthew G. Knepley } 36032f856554SMatthew G. Knepley 3604a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexGetHybridCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3605d71ae5a4SJacob Faibussowitsch { 360607218a29SMatthew G. Knepley DM plex, plexA = NULL; 360707218a29SMatthew G. Knepley DMEnclosureType encAux; 360807218a29SMatthew G. Knepley PetscSection section, sectionAux; 360907218a29SMatthew G. Knepley PetscDS ds, dsIn; 36106528b96dSMatthew G. Knepley const PetscInt *cells; 361107218a29SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, totDim, totDimAux, Nf, f; 36126528b96dSMatthew G. Knepley 36136528b96dSMatthew G. Knepley PetscFunctionBegin; 361407218a29SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 361507218a29SMatthew G. Knepley PetscValidHeaderSpecific(cellIS, IS_CLASSID, 2); 361607218a29SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 361707218a29SMatthew G. Knepley if (locX_t) { PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); } 361807218a29SMatthew G. Knepley if (locA) { PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); } 36194f572ea9SToby Isaac PetscAssertPointer(u, 6); 36204f572ea9SToby Isaac PetscAssertPointer(u_t, 7); 36214f572ea9SToby Isaac PetscAssertPointer(a, 8); 362207218a29SMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 362307218a29SMatthew G. Knepley numCells = cEnd - cStart; 362407218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 362507218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dm, §ion)); 362607218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 362707218a29SMatthew G. Knepley PetscCall(PetscDSGetNumFields(dsIn, &Nf)); 362807218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDim)); 362907218a29SMatthew G. Knepley if (locA) { 363007218a29SMatthew G. Knepley DM dmAux; 363107218a29SMatthew G. Knepley PetscDS probAux; 363207218a29SMatthew G. Knepley 363307218a29SMatthew G. Knepley PetscCall(VecGetDM(locA, &dmAux)); 363407218a29SMatthew G. Knepley PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 363507218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 363607218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dmAux, §ionAux)); 363707218a29SMatthew G. Knepley PetscCall(DMGetDS(dmAux, &probAux)); 363807218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 363907218a29SMatthew G. Knepley } 364007218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 364107218a29SMatthew G. Knepley if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 364207218a29SMatthew G. Knepley else { 364307218a29SMatthew G. Knepley *u_t = NULL; 364407218a29SMatthew G. Knepley } 364507218a29SMatthew G. Knepley if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 364607218a29SMatthew G. Knepley else { 364707218a29SMatthew G. Knepley *a = NULL; 364807218a29SMatthew G. Knepley } 364907218a29SMatthew G. Knepley // Loop over cohesive cells 365007218a29SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 365107218a29SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 365207218a29SMatthew G. Knepley const PetscInt cind = c - cStart; 365374a0c561SMatthew G. Knepley PetscScalar *xf = NULL, *xc = NULL, *x = NULL, *xf_t = NULL, *xc_t = NULL; 3654*8e3a54c0SPierre Jolivet PetscScalar *ul = &(*u)[cind * totDim], *ul_t = PetscSafePointerPlusOffset(*u_t, cind * totDim); 365507218a29SMatthew G. Knepley const PetscInt *cone, *ornt; 365607218a29SMatthew G. Knepley PetscInt Nx = 0, Nxf, s; 365707218a29SMatthew G. Knepley 365807218a29SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cell, &cone)); 365907218a29SMatthew G. Knepley PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 366007218a29SMatthew G. Knepley // Put in cohesive unknowns 366107218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, &Nxf, &xf)); 366274a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &xf_t)); 366307218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 366407218a29SMatthew G. Knepley PetscInt fdofIn, foff, foffIn; 366507218a29SMatthew G. Knepley PetscBool cohesive; 366607218a29SMatthew G. Knepley 366707218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 366807218a29SMatthew G. Knepley if (!cohesive) continue; 366907218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn)); 367007218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(ds, f, &foff)); 367107218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn)); 367207218a29SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + i] = xf[foff + i]; 367374a0c561SMatthew G. Knepley if (locX_t) 367474a0c561SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + i] = xf_t[foff + i]; 367507218a29SMatthew G. Knepley Nx += fdofIn; 367607218a29SMatthew G. Knepley } 367707218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, &Nxf, &xf)); 367874a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &xf_t)); 367907218a29SMatthew G. Knepley // Loop over sides of surface 368007218a29SMatthew G. Knepley for (s = 0; s < 2; ++s) { 368107218a29SMatthew G. Knepley const PetscInt *support; 368207218a29SMatthew G. Knepley const PetscInt face = cone[s]; 368307218a29SMatthew G. Knepley PetscInt ssize, ncell, Nxc; 368407218a29SMatthew G. Knepley 368507218a29SMatthew G. Knepley // I don't think I need the face to have 0 orientation in the hybrid cell 368607218a29SMatthew 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]); 368707218a29SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, face, &support)); 368807218a29SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, face, &ssize)); 368907218a29SMatthew G. Knepley if (support[0] == cell) ncell = support[1]; 369007218a29SMatthew G. Knepley else if (support[1] == cell) ncell = support[0]; 369107218a29SMatthew 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); 369207218a29SMatthew G. Knepley // Get closure of both face and cell, stick in cell for normal fields and face for cohesive fields 369307218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, ncell, &Nxc, &xc)); 369474a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, ncell, NULL, &xc_t)); 369507218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 369607218a29SMatthew G. Knepley PetscInt fdofIn, foffIn; 369707218a29SMatthew G. Knepley PetscBool cohesive; 369807218a29SMatthew G. Knepley 369907218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 370007218a29SMatthew G. Knepley if (cohesive) continue; 370107218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn)); 370207218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn)); 370307218a29SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + s * fdofIn + i] = xc[foffIn + i]; 370474a0c561SMatthew G. Knepley if (locX_t) 370574a0c561SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + s * fdofIn + i] = xc_t[foffIn + i]; 370607218a29SMatthew G. Knepley Nx += fdofIn; 370707218a29SMatthew G. Knepley } 370807218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, ncell, &Nxc, &xc)); 370974a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, ncell, NULL, &xc_t)); 371007218a29SMatthew G. Knepley } 371107218a29SMatthew 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); 371207218a29SMatthew G. Knepley 371307218a29SMatthew G. Knepley if (locA) { 371407218a29SMatthew G. Knepley PetscScalar *al = &(*a)[cind * totDimAux]; 371507218a29SMatthew G. Knepley PetscInt subcell; 371607218a29SMatthew G. Knepley 371707218a29SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 371807218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, &Nx, &x)); 371907218a29SMatthew 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); 372007218a29SMatthew G. Knepley for (PetscInt i = 0; i < totDimAux; ++i) al[i] = x[i]; 372107218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, &Nx, &x)); 372207218a29SMatthew G. Knepley } 372307218a29SMatthew G. Knepley } 372407218a29SMatthew G. Knepley PetscCall(DMDestroy(&plex)); 372507218a29SMatthew G. Knepley PetscCall(DMDestroy(&plexA)); 372607218a29SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 372707218a29SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 372807218a29SMatthew G. Knepley } 372907218a29SMatthew G. Knepley 373007218a29SMatthew G. Knepley /* 37313e2b0218SMatthew G. Knepley DMPlexGetHybridFields - Get the field values for the negative side (s = 0) and positive side (s = 1) of the interface 373207218a29SMatthew G. Knepley 373307218a29SMatthew G. Knepley Input Parameters: 373407218a29SMatthew G. Knepley + dm - The full domain DM 373507218a29SMatthew G. Knepley . dmX - An array of DM for the field, say an auxiliary DM, indexed by s 373607218a29SMatthew G. Knepley . dsX - An array of PetscDS for the field, indexed by s 373707218a29SMatthew G. Knepley . cellIS - The interface cells for which we want values 373807218a29SMatthew G. Knepley . locX - An array of local vectors with the field values, indexed by s 373907218a29SMatthew G. Knepley - useCell - Flag to have values come from neighboring cell rather than endcap face 374007218a29SMatthew G. Knepley 374107218a29SMatthew G. Knepley Output Parameter: 374207218a29SMatthew G. Knepley . x - An array of field values, indexed by s 374307218a29SMatthew G. Knepley 374407218a29SMatthew G. Knepley Note: 374576fbde31SPierre Jolivet The arrays in `x` will be allocated using `DMGetWorkArray()`, and must be returned using `DMPlexRestoreHybridFields()`. 374607218a29SMatthew G. Knepley 374707218a29SMatthew G. Knepley Level: advanced 374807218a29SMatthew G. Knepley 374976fbde31SPierre Jolivet .seealso: `DMPlexRestoreHybridFields()`, `DMGetWorkArray()` 375007218a29SMatthew G. Knepley */ 375107218a29SMatthew G. Knepley static PetscErrorCode DMPlexGetHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[]) 375207218a29SMatthew G. Knepley { 375307218a29SMatthew G. Knepley DM plexX[2]; 375407218a29SMatthew G. Knepley DMEnclosureType encX[2]; 375507218a29SMatthew G. Knepley PetscSection sectionX[2]; 375607218a29SMatthew G. Knepley const PetscInt *cells; 375707218a29SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, s, totDimX[2]; 375807218a29SMatthew G. Knepley 375907218a29SMatthew G. Knepley PetscFunctionBegin; 37604f572ea9SToby Isaac PetscAssertPointer(locX, 5); 376107218a29SMatthew G. Knepley if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS); 37624f572ea9SToby Isaac PetscAssertPointer(dmX, 2); 37634f572ea9SToby Isaac PetscAssertPointer(dsX, 3); 376407218a29SMatthew G. Knepley PetscValidHeaderSpecific(cellIS, IS_CLASSID, 4); 37654f572ea9SToby Isaac PetscAssertPointer(x, 7); 37669566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 37676528b96dSMatthew G. Knepley numCells = cEnd - cStart; 3768148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 376907218a29SMatthew G. Knepley PetscValidHeaderSpecific(dmX[s], DM_CLASSID, 2); 377007218a29SMatthew G. Knepley PetscValidHeaderSpecific(dsX[s], PETSCDS_CLASSID, 3); 377107218a29SMatthew G. Knepley PetscValidHeaderSpecific(locX[s], VEC_CLASSID, 5); 377207218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dmX[s], &plexX[s], PETSC_FALSE)); 377307218a29SMatthew G. Knepley PetscCall(DMGetEnclosureRelation(dmX[s], dm, &encX[s])); 377407218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dmX[s], §ionX[s])); 377507218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsX[s], &totDimX[s])); 377607218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dmX[s], numCells * totDimX[s], MPIU_SCALAR, &x[s])); 377704c51a94SMatthew G. Knepley } 3778148442b3SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 37796528b96dSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 37806528b96dSMatthew G. Knepley const PetscInt cind = c - cStart; 37816528b96dSMatthew G. Knepley const PetscInt *cone, *ornt; 37826528b96dSMatthew G. Knepley 37839566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 37849566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 378507218a29SMatthew 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]); 3786148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 378707218a29SMatthew G. Knepley const PetscInt tdX = totDimX[s]; 378807218a29SMatthew G. Knepley PetscScalar *closure = NULL, *xl = &x[s][cind * tdX]; 378907218a29SMatthew G. Knepley PetscInt face = cone[s], point = face, subpoint, Nx, i; 379007218a29SMatthew G. Knepley 379107218a29SMatthew G. Knepley if (useCell) { 37925fedec97SMatthew G. Knepley const PetscInt *support; 379307218a29SMatthew G. Knepley PetscInt ssize; 37946528b96dSMatthew G. Knepley 379507218a29SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, face, &support)); 379607218a29SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, face, &ssize)); 379707218a29SMatthew 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); 379807218a29SMatthew G. Knepley if (support[0] == cell) point = support[1]; 379907218a29SMatthew G. Knepley else if (support[1] == cell) point = support[0]; 380007218a29SMatthew 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); 380107218a29SMatthew G. Knepley } 380207218a29SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexX[s], dm, encX[s], point, &subpoint)); 3803e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(plexX[s], sectionX[s], PETSC_FALSE, locX[s], subpoint, ornt[s], &Nx, &closure)); 380407218a29SMatthew 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); 380507218a29SMatthew G. Knepley for (i = 0; i < Nx; ++i) xl[i] = closure[i]; 380607218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexX[s], sectionX[s], locX[s], subpoint, &Nx, &closure)); 38076528b96dSMatthew G. Knepley } 38086528b96dSMatthew G. Knepley } 380907218a29SMatthew G. Knepley for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexX[s])); 38109566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 38113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 38126528b96dSMatthew G. Knepley } 38136528b96dSMatthew G. Knepley 381407218a29SMatthew G. Knepley static PetscErrorCode DMPlexRestoreHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[]) 3815d71ae5a4SJacob Faibussowitsch { 38166528b96dSMatthew G. Knepley PetscFunctionBegin; 381707218a29SMatthew G. Knepley if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS); 381807218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dmX[0], 0, MPIU_SCALAR, &x[0])); 381907218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dmX[1], 0, MPIU_SCALAR, &x[1])); 38203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 38216528b96dSMatthew G. Knepley } 38226528b96dSMatthew G. Knepley 38232f856554SMatthew G. Knepley /*@C 38242f856554SMatthew G. Knepley DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 38252f856554SMatthew G. Knepley 38262f856554SMatthew G. Knepley Input Parameters: 3827a1cb98faSBarry Smith + dm - The `DM` 38282f856554SMatthew G. Knepley . fStart - The first face to include 38292f856554SMatthew G. Knepley . fEnd - The first face to exclude 38302f856554SMatthew G. Knepley . locX - A local vector with the solution fields 38312f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 38322f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 38332f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 383460225df5SJacob Faibussowitsch - locGrad - A local vector with field gradients, or NULL 38352f856554SMatthew G. Knepley 38362f856554SMatthew G. Knepley Output Parameters: 38372f856554SMatthew G. Knepley + Nface - The number of faces with field values 38382f856554SMatthew G. Knepley . uL - The field values at the left side of the face 38392f856554SMatthew G. Knepley - uR - The field values at the right side of the face 38402f856554SMatthew G. Knepley 38412f856554SMatthew G. Knepley Level: developer 38422f856554SMatthew G. Knepley 38431cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 38442f856554SMatthew G. Knepley @*/ 3845d71ae5a4SJacob 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) 3846d71ae5a4SJacob Faibussowitsch { 38472f856554SMatthew G. Knepley DM dmFace, dmCell, dmGrad = NULL; 38482f856554SMatthew G. Knepley PetscSection section; 38492f856554SMatthew G. Knepley PetscDS prob; 38502f856554SMatthew G. Knepley DMLabel ghostLabel; 38512f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 38522f856554SMatthew G. Knepley PetscBool *isFE; 38532f856554SMatthew G. Knepley PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 38542f856554SMatthew G. Knepley 38552f856554SMatthew G. Knepley PetscFunctionBegin; 38562f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 38572f856554SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3858ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5); 38592f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 38602f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 3861ad540459SPierre Jolivet if (locGrad) PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8); 38624f572ea9SToby Isaac PetscAssertPointer(uL, 10); 38634f572ea9SToby Isaac PetscAssertPointer(uR, 11); 38649566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 38659566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 38669566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 38679566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 38689566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(prob, &Nc)); 38699566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nf, &isFE)); 38702f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 38712f856554SMatthew G. Knepley PetscObject obj; 38722f856554SMatthew G. Knepley PetscClassId id; 38732f856554SMatthew G. Knepley 38749566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 38759566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 38769371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 38779371c9d4SSatish Balay isFE[f] = PETSC_TRUE; 38789371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 38799371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 38809371c9d4SSatish Balay } else { 38819371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 38829371c9d4SSatish Balay } 38832f856554SMatthew G. Knepley } 38849566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 38859566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locX, &x)); 38869566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 38879566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 38889566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 38899566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 38902f856554SMatthew G. Knepley if (locGrad) { 38919566063dSJacob Faibussowitsch PetscCall(VecGetDM(locGrad, &dmGrad)); 38929566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 38932f856554SMatthew G. Knepley } 38949566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uL)); 38959566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uR)); 38962f856554SMatthew G. Knepley /* Right now just eat the extra work for FE (could make a cell loop) */ 38972f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 38982f856554SMatthew G. Knepley const PetscInt *cells; 38992f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 39002f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 39012f856554SMatthew G. Knepley PetscScalar *xL, *xR, *gL, *gR; 39022f856554SMatthew G. Knepley PetscScalar *uLl = *uL, *uRl = *uR; 39032f856554SMatthew G. Knepley PetscInt ghost, nsupp, nchild; 39042f856554SMatthew G. Knepley 39059566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 39069566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 39079566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 39082f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 39099566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 39109566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 39119566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 39129566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 39132f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 39142f856554SMatthew G. Knepley PetscInt off; 39152f856554SMatthew G. Knepley 39169566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffset(prob, f, &off)); 39172f856554SMatthew G. Knepley if (isFE[f]) { 39182f856554SMatthew G. Knepley const PetscInt *cone; 39192f856554SMatthew G. Knepley PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 39202f856554SMatthew G. Knepley 39212f856554SMatthew G. Knepley xL = xR = NULL; 39229566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 39239566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL)); 39249566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR)); 39259566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[0], &cone)); 39269566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL)); 39279371c9d4SSatish Balay for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) 39289371c9d4SSatish Balay if (cone[faceLocL] == face) break; 39299566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[1], &cone)); 39309566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR)); 39319371c9d4SSatish Balay for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) 39329371c9d4SSatish Balay if (cone[faceLocR] == face) break; 39331dca8a05SBarry 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]); 39342f856554SMatthew G. Knepley /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 39352f856554SMatthew G. Knepley /* TODO: this is a hack that might not be right for nonconforming */ 39362f856554SMatthew G. Knepley if (faceLocL < coneSizeL) { 39379566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface * Nc + off])); 39389566063dSJacob Faibussowitsch if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 39392f856554SMatthew G. Knepley else { 39409371c9d4SSatish Balay for (d = 0; d < comp; ++d) uRl[iface * Nc + off + d] = uLl[iface * Nc + off + d]; 39419371c9d4SSatish Balay } 39429371c9d4SSatish Balay } else { 39439566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 39449566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 39452f856554SMatthew G. Knepley for (d = 0; d < comp; ++d) uLl[iface * Nc + off + d] = uRl[iface * Nc + off + d]; 39462f856554SMatthew G. Knepley } 39479566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL)); 39489566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR)); 39492f856554SMatthew G. Knepley } else { 39502f856554SMatthew G. Knepley PetscFV fv; 39512f856554SMatthew G. Knepley PetscInt numComp, c; 39522f856554SMatthew G. Knepley 39539566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *)&fv)); 39549566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &numComp)); 39559566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL)); 39569566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR)); 39572f856554SMatthew G. Knepley if (dmGrad) { 39582f856554SMatthew G. Knepley PetscReal dxL[3], dxR[3]; 39592f856554SMatthew G. Knepley 39609566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL)); 39619566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR)); 39622f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 39632f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 39642f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 39652f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c * dim], dxL); 39662f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c * dim], dxR); 39672f856554SMatthew G. Knepley } 39682f856554SMatthew G. Knepley } else { 39692f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 39702f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c]; 39712f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c]; 39722f856554SMatthew G. Knepley } 39732f856554SMatthew G. Knepley } 39742f856554SMatthew G. Knepley } 39752f856554SMatthew G. Knepley } 39762f856554SMatthew G. Knepley ++iface; 39772f856554SMatthew G. Knepley } 39782f856554SMatthew G. Knepley *Nface = iface; 39799566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locX, &x)); 39809566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 39819566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 398248a46eb9SPierre Jolivet if (locGrad) PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 39839566063dSJacob Faibussowitsch PetscCall(PetscFree(isFE)); 39843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 39852f856554SMatthew G. Knepley } 39862f856554SMatthew G. Knepley 39872f856554SMatthew G. Knepley /*@C 39882f856554SMatthew G. Knepley DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 39892f856554SMatthew G. Knepley 39902f856554SMatthew G. Knepley Input Parameters: 3991a1cb98faSBarry Smith + dm - The `DM` 39922f856554SMatthew G. Knepley . fStart - The first face to include 39932f856554SMatthew G. Knepley . fEnd - The first face to exclude 39942f856554SMatthew G. Knepley . locX - A local vector with the solution fields 39952f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 39962f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 39972f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 399860225df5SJacob Faibussowitsch - locGrad - A local vector with field gradients, or NULL 39992f856554SMatthew G. Knepley 40002f856554SMatthew G. Knepley Output Parameters: 40012f856554SMatthew G. Knepley + Nface - The number of faces with field values 40022f856554SMatthew G. Knepley . uL - The field values at the left side of the face 40032f856554SMatthew G. Knepley - uR - The field values at the right side of the face 40042f856554SMatthew G. Knepley 40052f856554SMatthew G. Knepley Level: developer 40062f856554SMatthew G. Knepley 40071cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 40082f856554SMatthew G. Knepley @*/ 4009d71ae5a4SJacob 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) 4010d71ae5a4SJacob Faibussowitsch { 40112f856554SMatthew G. Knepley PetscFunctionBegin; 40129566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL)); 40139566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR)); 40143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 40152f856554SMatthew G. Knepley } 40162f856554SMatthew G. Knepley 40172f856554SMatthew G. Knepley /*@C 40182f856554SMatthew G. Knepley DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 40192f856554SMatthew G. Knepley 40202f856554SMatthew G. Knepley Input Parameters: 4021a1cb98faSBarry Smith + dm - The `DM` 40222f856554SMatthew G. Knepley . fStart - The first face to include 40232f856554SMatthew G. Knepley . fEnd - The first face to exclude 40242f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 40252f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 40262f856554SMatthew G. Knepley 40272f856554SMatthew G. Knepley Output Parameters: 40282f856554SMatthew G. Knepley + Nface - The number of faces with field values 40292f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 40302f856554SMatthew G. Knepley - vol - The cell volume 40312f856554SMatthew G. Knepley 40322f856554SMatthew G. Knepley Level: developer 40332f856554SMatthew G. Knepley 40341cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 40352f856554SMatthew G. Knepley @*/ 4036d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 4037d71ae5a4SJacob Faibussowitsch { 40382f856554SMatthew G. Knepley DM dmFace, dmCell; 40392f856554SMatthew G. Knepley DMLabel ghostLabel; 40402f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom; 40412f856554SMatthew G. Knepley PetscInt dim, numFaces = fEnd - fStart, iface, face; 40422f856554SMatthew G. Knepley 40432f856554SMatthew G. Knepley PetscFunctionBegin; 40442f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 40452f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 40462f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 40474f572ea9SToby Isaac PetscAssertPointer(fgeom, 7); 40484f572ea9SToby Isaac PetscAssertPointer(vol, 8); 40499566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 40509566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 40519566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 40529566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 40539566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 40549566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 40559566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(numFaces, fgeom)); 40569566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * 2, MPIU_SCALAR, vol)); 40572f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 40582f856554SMatthew G. Knepley const PetscInt *cells; 40592f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 40602f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 40612f856554SMatthew G. Knepley PetscFVFaceGeom *fgeoml = *fgeom; 40622f856554SMatthew G. Knepley PetscReal *voll = *vol; 40632f856554SMatthew G. Knepley PetscInt ghost, d, nchild, nsupp; 40642f856554SMatthew G. Knepley 40659566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 40669566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 40679566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 40682f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 40699566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 40709566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 40719566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 40729566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 40732f856554SMatthew G. Knepley for (d = 0; d < dim; ++d) { 40742f856554SMatthew G. Knepley fgeoml[iface].centroid[d] = fg->centroid[d]; 40752f856554SMatthew G. Knepley fgeoml[iface].normal[d] = fg->normal[d]; 40762f856554SMatthew G. Knepley } 40772f856554SMatthew G. Knepley voll[iface * 2 + 0] = cgL->volume; 40782f856554SMatthew G. Knepley voll[iface * 2 + 1] = cgR->volume; 40792f856554SMatthew G. Knepley ++iface; 40802f856554SMatthew G. Knepley } 40812f856554SMatthew G. Knepley *Nface = iface; 40829566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 40839566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 40843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 40852f856554SMatthew G. Knepley } 40862f856554SMatthew G. Knepley 40872f856554SMatthew G. Knepley /*@C 40882f856554SMatthew G. Knepley DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 40892f856554SMatthew G. Knepley 40902f856554SMatthew G. Knepley Input Parameters: 4091a1cb98faSBarry Smith + dm - The `DM` 40922f856554SMatthew G. Knepley . fStart - The first face to include 40932f856554SMatthew G. Knepley . fEnd - The first face to exclude 40942f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 40952f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 40962f856554SMatthew G. Knepley 40972f856554SMatthew G. Knepley Output Parameters: 40982f856554SMatthew G. Knepley + Nface - The number of faces with field values 40992f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 41002f856554SMatthew G. Knepley - vol - The cell volume 41012f856554SMatthew G. Knepley 41022f856554SMatthew G. Knepley Level: developer 41032f856554SMatthew G. Knepley 41041cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 41052f856554SMatthew G. Knepley @*/ 4106d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 4107d71ae5a4SJacob Faibussowitsch { 41082f856554SMatthew G. Knepley PetscFunctionBegin; 41099566063dSJacob Faibussowitsch PetscCall(PetscFree(*fgeom)); 41109566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol)); 41113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 41122f856554SMatthew G. Knepley } 41132f856554SMatthew G. Knepley 4114d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 4115d71ae5a4SJacob Faibussowitsch { 4116a1cf66bbSMatthew G. Knepley char composeStr[33] = {0}; 4117a1cf66bbSMatthew G. Knepley PetscObjectId id; 4118a1cf66bbSMatthew G. Knepley PetscContainer container; 4119a1cf66bbSMatthew G. Knepley 4120a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 41219566063dSJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)quad, &id)); 412263a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id)); 41239566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container)); 4124a1cf66bbSMatthew G. Knepley if (container) { 41259566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(container, (void **)geom)); 4126a1cf66bbSMatthew G. Knepley } else { 41279566063dSJacob Faibussowitsch PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 41289566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 41299566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(container, (void *)*geom)); 41309566063dSJacob Faibussowitsch PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom)); 41319566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container)); 41329566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&container)); 4133a1cf66bbSMatthew G. Knepley } 41343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4135a1cf66bbSMatthew G. Knepley } 4136a1cf66bbSMatthew G. Knepley 4137d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 4138d71ae5a4SJacob Faibussowitsch { 4139a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 4140a1cf66bbSMatthew G. Knepley *geom = NULL; 41413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4142a1cf66bbSMatthew G. Knepley } 4143a1cf66bbSMatthew G. Knepley 4144d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 4145d71ae5a4SJacob Faibussowitsch { 414692d50984SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 414792d50984SMatthew G. Knepley const char *name = "Residual"; 414892d50984SMatthew G. Knepley DM dmAux = NULL; 414992d50984SMatthew G. Knepley DMLabel ghostLabel = NULL; 415092d50984SMatthew G. Knepley PetscDS prob = NULL; 415192d50984SMatthew G. Knepley PetscDS probAux = NULL; 415292d50984SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 415392d50984SMatthew G. Knepley PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 415492d50984SMatthew G. Knepley DMField coordField = NULL; 4155c0006e53SPatrick Farrell Vec locA; 4156c0006e53SPatrick Farrell PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 415792d50984SMatthew G. Knepley IS chunkIS; 415892d50984SMatthew G. Knepley const PetscInt *cells; 415992d50984SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 4160364207b6SKarl Rupp PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 416192d50984SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 416206ad1575SMatthew G. Knepley PetscFormKey key; 416392d50984SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 416492d50984SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 416592d50984SMatthew G. Knepley 416692d50984SMatthew G. Knepley PetscFunctionBegin; 41679566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 416892d50984SMatthew G. Knepley /* FEM+FVM */ 416992d50984SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 41709566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 41719566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 41729566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 41739566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 41749566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 417592d50984SMatthew G. Knepley if (locA) { 41769566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 41779566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 41789566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 417992d50984SMatthew G. Knepley } 418092d50984SMatthew G. Knepley /* 2: Get geometric data */ 418192d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 418292d50984SMatthew G. Knepley PetscObject obj; 418392d50984SMatthew G. Knepley PetscClassId id; 418492d50984SMatthew G. Knepley PetscBool fimp; 418592d50984SMatthew G. Knepley 41869566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 418792d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 41889566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 41899566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 4190ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 41915f80ce2aSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Use of FVM with PCPATCH not yet implemented"); 419292d50984SMatthew G. Knepley } 419392d50984SMatthew G. Knepley if (useFEM) { 41949566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 41959566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 419692d50984SMatthew G. Knepley if (maxDegree <= 1) { 41979566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 419848a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 419992d50984SMatthew G. Knepley } else { 42009566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 420192d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 420292d50984SMatthew G. Knepley PetscObject obj; 420392d50984SMatthew G. Knepley PetscClassId id; 420492d50984SMatthew G. Knepley PetscBool fimp; 420592d50984SMatthew G. Knepley 42069566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 420792d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 42089566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 42099566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 421092d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 421192d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 421292d50984SMatthew G. Knepley 42139566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 42149566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 42159566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 421692d50984SMatthew G. Knepley } 421792d50984SMatthew G. Knepley } 421892d50984SMatthew G. Knepley } 421992d50984SMatthew G. Knepley } 422092d50984SMatthew G. Knepley /* Loop over chunks */ 42219566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 42229566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 42239566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 422492d50984SMatthew G. Knepley numCells = cEnd - cStart; 422592d50984SMatthew G. Knepley numChunks = 1; 422692d50984SMatthew G. Knepley cellChunkSize = numCells / numChunks; 422792d50984SMatthew G. Knepley numChunks = PetscMin(1, numCells); 42286528b96dSMatthew G. Knepley key.label = NULL; 42296528b96dSMatthew G. Knepley key.value = 0; 423006ad1575SMatthew G. Knepley key.part = 0; 423192d50984SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 4232c0006e53SPatrick Farrell PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 4233c0006e53SPatrick Farrell PetscReal *vol = NULL; 4234c0006e53SPatrick Farrell PetscFVFaceGeom *fgeom = NULL; 423592d50984SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 4236c0006e53SPatrick Farrell PetscInt numFaces = 0; 423792d50984SMatthew G. Knepley 423892d50984SMatthew G. Knepley /* Extract field coefficients */ 423992d50984SMatthew G. Knepley if (useFEM) { 42409566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 42419566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 42429566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 42439566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 424492d50984SMatthew G. Knepley } 424592d50984SMatthew 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 */ 424692d50984SMatthew G. Knepley /* Loop over fields */ 424792d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 424892d50984SMatthew G. Knepley PetscObject obj; 424992d50984SMatthew G. Knepley PetscClassId id; 425092d50984SMatthew G. Knepley PetscBool fimp; 425192d50984SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 425292d50984SMatthew G. Knepley 42536528b96dSMatthew G. Knepley key.field = f; 42549566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 425592d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 42569566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 42579566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 425892d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 425992d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 426092d50984SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 426192d50984SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 426292d50984SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 426392d50984SMatthew G. Knepley PetscInt Nq, Nb; 426492d50984SMatthew G. Knepley 42659566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 42669566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 42679566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 426892d50984SMatthew G. Knepley blockSize = Nb; 426992d50984SMatthew G. Knepley batchSize = numBlocks * blockSize; 42709566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 427192d50984SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 427292d50984SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 427392d50984SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 427492d50984SMatthew G. Knepley offset = numCells - Nr; 427592d50984SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 427692d50984SMatthew 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) */ 42779566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 42789566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 42799566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 4280*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, &a[offset * totDimAux], t, &elemVec[offset * totDim])); 42819566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 428292d50984SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 428392d50984SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 428492d50984SMatthew G. Knepley 428592d50984SMatthew G. Knepley Ne = numFaces; 428692d50984SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 428792d50984SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 42889566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 428963a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 429092d50984SMatthew G. Knepley } 429192d50984SMatthew G. Knepley /* Loop over domain */ 429292d50984SMatthew G. Knepley if (useFEM) { 429392d50984SMatthew G. Knepley /* Add elemVec to locX */ 429492d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 429592d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 429692d50984SMatthew G. Knepley const PetscInt cind = c - cStart; 429792d50984SMatthew G. Knepley 42989566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 429992d50984SMatthew G. Knepley if (ghostLabel) { 430092d50984SMatthew G. Knepley PetscInt ghostVal; 430192d50984SMatthew G. Knepley 43029566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 430392d50984SMatthew G. Knepley if (ghostVal > 0) continue; 430492d50984SMatthew G. Knepley } 43059566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 430692d50984SMatthew G. Knepley } 430792d50984SMatthew G. Knepley } 430892d50984SMatthew G. Knepley /* Handle time derivative */ 430992d50984SMatthew G. Knepley if (locX_t) { 431092d50984SMatthew G. Knepley PetscScalar *x_t, *fa; 431192d50984SMatthew G. Knepley 43129566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 43139566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 431492d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 431592d50984SMatthew G. Knepley PetscFV fv; 431692d50984SMatthew G. Knepley PetscObject obj; 431792d50984SMatthew G. Knepley PetscClassId id; 431892d50984SMatthew G. Knepley PetscInt pdim, d; 431992d50984SMatthew G. Knepley 43209566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 43219566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 432292d50984SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 432392d50984SMatthew G. Knepley fv = (PetscFV)obj; 43249566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 432592d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 432692d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 432792d50984SMatthew G. Knepley PetscScalar *u_t, *r; 432892d50984SMatthew G. Knepley 432992d50984SMatthew G. Knepley if (ghostLabel) { 433092d50984SMatthew G. Knepley PetscInt ghostVal; 433192d50984SMatthew G. Knepley 43329566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 433392d50984SMatthew G. Knepley if (ghostVal > 0) continue; 433492d50984SMatthew G. Knepley } 43359566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 43369566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 433792d50984SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 433892d50984SMatthew G. Knepley } 433992d50984SMatthew G. Knepley } 43409566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 43419566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 434292d50984SMatthew G. Knepley } 434392d50984SMatthew G. Knepley if (useFEM) { 43449566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 43459566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 434692d50984SMatthew G. Knepley } 434792d50984SMatthew G. Knepley } 43489566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 43499566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 435092d50984SMatthew G. Knepley /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 435192d50984SMatthew G. Knepley if (useFEM) { 435292d50984SMatthew G. Knepley if (maxDegree <= 1) { 43539566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 43549566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 435592d50984SMatthew G. Knepley } else { 435692d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 43579566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 43589566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 435992d50984SMatthew G. Knepley } 43609566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 436192d50984SMatthew G. Knepley } 436292d50984SMatthew G. Knepley } 43639566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 43643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 436592d50984SMatthew G. Knepley } 436692d50984SMatthew G. Knepley 4367a1cf66bbSMatthew G. Knepley /* 4368a1cf66bbSMatthew 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 4369a1cf66bbSMatthew G. Knepley 4370a1cf66bbSMatthew G. Knepley X - The local solution vector 4371a5b23f4aSJose E. Roman X_t - The local solution time derivative vector, or NULL 4372a1cf66bbSMatthew G. Knepley */ 4373d71ae5a4SJacob 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) 4374d71ae5a4SJacob Faibussowitsch { 4375a1cf66bbSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 4376a1cf66bbSMatthew G. Knepley const char *name = "Jacobian", *nameP = "JacobianPre"; 4377a1cf66bbSMatthew G. Knepley DM dmAux = NULL; 4378a1cf66bbSMatthew G. Knepley PetscDS prob, probAux = NULL; 4379a1cf66bbSMatthew G. Knepley PetscSection sectionAux = NULL; 4380a1cf66bbSMatthew G. Knepley Vec A; 4381a1cf66bbSMatthew G. Knepley DMField coordField; 4382a1cf66bbSMatthew G. Knepley PetscFEGeom *cgeomFEM; 4383a1cf66bbSMatthew G. Knepley PetscQuadrature qGeom = NULL; 4384a1cf66bbSMatthew G. Knepley Mat J = Jac, JP = JacP; 4385a1cf66bbSMatthew G. Knepley PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 4386e432b41dSStefano Zampini PetscBool hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE; 4387a1cf66bbSMatthew G. Knepley const PetscInt *cells; 438806ad1575SMatthew G. Knepley PetscFormKey key; 43899b2fc754SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 4390a1cf66bbSMatthew G. Knepley 4391a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 43929566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 43939566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 43949566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 43959566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 43969566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A)); 43979a2a23afSMatthew G. Knepley if (A) { 43989566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 43999566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 44009566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 4401a1cf66bbSMatthew G. Knepley } 4402a1cf66bbSMatthew G. Knepley /* Get flags */ 44039566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 44049566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4405a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4406a1cf66bbSMatthew G. Knepley PetscObject disc; 4407a1cf66bbSMatthew G. Knepley PetscClassId id; 44089566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc)); 44099566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(disc, &id)); 44109371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 44119371c9d4SSatish Balay isFE[fieldI] = PETSC_TRUE; 44129371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 44139371c9d4SSatish Balay hasFV = PETSC_TRUE; 44149371c9d4SSatish Balay isFE[fieldI] = PETSC_FALSE; 44159371c9d4SSatish Balay } 4416a1cf66bbSMatthew G. Knepley } 44179566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 44189566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 44199566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 4420a1cf66bbSMatthew G. Knepley assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 4421a1cf66bbSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 44229566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */ 44239566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 44249566063dSJacob Faibussowitsch if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4425a1cf66bbSMatthew G. Knepley /* Compute batch sizes */ 4426a1cf66bbSMatthew G. Knepley if (isFE[0]) { 4427a1cf66bbSMatthew G. Knepley PetscFE fe; 4428a1cf66bbSMatthew G. Knepley PetscQuadrature q; 4429a1cf66bbSMatthew G. Knepley PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 4430a1cf66bbSMatthew G. Knepley 44319566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 44329566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 44339566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL)); 44349566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 44359566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4436a1cf66bbSMatthew G. Knepley blockSize = Nb * numQuadPoints; 4437a1cf66bbSMatthew G. Knepley batchSize = numBlocks * blockSize; 4438a1cf66bbSMatthew G. Knepley chunkSize = numBatches * batchSize; 4439a1cf66bbSMatthew G. Knepley numChunks = numCells / chunkSize + numCells % chunkSize; 44409566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4441a1cf66bbSMatthew G. Knepley } else { 4442a1cf66bbSMatthew G. Knepley chunkSize = numCells; 4443a1cf66bbSMatthew G. Knepley numChunks = 1; 4444a1cf66bbSMatthew G. Knepley } 4445a1cf66bbSMatthew G. Knepley /* Get work space */ 4446a1cf66bbSMatthew 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; 44479566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work)); 44489566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(work, wsz)); 4449a1cf66bbSMatthew G. Knepley off = 0; 4450a1cf66bbSMatthew G. Knepley u = X ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4451a1cf66bbSMatthew G. Knepley u_t = X_t ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4452a1cf66bbSMatthew G. Knepley a = dmAux ? (sz = chunkSize * totDimAux, off += sz, work + off - sz) : NULL; 4453a1cf66bbSMatthew G. Knepley elemMat = hasJac ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4454a1cf66bbSMatthew G. Knepley elemMatP = hasPrec ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4455a1cf66bbSMatthew G. Knepley elemMatD = hasDyn ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 445663a3b9bcSJacob Faibussowitsch PetscCheck(off == wsz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %" PetscInt_FMT " should be %" PetscInt_FMT, off, wsz); 4457a1cf66bbSMatthew G. Knepley /* Setup geometry */ 44589566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 44599566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 44609566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 4461a1cf66bbSMatthew G. Knepley if (!qGeom) { 4462a1cf66bbSMatthew G. Knepley PetscFE fe; 4463a1cf66bbSMatthew G. Knepley 44649566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 44659566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 44669566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 4467a1cf66bbSMatthew G. Knepley } 44689566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4469a1cf66bbSMatthew G. Knepley /* Compute volume integrals */ 44709566063dSJacob Faibussowitsch if (assembleJac) PetscCall(MatZeroEntries(J)); 44719566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(JP)); 44726528b96dSMatthew G. Knepley key.label = NULL; 44736528b96dSMatthew G. Knepley key.value = 0; 447406ad1575SMatthew G. Knepley key.part = 0; 4475a1cf66bbSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 4476a1cf66bbSMatthew G. Knepley const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 4477a1cf66bbSMatthew G. Knepley PetscInt c; 4478a1cf66bbSMatthew G. Knepley 4479a1cf66bbSMatthew G. Knepley /* Extract values */ 4480a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4481a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4482a1cf66bbSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 4483a1cf66bbSMatthew G. Knepley PetscInt i; 4484a1cf66bbSMatthew G. Knepley 4485a1cf66bbSMatthew G. Knepley if (X) { 44869566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 4487a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 44889566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 4489a1cf66bbSMatthew G. Knepley } 4490a1cf66bbSMatthew G. Knepley if (X_t) { 44919566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 4492a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[c * totDim + i] = x_t[i]; 44939566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 4494a1cf66bbSMatthew G. Knepley } 4495a1cf66bbSMatthew G. Knepley if (dmAux) { 44969566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4497a1cf66bbSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 44989566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4499a1cf66bbSMatthew G. Knepley } 4500a1cf66bbSMatthew G. Knepley } 4501a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4502a1cf66bbSMatthew G. Knepley PetscFE fe; 45039566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 4504a1cf66bbSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 45056528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 45069566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat)); 45079566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP)); 45089566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD)); 4509a1cf66bbSMatthew G. Knepley } 4510a1cf66bbSMatthew G. Knepley /* For finite volume, add the identity */ 4511a1cf66bbSMatthew G. Knepley if (!isFE[fieldI]) { 4512a1cf66bbSMatthew G. Knepley PetscFV fv; 4513a1cf66bbSMatthew G. Knepley PetscInt eOffset = 0, Nc, fc, foff; 4514a1cf66bbSMatthew G. Knepley 45159566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff)); 45169566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 45179566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 4518a1cf66bbSMatthew G. Knepley for (c = 0; c < chunkSize; ++c, eOffset += totDim * totDim) { 4519a1cf66bbSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 4520a1cf66bbSMatthew G. Knepley const PetscInt i = foff + fc; 4521ad540459SPierre Jolivet if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 4522ad540459SPierre Jolivet if (hasPrec) elemMatP[eOffset + i * totDim + i] = 1.0; 4523a1cf66bbSMatthew G. Knepley } 4524a1cf66bbSMatthew G. Knepley } 4525a1cf66bbSMatthew G. Knepley } 4526a1cf66bbSMatthew G. Knepley } 4527a1cf66bbSMatthew G. Knepley /* Add contribution from X_t */ 45289371c9d4SSatish Balay if (hasDyn) { 45299371c9d4SSatish Balay for (c = 0; c < chunkSize * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 45309371c9d4SSatish Balay } 4531a1cf66bbSMatthew G. Knepley /* Insert values into matrix */ 4532a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4533a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4534a1cf66bbSMatthew G. Knepley if (mesh->printFEM > 1) { 45359566063dSJacob Faibussowitsch if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c - cStart) * totDim * totDim])); 45369566063dSJacob Faibussowitsch if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c - cStart) * totDim * totDim])); 4537a1cf66bbSMatthew G. Knepley } 4538e8e188d2SZach Atkins if (assembleJac) PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4539e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JP, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4540a1cf66bbSMatthew G. Knepley } 4541a1cf66bbSMatthew G. Knepley } 4542a1cf66bbSMatthew G. Knepley /* Cleanup */ 45439566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 45449566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 45459566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 45469566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 45479566063dSJacob 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)); 4548a1cf66bbSMatthew G. Knepley /* Compute boundary integrals */ 45499566063dSJacob Faibussowitsch /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */ 4550a1cf66bbSMatthew G. Knepley /* Assemble matrix */ 45519371c9d4SSatish Balay if (assembleJac) { 45529371c9d4SSatish Balay PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 45539371c9d4SSatish Balay PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 45549371c9d4SSatish Balay } 45559371c9d4SSatish Balay PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 45569371c9d4SSatish Balay PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 45579566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 45583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4559a1cf66bbSMatthew G. Knepley } 45603e9753d6SMatthew G. Knepley 45613e9753d6SMatthew G. Knepley /******** FEM Assembly Function ********/ 45623e9753d6SMatthew G. Knepley 4563d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy) 4564d71ae5a4SJacob Faibussowitsch { 45653e9753d6SMatthew G. Knepley PetscBool isPlex; 45663e9753d6SMatthew G. Knepley 45673e9753d6SMatthew G. Knepley PetscFunctionBegin; 45689566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 45693e9753d6SMatthew G. Knepley if (isPlex) { 45703e9753d6SMatthew G. Knepley *plex = dm; 45719566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 45723e9753d6SMatthew G. Knepley } else { 45739566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 45743e9753d6SMatthew G. Knepley if (!*plex) { 45759566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 45769566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 45771baa6e33SBarry Smith if (copy) PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 45783e9753d6SMatthew G. Knepley } else { 45799566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)*plex)); 45803e9753d6SMatthew G. Knepley } 45813e9753d6SMatthew G. Knepley } 45823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 45833e9753d6SMatthew G. Knepley } 45843e9753d6SMatthew G. Knepley 45853e9753d6SMatthew G. Knepley /*@ 45863e9753d6SMatthew G. Knepley DMPlexGetGeometryFVM - Return precomputed geometric data 45873e9753d6SMatthew G. Knepley 458820f4b53cSBarry Smith Collective 45893e9753d6SMatthew G. Knepley 45903e9753d6SMatthew G. Knepley Input Parameter: 4591a1cb98faSBarry Smith . dm - The `DM` 45923e9753d6SMatthew G. Knepley 45933e9753d6SMatthew G. Knepley Output Parameters: 45943e9753d6SMatthew G. Knepley + facegeom - The values precomputed from face geometry 45953e9753d6SMatthew G. Knepley . cellgeom - The values precomputed from cell geometry 45963e9753d6SMatthew G. Knepley - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell 45973e9753d6SMatthew G. Knepley 45983e9753d6SMatthew G. Knepley Level: developer 45993e9753d6SMatthew G. Knepley 46001cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMTSSetRHSFunctionLocal()` 46013e9753d6SMatthew G. Knepley @*/ 4602d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius) 4603d71ae5a4SJacob Faibussowitsch { 46043e9753d6SMatthew G. Knepley DM plex; 46053e9753d6SMatthew G. Knepley 46063e9753d6SMatthew G. Knepley PetscFunctionBegin; 46073e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 46089566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 46099566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL)); 46109566063dSJacob Faibussowitsch if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius)); 46119566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 46123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 46133e9753d6SMatthew G. Knepley } 46143e9753d6SMatthew G. Knepley 46153e9753d6SMatthew G. Knepley /*@ 46163e9753d6SMatthew G. Knepley DMPlexGetGradientDM - Return gradient data layout 46173e9753d6SMatthew G. Knepley 461820f4b53cSBarry Smith Collective 46193e9753d6SMatthew G. Knepley 46203e9753d6SMatthew G. Knepley Input Parameters: 4621a1cb98faSBarry Smith + dm - The `DM` 462220f4b53cSBarry Smith - fv - The `PetscFV` 46233e9753d6SMatthew G. Knepley 46243e9753d6SMatthew G. Knepley Output Parameter: 46253e9753d6SMatthew G. Knepley . dmGrad - The layout for gradient values 46263e9753d6SMatthew G. Knepley 46273e9753d6SMatthew G. Knepley Level: developer 46283e9753d6SMatthew G. Knepley 46291cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetGeometryFVM()` 46303e9753d6SMatthew G. Knepley @*/ 4631d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad) 4632d71ae5a4SJacob Faibussowitsch { 46333e9753d6SMatthew G. Knepley DM plex; 46343e9753d6SMatthew G. Knepley PetscBool computeGradients; 46353e9753d6SMatthew G. Knepley 46363e9753d6SMatthew G. Knepley PetscFunctionBegin; 46373e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 46383e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 46394f572ea9SToby Isaac PetscAssertPointer(dmGrad, 3); 46409566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &computeGradients)); 46419371c9d4SSatish Balay if (!computeGradients) { 46429371c9d4SSatish Balay *dmGrad = NULL; 46433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 46449371c9d4SSatish Balay } 46459566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 46469566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad)); 46479566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 46483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 46493e9753d6SMatthew G. Knepley } 46503e9753d6SMatthew G. Knepley 4651d71ae5a4SJacob 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) 4652d71ae5a4SJacob Faibussowitsch { 46533e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 46543e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL; 46553e9753d6SMatthew G. Knepley DMEnclosureType encAux; 46563e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 46573e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 46583e9753d6SMatthew G. Knepley Vec locA = NULL; 46593e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL; 46603e9753d6SMatthew G. Knepley PetscInt totDim, totDimAux = 0; 46613e9753d6SMatthew G. Knepley 46623e9753d6SMatthew G. Knepley PetscFunctionBegin; 46639566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 46649566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 46659566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 46669566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 46679566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 46683e9753d6SMatthew G. Knepley if (locA) { 46693e9753d6SMatthew G. Knepley DM dmAux; 46703e9753d6SMatthew G. Knepley 46719566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 46729566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 46739566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 46749566063dSJacob Faibussowitsch PetscCall(DMGetDS(plexA, &probAux)); 46759566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 46769566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 46773e9753d6SMatthew G. Knepley } 46780c290148SMatthew G. Knepley { 46793e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 46803e9753d6SMatthew G. Knepley PetscInt maxDegree; 46813e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 46823e9753d6SMatthew G. Knepley IS pointIS; 46833e9753d6SMatthew G. Knepley const PetscInt *points; 46843e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 46853e9753d6SMatthew G. Knepley 46869566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 46870c290148SMatthew G. Knepley if (!pointIS) goto end; /* No points with that id on this process */ 46883e9753d6SMatthew G. Knepley { 46893e9753d6SMatthew G. Knepley IS isectIS; 46903e9753d6SMatthew G. Knepley 46913e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 46929566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 46939566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 46943e9753d6SMatthew G. Knepley pointIS = isectIS; 46953e9753d6SMatthew G. Knepley } 46969566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 46979566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 46989566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim, &elemVec, locA ? numFaces * totDimAux : 0, &a)); 46999566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 470048a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 47013e9753d6SMatthew G. Knepley if (!qGeom) { 47023e9753d6SMatthew G. Knepley PetscFE fe; 47033e9753d6SMatthew G. Knepley 47049566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 47059566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 47069566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 47073e9753d6SMatthew G. Knepley } 47089566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 47099566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 47103e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 4711f15274beSMatthew Knepley const PetscInt point = points[face], *support; 47123e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 4713f15274beSMatthew Knepley PetscInt i; 47143e9753d6SMatthew G. Knepley 47159566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 47169566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 47173e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 47189566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 47193e9753d6SMatthew G. Knepley if (locX_t) { 47209566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 47213e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 47229566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 47233e9753d6SMatthew G. Knepley } 47243e9753d6SMatthew G. Knepley if (locA) { 47253e9753d6SMatthew G. Knepley PetscInt subp; 47263e9753d6SMatthew G. Knepley 47279566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 47289566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 47293e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 47309566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 47313e9753d6SMatthew G. Knepley } 47323e9753d6SMatthew G. Knepley } 47339566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numFaces * totDim)); 47343e9753d6SMatthew G. Knepley { 47353e9753d6SMatthew G. Knepley PetscFE fe; 47363e9753d6SMatthew G. Knepley PetscInt Nb; 47373e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 47383e9753d6SMatthew G. Knepley /* Conforming batches */ 47393e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 47403e9753d6SMatthew G. Knepley /* Remainder */ 47413e9753d6SMatthew G. Knepley PetscInt Nr, offset; 47423e9753d6SMatthew G. Knepley 47439566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 47449566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 47459566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 47463e9753d6SMatthew G. Knepley /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */ 47473e9753d6SMatthew G. Knepley blockSize = Nb; 47483e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 47499566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 47503e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 47513e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 47523e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 47533e9753d6SMatthew G. Knepley offset = numFaces - Nr; 47549566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 47559566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 47569566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 47579566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 4758*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, &elemVec[offset * totDim])); 47599566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 47603e9753d6SMatthew G. Knepley } 47613e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 47623e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 47633e9753d6SMatthew G. Knepley 47649566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face * totDim])); 47659566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 47669566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face * totDim], ADD_ALL_VALUES)); 47673e9753d6SMatthew G. Knepley } 47689566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 47699566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 47709566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 47719566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 47729566063dSJacob Faibussowitsch PetscCall(PetscFree4(u, u_t, elemVec, a)); 47733e9753d6SMatthew G. Knepley } 47740c290148SMatthew G. Knepley end: 47759566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 47769566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexA)); 47773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 47783e9753d6SMatthew G. Knepley } 47793e9753d6SMatthew G. Knepley 4780d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF) 4781d71ae5a4SJacob Faibussowitsch { 47823e9753d6SMatthew G. Knepley DMField coordField; 47833e9753d6SMatthew G. Knepley DMLabel depthLabel; 47843e9753d6SMatthew G. Knepley IS facetIS; 47853e9753d6SMatthew G. Knepley PetscInt dim; 47863e9753d6SMatthew G. Knepley 47873e9753d6SMatthew G. Knepley PetscFunctionBegin; 47889566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 47899566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 47909566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 47919566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 47929566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 47939566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 47943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 47953e9753d6SMatthew G. Knepley } 47963e9753d6SMatthew G. Knepley 4797a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4798d71ae5a4SJacob Faibussowitsch { 47993e9753d6SMatthew G. Knepley PetscDS prob; 48003e9753d6SMatthew G. Knepley PetscInt numBd, bd; 48013e9753d6SMatthew G. Knepley DMField coordField = NULL; 48023e9753d6SMatthew G. Knepley IS facetIS = NULL; 48033e9753d6SMatthew G. Knepley DMLabel depthLabel; 48043e9753d6SMatthew G. Knepley PetscInt dim; 48053e9753d6SMatthew G. Knepley 48063e9753d6SMatthew G. Knepley PetscFunctionBegin; 48079566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 48089566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 48099566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 48109566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 48119566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 48123e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 481345480ffeSMatthew G. Knepley PetscWeakForm wf; 48143e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 48153e9753d6SMatthew G. Knepley DMLabel label; 48163e9753d6SMatthew G. Knepley const PetscInt *values; 48170c290148SMatthew G. Knepley PetscInt field, numValues, v; 48183e9753d6SMatthew G. Knepley PetscObject obj; 48193e9753d6SMatthew G. Knepley PetscClassId id; 48200c290148SMatthew G. Knepley PetscFormKey key; 48213e9753d6SMatthew G. Knepley 48229566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL)); 48233d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 48249566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 48259566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 48263d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 48273e9753d6SMatthew G. Knepley if (!facetIS) { 48283e9753d6SMatthew G. Knepley DMLabel depthLabel; 48293e9753d6SMatthew G. Knepley PetscInt dim; 48303e9753d6SMatthew G. Knepley 48319566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 48329566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 48339566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 48343e9753d6SMatthew G. Knepley } 48359566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 48360c290148SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 48370c290148SMatthew G. Knepley key.label = label; 48380c290148SMatthew G. Knepley key.value = values[v]; 48390c290148SMatthew G. Knepley key.field = field; 48400c290148SMatthew G. Knepley key.part = 0; 48419566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 48420c290148SMatthew G. Knepley } 48433e9753d6SMatthew G. Knepley } 48449566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 48453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 48463e9753d6SMatthew G. Knepley } 48473e9753d6SMatthew G. Knepley 4848d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4849d71ae5a4SJacob Faibussowitsch { 48503e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 48513e9753d6SMatthew G. Knepley const char *name = "Residual"; 48523e9753d6SMatthew G. Knepley DM dmAux = NULL; 48533e9753d6SMatthew G. Knepley DM dmGrad = NULL; 48543e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 48556528b96dSMatthew G. Knepley PetscDS ds = NULL; 48566528b96dSMatthew G. Knepley PetscDS dsAux = NULL; 48573e9753d6SMatthew G. Knepley PetscSection section = NULL; 48583e9753d6SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 48593e9753d6SMatthew G. Knepley PetscBool useFVM = PETSC_FALSE; 48603e9753d6SMatthew G. Knepley PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 48613e9753d6SMatthew G. Knepley PetscFV fvm = NULL; 48623e9753d6SMatthew G. Knepley DMField coordField = NULL; 48635962854dSMatthew G. Knepley Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 48643e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t, *a, *uL, *uR; 48653e9753d6SMatthew G. Knepley IS chunkIS; 48663e9753d6SMatthew G. Knepley const PetscInt *cells; 48673e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 48683e9753d6SMatthew G. Knepley PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd; 48693e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 48703e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 48713e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 48723e9753d6SMatthew G. Knepley 48733e9753d6SMatthew G. Knepley PetscFunctionBegin; 48743ba16761SJacob Faibussowitsch if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 4875437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 48763ba16761SJacob Faibussowitsch if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 48779566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 48783e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 48793e9753d6SMatthew G. Knepley /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */ 48803e9753d6SMatthew G. Knepley /* FEM+FVM */ 48819566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 48823e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 48839566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 48849566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 488507218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, NULL)); 48869566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 48879566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 48889566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 48893e9753d6SMatthew G. Knepley if (locA) { 48903e9753d6SMatthew G. Knepley PetscInt subcell; 48919566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 48921059d808SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell)); 489307218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux, subcell, &dsAux, NULL)); 48949566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 48953e9753d6SMatthew G. Knepley } 48963e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 48973e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 48983e9753d6SMatthew G. Knepley PetscObject obj; 48993e9753d6SMatthew G. Knepley PetscClassId id; 49003e9753d6SMatthew G. Knepley PetscBool fimp; 49013e9753d6SMatthew G. Knepley 49029566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 49033e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 49049566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 49059566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 4906ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 49079371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 49089371c9d4SSatish Balay useFVM = PETSC_TRUE; 49099371c9d4SSatish Balay fvm = (PetscFV)obj; 49109371c9d4SSatish Balay } 49113e9753d6SMatthew G. Knepley } 49123e9753d6SMatthew G. Knepley if (useFEM) { 49139566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 49149566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 49153e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 49169566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 491748a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 49183e9753d6SMatthew G. Knepley } else { 49199566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 49203e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 49213e9753d6SMatthew G. Knepley PetscObject obj; 49223e9753d6SMatthew G. Knepley PetscClassId id; 49233e9753d6SMatthew G. Knepley PetscBool fimp; 49243e9753d6SMatthew G. Knepley 49259566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 49263e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 49279566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 49289566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 49293e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 49303e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 49313e9753d6SMatthew G. Knepley 49329566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 49339566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 49349566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 49353e9753d6SMatthew G. Knepley } 49363e9753d6SMatthew G. Knepley } 49373e9753d6SMatthew G. Knepley } 49383e9753d6SMatthew G. Knepley } 49395962854dSMatthew G. Knepley // Handle non-essential (e.g. outflow) boundary values 49403e9753d6SMatthew G. Knepley if (useFVM) { 49415962854dSMatthew G. Knepley PetscCall(DMPlexInsertBoundaryValuesFVM(dm, fvm, locX, time, &locGrad)); 49429566063dSJacob Faibussowitsch PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 49439566063dSJacob Faibussowitsch PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad)); 49443e9753d6SMatthew G. Knepley } 49453e9753d6SMatthew G. Knepley /* Loop over chunks */ 49469566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 49473e9753d6SMatthew G. Knepley numCells = cEnd - cStart; 49483e9753d6SMatthew G. Knepley numChunks = 1; 49493e9753d6SMatthew G. Knepley cellChunkSize = numCells / numChunks; 49503e9753d6SMatthew G. Knepley faceChunkSize = (fEnd - fStart) / numChunks; 49513e9753d6SMatthew G. Knepley numChunks = PetscMin(1, numCells); 49523e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 49533e9753d6SMatthew G. Knepley PetscScalar *elemVec, *fluxL, *fluxR; 49543e9753d6SMatthew G. Knepley PetscReal *vol; 49553e9753d6SMatthew G. Knepley PetscFVFaceGeom *fgeom; 49563e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 49573e9753d6SMatthew G. Knepley PetscInt fS = fStart + chunk * faceChunkSize, fE = PetscMin(fS + faceChunkSize, fEnd), numFaces = 0, face; 49583e9753d6SMatthew G. Knepley 49593e9753d6SMatthew G. Knepley /* Extract field coefficients */ 49603e9753d6SMatthew G. Knepley if (useFEM) { 49619566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 49629566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 49639566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 49649566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 49653e9753d6SMatthew G. Knepley } 49663e9753d6SMatthew G. Knepley if (useFVM) { 49679566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 49689566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 49699566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 49709566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 49719566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxL, numFaces * totDim)); 49729566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxR, numFaces * totDim)); 49733e9753d6SMatthew G. Knepley } 49743e9753d6SMatthew 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 */ 49753e9753d6SMatthew G. Knepley /* Loop over fields */ 49763e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 49773e9753d6SMatthew G. Knepley PetscObject obj; 49783e9753d6SMatthew G. Knepley PetscClassId id; 49793e9753d6SMatthew G. Knepley PetscBool fimp; 49803e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 49813e9753d6SMatthew G. Knepley 49826528b96dSMatthew G. Knepley key.field = f; 49839566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 49843e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 49859566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 49869566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 49873e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 49883e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 49893e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 49903e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 49913e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 49923e9753d6SMatthew G. Knepley PetscInt Nq, Nb; 49933e9753d6SMatthew G. Knepley 49949566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 49959566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 49969566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 49973e9753d6SMatthew G. Knepley blockSize = Nb; 49983e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 49999566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 50003e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 50013e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 50023e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 50033e9753d6SMatthew G. Knepley offset = numCells - Nr; 50043e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 50053e9753d6SMatthew 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) */ 50069566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 50079566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec)); 50089566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 5009*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, &elemVec[offset * totDim])); 50109566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 50113e9753d6SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 50123e9753d6SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 50133e9753d6SMatthew G. Knepley 50143e9753d6SMatthew G. Knepley Ne = numFaces; 50153e9753d6SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 50163e9753d6SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 50179566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 501863a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 50193e9753d6SMatthew G. Knepley } 50203e9753d6SMatthew G. Knepley /* Loop over domain */ 50213e9753d6SMatthew G. Knepley if (useFEM) { 50223e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 50233e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 50243e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 50253e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 50263e9753d6SMatthew G. Knepley 50279566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 50283e9753d6SMatthew G. Knepley if (ghostLabel) { 50293e9753d6SMatthew G. Knepley PetscInt ghostVal; 50303e9753d6SMatthew G. Knepley 50319566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 50323e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 50333e9753d6SMatthew G. Knepley } 50349566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 50353e9753d6SMatthew G. Knepley } 50363e9753d6SMatthew G. Knepley } 50373e9753d6SMatthew G. Knepley if (useFVM) { 50383e9753d6SMatthew G. Knepley PetscScalar *fa; 50393e9753d6SMatthew G. Knepley PetscInt iface; 50403e9753d6SMatthew G. Knepley 50419566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 50423e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 50433e9753d6SMatthew G. Knepley PetscFV fv; 50443e9753d6SMatthew G. Knepley PetscObject obj; 50453e9753d6SMatthew G. Knepley PetscClassId id; 50465962854dSMatthew G. Knepley PetscInt cdim, foff, pdim; 50473e9753d6SMatthew G. Knepley 50485962854dSMatthew G. Knepley PetscCall(DMGetCoordinateDim(dm, &cdim)); 50499566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 50509566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(ds, f, &foff)); 50519566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 50523e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 50533e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 50549566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 50553e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 50563e9753d6SMatthew G. Knepley for (face = fS, iface = 0; face < fE; ++face) { 50573e9753d6SMatthew G. Knepley const PetscInt *scells; 50583e9753d6SMatthew G. Knepley PetscScalar *fL = NULL, *fR = NULL; 50593e9753d6SMatthew G. Knepley PetscInt ghost, d, nsupp, nchild; 50603e9753d6SMatthew G. Knepley 50619566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 50629566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 50639566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 50643e9753d6SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 50659566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &scells)); 50669566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[0], &ghost)); 50679566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL)); 50689566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[1], &ghost)); 50699566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR)); 50705962854dSMatthew G. Knepley if (mesh->printFVM > 1) { 50715962854dSMatthew G. Knepley PetscCall(DMPrintCellVectorReal(face, "Residual: normal", cdim, fgeom[iface].normal)); 50725962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: left state", pdim, &uL[iface * totDim + foff])); 50735962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: right state", pdim, &uR[iface * totDim + foff])); 50745962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: left flux", pdim, &fluxL[iface * totDim + foff])); 50755962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: right flux", pdim, &fluxR[iface * totDim + foff])); 50765962854dSMatthew G. Knepley } 50773e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) { 50783e9753d6SMatthew G. Knepley if (fL) fL[d] -= fluxL[iface * totDim + foff + d]; 50793e9753d6SMatthew G. Knepley if (fR) fR[d] += fluxR[iface * totDim + foff + d]; 50803e9753d6SMatthew G. Knepley } 50813e9753d6SMatthew G. Knepley ++iface; 50823e9753d6SMatthew G. Knepley } 50833e9753d6SMatthew G. Knepley } 50849566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 50853e9753d6SMatthew G. Knepley } 50863e9753d6SMatthew G. Knepley /* Handle time derivative */ 50873e9753d6SMatthew G. Knepley if (locX_t) { 50883e9753d6SMatthew G. Knepley PetscScalar *x_t, *fa; 50893e9753d6SMatthew G. Knepley 50909566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 50919566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 50923e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 50933e9753d6SMatthew G. Knepley PetscFV fv; 50943e9753d6SMatthew G. Knepley PetscObject obj; 50953e9753d6SMatthew G. Knepley PetscClassId id; 50963e9753d6SMatthew G. Knepley PetscInt pdim, d; 50973e9753d6SMatthew G. Knepley 50989566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 50999566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 51003e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 51013e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 51029566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 51033e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 51043e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 51053e9753d6SMatthew G. Knepley PetscScalar *u_t, *r; 51063e9753d6SMatthew G. Knepley 51073e9753d6SMatthew G. Knepley if (ghostLabel) { 51083e9753d6SMatthew G. Knepley PetscInt ghostVal; 51093e9753d6SMatthew G. Knepley 51109566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 51113e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 51123e9753d6SMatthew G. Knepley } 51139566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 51149566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 51153e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 51163e9753d6SMatthew G. Knepley } 51173e9753d6SMatthew G. Knepley } 51189566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 51199566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 51203e9753d6SMatthew G. Knepley } 51213e9753d6SMatthew G. Knepley if (useFEM) { 51229566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 51239566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 51243e9753d6SMatthew G. Knepley } 51253e9753d6SMatthew G. Knepley if (useFVM) { 51269566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 51279566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 51289566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 51299566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 51309566063dSJacob Faibussowitsch if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 51313e9753d6SMatthew G. Knepley } 51323e9753d6SMatthew G. Knepley } 51339566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 51349566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 51353e9753d6SMatthew G. Knepley 51363e9753d6SMatthew G. Knepley if (useFEM) { 51379566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user)); 51383e9753d6SMatthew G. Knepley 51393e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 51409566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 51419566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 51423e9753d6SMatthew G. Knepley } else { 51433e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 51449566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 51459566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 51463e9753d6SMatthew G. Knepley } 51479566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 51483e9753d6SMatthew G. Knepley } 51493e9753d6SMatthew G. Knepley } 51503e9753d6SMatthew G. Knepley 51513e9753d6SMatthew G. Knepley /* FEM */ 51523e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 51533e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 51543e9753d6SMatthew G. Knepley /* 3: Handle boundary values */ 51553e9753d6SMatthew G. Knepley /* 4: Loop over domain */ 51563e9753d6SMatthew G. Knepley /* Extract coefficients */ 51573e9753d6SMatthew G. Knepley /* Loop over fields */ 51583e9753d6SMatthew G. Knepley /* Set tiling for FE*/ 51593e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec */ 51603e9753d6SMatthew G. Knepley /* Loop over subdomain */ 51613e9753d6SMatthew G. Knepley /* Loop over quad points */ 51623e9753d6SMatthew G. Knepley /* Transform coords to real space */ 51633e9753d6SMatthew G. Knepley /* Evaluate field and aux fields at point */ 51643e9753d6SMatthew G. Knepley /* Evaluate residual at point */ 51653e9753d6SMatthew G. Knepley /* Transform residual to real space */ 51663e9753d6SMatthew G. Knepley /* Add residual to elemVec */ 51673e9753d6SMatthew G. Knepley /* Loop over domain */ 51683e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 51693e9753d6SMatthew G. Knepley 51703e9753d6SMatthew G. Knepley /* FVM */ 51713e9753d6SMatthew G. Knepley /* Get geometric data */ 51723e9753d6SMatthew G. Knepley /* If using gradients */ 51733e9753d6SMatthew G. Knepley /* Compute gradient data */ 51743e9753d6SMatthew G. Knepley /* Loop over domain faces */ 51753e9753d6SMatthew G. Knepley /* Count computational faces */ 51763e9753d6SMatthew G. Knepley /* Reconstruct cell gradient */ 51773e9753d6SMatthew G. Knepley /* Loop over domain cells */ 51783e9753d6SMatthew G. Knepley /* Limit cell gradients */ 51793e9753d6SMatthew G. Knepley /* Handle boundary values */ 51803e9753d6SMatthew G. Knepley /* Loop over domain faces */ 51813e9753d6SMatthew G. Knepley /* Read out field, centroid, normal, volume for each side of face */ 51823e9753d6SMatthew G. Knepley /* Riemann solve over faces */ 51833e9753d6SMatthew G. Knepley /* Loop over domain faces */ 51843e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 51853e9753d6SMatthew G. Knepley /* TODO Change printFEM to printDisc here */ 51863e9753d6SMatthew G. Knepley if (mesh->printFEM) { 51873e9753d6SMatthew G. Knepley Vec locFbc; 51883e9753d6SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 51893e9753d6SMatthew G. Knepley PetscScalar *zeroes; 51903e9753d6SMatthew G. Knepley 51919566063dSJacob Faibussowitsch PetscCall(VecDuplicate(locF, &locFbc)); 51929566063dSJacob Faibussowitsch PetscCall(VecCopy(locF, locFbc)); 51939566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 51949566063dSJacob Faibussowitsch PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 51959566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(maxDof, &zeroes)); 519648a46eb9SPierre Jolivet for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 51979566063dSJacob Faibussowitsch PetscCall(PetscFree(zeroes)); 51989566063dSJacob Faibussowitsch PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 51999566063dSJacob Faibussowitsch PetscCall(VecDestroy(&locFbc)); 52003e9753d6SMatthew G. Knepley } 52019566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 52023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 52033e9753d6SMatthew G. Knepley } 52043e9753d6SMatthew G. Knepley 52056528b96dSMatthew G. Knepley /* 52066528b96dSMatthew G. Knepley 1) Allow multiple kernels for BdResidual for hybrid DS 52076528b96dSMatthew G. Knepley 52086528b96dSMatthew G. Knepley DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux 52096528b96dSMatthew G. Knepley 52106528b96dSMatthew G. Knepley DONE 3) Change DMGetCellFields() to get different aux data a[] for each side 52116528b96dSMatthew G. Knepley - I think I just need to replace a[] with the closure from each face 52126528b96dSMatthew G. Knepley 52136528b96dSMatthew G. Knepley 4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before 52146528b96dSMatthew G. Knepley */ 5215d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 5216d71ae5a4SJacob Faibussowitsch { 52173e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 52183e9753d6SMatthew G. Knepley const char *name = "Hybrid Residual"; 521904c51a94SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 52203e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 52216528b96dSMatthew G. Knepley PetscDS ds = NULL; 522207218a29SMatthew G. Knepley PetscDS dsIn = NULL; 52236528b96dSMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 522404c51a94SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 522507218a29SMatthew G. Knepley DM dmScale[3] = {NULL, NULL, NULL}; 522607218a29SMatthew G. Knepley PetscDS dsScale[3] = {NULL, NULL, NULL}; 522707218a29SMatthew G. Knepley Vec locS[3] = {NULL, NULL, NULL}; 52283e9753d6SMatthew G. Knepley PetscSection section = NULL; 52293e9753d6SMatthew G. Knepley DMField coordField = NULL; 523007218a29SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 523107218a29SMatthew G. Knepley PetscScalar *s[3] = {NULL, NULL, NULL}; 5232b2ab40e6SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 523307218a29SMatthew G. Knepley PetscScalar *elemVecNeg, *elemVecPos, *elemVecCoh; 52343e9753d6SMatthew G. Knepley IS chunkIS; 52353e9753d6SMatthew G. Knepley const PetscInt *cells; 52363e9753d6SMatthew G. Knepley PetscInt *faces; 52373e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 52383e2b0218SMatthew G. Knepley PetscInt Nf, f, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk; 52393e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 52403e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 52413e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 52423e9753d6SMatthew G. Knepley 52433e9753d6SMatthew G. Knepley PetscFunctionBegin; 52443ba16761SJacob Faibussowitsch if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 5245437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5246437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 52473ba16761SJacob Faibussowitsch if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 52485fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 52495fedec97SMatthew G. Knepley const char *name; 52509566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 525163a3b9bcSJacob 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); 52525fedec97SMatthew G. Knepley } 52539566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 52543e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 52553e9753d6SMatthew G. Knepley /* FEM */ 52563e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 52579566063dSJacob Faibussowitsch PetscCall(DMGetSection(dm, §ion)); 52589566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 525907218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 52609566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 52619566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 526207218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn)); 52639566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 526404c51a94SMatthew G. Knepley if (locA[2]) { 52651059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 52661059d808SMatthew G. Knepley 52679566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 526807218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL)); 52699566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 52706528b96dSMatthew G. Knepley { 52716528b96dSMatthew G. Knepley const PetscInt *cone; 52726528b96dSMatthew G. Knepley PetscInt c; 52736528b96dSMatthew G. Knepley 52741059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 52756528b96dSMatthew G. Knepley for (c = 0; c < 2; ++c) { 52766528b96dSMatthew G. Knepley const PetscInt *support; 52776528b96dSMatthew G. Knepley PetscInt ssize, s; 52786528b96dSMatthew G. Knepley 52799566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 52809566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 52811059d808SMatthew 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); 52821059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 52831059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 52841059d808SMatthew 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); 52859566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 5286c75bfeddSPierre 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); 52879566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5288ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 528907218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL)); 52909566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 52916528b96dSMatthew G. Knepley } 52926528b96dSMatthew G. Knepley } 52933e9753d6SMatthew G. Knepley } 529407218a29SMatthew G. Knepley /* Handle mass matrix scaling 529507218a29SMatthew G. Knepley The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */ 529607218a29SMatthew G. Knepley PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2])); 529707218a29SMatthew G. Knepley if (locS[2]) { 52983e2b0218SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 529907218a29SMatthew G. Knepley PetscInt Nb, Nbs; 530007218a29SMatthew G. Knepley 530107218a29SMatthew G. Knepley PetscCall(VecGetDM(locS[2], &dmScale[2])); 53023e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[2], cellStart, &dsScale[2], NULL)); 53033e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2])); 530407218a29SMatthew G. Knepley // BRAD: This is not set correctly 530507218a29SMatthew G. Knepley key[2].field = 2; 530607218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb)); 530707218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs)); 530807218a29SMatthew 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); 53093e2b0218SMatthew G. Knepley { 53103e2b0218SMatthew G. Knepley const PetscInt *cone; 53113e2b0218SMatthew G. Knepley PetscInt c; 53123e2b0218SMatthew G. Knepley 53133e2b0218SMatthew G. Knepley locS[1] = locS[0] = locS[2]; 53143e2b0218SMatthew G. Knepley dmScale[1] = dmScale[0] = dmScale[2]; 53153e2b0218SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 53163e2b0218SMatthew G. Knepley for (c = 0; c < 2; ++c) { 53173e2b0218SMatthew G. Knepley const PetscInt *support; 53183e2b0218SMatthew G. Knepley PetscInt ssize, s; 53193e2b0218SMatthew G. Knepley 53203e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 53213e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 53223e2b0218SMatthew 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); 53233e2b0218SMatthew G. Knepley if (support[0] == cellStart) s = 1; 53243e2b0218SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 53253e2b0218SMatthew 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); 53263e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL)); 53273e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c])); 53283e2b0218SMatthew G. Knepley } 53293e2b0218SMatthew G. Knepley } 533007218a29SMatthew G. Knepley } 53313e9753d6SMatthew G. Knepley /* 2: Setup geometric data */ 53329566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 53339566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 53343e9753d6SMatthew G. Knepley if (maxDegree > 1) { 53359566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 53363e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 53373e9753d6SMatthew G. Knepley PetscFE fe; 53383e9753d6SMatthew G. Knepley 53399566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 53403e9753d6SMatthew G. Knepley if (fe) { 53419566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 53429566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 53433e9753d6SMatthew G. Knepley } 53443e9753d6SMatthew G. Knepley } 53453e9753d6SMatthew G. Knepley } 53463e9753d6SMatthew G. Knepley /* Loop over chunks */ 53473e9753d6SMatthew G. Knepley cellChunkSize = numCells; 53483e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 534907218a29SMatthew G. Knepley PetscCall(PetscCalloc1(2 * cellChunkSize, &faces)); 535007218a29SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 53513e9753d6SMatthew G. Knepley /* Extract field coefficients */ 53523e9753d6SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 535307218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 535407218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 53553e2b0218SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 535607218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecNeg)); 535707218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecPos)); 535807218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecCoh)); 53593e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 53603e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 53613e9753d6SMatthew G. Knepley 536207218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecNeg, cellChunkSize * totDim)); 536307218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecPos, cellChunkSize * totDim)); 536407218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecCoh, cellChunkSize * totDim)); 53653e9753d6SMatthew G. Knepley /* Get faces */ 53663e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 53673e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 53683e9753d6SMatthew G. Knepley const PetscInt *cone; 53699566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 537007218a29SMatthew G. Knepley faces[(c - cS) * 2 + 0] = cone[0]; 537107218a29SMatthew G. Knepley faces[(c - cS) * 2 + 1] = cone[1]; 53723e9753d6SMatthew G. Knepley } 537307218a29SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER)); 53743e9753d6SMatthew G. Knepley /* Get geometric data */ 53753e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 53769566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 53779566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 53783e9753d6SMatthew G. Knepley } else { 53793e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 53809566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 53813e9753d6SMatthew G. Knepley } 53823e9753d6SMatthew G. Knepley } 53833e9753d6SMatthew G. Knepley /* Loop over fields */ 53843e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 53853e9753d6SMatthew G. Knepley PetscFE fe; 53863e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 5387148442b3SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 53883e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 53893e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 53905fedec97SMatthew G. Knepley PetscBool isCohesiveField; 53913e9753d6SMatthew G. Knepley 53929566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 53933e9753d6SMatthew G. Knepley if (!fe) continue; 53949566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 53959566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 53969566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 53973e9753d6SMatthew G. Knepley blockSize = Nb; 53983e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 53999566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 54003e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 54013e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 54023e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 54033e9753d6SMatthew G. Knepley offset = numCells - Nr; 540407218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom)); 540507218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom)); 54069566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 54075fedec97SMatthew G. Knepley chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE; 54086528b96dSMatthew G. Knepley key[0].field = f; 54096528b96dSMatthew G. Knepley key[1].field = f; 54105fedec97SMatthew G. Knepley key[2].field = f; 541107218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVecNeg)); 5412*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[0], PetscSafePointerPlusOffset(a[0], offset * totDimAux[0]), t, &elemVecNeg[offset * totDim])); 541307218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVecPos)); 5414*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[1], PetscSafePointerPlusOffset(a[1], offset * totDimAux[1]), t, &elemVecPos[offset * totDim])); 541507218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVecCoh)); 5416*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[2], PetscSafePointerPlusOffset(a[2], offset * totDimAux[2]), t, &elemVecCoh[offset * totDim])); 54179566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 54189566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 54193e9753d6SMatthew G. Knepley } 54203e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 54213e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 54223e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 54233e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 542407218a29SMatthew G. Knepley PetscInt i; 54253e9753d6SMatthew G. Knepley 542607218a29SMatthew G. Knepley /* Scale element values */ 542707218a29SMatthew G. Knepley if (locS[0]) { 54283e2b0218SMatthew G. Knepley PetscInt Nb, off = cind * totDim, soff = cind * totDimScale[0]; 542907218a29SMatthew G. Knepley PetscBool cohesive; 543007218a29SMatthew G. Knepley 543107218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 543207218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, f, &Nb)); 543307218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 543407218a29SMatthew G. Knepley if (f == key[2].field) { 543507218a29SMatthew G. Knepley PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields"); 543607218a29SMatthew G. Knepley // No cohesive scaling field is currently input 543707218a29SMatthew 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]; 543807218a29SMatthew G. Knepley off += Nb; 543907218a29SMatthew G. Knepley } else { 544007218a29SMatthew G. Knepley const PetscInt N = cohesive ? Nb : Nb * 2; 544107218a29SMatthew G. Knepley 544207218a29SMatthew G. Knepley for (i = 0; i < N; ++i) elemVecCoh[off + i] += elemVecNeg[off + i] + elemVecPos[off + i]; 544307218a29SMatthew G. Knepley off += N; 544407218a29SMatthew G. Knepley } 544507218a29SMatthew G. Knepley } 544607218a29SMatthew G. Knepley } else { 544707218a29SMatthew G. Knepley for (i = cind * totDim; i < (cind + 1) * totDim; ++i) elemVecCoh[i] += elemVecNeg[i] + elemVecPos[i]; 544807218a29SMatthew G. Knepley } 544907218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVecCoh[cind * totDim])); 54503e9753d6SMatthew G. Knepley if (ghostLabel) { 54513e9753d6SMatthew G. Knepley PetscInt ghostVal; 54523e9753d6SMatthew G. Knepley 54539566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 54543e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 54553e9753d6SMatthew G. Knepley } 545607218a29SMatthew G. Knepley PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVecCoh[cind * totDim], ADD_ALL_VALUES)); 54573e9753d6SMatthew G. Knepley } 54583e9753d6SMatthew G. Knepley } 54599566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 546007218a29SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 54613e2b0218SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 546207218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecNeg)); 546307218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecPos)); 546407218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecCoh)); 54659566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 54669566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 54679566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 54683e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 54699566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 54709566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 54713e9753d6SMatthew G. Knepley } else { 54723e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 54739566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 54749566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 54753e9753d6SMatthew G. Knepley } 54769566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 54773e9753d6SMatthew G. Knepley } 547885cc2951SMatthew G. Knepley if (mesh->printFEM) { 547985cc2951SMatthew G. Knepley Vec locFbc; 548085cc2951SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 548185cc2951SMatthew G. Knepley PetscScalar *zeroes; 548285cc2951SMatthew G. Knepley 548385cc2951SMatthew G. Knepley PetscCall(VecDuplicate(locF, &locFbc)); 548485cc2951SMatthew G. Knepley PetscCall(VecCopy(locF, locFbc)); 548585cc2951SMatthew G. Knepley PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 548685cc2951SMatthew G. Knepley PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 548785cc2951SMatthew G. Knepley PetscCall(PetscCalloc1(maxDof, &zeroes)); 548885cc2951SMatthew G. Knepley for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 548985cc2951SMatthew G. Knepley PetscCall(PetscFree(zeroes)); 549085cc2951SMatthew G. Knepley PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 549185cc2951SMatthew G. Knepley PetscCall(VecDestroy(&locFbc)); 549285cc2951SMatthew G. Knepley } 54939566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 54943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 54953e9753d6SMatthew G. Knepley } 54963e9753d6SMatthew G. Knepley 5497a4e35b19SJacob 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) 5498d71ae5a4SJacob Faibussowitsch { 54993e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 55003e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL, tdm; 55013e9753d6SMatthew G. Knepley DMEnclosureType encAux; 5502be62b2b4SMatthew G. Knepley PetscDS ds, dsAux = NULL; 55033e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 5504e432b41dSStefano Zampini PetscSection globalSection; 55053e9753d6SMatthew G. Knepley Vec locA = NULL, tv; 5506be62b2b4SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL; 55073e9753d6SMatthew G. Knepley PetscInt v; 55083e9753d6SMatthew G. Knepley PetscInt Nf, totDim, totDimAux = 0; 5509be62b2b4SMatthew G. Knepley PetscBool hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, transform; 55103e9753d6SMatthew G. Knepley 55113e9753d6SMatthew G. Knepley PetscFunctionBegin; 55129566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 55139566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 55149566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 55159566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 55169566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 5517be62b2b4SMatthew G. Knepley PetscCall(DMGetDS(dm, &ds)); 5518be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetNumFields(ds, &Nf)); 5519be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 5520be62b2b4SMatthew G. Knepley PetscCall(PetscDSHasJacobian(ds, &hasJac)); 5521be62b2b4SMatthew G. Knepley PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec)); 55229566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA)); 55233e9753d6SMatthew G. Knepley if (locA) { 55243e9753d6SMatthew G. Knepley DM dmAux; 55253e9753d6SMatthew G. Knepley 55269566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 55279566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 55289566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 5529be62b2b4SMatthew G. Knepley PetscCall(DMGetDS(plexA, &dsAux)); 5530be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 55319566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 55323e9753d6SMatthew G. Knepley } 55333e9753d6SMatthew G. Knepley 55349566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 55353e9753d6SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 55363e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 55373e9753d6SMatthew G. Knepley PetscInt maxDegree; 55383e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 55393e9753d6SMatthew G. Knepley IS pointIS; 55403e9753d6SMatthew G. Knepley const PetscInt *points; 554106ad1575SMatthew G. Knepley PetscFormKey key; 55423e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 55433e9753d6SMatthew G. Knepley 554445480ffeSMatthew G. Knepley key.label = label; 554545480ffeSMatthew G. Knepley key.value = values[v]; 554606ad1575SMatthew G. Knepley key.part = 0; 55479566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 55483e9753d6SMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 55493e9753d6SMatthew G. Knepley { 55503e9753d6SMatthew G. Knepley IS isectIS; 55513e9753d6SMatthew G. Knepley 55523e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */ 55539566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 55549566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 55553e9753d6SMatthew G. Knepley pointIS = isectIS; 55563e9753d6SMatthew G. Knepley } 55579566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 55589566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 5559be62b2b4SMatthew G. Knepley PetscCall(PetscMalloc5(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, hasJac ? numFaces * totDim * totDim : 0, &elemMat, hasPrec ? numFaces * totDim * totDim : 0, &elemMatP, locA ? numFaces * totDimAux : 0, &a)); 55609566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 556148a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 55623e9753d6SMatthew G. Knepley if (!qGeom) { 55633e9753d6SMatthew G. Knepley PetscFE fe; 55643e9753d6SMatthew G. Knepley 5565be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&fe)); 55669566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 55679566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 55683e9753d6SMatthew G. Knepley } 55699566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 55709566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 55713e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 5572f15274beSMatthew Knepley const PetscInt point = points[face], *support; 55733e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 5574f15274beSMatthew Knepley PetscInt i; 55753e9753d6SMatthew G. Knepley 55769566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 55779566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 55783e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 55799566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 55803e9753d6SMatthew G. Knepley if (locX_t) { 55819566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 55823e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 55839566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 55843e9753d6SMatthew G. Knepley } 55853e9753d6SMatthew G. Knepley if (locA) { 55863e9753d6SMatthew G. Knepley PetscInt subp; 55879566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 55889566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 55893e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 55909566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 55913e9753d6SMatthew G. Knepley } 55923e9753d6SMatthew G. Knepley } 55939566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, numFaces * totDim * totDim)); 55943e9753d6SMatthew G. Knepley { 55953e9753d6SMatthew G. Knepley PetscFE fe; 55963e9753d6SMatthew G. Knepley PetscInt Nb; 55973e9753d6SMatthew G. Knepley /* Conforming batches */ 55983e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 55993e9753d6SMatthew G. Knepley /* Remainder */ 56003e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 56013e9753d6SMatthew G. Knepley PetscInt fieldJ, Nr, offset; 56023e9753d6SMatthew G. Knepley 5603be62b2b4SMatthew G. Knepley PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&fe)); 56049566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 56059566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 56063e9753d6SMatthew G. Knepley blockSize = Nb; 56073e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 56089566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 56093e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 56103e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 56113e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 56123e9753d6SMatthew G. Knepley offset = numFaces - Nr; 56139566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 56143e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 561545480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 5616be62b2b4SMatthew G. Knepley if (hasJac) PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, dsAux, a, t, X_tShift, elemMat)); 5617be62b2b4SMatthew G. Knepley if (hasPrec) PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, dsAux, a, t, X_tShift, elemMatP)); 56183e9753d6SMatthew G. Knepley } 56199566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 56203e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 562145480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 5622be62b2b4SMatthew G. Knepley if (hasJac) 5623*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMat[offset * totDim * totDim])); 5624be62b2b4SMatthew G. Knepley if (hasPrec) 5625*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN_PRE, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMatP[offset * totDim * totDim])); 56263e9753d6SMatthew G. Knepley } 56279566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 56283e9753d6SMatthew G. Knepley } 56293e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 56303e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 56313e9753d6SMatthew G. Knepley 56323e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 56339566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 56349566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face * totDim * totDim])); 5635be62b2b4SMatthew G. Knepley if (hasPrec) { 5636be62b2b4SMatthew G. Knepley if (hasJac) { 56379566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim])); 5638e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, support[0], &elemMat[face * totDim * totDim], ADD_VALUES)); 56393e9753d6SMatthew G. Knepley } 5640be62b2b4SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMatP[face * totDim * totDim])); 5641be62b2b4SMatthew G. Knepley PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, support[0], &elemMatP[face * totDim * totDim], ADD_VALUES)); 5642be62b2b4SMatthew G. Knepley } else { 5643be62b2b4SMatthew G. Knepley if (hasJac) { 5644be62b2b4SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim])); 5645be62b2b4SMatthew G. Knepley PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, support[0], &elemMat[face * totDim * totDim], ADD_VALUES)); 5646be62b2b4SMatthew G. Knepley } 5647be62b2b4SMatthew G. Knepley } 5648be62b2b4SMatthew G. Knepley } 56499566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 56509566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 56519566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 56529566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 5653be62b2b4SMatthew G. Knepley PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, a)); 56543e9753d6SMatthew G. Knepley } 56559566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 56569566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 56573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 56583e9753d6SMatthew G. Knepley } 56593e9753d6SMatthew G. Knepley 5660d71ae5a4SJacob 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) 5661d71ae5a4SJacob Faibussowitsch { 56623e9753d6SMatthew G. Knepley DMField coordField; 56633e9753d6SMatthew G. Knepley DMLabel depthLabel; 56643e9753d6SMatthew G. Knepley IS facetIS; 56653e9753d6SMatthew G. Knepley PetscInt dim; 56663e9753d6SMatthew G. Knepley 56673e9753d6SMatthew G. Knepley PetscFunctionBegin; 56689566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 56699566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 56709566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 56719566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 56729566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 56739566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 56743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 56753e9753d6SMatthew G. Knepley } 56763e9753d6SMatthew G. Knepley 5677a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user) 5678d71ae5a4SJacob Faibussowitsch { 56793e9753d6SMatthew G. Knepley PetscDS prob; 56803e9753d6SMatthew G. Knepley PetscInt dim, numBd, bd; 56813e9753d6SMatthew G. Knepley DMLabel depthLabel; 56823e9753d6SMatthew G. Knepley DMField coordField = NULL; 56833e9753d6SMatthew G. Knepley IS facetIS; 56843e9753d6SMatthew G. Knepley 56853e9753d6SMatthew G. Knepley PetscFunctionBegin; 56869566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 56879566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 56889566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 56899566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 56909566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 56919566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 56923e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 569345480ffeSMatthew G. Knepley PetscWeakForm wf; 56943e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 56953e9753d6SMatthew G. Knepley DMLabel label; 56963e9753d6SMatthew G. Knepley const PetscInt *values; 56973e9753d6SMatthew G. Knepley PetscInt fieldI, numValues; 56983e9753d6SMatthew G. Knepley PetscObject obj; 56993e9753d6SMatthew G. Knepley PetscClassId id; 57003e9753d6SMatthew G. Knepley 57019566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL)); 57023d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 57039566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj)); 57049566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 57053d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 57069566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 57073e9753d6SMatthew G. Knepley } 57089566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 57093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 57103e9753d6SMatthew G. Knepley } 57113e9753d6SMatthew G. Knepley 5712d71ae5a4SJacob 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) 5713d71ae5a4SJacob Faibussowitsch { 57143e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 57153e9753d6SMatthew G. Knepley const char *name = "Jacobian"; 57169a2a23afSMatthew G. Knepley DM dmAux = NULL, plex, tdm; 57173e9753d6SMatthew G. Knepley DMEnclosureType encAux; 57183e9753d6SMatthew G. Knepley Vec A, tv; 57193e9753d6SMatthew G. Knepley DMField coordField; 57203e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 5721e432b41dSStefano Zampini PetscSection section, globalSection, sectionAux; 57223e9753d6SMatthew G. Knepley PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL; 57233e9753d6SMatthew G. Knepley const PetscInt *cells; 57243e9753d6SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 572528351e22SJed Brown PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 5726e04ae0b4SMatthew G. Knepley PetscBool hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform; 57273e9753d6SMatthew G. Knepley 57283e9753d6SMatthew G. Knepley PetscFunctionBegin; 5729af18b51aSmarkadams4 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 5730e04ae0b4SMatthew G. Knepley if (!cellIS) goto end; 57319566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5732437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 5733437e83fbSMatthew G. Knepley if (cStart >= cEnd) goto end; 57349566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 57359566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 57369566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 57379566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 57389566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 573907218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 57409566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 57419566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 57429566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 57439566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 57443e9753d6SMatthew G. Knepley /* user passed in the same matrix, avoid double contributions and 57453e9753d6SMatthew G. Knepley only assemble the Jacobian */ 57463e9753d6SMatthew G. Knepley if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE; 57479566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 57483e9753d6SMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 57499566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 57509a2a23afSMatthew G. Knepley if (A) { 57519566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 57529566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 57539566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plex)); 57549566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plex, §ionAux)); 57559566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 57569566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 57573e9753d6SMatthew G. Knepley } 57589566063dSJacob 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)); 57599566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 57609566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 57613e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 57623e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 57633e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 57643e9753d6SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 57653e9753d6SMatthew G. Knepley PetscInt i; 57663e9753d6SMatthew G. Knepley 57679566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 57683e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 57699566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 57703e9753d6SMatthew G. Knepley if (X_t) { 57719566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 57723e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 57739566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 57743e9753d6SMatthew G. Knepley } 57753e9753d6SMatthew G. Knepley if (dmAux) { 57763e9753d6SMatthew G. Knepley PetscInt subcell; 57779566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 57789566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x)); 57793e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 57809566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x)); 57813e9753d6SMatthew G. Knepley } 57823e9753d6SMatthew G. Knepley } 57839566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 57849566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells * totDim * totDim)); 57859566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 57863e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 57873e9753d6SMatthew G. Knepley PetscClassId id; 57883e9753d6SMatthew G. Knepley PetscFE fe; 57893e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 57903e9753d6SMatthew G. Knepley PetscInt Nb; 57913e9753d6SMatthew G. Knepley /* Conforming batches */ 57923e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 57933e9753d6SMatthew G. Knepley /* Remainder */ 57943e9753d6SMatthew G. Knepley PetscInt Nr, offset, Nq; 57953e9753d6SMatthew G. Knepley PetscInt maxDegree; 57963e9753d6SMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 57973e9753d6SMatthew G. Knepley 57989566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 57999566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 58009371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 58019371c9d4SSatish Balay hasFV = PETSC_TRUE; 58029371c9d4SSatish Balay continue; 58039371c9d4SSatish Balay } 58049566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 58059566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 58069566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 580748a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 58083e9753d6SMatthew G. Knepley if (!qGeom) { 58099566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 58109566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 58113e9753d6SMatthew G. Knepley } 58129566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 58139566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 58143e9753d6SMatthew G. Knepley blockSize = Nb; 58153e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 58169566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 58173e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 58183e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 58193e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 58203e9753d6SMatthew G. Knepley offset = numCells - Nr; 58219566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 58229566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 58233e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 58246528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 58253e9753d6SMatthew G. Knepley if (hasJac) { 58269566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5827*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMat[offset * totDim * totDim])); 58283e9753d6SMatthew G. Knepley } 58293e9753d6SMatthew G. Knepley if (hasPrec) { 58309566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP)); 5831*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMatP[offset * totDim * totDim])); 58323e9753d6SMatthew G. Knepley } 58333e9753d6SMatthew G. Knepley if (hasDyn) { 58349566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 5835*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMatD[offset * totDim * totDim])); 58363e9753d6SMatthew G. Knepley } 58373e9753d6SMatthew G. Knepley } 58389566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 58399566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 58409566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 58419566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 58423e9753d6SMatthew G. Knepley } 58433e9753d6SMatthew G. Knepley /* Add contribution from X_t */ 58449371c9d4SSatish Balay if (hasDyn) { 58459371c9d4SSatish Balay for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 58469371c9d4SSatish Balay } 58473e9753d6SMatthew G. Knepley if (hasFV) { 58483e9753d6SMatthew G. Knepley PetscClassId id; 58493e9753d6SMatthew G. Knepley PetscFV fv; 58503e9753d6SMatthew G. Knepley PetscInt offsetI, NcI, NbI = 1, fc, f; 58513e9753d6SMatthew G. Knepley 58523e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 58539566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 58549566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI)); 58559566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fv, &id)); 58563e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 58573e9753d6SMatthew G. Knepley /* Put in the identity */ 58589566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcI)); 58593e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 58603e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 58613e9753d6SMatthew G. Knepley const PetscInt eOffset = cind * totDim * totDim; 58623e9753d6SMatthew G. Knepley for (fc = 0; fc < NcI; ++fc) { 58633e9753d6SMatthew G. Knepley for (f = 0; f < NbI; ++f) { 58643e9753d6SMatthew G. Knepley const PetscInt i = offsetI + f * NcI + fc; 58653e9753d6SMatthew G. Knepley if (hasPrec) { 5866ad540459SPierre Jolivet if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 58673e9753d6SMatthew G. Knepley elemMatP[eOffset + i * totDim + i] = 1.0; 58689371c9d4SSatish Balay } else { 58699371c9d4SSatish Balay elemMat[eOffset + i * totDim + i] = 1.0; 58709371c9d4SSatish Balay } 58713e9753d6SMatthew G. Knepley } 58723e9753d6SMatthew G. Knepley } 58733e9753d6SMatthew G. Knepley } 58743e9753d6SMatthew G. Knepley } 58753e9753d6SMatthew G. Knepley /* No allocated space for FV stuff, so ignore the zero entries */ 58769566063dSJacob Faibussowitsch PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); 58773e9753d6SMatthew G. Knepley } 58783e9753d6SMatthew G. Knepley /* Insert values into matrix */ 58793e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 58803e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 58813e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 58823e9753d6SMatthew G. Knepley 58833e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 58849566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * totDim])); 58853e9753d6SMatthew G. Knepley if (hasPrec) { 58863e9753d6SMatthew G. Knepley if (hasJac) { 58879566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5888e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 58893e9753d6SMatthew G. Knepley } 58909566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim])); 5891be62b2b4SMatthew G. Knepley PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES)); 58923e9753d6SMatthew G. Knepley } else { 58933e9753d6SMatthew G. Knepley if (hasJac) { 58949566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5895e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 58963e9753d6SMatthew G. Knepley } 58973e9753d6SMatthew G. Knepley } 58983e9753d6SMatthew G. Knepley } 58999566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 59009566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 59019566063dSJacob Faibussowitsch PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, elemMatD)); 59023e9753d6SMatthew G. Knepley if (dmAux) { 59039566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 59049566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 59053e9753d6SMatthew G. Knepley } 59063e9753d6SMatthew G. Knepley /* Compute boundary integrals */ 59079566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user)); 59083e9753d6SMatthew G. Knepley /* Assemble matrix */ 59099371c9d4SSatish Balay end : { 5910e04ae0b4SMatthew G. Knepley PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp; 5911e04ae0b4SMatthew G. Knepley 5912712fec58SPierre Jolivet PetscCall(MPIU_Allreduce(&assOp, &gassOp, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 59133e9753d6SMatthew G. Knepley if (hasJac && hasPrec) { 59149566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 59159566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 59163e9753d6SMatthew G. Knepley } 5917e04ae0b4SMatthew G. Knepley } 59189566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 59199566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 59209566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 59213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 59223e9753d6SMatthew G. Knepley } 59233e9753d6SMatthew G. Knepley 5924d71ae5a4SJacob 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) 5925d71ae5a4SJacob Faibussowitsch { 59263e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 59273e9753d6SMatthew G. Knepley const char *name = "Hybrid Jacobian"; 5928148442b3SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 5929148442b3SMatthew G. Knepley DMLabel ghostLabel = NULL; 59303e9753d6SMatthew G. Knepley DM plex = NULL; 59313e9753d6SMatthew G. Knepley DM plexA = NULL; 5932148442b3SMatthew G. Knepley PetscDS ds = NULL; 593307218a29SMatthew G. Knepley PetscDS dsIn = NULL; 5934148442b3SMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 5935148442b3SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 593607218a29SMatthew G. Knepley DM dmScale[3] = {NULL, NULL, NULL}; 593707218a29SMatthew G. Knepley PetscDS dsScale[3] = {NULL, NULL, NULL}; 593807218a29SMatthew G. Knepley Vec locS[3] = {NULL, NULL, NULL}; 59393e9753d6SMatthew G. Knepley PetscSection section = NULL; 5940148442b3SMatthew G. Knepley PetscSection sectionAux[3] = {NULL, NULL, NULL}; 59413e9753d6SMatthew G. Knepley DMField coordField = NULL; 594207218a29SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 594307218a29SMatthew G. Knepley PetscScalar *s[3] = {NULL, NULL, NULL}; 594407218a29SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 594507218a29SMatthew G. Knepley PetscScalar *elemMatNeg, *elemMatPos, *elemMatCoh; 594607218a29SMatthew G. Knepley PetscScalar *elemMatNegP, *elemMatPosP, *elemMatCohP; 5947e432b41dSStefano Zampini PetscSection globalSection; 59483e9753d6SMatthew G. Knepley IS chunkIS; 59493e9753d6SMatthew G. Knepley const PetscInt *cells; 59503e9753d6SMatthew G. Knepley PetscInt *faces; 59513e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 59523e2b0218SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk; 59533e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 59543e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 59553e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 5956e432b41dSStefano Zampini PetscBool hasBdJac, hasBdPrec; 59573e9753d6SMatthew G. Knepley 59583e9753d6SMatthew G. Knepley PetscFunctionBegin; 59593ba16761SJacob Faibussowitsch if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 5960437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5961437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 59623ba16761SJacob Faibussowitsch if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 59635fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 59645fedec97SMatthew G. Knepley const char *name; 59659566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 596663a3b9bcSJacob 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); 59675fedec97SMatthew G. Knepley } 59689566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 59699566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 59709566063dSJacob Faibussowitsch PetscCall(DMGetSection(dm, §ion)); 59719566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 59729566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 597307218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 59749566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 59759566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 597607218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn)); 59779566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac)); 59789566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec)); 59799566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 5980148442b3SMatthew G. Knepley if (locA[2]) { 59811059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 59821059d808SMatthew G. Knepley 59839566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 59849566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA)); 59859566063dSJacob Faibussowitsch PetscCall(DMGetSection(dmAux[2], §ionAux[2])); 598607218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL)); 59879566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 5988148442b3SMatthew G. Knepley { 5989148442b3SMatthew G. Knepley const PetscInt *cone; 5990148442b3SMatthew G. Knepley PetscInt c; 5991148442b3SMatthew G. Knepley 59921059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 5993148442b3SMatthew G. Knepley for (c = 0; c < 2; ++c) { 5994148442b3SMatthew G. Knepley const PetscInt *support; 5995148442b3SMatthew G. Knepley PetscInt ssize, s; 5996148442b3SMatthew G. Knepley 59979566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 59989566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 59991059d808SMatthew 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); 60001059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 60011059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 60021059d808SMatthew 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); 60039566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 60049566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 6005ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 600607218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL)); 60079566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 6008148442b3SMatthew G. Knepley } 6009148442b3SMatthew G. Knepley } 60103e9753d6SMatthew G. Knepley } 601107218a29SMatthew G. Knepley /* Handle mass matrix scaling 601207218a29SMatthew G. Knepley The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */ 601307218a29SMatthew G. Knepley PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2])); 601407218a29SMatthew G. Knepley if (locS[2]) { 60153e2b0218SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 601607218a29SMatthew G. Knepley PetscInt Nb, Nbs; 601707218a29SMatthew G. Knepley 601807218a29SMatthew G. Knepley PetscCall(VecGetDM(locS[2], &dmScale[2])); 601907218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[2], cells ? cells[cStart] : cStart, &dsScale[2], NULL)); 60203e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2])); 602107218a29SMatthew G. Knepley // BRAD: This is not set correctly 602207218a29SMatthew G. Knepley key[2].field = 2; 602307218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb)); 602407218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs)); 602507218a29SMatthew 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); 60263e2b0218SMatthew G. Knepley { 60273e2b0218SMatthew G. Knepley const PetscInt *cone; 60283e2b0218SMatthew G. Knepley PetscInt c; 60293e2b0218SMatthew G. Knepley 60303e2b0218SMatthew G. Knepley locS[1] = locS[0] = locS[2]; 60313e2b0218SMatthew G. Knepley dmScale[1] = dmScale[0] = dmScale[2]; 60323e2b0218SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 60333e2b0218SMatthew G. Knepley for (c = 0; c < 2; ++c) { 60343e2b0218SMatthew G. Knepley const PetscInt *support; 60353e2b0218SMatthew G. Knepley PetscInt ssize, s; 60363e2b0218SMatthew G. Knepley 60373e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 60383e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 60393e2b0218SMatthew 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); 60403e2b0218SMatthew G. Knepley if (support[0] == cellStart) s = 1; 60413e2b0218SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 60423e2b0218SMatthew 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); 60433e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL)); 60443e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c])); 60453e2b0218SMatthew G. Knepley } 60463e2b0218SMatthew G. Knepley } 604707218a29SMatthew G. Knepley } 604807218a29SMatthew G. Knepley /* 2: Setup geometric data */ 60499566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 60509566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 60513e9753d6SMatthew G. Knepley if (maxDegree > 1) { 60523e9753d6SMatthew G. Knepley PetscInt f; 60539566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 60543e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 60553e9753d6SMatthew G. Knepley PetscFE fe; 60563e9753d6SMatthew G. Knepley 60579566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 60583e9753d6SMatthew G. Knepley if (fe) { 60599566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 60609566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 60613e9753d6SMatthew G. Knepley } 60623e9753d6SMatthew G. Knepley } 60633e9753d6SMatthew G. Knepley } 606407218a29SMatthew G. Knepley /* Loop over chunks */ 60653e9753d6SMatthew G. Knepley cellChunkSize = numCells; 60663e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 606707218a29SMatthew G. Knepley PetscCall(PetscCalloc1(2 * cellChunkSize, &faces)); 6068a4158a15SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 606907218a29SMatthew G. Knepley /* Extract field coefficients */ 607007218a29SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 607107218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 607207218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 60738bf0a22dSMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 607407218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg)); 607507218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos)); 607607218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh)); 607707218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP)); 607807218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP)); 607907218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP)); 60803e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 60813e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 60823e9753d6SMatthew G. Knepley 608307218a29SMatthew G. Knepley if (hasBdJac) { 608407218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatNeg, cellChunkSize * totDim * totDim)); 608507218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatPos, cellChunkSize * totDim * totDim)); 608607218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatCoh, cellChunkSize * totDim * totDim)); 608707218a29SMatthew G. Knepley } 608807218a29SMatthew G. Knepley if (hasBdPrec) { 608907218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatNegP, cellChunkSize * totDim * totDim)); 609007218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatPosP, cellChunkSize * totDim * totDim)); 609107218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatCohP, cellChunkSize * totDim * totDim)); 609207218a29SMatthew G. Knepley } 60933e9753d6SMatthew G. Knepley /* Get faces */ 60943e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 60953e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 60963e9753d6SMatthew G. Knepley const PetscInt *cone; 60979566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(plex, cell, &cone)); 609807218a29SMatthew G. Knepley faces[(c - cS) * 2 + 0] = cone[0]; 609907218a29SMatthew G. Knepley faces[(c - cS) * 2 + 1] = cone[1]; 61003e9753d6SMatthew G. Knepley } 610107218a29SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER)); 61023e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 61039566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 61049566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 61053e9753d6SMatthew G. Knepley } else { 61063e9753d6SMatthew G. Knepley PetscInt f; 61073e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 61089566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 61093e9753d6SMatthew G. Knepley } 61103e9753d6SMatthew G. Knepley } 61113e9753d6SMatthew G. Knepley 61123e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 61133e9753d6SMatthew G. Knepley PetscFE feI; 61143e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI]; 61153e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 61163e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI]; 61173e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 61185fedec97SMatthew G. Knepley PetscBool isCohesiveField; 61193e9753d6SMatthew G. Knepley 61209566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI)); 61213e9753d6SMatthew G. Knepley if (!feI) continue; 61229566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches)); 61239566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 61249566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feI, &Nb)); 61253e9753d6SMatthew G. Knepley blockSize = Nb; 61263e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 61279566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches)); 61283e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 61293e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 61303e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 61313e9753d6SMatthew G. Knepley offset = numCells - Nr; 613207218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom)); 613307218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom)); 61349566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField)); 61353e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 61363e9753d6SMatthew G. Knepley PetscFE feJ; 61373e9753d6SMatthew G. Knepley 61389566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ)); 61393e9753d6SMatthew G. Knepley if (!feJ) continue; 6140148442b3SMatthew G. Knepley key[0].field = fieldI * Nf + fieldJ; 6141148442b3SMatthew G. Knepley key[1].field = fieldI * Nf + fieldJ; 61425fedec97SMatthew G. Knepley key[2].field = fieldI * Nf + fieldJ; 6143148442b3SMatthew G. Knepley if (hasBdJac) { 614407218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatNeg)); 6145*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[0], PetscSafePointerPlusOffset(a[0], offset * totDimAux[0]), t, X_tShift, &elemMatNeg[offset * totDim * totDim])); 614607218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatPos)); 6147*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[1], PetscSafePointerPlusOffset(a[1], offset * totDimAux[1]), t, X_tShift, &elemMatPos[offset * totDim * totDim])); 6148148442b3SMatthew G. Knepley } 6149148442b3SMatthew G. Knepley if (hasBdPrec) { 615007218a29SMatthew 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)); 6151*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[0], 0, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatNegP[offset * totDim * totDim])); 615207218a29SMatthew 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)); 6153*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[1], 1, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatPosP[offset * totDim * totDim])); 6154148442b3SMatthew G. Knepley } 61555fedec97SMatthew G. Knepley if (hasBdJac) { 615607218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatCoh)); 6157*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[2], PetscSafePointerPlusOffset(a[2], offset * totDimAux[2]), t, X_tShift, &elemMatCoh[offset * totDim * totDim])); 6158148442b3SMatthew G. Knepley } 61595fedec97SMatthew G. Knepley if (hasBdPrec) { 616007218a29SMatthew 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)); 6161*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[2], 2, Nr, remGeom, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatCohP[offset * totDim * totDim])); 61623e9753d6SMatthew G. Knepley } 61633e9753d6SMatthew G. Knepley } 61649566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 61659566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 61663e9753d6SMatthew G. Knepley } 61673e9753d6SMatthew G. Knepley /* Insert values into matrix */ 61683e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 61693e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 617007218a29SMatthew G. Knepley const PetscInt cind = c - cS, coff = cind * totDim * totDim; 617107218a29SMatthew G. Knepley PetscInt i, j; 61723e9753d6SMatthew G. Knepley 617307218a29SMatthew G. Knepley /* Scale element values */ 617407218a29SMatthew G. Knepley if (locS[0]) { 61753e2b0218SMatthew G. Knepley PetscInt Nb, soff = cind * totDimScale[0], off = 0; 617607218a29SMatthew G. Knepley PetscBool cohesive; 617707218a29SMatthew G. Knepley 617807218a29SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 617907218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, fieldI, &Nb)); 618007218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(ds, fieldI, &cohesive)); 618107218a29SMatthew G. Knepley 618207218a29SMatthew G. Knepley if (fieldI == key[2].field) { 618307218a29SMatthew G. Knepley PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields"); 61848bf0a22dSMatthew G. Knepley for (i = 0; i < Nb; ++i) { 618507218a29SMatthew 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]; 61868bf0a22dSMatthew G. Knepley if (hasBdPrec) 61878bf0a22dSMatthew 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]; 61888bf0a22dSMatthew G. Knepley } 618907218a29SMatthew G. Knepley off += Nb; 619007218a29SMatthew G. Knepley } else { 619107218a29SMatthew G. Knepley const PetscInt N = cohesive ? Nb : Nb * 2; 619207218a29SMatthew G. Knepley 61938bf0a22dSMatthew G. Knepley for (i = 0; i < N; ++i) { 619407218a29SMatthew 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]; 61958bf0a22dSMatthew G. Knepley if (hasBdPrec) 61968bf0a22dSMatthew 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]; 61978bf0a22dSMatthew G. Knepley } 619807218a29SMatthew G. Knepley off += N; 619907218a29SMatthew G. Knepley } 620007218a29SMatthew G. Knepley } 620107218a29SMatthew G. Knepley } else { 620207218a29SMatthew G. Knepley for (i = 0; i < totDim * totDim; ++i) elemMatCoh[coff + i] += elemMatNeg[coff + i] + elemMatPos[coff + i]; 62038bf0a22dSMatthew G. Knepley if (hasBdPrec) 62048bf0a22dSMatthew G. Knepley for (i = 0; i < totDim * totDim; ++i) elemMatCohP[coff + i] += elemMatNegP[coff + i] + elemMatPosP[coff + i]; 620507218a29SMatthew G. Knepley } 62063e9753d6SMatthew G. Knepley if (hasBdPrec) { 62073e9753d6SMatthew G. Knepley if (hasBdJac) { 620807218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim])); 6209e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES)); 62103e9753d6SMatthew G. Knepley } 621107218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCohP[cind * totDim * totDim])); 621207218a29SMatthew G. Knepley PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatCohP[cind * totDim * totDim], ADD_VALUES)); 62133e9753d6SMatthew G. Knepley } else if (hasBdJac) { 621407218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim])); 6215e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES)); 62163e9753d6SMatthew G. Knepley } 62173e9753d6SMatthew G. Knepley } 62183e9753d6SMatthew G. Knepley } 62199566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 622007218a29SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 622107218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg)); 622207218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos)); 622307218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh)); 622407218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP)); 622507218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP)); 622607218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP)); 62279566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 62289566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 62299566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 62303e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 62319566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 62329566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 62333e9753d6SMatthew G. Knepley } else { 62343e9753d6SMatthew G. Knepley PetscInt f; 62353e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 62369566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 62379566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 62383e9753d6SMatthew G. Knepley } 62399566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 62403e9753d6SMatthew G. Knepley } 62419566063dSJacob Faibussowitsch if (dmAux[2]) PetscCall(DMDestroy(&plexA)); 62429566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 62439566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 62443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 62453e9753d6SMatthew G. Knepley } 62468e3a2eefSMatthew G. Knepley 62478e3a2eefSMatthew G. Knepley /* 62488e3a2eefSMatthew 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. 62498e3a2eefSMatthew G. Knepley 62508e3a2eefSMatthew G. Knepley Input Parameters: 62518e3a2eefSMatthew G. Knepley + dm - The mesh 6252baca6076SPierre Jolivet . key - The PetscWeakFormKey indicating where integration should happen 625306ad1575SMatthew G. Knepley . cellIS - The cells to integrate over 62548e3a2eefSMatthew G. Knepley . t - The time 6255145b44c9SPierre Jolivet . X_tShift - The multiplier for the Jacobian with respect to X_t 62568e3a2eefSMatthew G. Knepley . X - Local solution vector 62578e3a2eefSMatthew G. Knepley . X_t - Time-derivative of the local solution vector 62588e3a2eefSMatthew G. Knepley . Y - Local input vector 625906ad1575SMatthew G. Knepley - user - the user context 62608e3a2eefSMatthew G. Knepley 62618e3a2eefSMatthew G. Knepley Output Parameter: 62628e3a2eefSMatthew G. Knepley . Z - Local output vector 62638e3a2eefSMatthew G. Knepley 62648e3a2eefSMatthew G. Knepley Note: 62658e3a2eefSMatthew G. Knepley We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 62668e3a2eefSMatthew G. Knepley like a GPU, or vectorize on a multicore machine. 62678e3a2eefSMatthew G. Knepley */ 6268d71ae5a4SJacob 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) 6269d71ae5a4SJacob Faibussowitsch { 62708e3a2eefSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 62718e3a2eefSMatthew G. Knepley const char *name = "Jacobian"; 62728e3a2eefSMatthew G. Knepley DM dmAux = NULL, plex, plexAux = NULL; 62738e3a2eefSMatthew G. Knepley DMEnclosureType encAux; 62748e3a2eefSMatthew G. Knepley Vec A; 62758e3a2eefSMatthew G. Knepley DMField coordField; 62768e3a2eefSMatthew G. Knepley PetscDS prob, probAux = NULL; 62778e3a2eefSMatthew G. Knepley PetscQuadrature quad; 62788e3a2eefSMatthew G. Knepley PetscSection section, globalSection, sectionAux; 62798e3a2eefSMatthew G. Knepley PetscScalar *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z; 62808e3a2eefSMatthew G. Knepley const PetscInt *cells; 62818e3a2eefSMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 62828e3a2eefSMatthew G. Knepley PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 62838e3a2eefSMatthew G. Knepley PetscBool hasDyn; 62848e3a2eefSMatthew G. Knepley 62858e3a2eefSMatthew G. Knepley PetscFunctionBegin; 628621d77094SMatthew G. Knepley if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 62879566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 62889566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 62899566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 62909566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 62919566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 62929566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 629307218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 62949566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 62959566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 62969566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 62978e3a2eefSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 62989566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 62998e3a2eefSMatthew G. Knepley if (A) { 63009566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 63019566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 63029566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexAux)); 63039566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexAux, §ionAux)); 63049566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 63059566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 63068e3a2eefSMatthew G. Knepley } 63079566063dSJacob Faibussowitsch PetscCall(VecSet(Z, 0.0)); 63089566063dSJacob 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)); 63099566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 63109566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 63118e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 63128e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 63138e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 63148e3a2eefSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 63158e3a2eefSMatthew G. Knepley PetscInt i; 63168e3a2eefSMatthew G. Knepley 63179566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X, cell, NULL, &x)); 63188e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 63199566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x)); 63208e3a2eefSMatthew G. Knepley if (X_t) { 63219566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t)); 63228e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 63239566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t)); 63248e3a2eefSMatthew G. Knepley } 63258e3a2eefSMatthew G. Knepley if (dmAux) { 63268e3a2eefSMatthew G. Knepley PetscInt subcell; 63279566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 63289566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 63298e3a2eefSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 63309566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 63318e3a2eefSMatthew G. Knepley } 63329566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x)); 63338e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) y[cind * totDim + i] = x[i]; 63349566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x)); 63358e3a2eefSMatthew G. Knepley } 63369566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 63379566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 63388e3a2eefSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 63398e3a2eefSMatthew G. Knepley PetscFE fe; 63408e3a2eefSMatthew G. Knepley PetscInt Nb; 63418e3a2eefSMatthew G. Knepley /* Conforming batches */ 63428e3a2eefSMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 63438e3a2eefSMatthew G. Knepley /* Remainder */ 63448e3a2eefSMatthew G. Knepley PetscInt Nr, offset, Nq; 63458e3a2eefSMatthew G. Knepley PetscQuadrature qGeom = NULL; 63468e3a2eefSMatthew G. Knepley PetscInt maxDegree; 63478e3a2eefSMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 63488e3a2eefSMatthew G. Knepley 63499566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 63509566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 63519566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 63529566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 63539566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 63549566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 63558e3a2eefSMatthew G. Knepley if (!qGeom) { 63569566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 63579566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 63588e3a2eefSMatthew G. Knepley } 63599566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 63609566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 63618e3a2eefSMatthew G. Knepley blockSize = Nb; 63628e3a2eefSMatthew G. Knepley batchSize = numBlocks * blockSize; 63639566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 63648e3a2eefSMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 63658e3a2eefSMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 63668e3a2eefSMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 63678e3a2eefSMatthew G. Knepley offset = numCells - Nr; 63689566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 63699566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 63708e3a2eefSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 63718e3a2eefSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 63729566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 6373*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMat[offset * totDim * totDim])); 63748e3a2eefSMatthew G. Knepley if (hasDyn) { 63759566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 6376*8e3a54c0SPierre Jolivet PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, &a[offset * totDimAux], t, X_tShift, &elemMatD[offset * totDim * totDim])); 63778e3a2eefSMatthew G. Knepley } 63788e3a2eefSMatthew G. Knepley } 63799566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 63809566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 63819566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 63829566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 63838e3a2eefSMatthew G. Knepley } 63848e3a2eefSMatthew G. Knepley if (hasDyn) { 63858e3a2eefSMatthew G. Knepley for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 63868e3a2eefSMatthew G. Knepley } 63878e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 63888e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 63898e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 63908e3a2eefSMatthew G. Knepley const PetscBLASInt M = totDim, one = 1; 63918e3a2eefSMatthew G. Knepley const PetscScalar a = 1.0, b = 0.0; 63928e3a2eefSMatthew G. Knepley 6393792fecdfSBarry Smith PetscCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind * totDim * totDim], &M, &y[cind * totDim], &one, &b, z, &one)); 63948e3a2eefSMatthew G. Knepley if (mesh->printFEM > 1) { 63959566063dSJacob Faibussowitsch PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 63969566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind * totDim])); 63979566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Z", totDim, z)); 63988e3a2eefSMatthew G. Knepley } 63999566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES)); 64008e3a2eefSMatthew G. Knepley } 64019566063dSJacob Faibussowitsch PetscCall(PetscFree6(u, u_t, elemMat, elemMatD, y, z)); 64028e3a2eefSMatthew G. Knepley if (mesh->printFEM) { 64039566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n")); 64049566063dSJacob Faibussowitsch PetscCall(VecView(Z, NULL)); 64058e3a2eefSMatthew G. Knepley } 64061059d808SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 64079566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 64089566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexAux)); 64099566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 64109566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 64113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 64128e3a2eefSMatthew G. Knepley } 6413