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); 1302cac4c232SBarry Smith PetscTryMethod(dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX_t, time, faceGeomFVM, cellGeomFVM, gradFVM)); 13033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 130456cf3b9cSMatthew G. Knepley } 130556cf3b9cSMatthew G. Knepley 1306*5962854dSMatthew G. Knepley // Handle non-essential (e.g. outflow) boundary values 1307*5962854dSMatthew G. Knepley PetscErrorCode DMPlexInsertBoundaryValuesFVM(DM dm, PetscFV fv, Vec locX, PetscReal time, Vec *locGradient) 1308*5962854dSMatthew G. Knepley { 1309*5962854dSMatthew G. Knepley DM dmGrad; 1310*5962854dSMatthew G. Knepley Vec cellGeometryFVM, faceGeometryFVM, locGrad = NULL; 1311*5962854dSMatthew G. Knepley 1312*5962854dSMatthew G. Knepley PetscFunctionBegin; 1313*5962854dSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1314*5962854dSMatthew G. Knepley PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 1315*5962854dSMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 1316*5962854dSMatthew G. Knepley if (locGradient) { 1317*5962854dSMatthew G. Knepley PetscAssertPointer(locGradient, 5); 1318*5962854dSMatthew G. Knepley *locGradient = NULL; 1319*5962854dSMatthew G. Knepley } 1320*5962854dSMatthew G. Knepley PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 1321*5962854dSMatthew G. Knepley /* Reconstruct and limit cell gradients */ 1322*5962854dSMatthew G. Knepley PetscCall(DMPlexGetGradientDM(dm, fv, &dmGrad)); 1323*5962854dSMatthew G. Knepley if (dmGrad) { 1324*5962854dSMatthew G. Knepley Vec grad; 1325*5962854dSMatthew G. Knepley PetscInt fStart, fEnd; 1326*5962854dSMatthew G. Knepley 1327*5962854dSMatthew G. Knepley PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1328*5962854dSMatthew G. Knepley PetscCall(DMGetGlobalVector(dmGrad, &grad)); 1329*5962854dSMatthew G. Knepley PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 1330*5962854dSMatthew G. Knepley /* Communicate gradient values */ 1331*5962854dSMatthew G. Knepley PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 1332*5962854dSMatthew G. Knepley PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 1333*5962854dSMatthew G. Knepley PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 1334*5962854dSMatthew G. Knepley PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 1335*5962854dSMatthew G. Knepley } 1336*5962854dSMatthew G. Knepley PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad)); 1337*5962854dSMatthew G. Knepley if (locGradient) *locGradient = locGrad; 1338*5962854dSMatthew G. Knepley else if (locGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 1339*5962854dSMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 1340*5962854dSMatthew G. Knepley } 1341*5962854dSMatthew 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 2171d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, 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; 2176338f77d5SMatthew G. Knepley Vec locX, 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; 2182338f77d5SMatthew G. Knepley PetscScalar *u, *a; 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 /* Get local solution with boundary values */ 22109566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &locX)); 22119566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 22129566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 22139566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 2214338f77d5SMatthew G. Knepley /* Read DS information */ 22159566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 22169566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 22179566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 22189566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, numCells, cStart, 1, &cellIS)); 22199566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 2220338f77d5SMatthew G. Knepley /* Read Auxiliary DS information */ 22219566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 22229a2a23afSMatthew G. Knepley if (locA) { 22239566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 22249566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 22259566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 22269566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 22279566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 22289566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 2229338f77d5SMatthew G. Knepley } 2230338f77d5SMatthew G. Knepley /* Allocate data arrays */ 22319566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numCells * totDim, &u)); 22329566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 2233338f77d5SMatthew G. Knepley /* Read out geometry */ 22349566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 22359566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 2236b7260050SToby Isaac if (maxDegree <= 1) { 22379566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 223848a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &cgeomFEM)); 2239b5a3613cSMatthew G. Knepley } 2240b5a3613cSMatthew G. Knepley if (useFVM) { 2241338f77d5SMatthew G. Knepley PetscFV fv = NULL; 2242b5a3613cSMatthew G. Knepley Vec grad; 2243b5a3613cSMatthew G. Knepley PetscInt fStart, fEnd; 2244b5a3613cSMatthew G. Knepley PetscBool compGrad; 2245b5a3613cSMatthew G. Knepley 2246338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2247338f77d5SMatthew G. Knepley PetscObject obj; 2248338f77d5SMatthew G. Knepley PetscClassId id; 2249338f77d5SMatthew G. Knepley 22509566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 22519566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 22529371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 22539371c9d4SSatish Balay fv = (PetscFV)obj; 22549371c9d4SSatish Balay break; 22559371c9d4SSatish Balay } 2256338f77d5SMatthew G. Knepley } 22579566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &compGrad)); 22589566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, PETSC_TRUE)); 22599566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM)); 22609566063dSJacob Faibussowitsch PetscCall(DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad)); 22619566063dSJacob Faibussowitsch PetscCall(PetscFVSetComputeGradients(fv, compGrad)); 22629566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 2263b5a3613cSMatthew G. Knepley /* Reconstruct and limit cell gradients */ 22649566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 22659566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmGrad, &grad)); 22669566063dSJacob Faibussowitsch PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 2267b5a3613cSMatthew G. Knepley /* Communicate gradient values */ 22689566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 22699566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 22709566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 22719566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 2272b5a3613cSMatthew G. Knepley /* Handle non-essential (e.g. outflow) boundary values */ 22739566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad)); 22749566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 2275b5a3613cSMatthew G. Knepley } 2276338f77d5SMatthew G. Knepley /* Read out data from inputs */ 227773d901b8SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 227873d901b8SMatthew G. Knepley PetscScalar *x = NULL; 227973d901b8SMatthew G. Knepley PetscInt i; 228073d901b8SMatthew G. Knepley 22819566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, c, NULL, &x)); 22820f2d7e86SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 22839566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x)); 228473d901b8SMatthew G. Knepley if (dmAux) { 22859566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x)); 22860f2d7e86SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 22879566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x)); 228873d901b8SMatthew G. Knepley } 228973d901b8SMatthew G. Knepley } 2290338f77d5SMatthew G. Knepley /* Do integration for each field */ 229173d901b8SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 2292c1f031eeSMatthew G. Knepley PetscObject obj; 2293c1f031eeSMatthew G. Knepley PetscClassId id; 2294c1f031eeSMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 229573d901b8SMatthew G. Knepley 22969566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 22979566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 2298c1f031eeSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 2299c1f031eeSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2300c1f031eeSMatthew G. Knepley PetscQuadrature q; 2301c330f8ffSToby Isaac PetscFEGeom *chunkGeom = NULL; 2302c1f031eeSMatthew G. Knepley PetscInt Nq, Nb; 2303c1f031eeSMatthew G. Knepley 23049566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 23059566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 23069566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 23079566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 2308c1f031eeSMatthew G. Knepley blockSize = Nb * Nq; 230973d901b8SMatthew G. Knepley batchSize = numBlocks * blockSize; 23109566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 231173d901b8SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 231273d901b8SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 231373d901b8SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 231473d901b8SMatthew G. Knepley offset = numCells - Nr; 231548a46eb9SPierre Jolivet if (!affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, q, PETSC_FALSE, &cgeomFEM)); 23169566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 23179566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral)); 23189566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &chunkGeom)); 23199566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset * totDim], probAux, &a[offset * totDimAux], &cintegral[offset * Nf])); 23209566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &chunkGeom)); 232148a46eb9SPierre Jolivet if (!affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 2322c1f031eeSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 2323c1f031eeSMatthew G. Knepley PetscInt foff; 2324420e96edSMatthew G. Knepley PetscPointFunc obj_func; 2325b69edc29SMatthew G. Knepley PetscScalar lint; 2326c1f031eeSMatthew G. Knepley 23279566063dSJacob Faibussowitsch PetscCall(PetscDSGetObjective(prob, f, &obj_func)); 23289566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, f, &foff)); 2329c1f031eeSMatthew G. Knepley if (obj_func) { 2330c1f031eeSMatthew G. Knepley for (c = 0; c < numCells; ++c) { 2331b5a3613cSMatthew G. Knepley PetscScalar *u_x; 2332b5a3613cSMatthew G. Knepley 23339566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x)); 2334338f77d5SMatthew 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); 2335338f77d5SMatthew G. Knepley cintegral[c * Nf + f] += PetscRealPart(lint) * cgeomFVM[c].volume; 233673d901b8SMatthew G. Knepley } 2337c1f031eeSMatthew G. Knepley } 233863a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 2339c1f031eeSMatthew G. Knepley } 2340338f77d5SMatthew G. Knepley /* Cleanup data arrays */ 2341b5a3613cSMatthew G. Knepley if (useFVM) { 23429566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 23439566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 23449566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 23459566063dSJacob Faibussowitsch PetscCall(VecDestroy(&faceGeometryFVM)); 23469566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cellGeometryFVM)); 23479566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dmGrad)); 2348b5a3613cSMatthew G. Knepley } 23499566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscFree(a)); 23509566063dSJacob Faibussowitsch PetscCall(PetscFree(u)); 2351338f77d5SMatthew G. Knepley /* Cleanup */ 235248a46eb9SPierre Jolivet if (affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 23539566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 23549566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 23559566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &locX)); 23563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2357338f77d5SMatthew G. Knepley } 2358338f77d5SMatthew G. Knepley 2359338f77d5SMatthew G. Knepley /*@ 2360338f77d5SMatthew G. Knepley DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user 2361338f77d5SMatthew G. Knepley 2362338f77d5SMatthew G. Knepley Input Parameters: 2363338f77d5SMatthew G. Knepley + dm - The mesh 2364338f77d5SMatthew G. Knepley . X - Global input vector 2365338f77d5SMatthew G. Knepley - user - The user context 2366338f77d5SMatthew G. Knepley 2367338f77d5SMatthew G. Knepley Output Parameter: 2368338f77d5SMatthew G. Knepley . integral - Integral for each field 2369338f77d5SMatthew G. Knepley 2370338f77d5SMatthew G. Knepley Level: developer 2371338f77d5SMatthew G. Knepley 23721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2373338f77d5SMatthew G. Knepley @*/ 2374d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user) 2375d71ae5a4SJacob Faibussowitsch { 2376338f77d5SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2377b8feb594SMatthew G. Knepley PetscScalar *cintegral, *lintegral; 2378412e9a14SMatthew G. Knepley PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 2379338f77d5SMatthew G. Knepley 2380338f77d5SMatthew G. Knepley PetscFunctionBegin; 2381338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2382338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 23834f572ea9SToby Isaac PetscAssertPointer(integral, 3); 23849566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 23859566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 23869566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 23879566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2388338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 23899566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &lintegral, (cEnd - cStart) * Nf, &cintegral)); 23909566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user)); 2391338f77d5SMatthew G. Knepley /* Sum up values */ 2392338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2393338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 2394338f77d5SMatthew G. Knepley 23959566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 2396b8feb594SMatthew G. Knepley for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c * Nf + f]; 2397338f77d5SMatthew G. Knepley } 23981c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 239973d901b8SMatthew G. Knepley if (mesh->printFEM) { 24009566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Integral:")); 24019566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), " %g", (double)PetscRealPart(integral[f]))); 24029566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "\n")); 240373d901b8SMatthew G. Knepley } 24049566063dSJacob Faibussowitsch PetscCall(PetscFree2(lintegral, cintegral)); 24059566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 24063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2407338f77d5SMatthew G. Knepley } 2408338f77d5SMatthew G. Knepley 2409338f77d5SMatthew G. Knepley /*@ 2410338f77d5SMatthew G. Knepley DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user 2411338f77d5SMatthew G. Knepley 2412338f77d5SMatthew G. Knepley Input Parameters: 2413338f77d5SMatthew G. Knepley + dm - The mesh 2414338f77d5SMatthew G. Knepley . X - Global input vector 2415338f77d5SMatthew G. Knepley - user - The user context 2416338f77d5SMatthew G. Knepley 2417338f77d5SMatthew G. Knepley Output Parameter: 241860225df5SJacob Faibussowitsch . F - Cellwise integrals for each field 2419338f77d5SMatthew G. Knepley 2420338f77d5SMatthew G. Knepley Level: developer 2421338f77d5SMatthew G. Knepley 24221cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2423338f77d5SMatthew G. Knepley @*/ 2424d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user) 2425d71ae5a4SJacob Faibussowitsch { 2426338f77d5SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 2427338f77d5SMatthew G. Knepley DM dmF; 2428338f77d5SMatthew G. Knepley PetscSection sectionF; 2429338f77d5SMatthew G. Knepley PetscScalar *cintegral, *af; 2430412e9a14SMatthew G. Knepley PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 2431338f77d5SMatthew G. Knepley 2432338f77d5SMatthew G. Knepley PetscFunctionBegin; 2433338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2434338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2435338f77d5SMatthew G. Knepley PetscValidHeaderSpecific(F, VEC_CLASSID, 3); 24369566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 24379566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 24389566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 24399566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2440338f77d5SMatthew G. Knepley /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 24419566063dSJacob Faibussowitsch PetscCall(PetscCalloc1((cEnd - cStart) * Nf, &cintegral)); 24429566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user)); 2443338f77d5SMatthew G. Knepley /* Put values in F*/ 24449566063dSJacob Faibussowitsch PetscCall(VecGetDM(F, &dmF)); 24459566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmF, §ionF)); 24469566063dSJacob Faibussowitsch PetscCall(VecGetArray(F, &af)); 2447338f77d5SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2448338f77d5SMatthew G. Knepley const PetscInt c = cell - cStart; 2449338f77d5SMatthew G. Knepley PetscInt dof, off; 2450338f77d5SMatthew G. Knepley 24519566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 24529566063dSJacob Faibussowitsch PetscCall(PetscSectionGetDof(sectionF, cell, &dof)); 24539566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(sectionF, cell, &off)); 245463a3b9bcSJacob Faibussowitsch PetscCheck(dof == Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %" PetscInt_FMT " != %" PetscInt_FMT, dof, Nf); 2455338f77d5SMatthew G. Knepley for (f = 0; f < Nf; ++f) af[off + f] = cintegral[c * Nf + f]; 2456338f77d5SMatthew G. Knepley } 24579566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(F, &af)); 24589566063dSJacob Faibussowitsch PetscCall(PetscFree(cintegral)); 24599566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 24603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 246173d901b8SMatthew G. Knepley } 246273d901b8SMatthew G. Knepley 2463d71ae5a4SJacob 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) 2464d71ae5a4SJacob Faibussowitsch { 24659b6f715bSMatthew G. Knepley DM plex = NULL, plexA = NULL; 2466a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 24679b6f715bSMatthew G. Knepley PetscDS prob, probAux = NULL; 24689b6f715bSMatthew G. Knepley PetscSection section, sectionAux = NULL; 24699b6f715bSMatthew G. Knepley Vec locA = NULL; 24709b6f715bSMatthew G. Knepley DMField coordField; 24719b6f715bSMatthew G. Knepley PetscInt Nf, totDim, *uOff, *uOff_x; 24729b6f715bSMatthew G. Knepley PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL; 24739b6f715bSMatthew G. Knepley PetscScalar *u, *a = NULL; 247464c72086SMatthew G. Knepley const PetscScalar *constants; 24759b6f715bSMatthew G. Knepley PetscInt numConstants, f; 247664c72086SMatthew G. Knepley 247764c72086SMatthew G. Knepley PetscFunctionBegin; 24789566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 24799566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 24809566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 24819566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 24829566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 248364c72086SMatthew G. Knepley /* Determine which discretizations we have */ 24849b6f715bSMatthew G. Knepley for (f = 0; f < Nf; ++f) { 248564c72086SMatthew G. Knepley PetscObject obj; 248664c72086SMatthew G. Knepley PetscClassId id; 248764c72086SMatthew G. Knepley 24889566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 24899566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 249063a3b9bcSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not supported for FVM (field %" PetscInt_FMT ")", f); 249164c72086SMatthew G. Knepley } 249264c72086SMatthew G. Knepley /* Read DS information */ 24939566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 24949566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 24959566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 24969566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 249764c72086SMatthew G. Knepley /* Read Auxiliary DS information */ 24989566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 24999b6f715bSMatthew G. Knepley if (locA) { 25009b6f715bSMatthew G. Knepley DM dmAux; 25019b6f715bSMatthew G. Knepley 25029566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 25039566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 25049566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 25059566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 25069566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 25079566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 25089566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 25099566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 251064c72086SMatthew G. Knepley } 25119b6f715bSMatthew G. Knepley /* Integrate over points */ 25129b6f715bSMatthew G. Knepley { 25139b6f715bSMatthew G. Knepley PetscFEGeom *fgeom, *chunkGeom = NULL; 2514b7260050SToby Isaac PetscInt maxDegree; 25159b6f715bSMatthew G. Knepley PetscQuadrature qGeom = NULL; 25169b6f715bSMatthew G. Knepley const PetscInt *points; 25179b6f715bSMatthew G. Knepley PetscInt numFaces, face, Nq, field; 25189b6f715bSMatthew G. Knepley PetscInt numChunks, chunkSize, chunk, Nr, offset; 251964c72086SMatthew G. Knepley 25209566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 25219566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 25229566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFaces * totDim, &u, locA ? numFaces * totDimAux : 0, &a)); 25239566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 252464c72086SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 252564c72086SMatthew G. Knepley PetscFE fe; 252664c72086SMatthew G. Knepley 25279566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe)); 25289566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 25299b6f715bSMatthew G. Knepley if (!qGeom) { 25309566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 25319566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 25329b6f715bSMatthew G. Knepley } 25339566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 25349566063dSJacob Faibussowitsch PetscCall(DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 25359b6f715bSMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 2536f15274beSMatthew Knepley const PetscInt point = points[face], *support; 25379b6f715bSMatthew G. Knepley PetscScalar *x = NULL; 2538f15274beSMatthew Knepley PetscInt i; 25399b6f715bSMatthew G. Knepley 25409566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 25419566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 25429b6f715bSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 25439566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 25449b6f715bSMatthew G. Knepley if (locA) { 25459b6f715bSMatthew G. Knepley PetscInt subp; 25469566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 25479566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 25489b6f715bSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[f * totDimAux + i] = x[i]; 25499566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 25509b6f715bSMatthew G. Knepley } 25519b6f715bSMatthew G. Knepley } 25529b6f715bSMatthew G. Knepley /* Get blocking */ 25539b6f715bSMatthew G. Knepley { 25549b6f715bSMatthew G. Knepley PetscQuadrature q; 25559b6f715bSMatthew G. Knepley PetscInt numBatches, batchSize, numBlocks, blockSize; 25569b6f715bSMatthew G. Knepley PetscInt Nq, Nb; 25579b6f715bSMatthew G. Knepley 25589566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 25599566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 25609566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 25619566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 256264c72086SMatthew G. Knepley blockSize = Nb * Nq; 256364c72086SMatthew G. Knepley batchSize = numBlocks * blockSize; 25649b6f715bSMatthew G. Knepley chunkSize = numBatches * batchSize; 25659566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 25669b6f715bSMatthew G. Knepley numChunks = numFaces / chunkSize; 25679b6f715bSMatthew G. Knepley Nr = numFaces % chunkSize; 256864c72086SMatthew G. Knepley offset = numFaces - Nr; 256964c72086SMatthew G. Knepley } 25709b6f715bSMatthew G. Knepley /* Do integration for each field */ 25719b6f715bSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 25729566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, chunk * chunkSize, (chunk + 1) * chunkSize, &chunkGeom)); 25739566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral)); 25749566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 257564c72086SMatthew G. Knepley } 25769566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 25779566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset * totDim], probAux, a ? &a[offset * totDimAux] : NULL, &fintegral[offset * Nf])); 25789566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 257964c72086SMatthew G. Knepley /* Cleanup data arrays */ 25809566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 25819566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 25829566063dSJacob Faibussowitsch PetscCall(PetscFree2(u, a)); 25839566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 258464c72086SMatthew G. Knepley } 258564c72086SMatthew G. Knepley } 25869566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 25879566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 25883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 25899b6f715bSMatthew G. Knepley } 25909b6f715bSMatthew G. Knepley 259160225df5SJacob Faibussowitsch /*@C 25929b6f715bSMatthew G. Knepley DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user 25939b6f715bSMatthew G. Knepley 25949b6f715bSMatthew G. Knepley Input Parameters: 25959b6f715bSMatthew G. Knepley + dm - The mesh 25969b6f715bSMatthew G. Knepley . X - Global input vector 2597a1cb98faSBarry Smith . label - The boundary `DMLabel` 2598a1cb98faSBarry Smith . numVals - The number of label values to use, or `PETSC_DETERMINE` for all values 2599a1cb98faSBarry Smith . vals - The label values to use, or NULL for all values 260067b8a455SSatish Balay . func - The function to integrate along the boundary 26019b6f715bSMatthew G. Knepley - user - The user context 26029b6f715bSMatthew G. Knepley 26039b6f715bSMatthew G. Knepley Output Parameter: 26049b6f715bSMatthew G. Knepley . integral - Integral for each field 26059b6f715bSMatthew G. Knepley 26069b6f715bSMatthew G. Knepley Level: developer 26079b6f715bSMatthew G. Knepley 26081cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeIntegralFEM()`, `DMPlexComputeBdResidualFEM()` 26099b6f715bSMatthew G. Knepley @*/ 2610d71ae5a4SJacob 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) 2611d71ae5a4SJacob Faibussowitsch { 26129b6f715bSMatthew G. Knepley Vec locX; 26139b6f715bSMatthew G. Knepley PetscSection section; 26149b6f715bSMatthew G. Knepley DMLabel depthLabel; 26159b6f715bSMatthew G. Knepley IS facetIS; 26169b6f715bSMatthew G. Knepley PetscInt dim, Nf, f, v; 26179b6f715bSMatthew G. Knepley 26189b6f715bSMatthew G. Knepley PetscFunctionBegin; 26199b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 26209b6f715bSMatthew G. Knepley PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2621292bffcbSToby Isaac PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 26224f572ea9SToby Isaac if (vals) PetscAssertPointer(vals, 5); 26234f572ea9SToby Isaac PetscAssertPointer(integral, 7); 26249566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 26259566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 26269566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 26279566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 26289566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 26299566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(section, &Nf)); 26309b6f715bSMatthew G. Knepley /* Get local solution with boundary values */ 26319566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(dm, &locX)); 26329566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 26339566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 26349566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 26359b6f715bSMatthew G. Knepley /* Loop over label values */ 26369566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(integral, Nf)); 26379b6f715bSMatthew G. Knepley for (v = 0; v < numVals; ++v) { 26389b6f715bSMatthew G. Knepley IS pointIS; 26399b6f715bSMatthew G. Knepley PetscInt numFaces, face; 26409b6f715bSMatthew G. Knepley PetscScalar *fintegral; 26419b6f715bSMatthew G. Knepley 26429566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, vals[v], &pointIS)); 26439b6f715bSMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 26449b6f715bSMatthew G. Knepley { 26459b6f715bSMatthew G. Knepley IS isectIS; 26469b6f715bSMatthew G. Knepley 26479b6f715bSMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 26489566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 26499566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 26509b6f715bSMatthew G. Knepley pointIS = isectIS; 26519b6f715bSMatthew G. Knepley } 26529566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 26539566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(numFaces * Nf, &fintegral)); 26549566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user)); 26559b6f715bSMatthew G. Knepley /* Sum point contributions into integral */ 26569371c9d4SSatish Balay for (f = 0; f < Nf; ++f) 26579371c9d4SSatish Balay for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face * Nf + f]; 26589566063dSJacob Faibussowitsch PetscCall(PetscFree(fintegral)); 26599566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 26609b6f715bSMatthew G. Knepley } 26619566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(dm, &locX)); 26629566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 26639566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 26643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 266564c72086SMatthew G. Knepley } 266664c72086SMatthew G. Knepley 2667d69c5d34SMatthew G. Knepley /*@ 2668a1cb98faSBarry Smith DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse `DM` to a uniformly refined `DM`. 2669d69c5d34SMatthew G. Knepley 2670d69c5d34SMatthew G. Knepley Input Parameters: 2671cf51de39SMatthew G. Knepley + dmc - The coarse mesh 2672cf51de39SMatthew G. Knepley . dmf - The fine mesh 2673cf51de39SMatthew G. Knepley . isRefined - Flag indicating regular refinement, rather than the same topology 2674d69c5d34SMatthew G. Knepley - user - The user context 2675d69c5d34SMatthew G. Knepley 2676d69c5d34SMatthew G. Knepley Output Parameter: 2677934789fcSMatthew G. Knepley . In - The interpolation matrix 2678d69c5d34SMatthew G. Knepley 2679d69c5d34SMatthew G. Knepley Level: developer 2680d69c5d34SMatthew G. Knepley 26811cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()` 2682d69c5d34SMatthew G. Knepley @*/ 2683d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user) 2684d71ae5a4SJacob Faibussowitsch { 2685d69c5d34SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmc->data; 2686d69c5d34SMatthew G. Knepley const char *name = "Interpolator"; 2687d69c5d34SMatthew G. Knepley PetscFE *feRef; 268897c42addSMatthew G. Knepley PetscFV *fvRef; 2689d69c5d34SMatthew G. Knepley PetscSection fsection, fglobalSection; 2690d69c5d34SMatthew G. Knepley PetscSection csection, cglobalSection; 2691d69c5d34SMatthew G. Knepley PetscScalar *elemMat; 2692485ad865SMatthew G. Knepley PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c; 26932ea9c922SToby Isaac PetscInt cTotDim = 0, rTotDim = 0; 2694d69c5d34SMatthew G. Knepley 2695d69c5d34SMatthew G. Knepley PetscFunctionBegin; 26969566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 26979566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 26989566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 26999566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 27009566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 27019566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 27029566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 27039566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 27049566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &feRef, Nf, &fvRef)); 2705d69c5d34SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 27062ea9c922SToby Isaac PetscObject obj, objc; 27072ea9c922SToby Isaac PetscClassId id, idc; 27082ea9c922SToby Isaac PetscInt rNb = 0, Nc = 0, cNb = 0; 2709d69c5d34SMatthew G. Knepley 27109566063dSJacob Faibussowitsch PetscCall(DMGetField(dmf, f, NULL, &obj)); 27119566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 271297c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 271397c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 271497c42addSMatthew G. Knepley 2715cf51de39SMatthew G. Knepley if (isRefined) { 27169566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 2717cf51de39SMatthew G. Knepley } else { 27189566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fe)); 2719cf51de39SMatthew G. Knepley feRef[f] = fe; 2720cf51de39SMatthew G. Knepley } 27219566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &rNb)); 27229566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 272397c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 272497c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 272597c42addSMatthew G. Knepley PetscDualSpace Q; 272697c42addSMatthew G. Knepley 2727cf51de39SMatthew G. Knepley if (isRefined) { 27289566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 2729cf51de39SMatthew G. Knepley } else { 27309566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)fv)); 2731cf51de39SMatthew G. Knepley fvRef[f] = fv; 2732cf51de39SMatthew G. Knepley } 27339566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 27349566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &rNb)); 27359566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 27369566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 273797c42addSMatthew G. Knepley } 27389566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, f, NULL, &objc)); 27399566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(objc, &idc)); 27402ea9c922SToby Isaac if (idc == PETSCFE_CLASSID) { 27412ea9c922SToby Isaac PetscFE fe = (PetscFE)objc; 27422ea9c922SToby Isaac 27439566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cNb)); 27442ea9c922SToby Isaac } else if (id == PETSCFV_CLASSID) { 27452ea9c922SToby Isaac PetscFV fv = (PetscFV)obj; 27462ea9c922SToby Isaac PetscDualSpace Q; 27472ea9c922SToby Isaac 27489566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 27499566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &cNb)); 2750d69c5d34SMatthew G. Knepley } 27512ea9c922SToby Isaac rTotDim += rNb; 27522ea9c922SToby Isaac cTotDim += cNb; 27532ea9c922SToby Isaac } 27549566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(rTotDim * cTotDim, &elemMat)); 27559566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, rTotDim * cTotDim)); 2756d69c5d34SMatthew G. Knepley for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 2757d69c5d34SMatthew G. Knepley PetscDualSpace Qref; 2758d69c5d34SMatthew G. Knepley PetscQuadrature f; 2759d69c5d34SMatthew G. Knepley const PetscReal *qpoints, *qweights; 2760d69c5d34SMatthew G. Knepley PetscReal *points; 2761d69c5d34SMatthew G. Knepley PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 2762d69c5d34SMatthew G. Knepley 2763d69c5d34SMatthew G. Knepley /* Compose points from all dual basis functionals */ 276497c42addSMatthew G. Knepley if (feRef[fieldI]) { 27659566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[fieldI], &Qref)); 27669566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[fieldI], &Nc)); 276797c42addSMatthew G. Knepley } else { 27689566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[fieldI], &Qref)); 27699566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[fieldI], &Nc)); 277097c42addSMatthew G. Knepley } 27719566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Qref, &fpdim)); 2772d69c5d34SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 27739566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 27749566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL)); 2775d69c5d34SMatthew G. Knepley npoints += Np; 2776d69c5d34SMatthew G. Knepley } 27779566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints * dim, &points)); 2778d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 27799566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 27809566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL)); 27819371c9d4SSatish Balay for (p = 0; p < Np; ++p, ++k) 27829371c9d4SSatish Balay for (d = 0; d < dim; ++d) points[k * dim + d] = qpoints[p * dim + d]; 2783d69c5d34SMatthew G. Knepley } 2784d69c5d34SMatthew G. Knepley 2785d69c5d34SMatthew G. Knepley for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 278697c42addSMatthew G. Knepley PetscObject obj; 278797c42addSMatthew G. Knepley PetscClassId id; 27889c3cf19fSMatthew G. Knepley PetscInt NcJ = 0, cpdim = 0, j, qNc; 2789d69c5d34SMatthew G. Knepley 27909566063dSJacob Faibussowitsch PetscCall(DMGetField(dmc, fieldJ, NULL, &obj)); 27919566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 279297c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 279397c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 2794ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 2795d69c5d34SMatthew G. Knepley 2796d69c5d34SMatthew G. Knepley /* Evaluate basis at points */ 27979566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &NcJ)); 27989566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 2799ffe73a53SMatthew G. Knepley /* For now, fields only interpolate themselves */ 2800ffe73a53SMatthew G. Knepley if (fieldI == fieldJ) { 280163a3b9bcSJacob 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); 28029566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation(fe, 1, npoints, points, 0, &T)); 2803d69c5d34SMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 28049566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 28059566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 280663a3b9bcSJacob 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); 2807d69c5d34SMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 280836a6d9c0SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2809d172c84bSMatthew G. Knepley /* 2810d172c84bSMatthew G. Knepley cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field 2811d172c84bSMatthew G. Knepley offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields 2812d172c84bSMatthew G. Knepley fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals 2813d172c84bSMatthew G. Knepley qNC, Nc, Ncj, c: Number of components in this field 2814d172c84bSMatthew G. Knepley Np, p: Number of quad points in the fine grid functional i 2815d172c84bSMatthew G. Knepley k: i*Np + p, overall point number for the interpolation 2816d172c84bSMatthew G. Knepley */ 2817ef0bb6c7SMatthew 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]; 281836a6d9c0SMatthew G. Knepley } 2819d69c5d34SMatthew G. Knepley } 2820d69c5d34SMatthew G. Knepley } 28219566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 2822ffe73a53SMatthew G. Knepley } 282397c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 282497c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 282597c42addSMatthew G. Knepley 282697c42addSMatthew G. Knepley /* Evaluate constant function at points */ 28279566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcJ)); 282897c42addSMatthew G. Knepley cpdim = 1; 282997c42addSMatthew G. Knepley /* For now, fields only interpolate themselves */ 283097c42addSMatthew G. Knepley if (fieldI == fieldJ) { 283163a3b9bcSJacob 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); 283297c42addSMatthew G. Knepley for (i = 0, k = 0; i < fpdim; ++i) { 28339566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 28349566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 283563a3b9bcSJacob 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); 283697c42addSMatthew G. Knepley for (p = 0; p < Np; ++p, ++k) { 283797c42addSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 2838458eb97cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += 1.0 * qweights[p * qNc + c]; 283997c42addSMatthew G. Knepley } 284097c42addSMatthew G. Knepley } 284197c42addSMatthew G. Knepley } 284297c42addSMatthew G. Knepley } 284397c42addSMatthew G. Knepley } 2844d172c84bSMatthew G. Knepley offsetJ += cpdim; 2845d69c5d34SMatthew G. Knepley } 2846d172c84bSMatthew G. Knepley offsetI += fpdim; 28479566063dSJacob Faibussowitsch PetscCall(PetscFree(points)); 2848d69c5d34SMatthew G. Knepley } 28499566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat)); 28507f5b169aSMatthew G. Knepley /* Preallocate matrix */ 28517f5b169aSMatthew G. Knepley { 2852c094ef40SMatthew G. Knepley Mat preallocator; 2853c094ef40SMatthew G. Knepley PetscScalar *vals; 2854c094ef40SMatthew G. Knepley PetscInt *cellCIndices, *cellFIndices; 2855c094ef40SMatthew G. Knepley PetscInt locRows, locCols, cell; 28567f5b169aSMatthew G. Knepley 28579566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 28589566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &preallocator)); 28599566063dSJacob Faibussowitsch PetscCall(MatSetType(preallocator, MATPREALLOCATOR)); 28609566063dSJacob Faibussowitsch PetscCall(MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 28619566063dSJacob Faibussowitsch PetscCall(MatSetUp(preallocator)); 28629566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(rTotDim * cTotDim, &vals, cTotDim, &cellCIndices, rTotDim, &cellFIndices)); 28637f5b169aSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 2864cf51de39SMatthew G. Knepley if (isRefined) { 28659566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices)); 28669566063dSJacob Faibussowitsch PetscCall(MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES)); 2867cf51de39SMatthew G. Knepley } else { 2868e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, preallocator, cell, vals, INSERT_VALUES)); 2869cf51de39SMatthew G. Knepley } 28707f5b169aSMatthew G. Knepley } 28719566063dSJacob Faibussowitsch PetscCall(PetscFree3(vals, cellCIndices, cellFIndices)); 28729566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY)); 28739566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY)); 28749566063dSJacob Faibussowitsch PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In)); 28759566063dSJacob Faibussowitsch PetscCall(MatDestroy(&preallocator)); 28767f5b169aSMatthew G. Knepley } 28777f5b169aSMatthew G. Knepley /* Fill matrix */ 28789566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(In)); 2879d69c5d34SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 2880cf51de39SMatthew G. Knepley if (isRefined) { 28819566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES)); 2882cf51de39SMatthew G. Knepley } else { 2883e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, In, c, elemMat, INSERT_VALUES)); 2884cf51de39SMatthew G. Knepley } 2885d69c5d34SMatthew G. Knepley } 28869566063dSJacob Faibussowitsch for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&feRef[f])); 28879566063dSJacob Faibussowitsch PetscCall(PetscFree2(feRef, fvRef)); 28889566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 28899566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 28909566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 28919318fe57SMatthew G. Knepley if (mesh->printFEM > 1) { 28929566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name)); 28932ce66baaSPierre Jolivet PetscCall(MatFilter(In, 1.0e-10, PETSC_FALSE, PETSC_FALSE)); 28949566063dSJacob Faibussowitsch PetscCall(MatView(In, NULL)); 2895d69c5d34SMatthew G. Knepley } 28969566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 28973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2898d69c5d34SMatthew G. Knepley } 28996c73c22cSMatthew G. Knepley 2900d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user) 2901d71ae5a4SJacob Faibussowitsch { 2902bd041c0cSMatthew G. Knepley SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "Laziness"); 2903bd041c0cSMatthew G. Knepley } 2904bd041c0cSMatthew G. Knepley 290568132eb9SMatthew G. Knepley /*@ 2906a1cb98faSBarry Smith DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse `DM` to a non-nested fine `DM`. 290768132eb9SMatthew G. Knepley 290868132eb9SMatthew G. Knepley Input Parameters: 290968132eb9SMatthew G. Knepley + dmf - The fine mesh 291068132eb9SMatthew G. Knepley . dmc - The coarse mesh 291168132eb9SMatthew G. Knepley - user - The user context 291268132eb9SMatthew G. Knepley 291368132eb9SMatthew G. Knepley Output Parameter: 291468132eb9SMatthew G. Knepley . In - The interpolation matrix 291568132eb9SMatthew G. Knepley 291668132eb9SMatthew G. Knepley Level: developer 291768132eb9SMatthew G. Knepley 29181cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()` 291968132eb9SMatthew G. Knepley @*/ 2920d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user) 2921d71ae5a4SJacob Faibussowitsch { 292264e98e1dSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 292364e98e1dSMatthew G. Knepley const char *name = "Interpolator"; 29244ef9d792SMatthew G. Knepley PetscDS prob; 2925a0806964SMatthew G. Knepley Mat interp; 2926a0806964SMatthew G. Knepley PetscSection fsection, globalFSection; 2927a0806964SMatthew G. Knepley PetscSection csection, globalCSection; 2928a0806964SMatthew G. Knepley PetscInt locRows, locCols; 29294ef9d792SMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 29304ef9d792SMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 29314ef9d792SMatthew G. Knepley PetscScalar *elemMat; 2932a0806964SMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell, s; 29334ef9d792SMatthew G. Knepley 29344ef9d792SMatthew G. Knepley PetscFunctionBegin; 29359566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 29369566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 29379566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 29389566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 29399566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 29409566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 29419566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 29429566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 29439566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 29449566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 29459566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 2946a0806964SMatthew G. Knepley PetscCall(DMPlexGetSimplexOrBoxCells(dmf, 0, &cStart, &cEnd)); 29479566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 29489566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 29494ef9d792SMatthew G. Knepley 2950a0806964SMatthew G. Knepley PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 2951a0806964SMatthew G. Knepley PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &interp)); 2952a0806964SMatthew G. Knepley PetscCall(MatSetType(interp, MATPREALLOCATOR)); 2953a0806964SMatthew G. Knepley PetscCall(MatSetSizes(interp, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 2954a0806964SMatthew G. Knepley PetscCall(MatSetUp(interp)); 2955a0806964SMatthew G. Knepley for (s = 0; s < 2; ++s) { 29564ef9d792SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 29574ef9d792SMatthew G. Knepley PetscObject obj; 29584ef9d792SMatthew G. Knepley PetscClassId id; 2959c0d7054bSMatthew G. Knepley PetscDualSpace Q = NULL; 2960ef0bb6c7SMatthew G. Knepley PetscTabulation T = NULL; 29614ef9d792SMatthew G. Knepley PetscQuadrature f; 29624ef9d792SMatthew G. Knepley const PetscReal *qpoints, *qweights; 2963d0f6233fSMatthew G. Knepley PetscInt Nc, qNc, Np, fpdim, off, i, d; 29644ef9d792SMatthew G. Knepley 2965d0f6233fSMatthew G. Knepley PetscCall(PetscDSGetFieldOffset(prob, field, &off)); 29669566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 29679566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 29684ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 29694ef9d792SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 29704ef9d792SMatthew G. Knepley 29719566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(fe, &Q)); 29729566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 2973a0806964SMatthew G. Knepley if (s) PetscCall(PetscFECreateTabulation(fe, 1, 1, x, 0, &T)); 29744ef9d792SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 29754ef9d792SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 29764ef9d792SMatthew G. Knepley 29779566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fv, &Q)); 29784ef9d792SMatthew G. Knepley Nc = 1; 297963a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 29809566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fpdim)); 29814ef9d792SMatthew G. Knepley /* For each fine grid cell */ 29824ef9d792SMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 29834ef9d792SMatthew G. Knepley PetscInt *findices, *cindices; 29844ef9d792SMatthew G. Knepley PetscInt numFIndices, numCIndices; 29854ef9d792SMatthew G. Knepley 29869566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 29879566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 2988d0f6233fSMatthew 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); 29894ef9d792SMatthew G. Knepley for (i = 0; i < fpdim; ++i) { 29904ef9d792SMatthew G. Knepley Vec pointVec; 29914ef9d792SMatthew G. Knepley PetscScalar *pV; 299212111d7cSToby Isaac PetscSF coarseCellSF = NULL; 29933a93e3b7SToby Isaac const PetscSFNode *coarseCells; 2994d0f6233fSMatthew G. Knepley PetscInt numCoarseCells, cpdim, row = findices[i + off], q, c, j; 29954ef9d792SMatthew G. Knepley 29964ef9d792SMatthew G. Knepley /* Get points from the dual basis functional quadrature */ 29979566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(Q, i, &f)); 29989566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights)); 299963a3b9bcSJacob 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); 30009566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np * dim, &pointVec)); 30019566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 30029566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 30034ef9d792SMatthew G. Knepley for (q = 0; q < Np; ++q) { 3004c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3005c330f8ffSToby Isaac 30064ef9d792SMatthew G. Knepley /* Transform point to real space */ 3007c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 30084ef9d792SMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 30094ef9d792SMatthew G. Knepley } 30109566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 30114ef9d792SMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 30121555c271SMatthew G. Knepley /* OPT: Read this out from preallocation information */ 30139566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 30144ef9d792SMatthew G. Knepley /* Update preallocation info */ 30159566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 30165f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Np, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 30179566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 30184ef9d792SMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3019826eb36dSMatthew G. Knepley PetscReal pVReal[3]; 3020c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3021826eb36dSMatthew G. Knepley 30229566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3023a0806964SMatthew G. Knepley if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetDimension((PetscFE)obj, &cpdim)); 3024a0806964SMatthew G. Knepley else cpdim = 1; 3025a0806964SMatthew G. Knepley 3026a0806964SMatthew G. Knepley if (s) { 30274ef9d792SMatthew G. Knepley /* Transform points from real space to coarse reference space */ 30289566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3029e2d86523SMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 3030c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 30314ef9d792SMatthew G. Knepley 30324ef9d792SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 30334ef9d792SMatthew G. Knepley /* Evaluate coarse basis on contained point */ 3034a0806964SMatthew G. Knepley PetscCall(PetscFEComputeTabulation((PetscFE)obj, 1, x, 0, T)); 30359566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 30364ef9d792SMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 30374ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3038ef0bb6c7SMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * qweights[ccell * qNc + c]; 30394ef9d792SMatthew G. Knepley } 30404ef9d792SMatthew G. Knepley } else { 30414ef9d792SMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 30429c3cf19fSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * qweights[ccell * qNc + c]; 30434ef9d792SMatthew G. Knepley } 30444ef9d792SMatthew G. Knepley } 30459566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 3046a0806964SMatthew G. Knepley } 3047a0806964SMatthew G. Knepley /* Update interpolator */ 3048d0f6233fSMatthew G. Knepley PetscCheck(numCIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, totDim); 3049a0806964SMatthew G. Knepley PetscCall(MatSetValues(interp, 1, &row, cpdim, &cindices[off], elemMat, INSERT_VALUES)); 30509566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 30514ef9d792SMatthew G. Knepley } 30529566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 30539566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 30549566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 30554ef9d792SMatthew G. Knepley } 30569566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 30574ef9d792SMatthew G. Knepley } 3058a0806964SMatthew G. Knepley if (s && id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3059a0806964SMatthew G. Knepley } 3060a0806964SMatthew G. Knepley if (!s) { 3061a0806964SMatthew G. Knepley PetscCall(MatAssemblyBegin(interp, MAT_FINAL_ASSEMBLY)); 3062a0806964SMatthew G. Knepley PetscCall(MatAssemblyEnd(interp, MAT_FINAL_ASSEMBLY)); 3063a0806964SMatthew G. Knepley PetscCall(MatPreallocatorPreallocate(interp, PETSC_TRUE, In)); 3064a0806964SMatthew G. Knepley PetscCall(MatDestroy(&interp)); 3065a0806964SMatthew G. Knepley interp = In; 3066a0806964SMatthew G. Knepley } 30674ef9d792SMatthew G. Knepley } 30689566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 30699566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 30709566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 30719566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 30729566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 30739566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 30743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 30754ef9d792SMatthew G. Knepley } 30764ef9d792SMatthew G. Knepley 307746fa42a0SMatthew G. Knepley /*@ 3078a1cb98faSBarry Smith DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse `DM` to a non-nested fine `DM`. 3079bd041c0cSMatthew G. Knepley 3080bd041c0cSMatthew G. Knepley Input Parameters: 3081bd041c0cSMatthew G. Knepley + dmf - The fine mesh 3082bd041c0cSMatthew G. Knepley . dmc - The coarse mesh 3083bd041c0cSMatthew G. Knepley - user - The user context 3084bd041c0cSMatthew G. Knepley 3085bd041c0cSMatthew G. Knepley Output Parameter: 3086bd041c0cSMatthew G. Knepley . mass - The mass matrix 3087bd041c0cSMatthew G. Knepley 3088bd041c0cSMatthew G. Knepley Level: developer 3089bd041c0cSMatthew G. Knepley 30901cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeMassMatrixNested()`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()` 3091bd041c0cSMatthew G. Knepley @*/ 3092d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user) 3093d71ae5a4SJacob Faibussowitsch { 3094bd041c0cSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dmf->data; 3095bd041c0cSMatthew G. Knepley const char *name = "Mass Matrix"; 3096bd041c0cSMatthew G. Knepley PetscDS prob; 3097bd041c0cSMatthew G. Knepley PetscSection fsection, csection, globalFSection, globalCSection; 3098e8f14785SLisandro Dalcin PetscHSetIJ ht; 3099bd041c0cSMatthew G. Knepley PetscLayout rLayout; 3100bd041c0cSMatthew G. Knepley PetscInt *dnz, *onz; 3101bd041c0cSMatthew G. Knepley PetscInt locRows, rStart, rEnd; 3102bd041c0cSMatthew G. Knepley PetscReal *x, *v0, *J, *invJ, detJ; 3103bd041c0cSMatthew G. Knepley PetscReal *v0c, *Jc, *invJc, detJc; 3104bd041c0cSMatthew G. Knepley PetscScalar *elemMat; 3105bd041c0cSMatthew G. Knepley PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 3106bd041c0cSMatthew G. Knepley 3107bd041c0cSMatthew G. Knepley PetscFunctionBegin; 31089566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmc, &dim)); 31099566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 31109566063dSJacob Faibussowitsch PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 31119566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 31129566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 31139566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 31149566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 31159566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 31169566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 31179566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 31189566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 31199566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 31209566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totDim, &elemMat)); 3121bd041c0cSMatthew G. Knepley 31229566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mass, &locRows, NULL)); 31239566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)mass), &rLayout)); 31249566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 31259566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 31269566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(rLayout)); 31279566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd)); 31289566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&rLayout)); 31299566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz)); 31309566063dSJacob Faibussowitsch PetscCall(PetscHSetIJCreate(&ht)); 3131bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3132bd041c0cSMatthew G. Knepley PetscObject obj; 3133bd041c0cSMatthew G. Knepley PetscClassId id; 3134bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3135bd041c0cSMatthew G. Knepley const PetscReal *qpoints; 3136bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3137bd041c0cSMatthew G. Knepley 31389566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 31399566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 31409566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 31419566063dSJacob Faibussowitsch else PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 31429566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL)); 3143bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3144bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3145bd041c0cSMatthew G. Knepley Vec pointVec; 3146bd041c0cSMatthew G. Knepley PetscScalar *pV; 3147bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3148bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3149bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, q, c; 3150bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3151bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3152bd041c0cSMatthew G. Knepley 31539566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 31549566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3155bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 31569566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 31579566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 31589566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3159bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3160c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3161c330f8ffSToby Isaac 3162bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3163c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3164bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3165bd041c0cSMatthew G. Knepley } 31669566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3167bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 31689566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 31699566063dSJacob Faibussowitsch PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view")); 3170bd041c0cSMatthew G. Knepley /* Update preallocation info */ 31719566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 31725f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 3173bd041c0cSMatthew G. Knepley { 3174e8f14785SLisandro Dalcin PetscHashIJKey key; 3175e8f14785SLisandro Dalcin PetscBool missing; 3176bd041c0cSMatthew G. Knepley 3177bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 3178e8f14785SLisandro Dalcin key.i = findices[i]; 3179e8f14785SLisandro Dalcin if (key.i >= 0) { 3180bd041c0cSMatthew G. Knepley /* Get indices for coarse elements */ 3181bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 31829566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3183bd041c0cSMatthew G. Knepley for (c = 0; c < numCIndices; ++c) { 3184e8f14785SLisandro Dalcin key.j = cindices[c]; 3185e8f14785SLisandro Dalcin if (key.j < 0) continue; 31869566063dSJacob Faibussowitsch PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 3187bd041c0cSMatthew G. Knepley if (missing) { 3188e8f14785SLisandro Dalcin if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i - rStart]; 3189e8f14785SLisandro Dalcin else ++onz[key.i - rStart]; 3190bd041c0cSMatthew G. Knepley } 3191bd041c0cSMatthew G. Knepley } 31929566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3193bd041c0cSMatthew G. Knepley } 3194bd041c0cSMatthew G. Knepley } 3195bd041c0cSMatthew G. Knepley } 3196bd041c0cSMatthew G. Knepley } 31979566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 31989566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 31999566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3200bd041c0cSMatthew G. Knepley } 3201bd041c0cSMatthew G. Knepley } 32029566063dSJacob Faibussowitsch PetscCall(PetscHSetIJDestroy(&ht)); 32039566063dSJacob Faibussowitsch PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 32049566063dSJacob Faibussowitsch PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 32059566063dSJacob Faibussowitsch PetscCall(PetscFree2(dnz, onz)); 3206bd041c0cSMatthew G. Knepley for (field = 0; field < Nf; ++field) { 3207bd041c0cSMatthew G. Knepley PetscObject obj; 3208bd041c0cSMatthew G. Knepley PetscClassId id; 3209ef0bb6c7SMatthew G. Knepley PetscTabulation T, Tfine; 3210bd041c0cSMatthew G. Knepley PetscQuadrature quad; 3211bd041c0cSMatthew G. Knepley const PetscReal *qpoints, *qweights; 3212bd041c0cSMatthew G. Knepley PetscInt Nq, Nc, i, d; 3213bd041c0cSMatthew G. Knepley 32149566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 32159566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 3216ef0bb6c7SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 32179566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 32189566063dSJacob Faibussowitsch PetscCall(PetscFEGetCellTabulation((PetscFE)obj, 1, &Tfine)); 32199566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, 1, x, 0, &T)); 3220ef0bb6c7SMatthew G. Knepley } else { 32219566063dSJacob Faibussowitsch PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 3222ef0bb6c7SMatthew G. Knepley } 32239566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights)); 3224bd041c0cSMatthew G. Knepley /* For each fine grid cell */ 3225bd041c0cSMatthew G. Knepley for (cell = cStart; cell < cEnd; ++cell) { 3226bd041c0cSMatthew G. Knepley Vec pointVec; 3227bd041c0cSMatthew G. Knepley PetscScalar *pV; 3228bd041c0cSMatthew G. Knepley PetscSF coarseCellSF = NULL; 3229bd041c0cSMatthew G. Knepley const PetscSFNode *coarseCells; 3230bd041c0cSMatthew G. Knepley PetscInt numCoarseCells, cpdim, q, c, j; 3231bd041c0cSMatthew G. Knepley PetscInt *findices, *cindices; 3232bd041c0cSMatthew G. Knepley PetscInt numFIndices, numCIndices; 3233bd041c0cSMatthew G. Knepley 32349566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 32359566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3236bd041c0cSMatthew G. Knepley /* Get points from the quadrature */ 32379566063dSJacob Faibussowitsch PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 32389566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(pointVec, dim)); 32399566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3240bd041c0cSMatthew G. Knepley for (q = 0; q < Nq; ++q) { 3241c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3242c330f8ffSToby Isaac 3243bd041c0cSMatthew G. Knepley /* Transform point to real space */ 3244c330f8ffSToby Isaac CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3245bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3246bd041c0cSMatthew G. Knepley } 32479566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 3248bd041c0cSMatthew G. Knepley /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 32499566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 3250bd041c0cSMatthew G. Knepley /* Update matrix */ 32519566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 32525f80ce2aSJacob Faibussowitsch PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 32539566063dSJacob Faibussowitsch PetscCall(VecGetArray(pointVec, &pV)); 3254bd041c0cSMatthew G. Knepley for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3255bd041c0cSMatthew G. Knepley PetscReal pVReal[3]; 3256c330f8ffSToby Isaac const PetscReal xi0[3] = {-1., -1., -1.}; 3257c330f8ffSToby Isaac 32589566063dSJacob Faibussowitsch PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3259bd041c0cSMatthew G. Knepley /* Transform points from real space to coarse reference space */ 32609566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3261bd041c0cSMatthew G. Knepley for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 3262c330f8ffSToby Isaac CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 3263bd041c0cSMatthew G. Knepley 3264bd041c0cSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 3265bd041c0cSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 3266bd041c0cSMatthew G. Knepley 3267bd041c0cSMatthew G. Knepley /* Evaluate coarse basis on contained point */ 32689566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &cpdim)); 32699566063dSJacob Faibussowitsch PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T)); 3270bd041c0cSMatthew G. Knepley /* Get elemMat entries by multiplying by weight */ 3271bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 32729566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3273bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3274ef0bb6c7SMatthew 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; 3275bd041c0cSMatthew G. Knepley } 3276bd041c0cSMatthew G. Knepley /* Update interpolator */ 32779566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 327863a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 32799566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3280bd041c0cSMatthew G. Knepley } 3281bd041c0cSMatthew G. Knepley } else { 3282bd041c0cSMatthew G. Knepley cpdim = 1; 3283bd041c0cSMatthew G. Knepley for (i = 0; i < numFIndices; ++i) { 32849566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, cpdim)); 3285bd041c0cSMatthew G. Knepley for (j = 0; j < cpdim; ++j) { 3286bd041c0cSMatthew G. Knepley for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * 1.0 * qweights[ccell * Nc + c] * detJ; 3287bd041c0cSMatthew G. Knepley } 3288bd041c0cSMatthew G. Knepley /* Update interpolator */ 32899566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 329063a3b9bcSJacob 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)); 329163a3b9bcSJacob Faibussowitsch PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 32929566063dSJacob Faibussowitsch PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3293bd041c0cSMatthew G. Knepley } 3294bd041c0cSMatthew G. Knepley } 32959566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3296bd041c0cSMatthew G. Knepley } 32979566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pointVec, &pV)); 32989566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&coarseCellSF)); 32999566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 33009566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3301bd041c0cSMatthew G. Knepley } 33029566063dSJacob Faibussowitsch if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3303bd041c0cSMatthew G. Knepley } 33049566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 33059566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0c, Jc, invJc)); 33069566063dSJacob Faibussowitsch PetscCall(PetscFree(elemMat)); 33079566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 33089566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 33093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3310bd041c0cSMatthew G. Knepley } 3311bd041c0cSMatthew G. Knepley 3312bd041c0cSMatthew G. Knepley /*@ 331346fa42a0SMatthew G. Knepley DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns 331446fa42a0SMatthew G. Knepley 331546fa42a0SMatthew G. Knepley Input Parameters: 331646fa42a0SMatthew G. Knepley + dmc - The coarse mesh 331760225df5SJacob Faibussowitsch . dmf - The fine mesh 331846fa42a0SMatthew G. Knepley - user - The user context 331946fa42a0SMatthew G. Knepley 332046fa42a0SMatthew G. Knepley Output Parameter: 332146fa42a0SMatthew G. Knepley . sc - The mapping 332246fa42a0SMatthew G. Knepley 332346fa42a0SMatthew G. Knepley Level: developer 332446fa42a0SMatthew G. Knepley 33251cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()` 332646fa42a0SMatthew G. Knepley @*/ 3327d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 3328d71ae5a4SJacob Faibussowitsch { 3329e9d4ef1bSMatthew G. Knepley PetscDS prob; 33307c927364SMatthew G. Knepley PetscFE *feRef; 333197c42addSMatthew G. Knepley PetscFV *fvRef; 33327c927364SMatthew G. Knepley Vec fv, cv; 33337c927364SMatthew G. Knepley IS fis, cis; 33347c927364SMatthew G. Knepley PetscSection fsection, fglobalSection, csection, cglobalSection; 33357c927364SMatthew G. Knepley PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 3336485ad865SMatthew G. Knepley PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m; 33376f3d3cbcSMatthew G. Knepley PetscBool *needAvg; 33387c927364SMatthew G. Knepley 33397c927364SMatthew G. Knepley PetscFunctionBegin; 33409566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 33419566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dmf, &dim)); 33429566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmf, &fsection)); 33439566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 33449566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmc, &csection)); 33459566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 33469566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 33479566063dSJacob Faibussowitsch PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 33489566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmc, &prob)); 33499566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nf, &feRef, Nf, &fvRef, Nf, &needAvg)); 33507c927364SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 335197c42addSMatthew G. Knepley PetscObject obj; 335297c42addSMatthew G. Knepley PetscClassId id; 3353aa7890ccSMatthew G. Knepley PetscInt fNb = 0, Nc = 0; 33547c927364SMatthew G. Knepley 33559566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 33569566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 335797c42addSMatthew G. Knepley if (id == PETSCFE_CLASSID) { 335897c42addSMatthew G. Knepley PetscFE fe = (PetscFE)obj; 33596f3d3cbcSMatthew G. Knepley PetscSpace sp; 33609b2fc754SMatthew G. Knepley PetscInt maxDegree; 336197c42addSMatthew G. Knepley 33629566063dSJacob Faibussowitsch PetscCall(PetscFERefine(fe, &feRef[f])); 33639566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feRef[f], &fNb)); 33649566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(fe, &Nc)); 33659566063dSJacob Faibussowitsch PetscCall(PetscFEGetBasisSpace(fe, &sp)); 33669566063dSJacob Faibussowitsch PetscCall(PetscSpaceGetDegree(sp, NULL, &maxDegree)); 33679b2fc754SMatthew G. Knepley if (!maxDegree) needAvg[f] = PETSC_TRUE; 336897c42addSMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 336997c42addSMatthew G. Knepley PetscFV fv = (PetscFV)obj; 337097c42addSMatthew G. Knepley PetscDualSpace Q; 337197c42addSMatthew G. Knepley 33729566063dSJacob Faibussowitsch PetscCall(PetscFVRefine(fv, &fvRef[f])); 33739566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 33749566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(Q, &fNb)); 33759566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 33766f3d3cbcSMatthew G. Knepley needAvg[f] = PETSC_TRUE; 337797c42addSMatthew G. Knepley } 3378d172c84bSMatthew G. Knepley fTotDim += fNb; 33797c927364SMatthew G. Knepley } 33809566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &cTotDim)); 33819566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(cTotDim, &cmap)); 33827c927364SMatthew G. Knepley for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 33837c927364SMatthew G. Knepley PetscFE feC; 338497c42addSMatthew G. Knepley PetscFV fvC; 33857c927364SMatthew G. Knepley PetscDualSpace QF, QC; 3386d172c84bSMatthew G. Knepley PetscInt order = -1, NcF, NcC, fpdim, cpdim; 33877c927364SMatthew G. Knepley 338897c42addSMatthew G. Knepley if (feRef[field]) { 33899566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&feC)); 33909566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feC, &NcC)); 33919566063dSJacob Faibussowitsch PetscCall(PetscFEGetNumComponents(feRef[field], &NcF)); 33929566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feRef[field], &QF)); 33939566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetOrder(QF, &order)); 33949566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 33959566063dSJacob Faibussowitsch PetscCall(PetscFEGetDualSpace(feC, &QC)); 33969566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 339797c42addSMatthew G. Knepley } else { 33989566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fvC)); 33999566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvC, &NcC)); 34009566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fvRef[field], &NcF)); 34019566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvRef[field], &QF)); 34029566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 34039566063dSJacob Faibussowitsch PetscCall(PetscFVGetDualSpace(fvC, &QC)); 34049566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 340597c42addSMatthew G. Knepley } 340663a3b9bcSJacob 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); 34077c927364SMatthew G. Knepley for (c = 0; c < cpdim; ++c) { 34087c927364SMatthew G. Knepley PetscQuadrature cfunc; 3409d172c84bSMatthew G. Knepley const PetscReal *cqpoints, *cqweights; 3410d172c84bSMatthew G. Knepley PetscInt NqcC, NpC; 341197c42addSMatthew G. Knepley PetscBool found = PETSC_FALSE; 34127c927364SMatthew G. Knepley 34139566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QC, c, &cfunc)); 34149566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights)); 341563a3b9bcSJacob 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); 34161dca8a05SBarry Smith PetscCheck(NpC == 1 || !feRef[field], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 34177c927364SMatthew G. Knepley for (f = 0; f < fpdim; ++f) { 34187c927364SMatthew G. Knepley PetscQuadrature ffunc; 3419d172c84bSMatthew G. Knepley const PetscReal *fqpoints, *fqweights; 34207c927364SMatthew G. Knepley PetscReal sum = 0.0; 3421d172c84bSMatthew G. Knepley PetscInt NqcF, NpF; 34227c927364SMatthew G. Knepley 34239566063dSJacob Faibussowitsch PetscCall(PetscDualSpaceGetFunctional(QF, f, &ffunc)); 34249566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights)); 342563a3b9bcSJacob 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); 34267c927364SMatthew G. Knepley if (NpC != NpF) continue; 34277c927364SMatthew G. Knepley for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 34287c927364SMatthew G. Knepley if (sum > 1.0e-9) continue; 3429d172c84bSMatthew G. Knepley for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d] * fqweights[d]); 3430d172c84bSMatthew G. Knepley if (sum < 1.0e-9) continue; 3431d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + f; 343297c42addSMatthew G. Knepley found = PETSC_TRUE; 34337c927364SMatthew G. Knepley break; 34347c927364SMatthew G. Knepley } 343597c42addSMatthew G. Knepley if (!found) { 343697c42addSMatthew G. Knepley /* TODO We really want the average here, but some asshole put VecScatter in the interface */ 3437d172c84bSMatthew G. Knepley if (fvRef[field] || (feRef[field] && order == 0)) { 3438d172c84bSMatthew G. Knepley cmap[offsetC + c] = offsetF + 0; 343997c42addSMatthew G. Knepley } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection"); 344097c42addSMatthew G. Knepley } 34417c927364SMatthew G. Knepley } 3442d172c84bSMatthew G. Knepley offsetC += cpdim; 3443d172c84bSMatthew G. Knepley offsetF += fpdim; 34447c927364SMatthew G. Knepley } 34459371c9d4SSatish Balay for (f = 0; f < Nf; ++f) { 34469371c9d4SSatish Balay PetscCall(PetscFEDestroy(&feRef[f])); 34479371c9d4SSatish Balay PetscCall(PetscFVDestroy(&fvRef[f])); 34489371c9d4SSatish Balay } 34499566063dSJacob Faibussowitsch PetscCall(PetscFree3(feRef, fvRef, needAvg)); 34507c927364SMatthew G. Knepley 34519566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmf, &fv)); 34529566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(dmc, &cv)); 34539566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(cv, &startC, &endC)); 34549566063dSJacob Faibussowitsch PetscCall(PetscSectionGetConstrainedStorageSize(cglobalSection, &m)); 34559566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(cTotDim, &cellCIndices, fTotDim, &cellFIndices)); 34569566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &cindices)); 34579566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &findices)); 34587c927364SMatthew G. Knepley for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 34597c927364SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 34609566063dSJacob Faibussowitsch PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices)); 34617c927364SMatthew G. Knepley for (d = 0; d < cTotDim; ++d) { 34620bd915a7SMatthew G. Knepley if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue; 3463d2457c26SMatthew 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]]); 34647c927364SMatthew G. Knepley cindices[cellCIndices[d] - startC] = cellCIndices[d]; 34657c927364SMatthew G. Knepley findices[cellCIndices[d] - startC] = cellFIndices[cmap[d]]; 34667c927364SMatthew G. Knepley } 34677c927364SMatthew G. Knepley } 34689566063dSJacob Faibussowitsch PetscCall(PetscFree(cmap)); 34699566063dSJacob Faibussowitsch PetscCall(PetscFree2(cellCIndices, cellFIndices)); 34707c927364SMatthew G. Knepley 34719566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis)); 34729566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis)); 34739566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(cv, cis, fv, fis, sc)); 34749566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cis)); 34759566063dSJacob Faibussowitsch PetscCall(ISDestroy(&fis)); 34769566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmf, &fv)); 34779566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(dmc, &cv)); 34789566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 34793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3480cb1e1211SMatthew G Knepley } 3481a1cf66bbSMatthew G. Knepley 34822f856554SMatthew G. Knepley /*@C 34832f856554SMatthew G. Knepley DMPlexGetCellFields - Retrieve the field values values for a chunk of cells 34842f856554SMatthew G. Knepley 34852f856554SMatthew G. Knepley Input Parameters: 3486a1cb98faSBarry Smith + dm - The `DM` 34872f856554SMatthew G. Knepley . cellIS - The cells to include 34882f856554SMatthew G. Knepley . locX - A local vector with the solution fields 34892f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 34902f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 34912f856554SMatthew G. Knepley 34922f856554SMatthew G. Knepley Output Parameters: 34932f856554SMatthew G. Knepley + u - The field coefficients 34942f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 34952f856554SMatthew G. Knepley - a - The auxiliary field coefficients 34962f856554SMatthew G. Knepley 34972f856554SMatthew G. Knepley Level: developer 34982f856554SMatthew G. Knepley 34991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 35002f856554SMatthew G. Knepley @*/ 3501d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3502d71ae5a4SJacob Faibussowitsch { 35032f856554SMatthew G. Knepley DM plex, plexA = NULL; 3504a6e0b375SMatthew G. Knepley DMEnclosureType encAux; 35052f856554SMatthew G. Knepley PetscSection section, sectionAux; 35062f856554SMatthew G. Knepley PetscDS prob; 35072f856554SMatthew G. Knepley const PetscInt *cells; 35082f856554SMatthew G. Knepley PetscInt cStart, cEnd, numCells, totDim, totDimAux, c; 35092f856554SMatthew G. Knepley 35102f856554SMatthew G. Knepley PetscFunctionBegin; 35112f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3512064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 3513ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); 3514ad540459SPierre Jolivet if (locA) PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); 35154f572ea9SToby Isaac PetscAssertPointer(u, 6); 35164f572ea9SToby Isaac PetscAssertPointer(u_t, 7); 35174f572ea9SToby Isaac PetscAssertPointer(a, 8); 35189566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 35199566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 35209566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 352107218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 35229566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 35232f856554SMatthew G. Knepley if (locA) { 35242f856554SMatthew G. Knepley DM dmAux; 35252f856554SMatthew G. Knepley PetscDS probAux; 35262f856554SMatthew G. Knepley 35279566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 35289566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 35299566063dSJacob Faibussowitsch PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 35309566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 35319566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 35329566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 35332f856554SMatthew G. Knepley } 35342f856554SMatthew G. Knepley numCells = cEnd - cStart; 35359566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 35369371c9d4SSatish Balay if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 3537ad540459SPierre Jolivet else *u_t = NULL; 35389371c9d4SSatish Balay if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 3539ad540459SPierre Jolivet else *a = NULL; 35402f856554SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 35412f856554SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 35422f856554SMatthew G. Knepley const PetscInt cind = c - cStart; 35432f856554SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a; 35442f856554SMatthew G. Knepley PetscInt i; 35452f856554SMatthew G. Knepley 35469566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x)); 35472f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul[cind * totDim + i] = x[i]; 35489566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x)); 35492f856554SMatthew G. Knepley if (locX_t) { 35509566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t)); 35512f856554SMatthew G. Knepley for (i = 0; i < totDim; ++i) ul_t[cind * totDim + i] = x_t[i]; 35529566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t)); 35532f856554SMatthew G. Knepley } 35542f856554SMatthew G. Knepley if (locA) { 35552f856554SMatthew G. Knepley PetscInt subcell; 35569566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 35579566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 35582f856554SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) al[cind * totDimAux + i] = x[i]; 35599566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 35602f856554SMatthew G. Knepley } 35612f856554SMatthew G. Knepley } 35629566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 35639566063dSJacob Faibussowitsch if (locA) PetscCall(DMDestroy(&plexA)); 35649566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 35653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 35662f856554SMatthew G. Knepley } 35672f856554SMatthew G. Knepley 35682f856554SMatthew G. Knepley /*@C 35692f856554SMatthew G. Knepley DMPlexRestoreCellFields - Restore the field values values for a chunk of cells 35702f856554SMatthew G. Knepley 35712f856554SMatthew G. Knepley Input Parameters: 3572a1cb98faSBarry Smith + dm - The `DM` 35732f856554SMatthew G. Knepley . cellIS - The cells to include 35742f856554SMatthew G. Knepley . locX - A local vector with the solution fields 35752f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 35762f856554SMatthew G. Knepley - locA - A local vector with auxiliary fields, or NULL 35772f856554SMatthew G. Knepley 35782f856554SMatthew G. Knepley Output Parameters: 35792f856554SMatthew G. Knepley + u - The field coefficients 35802f856554SMatthew G. Knepley . u_t - The fields derivative coefficients 35812f856554SMatthew G. Knepley - a - The auxiliary field coefficients 35822f856554SMatthew G. Knepley 35832f856554SMatthew G. Knepley Level: developer 35842f856554SMatthew G. Knepley 35851cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 35862f856554SMatthew G. Knepley @*/ 3587d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3588d71ae5a4SJacob Faibussowitsch { 35892f856554SMatthew G. Knepley PetscFunctionBegin; 35909566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u)); 35919566063dSJacob Faibussowitsch if (locX_t) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t)); 35929566063dSJacob Faibussowitsch if (locA) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a)); 35933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 35942f856554SMatthew G. Knepley } 35952f856554SMatthew G. Knepley 3596a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexGetHybridCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3597d71ae5a4SJacob Faibussowitsch { 359807218a29SMatthew G. Knepley DM plex, plexA = NULL; 359907218a29SMatthew G. Knepley DMEnclosureType encAux; 360007218a29SMatthew G. Knepley PetscSection section, sectionAux; 360107218a29SMatthew G. Knepley PetscDS ds, dsIn; 36026528b96dSMatthew G. Knepley const PetscInt *cells; 360307218a29SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, totDim, totDimAux, Nf, f; 36046528b96dSMatthew G. Knepley 36056528b96dSMatthew G. Knepley PetscFunctionBegin; 360607218a29SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 360707218a29SMatthew G. Knepley PetscValidHeaderSpecific(cellIS, IS_CLASSID, 2); 360807218a29SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 360907218a29SMatthew G. Knepley if (locX_t) { PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); } 361007218a29SMatthew G. Knepley if (locA) { PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); } 36114f572ea9SToby Isaac PetscAssertPointer(u, 6); 36124f572ea9SToby Isaac PetscAssertPointer(u_t, 7); 36134f572ea9SToby Isaac PetscAssertPointer(a, 8); 361407218a29SMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 361507218a29SMatthew G. Knepley numCells = cEnd - cStart; 361607218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 361707218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dm, §ion)); 361807218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 361907218a29SMatthew G. Knepley PetscCall(PetscDSGetNumFields(dsIn, &Nf)); 362007218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDim)); 362107218a29SMatthew G. Knepley if (locA) { 362207218a29SMatthew G. Knepley DM dmAux; 362307218a29SMatthew G. Knepley PetscDS probAux; 362407218a29SMatthew G. Knepley 362507218a29SMatthew G. Knepley PetscCall(VecGetDM(locA, &dmAux)); 362607218a29SMatthew G. Knepley PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 362707218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 362807218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dmAux, §ionAux)); 362907218a29SMatthew G. Knepley PetscCall(DMGetDS(dmAux, &probAux)); 363007218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 363107218a29SMatthew G. Knepley } 363207218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 363307218a29SMatthew G. Knepley if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 363407218a29SMatthew G. Knepley else { 363507218a29SMatthew G. Knepley *u_t = NULL; 363607218a29SMatthew G. Knepley } 363707218a29SMatthew G. Knepley if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 363807218a29SMatthew G. Knepley else { 363907218a29SMatthew G. Knepley *a = NULL; 364007218a29SMatthew G. Knepley } 364107218a29SMatthew G. Knepley // Loop over cohesive cells 364207218a29SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 364307218a29SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 364407218a29SMatthew G. Knepley const PetscInt cind = c - cStart; 364574a0c561SMatthew G. Knepley PetscScalar *xf = NULL, *xc = NULL, *x = NULL, *xf_t = NULL, *xc_t = NULL; 364674a0c561SMatthew G. Knepley PetscScalar *ul = &(*u)[cind * totDim], *ul_t = u_t ? &(*u_t)[cind * totDim] : NULL; 364707218a29SMatthew G. Knepley const PetscInt *cone, *ornt; 364807218a29SMatthew G. Knepley PetscInt Nx = 0, Nxf, s; 364907218a29SMatthew G. Knepley 365007218a29SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cell, &cone)); 365107218a29SMatthew G. Knepley PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 365207218a29SMatthew G. Knepley // Put in cohesive unknowns 365307218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, &Nxf, &xf)); 365474a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &xf_t)); 365507218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 365607218a29SMatthew G. Knepley PetscInt fdofIn, foff, foffIn; 365707218a29SMatthew G. Knepley PetscBool cohesive; 365807218a29SMatthew G. Knepley 365907218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 366007218a29SMatthew G. Knepley if (!cohesive) continue; 366107218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn)); 366207218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(ds, f, &foff)); 366307218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn)); 366407218a29SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + i] = xf[foff + i]; 366574a0c561SMatthew G. Knepley if (locX_t) 366674a0c561SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + i] = xf_t[foff + i]; 366707218a29SMatthew G. Knepley Nx += fdofIn; 366807218a29SMatthew G. Knepley } 366907218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, &Nxf, &xf)); 367074a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &xf_t)); 367107218a29SMatthew G. Knepley // Loop over sides of surface 367207218a29SMatthew G. Knepley for (s = 0; s < 2; ++s) { 367307218a29SMatthew G. Knepley const PetscInt *support; 367407218a29SMatthew G. Knepley const PetscInt face = cone[s]; 367507218a29SMatthew G. Knepley PetscInt ssize, ncell, Nxc; 367607218a29SMatthew G. Knepley 367707218a29SMatthew G. Knepley // I don't think I need the face to have 0 orientation in the hybrid cell 367807218a29SMatthew 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]); 367907218a29SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, face, &support)); 368007218a29SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, face, &ssize)); 368107218a29SMatthew G. Knepley if (support[0] == cell) ncell = support[1]; 368207218a29SMatthew G. Knepley else if (support[1] == cell) ncell = support[0]; 368307218a29SMatthew 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); 368407218a29SMatthew G. Knepley // Get closure of both face and cell, stick in cell for normal fields and face for cohesive fields 368507218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plex, section, locX, ncell, &Nxc, &xc)); 368674a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, ncell, NULL, &xc_t)); 368707218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 368807218a29SMatthew G. Knepley PetscInt fdofIn, foffIn; 368907218a29SMatthew G. Knepley PetscBool cohesive; 369007218a29SMatthew G. Knepley 369107218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 369207218a29SMatthew G. Knepley if (cohesive) continue; 369307218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn)); 369407218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn)); 369507218a29SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + s * fdofIn + i] = xc[foffIn + i]; 369674a0c561SMatthew G. Knepley if (locX_t) 369774a0c561SMatthew G. Knepley for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + s * fdofIn + i] = xc_t[foffIn + i]; 369807218a29SMatthew G. Knepley Nx += fdofIn; 369907218a29SMatthew G. Knepley } 370007218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plex, section, locX, ncell, &Nxc, &xc)); 370174a0c561SMatthew G. Knepley if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, ncell, NULL, &xc_t)); 370207218a29SMatthew G. Knepley } 370307218a29SMatthew 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); 370407218a29SMatthew G. Knepley 370507218a29SMatthew G. Knepley if (locA) { 370607218a29SMatthew G. Knepley PetscScalar *al = &(*a)[cind * totDimAux]; 370707218a29SMatthew G. Knepley PetscInt subcell; 370807218a29SMatthew G. Knepley 370907218a29SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 371007218a29SMatthew G. Knepley PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, &Nx, &x)); 371107218a29SMatthew 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); 371207218a29SMatthew G. Knepley for (PetscInt i = 0; i < totDimAux; ++i) al[i] = x[i]; 371307218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, &Nx, &x)); 371407218a29SMatthew G. Knepley } 371507218a29SMatthew G. Knepley } 371607218a29SMatthew G. Knepley PetscCall(DMDestroy(&plex)); 371707218a29SMatthew G. Knepley PetscCall(DMDestroy(&plexA)); 371807218a29SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 371907218a29SMatthew G. Knepley PetscFunctionReturn(PETSC_SUCCESS); 372007218a29SMatthew G. Knepley } 372107218a29SMatthew G. Knepley 372207218a29SMatthew G. Knepley /* 37233e2b0218SMatthew G. Knepley DMPlexGetHybridFields - Get the field values for the negative side (s = 0) and positive side (s = 1) of the interface 372407218a29SMatthew G. Knepley 372507218a29SMatthew G. Knepley Input Parameters: 372607218a29SMatthew G. Knepley + dm - The full domain DM 372707218a29SMatthew G. Knepley . dmX - An array of DM for the field, say an auxiliary DM, indexed by s 372807218a29SMatthew G. Knepley . dsX - An array of PetscDS for the field, indexed by s 372907218a29SMatthew G. Knepley . cellIS - The interface cells for which we want values 373007218a29SMatthew G. Knepley . locX - An array of local vectors with the field values, indexed by s 373107218a29SMatthew G. Knepley - useCell - Flag to have values come from neighboring cell rather than endcap face 373207218a29SMatthew G. Knepley 373307218a29SMatthew G. Knepley Output Parameter: 373407218a29SMatthew G. Knepley . x - An array of field values, indexed by s 373507218a29SMatthew G. Knepley 373607218a29SMatthew G. Knepley Note: 373776fbde31SPierre Jolivet The arrays in `x` will be allocated using `DMGetWorkArray()`, and must be returned using `DMPlexRestoreHybridFields()`. 373807218a29SMatthew G. Knepley 373907218a29SMatthew G. Knepley Level: advanced 374007218a29SMatthew G. Knepley 374176fbde31SPierre Jolivet .seealso: `DMPlexRestoreHybridFields()`, `DMGetWorkArray()` 374207218a29SMatthew G. Knepley */ 374307218a29SMatthew G. Knepley static PetscErrorCode DMPlexGetHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[]) 374407218a29SMatthew G. Knepley { 374507218a29SMatthew G. Knepley DM plexX[2]; 374607218a29SMatthew G. Knepley DMEnclosureType encX[2]; 374707218a29SMatthew G. Knepley PetscSection sectionX[2]; 374807218a29SMatthew G. Knepley const PetscInt *cells; 374907218a29SMatthew G. Knepley PetscInt cStart, cEnd, numCells, c, s, totDimX[2]; 375007218a29SMatthew G. Knepley 375107218a29SMatthew G. Knepley PetscFunctionBegin; 37524f572ea9SToby Isaac PetscAssertPointer(locX, 5); 375307218a29SMatthew G. Knepley if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS); 37544f572ea9SToby Isaac PetscAssertPointer(dmX, 2); 37554f572ea9SToby Isaac PetscAssertPointer(dsX, 3); 375607218a29SMatthew G. Knepley PetscValidHeaderSpecific(cellIS, IS_CLASSID, 4); 37574f572ea9SToby Isaac PetscAssertPointer(x, 7); 37589566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 37596528b96dSMatthew G. Knepley numCells = cEnd - cStart; 3760148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 376107218a29SMatthew G. Knepley PetscValidHeaderSpecific(dmX[s], DM_CLASSID, 2); 376207218a29SMatthew G. Knepley PetscValidHeaderSpecific(dsX[s], PETSCDS_CLASSID, 3); 376307218a29SMatthew G. Knepley PetscValidHeaderSpecific(locX[s], VEC_CLASSID, 5); 376407218a29SMatthew G. Knepley PetscCall(DMPlexConvertPlex(dmX[s], &plexX[s], PETSC_FALSE)); 376507218a29SMatthew G. Knepley PetscCall(DMGetEnclosureRelation(dmX[s], dm, &encX[s])); 376607218a29SMatthew G. Knepley PetscCall(DMGetLocalSection(dmX[s], §ionX[s])); 376707218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsX[s], &totDimX[s])); 376807218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dmX[s], numCells * totDimX[s], MPIU_SCALAR, &x[s])); 376904c51a94SMatthew G. Knepley } 3770148442b3SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 37716528b96dSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 37726528b96dSMatthew G. Knepley const PetscInt cind = c - cStart; 37736528b96dSMatthew G. Knepley const PetscInt *cone, *ornt; 37746528b96dSMatthew G. Knepley 37759566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 37769566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 377707218a29SMatthew 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]); 3778148442b3SMatthew G. Knepley for (s = 0; s < 2; ++s) { 377907218a29SMatthew G. Knepley const PetscInt tdX = totDimX[s]; 378007218a29SMatthew G. Knepley PetscScalar *closure = NULL, *xl = &x[s][cind * tdX]; 378107218a29SMatthew G. Knepley PetscInt face = cone[s], point = face, subpoint, Nx, i; 378207218a29SMatthew G. Knepley 378307218a29SMatthew G. Knepley if (useCell) { 37845fedec97SMatthew G. Knepley const PetscInt *support; 378507218a29SMatthew G. Knepley PetscInt ssize; 37866528b96dSMatthew G. Knepley 378707218a29SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, face, &support)); 378807218a29SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, face, &ssize)); 378907218a29SMatthew 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); 379007218a29SMatthew G. Knepley if (support[0] == cell) point = support[1]; 379107218a29SMatthew G. Knepley else if (support[1] == cell) point = support[0]; 379207218a29SMatthew 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); 379307218a29SMatthew G. Knepley } 379407218a29SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(plexX[s], dm, encX[s], point, &subpoint)); 3795e8e188d2SZach Atkins PetscCall(DMPlexVecGetOrientedClosure_Internal(plexX[s], sectionX[s], PETSC_FALSE, locX[s], subpoint, ornt[s], &Nx, &closure)); 379607218a29SMatthew 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); 379707218a29SMatthew G. Knepley for (i = 0; i < Nx; ++i) xl[i] = closure[i]; 379807218a29SMatthew G. Knepley PetscCall(DMPlexVecRestoreClosure(plexX[s], sectionX[s], locX[s], subpoint, &Nx, &closure)); 37996528b96dSMatthew G. Knepley } 38006528b96dSMatthew G. Knepley } 380107218a29SMatthew G. Knepley for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexX[s])); 38029566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 38033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 38046528b96dSMatthew G. Knepley } 38056528b96dSMatthew G. Knepley 380607218a29SMatthew G. Knepley static PetscErrorCode DMPlexRestoreHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[]) 3807d71ae5a4SJacob Faibussowitsch { 38086528b96dSMatthew G. Knepley PetscFunctionBegin; 380907218a29SMatthew G. Knepley if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS); 381007218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dmX[0], 0, MPIU_SCALAR, &x[0])); 381107218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dmX[1], 0, MPIU_SCALAR, &x[1])); 38123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 38136528b96dSMatthew G. Knepley } 38146528b96dSMatthew G. Knepley 38152f856554SMatthew G. Knepley /*@C 38162f856554SMatthew G. Knepley DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 38172f856554SMatthew G. Knepley 38182f856554SMatthew G. Knepley Input Parameters: 3819a1cb98faSBarry Smith + dm - The `DM` 38202f856554SMatthew G. Knepley . fStart - The first face to include 38212f856554SMatthew G. Knepley . fEnd - The first face to exclude 38222f856554SMatthew G. Knepley . locX - A local vector with the solution fields 38232f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 38242f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 38252f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 382660225df5SJacob Faibussowitsch - locGrad - A local vector with field gradients, or NULL 38272f856554SMatthew G. Knepley 38282f856554SMatthew G. Knepley Output Parameters: 38292f856554SMatthew G. Knepley + Nface - The number of faces with field values 38302f856554SMatthew G. Knepley . uL - The field values at the left side of the face 38312f856554SMatthew G. Knepley - uR - The field values at the right side of the face 38322f856554SMatthew G. Knepley 38332f856554SMatthew G. Knepley Level: developer 38342f856554SMatthew G. Knepley 38351cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 38362f856554SMatthew G. Knepley @*/ 3837d71ae5a4SJacob 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) 3838d71ae5a4SJacob Faibussowitsch { 38392f856554SMatthew G. Knepley DM dmFace, dmCell, dmGrad = NULL; 38402f856554SMatthew G. Knepley PetscSection section; 38412f856554SMatthew G. Knepley PetscDS prob; 38422f856554SMatthew G. Knepley DMLabel ghostLabel; 38432f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 38442f856554SMatthew G. Knepley PetscBool *isFE; 38452f856554SMatthew G. Knepley PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 38462f856554SMatthew G. Knepley 38472f856554SMatthew G. Knepley PetscFunctionBegin; 38482f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 38492f856554SMatthew G. Knepley PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3850ad540459SPierre Jolivet if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5); 38512f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 38522f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 3853ad540459SPierre Jolivet if (locGrad) PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8); 38544f572ea9SToby Isaac PetscAssertPointer(uL, 10); 38554f572ea9SToby Isaac PetscAssertPointer(uR, 11); 38569566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 38579566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 38589566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 38599566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 38609566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalComponents(prob, &Nc)); 38619566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nf, &isFE)); 38622f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 38632f856554SMatthew G. Knepley PetscObject obj; 38642f856554SMatthew G. Knepley PetscClassId id; 38652f856554SMatthew G. Knepley 38669566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 38679566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 38689371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 38699371c9d4SSatish Balay isFE[f] = PETSC_TRUE; 38709371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 38719371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 38729371c9d4SSatish Balay } else { 38739371c9d4SSatish Balay isFE[f] = PETSC_FALSE; 38749371c9d4SSatish Balay } 38752f856554SMatthew G. Knepley } 38769566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 38779566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locX, &x)); 38789566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 38799566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 38809566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 38819566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 38822f856554SMatthew G. Knepley if (locGrad) { 38839566063dSJacob Faibussowitsch PetscCall(VecGetDM(locGrad, &dmGrad)); 38849566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(locGrad, &lgrad)); 38852f856554SMatthew G. Knepley } 38869566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uL)); 38879566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uR)); 38882f856554SMatthew G. Knepley /* Right now just eat the extra work for FE (could make a cell loop) */ 38892f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 38902f856554SMatthew G. Knepley const PetscInt *cells; 38912f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 38922f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 38932f856554SMatthew G. Knepley PetscScalar *xL, *xR, *gL, *gR; 38942f856554SMatthew G. Knepley PetscScalar *uLl = *uL, *uRl = *uR; 38952f856554SMatthew G. Knepley PetscInt ghost, nsupp, nchild; 38962f856554SMatthew G. Knepley 38979566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 38989566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 38999566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 39002f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 39019566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 39029566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 39039566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 39049566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 39052f856554SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 39062f856554SMatthew G. Knepley PetscInt off; 39072f856554SMatthew G. Knepley 39089566063dSJacob Faibussowitsch PetscCall(PetscDSGetComponentOffset(prob, f, &off)); 39092f856554SMatthew G. Knepley if (isFE[f]) { 39102f856554SMatthew G. Knepley const PetscInt *cone; 39112f856554SMatthew G. Knepley PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 39122f856554SMatthew G. Knepley 39132f856554SMatthew G. Knepley xL = xR = NULL; 39149566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 39159566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL)); 39169566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR)); 39179566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[0], &cone)); 39189566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL)); 39199371c9d4SSatish Balay for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) 39209371c9d4SSatish Balay if (cone[faceLocL] == face) break; 39219566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cells[1], &cone)); 39229566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR)); 39239371c9d4SSatish Balay for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) 39249371c9d4SSatish Balay if (cone[faceLocR] == face) break; 39251dca8a05SBarry 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]); 39262f856554SMatthew G. Knepley /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 39272f856554SMatthew G. Knepley /* TODO: this is a hack that might not be right for nonconforming */ 39282f856554SMatthew G. Knepley if (faceLocL < coneSizeL) { 39299566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface * Nc + off])); 39309566063dSJacob Faibussowitsch if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 39312f856554SMatthew G. Knepley else { 39329371c9d4SSatish Balay for (d = 0; d < comp; ++d) uRl[iface * Nc + off + d] = uLl[iface * Nc + off + d]; 39339371c9d4SSatish Balay } 39349371c9d4SSatish Balay } else { 39359566063dSJacob Faibussowitsch PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 39369566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 39372f856554SMatthew G. Knepley for (d = 0; d < comp; ++d) uLl[iface * Nc + off + d] = uRl[iface * Nc + off + d]; 39382f856554SMatthew G. Knepley } 39399566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL)); 39409566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR)); 39412f856554SMatthew G. Knepley } else { 39422f856554SMatthew G. Knepley PetscFV fv; 39432f856554SMatthew G. Knepley PetscInt numComp, c; 39442f856554SMatthew G. Knepley 39459566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *)&fv)); 39469566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &numComp)); 39479566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL)); 39489566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR)); 39492f856554SMatthew G. Knepley if (dmGrad) { 39502f856554SMatthew G. Knepley PetscReal dxL[3], dxR[3]; 39512f856554SMatthew G. Knepley 39529566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL)); 39539566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR)); 39542f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 39552f856554SMatthew G. Knepley DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 39562f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 39572f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c * dim], dxL); 39582f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c * dim], dxR); 39592f856554SMatthew G. Knepley } 39602f856554SMatthew G. Knepley } else { 39612f856554SMatthew G. Knepley for (c = 0; c < numComp; ++c) { 39622f856554SMatthew G. Knepley uLl[iface * Nc + off + c] = xL[c]; 39632f856554SMatthew G. Knepley uRl[iface * Nc + off + c] = xR[c]; 39642f856554SMatthew G. Knepley } 39652f856554SMatthew G. Knepley } 39662f856554SMatthew G. Knepley } 39672f856554SMatthew G. Knepley } 39682f856554SMatthew G. Knepley ++iface; 39692f856554SMatthew G. Knepley } 39702f856554SMatthew G. Knepley *Nface = iface; 39719566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(locX, &x)); 39729566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 39739566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 397448a46eb9SPierre Jolivet if (locGrad) PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 39759566063dSJacob Faibussowitsch PetscCall(PetscFree(isFE)); 39763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 39772f856554SMatthew G. Knepley } 39782f856554SMatthew G. Knepley 39792f856554SMatthew G. Knepley /*@C 39802f856554SMatthew G. Knepley DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 39812f856554SMatthew G. Knepley 39822f856554SMatthew G. Knepley Input Parameters: 3983a1cb98faSBarry Smith + dm - The `DM` 39842f856554SMatthew G. Knepley . fStart - The first face to include 39852f856554SMatthew G. Knepley . fEnd - The first face to exclude 39862f856554SMatthew G. Knepley . locX - A local vector with the solution fields 39872f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL 39882f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 39892f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry 399060225df5SJacob Faibussowitsch - locGrad - A local vector with field gradients, or NULL 39912f856554SMatthew G. Knepley 39922f856554SMatthew G. Knepley Output Parameters: 39932f856554SMatthew G. Knepley + Nface - The number of faces with field values 39942f856554SMatthew G. Knepley . uL - The field values at the left side of the face 39952f856554SMatthew G. Knepley - uR - The field values at the right side of the face 39962f856554SMatthew G. Knepley 39972f856554SMatthew G. Knepley Level: developer 39982f856554SMatthew G. Knepley 39991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 40002f856554SMatthew G. Knepley @*/ 4001d71ae5a4SJacob 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) 4002d71ae5a4SJacob Faibussowitsch { 40032f856554SMatthew G. Knepley PetscFunctionBegin; 40049566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL)); 40059566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR)); 40063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 40072f856554SMatthew G. Knepley } 40082f856554SMatthew G. Knepley 40092f856554SMatthew G. Knepley /*@C 40102f856554SMatthew G. Knepley DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 40112f856554SMatthew G. Knepley 40122f856554SMatthew G. Knepley Input Parameters: 4013a1cb98faSBarry Smith + dm - The `DM` 40142f856554SMatthew G. Knepley . fStart - The first face to include 40152f856554SMatthew G. Knepley . fEnd - The first face to exclude 40162f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 40172f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 40182f856554SMatthew G. Knepley 40192f856554SMatthew G. Knepley Output Parameters: 40202f856554SMatthew G. Knepley + Nface - The number of faces with field values 40212f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 40222f856554SMatthew G. Knepley - vol - The cell volume 40232f856554SMatthew G. Knepley 40242f856554SMatthew G. Knepley Level: developer 40252f856554SMatthew G. Knepley 40261cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 40272f856554SMatthew G. Knepley @*/ 4028d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 4029d71ae5a4SJacob Faibussowitsch { 40302f856554SMatthew G. Knepley DM dmFace, dmCell; 40312f856554SMatthew G. Knepley DMLabel ghostLabel; 40322f856554SMatthew G. Knepley const PetscScalar *facegeom, *cellgeom; 40332f856554SMatthew G. Knepley PetscInt dim, numFaces = fEnd - fStart, iface, face; 40342f856554SMatthew G. Knepley 40352f856554SMatthew G. Knepley PetscFunctionBegin; 40362f856554SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 40372f856554SMatthew G. Knepley PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 40382f856554SMatthew G. Knepley PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 40394f572ea9SToby Isaac PetscAssertPointer(fgeom, 7); 40404f572ea9SToby Isaac PetscAssertPointer(vol, 8); 40419566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 40429566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 40439566063dSJacob Faibussowitsch PetscCall(VecGetDM(faceGeometry, &dmFace)); 40449566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 40459566063dSJacob Faibussowitsch PetscCall(VecGetDM(cellGeometry, &dmCell)); 40469566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 40479566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(numFaces, fgeom)); 40489566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * 2, MPIU_SCALAR, vol)); 40492f856554SMatthew G. Knepley for (face = fStart, iface = 0; face < fEnd; ++face) { 40502f856554SMatthew G. Knepley const PetscInt *cells; 40512f856554SMatthew G. Knepley PetscFVFaceGeom *fg; 40522f856554SMatthew G. Knepley PetscFVCellGeom *cgL, *cgR; 40532f856554SMatthew G. Knepley PetscFVFaceGeom *fgeoml = *fgeom; 40542f856554SMatthew G. Knepley PetscReal *voll = *vol; 40552f856554SMatthew G. Knepley PetscInt ghost, d, nchild, nsupp; 40562f856554SMatthew G. Knepley 40579566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 40589566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 40599566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 40602f856554SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 40619566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 40629566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &cells)); 40639566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 40649566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 40652f856554SMatthew G. Knepley for (d = 0; d < dim; ++d) { 40662f856554SMatthew G. Knepley fgeoml[iface].centroid[d] = fg->centroid[d]; 40672f856554SMatthew G. Knepley fgeoml[iface].normal[d] = fg->normal[d]; 40682f856554SMatthew G. Knepley } 40692f856554SMatthew G. Knepley voll[iface * 2 + 0] = cgL->volume; 40702f856554SMatthew G. Knepley voll[iface * 2 + 1] = cgR->volume; 40712f856554SMatthew G. Knepley ++iface; 40722f856554SMatthew G. Knepley } 40732f856554SMatthew G. Knepley *Nface = iface; 40749566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 40759566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 40763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 40772f856554SMatthew G. Knepley } 40782f856554SMatthew G. Knepley 40792f856554SMatthew G. Knepley /*@C 40802f856554SMatthew G. Knepley DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 40812f856554SMatthew G. Knepley 40822f856554SMatthew G. Knepley Input Parameters: 4083a1cb98faSBarry Smith + dm - The `DM` 40842f856554SMatthew G. Knepley . fStart - The first face to include 40852f856554SMatthew G. Knepley . fEnd - The first face to exclude 40862f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry 40872f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry 40882f856554SMatthew G. Knepley 40892f856554SMatthew G. Knepley Output Parameters: 40902f856554SMatthew G. Knepley + Nface - The number of faces with field values 40912f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal 40922f856554SMatthew G. Knepley - vol - The cell volume 40932f856554SMatthew G. Knepley 40942f856554SMatthew G. Knepley Level: developer 40952f856554SMatthew G. Knepley 40961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 40972f856554SMatthew G. Knepley @*/ 4098d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 4099d71ae5a4SJacob Faibussowitsch { 41002f856554SMatthew G. Knepley PetscFunctionBegin; 41019566063dSJacob Faibussowitsch PetscCall(PetscFree(*fgeom)); 41029566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol)); 41033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 41042f856554SMatthew G. Knepley } 41052f856554SMatthew G. Knepley 4106d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 4107d71ae5a4SJacob Faibussowitsch { 4108a1cf66bbSMatthew G. Knepley char composeStr[33] = {0}; 4109a1cf66bbSMatthew G. Knepley PetscObjectId id; 4110a1cf66bbSMatthew G. Knepley PetscContainer container; 4111a1cf66bbSMatthew G. Knepley 4112a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 41139566063dSJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)quad, &id)); 411463a3b9bcSJacob Faibussowitsch PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id)); 41159566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container)); 4116a1cf66bbSMatthew G. Knepley if (container) { 41179566063dSJacob Faibussowitsch PetscCall(PetscContainerGetPointer(container, (void **)geom)); 4118a1cf66bbSMatthew G. Knepley } else { 41199566063dSJacob Faibussowitsch PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 41209566063dSJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 41219566063dSJacob Faibussowitsch PetscCall(PetscContainerSetPointer(container, (void *)*geom)); 41229566063dSJacob Faibussowitsch PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom)); 41239566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container)); 41249566063dSJacob Faibussowitsch PetscCall(PetscContainerDestroy(&container)); 4125a1cf66bbSMatthew G. Knepley } 41263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4127a1cf66bbSMatthew G. Knepley } 4128a1cf66bbSMatthew G. Knepley 4129d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 4130d71ae5a4SJacob Faibussowitsch { 4131a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 4132a1cf66bbSMatthew G. Knepley *geom = NULL; 41333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4134a1cf66bbSMatthew G. Knepley } 4135a1cf66bbSMatthew G. Knepley 4136d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 4137d71ae5a4SJacob Faibussowitsch { 413892d50984SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 413992d50984SMatthew G. Knepley const char *name = "Residual"; 414092d50984SMatthew G. Knepley DM dmAux = NULL; 414192d50984SMatthew G. Knepley DMLabel ghostLabel = NULL; 414292d50984SMatthew G. Knepley PetscDS prob = NULL; 414392d50984SMatthew G. Knepley PetscDS probAux = NULL; 414492d50984SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 414592d50984SMatthew G. Knepley PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 414692d50984SMatthew G. Knepley DMField coordField = NULL; 4147c0006e53SPatrick Farrell Vec locA; 4148c0006e53SPatrick Farrell PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 414992d50984SMatthew G. Knepley IS chunkIS; 415092d50984SMatthew G. Knepley const PetscInt *cells; 415192d50984SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 4152364207b6SKarl Rupp PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 415392d50984SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 415406ad1575SMatthew G. Knepley PetscFormKey key; 415592d50984SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 415692d50984SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 415792d50984SMatthew G. Knepley 415892d50984SMatthew G. Knepley PetscFunctionBegin; 41599566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 416092d50984SMatthew G. Knepley /* FEM+FVM */ 416192d50984SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 41629566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 41639566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 41649566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 41659566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 41669566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 416792d50984SMatthew G. Knepley if (locA) { 41689566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 41699566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 41709566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 417192d50984SMatthew G. Knepley } 417292d50984SMatthew G. Knepley /* 2: Get geometric data */ 417392d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 417492d50984SMatthew G. Knepley PetscObject obj; 417592d50984SMatthew G. Knepley PetscClassId id; 417692d50984SMatthew G. Knepley PetscBool fimp; 417792d50984SMatthew G. Knepley 41789566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 417992d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 41809566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 41819566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 4182ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 41835f80ce2aSJacob Faibussowitsch PetscCheck(id != PETSCFV_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Use of FVM with PCPATCH not yet implemented"); 418492d50984SMatthew G. Knepley } 418592d50984SMatthew G. Knepley if (useFEM) { 41869566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 41879566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 418892d50984SMatthew G. Knepley if (maxDegree <= 1) { 41899566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 419048a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 419192d50984SMatthew G. Knepley } else { 41929566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 419392d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 419492d50984SMatthew G. Knepley PetscObject obj; 419592d50984SMatthew G. Knepley PetscClassId id; 419692d50984SMatthew G. Knepley PetscBool fimp; 419792d50984SMatthew G. Knepley 41989566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 419992d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 42009566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 42019566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 420292d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 420392d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 420492d50984SMatthew G. Knepley 42059566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 42069566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 42079566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 420892d50984SMatthew G. Knepley } 420992d50984SMatthew G. Knepley } 421092d50984SMatthew G. Knepley } 421192d50984SMatthew G. Knepley } 421292d50984SMatthew G. Knepley /* Loop over chunks */ 42139566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 42149566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 42159566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 421692d50984SMatthew G. Knepley numCells = cEnd - cStart; 421792d50984SMatthew G. Knepley numChunks = 1; 421892d50984SMatthew G. Knepley cellChunkSize = numCells / numChunks; 421992d50984SMatthew G. Knepley numChunks = PetscMin(1, numCells); 42206528b96dSMatthew G. Knepley key.label = NULL; 42216528b96dSMatthew G. Knepley key.value = 0; 422206ad1575SMatthew G. Knepley key.part = 0; 422392d50984SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 4224c0006e53SPatrick Farrell PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 4225c0006e53SPatrick Farrell PetscReal *vol = NULL; 4226c0006e53SPatrick Farrell PetscFVFaceGeom *fgeom = NULL; 422792d50984SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 4228c0006e53SPatrick Farrell PetscInt numFaces = 0; 422992d50984SMatthew G. Knepley 423092d50984SMatthew G. Knepley /* Extract field coefficients */ 423192d50984SMatthew G. Knepley if (useFEM) { 42329566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 42339566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 42349566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 42359566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 423692d50984SMatthew G. Knepley } 423792d50984SMatthew 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 */ 423892d50984SMatthew G. Knepley /* Loop over fields */ 423992d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 424092d50984SMatthew G. Knepley PetscObject obj; 424192d50984SMatthew G. Knepley PetscClassId id; 424292d50984SMatthew G. Knepley PetscBool fimp; 424392d50984SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 424492d50984SMatthew G. Knepley 42456528b96dSMatthew G. Knepley key.field = f; 42469566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 424792d50984SMatthew G. Knepley if (isImplicit != fimp) continue; 42489566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 42499566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 425092d50984SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 425192d50984SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 425292d50984SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 425392d50984SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 425492d50984SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 425592d50984SMatthew G. Knepley PetscInt Nq, Nb; 425692d50984SMatthew G. Knepley 42579566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 42589566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 42599566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 426092d50984SMatthew G. Knepley blockSize = Nb; 426192d50984SMatthew G. Knepley batchSize = numBlocks * blockSize; 42629566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 426392d50984SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 426492d50984SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 426592d50984SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 426692d50984SMatthew G. Knepley offset = numCells - Nr; 426792d50984SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 426892d50984SMatthew 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) */ 42699566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 42709566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 42719566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 42729566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, &elemVec[offset * totDim])); 42739566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 427492d50984SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 427592d50984SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 427692d50984SMatthew G. Knepley 427792d50984SMatthew G. Knepley Ne = numFaces; 427892d50984SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 427992d50984SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 42809566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 428163a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 428292d50984SMatthew G. Knepley } 428392d50984SMatthew G. Knepley /* Loop over domain */ 428492d50984SMatthew G. Knepley if (useFEM) { 428592d50984SMatthew G. Knepley /* Add elemVec to locX */ 428692d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 428792d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 428892d50984SMatthew G. Knepley const PetscInt cind = c - cStart; 428992d50984SMatthew G. Knepley 42909566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 429192d50984SMatthew G. Knepley if (ghostLabel) { 429292d50984SMatthew G. Knepley PetscInt ghostVal; 429392d50984SMatthew G. Knepley 42949566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 429592d50984SMatthew G. Knepley if (ghostVal > 0) continue; 429692d50984SMatthew G. Knepley } 42979566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 429892d50984SMatthew G. Knepley } 429992d50984SMatthew G. Knepley } 430092d50984SMatthew G. Knepley /* Handle time derivative */ 430192d50984SMatthew G. Knepley if (locX_t) { 430292d50984SMatthew G. Knepley PetscScalar *x_t, *fa; 430392d50984SMatthew G. Knepley 43049566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 43059566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 430692d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 430792d50984SMatthew G. Knepley PetscFV fv; 430892d50984SMatthew G. Knepley PetscObject obj; 430992d50984SMatthew G. Knepley PetscClassId id; 431092d50984SMatthew G. Knepley PetscInt pdim, d; 431192d50984SMatthew G. Knepley 43129566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 43139566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 431492d50984SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 431592d50984SMatthew G. Knepley fv = (PetscFV)obj; 43169566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 431792d50984SMatthew G. Knepley for (c = cS; c < cE; ++c) { 431892d50984SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 431992d50984SMatthew G. Knepley PetscScalar *u_t, *r; 432092d50984SMatthew G. Knepley 432192d50984SMatthew G. Knepley if (ghostLabel) { 432292d50984SMatthew G. Knepley PetscInt ghostVal; 432392d50984SMatthew G. Knepley 43249566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 432592d50984SMatthew G. Knepley if (ghostVal > 0) continue; 432692d50984SMatthew G. Knepley } 43279566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 43289566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 432992d50984SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 433092d50984SMatthew G. Knepley } 433192d50984SMatthew G. Knepley } 43329566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 43339566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 433492d50984SMatthew G. Knepley } 433592d50984SMatthew G. Knepley if (useFEM) { 43369566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 43379566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 433892d50984SMatthew G. Knepley } 433992d50984SMatthew G. Knepley } 43409566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 43419566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 434292d50984SMatthew G. Knepley /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 434392d50984SMatthew G. Knepley if (useFEM) { 434492d50984SMatthew G. Knepley if (maxDegree <= 1) { 43459566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 43469566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 434792d50984SMatthew G. Knepley } else { 434892d50984SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 43499566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 43509566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 435192d50984SMatthew G. Knepley } 43529566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 435392d50984SMatthew G. Knepley } 435492d50984SMatthew G. Knepley } 43559566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 43563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 435792d50984SMatthew G. Knepley } 435892d50984SMatthew G. Knepley 4359a1cf66bbSMatthew G. Knepley /* 4360a1cf66bbSMatthew 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 4361a1cf66bbSMatthew G. Knepley 4362a1cf66bbSMatthew G. Knepley X - The local solution vector 4363a5b23f4aSJose E. Roman X_t - The local solution time derivative vector, or NULL 4364a1cf66bbSMatthew G. Knepley */ 4365d71ae5a4SJacob 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) 4366d71ae5a4SJacob Faibussowitsch { 4367a1cf66bbSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 4368a1cf66bbSMatthew G. Knepley const char *name = "Jacobian", *nameP = "JacobianPre"; 4369a1cf66bbSMatthew G. Knepley DM dmAux = NULL; 4370a1cf66bbSMatthew G. Knepley PetscDS prob, probAux = NULL; 4371a1cf66bbSMatthew G. Knepley PetscSection sectionAux = NULL; 4372a1cf66bbSMatthew G. Knepley Vec A; 4373a1cf66bbSMatthew G. Knepley DMField coordField; 4374a1cf66bbSMatthew G. Knepley PetscFEGeom *cgeomFEM; 4375a1cf66bbSMatthew G. Knepley PetscQuadrature qGeom = NULL; 4376a1cf66bbSMatthew G. Knepley Mat J = Jac, JP = JacP; 4377a1cf66bbSMatthew G. Knepley PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 4378e432b41dSStefano Zampini PetscBool hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE; 4379a1cf66bbSMatthew G. Knepley const PetscInt *cells; 438006ad1575SMatthew G. Knepley PetscFormKey key; 43819b2fc754SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 4382a1cf66bbSMatthew G. Knepley 4383a1cf66bbSMatthew G. Knepley PetscFunctionBegin; 43849566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 43859566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 43869566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 43879566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 43889566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A)); 43899a2a23afSMatthew G. Knepley if (A) { 43909566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 43919566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dmAux, §ionAux)); 43929566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 4393a1cf66bbSMatthew G. Knepley } 4394a1cf66bbSMatthew G. Knepley /* Get flags */ 43959566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 43969566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4397a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4398a1cf66bbSMatthew G. Knepley PetscObject disc; 4399a1cf66bbSMatthew G. Knepley PetscClassId id; 44009566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc)); 44019566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(disc, &id)); 44029371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 44039371c9d4SSatish Balay isFE[fieldI] = PETSC_TRUE; 44049371c9d4SSatish Balay } else if (id == PETSCFV_CLASSID) { 44059371c9d4SSatish Balay hasFV = PETSC_TRUE; 44069371c9d4SSatish Balay isFE[fieldI] = PETSC_FALSE; 44079371c9d4SSatish Balay } 4408a1cf66bbSMatthew G. Knepley } 44099566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 44109566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 44119566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 4412a1cf66bbSMatthew G. Knepley assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 4413a1cf66bbSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 44149566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */ 44159566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 44169566063dSJacob Faibussowitsch if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4417a1cf66bbSMatthew G. Knepley /* Compute batch sizes */ 4418a1cf66bbSMatthew G. Knepley if (isFE[0]) { 4419a1cf66bbSMatthew G. Knepley PetscFE fe; 4420a1cf66bbSMatthew G. Knepley PetscQuadrature q; 4421a1cf66bbSMatthew G. Knepley PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 4422a1cf66bbSMatthew G. Knepley 44239566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 44249566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &q)); 44259566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL)); 44269566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 44279566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4428a1cf66bbSMatthew G. Knepley blockSize = Nb * numQuadPoints; 4429a1cf66bbSMatthew G. Knepley batchSize = numBlocks * blockSize; 4430a1cf66bbSMatthew G. Knepley chunkSize = numBatches * batchSize; 4431a1cf66bbSMatthew G. Knepley numChunks = numCells / chunkSize + numCells % chunkSize; 44329566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4433a1cf66bbSMatthew G. Knepley } else { 4434a1cf66bbSMatthew G. Knepley chunkSize = numCells; 4435a1cf66bbSMatthew G. Knepley numChunks = 1; 4436a1cf66bbSMatthew G. Knepley } 4437a1cf66bbSMatthew G. Knepley /* Get work space */ 4438a1cf66bbSMatthew 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; 44399566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work)); 44409566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(work, wsz)); 4441a1cf66bbSMatthew G. Knepley off = 0; 4442a1cf66bbSMatthew G. Knepley u = X ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4443a1cf66bbSMatthew G. Knepley u_t = X_t ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4444a1cf66bbSMatthew G. Knepley a = dmAux ? (sz = chunkSize * totDimAux, off += sz, work + off - sz) : NULL; 4445a1cf66bbSMatthew G. Knepley elemMat = hasJac ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4446a1cf66bbSMatthew G. Knepley elemMatP = hasPrec ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4447a1cf66bbSMatthew G. Knepley elemMatD = hasDyn ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 444863a3b9bcSJacob Faibussowitsch PetscCheck(off == wsz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %" PetscInt_FMT " should be %" PetscInt_FMT, off, wsz); 4449a1cf66bbSMatthew G. Knepley /* Setup geometry */ 44509566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 44519566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 44529566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 4453a1cf66bbSMatthew G. Knepley if (!qGeom) { 4454a1cf66bbSMatthew G. Knepley PetscFE fe; 4455a1cf66bbSMatthew G. Knepley 44569566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 44579566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 44589566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 4459a1cf66bbSMatthew G. Knepley } 44609566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4461a1cf66bbSMatthew G. Knepley /* Compute volume integrals */ 44629566063dSJacob Faibussowitsch if (assembleJac) PetscCall(MatZeroEntries(J)); 44639566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(JP)); 44646528b96dSMatthew G. Knepley key.label = NULL; 44656528b96dSMatthew G. Knepley key.value = 0; 446606ad1575SMatthew G. Knepley key.part = 0; 4467a1cf66bbSMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 4468a1cf66bbSMatthew G. Knepley const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 4469a1cf66bbSMatthew G. Knepley PetscInt c; 4470a1cf66bbSMatthew G. Knepley 4471a1cf66bbSMatthew G. Knepley /* Extract values */ 4472a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4473a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4474a1cf66bbSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 4475a1cf66bbSMatthew G. Knepley PetscInt i; 4476a1cf66bbSMatthew G. Knepley 4477a1cf66bbSMatthew G. Knepley if (X) { 44789566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 4479a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 44809566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 4481a1cf66bbSMatthew G. Knepley } 4482a1cf66bbSMatthew G. Knepley if (X_t) { 44839566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 4484a1cf66bbSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[c * totDim + i] = x_t[i]; 44859566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 4486a1cf66bbSMatthew G. Knepley } 4487a1cf66bbSMatthew G. Knepley if (dmAux) { 44889566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4489a1cf66bbSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 44909566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4491a1cf66bbSMatthew G. Knepley } 4492a1cf66bbSMatthew G. Knepley } 4493a1cf66bbSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 4494a1cf66bbSMatthew G. Knepley PetscFE fe; 44959566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 4496a1cf66bbSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 44976528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 44989566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat)); 44999566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP)); 45009566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD)); 4501a1cf66bbSMatthew G. Knepley } 4502a1cf66bbSMatthew G. Knepley /* For finite volume, add the identity */ 4503a1cf66bbSMatthew G. Knepley if (!isFE[fieldI]) { 4504a1cf66bbSMatthew G. Knepley PetscFV fv; 4505a1cf66bbSMatthew G. Knepley PetscInt eOffset = 0, Nc, fc, foff; 4506a1cf66bbSMatthew G. Knepley 45079566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff)); 45089566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 45099566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &Nc)); 4510a1cf66bbSMatthew G. Knepley for (c = 0; c < chunkSize; ++c, eOffset += totDim * totDim) { 4511a1cf66bbSMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 4512a1cf66bbSMatthew G. Knepley const PetscInt i = foff + fc; 4513ad540459SPierre Jolivet if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 4514ad540459SPierre Jolivet if (hasPrec) elemMatP[eOffset + i * totDim + i] = 1.0; 4515a1cf66bbSMatthew G. Knepley } 4516a1cf66bbSMatthew G. Knepley } 4517a1cf66bbSMatthew G. Knepley } 4518a1cf66bbSMatthew G. Knepley } 4519a1cf66bbSMatthew G. Knepley /* Add contribution from X_t */ 45209371c9d4SSatish Balay if (hasDyn) { 45219371c9d4SSatish Balay for (c = 0; c < chunkSize * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 45229371c9d4SSatish Balay } 4523a1cf66bbSMatthew G. Knepley /* Insert values into matrix */ 4524a1cf66bbSMatthew G. Knepley for (c = 0; c < Ncell; ++c) { 4525a1cf66bbSMatthew G. Knepley const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4526a1cf66bbSMatthew G. Knepley if (mesh->printFEM > 1) { 45279566063dSJacob Faibussowitsch if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c - cStart) * totDim * totDim])); 45289566063dSJacob Faibussowitsch if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c - cStart) * totDim * totDim])); 4529a1cf66bbSMatthew G. Knepley } 4530e8e188d2SZach Atkins if (assembleJac) PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4531e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JP, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4532a1cf66bbSMatthew G. Knepley } 4533a1cf66bbSMatthew G. Knepley } 4534a1cf66bbSMatthew G. Knepley /* Cleanup */ 45359566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 45369566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 45379566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 45389566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 45399566063dSJacob 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)); 4540a1cf66bbSMatthew G. Knepley /* Compute boundary integrals */ 45419566063dSJacob Faibussowitsch /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */ 4542a1cf66bbSMatthew G. Knepley /* Assemble matrix */ 45439371c9d4SSatish Balay if (assembleJac) { 45449371c9d4SSatish Balay PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 45459371c9d4SSatish Balay PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 45469371c9d4SSatish Balay } 45479371c9d4SSatish Balay PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 45489371c9d4SSatish Balay PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 45499566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 45503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4551a1cf66bbSMatthew G. Knepley } 45523e9753d6SMatthew G. Knepley 45533e9753d6SMatthew G. Knepley /******** FEM Assembly Function ********/ 45543e9753d6SMatthew G. Knepley 4555d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy) 4556d71ae5a4SJacob Faibussowitsch { 45573e9753d6SMatthew G. Knepley PetscBool isPlex; 45583e9753d6SMatthew G. Knepley 45593e9753d6SMatthew G. Knepley PetscFunctionBegin; 45609566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 45613e9753d6SMatthew G. Knepley if (isPlex) { 45623e9753d6SMatthew G. Knepley *plex = dm; 45639566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 45643e9753d6SMatthew G. Knepley } else { 45659566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 45663e9753d6SMatthew G. Knepley if (!*plex) { 45679566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 45689566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 45691baa6e33SBarry Smith if (copy) PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 45703e9753d6SMatthew G. Knepley } else { 45719566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)*plex)); 45723e9753d6SMatthew G. Knepley } 45733e9753d6SMatthew G. Knepley } 45743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 45753e9753d6SMatthew G. Knepley } 45763e9753d6SMatthew G. Knepley 45773e9753d6SMatthew G. Knepley /*@ 45783e9753d6SMatthew G. Knepley DMPlexGetGeometryFVM - Return precomputed geometric data 45793e9753d6SMatthew G. Knepley 458020f4b53cSBarry Smith Collective 45813e9753d6SMatthew G. Knepley 45823e9753d6SMatthew G. Knepley Input Parameter: 4583a1cb98faSBarry Smith . dm - The `DM` 45843e9753d6SMatthew G. Knepley 45853e9753d6SMatthew G. Knepley Output Parameters: 45863e9753d6SMatthew G. Knepley + facegeom - The values precomputed from face geometry 45873e9753d6SMatthew G. Knepley . cellgeom - The values precomputed from cell geometry 45883e9753d6SMatthew G. Knepley - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell 45893e9753d6SMatthew G. Knepley 45903e9753d6SMatthew G. Knepley Level: developer 45913e9753d6SMatthew G. Knepley 45921cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMTSSetRHSFunctionLocal()` 45933e9753d6SMatthew G. Knepley @*/ 4594d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius) 4595d71ae5a4SJacob Faibussowitsch { 45963e9753d6SMatthew G. Knepley DM plex; 45973e9753d6SMatthew G. Knepley 45983e9753d6SMatthew G. Knepley PetscFunctionBegin; 45993e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 46009566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 46019566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL)); 46029566063dSJacob Faibussowitsch if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius)); 46039566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 46043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 46053e9753d6SMatthew G. Knepley } 46063e9753d6SMatthew G. Knepley 46073e9753d6SMatthew G. Knepley /*@ 46083e9753d6SMatthew G. Knepley DMPlexGetGradientDM - Return gradient data layout 46093e9753d6SMatthew G. Knepley 461020f4b53cSBarry Smith Collective 46113e9753d6SMatthew G. Knepley 46123e9753d6SMatthew G. Knepley Input Parameters: 4613a1cb98faSBarry Smith + dm - The `DM` 461420f4b53cSBarry Smith - fv - The `PetscFV` 46153e9753d6SMatthew G. Knepley 46163e9753d6SMatthew G. Knepley Output Parameter: 46173e9753d6SMatthew G. Knepley . dmGrad - The layout for gradient values 46183e9753d6SMatthew G. Knepley 46193e9753d6SMatthew G. Knepley Level: developer 46203e9753d6SMatthew G. Knepley 46211cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetGeometryFVM()` 46223e9753d6SMatthew G. Knepley @*/ 4623d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad) 4624d71ae5a4SJacob Faibussowitsch { 46253e9753d6SMatthew G. Knepley DM plex; 46263e9753d6SMatthew G. Knepley PetscBool computeGradients; 46273e9753d6SMatthew G. Knepley 46283e9753d6SMatthew G. Knepley PetscFunctionBegin; 46293e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 46303e9753d6SMatthew G. Knepley PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 46314f572ea9SToby Isaac PetscAssertPointer(dmGrad, 3); 46329566063dSJacob Faibussowitsch PetscCall(PetscFVGetComputeGradients(fv, &computeGradients)); 46339371c9d4SSatish Balay if (!computeGradients) { 46349371c9d4SSatish Balay *dmGrad = NULL; 46353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 46369371c9d4SSatish Balay } 46379566063dSJacob Faibussowitsch PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 46389566063dSJacob Faibussowitsch PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad)); 46399566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 46403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 46413e9753d6SMatthew G. Knepley } 46423e9753d6SMatthew G. Knepley 4643d71ae5a4SJacob 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) 4644d71ae5a4SJacob Faibussowitsch { 46453e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 46463e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL; 46473e9753d6SMatthew G. Knepley DMEnclosureType encAux; 46483e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 46493e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 46503e9753d6SMatthew G. Knepley Vec locA = NULL; 46513e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL; 46523e9753d6SMatthew G. Knepley PetscInt totDim, totDimAux = 0; 46533e9753d6SMatthew G. Knepley 46543e9753d6SMatthew G. Knepley PetscFunctionBegin; 46559566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 46569566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 46579566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 46589566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 46599566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 46603e9753d6SMatthew G. Knepley if (locA) { 46613e9753d6SMatthew G. Knepley DM dmAux; 46623e9753d6SMatthew G. Knepley 46639566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 46649566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 46659566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 46669566063dSJacob Faibussowitsch PetscCall(DMGetDS(plexA, &probAux)); 46679566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 46689566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 46693e9753d6SMatthew G. Knepley } 46700c290148SMatthew G. Knepley { 46713e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 46723e9753d6SMatthew G. Knepley PetscInt maxDegree; 46733e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 46743e9753d6SMatthew G. Knepley IS pointIS; 46753e9753d6SMatthew G. Knepley const PetscInt *points; 46763e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 46773e9753d6SMatthew G. Knepley 46789566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 46790c290148SMatthew G. Knepley if (!pointIS) goto end; /* No points with that id on this process */ 46803e9753d6SMatthew G. Knepley { 46813e9753d6SMatthew G. Knepley IS isectIS; 46823e9753d6SMatthew G. Knepley 46833e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 46849566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 46859566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 46863e9753d6SMatthew G. Knepley pointIS = isectIS; 46873e9753d6SMatthew G. Knepley } 46889566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 46899566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 46909566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim, &elemVec, locA ? numFaces * totDimAux : 0, &a)); 46919566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 469248a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 46933e9753d6SMatthew G. Knepley if (!qGeom) { 46943e9753d6SMatthew G. Knepley PetscFE fe; 46953e9753d6SMatthew G. Knepley 46969566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 46979566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 46989566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 46993e9753d6SMatthew G. Knepley } 47009566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 47019566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 47023e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 4703f15274beSMatthew Knepley const PetscInt point = points[face], *support; 47043e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 4705f15274beSMatthew Knepley PetscInt i; 47063e9753d6SMatthew G. Knepley 47079566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 47089566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 47093e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 47109566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 47113e9753d6SMatthew G. Knepley if (locX_t) { 47129566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 47133e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 47149566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 47153e9753d6SMatthew G. Knepley } 47163e9753d6SMatthew G. Knepley if (locA) { 47173e9753d6SMatthew G. Knepley PetscInt subp; 47183e9753d6SMatthew G. Knepley 47199566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 47209566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 47213e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 47229566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 47233e9753d6SMatthew G. Knepley } 47243e9753d6SMatthew G. Knepley } 47259566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numFaces * totDim)); 47263e9753d6SMatthew G. Knepley { 47273e9753d6SMatthew G. Knepley PetscFE fe; 47283e9753d6SMatthew G. Knepley PetscInt Nb; 47293e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 47303e9753d6SMatthew G. Knepley /* Conforming batches */ 47313e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 47323e9753d6SMatthew G. Knepley /* Remainder */ 47333e9753d6SMatthew G. Knepley PetscInt Nr, offset; 47343e9753d6SMatthew G. Knepley 47359566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 47369566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 47379566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 47383e9753d6SMatthew G. Knepley /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */ 47393e9753d6SMatthew G. Knepley blockSize = Nb; 47403e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 47419566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 47423e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 47433e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 47443e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 47453e9753d6SMatthew G. Knepley offset = numFaces - Nr; 47469566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 47479566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 47489566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 47499566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 47509566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, &elemVec[offset * totDim])); 47519566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 47523e9753d6SMatthew G. Knepley } 47533e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 47543e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 47553e9753d6SMatthew G. Knepley 47569566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face * totDim])); 47579566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 47589566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face * totDim], ADD_ALL_VALUES)); 47593e9753d6SMatthew G. Knepley } 47609566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 47619566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 47629566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 47639566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 47649566063dSJacob Faibussowitsch PetscCall(PetscFree4(u, u_t, elemVec, a)); 47653e9753d6SMatthew G. Knepley } 47660c290148SMatthew G. Knepley end: 47679566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 47689566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexA)); 47693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 47703e9753d6SMatthew G. Knepley } 47713e9753d6SMatthew G. Knepley 4772d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF) 4773d71ae5a4SJacob Faibussowitsch { 47743e9753d6SMatthew G. Knepley DMField coordField; 47753e9753d6SMatthew G. Knepley DMLabel depthLabel; 47763e9753d6SMatthew G. Knepley IS facetIS; 47773e9753d6SMatthew G. Knepley PetscInt dim; 47783e9753d6SMatthew G. Knepley 47793e9753d6SMatthew G. Knepley PetscFunctionBegin; 47809566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 47819566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 47829566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 47839566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 47849566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 47859566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 47863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 47873e9753d6SMatthew G. Knepley } 47883e9753d6SMatthew G. Knepley 4789a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4790d71ae5a4SJacob Faibussowitsch { 47913e9753d6SMatthew G. Knepley PetscDS prob; 47923e9753d6SMatthew G. Knepley PetscInt numBd, bd; 47933e9753d6SMatthew G. Knepley DMField coordField = NULL; 47943e9753d6SMatthew G. Knepley IS facetIS = NULL; 47953e9753d6SMatthew G. Knepley DMLabel depthLabel; 47963e9753d6SMatthew G. Knepley PetscInt dim; 47973e9753d6SMatthew G. Knepley 47983e9753d6SMatthew G. Knepley PetscFunctionBegin; 47999566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 48009566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 48019566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 48029566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 48039566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 48043e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 480545480ffeSMatthew G. Knepley PetscWeakForm wf; 48063e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 48073e9753d6SMatthew G. Knepley DMLabel label; 48083e9753d6SMatthew G. Knepley const PetscInt *values; 48090c290148SMatthew G. Knepley PetscInt field, numValues, v; 48103e9753d6SMatthew G. Knepley PetscObject obj; 48113e9753d6SMatthew G. Knepley PetscClassId id; 48120c290148SMatthew G. Knepley PetscFormKey key; 48133e9753d6SMatthew G. Knepley 48149566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL)); 48153d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 48169566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 48179566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 48183d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 48193e9753d6SMatthew G. Knepley if (!facetIS) { 48203e9753d6SMatthew G. Knepley DMLabel depthLabel; 48213e9753d6SMatthew G. Knepley PetscInt dim; 48223e9753d6SMatthew G. Knepley 48239566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 48249566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 48259566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 48263e9753d6SMatthew G. Knepley } 48279566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 48280c290148SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 48290c290148SMatthew G. Knepley key.label = label; 48300c290148SMatthew G. Knepley key.value = values[v]; 48310c290148SMatthew G. Knepley key.field = field; 48320c290148SMatthew G. Knepley key.part = 0; 48339566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 48340c290148SMatthew G. Knepley } 48353e9753d6SMatthew G. Knepley } 48369566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 48373ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 48383e9753d6SMatthew G. Knepley } 48393e9753d6SMatthew G. Knepley 4840d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4841d71ae5a4SJacob Faibussowitsch { 48423e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 48433e9753d6SMatthew G. Knepley const char *name = "Residual"; 48443e9753d6SMatthew G. Knepley DM dmAux = NULL; 48453e9753d6SMatthew G. Knepley DM dmGrad = NULL; 48463e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 48476528b96dSMatthew G. Knepley PetscDS ds = NULL; 48486528b96dSMatthew G. Knepley PetscDS dsAux = NULL; 48493e9753d6SMatthew G. Knepley PetscSection section = NULL; 48503e9753d6SMatthew G. Knepley PetscBool useFEM = PETSC_FALSE; 48513e9753d6SMatthew G. Knepley PetscBool useFVM = PETSC_FALSE; 48523e9753d6SMatthew G. Knepley PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 48533e9753d6SMatthew G. Knepley PetscFV fvm = NULL; 48543e9753d6SMatthew G. Knepley DMField coordField = NULL; 4855*5962854dSMatthew G. Knepley Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 48563e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t, *a, *uL, *uR; 48573e9753d6SMatthew G. Knepley IS chunkIS; 48583e9753d6SMatthew G. Knepley const PetscInt *cells; 48593e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 48603e9753d6SMatthew G. Knepley PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd; 48613e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 48623e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 48633e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 48643e9753d6SMatthew G. Knepley 48653e9753d6SMatthew G. Knepley PetscFunctionBegin; 48663ba16761SJacob Faibussowitsch if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 4867437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 48683ba16761SJacob Faibussowitsch if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 48699566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 48703e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 48713e9753d6SMatthew G. Knepley /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */ 48723e9753d6SMatthew G. Knepley /* FEM+FVM */ 48739566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 48743e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 48759566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 48769566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 487707218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, NULL)); 48789566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 48799566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 48809566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 48813e9753d6SMatthew G. Knepley if (locA) { 48823e9753d6SMatthew G. Knepley PetscInt subcell; 48839566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 48841059d808SMatthew G. Knepley PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell)); 488507218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux, subcell, &dsAux, NULL)); 48869566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 48873e9753d6SMatthew G. Knepley } 48883e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 48893e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 48903e9753d6SMatthew G. Knepley PetscObject obj; 48913e9753d6SMatthew G. Knepley PetscClassId id; 48923e9753d6SMatthew G. Knepley PetscBool fimp; 48933e9753d6SMatthew G. Knepley 48949566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 48953e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 48969566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 48979566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 4898ad540459SPierre Jolivet if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 48999371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 49009371c9d4SSatish Balay useFVM = PETSC_TRUE; 49019371c9d4SSatish Balay fvm = (PetscFV)obj; 49029371c9d4SSatish Balay } 49033e9753d6SMatthew G. Knepley } 49043e9753d6SMatthew G. Knepley if (useFEM) { 49059566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 49069566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 49073e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 49089566063dSJacob Faibussowitsch PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 490948a46eb9SPierre Jolivet if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 49103e9753d6SMatthew G. Knepley } else { 49119566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 49123e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 49133e9753d6SMatthew G. Knepley PetscObject obj; 49143e9753d6SMatthew G. Knepley PetscClassId id; 49153e9753d6SMatthew G. Knepley PetscBool fimp; 49163e9753d6SMatthew G. Knepley 49179566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 49183e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 49199566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 49209566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 49213e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 49223e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 49233e9753d6SMatthew G. Knepley 49249566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 49259566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 49269566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 49273e9753d6SMatthew G. Knepley } 49283e9753d6SMatthew G. Knepley } 49293e9753d6SMatthew G. Knepley } 49303e9753d6SMatthew G. Knepley } 4931*5962854dSMatthew G. Knepley // Handle non-essential (e.g. outflow) boundary values 49323e9753d6SMatthew G. Knepley if (useFVM) { 4933*5962854dSMatthew G. Knepley PetscCall(DMPlexInsertBoundaryValuesFVM(dm, fvm, locX, time, &locGrad)); 49349566063dSJacob Faibussowitsch PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 49359566063dSJacob Faibussowitsch PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad)); 49363e9753d6SMatthew G. Knepley } 49373e9753d6SMatthew G. Knepley /* Loop over chunks */ 49389566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 49393e9753d6SMatthew G. Knepley numCells = cEnd - cStart; 49403e9753d6SMatthew G. Knepley numChunks = 1; 49413e9753d6SMatthew G. Knepley cellChunkSize = numCells / numChunks; 49423e9753d6SMatthew G. Knepley faceChunkSize = (fEnd - fStart) / numChunks; 49433e9753d6SMatthew G. Knepley numChunks = PetscMin(1, numCells); 49443e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 49453e9753d6SMatthew G. Knepley PetscScalar *elemVec, *fluxL, *fluxR; 49463e9753d6SMatthew G. Knepley PetscReal *vol; 49473e9753d6SMatthew G. Knepley PetscFVFaceGeom *fgeom; 49483e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 49493e9753d6SMatthew G. Knepley PetscInt fS = fStart + chunk * faceChunkSize, fE = PetscMin(fS + faceChunkSize, fEnd), numFaces = 0, face; 49503e9753d6SMatthew G. Knepley 49513e9753d6SMatthew G. Knepley /* Extract field coefficients */ 49523e9753d6SMatthew G. Knepley if (useFEM) { 49539566063dSJacob Faibussowitsch PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 49549566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 49559566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 49569566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 49573e9753d6SMatthew G. Knepley } 49583e9753d6SMatthew G. Knepley if (useFVM) { 49599566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 49609566063dSJacob Faibussowitsch PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 49619566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 49629566063dSJacob Faibussowitsch PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 49639566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxL, numFaces * totDim)); 49649566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(fluxR, numFaces * totDim)); 49653e9753d6SMatthew G. Knepley } 49663e9753d6SMatthew 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 */ 49673e9753d6SMatthew G. Knepley /* Loop over fields */ 49683e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 49693e9753d6SMatthew G. Knepley PetscObject obj; 49703e9753d6SMatthew G. Knepley PetscClassId id; 49713e9753d6SMatthew G. Knepley PetscBool fimp; 49723e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 49733e9753d6SMatthew G. Knepley 49746528b96dSMatthew G. Knepley key.field = f; 49759566063dSJacob Faibussowitsch PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 49763e9753d6SMatthew G. Knepley if (isImplicit != fimp) continue; 49779566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 49789566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 49793e9753d6SMatthew G. Knepley if (id == PETSCFE_CLASSID) { 49803e9753d6SMatthew G. Knepley PetscFE fe = (PetscFE)obj; 49813e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 49823e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 49833e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 49843e9753d6SMatthew G. Knepley PetscInt Nq, Nb; 49853e9753d6SMatthew G. Knepley 49869566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 49879566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 49889566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 49893e9753d6SMatthew G. Knepley blockSize = Nb; 49903e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 49919566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 49923e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 49933e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 49943e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 49953e9753d6SMatthew G. Knepley offset = numCells - Nr; 49963e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 49973e9753d6SMatthew 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) */ 49989566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 49999566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec)); 50009566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 5001072f5ffdSStefano Zampini PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux, a ? &a[offset * totDimAux] : NULL, t, &elemVec[offset * totDim])); 50029566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 50033e9753d6SMatthew G. Knepley } else if (id == PETSCFV_CLASSID) { 50043e9753d6SMatthew G. Knepley PetscFV fv = (PetscFV)obj; 50053e9753d6SMatthew G. Knepley 50063e9753d6SMatthew G. Knepley Ne = numFaces; 50073e9753d6SMatthew G. Knepley /* Riemann solve over faces (need fields at face centroids) */ 50083e9753d6SMatthew G. Knepley /* We need to evaluate FE fields at those coordinates */ 50099566063dSJacob Faibussowitsch PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 501063a3b9bcSJacob Faibussowitsch } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 50113e9753d6SMatthew G. Knepley } 50123e9753d6SMatthew G. Knepley /* Loop over domain */ 50133e9753d6SMatthew G. Knepley if (useFEM) { 50143e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 50153e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 50163e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 50173e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 50183e9753d6SMatthew G. Knepley 50199566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 50203e9753d6SMatthew G. Knepley if (ghostLabel) { 50213e9753d6SMatthew G. Knepley PetscInt ghostVal; 50223e9753d6SMatthew G. Knepley 50239566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 50243e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 50253e9753d6SMatthew G. Knepley } 50269566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 50273e9753d6SMatthew G. Knepley } 50283e9753d6SMatthew G. Knepley } 50293e9753d6SMatthew G. Knepley if (useFVM) { 50303e9753d6SMatthew G. Knepley PetscScalar *fa; 50313e9753d6SMatthew G. Knepley PetscInt iface; 50323e9753d6SMatthew G. Knepley 50339566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 50343e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 50353e9753d6SMatthew G. Knepley PetscFV fv; 50363e9753d6SMatthew G. Knepley PetscObject obj; 50373e9753d6SMatthew G. Knepley PetscClassId id; 5038*5962854dSMatthew G. Knepley PetscInt cdim, foff, pdim; 50393e9753d6SMatthew G. Knepley 5040*5962854dSMatthew G. Knepley PetscCall(DMGetCoordinateDim(dm, &cdim)); 50419566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 50429566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(ds, f, &foff)); 50439566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 50443e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 50453e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 50469566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 50473e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 50483e9753d6SMatthew G. Knepley for (face = fS, iface = 0; face < fE; ++face) { 50493e9753d6SMatthew G. Knepley const PetscInt *scells; 50503e9753d6SMatthew G. Knepley PetscScalar *fL = NULL, *fR = NULL; 50513e9753d6SMatthew G. Knepley PetscInt ghost, d, nsupp, nchild; 50523e9753d6SMatthew G. Knepley 50539566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 50549566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 50559566063dSJacob Faibussowitsch PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 50563e9753d6SMatthew G. Knepley if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 50579566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, face, &scells)); 50589566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[0], &ghost)); 50599566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL)); 50609566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, scells[1], &ghost)); 50619566063dSJacob Faibussowitsch if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR)); 5062*5962854dSMatthew G. Knepley if (mesh->printFVM > 1) { 5063*5962854dSMatthew G. Knepley PetscCall(DMPrintCellVectorReal(face, "Residual: normal", cdim, fgeom[iface].normal)); 5064*5962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: left state", pdim, &uL[iface * totDim + foff])); 5065*5962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: right state", pdim, &uR[iface * totDim + foff])); 5066*5962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: left flux", pdim, &fluxL[iface * totDim + foff])); 5067*5962854dSMatthew G. Knepley PetscCall(DMPrintCellVector(face, "Residual: right flux", pdim, &fluxR[iface * totDim + foff])); 5068*5962854dSMatthew G. Knepley } 50693e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) { 50703e9753d6SMatthew G. Knepley if (fL) fL[d] -= fluxL[iface * totDim + foff + d]; 50713e9753d6SMatthew G. Knepley if (fR) fR[d] += fluxR[iface * totDim + foff + d]; 50723e9753d6SMatthew G. Knepley } 50733e9753d6SMatthew G. Knepley ++iface; 50743e9753d6SMatthew G. Knepley } 50753e9753d6SMatthew G. Knepley } 50769566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 50773e9753d6SMatthew G. Knepley } 50783e9753d6SMatthew G. Knepley /* Handle time derivative */ 50793e9753d6SMatthew G. Knepley if (locX_t) { 50803e9753d6SMatthew G. Knepley PetscScalar *x_t, *fa; 50813e9753d6SMatthew G. Knepley 50829566063dSJacob Faibussowitsch PetscCall(VecGetArray(locF, &fa)); 50839566063dSJacob Faibussowitsch PetscCall(VecGetArray(locX_t, &x_t)); 50843e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 50853e9753d6SMatthew G. Knepley PetscFV fv; 50863e9753d6SMatthew G. Knepley PetscObject obj; 50873e9753d6SMatthew G. Knepley PetscClassId id; 50883e9753d6SMatthew G. Knepley PetscInt pdim, d; 50893e9753d6SMatthew G. Knepley 50909566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 50919566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 50923e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 50933e9753d6SMatthew G. Knepley fv = (PetscFV)obj; 50949566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &pdim)); 50953e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 50963e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 50973e9753d6SMatthew G. Knepley PetscScalar *u_t, *r; 50983e9753d6SMatthew G. Knepley 50993e9753d6SMatthew G. Knepley if (ghostLabel) { 51003e9753d6SMatthew G. Knepley PetscInt ghostVal; 51013e9753d6SMatthew G. Knepley 51029566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 51033e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 51043e9753d6SMatthew G. Knepley } 51059566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 51069566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 51073e9753d6SMatthew G. Knepley for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 51083e9753d6SMatthew G. Knepley } 51093e9753d6SMatthew G. Knepley } 51109566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locX_t, &x_t)); 51119566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(locF, &fa)); 51123e9753d6SMatthew G. Knepley } 51133e9753d6SMatthew G. Knepley if (useFEM) { 51149566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 51159566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 51163e9753d6SMatthew G. Knepley } 51173e9753d6SMatthew G. Knepley if (useFVM) { 51189566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 51199566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 51209566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 51219566063dSJacob Faibussowitsch PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 51229566063dSJacob Faibussowitsch if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 51233e9753d6SMatthew G. Knepley } 51243e9753d6SMatthew G. Knepley } 51259566063dSJacob Faibussowitsch if (useFEM) PetscCall(ISDestroy(&chunkIS)); 51269566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 51273e9753d6SMatthew G. Knepley 51283e9753d6SMatthew G. Knepley if (useFEM) { 51299566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user)); 51303e9753d6SMatthew G. Knepley 51313e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 51329566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 51339566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 51343e9753d6SMatthew G. Knepley } else { 51353e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 51369566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 51379566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&quads[f])); 51383e9753d6SMatthew G. Knepley } 51399566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 51403e9753d6SMatthew G. Knepley } 51413e9753d6SMatthew G. Knepley } 51423e9753d6SMatthew G. Knepley 51433e9753d6SMatthew G. Knepley /* FEM */ 51443e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 51453e9753d6SMatthew G. Knepley /* 2: Get geometric data */ 51463e9753d6SMatthew G. Knepley /* 3: Handle boundary values */ 51473e9753d6SMatthew G. Knepley /* 4: Loop over domain */ 51483e9753d6SMatthew G. Knepley /* Extract coefficients */ 51493e9753d6SMatthew G. Knepley /* Loop over fields */ 51503e9753d6SMatthew G. Knepley /* Set tiling for FE*/ 51513e9753d6SMatthew G. Knepley /* Integrate FE residual to get elemVec */ 51523e9753d6SMatthew G. Knepley /* Loop over subdomain */ 51533e9753d6SMatthew G. Knepley /* Loop over quad points */ 51543e9753d6SMatthew G. Knepley /* Transform coords to real space */ 51553e9753d6SMatthew G. Knepley /* Evaluate field and aux fields at point */ 51563e9753d6SMatthew G. Knepley /* Evaluate residual at point */ 51573e9753d6SMatthew G. Knepley /* Transform residual to real space */ 51583e9753d6SMatthew G. Knepley /* Add residual to elemVec */ 51593e9753d6SMatthew G. Knepley /* Loop over domain */ 51603e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 51613e9753d6SMatthew G. Knepley 51623e9753d6SMatthew G. Knepley /* FVM */ 51633e9753d6SMatthew G. Knepley /* Get geometric data */ 51643e9753d6SMatthew G. Knepley /* If using gradients */ 51653e9753d6SMatthew G. Knepley /* Compute gradient data */ 51663e9753d6SMatthew G. Knepley /* Loop over domain faces */ 51673e9753d6SMatthew G. Knepley /* Count computational faces */ 51683e9753d6SMatthew G. Knepley /* Reconstruct cell gradient */ 51693e9753d6SMatthew G. Knepley /* Loop over domain cells */ 51703e9753d6SMatthew G. Knepley /* Limit cell gradients */ 51713e9753d6SMatthew G. Knepley /* Handle boundary values */ 51723e9753d6SMatthew G. Knepley /* Loop over domain faces */ 51733e9753d6SMatthew G. Knepley /* Read out field, centroid, normal, volume for each side of face */ 51743e9753d6SMatthew G. Knepley /* Riemann solve over faces */ 51753e9753d6SMatthew G. Knepley /* Loop over domain faces */ 51763e9753d6SMatthew G. Knepley /* Accumulate fluxes to cells */ 51773e9753d6SMatthew G. Knepley /* TODO Change printFEM to printDisc here */ 51783e9753d6SMatthew G. Knepley if (mesh->printFEM) { 51793e9753d6SMatthew G. Knepley Vec locFbc; 51803e9753d6SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 51813e9753d6SMatthew G. Knepley PetscScalar *zeroes; 51823e9753d6SMatthew G. Knepley 51839566063dSJacob Faibussowitsch PetscCall(VecDuplicate(locF, &locFbc)); 51849566063dSJacob Faibussowitsch PetscCall(VecCopy(locF, locFbc)); 51859566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 51869566063dSJacob Faibussowitsch PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 51879566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(maxDof, &zeroes)); 518848a46eb9SPierre Jolivet for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 51899566063dSJacob Faibussowitsch PetscCall(PetscFree(zeroes)); 51909566063dSJacob Faibussowitsch PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 51919566063dSJacob Faibussowitsch PetscCall(VecDestroy(&locFbc)); 51923e9753d6SMatthew G. Knepley } 51939566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 51943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 51953e9753d6SMatthew G. Knepley } 51963e9753d6SMatthew G. Knepley 51976528b96dSMatthew G. Knepley /* 51986528b96dSMatthew G. Knepley 1) Allow multiple kernels for BdResidual for hybrid DS 51996528b96dSMatthew G. Knepley 52006528b96dSMatthew G. Knepley DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux 52016528b96dSMatthew G. Knepley 52026528b96dSMatthew G. Knepley DONE 3) Change DMGetCellFields() to get different aux data a[] for each side 52036528b96dSMatthew G. Knepley - I think I just need to replace a[] with the closure from each face 52046528b96dSMatthew G. Knepley 52056528b96dSMatthew G. Knepley 4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before 52066528b96dSMatthew G. Knepley */ 5207d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 5208d71ae5a4SJacob Faibussowitsch { 52093e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 52103e9753d6SMatthew G. Knepley const char *name = "Hybrid Residual"; 521104c51a94SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 52123e9753d6SMatthew G. Knepley DMLabel ghostLabel = NULL; 52136528b96dSMatthew G. Knepley PetscDS ds = NULL; 521407218a29SMatthew G. Knepley PetscDS dsIn = NULL; 52156528b96dSMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 521604c51a94SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 521707218a29SMatthew G. Knepley DM dmScale[3] = {NULL, NULL, NULL}; 521807218a29SMatthew G. Knepley PetscDS dsScale[3] = {NULL, NULL, NULL}; 521907218a29SMatthew G. Knepley Vec locS[3] = {NULL, NULL, NULL}; 52203e9753d6SMatthew G. Knepley PetscSection section = NULL; 52213e9753d6SMatthew G. Knepley DMField coordField = NULL; 522207218a29SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 522307218a29SMatthew G. Knepley PetscScalar *s[3] = {NULL, NULL, NULL}; 5224b2ab40e6SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 522507218a29SMatthew G. Knepley PetscScalar *elemVecNeg, *elemVecPos, *elemVecCoh; 52263e9753d6SMatthew G. Knepley IS chunkIS; 52273e9753d6SMatthew G. Knepley const PetscInt *cells; 52283e9753d6SMatthew G. Knepley PetscInt *faces; 52293e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 52303e2b0218SMatthew G. Knepley PetscInt Nf, f, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk; 52313e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 52323e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 52333e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 52343e9753d6SMatthew G. Knepley 52353e9753d6SMatthew G. Knepley PetscFunctionBegin; 52363ba16761SJacob Faibussowitsch if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 5237437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5238437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 52393ba16761SJacob Faibussowitsch if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 52405fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 52415fedec97SMatthew G. Knepley const char *name; 52429566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 524363a3b9bcSJacob 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); 52445fedec97SMatthew G. Knepley } 52459566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 52463e9753d6SMatthew G. Knepley /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 52473e9753d6SMatthew G. Knepley /* FEM */ 52483e9753d6SMatthew G. Knepley /* 1: Get sizes from dm and dmAux */ 52499566063dSJacob Faibussowitsch PetscCall(DMGetSection(dm, §ion)); 52509566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 525107218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 52529566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 52539566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 525407218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn)); 52559566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 525604c51a94SMatthew G. Knepley if (locA[2]) { 52571059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 52581059d808SMatthew G. Knepley 52599566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 526007218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL)); 52619566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 52626528b96dSMatthew G. Knepley { 52636528b96dSMatthew G. Knepley const PetscInt *cone; 52646528b96dSMatthew G. Knepley PetscInt c; 52656528b96dSMatthew G. Knepley 52661059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 52676528b96dSMatthew G. Knepley for (c = 0; c < 2; ++c) { 52686528b96dSMatthew G. Knepley const PetscInt *support; 52696528b96dSMatthew G. Knepley PetscInt ssize, s; 52706528b96dSMatthew G. Knepley 52719566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 52729566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 52731059d808SMatthew 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); 52741059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 52751059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 52761059d808SMatthew 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); 52779566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 5278c75bfeddSPierre 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); 52799566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5280ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 528107218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL)); 52829566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 52836528b96dSMatthew G. Knepley } 52846528b96dSMatthew G. Knepley } 52853e9753d6SMatthew G. Knepley } 528607218a29SMatthew G. Knepley /* Handle mass matrix scaling 528707218a29SMatthew G. Knepley The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */ 528807218a29SMatthew G. Knepley PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2])); 528907218a29SMatthew G. Knepley if (locS[2]) { 52903e2b0218SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 529107218a29SMatthew G. Knepley PetscInt Nb, Nbs; 529207218a29SMatthew G. Knepley 529307218a29SMatthew G. Knepley PetscCall(VecGetDM(locS[2], &dmScale[2])); 52943e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[2], cellStart, &dsScale[2], NULL)); 52953e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2])); 529607218a29SMatthew G. Knepley // BRAD: This is not set correctly 529707218a29SMatthew G. Knepley key[2].field = 2; 529807218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb)); 529907218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs)); 530007218a29SMatthew 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); 53013e2b0218SMatthew G. Knepley { 53023e2b0218SMatthew G. Knepley const PetscInt *cone; 53033e2b0218SMatthew G. Knepley PetscInt c; 53043e2b0218SMatthew G. Knepley 53053e2b0218SMatthew G. Knepley locS[1] = locS[0] = locS[2]; 53063e2b0218SMatthew G. Knepley dmScale[1] = dmScale[0] = dmScale[2]; 53073e2b0218SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 53083e2b0218SMatthew G. Knepley for (c = 0; c < 2; ++c) { 53093e2b0218SMatthew G. Knepley const PetscInt *support; 53103e2b0218SMatthew G. Knepley PetscInt ssize, s; 53113e2b0218SMatthew G. Knepley 53123e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 53133e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 53143e2b0218SMatthew 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); 53153e2b0218SMatthew G. Knepley if (support[0] == cellStart) s = 1; 53163e2b0218SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 53173e2b0218SMatthew 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); 53183e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL)); 53193e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c])); 53203e2b0218SMatthew G. Knepley } 53213e2b0218SMatthew G. Knepley } 532207218a29SMatthew G. Knepley } 53233e9753d6SMatthew G. Knepley /* 2: Setup geometric data */ 53249566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 53259566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 53263e9753d6SMatthew G. Knepley if (maxDegree > 1) { 53279566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 53283e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 53293e9753d6SMatthew G. Knepley PetscFE fe; 53303e9753d6SMatthew G. Knepley 53319566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 53323e9753d6SMatthew G. Knepley if (fe) { 53339566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 53349566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 53353e9753d6SMatthew G. Knepley } 53363e9753d6SMatthew G. Knepley } 53373e9753d6SMatthew G. Knepley } 53383e9753d6SMatthew G. Knepley /* Loop over chunks */ 53393e9753d6SMatthew G. Knepley cellChunkSize = numCells; 53403e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 534107218a29SMatthew G. Knepley PetscCall(PetscCalloc1(2 * cellChunkSize, &faces)); 534207218a29SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 53433e9753d6SMatthew G. Knepley /* Extract field coefficients */ 53443e9753d6SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 534507218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 534607218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 53473e2b0218SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 534807218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecNeg)); 534907218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecPos)); 535007218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecCoh)); 53513e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 53523e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 53533e9753d6SMatthew G. Knepley 535407218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecNeg, cellChunkSize * totDim)); 535507218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecPos, cellChunkSize * totDim)); 535607218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemVecCoh, cellChunkSize * totDim)); 53573e9753d6SMatthew G. Knepley /* Get faces */ 53583e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 53593e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 53603e9753d6SMatthew G. Knepley const PetscInt *cone; 53619566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, cell, &cone)); 536207218a29SMatthew G. Knepley faces[(c - cS) * 2 + 0] = cone[0]; 536307218a29SMatthew G. Knepley faces[(c - cS) * 2 + 1] = cone[1]; 53643e9753d6SMatthew G. Knepley } 536507218a29SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER)); 53663e9753d6SMatthew G. Knepley /* Get geometric data */ 53673e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 53689566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 53699566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 53703e9753d6SMatthew G. Knepley } else { 53713e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 53729566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 53733e9753d6SMatthew G. Knepley } 53743e9753d6SMatthew G. Knepley } 53753e9753d6SMatthew G. Knepley /* Loop over fields */ 53763e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 53773e9753d6SMatthew G. Knepley PetscFE fe; 53783e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 5379148442b3SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 53803e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 53813e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 53825fedec97SMatthew G. Knepley PetscBool isCohesiveField; 53833e9753d6SMatthew G. Knepley 53849566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 53853e9753d6SMatthew G. Knepley if (!fe) continue; 53869566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 53879566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 53889566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 53893e9753d6SMatthew G. Knepley blockSize = Nb; 53903e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 53919566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 53923e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 53933e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 53943e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 53953e9753d6SMatthew G. Knepley offset = numCells - Nr; 539607218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom)); 539707218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom)); 53989566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 53995fedec97SMatthew G. Knepley chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE; 54006528b96dSMatthew G. Knepley key[0].field = f; 54016528b96dSMatthew G. Knepley key[1].field = f; 54025fedec97SMatthew G. Knepley key[2].field = f; 540307218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVecNeg)); 540407218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, &elemVecNeg[offset * totDim])); 540507218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVecPos)); 540607218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, &elemVecPos[offset * totDim])); 540707218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVecCoh)); 540807218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, &elemVecCoh[offset * totDim])); 54099566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 54109566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 54113e9753d6SMatthew G. Knepley } 54123e9753d6SMatthew G. Knepley /* Add elemVec to locX */ 54133e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 54143e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 54153e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 541607218a29SMatthew G. Knepley PetscInt i; 54173e9753d6SMatthew G. Knepley 541807218a29SMatthew G. Knepley /* Scale element values */ 541907218a29SMatthew G. Knepley if (locS[0]) { 54203e2b0218SMatthew G. Knepley PetscInt Nb, off = cind * totDim, soff = cind * totDimScale[0]; 542107218a29SMatthew G. Knepley PetscBool cohesive; 542207218a29SMatthew G. Knepley 542307218a29SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 542407218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, f, &Nb)); 542507218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 542607218a29SMatthew G. Knepley if (f == key[2].field) { 542707218a29SMatthew G. Knepley PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields"); 542807218a29SMatthew G. Knepley // No cohesive scaling field is currently input 542907218a29SMatthew 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]; 543007218a29SMatthew G. Knepley off += Nb; 543107218a29SMatthew G. Knepley } else { 543207218a29SMatthew G. Knepley const PetscInt N = cohesive ? Nb : Nb * 2; 543307218a29SMatthew G. Knepley 543407218a29SMatthew G. Knepley for (i = 0; i < N; ++i) elemVecCoh[off + i] += elemVecNeg[off + i] + elemVecPos[off + i]; 543507218a29SMatthew G. Knepley off += N; 543607218a29SMatthew G. Knepley } 543707218a29SMatthew G. Knepley } 543807218a29SMatthew G. Knepley } else { 543907218a29SMatthew G. Knepley for (i = cind * totDim; i < (cind + 1) * totDim; ++i) elemVecCoh[i] += elemVecNeg[i] + elemVecPos[i]; 544007218a29SMatthew G. Knepley } 544107218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVecCoh[cind * totDim])); 54423e9753d6SMatthew G. Knepley if (ghostLabel) { 54433e9753d6SMatthew G. Knepley PetscInt ghostVal; 54443e9753d6SMatthew G. Knepley 54459566063dSJacob Faibussowitsch PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 54463e9753d6SMatthew G. Knepley if (ghostVal > 0) continue; 54473e9753d6SMatthew G. Knepley } 544807218a29SMatthew G. Knepley PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVecCoh[cind * totDim], ADD_ALL_VALUES)); 54493e9753d6SMatthew G. Knepley } 54503e9753d6SMatthew G. Knepley } 54519566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 545207218a29SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 54533e2b0218SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 545407218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecNeg)); 545507218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecPos)); 545607218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecCoh)); 54579566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 54589566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 54599566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 54603e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 54619566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 54629566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 54633e9753d6SMatthew G. Knepley } else { 54643e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 54659566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 54669566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 54673e9753d6SMatthew G. Knepley } 54689566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 54693e9753d6SMatthew G. Knepley } 547085cc2951SMatthew G. Knepley if (mesh->printFEM) { 547185cc2951SMatthew G. Knepley Vec locFbc; 547285cc2951SMatthew G. Knepley PetscInt pStart, pEnd, p, maxDof; 547385cc2951SMatthew G. Knepley PetscScalar *zeroes; 547485cc2951SMatthew G. Knepley 547585cc2951SMatthew G. Knepley PetscCall(VecDuplicate(locF, &locFbc)); 547685cc2951SMatthew G. Knepley PetscCall(VecCopy(locF, locFbc)); 547785cc2951SMatthew G. Knepley PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 547885cc2951SMatthew G. Knepley PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 547985cc2951SMatthew G. Knepley PetscCall(PetscCalloc1(maxDof, &zeroes)); 548085cc2951SMatthew G. Knepley for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 548185cc2951SMatthew G. Knepley PetscCall(PetscFree(zeroes)); 548285cc2951SMatthew G. Knepley PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 548385cc2951SMatthew G. Knepley PetscCall(VecDestroy(&locFbc)); 548485cc2951SMatthew G. Knepley } 54859566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 54863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 54873e9753d6SMatthew G. Knepley } 54883e9753d6SMatthew G. Knepley 5489a4e35b19SJacob 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) 5490d71ae5a4SJacob Faibussowitsch { 54913e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 54923e9753d6SMatthew G. Knepley DM plex = NULL, plexA = NULL, tdm; 54933e9753d6SMatthew G. Knepley DMEnclosureType encAux; 54943e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 54953e9753d6SMatthew G. Knepley PetscSection section, sectionAux = NULL; 5496e432b41dSStefano Zampini PetscSection globalSection; 54973e9753d6SMatthew G. Knepley Vec locA = NULL, tv; 54983e9753d6SMatthew G. Knepley PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL; 54993e9753d6SMatthew G. Knepley PetscInt v; 55003e9753d6SMatthew G. Knepley PetscInt Nf, totDim, totDimAux = 0; 5501e432b41dSStefano Zampini PetscBool transform; 55023e9753d6SMatthew G. Knepley 55033e9753d6SMatthew G. Knepley PetscFunctionBegin; 55049566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 55059566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 55069566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 55079566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 55089566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 55099566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 55109566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 55119566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 55129566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA)); 55133e9753d6SMatthew G. Knepley if (locA) { 55143e9753d6SMatthew G. Knepley DM dmAux; 55153e9753d6SMatthew G. Knepley 55169566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA, &dmAux)); 55179566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 55189566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 55199566063dSJacob Faibussowitsch PetscCall(DMGetDS(plexA, &probAux)); 55209566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 55219566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexA, §ionAux)); 55223e9753d6SMatthew G. Knepley } 55233e9753d6SMatthew G. Knepley 55249566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 55253e9753d6SMatthew G. Knepley for (v = 0; v < numValues; ++v) { 55263e9753d6SMatthew G. Knepley PetscFEGeom *fgeom; 55273e9753d6SMatthew G. Knepley PetscInt maxDegree; 55283e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 55293e9753d6SMatthew G. Knepley IS pointIS; 55303e9753d6SMatthew G. Knepley const PetscInt *points; 553106ad1575SMatthew G. Knepley PetscFormKey key; 55323e9753d6SMatthew G. Knepley PetscInt numFaces, face, Nq; 55333e9753d6SMatthew G. Knepley 553445480ffeSMatthew G. Knepley key.label = label; 553545480ffeSMatthew G. Knepley key.value = values[v]; 553606ad1575SMatthew G. Knepley key.part = 0; 55379566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 55383e9753d6SMatthew G. Knepley if (!pointIS) continue; /* No points with that id on this process */ 55393e9753d6SMatthew G. Knepley { 55403e9753d6SMatthew G. Knepley IS isectIS; 55413e9753d6SMatthew G. Knepley 55423e9753d6SMatthew G. Knepley /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */ 55439566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 55449566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 55453e9753d6SMatthew G. Knepley pointIS = isectIS; 55463e9753d6SMatthew G. Knepley } 55479566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(pointIS, &numFaces)); 55489566063dSJacob Faibussowitsch PetscCall(ISGetIndices(pointIS, &points)); 55499566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim * totDim, &elemMat, locA ? numFaces * totDimAux : 0, &a)); 55509566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 555148a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 55523e9753d6SMatthew G. Knepley if (!qGeom) { 55533e9753d6SMatthew G. Knepley PetscFE fe; 55543e9753d6SMatthew G. Knepley 55559566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 55569566063dSJacob Faibussowitsch PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 55579566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 55583e9753d6SMatthew G. Knepley } 55599566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 55609566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 55613e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 5562f15274beSMatthew Knepley const PetscInt point = points[face], *support; 55633e9753d6SMatthew G. Knepley PetscScalar *x = NULL; 5564f15274beSMatthew Knepley PetscInt i; 55653e9753d6SMatthew G. Knepley 55669566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, point, &support)); 55679566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 55683e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 55699566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 55703e9753d6SMatthew G. Knepley if (locX_t) { 55719566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 55723e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 55739566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 55743e9753d6SMatthew G. Knepley } 55753e9753d6SMatthew G. Knepley if (locA) { 55763e9753d6SMatthew G. Knepley PetscInt subp; 55779566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 55789566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 55793e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 55809566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 55813e9753d6SMatthew G. Knepley } 55823e9753d6SMatthew G. Knepley } 55839566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, numFaces * totDim * totDim)); 55843e9753d6SMatthew G. Knepley { 55853e9753d6SMatthew G. Knepley PetscFE fe; 55863e9753d6SMatthew G. Knepley PetscInt Nb; 55873e9753d6SMatthew G. Knepley /* Conforming batches */ 55883e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 55893e9753d6SMatthew G. Knepley /* Remainder */ 55903e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL; 55913e9753d6SMatthew G. Knepley PetscInt fieldJ, Nr, offset; 55923e9753d6SMatthew G. Knepley 55939566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 55949566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 55959566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 55963e9753d6SMatthew G. Knepley blockSize = Nb; 55973e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 55989566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 55993e9753d6SMatthew G. Knepley numChunks = numFaces / (numBatches * batchSize); 56003e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 56013e9753d6SMatthew G. Knepley Nr = numFaces % (numBatches * batchSize); 56023e9753d6SMatthew G. Knepley offset = numFaces - Nr; 56039566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 56043e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 560545480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 56069566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 56073e9753d6SMatthew G. Knepley } 56089566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 56093e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 561045480ffeSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 56119566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMat[offset * totDim * totDim])); 56123e9753d6SMatthew G. Knepley } 56139566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 56143e9753d6SMatthew G. Knepley } 56153e9753d6SMatthew G. Knepley for (face = 0; face < numFaces; ++face) { 56163e9753d6SMatthew G. Knepley const PetscInt point = points[face], *support; 56173e9753d6SMatthew G. Knepley 56183e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 56199566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(plex, point, &support)); 56209566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face * totDim * totDim])); 56219566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim])); 5622e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, support[0], &elemMat[face * totDim * totDim], ADD_VALUES)); 56233e9753d6SMatthew G. Knepley } 56249566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 56259566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 56269566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(pointIS, &points)); 56279566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 56289566063dSJacob Faibussowitsch PetscCall(PetscFree4(u, u_t, elemMat, a)); 56293e9753d6SMatthew G. Knepley } 56309566063dSJacob Faibussowitsch if (plex) PetscCall(DMDestroy(&plex)); 56319566063dSJacob Faibussowitsch if (plexA) PetscCall(DMDestroy(&plexA)); 56323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 56333e9753d6SMatthew G. Knepley } 56343e9753d6SMatthew G. Knepley 5635d71ae5a4SJacob 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) 5636d71ae5a4SJacob Faibussowitsch { 56373e9753d6SMatthew G. Knepley DMField coordField; 56383e9753d6SMatthew G. Knepley DMLabel depthLabel; 56393e9753d6SMatthew G. Knepley IS facetIS; 56403e9753d6SMatthew G. Knepley PetscInt dim; 56413e9753d6SMatthew G. Knepley 56423e9753d6SMatthew G. Knepley PetscFunctionBegin; 56439566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 56449566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 56459566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 56469566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 56479566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 56489566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 56493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 56503e9753d6SMatthew G. Knepley } 56513e9753d6SMatthew G. Knepley 5652a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user) 5653d71ae5a4SJacob Faibussowitsch { 56543e9753d6SMatthew G. Knepley PetscDS prob; 56553e9753d6SMatthew G. Knepley PetscInt dim, numBd, bd; 56563e9753d6SMatthew G. Knepley DMLabel depthLabel; 56573e9753d6SMatthew G. Knepley DMField coordField = NULL; 56583e9753d6SMatthew G. Knepley IS facetIS; 56593e9753d6SMatthew G. Knepley 56603e9753d6SMatthew G. Knepley PetscFunctionBegin; 56619566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &prob)); 56629566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 56639566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 56649566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 56659566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 56669566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 56673e9753d6SMatthew G. Knepley for (bd = 0; bd < numBd; ++bd) { 566845480ffeSMatthew G. Knepley PetscWeakForm wf; 56693e9753d6SMatthew G. Knepley DMBoundaryConditionType type; 56703e9753d6SMatthew G. Knepley DMLabel label; 56713e9753d6SMatthew G. Knepley const PetscInt *values; 56723e9753d6SMatthew G. Knepley PetscInt fieldI, numValues; 56733e9753d6SMatthew G. Knepley PetscObject obj; 56743e9753d6SMatthew G. Knepley PetscClassId id; 56753e9753d6SMatthew G. Knepley 56769566063dSJacob Faibussowitsch PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL)); 56773d3e5d66SMatthew G. Knepley if (type & DM_BC_ESSENTIAL) continue; 56789566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj)); 56799566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 56803d3e5d66SMatthew G. Knepley if (id != PETSCFE_CLASSID) continue; 56819566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 56823e9753d6SMatthew G. Knepley } 56839566063dSJacob Faibussowitsch PetscCall(ISDestroy(&facetIS)); 56843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 56853e9753d6SMatthew G. Knepley } 56863e9753d6SMatthew G. Knepley 5687d71ae5a4SJacob 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) 5688d71ae5a4SJacob Faibussowitsch { 56893e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 56903e9753d6SMatthew G. Knepley const char *name = "Jacobian"; 56919a2a23afSMatthew G. Knepley DM dmAux = NULL, plex, tdm; 56923e9753d6SMatthew G. Knepley DMEnclosureType encAux; 56933e9753d6SMatthew G. Knepley Vec A, tv; 56943e9753d6SMatthew G. Knepley DMField coordField; 56953e9753d6SMatthew G. Knepley PetscDS prob, probAux = NULL; 5696e432b41dSStefano Zampini PetscSection section, globalSection, sectionAux; 56973e9753d6SMatthew G. Knepley PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL; 56983e9753d6SMatthew G. Knepley const PetscInt *cells; 56993e9753d6SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 570028351e22SJed Brown PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 5701e04ae0b4SMatthew G. Knepley PetscBool hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform; 57023e9753d6SMatthew G. Knepley 57033e9753d6SMatthew G. Knepley PetscFunctionBegin; 5704af18b51aSmarkadams4 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 5705e04ae0b4SMatthew G. Knepley if (!cellIS) goto end; 57069566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5707437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 5708437e83fbSMatthew G. Knepley if (cStart >= cEnd) goto end; 57099566063dSJacob Faibussowitsch PetscCall(DMHasBasisTransform(dm, &transform)); 57109566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 57119566063dSJacob Faibussowitsch PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 57129566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 57139566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 571407218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 57159566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 57169566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 57179566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(prob, &hasJac)); 57189566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 57193e9753d6SMatthew G. Knepley /* user passed in the same matrix, avoid double contributions and 57203e9753d6SMatthew G. Knepley only assemble the Jacobian */ 57213e9753d6SMatthew G. Knepley if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE; 57229566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 57233e9753d6SMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 57249566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 57259a2a23afSMatthew G. Knepley if (A) { 57269566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 57279566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 57289566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plex)); 57299566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plex, §ionAux)); 57309566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 57319566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 57323e9753d6SMatthew G. Knepley } 57339566063dSJacob 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)); 57349566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 57359566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 57363e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 57373e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 57383e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 57393e9753d6SMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 57403e9753d6SMatthew G. Knepley PetscInt i; 57413e9753d6SMatthew G. Knepley 57429566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 57433e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 57449566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 57453e9753d6SMatthew G. Knepley if (X_t) { 57469566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 57473e9753d6SMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 57489566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 57493e9753d6SMatthew G. Knepley } 57503e9753d6SMatthew G. Knepley if (dmAux) { 57513e9753d6SMatthew G. Knepley PetscInt subcell; 57529566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 57539566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x)); 57543e9753d6SMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 57559566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x)); 57563e9753d6SMatthew G. Knepley } 57573e9753d6SMatthew G. Knepley } 57589566063dSJacob Faibussowitsch if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 57599566063dSJacob Faibussowitsch if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells * totDim * totDim)); 57609566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 57613e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 57623e9753d6SMatthew G. Knepley PetscClassId id; 57633e9753d6SMatthew G. Knepley PetscFE fe; 57643e9753d6SMatthew G. Knepley PetscQuadrature qGeom = NULL; 57653e9753d6SMatthew G. Knepley PetscInt Nb; 57663e9753d6SMatthew G. Knepley /* Conforming batches */ 57673e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 57683e9753d6SMatthew G. Knepley /* Remainder */ 57693e9753d6SMatthew G. Knepley PetscInt Nr, offset, Nq; 57703e9753d6SMatthew G. Knepley PetscInt maxDegree; 57713e9753d6SMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 57723e9753d6SMatthew G. Knepley 57739566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 57749566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 57759371c9d4SSatish Balay if (id == PETSCFV_CLASSID) { 57769371c9d4SSatish Balay hasFV = PETSC_TRUE; 57779371c9d4SSatish Balay continue; 57789371c9d4SSatish Balay } 57799566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 57809566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 57819566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 578248a46eb9SPierre Jolivet if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 57833e9753d6SMatthew G. Knepley if (!qGeom) { 57849566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 57859566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 57863e9753d6SMatthew G. Knepley } 57879566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 57889566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 57893e9753d6SMatthew G. Knepley blockSize = Nb; 57903e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 57919566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 57923e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 57933e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 57943e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 57953e9753d6SMatthew G. Knepley offset = numCells - Nr; 57969566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 57979566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 57983e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 57996528b96dSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 58003e9753d6SMatthew G. Knepley if (hasJac) { 58019566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5802072f5ffdSStefano Zampini PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMat[offset * totDim * totDim])); 58033e9753d6SMatthew G. Knepley } 58043e9753d6SMatthew G. Knepley if (hasPrec) { 58059566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP)); 5806072f5ffdSStefano Zampini PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMatP[offset * totDim * totDim])); 58073e9753d6SMatthew G. Knepley } 58083e9753d6SMatthew G. Knepley if (hasDyn) { 58099566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 5810072f5ffdSStefano Zampini PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMatD[offset * totDim * totDim])); 58113e9753d6SMatthew G. Knepley } 58123e9753d6SMatthew G. Knepley } 58139566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 58149566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 58159566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 58169566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 58173e9753d6SMatthew G. Knepley } 58183e9753d6SMatthew G. Knepley /* Add contribution from X_t */ 58199371c9d4SSatish Balay if (hasDyn) { 58209371c9d4SSatish Balay for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 58219371c9d4SSatish Balay } 58223e9753d6SMatthew G. Knepley if (hasFV) { 58233e9753d6SMatthew G. Knepley PetscClassId id; 58243e9753d6SMatthew G. Knepley PetscFV fv; 58253e9753d6SMatthew G. Knepley PetscInt offsetI, NcI, NbI = 1, fc, f; 58263e9753d6SMatthew G. Knepley 58273e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 58289566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 58299566063dSJacob Faibussowitsch PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI)); 58309566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId((PetscObject)fv, &id)); 58313e9753d6SMatthew G. Knepley if (id != PETSCFV_CLASSID) continue; 58323e9753d6SMatthew G. Knepley /* Put in the identity */ 58339566063dSJacob Faibussowitsch PetscCall(PetscFVGetNumComponents(fv, &NcI)); 58343e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 58353e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 58363e9753d6SMatthew G. Knepley const PetscInt eOffset = cind * totDim * totDim; 58373e9753d6SMatthew G. Knepley for (fc = 0; fc < NcI; ++fc) { 58383e9753d6SMatthew G. Knepley for (f = 0; f < NbI; ++f) { 58393e9753d6SMatthew G. Knepley const PetscInt i = offsetI + f * NcI + fc; 58403e9753d6SMatthew G. Knepley if (hasPrec) { 5841ad540459SPierre Jolivet if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 58423e9753d6SMatthew G. Knepley elemMatP[eOffset + i * totDim + i] = 1.0; 58439371c9d4SSatish Balay } else { 58449371c9d4SSatish Balay elemMat[eOffset + i * totDim + i] = 1.0; 58459371c9d4SSatish Balay } 58463e9753d6SMatthew G. Knepley } 58473e9753d6SMatthew G. Knepley } 58483e9753d6SMatthew G. Knepley } 58493e9753d6SMatthew G. Knepley } 58503e9753d6SMatthew G. Knepley /* No allocated space for FV stuff, so ignore the zero entries */ 58519566063dSJacob Faibussowitsch PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); 58523e9753d6SMatthew G. Knepley } 58533e9753d6SMatthew G. Knepley /* Insert values into matrix */ 58543e9753d6SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 58553e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 58563e9753d6SMatthew G. Knepley const PetscInt cind = c - cStart; 58573e9753d6SMatthew G. Knepley 58583e9753d6SMatthew G. Knepley /* Transform to global basis before insertion in Jacobian */ 58599566063dSJacob Faibussowitsch if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * totDim])); 58603e9753d6SMatthew G. Knepley if (hasPrec) { 58613e9753d6SMatthew G. Knepley if (hasJac) { 58629566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5863e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 58643e9753d6SMatthew G. Knepley } 58659566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim])); 58669566063dSJacob Faibussowitsch PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES)); 58673e9753d6SMatthew G. Knepley } else { 58683e9753d6SMatthew G. Knepley if (hasJac) { 58699566063dSJacob Faibussowitsch if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5870e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 58713e9753d6SMatthew G. Knepley } 58723e9753d6SMatthew G. Knepley } 58733e9753d6SMatthew G. Knepley } 58749566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 58759566063dSJacob Faibussowitsch if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 58769566063dSJacob Faibussowitsch PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, elemMatD)); 58773e9753d6SMatthew G. Knepley if (dmAux) { 58789566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 58799566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 58803e9753d6SMatthew G. Knepley } 58813e9753d6SMatthew G. Knepley /* Compute boundary integrals */ 58829566063dSJacob Faibussowitsch PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user)); 58833e9753d6SMatthew G. Knepley /* Assemble matrix */ 58849371c9d4SSatish Balay end : { 5885e04ae0b4SMatthew G. Knepley PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp; 5886e04ae0b4SMatthew G. Knepley 5887712fec58SPierre Jolivet PetscCall(MPIU_Allreduce(&assOp, &gassOp, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 58883e9753d6SMatthew G. Knepley if (hasJac && hasPrec) { 58899566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 58909566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 58913e9753d6SMatthew G. Knepley } 5892e04ae0b4SMatthew G. Knepley } 58939566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 58949566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 58959566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 58963ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 58973e9753d6SMatthew G. Knepley } 58983e9753d6SMatthew G. Knepley 5899d71ae5a4SJacob 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) 5900d71ae5a4SJacob Faibussowitsch { 59013e9753d6SMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 59023e9753d6SMatthew G. Knepley const char *name = "Hybrid Jacobian"; 5903148442b3SMatthew G. Knepley DM dmAux[3] = {NULL, NULL, NULL}; 5904148442b3SMatthew G. Knepley DMLabel ghostLabel = NULL; 59053e9753d6SMatthew G. Knepley DM plex = NULL; 59063e9753d6SMatthew G. Knepley DM plexA = NULL; 5907148442b3SMatthew G. Knepley PetscDS ds = NULL; 590807218a29SMatthew G. Knepley PetscDS dsIn = NULL; 5909148442b3SMatthew G. Knepley PetscDS dsAux[3] = {NULL, NULL, NULL}; 5910148442b3SMatthew G. Knepley Vec locA[3] = {NULL, NULL, NULL}; 591107218a29SMatthew G. Knepley DM dmScale[3] = {NULL, NULL, NULL}; 591207218a29SMatthew G. Knepley PetscDS dsScale[3] = {NULL, NULL, NULL}; 591307218a29SMatthew G. Knepley Vec locS[3] = {NULL, NULL, NULL}; 59143e9753d6SMatthew G. Knepley PetscSection section = NULL; 5915148442b3SMatthew G. Knepley PetscSection sectionAux[3] = {NULL, NULL, NULL}; 59163e9753d6SMatthew G. Knepley DMField coordField = NULL; 591707218a29SMatthew G. Knepley PetscScalar *a[3] = {NULL, NULL, NULL}; 591807218a29SMatthew G. Knepley PetscScalar *s[3] = {NULL, NULL, NULL}; 591907218a29SMatthew G. Knepley PetscScalar *u = NULL, *u_t; 592007218a29SMatthew G. Knepley PetscScalar *elemMatNeg, *elemMatPos, *elemMatCoh; 592107218a29SMatthew G. Knepley PetscScalar *elemMatNegP, *elemMatPosP, *elemMatCohP; 5922e432b41dSStefano Zampini PetscSection globalSection; 59233e9753d6SMatthew G. Knepley IS chunkIS; 59243e9753d6SMatthew G. Knepley const PetscInt *cells; 59253e9753d6SMatthew G. Knepley PetscInt *faces; 59263e9753d6SMatthew G. Knepley PetscInt cStart, cEnd, numCells; 59273e2b0218SMatthew G. Knepley PetscInt Nf, fieldI, fieldJ, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk; 59283e9753d6SMatthew G. Knepley PetscInt maxDegree = PETSC_MAX_INT; 59293e9753d6SMatthew G. Knepley PetscQuadrature affineQuad = NULL, *quads = NULL; 59303e9753d6SMatthew G. Knepley PetscFEGeom *affineGeom = NULL, **geoms = NULL; 5931e432b41dSStefano Zampini PetscBool hasBdJac, hasBdPrec; 59323e9753d6SMatthew G. Knepley 59333e9753d6SMatthew G. Knepley PetscFunctionBegin; 59343ba16761SJacob Faibussowitsch if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 5935437e83fbSMatthew G. Knepley PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5936437e83fbSMatthew G. Knepley PetscCall(ISGetLocalSize(cellIS, &numCells)); 59373ba16761SJacob Faibussowitsch if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 59385fedec97SMatthew G. Knepley if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 59395fedec97SMatthew G. Knepley const char *name; 59409566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 594163a3b9bcSJacob 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); 59425fedec97SMatthew G. Knepley } 59439566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 59449566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 59459566063dSJacob Faibussowitsch PetscCall(DMGetSection(dm, §ion)); 59469566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 59479566063dSJacob Faibussowitsch PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 594807218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn)); 59499566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 59509566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 595107218a29SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn)); 59529566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac)); 59539566063dSJacob Faibussowitsch PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec)); 59549566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 5955148442b3SMatthew G. Knepley if (locA[2]) { 59561059d808SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 59571059d808SMatthew G. Knepley 59589566063dSJacob Faibussowitsch PetscCall(VecGetDM(locA[2], &dmAux[2])); 59599566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA)); 59609566063dSJacob Faibussowitsch PetscCall(DMGetSection(dmAux[2], §ionAux[2])); 596107218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL)); 59629566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 5963148442b3SMatthew G. Knepley { 5964148442b3SMatthew G. Knepley const PetscInt *cone; 5965148442b3SMatthew G. Knepley PetscInt c; 5966148442b3SMatthew G. Knepley 59671059d808SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 5968148442b3SMatthew G. Knepley for (c = 0; c < 2; ++c) { 5969148442b3SMatthew G. Knepley const PetscInt *support; 5970148442b3SMatthew G. Knepley PetscInt ssize, s; 5971148442b3SMatthew G. Knepley 59729566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 59739566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 59741059d808SMatthew 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); 59751059d808SMatthew G. Knepley if (support[0] == cellStart) s = 1; 59761059d808SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 59771059d808SMatthew 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); 59789566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 59799566063dSJacob Faibussowitsch if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5980ad540459SPierre Jolivet else dmAux[c] = dmAux[2]; 598107218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL)); 59829566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 5983148442b3SMatthew G. Knepley } 5984148442b3SMatthew G. Knepley } 59853e9753d6SMatthew G. Knepley } 598607218a29SMatthew G. Knepley /* Handle mass matrix scaling 598707218a29SMatthew G. Knepley The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */ 598807218a29SMatthew G. Knepley PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2])); 598907218a29SMatthew G. Knepley if (locS[2]) { 59903e2b0218SMatthew G. Knepley const PetscInt cellStart = cells ? cells[cStart] : cStart; 599107218a29SMatthew G. Knepley PetscInt Nb, Nbs; 599207218a29SMatthew G. Knepley 599307218a29SMatthew G. Knepley PetscCall(VecGetDM(locS[2], &dmScale[2])); 599407218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[2], cells ? cells[cStart] : cStart, &dsScale[2], NULL)); 59953e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2])); 599607218a29SMatthew G. Knepley // BRAD: This is not set correctly 599707218a29SMatthew G. Knepley key[2].field = 2; 599807218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb)); 599907218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs)); 600007218a29SMatthew 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); 60013e2b0218SMatthew G. Knepley { 60023e2b0218SMatthew G. Knepley const PetscInt *cone; 60033e2b0218SMatthew G. Knepley PetscInt c; 60043e2b0218SMatthew G. Knepley 60053e2b0218SMatthew G. Knepley locS[1] = locS[0] = locS[2]; 60063e2b0218SMatthew G. Knepley dmScale[1] = dmScale[0] = dmScale[2]; 60073e2b0218SMatthew G. Knepley PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 60083e2b0218SMatthew G. Knepley for (c = 0; c < 2; ++c) { 60093e2b0218SMatthew G. Knepley const PetscInt *support; 60103e2b0218SMatthew G. Knepley PetscInt ssize, s; 60113e2b0218SMatthew G. Knepley 60123e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 60133e2b0218SMatthew G. Knepley PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 60143e2b0218SMatthew 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); 60153e2b0218SMatthew G. Knepley if (support[0] == cellStart) s = 1; 60163e2b0218SMatthew G. Knepley else if (support[1] == cellStart) s = 0; 60173e2b0218SMatthew 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); 60183e2b0218SMatthew G. Knepley PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL)); 60193e2b0218SMatthew G. Knepley PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c])); 60203e2b0218SMatthew G. Knepley } 60213e2b0218SMatthew G. Knepley } 602207218a29SMatthew G. Knepley } 602307218a29SMatthew G. Knepley /* 2: Setup geometric data */ 60249566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 60259566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 60263e9753d6SMatthew G. Knepley if (maxDegree > 1) { 60273e9753d6SMatthew G. Knepley PetscInt f; 60289566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 60293e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 60303e9753d6SMatthew G. Knepley PetscFE fe; 60313e9753d6SMatthew G. Knepley 60329566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 60333e9753d6SMatthew G. Knepley if (fe) { 60349566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 60359566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)quads[f])); 60363e9753d6SMatthew G. Knepley } 60373e9753d6SMatthew G. Knepley } 60383e9753d6SMatthew G. Knepley } 603907218a29SMatthew G. Knepley /* Loop over chunks */ 60403e9753d6SMatthew G. Knepley cellChunkSize = numCells; 60413e9753d6SMatthew G. Knepley numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 604207218a29SMatthew G. Knepley PetscCall(PetscCalloc1(2 * cellChunkSize, &faces)); 6043a4158a15SMatthew G. Knepley PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 604407218a29SMatthew G. Knepley /* Extract field coefficients */ 604507218a29SMatthew G. Knepley /* NOTE This needs the end cap faces to have identical orientations */ 604607218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 604707218a29SMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 60488bf0a22dSMatthew G. Knepley PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s)); 604907218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg)); 605007218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos)); 605107218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh)); 605207218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP)); 605307218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP)); 605407218a29SMatthew G. Knepley PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP)); 60553e9753d6SMatthew G. Knepley for (chunk = 0; chunk < numChunks; ++chunk) { 60563e9753d6SMatthew G. Knepley PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 60573e9753d6SMatthew G. Knepley 605807218a29SMatthew G. Knepley if (hasBdJac) { 605907218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatNeg, cellChunkSize * totDim * totDim)); 606007218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatPos, cellChunkSize * totDim * totDim)); 606107218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatCoh, cellChunkSize * totDim * totDim)); 606207218a29SMatthew G. Knepley } 606307218a29SMatthew G. Knepley if (hasBdPrec) { 606407218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatNegP, cellChunkSize * totDim * totDim)); 606507218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatPosP, cellChunkSize * totDim * totDim)); 606607218a29SMatthew G. Knepley PetscCall(PetscArrayzero(elemMatCohP, cellChunkSize * totDim * totDim)); 606707218a29SMatthew G. Knepley } 60683e9753d6SMatthew G. Knepley /* Get faces */ 60693e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 60703e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 60713e9753d6SMatthew G. Knepley const PetscInt *cone; 60729566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(plex, cell, &cone)); 607307218a29SMatthew G. Knepley faces[(c - cS) * 2 + 0] = cone[0]; 607407218a29SMatthew G. Knepley faces[(c - cS) * 2 + 1] = cone[1]; 60753e9753d6SMatthew G. Knepley } 607607218a29SMatthew G. Knepley PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER)); 60773e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 60789566063dSJacob Faibussowitsch if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 60799566063dSJacob Faibussowitsch if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 60803e9753d6SMatthew G. Knepley } else { 60813e9753d6SMatthew G. Knepley PetscInt f; 60823e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 60839566063dSJacob Faibussowitsch if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 60843e9753d6SMatthew G. Knepley } 60853e9753d6SMatthew G. Knepley } 60863e9753d6SMatthew G. Knepley 60873e9753d6SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 60883e9753d6SMatthew G. Knepley PetscFE feI; 60893e9753d6SMatthew G. Knepley PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI]; 60903e9753d6SMatthew G. Knepley PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 60913e9753d6SMatthew G. Knepley PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI]; 60923e9753d6SMatthew G. Knepley PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 60935fedec97SMatthew G. Knepley PetscBool isCohesiveField; 60943e9753d6SMatthew G. Knepley 60959566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI)); 60963e9753d6SMatthew G. Knepley if (!feI) continue; 60979566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches)); 60989566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 60999566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(feI, &Nb)); 61003e9753d6SMatthew G. Knepley blockSize = Nb; 61013e9753d6SMatthew G. Knepley batchSize = numBlocks * blockSize; 61029566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches)); 61033e9753d6SMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 61043e9753d6SMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 61053e9753d6SMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 61063e9753d6SMatthew G. Knepley offset = numCells - Nr; 610707218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom)); 610807218a29SMatthew G. Knepley PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom)); 61099566063dSJacob Faibussowitsch PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField)); 61103e9753d6SMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 61113e9753d6SMatthew G. Knepley PetscFE feJ; 61123e9753d6SMatthew G. Knepley 61139566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ)); 61143e9753d6SMatthew G. Knepley if (!feJ) continue; 6115148442b3SMatthew G. Knepley key[0].field = fieldI * Nf + fieldJ; 6116148442b3SMatthew G. Knepley key[1].field = fieldI * Nf + fieldJ; 61175fedec97SMatthew G. Knepley key[2].field = fieldI * Nf + fieldJ; 6118148442b3SMatthew G. Knepley if (hasBdJac) { 611907218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatNeg)); 612007218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatNeg[offset * totDim * totDim])); 612107218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatPos)); 612207218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatPos[offset * totDim * totDim])); 6123148442b3SMatthew G. Knepley } 6124148442b3SMatthew G. Knepley if (hasBdPrec) { 612507218a29SMatthew 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)); 612607218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[0], 0, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatNegP[offset * totDim * totDim])); 612707218a29SMatthew 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)); 612807218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[1], 1, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatPosP[offset * totDim * totDim])); 6129148442b3SMatthew G. Knepley } 61305fedec97SMatthew G. Knepley if (hasBdJac) { 613107218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatCoh)); 613207218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatCoh[offset * totDim * totDim])); 6133148442b3SMatthew G. Knepley } 61345fedec97SMatthew G. Knepley if (hasBdPrec) { 613507218a29SMatthew 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)); 613607218a29SMatthew G. Knepley PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[2], 2, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatCohP[offset * totDim * totDim])); 61373e9753d6SMatthew G. Knepley } 61383e9753d6SMatthew G. Knepley } 61399566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 61409566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 61413e9753d6SMatthew G. Knepley } 61423e9753d6SMatthew G. Knepley /* Insert values into matrix */ 61433e9753d6SMatthew G. Knepley for (c = cS; c < cE; ++c) { 61443e9753d6SMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 614507218a29SMatthew G. Knepley const PetscInt cind = c - cS, coff = cind * totDim * totDim; 614607218a29SMatthew G. Knepley PetscInt i, j; 61473e9753d6SMatthew G. Knepley 614807218a29SMatthew G. Knepley /* Scale element values */ 614907218a29SMatthew G. Knepley if (locS[0]) { 61503e2b0218SMatthew G. Knepley PetscInt Nb, soff = cind * totDimScale[0], off = 0; 615107218a29SMatthew G. Knepley PetscBool cohesive; 615207218a29SMatthew G. Knepley 615307218a29SMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 615407218a29SMatthew G. Knepley PetscCall(PetscDSGetFieldSize(ds, fieldI, &Nb)); 615507218a29SMatthew G. Knepley PetscCall(PetscDSGetCohesive(ds, fieldI, &cohesive)); 615607218a29SMatthew G. Knepley 615707218a29SMatthew G. Knepley if (fieldI == key[2].field) { 615807218a29SMatthew G. Knepley PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields"); 61598bf0a22dSMatthew G. Knepley for (i = 0; i < Nb; ++i) { 616007218a29SMatthew 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]; 61618bf0a22dSMatthew G. Knepley if (hasBdPrec) 61628bf0a22dSMatthew 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]; 61638bf0a22dSMatthew G. Knepley } 616407218a29SMatthew G. Knepley off += Nb; 616507218a29SMatthew G. Knepley } else { 616607218a29SMatthew G. Knepley const PetscInt N = cohesive ? Nb : Nb * 2; 616707218a29SMatthew G. Knepley 61688bf0a22dSMatthew G. Knepley for (i = 0; i < N; ++i) { 616907218a29SMatthew 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]; 61708bf0a22dSMatthew G. Knepley if (hasBdPrec) 61718bf0a22dSMatthew 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]; 61728bf0a22dSMatthew G. Knepley } 617307218a29SMatthew G. Knepley off += N; 617407218a29SMatthew G. Knepley } 617507218a29SMatthew G. Knepley } 617607218a29SMatthew G. Knepley } else { 617707218a29SMatthew G. Knepley for (i = 0; i < totDim * totDim; ++i) elemMatCoh[coff + i] += elemMatNeg[coff + i] + elemMatPos[coff + i]; 61788bf0a22dSMatthew G. Knepley if (hasBdPrec) 61798bf0a22dSMatthew G. Knepley for (i = 0; i < totDim * totDim; ++i) elemMatCohP[coff + i] += elemMatNegP[coff + i] + elemMatPosP[coff + i]; 618007218a29SMatthew G. Knepley } 61813e9753d6SMatthew G. Knepley if (hasBdPrec) { 61823e9753d6SMatthew G. Knepley if (hasBdJac) { 618307218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim])); 6184e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES)); 61853e9753d6SMatthew G. Knepley } 618607218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCohP[cind * totDim * totDim])); 618707218a29SMatthew G. Knepley PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatCohP[cind * totDim * totDim], ADD_VALUES)); 61883e9753d6SMatthew G. Knepley } else if (hasBdJac) { 618907218a29SMatthew G. Knepley if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim])); 6190e8e188d2SZach Atkins PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES)); 61913e9753d6SMatthew G. Knepley } 61923e9753d6SMatthew G. Knepley } 61933e9753d6SMatthew G. Knepley } 61949566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 619507218a29SMatthew G. Knepley PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a)); 619607218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg)); 619707218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos)); 619807218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh)); 619907218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP)); 620007218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP)); 620107218a29SMatthew G. Knepley PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP)); 62029566063dSJacob Faibussowitsch PetscCall(PetscFree(faces)); 62039566063dSJacob Faibussowitsch PetscCall(ISDestroy(&chunkIS)); 62049566063dSJacob Faibussowitsch PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 62053e9753d6SMatthew G. Knepley if (maxDegree <= 1) { 62069566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 62079566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&affineQuad)); 62083e9753d6SMatthew G. Knepley } else { 62093e9753d6SMatthew G. Knepley PetscInt f; 62103e9753d6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 62119566063dSJacob Faibussowitsch if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 62129566063dSJacob Faibussowitsch if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 62133e9753d6SMatthew G. Knepley } 62149566063dSJacob Faibussowitsch PetscCall(PetscFree2(quads, geoms)); 62153e9753d6SMatthew G. Knepley } 62169566063dSJacob Faibussowitsch if (dmAux[2]) PetscCall(DMDestroy(&plexA)); 62179566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 62189566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 62193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 62203e9753d6SMatthew G. Knepley } 62218e3a2eefSMatthew G. Knepley 62228e3a2eefSMatthew G. Knepley /* 62238e3a2eefSMatthew 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. 62248e3a2eefSMatthew G. Knepley 62258e3a2eefSMatthew G. Knepley Input Parameters: 62268e3a2eefSMatthew G. Knepley + dm - The mesh 6227baca6076SPierre Jolivet . key - The PetscWeakFormKey indicating where integration should happen 622806ad1575SMatthew G. Knepley . cellIS - The cells to integrate over 62298e3a2eefSMatthew G. Knepley . t - The time 6230145b44c9SPierre Jolivet . X_tShift - The multiplier for the Jacobian with respect to X_t 62318e3a2eefSMatthew G. Knepley . X - Local solution vector 62328e3a2eefSMatthew G. Knepley . X_t - Time-derivative of the local solution vector 62338e3a2eefSMatthew G. Knepley . Y - Local input vector 623406ad1575SMatthew G. Knepley - user - the user context 62358e3a2eefSMatthew G. Knepley 62368e3a2eefSMatthew G. Knepley Output Parameter: 62378e3a2eefSMatthew G. Knepley . Z - Local output vector 62388e3a2eefSMatthew G. Knepley 62398e3a2eefSMatthew G. Knepley Note: 62408e3a2eefSMatthew G. Knepley We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 62418e3a2eefSMatthew G. Knepley like a GPU, or vectorize on a multicore machine. 62428e3a2eefSMatthew G. Knepley */ 6243d71ae5a4SJacob 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) 6244d71ae5a4SJacob Faibussowitsch { 62458e3a2eefSMatthew G. Knepley DM_Plex *mesh = (DM_Plex *)dm->data; 62468e3a2eefSMatthew G. Knepley const char *name = "Jacobian"; 62478e3a2eefSMatthew G. Knepley DM dmAux = NULL, plex, plexAux = NULL; 62488e3a2eefSMatthew G. Knepley DMEnclosureType encAux; 62498e3a2eefSMatthew G. Knepley Vec A; 62508e3a2eefSMatthew G. Knepley DMField coordField; 62518e3a2eefSMatthew G. Knepley PetscDS prob, probAux = NULL; 62528e3a2eefSMatthew G. Knepley PetscQuadrature quad; 62538e3a2eefSMatthew G. Knepley PetscSection section, globalSection, sectionAux; 62548e3a2eefSMatthew G. Knepley PetscScalar *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z; 62558e3a2eefSMatthew G. Knepley const PetscInt *cells; 62568e3a2eefSMatthew G. Knepley PetscInt Nf, fieldI, fieldJ; 62578e3a2eefSMatthew G. Knepley PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 62588e3a2eefSMatthew G. Knepley PetscBool hasDyn; 62598e3a2eefSMatthew G. Knepley 62608e3a2eefSMatthew G. Knepley PetscFunctionBegin; 626121d77094SMatthew G. Knepley if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 62629566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 62639566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex)); 62649566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(cellIS, &numCells)); 62659566063dSJacob Faibussowitsch PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 62669566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, §ion)); 62679566063dSJacob Faibussowitsch PetscCall(DMGetGlobalSection(dm, &globalSection)); 626807218a29SMatthew G. Knepley PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL)); 62699566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(prob, &Nf)); 62709566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 62719566063dSJacob Faibussowitsch PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 62728e3a2eefSMatthew G. Knepley hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 62739566063dSJacob Faibussowitsch PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 62748e3a2eefSMatthew G. Knepley if (A) { 62759566063dSJacob Faibussowitsch PetscCall(VecGetDM(A, &dmAux)); 62769566063dSJacob Faibussowitsch PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 62779566063dSJacob Faibussowitsch PetscCall(DMConvert(dmAux, DMPLEX, &plexAux)); 62789566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(plexAux, §ionAux)); 62799566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmAux, &probAux)); 62809566063dSJacob Faibussowitsch PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 62818e3a2eefSMatthew G. Knepley } 62829566063dSJacob Faibussowitsch PetscCall(VecSet(Z, 0.0)); 62839566063dSJacob 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)); 62849566063dSJacob Faibussowitsch if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 62859566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateField(dm, &coordField)); 62868e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 62878e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 62888e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 62898e3a2eefSMatthew G. Knepley PetscScalar *x = NULL, *x_t = NULL; 62908e3a2eefSMatthew G. Knepley PetscInt i; 62918e3a2eefSMatthew G. Knepley 62929566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X, cell, NULL, &x)); 62938e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 62949566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x)); 62958e3a2eefSMatthew G. Knepley if (X_t) { 62969566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t)); 62978e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 62989566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t)); 62998e3a2eefSMatthew G. Knepley } 63008e3a2eefSMatthew G. Knepley if (dmAux) { 63018e3a2eefSMatthew G. Knepley PetscInt subcell; 63029566063dSJacob Faibussowitsch PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 63039566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 63048e3a2eefSMatthew G. Knepley for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 63059566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 63068e3a2eefSMatthew G. Knepley } 63079566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x)); 63088e3a2eefSMatthew G. Knepley for (i = 0; i < totDim; ++i) y[cind * totDim + i] = x[i]; 63099566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x)); 63108e3a2eefSMatthew G. Knepley } 63119566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 63129566063dSJacob Faibussowitsch if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 63138e3a2eefSMatthew G. Knepley for (fieldI = 0; fieldI < Nf; ++fieldI) { 63148e3a2eefSMatthew G. Knepley PetscFE fe; 63158e3a2eefSMatthew G. Knepley PetscInt Nb; 63168e3a2eefSMatthew G. Knepley /* Conforming batches */ 63178e3a2eefSMatthew G. Knepley PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 63188e3a2eefSMatthew G. Knepley /* Remainder */ 63198e3a2eefSMatthew G. Knepley PetscInt Nr, offset, Nq; 63208e3a2eefSMatthew G. Knepley PetscQuadrature qGeom = NULL; 63218e3a2eefSMatthew G. Knepley PetscInt maxDegree; 63228e3a2eefSMatthew G. Knepley PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 63238e3a2eefSMatthew G. Knepley 63249566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 63259566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &quad)); 63269566063dSJacob Faibussowitsch PetscCall(PetscFEGetDimension(fe, &Nb)); 63279566063dSJacob Faibussowitsch PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 63289566063dSJacob Faibussowitsch PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 63299566063dSJacob Faibussowitsch if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 63308e3a2eefSMatthew G. Knepley if (!qGeom) { 63319566063dSJacob Faibussowitsch PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 63329566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)qGeom)); 63338e3a2eefSMatthew G. Knepley } 63349566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 63359566063dSJacob Faibussowitsch PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 63368e3a2eefSMatthew G. Knepley blockSize = Nb; 63378e3a2eefSMatthew G. Knepley batchSize = numBlocks * blockSize; 63389566063dSJacob Faibussowitsch PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 63398e3a2eefSMatthew G. Knepley numChunks = numCells / (numBatches * batchSize); 63408e3a2eefSMatthew G. Knepley Ne = numChunks * numBatches * batchSize; 63418e3a2eefSMatthew G. Knepley Nr = numCells % (numBatches * batchSize); 63428e3a2eefSMatthew G. Knepley offset = numCells - Nr; 63439566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 63449566063dSJacob Faibussowitsch PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 63458e3a2eefSMatthew G. Knepley for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 63468e3a2eefSMatthew G. Knepley key.field = fieldI * Nf + fieldJ; 63479566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 63489566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMat[offset * totDim * totDim])); 63498e3a2eefSMatthew G. Knepley if (hasDyn) { 63509566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 63519566063dSJacob Faibussowitsch PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMatD[offset * totDim * totDim])); 63528e3a2eefSMatthew G. Knepley } 63538e3a2eefSMatthew G. Knepley } 63549566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 63559566063dSJacob Faibussowitsch PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 63569566063dSJacob Faibussowitsch PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 63579566063dSJacob Faibussowitsch PetscCall(PetscQuadratureDestroy(&qGeom)); 63588e3a2eefSMatthew G. Knepley } 63598e3a2eefSMatthew G. Knepley if (hasDyn) { 63608e3a2eefSMatthew G. Knepley for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 63618e3a2eefSMatthew G. Knepley } 63628e3a2eefSMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 63638e3a2eefSMatthew G. Knepley const PetscInt cell = cells ? cells[c] : c; 63648e3a2eefSMatthew G. Knepley const PetscInt cind = c - cStart; 63658e3a2eefSMatthew G. Knepley const PetscBLASInt M = totDim, one = 1; 63668e3a2eefSMatthew G. Knepley const PetscScalar a = 1.0, b = 0.0; 63678e3a2eefSMatthew G. Knepley 6368792fecdfSBarry Smith PetscCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind * totDim * totDim], &M, &y[cind * totDim], &one, &b, z, &one)); 63698e3a2eefSMatthew G. Knepley if (mesh->printFEM > 1) { 63709566063dSJacob Faibussowitsch PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 63719566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind * totDim])); 63729566063dSJacob Faibussowitsch PetscCall(DMPrintCellVector(c, "Z", totDim, z)); 63738e3a2eefSMatthew G. Knepley } 63749566063dSJacob Faibussowitsch PetscCall(DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES)); 63758e3a2eefSMatthew G. Knepley } 63769566063dSJacob Faibussowitsch PetscCall(PetscFree6(u, u_t, elemMat, elemMatD, y, z)); 63778e3a2eefSMatthew G. Knepley if (mesh->printFEM) { 63789566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n")); 63799566063dSJacob Faibussowitsch PetscCall(VecView(Z, NULL)); 63808e3a2eefSMatthew G. Knepley } 63811059d808SMatthew G. Knepley PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 63829566063dSJacob Faibussowitsch PetscCall(PetscFree(a)); 63839566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plexAux)); 63849566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 63859566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 63863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 63878e3a2eefSMatthew G. Knepley } 6388